| /* |
| * 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.codehaus.groovy.util; |
| |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.NoSuchElementException; |
| import java.util.concurrent.ConcurrentLinkedQueue; |
| |
| /** |
| * A queue that stores values wrapped in a Reference, the type of which is |
| * determined by the provided {@link ReferenceBundle}. References stored |
| * in this queue will be removed when reference processing occurs. |
| * <p> |
| * This queue is backed by a {@link ConcurrentLinkedQueue} and is thread safe. |
| * The iterator will only return non-null values (reachable) and is based on |
| * the "weakly consistent" iterator of the underlying {@link ConcurrentLinkedQueue}. |
| * |
| * @param <T> the type of values to store |
| */ |
| public class ManagedConcurrentLinkedQueue<T> implements Iterable<T> { |
| |
| private final ReferenceBundle bundle; |
| private final ConcurrentLinkedQueue<Element<T>> queue; |
| |
| /** |
| * Creates an empty ManagedConcurrentLinkedQueue that will use the provided |
| * {@code ReferenceBundle} to store values as the given Reference |
| * type. |
| * |
| * @param bundle used to create the appropriate Reference type |
| * for the values stored |
| */ |
| public ManagedConcurrentLinkedQueue(ReferenceBundle bundle) { |
| this.bundle = bundle; |
| this.queue = new ConcurrentLinkedQueue<Element<T>>(); |
| } |
| |
| /** |
| * Adds the specified value to the queue. |
| * |
| * @param value the value to add |
| */ |
| public void add(T value) { |
| Element<T> e = new Element<T>(value); |
| queue.offer(e); |
| } |
| |
| /** |
| * Returns {@code true} if this queue contains no elements. |
| * <p> |
| * This method does not check the elements to verify they contain |
| * non-null reference values. |
| */ |
| public boolean isEmpty() { |
| return queue.isEmpty(); |
| } |
| |
| /** |
| * Returns an array containing all values from this queue in the sequence they |
| * were added. |
| * |
| * @param tArray the array to populate if big enough, else a new array with |
| * the same runtime type |
| * @return an array containing all non-null values in this queue |
| */ |
| public T[] toArray(T[] tArray) { |
| return values().toArray(tArray); |
| } |
| |
| /** |
| * Returns a list containing all values from this queue in the |
| * sequence they were added. |
| */ |
| public List<T> values() { |
| List<T> result = new ArrayList<T>(); |
| for (T t : this) { |
| result.add(t); |
| } |
| return result; |
| } |
| |
| /** |
| * Returns an iterator over all non-null values in this queue. The values should be |
| * returned in the order they were added. |
| */ |
| @Override |
| public Iterator<T> iterator() { |
| return new Itr(queue.iterator()); |
| } |
| |
| private class Element<V> extends ManagedReference<V> { |
| |
| Element(V value) { |
| super(bundle, value); |
| } |
| |
| @Override |
| public void finalizeReference() { |
| queue.remove(this); |
| super.finalizeReference(); |
| } |
| |
| } |
| |
| private class Itr implements Iterator<T> { |
| |
| final Iterator<Element<T>> wrapped; |
| |
| T value; |
| Element<T> current; |
| boolean exhausted; |
| |
| Itr(Iterator<Element<T>> wrapped) { |
| this.wrapped = wrapped; |
| } |
| |
| @Override |
| public boolean hasNext() { |
| if (!exhausted && value == null) { |
| advance(); |
| } |
| return value != null; |
| } |
| |
| @Override |
| public T next() { |
| if (!hasNext()) { |
| throw new NoSuchElementException(); |
| } |
| T next = value; |
| value = null; |
| return next; |
| } |
| |
| @Override |
| public void remove() { |
| if (current == null || value != null) { |
| throw new IllegalStateException("Next method has not been called"); |
| } |
| wrapped.remove(); |
| current = null; |
| } |
| |
| private void advance() { |
| while (wrapped.hasNext()) { |
| Element<T> e = wrapped.next(); |
| T v = e.get(); |
| if (v != null) { |
| current = e; |
| value = v; |
| return; |
| } |
| wrapped.remove(); |
| } |
| value = null; |
| current = null; |
| exhausted = true; |
| } |
| |
| } |
| |
| } |