1 package net
.kezvh
.collections
;
3 import java
.lang
.reflect
.Array
;
4 import java
.lang
.reflect
.InvocationTargetException
;
5 import java
.lang
.reflect
.Method
;
6 import java
.util
.AbstractSet
;
7 import java
.util
.ArrayList
;
8 import java
.util
.Arrays
;
9 import java
.util
.Collection
;
10 import java
.util
.Collections
;
11 import java
.util
.Comparator
;
12 import java
.util
.Iterator
;
13 import java
.util
.List
;
15 import java
.util
.NoSuchElementException
;
17 import java
.util
.SortedSet
;
18 import java
.util
.TreeSet
;
20 import net
.kezvh
.functional
.lambda
.EquivalenceRelation
;
21 import net
.kezvh
.functional
.lambda
.L1
;
22 import net
.kezvh
.functional
.lambda
.Predicate1
;
23 import net
.kezvh
.math
.KezvhMath
;
24 import net
.kezvh
.patterns
.AbstractFactory
;
25 import net
.kezvh
.patterns
.AbstractFactory
.CreationFailedException
;
30 public final class CollectionsUtilities
{
31 private static final String COULD_NOT_CONSTRUCT_DEFAULT_VALUE
= "Could not construct default value";
33 private static final class ConditionalIterator
<T
> implements Iterator
<T
> {
34 private final Iterator
<T
> iterator
;
35 private final Predicate1
<T
> condition
;
36 private boolean notEmpty
= false;
39 public ConditionalIterator(final Iterator
<T
> iterator
, final Predicate1
<T
> condition
) {
40 this.iterator
= iterator
;
41 this.condition
= condition
;
45 private void advance() {
46 this.notEmpty
= false;
47 while (this.iterator
.hasNext() && !this.notEmpty
) {
48 this.current
= this.iterator
.next();
49 this.notEmpty
= this.condition
.op(this.current
);
53 public boolean hasNext() {
59 throw new NoSuchElementException();
68 public void remove() {
69 throw new UnsupportedOperationException();
73 private static final class ConditionalSet
<T
> extends AbstractSet
<T
> {
74 private final Set
<T
> set
;
75 private final Predicate1
<T
> condition
;
77 public ConditionalSet(final Set
<T
> set
, final Predicate1
<T
> condition
) {
79 this.condition
= condition
;
84 return CollectionsUtilities
.count(this.iterator());
88 public Iterator
<T
> iterator() {
89 return new ConditionalIterator
<T
>(this.set
.iterator(), this.condition
);
93 private static class ConcatenatedIterator
<T
> implements Iterator
<T
> {
94 private final Iterator
<T
>[] iterators
;
95 private int index
= 0;
97 public ConcatenatedIterator(final Iterator
<T
>[] iterators
) {
98 this.iterators
= Arrays
.copyOf(iterators
, iterators
.length
);
101 public boolean hasNext() {
102 return this.index
!= this.iterators
.length
&& this.iterators
[this.index
].hasNext();
106 while (!this.iterators
[this.index
].hasNext()) {
109 if (this.index
== this.iterators
.length
)
110 throw new NoSuchElementException();
113 return this.iterators
[this.index
].next();
116 public void remove() {
117 this.iterators
[this.index
].remove();
123 * @param iterator COMMENT
126 public static <T
> int count(final Iterator
<T
> iterator
) {
128 while (iterator
.hasNext()) {
137 * @param start COMMENT
139 * @param incrementer COMMENT
142 public static <T
extends Comparable
<T
>> List
<T
> range(final T start
, final T end
, final L1
<T
, T
> incrementer
) {
143 final List
<T
> range
= new ArrayList
<T
>();
145 while (current
.compareTo(end
) < 0) {
147 current
= incrementer
.op(current
);
149 return Collections
.unmodifiableList(range
);
154 * @param iterators COMMENT
157 public static <T
> Iterator
<T
> concatenate(final Iterator
<T
>[] iterators
) {
158 return new ConcatenatedIterator
<T
>(iterators
);
163 * @param iterators COMMENT
166 public static <T
> Iterator
<T
> concatenate(final Collection
<Iterator
<T
>> iterators
) {
167 final Iterator
<T
>[] array
= (Iterator
<T
>[]) Array
.newInstance(iterators
.iterator().next().getClass(), iterators
.size());
168 return CollectionsUtilities
.concatenate(array
);
174 * @param toAdd COMMENT
177 public static <T
> boolean addAll(final Collection
<T
> c
, final T
[] toAdd
) {
178 return c
.addAll(Arrays
.asList(toAdd
));
183 * @param collection COMMENT
184 * @param condition COMMENT
187 // //////////////////////////////////////
188 public static <T
> List
<T
> match(final List
<T
> collection
, final Predicate1
<T
> condition
) {
191 matches
= collection
.getClass().newInstance();
192 } catch (final Exception e
) {
193 matches
= new ArrayList
<T
>();
195 for (final T o
: collection
)
204 * @param iterator COMMENT
205 * @param condition COMMENT
208 public static <T
> Iterator
<T
> matchView(final Iterator
<T
> iterator
, final Predicate1
<T
> condition
) {
209 return new ConditionalIterator
<T
>(iterator
, condition
);
215 * @param condition COMMENT
218 public static <T
> Set
<T
> matchView(final Set
<T
> set
, final Predicate1
<T
> condition
) {
219 return new ConditionalSet
<T
>(set
, condition
);
228 * @param defaultValueClass COMMENT
230 * @throws InstantiationException COMMENT
231 * @throws IllegalAccessException COMMENT
233 public static <K
, V
> V
ensureContainsKey(final Map
<K
, V
> map
, final K key
, final Class
<V
> defaultValueClass
) throws InstantiationException
, IllegalAccessException
{
234 if (map
.containsKey(key
))
238 defaultValue
= defaultValueClass
.newInstance();
240 map
.put(key
, defaultValue
);
249 * @param clonableDefaultValue COMMENT
251 * @throws NoSuchMethodException COMMENT
252 * @throws InvocationTargetException COMMENT
253 * @throws IllegalAccessException COMMENT
255 public static <K
, V
> V
ensureContainsKey(final Map
<K
, V
> map
, final K key
, final Cloneable clonableDefaultValue
) throws NoSuchMethodException
, InvocationTargetException
, IllegalAccessException
{
256 if (map
.containsKey(key
))
260 final Method cloneMethod
= clonableDefaultValue
.getClass().getMethod("clone", null);
261 defaultValue
= (V
) cloneMethod
.invoke(clonableDefaultValue
, null);
263 map
.put(key
, defaultValue
);
272 * @param defaultValueConstructor COMMENT
274 * @throws CreationFailedException COMMENT
276 public static <K
, V
> V
ensureContainsKey(final Map
<K
, V
> map
, final K key
, final AbstractFactory
<V
> defaultValueConstructor
) throws CreationFailedException
{
277 if (map
.containsKey(key
))
279 final V defaultValue
= defaultValueConstructor
.create();
281 map
.put(key
, defaultValue
);
285 // ///////////////////////////////////////
294 public static <V
> boolean removeFirst(final Collection
<V
> c
, final V o
, final EquivalenceRelation
<V
> e
) {
295 for (final Iterator
<V
> i
= c
.iterator(); i
.hasNext();)
296 if (e
.op(o
, i
.next())) {
310 public static <V
> boolean removeAll(final Collection
<V
> c
, final V o
, final EquivalenceRelation
<V
> e
) {
311 boolean removed
= false;
313 for (final Iterator
<V
> i
= c
.iterator(); i
.hasNext();)
314 if (e
.op(o
, i
.next())) {
329 public static <V
> boolean replaceFirst(final List
<V
> l
, final V o
, final EquivalenceRelation
<V
> e
) {
330 for (int i
= 0; i
< l
.size(); i
++)
331 if (e
.op(o
, l
.get(i
))) {
339 // ///////////////////////////////////////
345 * @param keys COMMENT
348 public static <K
, V
> V
[] slice(final Map
<K
, V
> map
, final K
... keys
) {
349 final V
[] values
= (V
[]) Array
.newInstance(map
.get(keys
[0]).getClass(), keys
.length
);
350 for (int i
= 0; i
< keys
.length
; i
++)
351 values
[i
] = map
.get(keys
[i
]);
359 * @param keys COMMENT
362 public static <K
, V
> List
<V
> slice(final Map
<K
, V
> map
, final List
<K
> keys
) {
365 values
= keys
.getClass().newInstance();
366 } catch (final InstantiationException e
) {
367 values
= new ArrayList
<V
>();
368 } catch (final IllegalAccessException e
) {
369 values
= new ArrayList
<V
>();
372 for (int i
= 0; i
< keys
.size(); i
++)
373 values
.add(map
.get(keys
.get(i
)));
377 // //////////////////////////////////////////////
381 * @param comparator COMMENT
384 public static <V
> Comparator
<V
> reverse(final Comparator
<V
> comparator
) {
385 return new Comparator
<V
>() {
386 public int compare(final V arg0
, final V arg1
) {
387 return comparator
.compare(arg1
, arg0
);
392 // ////////////////////////////////////////////////
400 public static <V
> boolean sameContents(final Collection
<V
> a
, final Collection
<V
> b
) {
401 final Multiset
<V
> x
= new MappedMultiset
<V
>(a
);
402 final Multiset
<V
> y
= new MappedMultiset
<V
>(b
);
406 // ////////////////////////////////////////////////
408 private static final class ComparableComarator
<V
extends Comparable
<V
>> implements Comparator
<V
> {
409 public int compare(final V o1
, final V o2
) {
410 return o1
.compareTo(o2
);
420 public static <K
, V
extends Comparable
<V
>> SortedSet
<K
> keySetByValues(final Map
<K
, V
> map
) {
421 return CollectionsUtilities
.keySetByValues(map
, new ComparableComarator
<V
>());
424 @SuppressWarnings("unchecked")
425 private static <T
> int finagleComparison(final T arg0
, final T arg1
) {
426 if (arg0
instanceof Comparable
&& arg1
instanceof Comparable
)
428 return ((Comparable
<T
>) arg0
).compareTo(arg1
);
429 } catch (final ClassCastException e
) {
431 return -((Comparable
<T
>) arg1
).compareTo(arg0
);
432 } catch (final ClassCastException f
) {
437 final int hashCompare
= KezvhMath
.compare(arg0
.hashCode(), arg1
.hashCode()); // usually different if objects are not
439 if (hashCompare
!= 0)
442 return KezvhMath
.compare(System
.identityHashCode(arg0
), System
.identityHashCode(arg1
)); // kind of a last ditch effort,
443 // which should *usually* return
444 // different values for objects
445 // which are not equal. otw, yur screwed
455 public static <K
, V
> SortedSet
<K
> keySetByValues(final Map
<K
, V
> map
, final Comparator
<V
> c
) {
456 final Comparator
<K
> orderByValue
= new Comparator
<K
>() {
457 public int compare(final K arg0
, final K arg1
) {
458 final boolean has0
= map
.containsKey(arg0
);
459 final boolean has1
= map
.containsKey(arg1
);
461 return KezvhMath
.compare(has0
, has1
);
463 int cmp
= c
.compare(map
.get(arg0
), map
.get(arg1
));
464 if (cmp
== 0 && !arg0
.equals(arg1
)) { // distinct keys map to equal objects
465 cmp
= CollectionsUtilities
.finagleComparison(arg0
, arg1
); // we do this to try to keep two separate keys from
466 // mapping to the same index of the sorted set
467 if (cmp
== 0) // this is bad - no way to order things...
468 throw new IllegalArgumentException("cannot figure out how to order two equal objects: " + arg0
+ ", " + arg1
);
473 final SortedSet
<K
> keySet
= new TreeSet
<K
>(orderByValue
);
474 keySet
.addAll(map
.keySet());
478 // ///////////////////////////////////////////////
485 public static <T
> int hash(final Iterable
<T
> c
) {
491 for (final T element
: c
)
492 result
= 31 * result
+ (element
== null ?
0 : element
.hashCode());