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

org.zoodb.jdo.internal.util.BucketStack Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2009-2013 Tilmann Zaeschke. All rights reserved.
 * 
 * This file is part of ZooDB.
 * 
 * ZooDB is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * ZooDB is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with ZooDB.  If not, see .
 * 
 * See the README and COPYING files for further information. 
 */
package org.zoodb.jdo.internal.util;

import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.NoSuchElementException;
import java.util.RandomAccess;

/**
 * Bucket array list without random access. This is best used as stack.
 * 
 * See PerfIterator for performance considerations.
 * 
 * Works like an ArrayList but is much faster when getting big, because the bucket architecture
 * avoids copying the existing list to a new array as happens in the ArrayList.
 * 
 * Features:
 * - Fast adding, removing and traversal.
 * - Speed of all operations (except clear()) independent of size.
 *  
 * Limitations:
 * - Only the last element can be removed!
 * - Elements can only be added to the end.
 * 
 * @author Tilmann Zaeschke
 */
public class BucketStack 
implements RandomAccess, java.io.Serializable, Iterable
{
	private static final long serialVersionUID = 8683452581122892189L;

	//TODO use bucket List!
	private final LinkedList buckets = new LinkedList();

	/**
	 * The size of the BucketList (the number of elements it contains).
	 */
	private int size = 0;
	private int cntInBucket;
	
	private final int bucketSize;

	//TODO this is not used much...
	private int modCount = 0;
	
	/**
	 * Constructs an empty list with an initial capacity of ten.
	 */
	public BucketStack() {
		this(1000);
	}

	/**
	 * Constructs an empty list with an initial capacity of ten.
	 * @param bucketSize 
	 */
	public BucketStack(int bucketSize) {
		this.bucketSize = bucketSize;
		cntInBucket = bucketSize;  //special value for empty list
	}

	/**
	 * Returns the number of elements in this list.
	 *
	 * @return the number of elements in this list
	 */
	public int size() {
		return size;
	}

	/**
	 * Returns true if this list contains no elements.
	 *
	 * @return true if this list contains no elements
	 */
	public boolean isEmpty() {
		return size == 0;
	}


	/**
	 * Appends the specified element to the end of this list.
	 *
	 * @param e element to be appended to this list
	 * @return true (as specified by {@link Collection#add})
	 */
	@SuppressWarnings("unchecked")
	public boolean push(E e) {
		if (cntInBucket >= bucketSize) {
			buckets.add((E[]) new Object[bucketSize]);
			cntInBucket = 0;
		}
		buckets.getLast()[cntInBucket++] = e;
		size++;
		return true;
	}
	
	public E peek() {
		return buckets.getLast()[cntInBucket-1];
	}

	/**
	 * Removes the element at the specified position in this list.
	 * Only the last element in the list can be removed.
	 *
	 * @return the element that was removed from the list
	 * @throws NoSuchElementException
	 */
	public E pop() {
		modCount++;
		
		if (size == 0) {
			throw new NoSuchElementException();
		}
		
		size--;

		if (cntInBucket == 1) {
			cntInBucket = bucketSize;
			return buckets.removeLast()[0];
		}
		return buckets.getLast()[--cntInBucket];
	}

	/**
	 * Removes all of the elements from this list.  The list will
	 * be empty after this call returns.
	 */
	public void clear() {
		modCount++;

		buckets.clear();
		cntInBucket = bucketSize;
		size = 0;
	}

	@Override
	public Iterator iterator() {
		return new BucketIterator(buckets.iterator(), size % bucketSize, modCount);
	}
	
	/**
	 * Iterator for BucketArrayList.
	 * Concurrency: 
	 * - If clear() and remove() are not used, concurrency is simple, we just remember the current 
	 *   max and iterator to it. This is effectively a COW iterator. If clear() and remove() are
	 *   used, we would have to make sure that the references are not deleted. For example:
	 *   remove() keeps references; only clear() removes the whole tree (replace by new empty 
	 *   bucket); but the iterator could keep a reference to the tree as long as required.
	 * - We could make the iterator adaptive, so it only iterates to the end of the current list.
	 *   This works nicely with clear() and remove(), but results in a somewhat unusual concurrency
	 *   policy.
	 * TODO choose and implement.
	 * 
	 *  TODO
	 *  Other improvement: may it be faster to store a stack here and keep a reference to the 
	 *  current bucket? Iteration should be faster for large pages, but Iterator creation is slower.
	 *  But for large pages, using get to find them should be fast as well. 
	 */
	private class BucketIterator implements Iterator {
		
		private int pos = bucketSize;
		private E[] currentBucket;
		private final Iterator buckets;
		private final int cntLast;
		private final int modCountI;
		
		/**
		 * @param max Maximum index = (size-1)
		 */
		private BucketIterator(Iterator buckets, int cntLast, int modCountI) {
			this.buckets = buckets;
			this.cntLast = cntLast == 0 ? bucketSize : cntLast;
			this.modCountI = modCountI;
		}

		@Override
		public boolean hasNext() {
			if (buckets.hasNext()) {
				return true;
			}
			return pos < cntLast;
		}

		@Override
		public E next() {
			if (modCountI != modCount) {
				throw new ConcurrentModificationException();
			}
			if (!hasNext()) {
				throw new NoSuchElementException();
			}
			
			if (pos >= bucketSize) {
				pos = 0;
				currentBucket = buckets.next();
			}
			return currentBucket[pos++];
		}

		@Override
		public void remove() {
			throw new UnsupportedOperationException();
		}		
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy