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:
parent
41d170f076
commit
6d8659cad5
3
pom.xml
3
pom.xml
|
@ -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>
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<String> writer = new ThrowingClosure() {
|
* CatchAndRethrowClosure<String> 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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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>
|
|
|
@ -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>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue