package net.varkhan.base.containers;
import net.varkhan.base.containers.array.Arrays;
import net.varkhan.base.containers.list.List;
import net.varkhan.base.containers.map.Map;
import java.io.IOException;
import java.util.Comparator;
import java.util.NoSuchElementException;
/**
* <b>Static {@link Container} manipulation utilities.</b>.
* <p/>
* Utilities for converting Container types from and into other types,
* searching and processing their contents, and comparing instances.
* <p/>
*
* @author varkhan
* @date 3/18/12
* @time 2:49 PM
*/
public class Containers {
/**********************************************************************************
** Static predefined containers
**/
/**
* An empty container, that contains no element (whose {@code isEmpty()}
* method always returns {@literal true}, and whose {@code size()} is always
* {@literal 0}).
*/
public static final Container EMPTY=new Empty();
/**
* An empty container, whose {@code isEmpty()} method always returns {@literal true},
* and whose {@code size()} is always {@literal 0}.
*/
public static final class Empty<Type> implements Container<Type> {
public long size() { return 0; }
public boolean isEmpty() { return true; }
public Iterator<Type> iterator() { return new Iterator.Empty<Type>(); }
public <Par> long visit(Visitor<Type,Par> vis, Par par) { return 0; }
}
/**
* A singleton container, that contains a single element.
*/
public static final class Singleton<Type> implements Container<Type> {
private final Type element;
/**
* Create a singleton container.
*
* @param e the single element this container contains
*/
public Singleton(Type e) { element=e; }
public long size() { return 1; }
public boolean isEmpty() { return false; }
public Iterator<? extends Type> iterator() { return new Iterator.Singleton<Type>(element); }
public <Par> long visit(Visitor<Type,Par> vis, Par par) { return vis.invoke(element,par); }
}
/**
* An enumeration container, that contains all elements in an array, in order.
*/
public static final class Enumerate<Type> implements Container<Type> {
private final Type[] elements;
/**
* Create an enumeration container.
*
* @param e the array of all the elements contained
*/
public Enumerate(Type... e) { elements = e; }
public long size() {
return elements==null?0:elements.length;
}
public boolean isEmpty() {
return elements==null||elements.length==0;
}
public Iterator<? extends Type> iterator() {
return elements==null?new Iterator.Empty<Type>():new Iterator.Enumerate<Type>(elements);
}
public <Par> long visit(Visitor<Type,Par> vis, Par par) {
long s =0;
if(elements!=null) for(Type e: elements) {
long v = vis.invoke(e,par);
if(v<0) return -1;
s += v;
}
return s;
}
}
/*********************************************************************************
** Equality
**/
/**
* Deep equality of containers.
* <p/>
* Note that two containers that contain the same set of elements but
* <em>iterate</em> through them in a different order will <em>not</em>
* be considered equal by this method.
*
* @param obj1 the left containers to inspect
* @param obj2 the right containers to inspect
* @param <E> the type of the container elements
*
* @return {@literal true} if the two containers have the same size, and the
* element returned by their iterators at each iteration step are either
* {@see Object#equals} to each other or both {@literal null}.
*/
public static <E> boolean equals(Container<E> obj1, Container<E> obj2) {
if(obj1==obj2) return true;
// We don't compare sizes, as this can be a slow operation for some containers,
// and we have to check elements one by one anyways
Iterator<? extends E> it1 = obj1.iterator();
Iterator<? extends E> it2 = obj2.iterator();
// As long as both collection have elements, check for equality
while(it1.hasNext() && it2.hasNext()) {
E el1 = it1.next();
E el2 = it2.next();
if(el1!=el2&&(el1==null||el2==null||!el1.equals(el2))) return false;
}
// If one of the containers has remaining elements, not equal
return !(it1.hasNext() || it2.hasNext());
}
/**
* Deep equality of maps.
* <p/>
* Note that two maps that contain the same set of key-value pairs but
* <em>iterate</em> through them in a different order will <em>not</em>
* be considered equal by this method.
*
* @param obj1 the left map to inspect
* @param obj2 the right map to inspect
* @param <K> the type of the map keys
* @param <V> the type of the map values
*
* @return {@literal true} if the two maps have the same size, and the
* entries returned by their iterators at each iteration step contain
* keys and values that are respectively either {@see Object#equals}
* to each other or both {@literal null}.
*/
public static <K,V> boolean equals(Map<K,V> obj1, Map<K,V> obj2) {
if(obj1==obj2) return true;
// We don't compare sizes, as this can be a slow operation for some maps,
// and we have to check entries one by one anyways
Iterator<? extends Map.Entry<K,V>> it1 = obj1.iterator();
Iterator<? extends Map.Entry<K,V>> it2 = obj2.iterator();
// As long as both collection have elements, check for equality
while(it1.hasNext() && it2.hasNext()) {
Map.Entry<K,V> e1 = it1.next();
Map.Entry<K,V> e2 = it2.next();
K k1 = e1.getKey();
K k2 = e2.getKey();
if(k1!=k2&&(k1==null||k2==null||!k1.equals(k2))) return false;
V v1 = e1.getValue();
V v2 = e2.getValue();
if(v1!=v2&&(v1==null||v2==null||!v1.equals(v2))) return false;
}
// If one of the maps has remaining entries, not equal
return !(it1.hasNext() || it2.hasNext());
}
/*********************************************************************************
** String transformation
**/
/**
* Appends as strings the elements of an array, wrapping each non-null
* element with delimiters and separating them with a given string.
*
* @param buf the buffer to append the composed string to
* @param ldl the left delimiter for non-null elements
* @param rdl the right delimiter for non-null elements
* @param nil the representation to use for {@literal null} elements
* @param sep the separator to use
* @param array the array to join
*
* @param <T> the element type
*
* @return the original buffer, for chaining purposes
*
* @throws IOException if the output buffer raises this exception on {@code append()}
*/
public static <T,A extends Appendable> A join(A buf, String ldl, String rdl, String nil, String sep, java.lang.Iterable<T> array) throws IOException {
if(sep==null) {
for(T elt: array) {
if(elt!=null) {
if(ldl!=null) buf.append(ldl);
buf.append(elt.toString());
if(rdl!=null) buf.append(rdl);
}
else if(nil!=null) buf.append(nil);
}
}
else {
boolean fst = true;
for(T elt: array) {
if(fst) fst=false;
else buf.append(sep);
if(elt!=null) {
if(ldl!=null) buf.append(ldl);
buf.append(elt.toString());
if(rdl!=null) buf.append(rdl);
}
else if(nil!=null) buf.append(nil);
}
}
return buf;
}
/**
* Appends as strings the elements of an array, wrapping each non-null
* element with delimiters and separating them with a given string.
*
* @param ldl the left delimiter for non-null elements
* @param rdl the right delimiter for non-null elements
* @param nil the representation to use for {@literal null} elements
* @param sep the separator to use
* @param array the array to join
*
* @param <T> the element type
*
* @return the original buffer, for chaining purposes
*/
public static <T> StringBuilder join(StringBuilder buf, String ldl, String rdl, String nil, String sep, java.lang.Iterable<T> array) {
if(sep==null) {
for(T elt: array) {
if(elt!=null) {
if(ldl!=null) buf.append(ldl);
buf.append(elt.toString());
if(rdl!=null) buf.append(rdl);
}
else if(nil!=null) buf.append(nil);
}
}
else {
boolean fst = true;
for(T elt: array) {
if(fst) fst=false;
else buf.append(sep);
if(elt!=null) {
if(ldl!=null) buf.append(ldl);
buf.append(elt.toString());
if(rdl!=null) buf.append(rdl);
}
else if(nil!=null) buf.append(nil);
}
}
return buf;
}
/**
* Appends as strings the elements of an array, wrapping each non-null
* element with delimiters and separating them with a given string.
*
* @param ldl the left delimiter for non-null elements
* @param rdl the right delimiter for non-null elements
* @param nil the representation to use for {@literal null} elements
* @param sep the separator between elements
* @param array the array to join
*
* @param <T> the element type
*
* @return a concatenation of the elements of the array, as strings wrapped in the delimiters, and the separator
*/
public static <T> String join(String ldl, String rdl, String nil, String sep, java.lang.Iterable<T> array) {
return join(new StringBuilder(), ldl, rdl, nil, sep, array).toString();
}
/**
* Appends as strings the elements of an array, separating them with a given string.
*
* @param sep the separator between elements
* @param array the array to join
* @param <T> the element type
*
* @return a concatenation of the elements of the array, as strings, and the separator
*/
public static <T> String join(String sep, java.lang.Iterable<T> array) {
return join(new StringBuilder(), null, null, "null", sep, array).toString();
}
/**
* Appends as strings the elements of a map, wrapping each non-null
* element with delimiters and separating them with a given string.
*
* @param buf the buffer to append the composed string to
* @param ldl the left delimiter of key-value pairs
* @param edl the delimiter between keys and values
* @param rdl the right delimiter of key-value pairs
* @param nil the representation to use for {@literal null} keys or values
* @param sep the separator between key-value pairs
* @param map the sequence of map entries to join
*
* @param <K> the key type
* @param <V> the value type
* @param <A> the buffer type
*
* @return the original buffer, for chaining purposes
*
* @throws IOException if the output buffer raises this exception on {@code append()}
*/
public static <K,V,A extends Appendable> A join(A buf, String ldl, String edl, String rdl, String nil, String sep, java.lang.Iterable<java.util.Map.Entry<K,V>> map) throws IOException {
if(sep==null) {
for(java.util.Map.Entry<K,V> elt: map) {
if(elt!=null) {
if(ldl!=null) buf.append(ldl);
K key = elt.getKey();
buf.append(key==null ? nil : key.toString());
if(edl!=null) buf.append(edl);
V val = elt.getValue();
buf.append(val==null ? nil : val.toString());
if(rdl!=null) buf.append(rdl);
}
}
}
else {
boolean fst = true;
for(java.util.Map.Entry<K,V> elt: map) {
if(fst) fst=false;
else buf.append(sep);
if(elt!=null) {
if(ldl!=null) buf.append(ldl);
K key = elt.getKey();
buf.append(key==null ? nil : key.toString());
if(edl!=null) buf.append(edl);
V val = elt.getValue();
buf.append(val==null ? nil : val.toString());
if(rdl!=null) buf.append(rdl);
}
}
}
return buf;
}
/**
* Appends as strings the key-value pairs of a map, wrapping each non-null
* element with delimiters and separating them with a given string.
*
* @param buf the buffer to append the composed string to
* @param ldl the left delimiter of key-value pairs
* @param edl the delimiter between keys and values
* @param rdl the right delimiter of key-value pairs
* @param nil the representation to use for {@literal null} keys or values
* @param sep the separator between key-value pairs
* @param map the sequence of map entries to join
*
* @param <K> the key type
* @param <V> the value type
*
* @return the original buffer, for chaining purposes
*/
public static <K,V> StringBuilder join(StringBuilder buf, String ldl, String edl, String rdl, String nil, String sep, java.lang.Iterable<java.util.Map.Entry<K,V>> map) {
if(sep==null) {
for(java.util.Map.Entry<K,V> elt: map) {
if(elt!=null) {
if(ldl!=null) buf.append(ldl);
K key = elt.getKey();
buf.append(key==null ? nil : key.toString());
if(edl!=null) buf.append(edl);
V val = elt.getValue();
buf.append(val==null ? nil : val.toString());
if(rdl!=null) buf.append(rdl);
}
}
}
else {
boolean fst = true;
for(java.util.Map.Entry<K,V> elt: map) {
if(fst) fst=false;
else buf.append(sep);
if(elt!=null) {
if(ldl!=null) buf.append(ldl);
K key = elt.getKey();
buf.append(key==null ? nil : key.toString());
if(edl!=null) buf.append(edl);
V val = elt.getValue();
buf.append(val==null ? nil : val.toString());
if(rdl!=null) buf.append(rdl);
}
}
}
return buf;
}
/**
* Appends as strings the key-value pairs of a map, wrapping each non-null
* element with delimiters and separating them with a given string.
*
* @param ldl the left delimiter of key-value pairs
* @param edl the delimiter between keys and values
* @param rdl the right delimiter of key-value pairs
* @param nil the representation to use for {@literal null} keys or values
* @param sep the separator between key-value pairs
* @param map the sequence of map entries to join
*
* @param <K> the key type
* @param <V> the value type
*
* @return a concatenation of the elements of the array, as strings wrapped in the delimiters, and the separator
*/
public static <K,V> String join(String ldl, String edl, String rdl, String nil, String sep, java.lang.Iterable<java.util.Map.Entry<K,V>> map) {
return join(new StringBuilder(), ldl, edl, rdl, nil, sep, map).toString();
}
/*********************************************************************************
** Sorting
**/
/**
* Sorts a list in place using the natural order.
*
* @param lst the list to sort
* @param <T> the element type
* @return the number of swap operations required for the sorting
*/
@SuppressWarnings("unchecked")
public static <T extends Comparable<? super T>> int sort(List<T> lst) {
Comparable[] a = new Comparable[(int)lst.size()];
int i=0;
for(Comparable o: (java.lang.Iterable<? extends Comparable>) lst) a[i++] = o;
int s = Arrays.sort(a);
i=0;
for(Comparable o: a) lst.set(i++,(T)o);
return s;
}
/**
* Sorts a list in place using a comparator.
*
*
* @param comp the comparator
* @param lst the list to sort
* @param <T> the element type
* @return the number of swap operations required for the sorting
*/
@SuppressWarnings("unchecked")
public static <T> int sort(Comparator<? super T> comp, List<T> lst) {
Object[] a = new Object[(int)lst.size()];
int i=0;
for(Object o: lst) a[i++] = o;
int s = Arrays.sort((Comparator)comp,a);
i=0;
for(Object o: a) lst.set(i++,(T)o);
return s;
}
}