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

org.apache.jackrabbit.util.WeakIdentityCollection Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.jackrabbit.util;

import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.BitSet;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.lang.ref.ReferenceQueue;

/**
 * WeakIdentityCollection implements a Collection with weak values.
 * Equality of elements is tested using the == operator.
 * 

* This collection does not hide the fact that the garbage collector will remove * a mapping at some point in time. Thus, the {@link java.util.Iterator} returned * by this collection might return null values. The same applies * to the method {@link #toArray()} in both its variants. */ public class WeakIdentityCollection implements Collection { /** * The weak references. */ private transient WeakRef[] elementData; /** * The current number of elements in {@link #elementData}. */ private int size; /** * The reference queue to poll for references that point to unreachable * objects. */ private final ReferenceQueue refQueue = new ReferenceQueue(); /** * BitSet where a set bit indicates that the slot at this position in * {@link #elementData} is empty and can be reused. */ private final BitSet emptySlots = new BitSet(); /** * Creates a new WeakIdentityCollection. * * @param initialCapacity the initial capacity. */ public WeakIdentityCollection(int initialCapacity) { if (initialCapacity < 0) { throw new IllegalArgumentException("Illegal Capacity: " + initialCapacity); } this.elementData = new WeakRef[initialCapacity]; } /** * Returns the current size of this collection. * * @return the current size of this collection. */ public int size() { return size; } /** * Returns true if this collection is empty. * * @return true if this collection is empty. */ public boolean isEmpty() { return size == 0; } /** * Releases all references held by this collection. */ public void clear() { for (int i = 0; i < size; i++) { elementData[i] = null; } size = 0; emptySlots.clear(); } /** * Adds object o to this collection. * * @param o the object to add. * @return always true as this collection allows duplicates. * @throws NullPointerException if o is null. */ public boolean add(Object o) { if (o == null) { throw new NullPointerException("Object must not be null"); } // poll refQueue for a slot we can reuse WeakRef ref = (WeakRef) refQueue.poll(); if (ref != null) { elementData[ref.index] = new WeakRef(o, ref.index); cleanQueue(); } else if (!emptySlots.isEmpty()) { int idx = emptySlots.nextSetBit(0); elementData[idx] = new WeakRef(o, idx); emptySlots.clear(idx); } else { ensureCapacity(size + 1); elementData[size++] = new WeakRef(o, size - 1); } return true; } /** * Returns true if this collection contains o. * * @param o element whose presence in this collection is to be tested. * @return true if this collection contains the specified * element */ public boolean contains(Object o) { for (int i = 0; i < size; i++) { if (elementData[i].get() == o) { return true; } } return false; } /** * Removes the object o from this collection if it is present. * * @param o the object to remove. * @return true if this collection changed as a result of the * call. */ public boolean remove(Object o) { for (int i = 0; i < size; i++) { if (elementData[i].get() == o) { emptySlots.set(i); // overwrite entry with dummy ref elementData[i] = new WeakRef(null, i); return true; } } return false; } /** * @throws UnsupportedOperationException always. */ public boolean addAll(Collection c) { throw new UnsupportedOperationException("addAll"); } /** * @throws UnsupportedOperationException always. */ public boolean containsAll(Collection c) { throw new UnsupportedOperationException("containsAll"); } /** * @throws UnsupportedOperationException always. */ public boolean removeAll(Collection c) { throw new UnsupportedOperationException("removeAll"); } /** * @throws UnsupportedOperationException always. */ public boolean retainAll(Collection c) { throw new UnsupportedOperationException("retainAll"); } /** * Returns an {@link java.util.Iterator} over the elements of this * collection. The returned iterator is not fail-fast. That is, it does * not throw a {@link java.util.ConcurrentModificationException} if this * collection is modified while iterating over the collection. * * @return an {@link java.util.Iterator} over the elements of this * collection. */ public Iterator iterator() { return new Iter(); } /** * Returns an array containing all of the elements in this collection. The * returned array may contain null elements! * * @return an array containing all of the elements in this collection. */ public Object[] toArray() { Object[] result = new Object[size]; for (int i = 0; i < result.length; i++) { result[i] = elementData[i].get(); } return result; } /** * The returned array may contain null elements! * {@inheritDoc} */ public Object[] toArray(Object a[]) { if (a.length < size) { a = (Object[]) java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size); } for (int i = 0; i < size; i++) { a[i] = elementData[i].get(); } if (a.length > size) { a[size] = null; } return a; } /** * Ensures that the internal {@link #elementData} has * minCapacity. * * @param minCapacity the minimal capacity to ensure. */ private void ensureCapacity(int minCapacity) { int oldCapacity = elementData.length; if (minCapacity > oldCapacity) { Object oldData[] = elementData; int newCapacity = (oldCapacity * 3)/2 + 1; if (newCapacity < minCapacity) newCapacity = minCapacity; elementData = new WeakRef[newCapacity]; System.arraycopy(oldData, 0, elementData, 0, size); } } /** * Polls the reference queue until no reference is available anymore. */ private void cleanQueue() { WeakRef ref; while ((ref = (WeakRef) refQueue.poll()) != null) { emptySlots.set(ref.index); } } /** * Iterator implementation for this collecation. */ private final class Iter implements Iterator { /** * current index. */ private int index; /** * The current element data. */ private Reference[] elements = elementData; /** * The current size of this collection. */ private int size = WeakIdentityCollection.this.size; /** * @throws UnsupportedOperationException always. */ public void remove() { throw new UnsupportedOperationException("remove"); } /** * @inheritDoc */ public boolean hasNext() { return index < size; } /** * @inheritDoc */ public Object next() { if (index >= size) { throw new NoSuchElementException(); } return elements[index++].get(); } } /** * Weak reference with index value that points to the slot in {@link * WeakIdentityCollection#elementData}. */ private final class WeakRef extends WeakReference { /** * The index of this weak reference. */ private final int index; /** * Creates a new WeakRef. * * @param referent object the new weak reference will refer to. * @param index the index of this weak reference. */ public WeakRef(Object referent, int index) { super(referent, refQueue); this.index = index; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy