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

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

Go to download

The bndlib project is a general library to be used with OSGi bundles. It contains lots of cool functionality that calculates dependencies, etc.

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

import java.util.*;

/**
 * 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() {
			return get(n - 1);
		}

		public int nextIndex() {
			return (n + 1 - 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((T[]) x.clone(), 0, x.length, (Comparator) comparator);
	}

	@SuppressWarnings("cast")
	public SortedList(Comparator cmp, T... x) {
		this((T[]) 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 indexOf((T) o) >= 0;
	}

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

	public Object[] toArray() {
		return list.clone();
	}

	@SuppressWarnings("hiding")
	public  T[] toArray(T[] a) {
		if (a == null || a.length < list.length) {
			return (T[]) list.clone();
		}
		System.arraycopy(list, 0, a, 0, list.length);
		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 = indexOf(fromElement);
		int end = indexOf(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 = Arrays.binarySearch(list, (T) o, cmp);
		if (n >= start && n < end)
			return n - start;

		return -1;
	}

	public SortedList headSet(T toElement) {
		int i = indexOf(toElement);
		if (i < 0) {
			if (isSubSet())
				throw new IllegalArgumentException("This list is a subset");
			i = end;
		}

		if (i == end)
			return this;

		return subList(0, i);
	}

	public SortedSet tailSet(T fromElement) {
		int i = indexOf(fromElement);
		if (i < 0) {
			if (isSubSet())
				throw new IllegalArgumentException("This list is a subset");
			i = start;
		}

		return subList(i, end);
	}

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

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

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

	public T get(int index) {
		return list[index + start];
	}

	@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 int lastIndexOf(Object o) {
		int n = indexOf(o);
		if (n < 0)
			return -1;

		while (cmp.compare(list[n], (T) o) == 0)
			n++;

		return n;
	}

	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;

		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 s : list) {
			sb.append(del);
			sb.append(s);
			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 (prev.equals(list[i]))
				return true;
		}
		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;
	}
}