package org.osgl.util; import org.osgl.$; import java.io.Serializable; import java.util.*; /** * A simple array based List that support append element to the tail of * the list only. * * <p>Notes:</p> * <ul> * <li>This class is NOT thread safe. Don't use it in multiple thread context</li> * <li>{@link List#remove(int) removeX} methods are not supported</li> * <li>After running {@link #toList()} the builder is obsolete and cannot be used anymore</li> * <li>{@link #clear()} method can be called to reset the builder before calling {@link #toList()}</li> * </ul> */ public class ListBuilder<T> extends AbstractList<T> implements RandomAccess, Serializable { private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; Object[] buf; int size; ListBuilder() { this(10); } @SuppressWarnings("unchecked") private ListBuilder(Collection<? extends T> collection) { int len = collection.size(); if (len == 0) { buf = new Object[10]; } else { Object[] a0 = collection.toArray(); buf = new Object[len]; System.arraycopy(a0, 0, buf, 0, len); size = len; } } @SuppressWarnings("unchecked") public ListBuilder(int initialCapacity) { if (initialCapacity < 0 || initialCapacity > MAX_ARRAY_SIZE) { throw new IllegalArgumentException(); } buf = (T[]) new Object[initialCapacity]; } private void checkState() { if (null == buf) { throw new IllegalStateException("ListBuilder is consumed"); } } private void trimToSize() { modCount++; int oldCapacity = buf.length; if (size < oldCapacity) { buf = Arrays.copyOf(buf, size); } } private void ensureCapacity(int capacity) { if (capacity > MAX_ARRAY_SIZE) { throw new OutOfMemoryError(); } int oldCapacity = buf.length; if (capacity > oldCapacity) { int newCapacity = oldCapacity + (oldCapacity >> 1); if (newCapacity < capacity) { newCapacity = capacity; } // minCapacity is usually close to size, so this is a win: buf = Arrays.copyOf(buf, newCapacity); } } @Override public int size() { checkState(); return size; } @Override public T get(int index) { checkState(); if (index < 0 || index >= size) { throw new IndexOutOfBoundsException(); } return (T)buf[index]; } @Override public boolean add(T t) { checkState(); int sz = size++; ensureCapacity(sz + 1); buf[sz] = t; return true; } @Override public void add(int index, T element) { if (index > size) { throw new IndexOutOfBoundsException(); } checkState(); int sz = size++; ensureCapacity(sz + 1); if (index == sz) { buf[sz] = element; } else { System.arraycopy(buf, index, buf, index + 1, sz - index); buf[index] = element; } } @Override public Object[] toArray() { checkState(); return Arrays.copyOf(buf, size); } @Override @SuppressWarnings("unchecked") public <T> T[] toArray(T[] a) { checkState(); final int sz = size, len = a.length; if (len < sz) { // Make a new array of a's runtime type, but my contents: return (T[]) Arrays.copyOf(buf, sz, a.getClass()); } System.arraycopy(buf, 0, a, 0, sz); if (len > sz) { a[sz] = null; } return a; } @Override public boolean addAll(Collection <? extends T> c) { checkState(); int cSz = c.size(), oldSz = size; if (cSz < 1) { return false; } size += cSz; ensureCapacity(size); Object[] newData = c.toArray(); System.arraycopy(newData, 0, buf, oldSz, cSz); return true; // Object[] a = c.toArray(); // int numNew = a.length; // ensureCapacity(size + numNew); // Increments modCount // System.arraycopy(a, 0, buf, size, numNew); // size += numNew; // return numNew != 0; } public boolean addAll(ListBuilder<? extends T> c) { return addAll(size, c); } public boolean addAll(int index, ListBuilder<? extends T> c) { checkState(); if (index < 0 || index > size) { throw new IndexOutOfBoundsException(); } if (null == c.buf) { return false; } int cSz = c.size(), oldSz = size; if (cSz == 0) { return false; } size += cSz; ensureCapacity(size); Object[] data = buf; if (index < oldSz) { System.arraycopy(data, index, data, index + cSz, oldSz - index); } ListBuilder<T> that = (ListBuilder<T>) c; Object[] newData = that.buf; System.arraycopy(newData, 0, data, index, cSz); return true; } @Override public boolean addAll(int index, Collection<? extends T> c) { checkState(); if (index < 0 || index > size) { throw new IndexOutOfBoundsException(); } int cSz = c.size(), oldSz = size; if (cSz == 0) { return false; } size += cSz; ensureCapacity(size); Object[] data = buf; if (index < oldSz) { System.arraycopy(data, index, data, index + cSz, oldSz - index); } Object[] newData = c.toArray(); System.arraycopy(newData, 0, data, index, cSz); return true; } @Override @SuppressWarnings("unchecked") public void clear() { buf = (T[]) new Object[10]; size = 0; } public ListBuilder<T> append(T t) { add(t); return this; } public ListBuilder<T> append(Object[] ta) { checkState(); int len = ta.length, oldSz = size; size += len; ensureCapacity(size); Object[] data = buf; System.arraycopy(ta, 0, data, oldSz, len); return this; } public ListBuilder<T> append(Object[] ta1, Object[] ta2) { checkState(); int l1 = ta1.length, l2 = ta2.length, oldSz = size; size += l1 + l2; ensureCapacity(size); Object[] data = buf; System.arraycopy(ta1, 0, data, oldSz, l1); System.arraycopy(ta2, 0, data, oldSz + l1, l2); return this; } public ListBuilder<T> append(Object[] ta1, Object[] ta2, Object[]... taa) { checkState(); int l1 = ta1.length, l2 = ta2.length, oldSz = size; int len = l1 + l2; for (Object[] ta : taa) { len += ta.length; } size += len; ensureCapacity(size); Object[] data = buf; System.arraycopy(ta1, 0, data, oldSz, l1); System.arraycopy(ta2, 0, data, oldSz += l1, l2); oldSz += l2; for (Object[] ta : taa) { int l = ta.length; System.arraycopy(ta, 0, data, oldSz, l); oldSz += l; } return this; } public ListBuilder<T> append(T t1, T t2) { checkState(); size += 2; int sz = size; ensureCapacity(sz); Object[] data = buf; data[sz - 1] = t2; data[sz - 2] = t1; return this; } public ListBuilder<T> append(T t1, T t2, T t3) { checkState(); size += 3; int sz = size; ensureCapacity(sz); Object[] data = buf; data[sz - 1] = t3; data[sz - 2] = t2; data[sz - 3] = t1; return this; } public ListBuilder<T> append(T t1, T t2, T t3, T t4) { checkState(); size += 4; int sz = size; ensureCapacity(sz); Object[] data = buf; data[sz - 1] = t4; data[sz - 2] = t3; data[sz - 3] = t2; data[sz - 4] = t1; return this; } public ListBuilder<T> append(T t1, T t2, T t3, T t4, T t5) { checkState(); size += 5; int sz = size; ensureCapacity(sz); Object[] data = buf; data[sz - 1] = t5; data[sz - 2] = t4; data[sz - 3] = t3; data[sz - 4] = t2; data[sz - 5] = t1; return this; } public ListBuilder<T> append(T t1, T t2, T t3, T t4, T t5, T... ta) { checkState(); int len = ta.length, oldSz = size; size += (len + 5); ensureCapacity(size); Object[] data = buf; System.arraycopy(ta, 0, data, oldSz + 5, len); data[oldSz + 4] = t5; data[oldSz + 3] = t4; data[oldSz + 2] = t3; data[oldSz + 1] = t2; data[oldSz] = t1; return this; } public ListBuilder<T> append(Collection<? extends T> col) { addAll(col); return this; } public ListBuilder<T> append(Collection<? extends T> c1, Collection<? extends T> c2) { checkState(); int l1 = c1.size(), l2 = c2.size(), oldSz = size; size += l1 + l2; int sz = size; ensureCapacity(sz); Object[] data = buf; Object[] newData = c1.toArray(); System.arraycopy(newData, 0, data, oldSz, l1); newData = c2.toArray(); System.arraycopy(newData, 0, data, oldSz += l1, l2); return this; } public ListBuilder<T> append(Collection<? extends T> c1, Collection<? extends T> c2, Collection<? extends T>... ca ) { checkState(); int l1 = c1.size(), l2 = c2.size(), oldSz = size; int len = l1 + l2; for (Collection<? extends T> c : ca) { len += c.size(); } size += len; int sz = size; ensureCapacity(sz); Object[] data = buf; Object[] newData = c1.toArray(); System.arraycopy(newData, 0, data, oldSz, l1); newData = c2.toArray(); System.arraycopy(newData, 0, data, oldSz += l1, l2); oldSz += l2; for (Collection<? extends T> c : ca) { newData = c.toArray(); int l = newData.length; System.arraycopy(newData, 0, data, oldSz, l); oldSz += l; } return this; } @SuppressWarnings("unchecked") public ListBuilder<T> append(Iterable<? extends T> iterable) { checkState(); if (iterable instanceof Collection) { append((Collection<? extends T>) iterable); } Iterator<? extends T> e = iterable.iterator(); while (e.hasNext()) { append(e.next()); } return this; } public ListBuilder<T> append(Iterator<? extends T> iterator) { checkState(); while (iterator.hasNext()) { append(iterator.next()); } return this; } public ListBuilder<T> append(Enumeration<? extends T> enumeration) { checkState(); while (enumeration.hasMoreElements()) { append(enumeration.nextElement()); } return this; } /** * Return an immutable list contains all element of this list builder * and then release references to the internal buffer. The list builder * is obsolete after calling this method, and calling other building * method thereafter will trigger {@link IllegalStateException} * * @return an immutable list of all element of this builder */ public C.List<T> toList() { checkState(); trimToSize(); Object[] data = buf; buf = null; return (C.List<T>)ImmutableList.of(data); } public C.Set<T> toSet() { checkState(); trimToSize(); Object[] data = buf; buf = null; return (C.Set<T>)ImmutableSet.of(data); } /** * Returns an immutable {@link C.List} from iterable * @param iterable the iterable * @param <T> the element type * @return an immutable list contains all elements from the iterable */ public static <T> C.List<T> toList(Iterable<? extends T> iterable) { if (iterable instanceof Collection) { return toList((Collection<T>) iterable); } ListBuilder<T> lb = new ListBuilder<T>(10); for (T t : iterable) { lb.add(t); } return lb.toList(); } /** * Returns an immutable {@link org.osgl.util.C.List} from an iterator * @param iterator the iterator * @param <T> the element type * @return an immutable list contains all elements from the iterator */ public static <T> C.List<T> toList(Iterator<? extends T> iterator) { ListBuilder<T> lb = new ListBuilder<T>(10); lb.append(iterator); return lb.toList(); } public static <T> C.List<T> toList(Enumeration<? extends T> enumeration) { ListBuilder<T> lb = new ListBuilder<T>(10); lb.append(enumeration); return lb.toList(); } /** * Returns an immutable {@link C.List} from a collection * * @param col the collection specified * @param <T> element type * @return an immutable list contains all elements in the collection */ public static <T> C.List<T> toList(Collection<? extends T> col) { if (col.size() == 0) { return Nil.list(); } if (col instanceof C.List) { C.List<T> list = $.cast(col); if (list.is(C.Feature.IMMUTABLE)) { return list; } } return new ListBuilder<T>(col).toList(); } /** * Create an empty ListBuilder instance * * @param <T> the type of the element in the builder * @return a list builder */ public static <T> ListBuilder<T> create() { return new ListBuilder<T>(); } public static <T> ListBuilder<T> create(int initialCapacity) { return new ListBuilder<T>(initialCapacity); } }