home *** CD-ROM | disk | FTP | other *** search
- /*
- File: LinkedBuffer.java
-
- Originally written by Doug Lea and released into the public domain.
- Thanks for the assistance and support of Sun Microsystems Labs, Agorics
- Inc, Loral, and everyone contributing, testing, and using this code.
-
- History:
- Date Who What
- 24Sep95 dl@cs.oswego.edu Create from collections.java working file
- 13Oct95 dl Changed protection statuses
-
- */
-
- package collections;
-
- import java.util.Enumeration;
- import java.util.NoSuchElementException;
-
- /**
- *
- * Linked Buffer implementation of Bags. The Bag consists of
- * any number of buffers holding elements, arranged in a list.
- * Each buffer holds an array of elements. The size of each
- * buffer is the value of chunkSize that was current during the
- * operation that caused the Bag to grow. The chunkSize() may
- * be adjusted at any time. (It is not considered a version change.)
- *
- * <P>
- * All but the final buffer is always kept full.
- * When a buffer has no elements, it is released (so is
- * available for garbage collection).
- * <P>
- * LinkedBuffers are good choices for collections in which
- * you merely put a lot of things in, and then look at
- * them via enumerations, but don't often look for
- * particular elements.
- *
- * @author Doug Lea
- * @version 0.93
- *
- * <P> For an introduction to this package see <A HREF="index.html"> Overview </A>.
- **/
-
- public class LinkedBuffer extends UpdatableBagImpl implements UpdatableBag {
-
-
- /**
- * The default chunk size to use for buffers
- **/
-
- public static final int defaultChunkSize = 32;
-
- // instance variables
-
- /**
- * The last node of the circular list of chunks. Null if empty.
- **/
-
- protected CLCell tail_;
-
- /**
- * The number of elements of the tail node actually used. (all others
- * are kept full).
- **/
- protected int lastCount_;
-
- /**
- * The chunk size to use for making next buffer
- **/
-
- protected int chunkSize_;
-
- // constructors
-
- /**
- * Make an empty buffer.
- **/
- public LinkedBuffer() { this(null, 0, null, 0, defaultChunkSize); }
-
- /**
- * Make an empty buffer, using the supplied element screener.
- **/
-
- public LinkedBuffer(Predicate s) { this(s, 0, null, 0, defaultChunkSize); }
-
- /**
- * Special version of constructor needed by clone()
- **/
- protected LinkedBuffer(Predicate s, int n, CLCell t, int lc, int cs) {
- super(s);
- count_ = n;
- tail_ = t;
- lastCount_ = lc;
- chunkSize_ = cs;
- }
-
- /**
- * Make an independent copy. Does not clone elements.
- **/
- protected Object clone() throws CloneNotSupportedException {
- if (count_ == 0) return new LinkedBuffer(screener_);
- else {
- CLCell h = tail_.copyList();
- CLCell p = h;
- do {
- Object obuff[] = (Object[])(p.element());
- Object nbuff[] = new Object[obuff.length];
- for (int i = 0; i < obuff.length; ++i) nbuff[i] = obuff[i];
- p.element(nbuff);
- p = p.next();
- } while (p != h);
- return new LinkedBuffer(screener_, count_, h, lastCount_, chunkSize_);
- }
- }
-
-
- /**
- * Report the chunk size used when adding new buffers to the list
- **/
-
- public synchronized int chunkSize() { return chunkSize_; }
-
- /**
- * Set the chunk size to be used when adding new buffers to the
- * list during future add() operations.
- * Any value greater than 0 is OK. (A value of 1 makes this a
- * into very slow simulation of a linked list!)
- **/
-
- public synchronized void chunkSize(int newChunkSize)
- throws IllegalArgumentException {
- if (newChunkSize > 0)
- chunkSize_ = newChunkSize;
- else
- throw new IllegalArgumentException("Attempt to set impossible chunk size value of " + newChunkSize);
- }
-
- // Collection methods
-
- /*
- This code is pretty repetitive, but I don't know a nice way to
- separate traversal logic from actions
- */
-
- /**
- * Implements collections.Collection.includes.
- * Time complexity: O(n).
- * @see collections.Collection#includes
- **/
- public synchronized boolean includes(Object element) {
- if (element == null || count_ == 0) return false;
- CLCell p = tail_.next();
- for (;;) {
- Object buff[] = (Object[])(p.element());
- boolean isLast = p == tail_;
- int n;
- if (isLast) n = lastCount_;
- else n = buff.length;
- for (int i = 0; i < n; ++i) {
- if (buff[i].equals(element))
- return true;
- }
- if (isLast) break;
- else p = p.next();
- }
- return false;
- }
-
- /**
- * Implements collections.Collection.occurrencesOf.
- * Time complexity: O(n).
- * @see collections.Collection#occurrencesOf
- **/
- public synchronized int occurrencesOf(Object element) {
- if (element == null || count_ == 0) return 0;
- int c = 0;
- CLCell p = tail_.next();
- for (;;) {
- Object buff[] = (Object[])(p.element());
- boolean isLast = p == tail_;
- int n;
- if (isLast) n = lastCount_;
- else n = buff.length;
- for (int i = 0; i < n; ++i) {
- if (buff[i].equals(element))
- ++c;
- }
- if (isLast) break;
- else p = p.next();
- }
- return c;
- }
-
- /**
- * Implements collections.Collection.elements.
- * Time complexity: O(1).
- * @see collections.Collection#elements
- **/
- public synchronized CollectionEnumeration elements() {
- return new LBEnumeration(this, ((tail_ == null) ? null : tail_.next()));
- }
-
- // UpdatableCollection methods
-
- /**
- * Implements collections.UpdatableCollection.clear.
- * Time complexity: O(1).
- * @see collections.UpdatableCollection#clear
- **/
- public synchronized void clear() {
- setCount(0);
- tail_ = null;
- lastCount_ = 0;
- }
-
- /**
- * Implements collections.UpdatableCollection.exclude.
- * Time complexity: O(n).
- * @see collections.UpdatableCollection#exclude
- **/
- public synchronized void exclude(Object element) {
- remove_(element, true);
- }
-
-
- /**
- * Implements collections.UpdatableCollection.removeOneOf.
- * Time complexity: O(n).
- * @see collections.UpdatableCollection#removeOneOf
- **/
- public synchronized void removeOneOf(Object element) {
- remove_(element, false);
- }
-
- /**
- * Implements collections.UpdatableCollection.replaceOneOf
- * Time complexity: O(n).
- * @see collections.UpdatableCollection#replaceOneOf
- **/
- public synchronized void replaceOneOf(Object oldElement, Object newElement)
- throws IllegalElementException {
- replace_(oldElement, newElement, false);
- }
-
- /**
- * Implements collections.UpdatableCollection.replaceAllOf.
- * Time complexity: O(n).
- * @see collections.UpdatableCollection#replaceAllOf
- **/
- public synchronized void replaceAllOf(Object oldElement,
- Object newElement)
- throws IllegalElementException {
- replace_(oldElement, newElement, true);
- }
-
- /**
- * Implements collections.UpdatableCollection.take.
- * Time complexity: O(1).
- * Takes the least element.
- * @see collections.UpdatableCollection#take
- **/
- public synchronized Object take()
- throws NoSuchElementException {
- if (count_ != 0) {
- Object buff[] = (Object[])(tail_.element());
- Object v = buff[lastCount_-1];
- buff[lastCount_-1] = null;
- shrink_();
- return v;
- }
- checkIndex(0);
- return null; // not reached
- }
-
-
-
- // UpdatableBag methods
-
- /**
- * Implements collections.UpdatableBag.addIfAbsent.
- * Time complexity: O(n).
- * @see collections.UpdatableBag#addIfAbsent
- **/
- public synchronized void addIfAbsent(Object element)
- throws IllegalElementException {
- if (!includes(element)) add(element);
- }
-
-
- /**
- * Implements collections.UpdatableBag.add.
- * Time complexity: O(1).
- * @see collections.UpdatableBag#add
- **/
- public synchronized void add(Object element)
- throws IllegalElementException {
- checkElement(element);
-
- incCount();
- if (tail_ == null) {
- tail_ = new CLCell(new Object[chunkSize_]);
- lastCount_ = 0;
- }
-
- Object buff[] = (Object[])(tail_.element());
- if (lastCount_ == buff.length) {
- buff = new Object[chunkSize_];
- tail_.addNext(buff);
- tail_ = tail_.next();
- lastCount_ = 0;
- }
- buff[lastCount_++] = element;
- }
-
- /**
- * helper for remove/exclude
- **/
-
- private void remove_(Object element, boolean allOccurrences) {
- if (element == null || count_ == 0) return;
- CLCell p = tail_;
- for (;;) {
- Object buff[] = (Object[])(p.element());
- int i = (p == tail_)? lastCount_ - 1 : buff.length - 1;
- while (i >= 0) {
- if (buff[i].equals(element)) {
-
- Object lastBuff[] = (Object[])(tail_.element());
- buff[i] = lastBuff[lastCount_-1];
- lastBuff[lastCount_-1] = null;
- shrink_();
-
- if (!allOccurrences || count_ == 0)
- return;
-
- if (p == tail_ && i >= lastCount_) i = lastCount_-1;
- }
- else
- --i;
- }
- if (p == tail_.next()) break;
- else p = p.prev();
- }
- }
-
- private void replace_(Object oldElement, Object newElement, boolean allOccurrences)
- throws IllegalElementException {
- if (oldElement == null || count_ == 0 || oldElement.equals(newElement))
- return;
- CLCell p = tail_.next();
- for (;;) {
- Object buff[] = (Object[])(p.element());
- boolean isLast = p == tail_;
- int n;
- if (isLast) n = lastCount_;
- else n = buff.length;
- for (int i = 0; i < n; ++i) {
- if (buff[i].equals(oldElement)) {
- checkElement(newElement);
- incVersion();
- buff[i] = newElement;
- if (!allOccurrences)
- return;
- }
- }
- if (isLast) break;
- else p = p.next();
- }
- }
-
- private void shrink_() {
- decCount();
- lastCount_--;
- if (lastCount_ == 0) {
- if (count_ == 0)
- clear();
- else {
- CLCell tmp = tail_;
- tail_ = tail_.prev();
- tmp.unlink();
- Object buff[] = (Object[])(tail_.element());
- lastCount_ = buff.length;
- }
- }
- }
-
- // ImplementationCheckable methods
-
- /**
- * Implements collections.ImplementationCheckable.checkImplementation.
- * @see collections.ImplementationCheckable#checkImplementation
- **/
- public void checkImplementation()
- throws ImplementationError {
-
- super.checkImplementation();
- assert(chunkSize_ >= 0);
- assert(lastCount_ >= 0);
- assert(((count_ == 0) == (tail_ == null)));
-
- if (tail_ == null) return;
- int c = 0;
- CLCell p = tail_.next();
- for (;;) {
- Object buff[] = (Object[])(p.element());
- boolean isLast = p == tail_;
- int n;
- if (isLast) n = lastCount_;
- else n = buff.length;
- c += n;
- for (int i = 0; i < n; ++i) {
- Object v = buff[i];
- assert(canInclude(v) && includes(v));
- }
- if (isLast) break;
- else p = p.next();
- }
-
- assert(c == count_);
-
- }
-
- }
-
-