reverting commit 1311904

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/collections/trunk@1311954 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Luc Maisonobe 2012-04-10 19:38:24 +00:00
parent 41d170f076
commit 6d8659cad5
22 changed files with 805 additions and 2163 deletions

View File

@ -226,9 +226,6 @@
<contributor> <contributor>
<name>Berin Loritsch</name> <name>Berin Loritsch</name>
</contributor> </contributor>
<contributor>
<name>Luc Maisonobe</name>
</contributor>
<contributor> <contributor>
<name>Hendrik Maryns</name> <name>Hendrik Maryns</name>
</contributor> </contributor>

View File

@ -1,136 +1,136 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with * (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.commons.collections; package org.apache.commons.collections;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import org.apache.commons.collections.collection.AbstractCollectionDecorator; import org.apache.commons.collections.collection.AbstractCollectionDecorator;
/** /**
* An IndexedCollection is a Map-like view onto a Collection. It accepts a * An IndexedCollection is a Map-like view onto a Collection. It accepts a
* keyTransformer to define how the keys are converted from the values. * keyTransformer to define how the keys are converted from the values.
* <p> * <p>
* Modifications made to this decorator modify the index as well as the * Modifications made to this decorator modify the index as well as the
* decorated {@link Collection}. However, modifications to the underlying * decorated {@link Collection}. However, modifications to the underlying
* {@link Collection} will not updated the index and it will get out of sync. * {@link Collection} will not updated the index and it will get out of sync.
* <p> * <p>
* If modification to the decorated {@link Collection} is unavoidable, then a * If modification to the decorated {@link Collection} is unavoidable, then a
* call to {@link #reindex()} will update the index to the current contents of * call to {@link #reindex()} will update the index to the current contents of
* the {@link Collection}. * the {@link Collection}.
* *
* @param <K> the type of object in the index. * @param <K> the type of object in the index.
* @param <C> the type of object in the collection. * @param <C> the type of object in the collection.
* @author Stephen Kestle * @author Stephen Kestle
*/ */
// TODO support MultiMap/non-unique index behavior // TODO support MultiMap/non-unique index behavior
// TODO add support for remove and clear // TODO add support for remove and clear
public class IndexedCollection<K, C> extends AbstractCollectionDecorator<C> { public class IndexedCollection<K, C> extends AbstractCollectionDecorator<C> {
/** /**
* . * .
*/ */
private static final long serialVersionUID = -5512610452568370038L; private static final long serialVersionUID = -5512610452568370038L;
/** /**
* Create an {@link IndexedCollection} for a unique index. * Create an {@link IndexedCollection} for a unique index.
* *
* @param <K> the index object type. * @param <K> the index object type.
* @param <C> the collection type. * @param <C> the collection type.
* @param coll the decorated {@link Collection}. * @param coll the decorated {@link Collection}.
* @param keyTransformer the {@link Transformer} for generating index keys. * @param keyTransformer the {@link Transformer} for generating index keys.
* @return the created {@link IndexedCollection}. * @return the created {@link IndexedCollection}.
*/ */
public static <K, C> IndexedCollection<K, C> uniqueIndexedCollection(final Collection<C> coll, final Transformer<C, K> keyTransformer) { public static <K, C> IndexedCollection<K, C> uniqueIndexedCollection(final Collection<C> coll, final Transformer<C, K> keyTransformer) {
return new IndexedCollection<K, C>(coll, keyTransformer, new HashMap<K, C>()); return new IndexedCollection<K, C>(coll, keyTransformer, new HashMap<K, C>());
} }
/** /**
* The {@link Transformer} for generating index keys. * The {@link Transformer} for generating index keys.
*/ */
private final Transformer<C, K> keyTransformer; private final Transformer<C, K> keyTransformer;
/** /**
* The map of indexes to collected objects. * The map of indexes to collected objects.
*/ */
private final HashMap<K, C> index; private final HashMap<K, C> index;
/** /**
* Create a {@link IndexedCollection} for a unique index. * Create a {@link IndexedCollection} for a unique index.
* *
* @param coll the decorated {@link Collection}. * @param coll the decorated {@link Collection}.
* @param keyTransformer the {@link Transformer} for generating index keys. * @param keyTransformer the {@link Transformer} for generating index keys.
*/ */
public IndexedCollection(Collection<C> coll, Transformer<C, K> keyTransformer, HashMap<K, C> map) { public IndexedCollection(Collection<C> coll, Transformer<C, K> keyTransformer, HashMap<K, C> map) {
super(coll); super(coll);
this.keyTransformer = keyTransformer; this.keyTransformer = keyTransformer;
this.index = map; this.index = map;
reindex(); reindex();
} }
/** /**
* Clears the index and re-indexes the entire decorated {@link Collection}. * Clears the index and re-indexes the entire decorated {@link Collection}.
*/ */
public void reindex() { public void reindex() {
index.clear(); index.clear();
for (C c : decorated()) { for (C c : decorated()) {
addIndex(c); addIndex(c);
} }
} }
/** /**
* Adds an object to the collection and index. * Adds an object to the collection and index.
*/ */
@Override @Override
// TODO: Add error handling for when super.add() fails // TODO: Add error handling for when super.add() fails
public boolean add(C object) { public boolean add(C object) {
addIndex(object); addIndex(object);
return super.add(object); return super.add(object);
} }
/** /**
* Adds an entire collection to the collection and index. * Adds an entire collection to the collection and index.
*/ */
@Override @Override
// TODO: Add error handling for when super.addAll() fails // TODO: Add error handling for when super.addAll() fails
public boolean addAll(Collection<? extends C> coll) { public boolean addAll(Collection<? extends C> coll) {
for (C c : coll) { for (C c : coll) {
addIndex(c); addIndex(c);
} }
return super.addAll(coll); return super.addAll(coll);
} }
/** /**
* Provides checking for adding the index. * Provides checking for adding the index.
* *
* @param object the object to index. * @param object the object to index.
*/ */
private void addIndex(C object) { private void addIndex(C object) {
final C existingObject = index.put(keyTransformer.transform(object), object); final C existingObject = index.put(keyTransformer.transform(object), object);
if (existingObject != null) { if (existingObject != null) {
throw new IllegalArgumentException("Duplicate key in uniquely indexed collection."); throw new IllegalArgumentException("Duplicate key in uniquely indexed collection.");
} }
} }
/** /**
* Get the element associated with the given key. * Get the element associated with the given key.
* @param key to look up * @param key to look up
* @return element found * @return element found
*/ */
public C get(K key) { public C get(K key) {
return index.get(key); return index.get(key);
} }
} }

View File

@ -1,76 +1,76 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with * (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.commons.collections.functors; package org.apache.commons.collections.functors;
import org.apache.commons.collections.Closure; import org.apache.commons.collections.Closure;
import org.apache.commons.collections.FunctorException; import org.apache.commons.collections.FunctorException;
/** /**
* {@link Closure} that catches any checked exception and re-throws it as a * {@link Closure} that catches any checked exception and re-throws it as a
* {@link FunctorException} runtime exception. Example usage: * {@link FunctorException} runtime exception. Example usage:
* *
* <pre> * <pre>
* // Create a catch and re-throw closure via anonymous subclass * // Create a catch and re-throw closure via anonymous subclass
* CatchAndRethrowClosure&lt;String&gt; writer = new ThrowingClosure() { * CatchAndRethrowClosure&lt;String&gt; writer = new ThrowingClosure() {
* private java.io.Writer out = // some writer * private java.io.Writer out = // some writer
* *
* protected void executeAndThrow(String input) throws IOException { * protected void executeAndThrow(String input) throws IOException {
* out.write(input); // throwing of IOException allowed * out.write(input); // throwing of IOException allowed
* } * }
* }; * };
* *
* // use catch and re-throw closure * // use catch and re-throw closure
* java.util.List<String> strList = // some list * java.util.List<String> strList = // some list
* try { * try {
* CollctionUtils.forAllDo(strList, writer); * CollctionUtils.forAllDo(strList, writer);
* } catch (FunctorException ex) { * } catch (FunctorException ex) {
* Throwable originalError = ex.getCause(); * Throwable originalError = ex.getCause();
* // handle error * // handle error
* } * }
* </pre> * </pre>
* *
* @since Commons Collections 4.0 * @since Commons Collections 4.0
* @version $Revision$ * @version $Revision$
*/ */
public abstract class CatchAndRethrowClosure<E> implements Closure<E> { public abstract class CatchAndRethrowClosure<E> implements Closure<E> {
/** /**
* Execute this closure on the specified input object. * Execute this closure on the specified input object.
* *
* @param input the input to execute on * @param input the input to execute on
* @throws FunctorException (runtime) if the closure execution resulted in a * @throws FunctorException (runtime) if the closure execution resulted in a
* checked exception. * checked exception.
*/ */
public void execute(E input) { public void execute(E input) {
try { try {
executeAndThrow(input); executeAndThrow(input);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
throw ex; throw ex;
} catch (Throwable t) { } catch (Throwable t) {
throw new FunctorException(t); throw new FunctorException(t);
} }
} }
/** /**
* Execute this closure on the specified input object. * Execute this closure on the specified input object.
* *
* @param input the input to execute on * @param input the input to execute on
* @throws Throwable if the closure execution resulted in a checked * @throws Throwable if the closure execution resulted in a checked
* exception. * exception.
*/ */
protected abstract void executeAndThrow(E input) throws Throwable; protected abstract void executeAndThrow(E input) throws Throwable;
} }

View File

@ -1,188 +1,188 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with * (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.commons.collections.functors; package org.apache.commons.collections.functors;
import java.io.Serializable; import java.io.Serializable;
import java.util.Comparator; import java.util.Comparator;
import org.apache.commons.collections.Predicate; import org.apache.commons.collections.Predicate;
/** /**
* Predicate that compares the input object with the one stored in the predicate using a comparator. * Predicate that compares the input object with the one stored in the predicate using a comparator.
* In addition, the comparator result can be evaluated in accordance to a supplied criterion value. * In addition, the comparator result can be evaluated in accordance to a supplied criterion value.
* *
* In order to demonstrate the use of the predicate, the following variables are declared: * In order to demonstrate the use of the predicate, the following variables are declared:
* *
* <pre> * <pre>
* Integer ONE = new Integer(1); * Integer ONE = new Integer(1);
* Integer TWO = new Integer(2); * Integer TWO = new Integer(2);
* *
* Comparator comparator = new Comparator() { * Comparator comparator = new Comparator() {
* *
* public int compare(Object first, Object second) { * public int compare(Object first, Object second) {
* return ((Integer) second) - ((Integer) first); * return ((Integer) second) - ((Integer) first);
* } * }
* *
* }; * };
* </pre> * </pre>
* *
* Using the declared variables, the <code>ComparatorPredicate</code> can be used used in the * Using the declared variables, the <code>ComparatorPredicate</code> can be used used in the
* following way: * following way:
* *
* <pre> * <pre>
* ComparatorPredicate.getInstance(ONE, comparator).evaluate(TWO); * ComparatorPredicate.getInstance(ONE, comparator).evaluate(TWO);
* </pre> * </pre>
* *
* The input variable <code>TWO</code> in compared to the stored variable <code>ONE</code> using * The input variable <code>TWO</code> in compared to the stored variable <code>ONE</code> using
* the supplied <code>comparator</code>. This is the default usage of the predicate and will return * the supplied <code>comparator</code>. This is the default usage of the predicate and will return
* <code>true</code> if the underlying comparator returns <code>0</code>. In addition to the default * <code>true</code> if the underlying comparator returns <code>0</code>. In addition to the default
* usage of the predicate, it is possible to evaluate the comparator's result in several ways. The * usage of the predicate, it is possible to evaluate the comparator's result in several ways. The
* following {@link Criterion} enumeration values are provided by the predicate: * following {@link Criterion} enumeration values are provided by the predicate:
* </p> * </p>
* *
* <ul> * <ul>
* <li>EQUAL</li> * <li>EQUAL</li>
* <li>GREATER</li> * <li>GREATER</li>
* <li>GREATER_OR_EQUAL</li> * <li>GREATER_OR_EQUAL</li>
* <li>LESS</li> * <li>LESS</li>
* <li>LESS_OR_EQUAL</li> * <li>LESS_OR_EQUAL</li>
* </ul> * </ul>
* *
* The following examples demonstrates how these constants can be used in order to manipulate the * The following examples demonstrates how these constants can be used in order to manipulate the
* evaluation of a comparator result. * evaluation of a comparator result.
* *
* <pre> * <pre>
* ComparatorPredicate.getInstance(ONE, comparator, <b>ComparatorPredicate.Criterion.GREATER</b>).evaluate(TWO); * ComparatorPredicate.getInstance(ONE, comparator, <b>ComparatorPredicate.Criterion.GREATER</b>).evaluate(TWO);
* </pre> * </pre>
* *
* The input variable TWO is compared to the stored variable ONE using the supplied <code>comparator</code> * The input variable TWO is compared to the stored variable ONE using the supplied <code>comparator</code>
* using the <code>GREATER</code> evaluation criterion constant. This instructs the predicate to * using the <code>GREATER</code> evaluation criterion constant. This instructs the predicate to
* return <code>true</code> if the comparator returns a value greater than <code>0</code>. * return <code>true</code> if the comparator returns a value greater than <code>0</code>.
* *
* @since Commons Collections 4.0 * @since Commons Collections 4.0
* @version $Revision$ * @version $Revision$
* *
* @author Rune Peter Bjørnstad. * @author Rune Peter Bjørnstad.
*/ */
public class ComparatorPredicate<T> implements Predicate<T>, Serializable { public class ComparatorPredicate<T> implements Predicate<T>, Serializable {
private static final long serialVersionUID = -1863209236504077399L; private static final long serialVersionUID = -1863209236504077399L;
public enum Criterion { public enum Criterion {
EQUAL, GREATER, LESS, GREATER_OR_EQUAL, LESS_OR_EQUAL, EQUAL, GREATER, LESS, GREATER_OR_EQUAL, LESS_OR_EQUAL,
} }
// Instance variables: // Instance variables:
/** The internal object to compare with */ /** The internal object to compare with */
private final T object; private final T object;
/** The comparator to use for comparison */ /** The comparator to use for comparison */
private final Comparator<T> comparator; private final Comparator<T> comparator;
/** The comparison evaluation criterion to use */ /** The comparison evaluation criterion to use */
private final Criterion criterion; private final Criterion criterion;
/** /**
* Factory to create the comparator predicate * Factory to create the comparator predicate
* *
* @param object the object to compare to * @param object the object to compare to
* @param comparator the comparator to use for comparison * @param comparator the comparator to use for comparison
* @return the predicate * @return the predicate
* @throws IllegalArgumentException if comparator is null * @throws IllegalArgumentException if comparator is null
*/ */
public static <T> Predicate<T> comparatorPredicate(T object, Comparator<T> comparator) { public static <T> Predicate<T> comparatorPredicate(T object, Comparator<T> comparator) {
return comparatorPredicate(object, comparator, Criterion.EQUAL); return comparatorPredicate(object, comparator, Criterion.EQUAL);
} }
/** /**
* Factory to create the comparator predicate * Factory to create the comparator predicate
* *
* @param object the object to compare to * @param object the object to compare to
* @param comparator the comparator to use for comparison * @param comparator the comparator to use for comparison
* @param criterion the criterion to use to evaluate comparison * @param criterion the criterion to use to evaluate comparison
* @return the predicate * @return the predicate
* @throws IllegalArgumentException if comparator is null of criterion is invalid * @throws IllegalArgumentException if comparator is null of criterion is invalid
*/ */
public static <T> Predicate<T> comparatorPredicate(T object, Comparator<T> comparator, Criterion criterion) { public static <T> Predicate<T> comparatorPredicate(T object, Comparator<T> comparator, Criterion criterion) {
if (comparator == null) { if (comparator == null) {
throw new IllegalArgumentException("Comparator must not be null."); throw new IllegalArgumentException("Comparator must not be null.");
} }
if (criterion == null) { if (criterion == null) {
throw new IllegalArgumentException("Criterion must not be null."); throw new IllegalArgumentException("Criterion must not be null.");
} }
return new ComparatorPredicate<T>(object, comparator, criterion); return new ComparatorPredicate<T>(object, comparator, criterion);
} }
/** /**
* Constructor that performs no validation. * Constructor that performs no validation.
* Use <code>getInstance</code> if you want. * Use <code>getInstance</code> if you want.
* *
* @param object the object to compare to * @param object the object to compare to
* @param comparator the comparator to use for comparison * @param comparator the comparator to use for comparison
* @param criterion the criterion to use to evaluate comparison * @param criterion the criterion to use to evaluate comparison
*/ */
public ComparatorPredicate(T object, Comparator<T> comparator, Criterion criterion) { public ComparatorPredicate(T object, Comparator<T> comparator, Criterion criterion) {
super(); super();
this.object = object; this.object = object;
this.comparator = comparator; this.comparator = comparator;
this.criterion = criterion; this.criterion = criterion;
} }
/** /**
* Evaluates the predicate. The predicate evaluates to <code>true</code> in the following cases: * Evaluates the predicate. The predicate evaluates to <code>true</code> in the following cases:
* *
* <ul> * <ul>
* <li><code>comparator.compare(object, input) == 0 && criterion == EQUAL</code></li> * <li><code>comparator.compare(object, input) == 0 && criterion == EQUAL</code></li>
* <li><code>comparator.compare(object, input) < 0 && criterion == LESS</code></li> * <li><code>comparator.compare(object, input) < 0 && criterion == LESS</code></li>
* <li><code>comparator.compare(object, input) > 0 && criterion == GREATER</code></li> * <li><code>comparator.compare(object, input) > 0 && criterion == GREATER</code></li>
* <li><code>comparator.compare(object, input) >= 0 && criterion == GREATER_OR_EQUAL</code></li> * <li><code>comparator.compare(object, input) >= 0 && criterion == GREATER_OR_EQUAL</code></li>
* <li><code>comparator.compare(object, input) <= 0 && criterion == LESS_OR_EQUAL</code></li> * <li><code>comparator.compare(object, input) <= 0 && criterion == LESS_OR_EQUAL</code></li>
* </ul> * </ul>
* *
* @see org.apache.commons.collections.Predicate#evaluate(java.lang.Object) * @see org.apache.commons.collections.Predicate#evaluate(java.lang.Object)
* @see java.util.Comparator#compare(java.lang.Object first, java.lang.Object second) * @see java.util.Comparator#compare(java.lang.Object first, java.lang.Object second)
* *
* @throws IllegalStateException if the criterion is invalid (really not possible) * @throws IllegalStateException if the criterion is invalid (really not possible)
*/ */
public boolean evaluate(T target) { public boolean evaluate(T target) {
boolean result = false; boolean result = false;
int comparison = comparator.compare(object, target); int comparison = comparator.compare(object, target);
switch (criterion) { switch (criterion) {
case EQUAL: case EQUAL:
result = (comparison == 0); result = (comparison == 0);
break; break;
case GREATER: case GREATER:
result = (comparison > 0); result = (comparison > 0);
break; break;
case LESS: case LESS:
result = (comparison < 0); result = (comparison < 0);
break; break;
case GREATER_OR_EQUAL: case GREATER_OR_EQUAL:
result = (comparison >= 0); result = (comparison >= 0);
break; break;
case LESS_OR_EQUAL: case LESS_OR_EQUAL:
result = (comparison <= 0); result = (comparison <= 0);
break; break;
default: default:
throw new IllegalStateException("The current criterion '" + criterion + "' is invalid."); throw new IllegalStateException("The current criterion '" + criterion + "' is invalid.");
} }
return result; return result;
} }
} }

View File

@ -1,148 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.collections.list.difference;
/** This interface should be implemented by user object to walk
* through {@link EditScript EditScript} objects.
* <p>Users should implement this interface in order to walk through
* the {@link EditScript EditScript} object created by the comparison
* of two sequences. This is a direct application of the visitor
* design pattern. The {@link EditScript#visit EditScript.visit}
* method takes an object implementing this interface as an argument,
* it will perform the loop over all commands in the script and the
* proper methods of the user class will be called as the commands are
* encountered.</p>
* <p>The implementation of the user visitor class will depend on the
* need. Here are two examples.
* </p>
*
* <p>
* The first example is a visitor that build the longest common
* subsequence:
* <pre>
* import org.apache.commons.collections.list.difference.CommandVisitor;
*
* import java.util.ArrayList;
*
* public class LongestCommonSubSequence implements CommandVisitor {
*
* public LongestCommonSubSequence() {
* a = new ArrayList();
* }
*
* public void visitInsertCommand(Object object) {
* }
*
* public void visitKeepCommand(Object object) {
* a.add(object);
* }
*
* public void visitDeleteCommand(Object object) {
* }
*
* public Object[] getSubSequence() {
* return a.toArray();
* }
*
* private arrayList a;
*
* }
* </pre>
* </p>
*
* <p>
* The second example is a visitor that shows the commands and the way
* they transform the first sequence into the second one:
* <pre>
* import org.apache.commons.collections.list.difference.CommandVisitor;
*
* import java.util.Arrays;
* import java.util.ArrayList;
* import java.util.Iterator;
*
* public class ShowVisitor implements CommandVisitor {
*
* public ShowVisitor(Object[] sequence1) {
* v = new ArrayList();
* v.addAll(Arrays.asList(sequence1));
* index = 0;
* }
*
* public void visitInsertCommand(Object object) {
* v.insertElementAt(object, index++);
* display("insert", object);
* }
*
* public void visitKeepCommand(Object object) {
* ++index;
* display("keep ", object);
* }
*
* public void visitDeleteCommand(Object object) {
* v.remove(index);
* display("delete", object);
* }
*
* private void display(String commandName, Object object) {
* System.out.println(commandName + " " + object + " ->" + this);
* }
*
* public String toString() {
* StringBuffer buffer = new StringBuffer();
* for (Iterator iter = v.iterator(); iter.hasNext();) {
* buffer.append(' ').append(iter.next());
* }
* return buffer.toString();
* }
*
* private ArrayList v;
* private int index;
*
* }
* </pre>
* </p>
* @since 4.0
* @author Jordane Sarda
* @author Luc Maisonobe
* @version $Id$
*/
public interface CommandVisitor<T> {
/** Method called when an insert command is encountered.
* @param object object to insert (this object comes from the
* second sequence)
*/
void visitInsertCommand(T object);
/** Method called when a keep command is encountered.
* @param object object to keep (this object comes from the
* first sequence)
*/
void visitKeepCommand(T object);
/** Method called when a delete command is encountered.
* @param object object to delete (this object comes from the
* first sequence)
*/
void visitDeleteCommand(T object);
}

View File

@ -1,56 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.collections.list.difference;
/** Command representing the deletion of one object of the first sequence.
* When one object of the first sequence has no corresponding object
* in the second sequence at the right place, the {@link EditScript
* edit script} transforming the first sequence into the second
* sequence uses an instance of this class to represent the deletion
* of this object. The objects embedded in these type of commands
* always come from the first sequence.
* @see SequencesComparator
* @see EditScript
* @since 4.0
* @author Jordane Sarda
* @author Luc Maisonobe
* @version $Id$
*/
public class DeleteCommand<T> extends EditCommand<T> {
/** Simple constructor.
* Creates a new instance of DeleteCommand
* @param object the object of the first sequence that should be deleted
*/
public DeleteCommand(T object) {
super(object);
}
/** Accept a visitor.
* When a <code>DeleteCommand</code> accepts a visitor, it calls
* its {@link CommandVisitor#visitDeleteCommand
* visitDeleteCommand} method.
* @param visitor the visitor to be accepted
*/
public void accept(CommandVisitor<T> visitor) {
visitor.visitDeleteCommand(object);
}
}

View File

@ -1,76 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.collections.list.difference;
/** Abstract base class for all commands used to transform an objects
* sequence into another one.
* <p>When two objects sequences are compared through the {@link
* SequencesComparator#getScript SequencesComparator.getScript}
* method, the result is provided has a {@link EditScript script}
* containing the commands that progressively transform the first
* sequence into the second one.</p>
* <p>There are only three types of commands, all of which are
* subclasses of this abstract class. Each command is associated with
* one object belonging to at least one of the sequences. These
* commands are {@link InsertCommand InsertCommand} which correspond
* to an object of the second sequence beeing inserted into the first
* sequence, {@link DeleteCommand DeleteCommand} which correspond to
* an object of the first sequence beeing removed and {@link
* KeepCommand KeepCommand} which correspond to an object of the first
* sequence which <code>equals</code> an object in the second
* sequence. It is guaranteed that comparison is always performed this
* way (i.e. the <code>equals</code> method of the object from the
* first sequence is used and the object passed as an argument comes
* from the second sequence) ; this can be important if subclassing is
* used for some elements in the first sequence and the
* <code>equals</code> method is specialized.</p>
* @see SequencesComparator
* @see EditScript
* @since 4.0
* @author Jordane Sarda
* @author Luc Maisonobe
* @version $Id$
*/
public abstract class EditCommand<T> {
/** Simple constructor.
* Creates a new instance of EditCommand
* @param object reference to the object associated with this
* command, this refers to an element of one of the sequences
* beeing compared
*/
protected EditCommand(T object) {
this.object = object;
}
/** Accept a visitor.
* This method is invoked for each commands belonging to an {@link
* EditScript EditScript}, in order to implement the visitor
* design pattern
* @param visitor the visitor to be accepted
*/
public abstract void accept(CommandVisitor<T> visitor);
/** Object on which the command should be applied. */
protected T object;
}

View File

@ -1,126 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.collections.list.difference;
import java.util.ArrayList;
import java.util.List;
/**
* This class gathers all the {@link EditCommand commands} needed to
* transform one objects sequence into another objects sequence.
* <p>An edit script is the most general view of the differences
* between two sequences. It is built as the result of the comparison
* between two sequences by the {@link SequencesComparator
* SequencesComparator} class. The user can walk through it using
* the <em>visitor</em> design pattern.</p>
* <p>It is guaranteed that the objects embedded in the {@link
* InsertCommand insert commands} come from the second sequence and
* that the objects embedded in either the {@link DeleteCommand delete
* commands} or {@link KeepCommand keep commands} come from the first
* sequence. This can be important if subclassing is used for some
* elements in the first sequence and the <code>equals</code> method
* is specialized.</p>
* @see SequencesComparator
* @see EditCommand
* @see CommandVisitor
* @see ReplacementsHandler
*
* @since 4.0
* @author Jordane Sarda
* @author Luc Maisonobe
* @version $Id$
*/
public class EditScript<T> {
/** Container for the commands. */
private List<EditCommand<T>> commands;
/** Length of the longest common subsequence. */
private int lcsLength;
/** Number of modifications. */
private int modifications;
/** Simple constructor.
* Creates a new empty script.
*/
public EditScript() {
commands = new ArrayList<EditCommand<T>>();
lcsLength = 0;
modifications = 0;
}
/** Add a keep command to the script.
* @param command command to add
*/
public void append(KeepCommand<T> command) {
commands.add(command);
++lcsLength;
}
/** Add an insert command to the script.
* @param command command to add
*/
public void append(InsertCommand<T> command) {
commands.add(command);
++modifications;
}
/** Add a delete command to the script.
* @param command command to add
*/
public void append(DeleteCommand<T> command) {
commands.add(command);
++modifications;
}
/** Visit the script.
* The script implements the <em>visitor</em> design pattern, this
* method is the entry point to which the user supplies its own
* visitor, the script will be responsible to drive it through the
* commands in order and call the appropriate method as each
* command is encountered.
* @param visitor the visitor that will visit all commands in turn
*/
public void visit(CommandVisitor<T> visitor) {
for (EditCommand<T> command : commands) {
command.accept(visitor);
}
}
/** Get the length of the Longest Common Subsequence (LCS).
* The length of the longest common subsequence is the number of
* {@link KeepCommand keep commands} in the script.
* @return length of the Longest Common Subsequence
*/
public int getLCSLength() {
return lcsLength;
}
/** Get the number of effective modifications.
* The number of effective modification is the number of {@link
* DeleteCommand delete} and {@link InsertCommand insert} commands
* in the script.
* @return number of effective modifications
*/
public int getModifications() {
return modifications;
}
}

View File

@ -1,57 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.collections.list.difference;
/** Command representing the insertion of one object of the second sequence.
* When one object of the second sequence has no corresponding object
* in the first sequence at the right place, the {@link EditScript
* edit script} transforming the first sequence into the second
* sequence uses an instance of this class to represent the insertion
* of this object. The objects embedded in these type of commands
* always come from the second sequence.
* @see SequencesComparator
* @see EditScript
* @since 4.0
* @author Jordane Sarda
* @author Luc Maisonobe
* @version $Id$
*/
public class InsertCommand<T> extends EditCommand<T> {
/** Simple constructor.
* Creates a new instance of InsertCommand
* @param object the object of the second sequence that should be inserted
*/
public InsertCommand(T object) {
super(object);
}
/** Accept a visitor.
* When an <code>InsertCommand</code> accepts a visitor, it calls
* its {@link CommandVisitor#visitInsertCommand
* visitInsertCommand} method.
* @param visitor the visitor to be accepted
*/
public void accept(CommandVisitor<T> visitor) {
visitor.visitInsertCommand(object);
}
}

View File

@ -1,58 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.collections.list.difference;
/** Command representing the keeping of one object present in both sequences.
* When one object of the first sequence <code>equals</code> another
* objects in the second sequence at the right place, the {@link
* EditScript edit script} transforming the first sequence into the
* second sequence uses an instance of this class to represent the
* keeping of this object. The objects embedded in these type of
* commands always come from the first sequence.
* @see SequencesComparator
* @see EditScript
* @since 4.0
* @author Jordane Sarda
* @author Luc Maisonobe
* @version $Id$
*/
public class KeepCommand<T> extends EditCommand<T> {
/** Simple constructor.
* Creates a new instance of KeepCommand
* @param object the object belonging to both sequences (the
* object is a reference to the instance in the first sequence
* which is known to be equal to an instance in the second
* sequence)
*/
public KeepCommand(T object) {
super(object);
}
/** Accept a visitor.
* When a <code>KeepCommand</code> accepts a visitor, it calls
* its {@link CommandVisitor#visitKeepCommand visitKeepCommand} method.
* @param visitor the visitor to be accepted
*/
public void accept(CommandVisitor<T> visitor) {
visitor.visitKeepCommand(object);
}
}

View File

@ -1,107 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.collections.list.difference;
import java.util.ArrayList;
import java.util.List;
/**
* This class handles sequences of replacements resulting from a
* comparison.
* <p>The comparison of two objects sequences leads to the
* identification of common parts and parts which only belong to the
* first or to the second sequence. The common parts appear in the
* edit script in the form of <em>keep</em> commands, they can be considered
* as synchronization objects between the two sequences. These
* synchronization objects split the two sequences in synchronized
* sub-sequences. The first sequence can be transformed into the second
* one by replacing each synchronized sub-sequence of the first
* sequence by the corresponding sub-sequence of the second
* sequence. This is a synthetic way to see an {@link EditScript edit
* script}, replacing individual {@link DeleteCommand delete}, {@link
* KeepCommand keep} and {@link InsertCommand insert} commands by
* fewer replacements acting on complete sub-sequences.</p>
* <p>This class is devoted to perform this interpretation. It visits
* an {@link EditScript edit script} (because it implements the {@link
* CommandVisitor CommandVisitor} interface) and calls a user-supplied
* handler implementing the {@link ReplacementsHandler
* ReplacementsHandler} interface to process the sub-sequences.</p>
* @see ReplacementsHandler
* @see EditScript
* @see SequencesComparator
* @since 4.0
* @author Luc Maisonobe
* @author Jordane Sarda
* @version $Id$
*/
public class ReplacementsFinder<T> implements CommandVisitor<T> {
private List<T> pendingInsertions;
private List<T> pendingDeletions;
private int skipped;
/** Handler to call when synchronized sequences are found. */
private ReplacementsHandler<T> handler;
/** Simple constructor.
* Creates a new instance of ReplacementsFinder
* @param handler handler to call when synchronized sequences are
* found
*/
public ReplacementsFinder(ReplacementsHandler<T> handler) {
pendingInsertions = new ArrayList<T>();
pendingDeletions = new ArrayList<T>();
skipped = 0;
this.handler = handler;
}
/** Add an object to the pending insertions set.
* @param object object to insert
*/
public void visitInsertCommand(T object) {
pendingInsertions.add(object);
}
/** Handle a synchronization object.
* <p>When a synchronization object is identified, the pending
* insertions and pending deletions sets are provided to the user
* handler as subsequences.</p>
* @param object synchronization object detected
*/
public void visitKeepCommand(T object) {
if (pendingDeletions.isEmpty() && pendingInsertions.isEmpty()) {
++skipped;
} else {
handler.handleReplacement(skipped, pendingDeletions, pendingInsertions);
pendingDeletions.clear();
pendingInsertions.clear();
skipped = 1;
}
}
/** Add an object to the pending deletions set.
* @param object object to delete
*/
public void visitDeleteCommand(T object) {
pendingDeletions.add(object);
}
}

View File

@ -1,48 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.collections.list.difference;
import java.util.List;
/** This interface is devoted to handle synchronized replacement sequences.
* @see ReplacementsFinder
* @since 4.0
* @author Luc Maisonobe
* @version $Id$
*/
public interface ReplacementsHandler<T> {
/** Handle two synchronized sequences.
* <p>This method is called by a {@link ReplacementsFinder
* ReplacementsFinder} instance when it has synchronized two
* sub-sequences of object arrays being compared, and at least one
* of the sequences is non-empty. Since the sequences are
* synchronized, the objects before the two sub-sequences are equals
* (if they exist). This property also holds for the objects after the
* two sub-sequences.</p>
* <p>The replacement is defined as replacing the <code>from</code>
* sub-sequence into the <code>to</code> sub-sequence.</p>
* @param skipped number of tokens skipped since the last call (i.e.
* number of tokens that were in both sequences), this number should
* be strictly positive except on the very first call where it can be
* zero (if the first object of the two sequences are different)
* @param from sub-sequence of objects coming from the first sequence
* @param to sub-sequence of objects coming from the second sequence
*/
public void handleReplacement(int skipped, List<T> from, List<T> to);
}

View File

@ -1,265 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.collections.list.difference;
import java.util.List;
/**
* This class allows to compare two objects sequences.
* <p>The two sequences can hold any object type, as only the
* <code>equals</code> method is used to compare the elements of the
* sequences. It is guaranteed that the comparisons will always be
* done as <code>o1.equals(o2)</code> where <code>o1</code> belongs to
* the first sequence and <code>o2</code> belongs to the second
* sequence. This can be important if subclassing is used for some
* elements in the first sequence and the <code>equals</code> method
* is specialized.</p>
* <p>Comparison can be seen from two points of view: either as
* giving the smallest modification allowing to transform the first
* sequence into the second one, or as giving the longest sequence
* which is a subsequence of both initial sequences. The
* <code>equals</code> method is used to compare objects, so any
* object can be put into sequences. Modifications include deleting,
* inserting or keeping one object, starting from the beginning of the
* first sequence.</p>
* <p>This class implements the comparison algorithm, which is the
* very efficient algorithm from Eugene W. Myers <a
* href="http://www.cis.upenn.edu/~bcpierce/courses/dd/papers/diff.ps">An
* O(ND) Difference Algorithm and Its Variations</a>. This algorithm
* produces the shortest possible {@link
* org.apache.commons.collections.list.difference.EditScript edit script}
* containing all the {@link
* org.apache.commons.collections.list.difference.EditCommand commands} needed to
* transform the first sequence into the second one.</p>
* @see EditScript
* @see EditCommand
* @see CommandVisitor
* @since 4.0
* @author Jordane Sarda
* @version $Id$
*/
public class SequencesComparator<T> {
/** First sequence. */
private List<T> sequence1;
/** Second sequence. */
private List<T> sequence2;
/** Temporary variables. */
private int[] vDown;
private int[] vUp;
/** Simple constructor.
* <p>Creates a new instance of SequencesComparator</p>
* <p>It is <em>guaranteed</em> that the comparisons will always be
* done as <code>o1.equals(o2)</code> where <code>o1</code> belongs
* to the first sequence and <code>o2</code> belongs to the second
* sequence. This can be important if subclassing is used for some
* elements in the first sequence and the <code>equals</code> method
* is specialized.</p>
* @param sequence1 first sequence to be compared
* @param sequence2 second sequence to be compared
*/
public SequencesComparator(List<T> sequence1, List<T> sequence2) {
this.sequence1 = sequence1;
this.sequence2 = sequence2;
int size = sequence1.size() + sequence2.size() + 2;
vDown = new int[size];
vUp = new int[size];
}
/** Build a snake.
* @param start the value of the start of the snake
* @param diag the value of the diagonal of the snake
* @param end1 the value of the end of the first sequence to be compared
* @param end2 the value of the end of the second sequence to be compared
* @return the snake built
*/
private Snake buildSnake(int start, int diag, int end1, int end2) {
int end = start;
while (((end - diag) < end2)
&& (end < end1)
&& sequence1.get(end).equals(sequence2.get(end - diag))) {
++end;
}
return new Snake(start, end, diag);
}
/** Get the middle snake corresponding to two subsequences of the
* main sequences.
* The snake is found using the MYERS Algorithm (this algorithms has
* also been implemented in the GNU diff program). This algorithm is
* explained in Eugene Myers article: <a
* href="http://www.cs.arizona.edu/people/gene/PAPERS/diff.ps">An
* O(ND) Difference Algorithm and Its Variations</a>.
* @param start1 the begin of the first sequence to be compared
* @param end1 the end of the first sequence to be compared
* @param start2 the begin of the second sequence to be compared
* @param end2 the end of the second sequence to be compared
* @return the middle snake
*/
private Snake getMiddleSnake(int start1, int end1, int start2, int end2) {
// Myers Algorithm
//Initialisations
int m = end1 - start1;
int n = end2 - start2;
if ((m == 0) || (n == 0)) {
return null;
}
int delta = m - n;
int sum = n + m;
int offset = ((sum % 2 == 0) ? sum : (sum + 1)) / 2;
vDown[1+offset] = start1;
vUp[1+offset] = end1 + 1;
for (int d = 0; d <= offset ; ++d) {
// Down
for (int k = -d; k <= d; k += 2) {
// First step
int i = k + offset;
if ((k == -d) || ((k != d) && (vDown[i-1] < vDown[i+1]))) {
vDown[i] = vDown[i+1];
} else {
vDown[i] = vDown[i-1] + 1;
}
int x = vDown[i];
int y = x - start1 + start2 - k;
while ((x < end1) && (y < end2) && (sequence1.get(x).equals(sequence2.get(y)))) {
vDown[i] = ++x;
++y;
}
// Second step
if (((delta % 2) != 0 ) && ((delta - d) <= k) && (k <= (delta + d))) {
if (vUp[i-delta] <= vDown[i]) {
return buildSnake(vUp[i-delta], k + start1 - start2, end1, end2);
}
}
}
// Up
for (int k = (delta - d); k <= (delta + d); k += 2) {
// First step
int i = k + offset - delta;
if ((k == (delta - d))
|| ((k != (delta + d)) && (vUp[i+1] <= vUp[i-1]))) {
vUp[i] = vUp[i+1] - 1;
} else {
vUp[i] = vUp[i-1];
}
int x = vUp[i] - 1;
int y = x - start1 + start2 - k;
while ((x >= start1) && (y >= start2)
&& sequence1.get(x).equals(sequence2.get(y))) {
vUp[i] = x--;
y--;
}
// Second step
if (((delta % 2) == 0) && (-d <= k) && (k <= d) ) {
if (vUp[i] <= vDown[i + delta]) {
return buildSnake(vUp[i], k + start1 - start2, end1, end2);
}
}
}
}
// this should not happen
throw new RuntimeException("Internal Error");
}
/** Build an edit script.
* @param start1 the begin of the first sequence to be compared
* @param end1 the end of the first sequence to be compared
* @param start2 the begin of the second sequence to be compared
* @param end2 the end of the second sequence to be compared
* @param script the edited script
*/
private void buildScript(int start1, int end1, int start2, int end2,
EditScript<T> script) {
Snake middle = getMiddleSnake(start1, end1, start2, end2);
if ((middle == null)
|| ((middle.getStart() == end1) && (middle.getDiag() == (end1 - end2)))
|| ((middle.getEnd() == start1) && (middle.getDiag() == (start1 - start2)))) {
int i = start1;
int j = start2;
while ((i < end1) || (j < end2)) {
if ((i < end1) && (j < end2) && sequence1.get(i).equals(sequence2.get(j))) {
script.append(new KeepCommand<T>(sequence1.get(i)));
++i;
++j;
} else {
if ((end1 - start1) > (end2 - start2)) {
script.append(new DeleteCommand<T>(sequence1.get(i)));
++i;
} else {
script.append(new InsertCommand<T>(sequence2.get(j)));
++j;
}
}
}
} else {
buildScript(start1, middle.getStart(),
start2, middle.getStart() - middle.getDiag(),
script);
for (int i = middle.getStart(); i < middle.getEnd(); ++i) {
script.append(new KeepCommand<T>(sequence1.get(i)));
}
buildScript(middle.getEnd(), end1,
middle.getEnd() - middle.getDiag(), end2,
script);
}
}
/** Get the edit script script.
* <p>It is guaranteed that the objects embedded in the {@link
* InsertCommand insert commands} come from the second sequence and
* that the objects embedded in either the {@link DeleteCommand
* delete commands} or {@link KeepCommand keep commands} come from
* the first sequence. This can be important if subclassing is used
* for some elements in the first sequence and the
* <code>equals</code> method is specialized.</p>
* @return the edit script resulting from the comparison of the two
* sequences
*/
public EditScript<T> getScript() {
EditScript<T> script = new EditScript<T>();
buildScript(0, sequence1.size(), 0, sequence2.size(), script);
return script;
}
}

View File

@ -1,86 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.collections.list.difference;
/**
* This class is a simple placeholder to hold the end part of a path
* under construction in a {@link SequencesComparator
* SequencesComparator}.
* <p>A snake is an internal structure used in Eugene W. Myers
* algorithm (<a
* href="http://www.cis.upenn.edu/~bcpierce/courses/dd/papers/diff.ps">An
* O(ND) Difference Algorithm and Its Variations</a>).</p>
* @since 4.0
* @author Jordane Sarda
* @version $Id$
*/
public class Snake {
/** Start index. */
private int start;
/** End index. */
private int end;
/** Diagonal number. */
private int diag;
/** Simple constructor.
* Creates a new instance of Snake with default indices
*/
public Snake() {
start = -1;
end = -1;
diag = 0;
}
/** Simple constructor.
* Creates a new instance of Snake with specified indices
* @param start start index of the snake
* @param end end index of the snake
* @param diag diagonal number
*/
public Snake(int start, int end, int diag) {
this.start = start;
this.end = end;
this.diag = diag;
}
/** Get the start index of the snake.
* @return start index of the snake
*/
public int getStart() {
return start;
}
/** Get the end index of the snake.
* @return end index of the snake
*/
public int getEnd() {
return end;
}
/** Get the diagonal number of the snake.
* @return diagonal number of the snake
*/
public int getDiag() {
return diag;
}
}

View File

@ -1,93 +0,0 @@
<!-- $Id$ -->
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<body>
This package provides classes to compare two objects sequences.
<p>
The two sequences can hold any object type, as only the
<code>equals</code> method is used to compare the elements of the
sequences. It is guaranteed that the comparisons will always be done
as <code>o1.equals(o2)</code> where <code>o1</code> belongs to the
first sequence and <code>o2</code> belongs to the second
sequence. This can be important if subclassing is used for some
elements in the first sequence and the <code>equals</code> method is
specialized.
</p>
<p>
Comparison can be seen from two points of view: either as giving the
smallest modification allowing to transform the first sequence into
the second one, or as giving the longest sequence which is a
subsequence of both initial sequences. The <code>equals</code> method
is used to compare objects, so any object can be put into
sequences. Modifications include deleting, inserting or keeping one
object, starting from the beginning of the first sequence. Like most
algorithms of the same type, objects transpositions are not
supported. This means that if a sequence <code>(A, B)</code> is
compared to <code>(B, A)</code>, the result will be either the
sequence of three commands <code>delete A</code>, <code>keep B</code>,
<code>insert A</code> or the sequence <code>insert B</code>,
<code>keep A</code>, <code>delete B</code>.
</p>
<p>
The package uses a very efficient comparison algorithm designed by
Eugene W. Myers and described in his paper: <a
href="http://www.cis.upenn.edu/~bcpierce/courses/dd/papers/diff.ps">An O(ND)
Difference Algorithm and Its Variations</a>. This algorithm produces
the shortest possible {@link
org.apache.commons.collections.list.difference.EditScript edit script} containing
all the {@link org.apache.commons.collections.list.difference.EditCommand
commands} needed to transform the first sequence into the second
one. The entry point for the user to this algorithm is the {@link
org.apache.commons.collections.list.difference.SequencesComparator
SequencesComparator} class.
</p>
<p>
As explained in Gene Myers paper, the edit script is equivalent to all
other representations and contains all the needed information either
to perform the transformation, of course, or to retrieve the longest
common subsequence for example.
</p>
<p>
If the user needs a very fine grained access to the comparison result,
he needs to go through this script by providing a visitor implementing
the {@link org.apache.commons.collections.list.difference.CommandVisitor
CommandVisitor} interface.
</p>
<p>
Sometimes however, a more synthetic approach is needed. If the user
prefers to see the differences between the two sequences as global
<code>replacement</code> operations acting on complete subsequences of
the original sequences, he will provide an object implementing the
simple {@link org.apache.commons.collections.list.difference.ReplacementsHandler
ReplacementsHandler} interface, using an instance of the {@link
org.apache.commons.collections.list.difference.ReplacementsFinder
ReplacementsFinder} class as a command converting layer between his
object and the edit script. The number of objects which are common to
both initial arrays and hence are skipped between each call to the user
{@link
org.apache.commons.collections.list.difference.ReplacementsHandler#handleReplacement
handleReplacement} method is also provided. This allows the user to keep
track of the current index in both arrays if he needs so.
</p>
</body>

View File

@ -1,38 +1,38 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with * (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.commons.collections; package org.apache.commons.collections;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import org.junit.Before; import org.junit.Before;
public abstract class AbstractDecoratedCollectionTest<C> { public abstract class AbstractDecoratedCollectionTest<C> {
/** /**
* The {@link Collection} being decorated. * The {@link Collection} being decorated.
*/ */
protected Collection<C> original; protected Collection<C> original;
/** /**
* The Collection under test that decorates {@link #original}. * The Collection under test that decorates {@link #original}.
*/ */
protected Collection<C> decorated; protected Collection<C> decorated;
@Before @Before
public void setUpDecoratedCollection() throws Exception { public void setUpDecoratedCollection() throws Exception {
original = new ArrayList<C>(); original = new ArrayList<C>();
} }
} }

View File

@ -1,67 +1,67 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with * (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.commons.collections; package org.apache.commons.collections;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.ListIterator; import java.util.ListIterator;
import org.easymock.EasyMock; import org.easymock.EasyMock;
import org.easymock.IExpectationSetters; import org.easymock.IExpectationSetters;
/** /**
* Provides utilities for making mock-based tests. Most notable is the generic "type-safe" * Provides utilities for making mock-based tests. Most notable is the generic "type-safe"
* {@link #createMock(Class)} method, and {@link #replay()} and {@link #verify()} methods * {@link #createMock(Class)} method, and {@link #replay()} and {@link #verify()} methods
* that call the respective methods on all created mock objects. * that call the respective methods on all created mock objects.
* *
* @author Stephen Kestle * @author Stephen Kestle
*/ */
public abstract class MockTestCase { public abstract class MockTestCase {
private List<Object> mockObjects = new ArrayList<Object>(); private List<Object> mockObjects = new ArrayList<Object>();
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected <T> T createMock(Class<?> name) { protected <T> T createMock(Class<?> name) {
T mock = (T) EasyMock.createMock(name); T mock = (T) EasyMock.createMock(name);
return registerMock(mock); return registerMock(mock);
} }
private <T> T registerMock(T mock) { private <T> T registerMock(T mock) {
mockObjects.add(mock); mockObjects.add(mock);
return mock; return mock;
} }
protected <T> IExpectationSetters<T> expect(T t) { protected <T> IExpectationSetters<T> expect(T t) {
return EasyMock.expect(t); return EasyMock.expect(t);
} }
protected final void replay() { protected final void replay() {
for (Object o : mockObjects) { for (Object o : mockObjects) {
EasyMock.replay(o); EasyMock.replay(o);
} }
} }
protected final void verify() { protected final void verify() {
for (ListIterator<Object> i = mockObjects.listIterator(); i.hasNext();) { for (ListIterator<Object> i = mockObjects.listIterator(); i.hasNext();) {
try { try {
EasyMock.verify(i.next()); EasyMock.verify(i.next());
} catch (AssertionError e) { } catch (AssertionError e) {
throw new AssertionError((i.previousIndex() + 1) + "" throw new AssertionError((i.previousIndex() + 1) + ""
+ e.getMessage()); + e.getMessage());
} }
} }
} }
} }

View File

@ -1,90 +1,90 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with * (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.commons.collections; package org.apache.commons.collections;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertNull;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@SuppressWarnings("boxing") @SuppressWarnings("boxing")
public class TestIndexedCollection extends AbstractDecoratedCollectionTest<String> { public class TestIndexedCollection extends AbstractDecoratedCollectionTest<String> {
private IndexedCollection<Integer, String> indexed; private IndexedCollection<Integer, String> indexed;
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
indexed = IndexedCollection.uniqueIndexedCollection(original, new Transformer<String, Integer>() { indexed = IndexedCollection.uniqueIndexedCollection(original, new Transformer<String, Integer>() {
public Integer transform(String input) { public Integer transform(String input) {
return Integer.parseInt(input); return Integer.parseInt(input);
} }
}); });
decorated = indexed; decorated = indexed;
} }
@Test @Test
public void addedObjectsCanBeRetrievedByKey() throws Exception { public void addedObjectsCanBeRetrievedByKey() throws Exception {
decorated.add("12"); decorated.add("12");
decorated.add("16"); decorated.add("16");
decorated.add("1"); decorated.add("1");
decorated.addAll(asList("2","3","4")); decorated.addAll(asList("2","3","4"));
assertEquals("12", indexed.get(12)); assertEquals("12", indexed.get(12));
assertEquals("16", indexed.get(16)); assertEquals("16", indexed.get(16));
assertEquals("1", indexed.get(1)); assertEquals("1", indexed.get(1));
assertEquals("2", indexed.get(2)); assertEquals("2", indexed.get(2));
assertEquals("3", indexed.get(3)); assertEquals("3", indexed.get(3));
assertEquals("4", indexed.get(4)); assertEquals("4", indexed.get(4));
} }
@Test(expected=IllegalArgumentException.class) @Test(expected=IllegalArgumentException.class)
public void ensureDuplicateObjectsCauseException() throws Exception { public void ensureDuplicateObjectsCauseException() throws Exception {
decorated.add("1"); decorated.add("1");
decorated.add("1"); decorated.add("1");
} }
@Test @Test
public void decoratedCollectionIsIndexedOnCreation() throws Exception { public void decoratedCollectionIsIndexedOnCreation() throws Exception {
original.add("1"); original.add("1");
original.add("2"); original.add("2");
original.add("3"); original.add("3");
indexed = IndexedCollection.uniqueIndexedCollection(original, new Transformer<String, Integer>() { indexed = IndexedCollection.uniqueIndexedCollection(original, new Transformer<String, Integer>() {
public Integer transform(String input) { public Integer transform(String input) {
return Integer.parseInt(input); return Integer.parseInt(input);
} }
}); });
assertEquals("1", indexed.get(1)); assertEquals("1", indexed.get(1));
assertEquals("2", indexed.get(2)); assertEquals("2", indexed.get(2));
assertEquals("3", indexed.get(3)); assertEquals("3", indexed.get(3));
} }
@Test @Test
public void reindexUpdatesIndexWhenTheDecoratedCollectionIsModifiedSeparately() throws Exception { public void reindexUpdatesIndexWhenTheDecoratedCollectionIsModifiedSeparately() throws Exception {
original.add("1"); original.add("1");
original.add("2"); original.add("2");
original.add("3"); original.add("3");
assertNull(indexed.get(1)); assertNull(indexed.get(1));
assertNull(indexed.get(2)); assertNull(indexed.get(2));
assertNull(indexed.get(3)); assertNull(indexed.get(3));
indexed.reindex(); indexed.reindex();
assertEquals("1", indexed.get(1)); assertEquals("1", indexed.get(1));
assertEquals("2", indexed.get(2)); assertEquals("2", indexed.get(2));
assertEquals("3", indexed.get(3)); assertEquals("3", indexed.get(3));
} }
} }

View File

@ -1,35 +1,35 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with * (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.commons.collections.functors; package org.apache.commons.collections.functors;
import org.apache.commons.collections.Closure; import org.apache.commons.collections.Closure;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
public abstract class BasicClosureTestBase { public abstract class BasicClosureTestBase {
@Test @Test
public void closureSanityTests() throws Exception { public void closureSanityTests() throws Exception {
Closure<?> closure = generateClosure(); Closure<?> closure = generateClosure();
Assert.assertNotNull(closure); Assert.assertNotNull(closure);
} }
/** /**
* @return a closure for general sanity tests. * @return a closure for general sanity tests.
*/ */
protected abstract <T> Closure<T> generateClosure(); protected abstract <T> Closure<T> generateClosure();
} }

View File

@ -1,93 +1,93 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with * (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.commons.collections.functors; package org.apache.commons.collections.functors;
import java.io.IOException; import java.io.IOException;
import org.apache.commons.collections.Closure; import org.apache.commons.collections.Closure;
import org.apache.commons.collections.FunctorException; import org.apache.commons.collections.FunctorException;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
public class TestCatchAndRethrowClosure extends BasicClosureTestBase { public class TestCatchAndRethrowClosure extends BasicClosureTestBase {
private static <T> Closure<T> generateIOExceptionClosure() { private static <T> Closure<T> generateIOExceptionClosure() {
return new CatchAndRethrowClosure<T>() { return new CatchAndRethrowClosure<T>() {
@Override @Override
protected void executeAndThrow(T input) throws IOException { protected void executeAndThrow(T input) throws IOException {
throw new IOException(); throw new IOException();
} }
}; };
} }
private static <T> Closure<T> generateNullPointerExceptionClosure() { private static <T> Closure<T> generateNullPointerExceptionClosure() {
return new CatchAndRethrowClosure<T>() { return new CatchAndRethrowClosure<T>() {
@Override @Override
protected void executeAndThrow(T input) { protected void executeAndThrow(T input) {
throw new NullPointerException(); throw new NullPointerException();
} }
}; };
} }
private static <T> Closure<T> generateNoExceptionClosure() { private static <T> Closure<T> generateNoExceptionClosure() {
return new CatchAndRethrowClosure<T>() { return new CatchAndRethrowClosure<T>() {
@Override @Override
protected void executeAndThrow(T input) { protected void executeAndThrow(T input) {
} }
}; };
} }
@Override @Override
protected <T> Closure<T> generateClosure() { protected <T> Closure<T> generateClosure() {
return generateNoExceptionClosure(); return generateNoExceptionClosure();
} }
@Test @Test
public void testThrowingClosure() { public void testThrowingClosure() {
Closure<Integer> closure = generateNoExceptionClosure(); Closure<Integer> closure = generateNoExceptionClosure();
try { try {
closure.execute(Integer.valueOf(0)); closure.execute(Integer.valueOf(0));
} catch (FunctorException ex) { } catch (FunctorException ex) {
Assert.fail(); Assert.fail();
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
Assert.fail(); Assert.fail();
} }
closure = generateIOExceptionClosure(); closure = generateIOExceptionClosure();
try { try {
closure.execute(Integer.valueOf(0)); closure.execute(Integer.valueOf(0));
Assert.fail(); Assert.fail();
} catch (FunctorException ex) { } catch (FunctorException ex) {
Assert.assertTrue(ex.getCause() instanceof IOException); Assert.assertTrue(ex.getCause() instanceof IOException);
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
Assert.fail(); Assert.fail();
} }
closure = generateNullPointerExceptionClosure(); closure = generateNullPointerExceptionClosure();
try { try {
closure.execute(Integer.valueOf(0)); closure.execute(Integer.valueOf(0));
Assert.fail(); Assert.fail();
} catch (FunctorException ex) { } catch (FunctorException ex) {
Assert.fail(); Assert.fail();
} catch (RuntimeException ex) { } catch (RuntimeException ex) {
Assert.assertTrue(ex instanceof NullPointerException); Assert.assertTrue(ex instanceof NullPointerException);
} }
} }
} }

View File

@ -1,82 +1,82 @@
/* /*
* Licensed to the Apache Software Foundation (ASF) under one or more * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with * contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. * this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 * The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with * (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at * the License. You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.commons.collections.functors; package org.apache.commons.collections.functors;
import static org.apache.commons.collections.functors.ComparatorPredicate.*; import static org.apache.commons.collections.functors.ComparatorPredicate.*;
import java.util.Comparator; import java.util.Comparator;
import org.apache.commons.collections.Predicate; import org.apache.commons.collections.Predicate;
import org.junit.Test; import org.junit.Test;
public class TestComparatorPredicate extends BasicPredicateTestBase { public class TestComparatorPredicate extends BasicPredicateTestBase {
private class TestComparator<T extends Comparable<T>> implements Comparator<T> { private class TestComparator<T extends Comparable<T>> implements Comparator<T> {
public int compare(T first, T second) { public int compare(T first, T second) {
return first.compareTo(second); return first.compareTo(second);
} }
} }
@Test @Test
public void compareEquals() { public void compareEquals() {
Integer value = Integer.valueOf(10); Integer value = Integer.valueOf(10);
Predicate<Integer> p = comparatorPredicate(value, new TestComparator<Integer>()); Predicate<Integer> p = comparatorPredicate(value, new TestComparator<Integer>());
assertFalse(p, Integer.valueOf(value.intValue() - 1)); assertFalse(p, Integer.valueOf(value.intValue() - 1));
assertTrue(p, Integer.valueOf(value.intValue())); assertTrue(p, Integer.valueOf(value.intValue()));
assertFalse(p, Integer.valueOf(value.intValue() + 1)); assertFalse(p, Integer.valueOf(value.intValue() + 1));
} }
@Test @Test
public void compareGreater() { public void compareGreater() {
Integer value = Integer.valueOf(10); Integer value = Integer.valueOf(10);
Predicate<Integer> p = comparatorPredicate(value, new TestComparator<Integer>(), Criterion.GREATER); Predicate<Integer> p = comparatorPredicate(value, new TestComparator<Integer>(), Criterion.GREATER);
assertTrue(p, Integer.valueOf(value.intValue() - 1)); assertTrue(p, Integer.valueOf(value.intValue() - 1));
assertFalse(p, Integer.valueOf(value.intValue())); assertFalse(p, Integer.valueOf(value.intValue()));
assertFalse(p, Integer.valueOf(value.intValue() + 1)); assertFalse(p, Integer.valueOf(value.intValue() + 1));
} }
@Test @Test
public void compareLess() { public void compareLess() {
Integer value = Integer.valueOf(10); Integer value = Integer.valueOf(10);
Predicate<Integer> p = comparatorPredicate(value, new TestComparator<Integer>(), Criterion.LESS); Predicate<Integer> p = comparatorPredicate(value, new TestComparator<Integer>(), Criterion.LESS);
assertFalse(p, Integer.valueOf(value.intValue() - 1)); assertFalse(p, Integer.valueOf(value.intValue() - 1));
assertFalse(p, Integer.valueOf(value.intValue())); assertFalse(p, Integer.valueOf(value.intValue()));
assertTrue(p, Integer.valueOf(value.intValue() + 1)); assertTrue(p, Integer.valueOf(value.intValue() + 1));
} }
@Test @Test
public void compareGreaterOrEqual() { public void compareGreaterOrEqual() {
Integer value = Integer.valueOf(10); Integer value = Integer.valueOf(10);
Predicate<Integer> p = comparatorPredicate(value, new TestComparator<Integer>(), Criterion.GREATER_OR_EQUAL); Predicate<Integer> p = comparatorPredicate(value, new TestComparator<Integer>(), Criterion.GREATER_OR_EQUAL);
assertTrue(p, Integer.valueOf(value.intValue() - 1)); assertTrue(p, Integer.valueOf(value.intValue() - 1));
assertTrue(p, Integer.valueOf(value.intValue())); assertTrue(p, Integer.valueOf(value.intValue()));
assertFalse(p, Integer.valueOf(value.intValue() + 1)); assertFalse(p, Integer.valueOf(value.intValue() + 1));
} }
@Test @Test
public void compareLessOrEqual() { public void compareLessOrEqual() {
Integer value = Integer.valueOf(10); Integer value = Integer.valueOf(10);
Predicate<Integer> p = comparatorPredicate(value, new TestComparator<Integer>(), Criterion.LESS_OR_EQUAL); Predicate<Integer> p = comparatorPredicate(value, new TestComparator<Integer>(), Criterion.LESS_OR_EQUAL);
assertFalse(p, Integer.valueOf(value.intValue() - 1)); assertFalse(p, Integer.valueOf(value.intValue() - 1));
assertTrue(p, Integer.valueOf(value.intValue())); assertTrue(p, Integer.valueOf(value.intValue()));
assertTrue(p, Integer.valueOf(value.intValue() + 1)); assertTrue(p, Integer.valueOf(value.intValue() + 1));
} }
@Override @Override
protected Predicate<?> generatePredicate() { protected Predicate<?> generatePredicate() {
return comparatorPredicate(Integer.valueOf(10), new TestComparator<Integer>()); return comparatorPredicate(Integer.valueOf(10), new TestComparator<Integer>());
} }
} }

View File

@ -1,235 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.collections.list.difference;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class SequencesComparatorTest {
@Test
public void testLength() {
for (int i = 0; i < before.size(); ++i) {
SequencesComparator<Character> comparator =
new SequencesComparator<Character>(sequence(before.get(i)),
sequence(after.get(i)));
Assert.assertEquals(length[i], comparator.getScript().getModifications());
}
}
@Test
public void testExecution() {
ExecutionVisitor<Character> ev = new ExecutionVisitor<Character>();
for (int i = 0; i < before.size(); ++i) {
ev.setList(sequence(before.get(i)));
new SequencesComparator<Character>(sequence(before.get(i)),
sequence(after.get(i))).getScript().visit(ev);
Assert.assertEquals(after.get(i), ev.getString());
}
}
@Test
public void testMinimal() {
String[] shadokAlph = new String[] {
new String("GA"),
new String("BU"),
new String("ZO"),
new String("MEU")
};
List<String> sentenceBefore = new ArrayList<String>();
List<String> sentenceAfter = new ArrayList<String>();
sentenceBefore.add(shadokAlph[0]);
sentenceBefore.add(shadokAlph[2]);
sentenceBefore.add(shadokAlph[3]);
sentenceBefore.add(shadokAlph[1]);
sentenceBefore.add(shadokAlph[0]);
sentenceBefore.add(shadokAlph[0]);
sentenceBefore.add(shadokAlph[2]);
sentenceBefore.add(shadokAlph[1]);
sentenceBefore.add(shadokAlph[3]);
sentenceBefore.add(shadokAlph[0]);
sentenceBefore.add(shadokAlph[2]);
sentenceBefore.add(shadokAlph[1]);
sentenceBefore.add(shadokAlph[3]);
sentenceBefore.add(shadokAlph[2]);
sentenceBefore.add(shadokAlph[2]);
sentenceBefore.add(shadokAlph[0]);
sentenceBefore.add(shadokAlph[1]);
sentenceBefore.add(shadokAlph[3]);
sentenceBefore.add(shadokAlph[0]);
sentenceBefore.add(shadokAlph[3]);
Random random = new Random(4564634237452342L);
for (int nbCom = 0; nbCom <= 40; nbCom+=5) {
sentenceAfter.clear();
sentenceAfter.addAll(sentenceBefore);
for (int i = 0; i<nbCom; i++) {
if (random.nextInt(2) == 0) {
sentenceAfter.add(random.nextInt(sentenceAfter.size() + 1),
shadokAlph[random.nextInt(4)]);
} else {
sentenceAfter.remove(random.nextInt(sentenceAfter.size()));
}
}
SequencesComparator<String> comparator =
new SequencesComparator<String>(sentenceBefore, sentenceAfter);
Assert.assertTrue(comparator.getScript().getModifications() <= nbCom);
}
}
@Test
public void testShadok() {
int lgMax = 5;
String[] shadokAlph = new String[] {
new String("GA"),
new String("BU"),
new String("ZO"),
new String("MEU")
};
List<List<String>> shadokSentences = new ArrayList<List<String>>();
for (int lg=0; lg<lgMax; ++lg) {
List<List<String>> newTab = new ArrayList<List<String>>();
newTab.add(new ArrayList<String>());
for (int k = 0; k < shadokAlph.length; k++) {
for (List<String> sentence : shadokSentences) {
List<String> newSentence = new ArrayList<String>(sentence);
newSentence.add(shadokAlph[k]);
newTab.add(newSentence);
}
}
shadokSentences = newTab;
}
ExecutionVisitor<String> ev = new ExecutionVisitor<String>();
for (int i = 0; i < shadokSentences.size(); ++i) {
for (int j = 0; j < shadokSentences.size(); ++j) {
ev.setList(shadokSentences.get(i));
new SequencesComparator<String>(shadokSentences.get(i),
shadokSentences.get(j)).getScript().visit(ev);
StringBuilder concat = new StringBuilder();
for (final String s : shadokSentences.get(j)) {
concat.append(s);
}
Assert.assertEquals(concat.toString(), ev.getString());
}
}
}
private List<Character> sequence(String string) {
List<Character> list = new ArrayList<Character>();
for (int i = 0; i < string.length(); ++i) {
list.add(new Character(string.charAt(i)));
}
return list;
}
private class ExecutionVisitor<T> implements CommandVisitor<T> {
private List<T> v;
private int index;
public void setList(List<T> array) {
v = new ArrayList<T>(array);
index = 0;
}
public void visitInsertCommand(T object) {
v.add(index++, object);
}
public void visitKeepCommand(T object) {
++index;
}
public void visitDeleteCommand(T object) {
v.remove(index);
}
public String getString() {
StringBuffer buffer = new StringBuffer();
for (T c : v) {
buffer.append(c);
}
return buffer.toString();
}
}
@Before
public void setUp() {
before = Arrays.asList(new String[] {
"bottle",
"nematode knowledge",
"",
"aa",
"prefixed string",
"ABCABBA",
"glop glop",
"coq",
"spider-man"
});
after = Arrays.asList(new String[] {
"noodle",
"empty bottle",
"",
"C",
"prefix",
"CBABAC",
"pas glop pas glop",
"ane",
"klingon"
});
length = new int[] {
6,
16,
0,
3,
9,
5,
8,
6,
13
};
}
@After
public void tearDown() {
before = null;
after = null;
length = null;
}
private List<String> before;
private List<String> after;
private int[] length;
}