All Downloads are FREE. Search and download functionalities are using the official Maven repository.

aQute.lib.collections.SortedList Maven / Gradle / Ivy

There is a newer version: 7.0.0
Show newest version
package aQute.lib.collections;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;
import java.util.SortedSet;

/**
 * An immutbale list that sorts objects by their natural order or through a
 * comparator. It has convenient methods/constructors to create it from
 * collections and iterators. Why not maintain the lists in their sorted form?
 * Well, TreeMaps are quite expensive ... I once profiled bnd and was shocked
 * how much memory the Jar class took due to the TreeMaps. I could not easily
 * change it unfortunately. The other reason is that Parameters uses a
 * LinkedHashMap because the preferred order should be the declaration order.
 * However, sometimes you need to sort the keys by name. Last, and most
 * important reason, is that sometimes you do not know what collection you have
 * or it is not available in a sort ordering (MultiMap for example) ... I found
 * myself sorting these things over and over again and decided to just make an
 * immutable SortedList that is easy to slice and dice
 * 
 * @param 
 */
@SuppressWarnings("unchecked")
public class SortedList implements SortedSet, List {
	static SortedList< ? >		empty		= new SortedList();

	final T[]					list;
	final int					start;
	final int					end;
	final Comparator			cmp;
	Class< ? >					type;
	static Comparator	comparator	=															//

												new Comparator() {
													public int compare(Object o1, Object o2) {

														if (o1 == o2)
															return 0;

														if (o1.equals(o2))
															return 0;

														return ((Comparable) o1).compareTo(o2);
													}
												};

	class It implements ListIterator {
		int n;

		It(int n) {
			this.n = n;
		}

		public boolean hasNext() {
			return n < end;
		}

		public T next() throws NoSuchElementException {
			if (!hasNext()) {
				throw new NoSuchElementException("");
			}
			return list[n++];
		}

		public boolean hasPrevious() {
			return n > start;
		}

		public T previous() {
			assert n > start;
			return list[--n];
		}

		public int nextIndex() {
			return (n - start);
		}

		public int previousIndex() {
			return (n - 1) - start;
		}

		@Deprecated
		public void remove() {
			throw new UnsupportedOperationException("Immutable");
		}

		@Deprecated
		public void set(T e) {
			throw new UnsupportedOperationException("Immutable");
		}

		@Deprecated
		public void add(T e) {
			throw new UnsupportedOperationException("Immutable");
		}
	}

	public SortedList(Collection< ? extends Comparable< ? >> x) {
		this((Collection) x, 0, x.size(), (Comparator) comparator);
	}

	public SortedList(Collection x, Comparator cmp) {
		this(x, 0, x.size(), cmp);
	}

	@SuppressWarnings("cast")
	public SortedList(T... x) {
		this(x.clone(), 0, x.length, (Comparator) comparator);
	}

	@SuppressWarnings("cast")
	public SortedList(Comparator cmp, T... x) {
		this(x.clone(), 0, x.length, cmp);
	}

	private SortedList(SortedList other, int start, int end) {
		this.list = other.list;
		this.cmp = other.cmp;
		this.start = start;
		this.end = end;
	}

	public SortedList(T[] x, int start, int end, Comparator comparator2) {
		if (start > end) {
			int tmp = start;
			start = end;
			end = tmp;
		}
		if (start < 0 || start >= x.length)
			throw new IllegalArgumentException("Start is not in list");

		if (end < 0 || end > x.length)
			throw new IllegalArgumentException("End is not in list");

		this.list = x.clone();
		Arrays.sort(this.list, start, end, comparator2);
		this.start = start;
		this.end = end;
		this.cmp = comparator2;
	}

	public SortedList(Collection< ? extends T> x, int start, int end, Comparator cmp) {
		if (start > end) {
			int tmp = start;
			start = end;
			end = tmp;
		}
		if (start < 0 || start > x.size())
			throw new IllegalArgumentException("Start is not in list");

		if (end < 0 || end > x.size())
			throw new IllegalArgumentException("End is not in list");

		this.list = (T[]) x.toArray();
		Arrays.sort(this.list, start, end, cmp);
		this.start = start;
		this.end = end;
		this.cmp = cmp;
	}

	private SortedList() {
		list = null;
		start = 0;
		end = 0;
		cmp = null;
	}

	public int size() {
		return end - start;
	}

	public boolean isEmpty() {
		return start == end;
	}

	@SuppressWarnings("cast")
	public boolean contains(Object o) {
		assert type == null || type.isInstance(o);
		return find((T) o) >= 0;
	}

	public Iterator iterator() {
		return new It(start);
	}

	public Object[] toArray() {
		if (list == null) {
			return new Object[0];
		}

		if (start == 0 && end == list.length)
			return list.clone();

		if (type != null)
			return (Object[]) Array.newInstance(type, size());

		return toArray(new Object[0]);
	}

	@SuppressWarnings("hiding")
	public  X[] toArray(X[] a) {
		int size = size();

		if (a.length < size)
			a = (X[]) Array.newInstance(a.getClass().getComponentType(), size);

		System.arraycopy(list, start, a, 0, size);
		if (a.length > size)
			a[size] = null;
		return a;
	}

	public boolean add(T e) {
		throw new UnsupportedOperationException("Immutable");
	}

	public boolean remove(Object o) {
		throw new UnsupportedOperationException("Immutable");
	}

	public boolean containsAll(Collection< ? > c) {
		if (c.isEmpty())
			return true;

		if (isEmpty())
			return false;

		// TODO take advantage of sorted nature for this

		for (Object el : c) {
			if (!contains(el))
				return false;
		}
		return false;
	}

	public boolean addAll(Collection< ? extends T> c) {
		throw new UnsupportedOperationException("Immutable");
	}

	public boolean retainAll(Collection< ? > c) {
		throw new UnsupportedOperationException("Immutable");
	}

	public boolean removeAll(Collection< ? > c) {
		throw new UnsupportedOperationException("Immutable");
	}

	public void clear() {
		throw new UnsupportedOperationException("Immutable");
	}

	public Comparator< ? super T> comparator() {
		return cmp;
	}

	public boolean isSubSet() {
		return start > 0 && end < list.length;
	}

	public SortedList subSet(T fromElement, T toElement) {
		int start = find(fromElement);
		int end = find(toElement);
		if (isSubSet() && (start < 0 || end < 0))
			throw new IllegalArgumentException("This list is a subset");
		if (start < 0)
			start = 0;
		if (end < 0)
			end = list.length;

		return subList(start, end);
	}

	public int indexOf(Object o) {
		assert type == null || type.isInstance(o);

		int n = find((T) o);
		if (n < end && comparator.compare(o, list[n]) == 0)
			return n;

		return -1;
	}

	public int lastIndexOf(Object o) {
		assert type == null || type.isInstance(o);

		int n = find((T) o);
		if (n >= end || comparator.compare(o, list[n]) != 0)
			return -1;

		while (n < end - 1 && comparator.compare(o, list[n + 1]) == 0)
			n++;

		return n;
	}

	/**
	 * Find the first element that is equal or bigger than the given element
	 * 
	 * @param toElement
	 * @return absolute index (not relative!), returns end if not found
	 */
	private int find(T toElement) {
		int i = start;
		while (i < end) {
			if (comparator.compare(toElement, list[i]) <= 0)
				break;
			else
				i++;
		}

		return i;
	}

	public SortedSet tailSet(T fromElement) {
		int i = find(fromElement);
		return subList(i - start, end - start);
	}

	public SortedList headSet(T toElement) {
		int i = find(toElement);
		return subList(0, i - start);
	}

	public T first() {
		if (isEmpty())
			throw new NoSuchElementException("first");
		return get(0);
	}

	public T last() {
		if (isEmpty())
			throw new NoSuchElementException("last");
		return get(size() - 1);
	}

	@Deprecated
	public boolean addAll(int index, Collection< ? extends T> c) {
		throw new UnsupportedOperationException("Immutable");
	}

	public T get(int index) {
		index += start;
		if (index >= end)
			throw new ArrayIndexOutOfBoundsException();

		return list[index];
	}

	@Deprecated
	public T set(int index, T element) {
		throw new UnsupportedOperationException("Immutable");
	}

	@Deprecated
	public void add(int index, T element) {
		throw new UnsupportedOperationException("Immutable");
	}

	@Deprecated
	public T remove(int index) {
		throw new UnsupportedOperationException("Immutable");
	}

	public ListIterator listIterator() {
		return new It(start);
	}

	public ListIterator listIterator(int index) {
		return new It(index + start);
	}

	public SortedList subList(int fromIndex, int toIndex) {
		fromIndex += start;
		toIndex += start;

		if (toIndex < fromIndex) {
			int tmp = toIndex;
			toIndex = fromIndex;
			fromIndex = tmp;
		}

		toIndex = Math.max(0, toIndex);
		toIndex = Math.min(toIndex, end);
		fromIndex = Math.max(0, fromIndex);
		fromIndex = Math.min(fromIndex, end);
		if (fromIndex == start && toIndex == end)
			return this;

		if (toIndex == fromIndex)
			return (SortedList) empty();

		return new SortedList(this, fromIndex, toIndex);
	}

	@Override
	@Deprecated
	public boolean equals(Object other) {
		return super.equals(other);
	}

	@Override
	@Deprecated
	public int hashCode() {
		return super.hashCode();
	}

	public boolean isEqual(SortedList list) {
		if (size() != list.size())
			return false;

		for (int as = start, bs = list.start, al = size(); as < al && bs < al; as++, bs++) {
			if (comparator.compare(this.list[as], this.list[bs]) != 0)
				return false;
		}
		return true;
	}

	public Class< ? > getType() {
		return type;
	}

	public void setType(Class< ? > type) {
		this.type = type;
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append("[");
		String del = "";
		for (T t : this) {
			sb.append(del);
			sb.append(t);
			del = ", ";
		}

		sb.append("]");
		return sb.toString();
	}

	public boolean hasDuplicates() {
		if (list.length < 2)
			return false;

		T prev = list[0];
		for (int i = 1; i < list.length; i++) {
			if (comparator.compare(prev, list[i]) == 0)
				return true;

			prev = list[i];
		}
		return false;
	}

	public static > SortedList fromIterator(Iterator it) {
		IteratorList l = new IteratorList(it);
		return new SortedList(l);
	}

	public static  SortedList fromIterator(Iterator it, Comparator cmp) {
		IteratorList l = new IteratorList(it);
		return new SortedList(l, cmp);
	}

	public static  SortedSet empty() {
		return (SortedSet) empty;
	}

}