[COLLECTION-432] Remove Buffer interface and related classes/packages.
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/collections/trunk@1468586 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
bb684e9652
commit
7dfbf675cb
|
@ -1,60 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines a collection that allows objects to be removed in some well-defined order.
|
|
||||||
* <p>
|
|
||||||
* The removal order can be based on insertion order (eg, a FIFO queue or a
|
|
||||||
* LIFO stack), on access order (eg, an LRU cache), on some arbitrary comparator
|
|
||||||
* (eg, a priority queue) or on any other well-defined ordering.
|
|
||||||
* <p>
|
|
||||||
* Note that the removal order is not necessarily the same as the iteration
|
|
||||||
* order. A <code>Buffer</code> implementation may have equivalent removal
|
|
||||||
* and iteration orders, but this is not required.
|
|
||||||
* <p>
|
|
||||||
* This interface does not specify any behavior for
|
|
||||||
* {@link Object#equals(Object)} and {@link Object#hashCode} methods. It
|
|
||||||
* is therefore possible for a <code>Buffer</code> implementation to also
|
|
||||||
* also implement {@link java.util.List}, {@link java.util.Set} or
|
|
||||||
* {@link Bag}.
|
|
||||||
*
|
|
||||||
* @param <E> the type of the elements in the buffer
|
|
||||||
* @since 2.1
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public interface Buffer<E> extends Collection<E> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets and removes the next object from the buffer.
|
|
||||||
*
|
|
||||||
* @return the next object in the buffer, which is also removed
|
|
||||||
* @throws BufferUnderflowException if the buffer is already empty
|
|
||||||
*/
|
|
||||||
E remove();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the next object from the buffer without removing it.
|
|
||||||
*
|
|
||||||
* @return the next object in the buffer, which is not removed
|
|
||||||
* @throws BufferUnderflowException if the buffer is empty
|
|
||||||
*/
|
|
||||||
E get();
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The BufferOverflowException is used when the buffer's capacity has been
|
|
||||||
* exceeded.
|
|
||||||
*
|
|
||||||
* @since 2.1
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public class BufferOverflowException extends RuntimeException {
|
|
||||||
|
|
||||||
/** Serialization version */
|
|
||||||
private static final long serialVersionUID = -3992254982265755876L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new <code>BufferOverflowException</code>.
|
|
||||||
*/
|
|
||||||
public BufferOverflowException() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a new <code>BufferOverflowException</code>.
|
|
||||||
*
|
|
||||||
* @param message the detail message for this exception
|
|
||||||
*/
|
|
||||||
public BufferOverflowException(final String message) {
|
|
||||||
this(message, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a new <code>BufferOverflowException</code>.
|
|
||||||
*
|
|
||||||
* @param message the detail message for this exception
|
|
||||||
* @param exception the root cause of the exception
|
|
||||||
*/
|
|
||||||
public BufferOverflowException(final String message, final Throwable exception) {
|
|
||||||
super(message, exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,61 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections;
|
|
||||||
|
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The BufferUnderflowException is used when the buffer is already empty.
|
|
||||||
* <p>
|
|
||||||
* NOTE: From version 3.0, this exception extends NoSuchElementException.
|
|
||||||
*
|
|
||||||
* @since 2.1
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public class BufferUnderflowException extends NoSuchElementException {
|
|
||||||
|
|
||||||
/** Serialization version */
|
|
||||||
private static final long serialVersionUID = 7106567570467436893L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new <code>BufferUnderflowException</code>.
|
|
||||||
*/
|
|
||||||
public BufferUnderflowException() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a new <code>BufferUnderflowException</code>.
|
|
||||||
*
|
|
||||||
* @param message the detail message for this exception
|
|
||||||
*/
|
|
||||||
public BufferUnderflowException(final String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct a new <code>BufferUnderflowException</code>.
|
|
||||||
*
|
|
||||||
* @param message the detail message for this exception
|
|
||||||
* @param exception the root cause of the exception
|
|
||||||
*/
|
|
||||||
public BufferUnderflowException(final String message, final Throwable exception) {
|
|
||||||
super(message);
|
|
||||||
initCause(exception);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,206 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections;
|
|
||||||
|
|
||||||
import org.apache.commons.collections.buffer.BlockingBuffer;
|
|
||||||
import org.apache.commons.collections.buffer.BoundedBuffer;
|
|
||||||
import org.apache.commons.collections.buffer.CircularFifoBuffer;
|
|
||||||
import org.apache.commons.collections.buffer.PredicatedBuffer;
|
|
||||||
import org.apache.commons.collections.buffer.SynchronizedBuffer;
|
|
||||||
import org.apache.commons.collections.buffer.TransformedBuffer;
|
|
||||||
import org.apache.commons.collections.buffer.UnmodifiableBuffer;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Provides utility methods and decorators for {@link Buffer} instances.
|
|
||||||
*
|
|
||||||
* @since 2.1
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public class BufferUtils {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An empty unmodifiable buffer.
|
|
||||||
*/
|
|
||||||
public static final Buffer<Object> EMPTY_BUFFER = UnmodifiableBuffer.unmodifiableBuffer(new CircularFifoBuffer<Object>(1));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <code>BufferUtils</code> should not normally be instantiated.
|
|
||||||
*/
|
|
||||||
public BufferUtils() {
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Returns a synchronized buffer backed by the given buffer.
|
|
||||||
* Much like the synchronized collections returned by
|
|
||||||
* {@link java.util.Collections}, you must manually synchronize on
|
|
||||||
* the returned buffer's iterator to avoid non-deterministic behavior:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* Buffer b = BufferUtils.synchronizedBuffer(myBuffer);
|
|
||||||
* synchronized (b) {
|
|
||||||
* Iterator i = b.iterator();
|
|
||||||
* while (i.hasNext()) {
|
|
||||||
* process (i.next());
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @param <E> the type of the elements in the buffer
|
|
||||||
* @param buffer the buffer to synchronize, must not be null
|
|
||||||
* @return a synchronized buffer backed by that buffer
|
|
||||||
* @throws IllegalArgumentException if the Buffer is null
|
|
||||||
*/
|
|
||||||
public static <E> Buffer<E> synchronizedBuffer(final Buffer<E> buffer) {
|
|
||||||
return SynchronizedBuffer.synchronizedBuffer(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a synchronized buffer backed by the given buffer that will
|
|
||||||
* block on {@link Buffer#get()} and {@link Buffer#remove()} operations.
|
|
||||||
* If the buffer is empty, then the {@link Buffer#get()} and
|
|
||||||
* {@link Buffer#remove()} operations will block until new elements
|
|
||||||
* are added to the buffer, rather than immediately throwing a
|
|
||||||
* <code>BufferUnderflowException</code>.
|
|
||||||
*
|
|
||||||
* @param <E> the type of the elements in the buffer
|
|
||||||
* @param buffer the buffer to synchronize, must not be null
|
|
||||||
* @return a blocking buffer backed by that buffer
|
|
||||||
* @throws IllegalArgumentException if the Buffer is null
|
|
||||||
*/
|
|
||||||
public static <E> Buffer<E> blockingBuffer(final Buffer<E> buffer) {
|
|
||||||
return BlockingBuffer.blockingBuffer(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a synchronized buffer backed by the given buffer that will
|
|
||||||
* block on {@link Buffer#get()} and {@link Buffer#remove()} operations
|
|
||||||
* until <code>timeout</code> expires. If the buffer is empty, then the
|
|
||||||
* {@link Buffer#get()} and {@link Buffer#remove()} operations will block
|
|
||||||
* until new elements are added to the buffer, rather than immediately
|
|
||||||
* throwing a <code>BufferUnderflowException</code>.
|
|
||||||
*
|
|
||||||
* @param <E> the type of the elements in the buffer
|
|
||||||
* @param buffer the buffer to synchronize, must not be null
|
|
||||||
* @param timeoutMillis the timeout value in milliseconds, zero or less for no timeout
|
|
||||||
* @return a blocking buffer backed by that buffer
|
|
||||||
* @throws IllegalArgumentException if the Buffer is null
|
|
||||||
* @since 3.2
|
|
||||||
*/
|
|
||||||
public static <E> Buffer<E> blockingBuffer(final Buffer<E> buffer, final long timeoutMillis) {
|
|
||||||
return BlockingBuffer.blockingBuffer(buffer, timeoutMillis);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a synchronized buffer backed by the given buffer that will
|
|
||||||
* block on {@link Buffer#add(Object)} and
|
|
||||||
* {@link Buffer#addAll(java.util.Collection)} until enough object(s) are
|
|
||||||
* removed from the buffer to allow the object(s) to be added and still
|
|
||||||
* maintain the maximum size.
|
|
||||||
*
|
|
||||||
* @param <E> the type of the elements in the buffer
|
|
||||||
* @param buffer the buffer to make bounded, must not be null
|
|
||||||
* @param maximumSize the maximum size
|
|
||||||
* @return a bounded buffer backed by the given buffer
|
|
||||||
* @throws IllegalArgumentException if the given buffer is null
|
|
||||||
* @since 3.2
|
|
||||||
*/
|
|
||||||
public static <E> Buffer<E> boundedBuffer(final Buffer<E> buffer, final int maximumSize) {
|
|
||||||
return BoundedBuffer.boundedBuffer(buffer, maximumSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a synchronized buffer backed by the given buffer that will
|
|
||||||
* block on {@link Buffer#add(Object)} and
|
|
||||||
* {@link Buffer#addAll(java.util.Collection)} until enough object(s) are
|
|
||||||
* removed from the buffer to allow the object(s) to be added and still
|
|
||||||
* maintain the maximum size or the timeout expires.
|
|
||||||
*
|
|
||||||
* @param <E> the type of the elements in the buffer
|
|
||||||
* @param buffer the buffer to make bounded, must not be null
|
|
||||||
* @param maximumSize the maximum size
|
|
||||||
* @param timeoutMillis the timeout value in milliseconds, zero or less for no timeout
|
|
||||||
* @return a bounded buffer backed by the given buffer
|
|
||||||
* @throws IllegalArgumentException if the given buffer is null
|
|
||||||
* @since 3.2
|
|
||||||
*/
|
|
||||||
public static <E> Buffer<E> boundedBuffer(final Buffer<E> buffer, final int maximumSize, final long timeoutMillis) {
|
|
||||||
return BoundedBuffer.boundedBuffer(buffer, maximumSize, timeoutMillis);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an unmodifiable buffer backed by the given buffer.
|
|
||||||
*
|
|
||||||
* @param <E> the type of the elements in the buffer
|
|
||||||
* @param buffer the buffer to make unmodifiable, must not be null
|
|
||||||
* @return an unmodifiable buffer backed by that buffer
|
|
||||||
* @throws IllegalArgumentException if the Buffer is null
|
|
||||||
*/
|
|
||||||
public static <E> Buffer<E> unmodifiableBuffer(final Buffer<E> buffer) {
|
|
||||||
return UnmodifiableBuffer.unmodifiableBuffer(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a predicated (validating) buffer backed by the given buffer.
|
|
||||||
* <p>
|
|
||||||
* Only objects that pass the test in the given predicate can be added to the buffer.
|
|
||||||
* Trying to add an invalid object results in an IllegalArgumentException.
|
|
||||||
* It is important not to use the original buffer after invoking this method,
|
|
||||||
* as it is a backdoor for adding invalid objects.
|
|
||||||
*
|
|
||||||
* @param <E> the type of the elements in the buffer
|
|
||||||
* @param buffer the buffer to predicate, must not be null
|
|
||||||
* @param predicate the predicate used to evaluate new elements, must not be null
|
|
||||||
* @return a predicated buffer
|
|
||||||
* @throws IllegalArgumentException if the Buffer or Predicate is null
|
|
||||||
*/
|
|
||||||
public static <E> Buffer<E> predicatedBuffer(final Buffer<E> buffer, final Predicate<? super E> predicate) {
|
|
||||||
return PredicatedBuffer.predicatedBuffer(buffer, predicate);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a transformed buffer backed by the given buffer.
|
|
||||||
* <p>
|
|
||||||
* Each object is passed through the transformer as it is added to the
|
|
||||||
* Buffer. It is important not to use the original buffer after invoking this
|
|
||||||
* method, as it is a backdoor for adding untransformed objects.
|
|
||||||
* <p>
|
|
||||||
* Existing entries in the specified buffer will not be transformed.
|
|
||||||
* If you want that behaviour, see {@link TransformedBuffer#transformedBuffer}.
|
|
||||||
*
|
|
||||||
* @param <E> the type of the elements in the buffer
|
|
||||||
* @param buffer the buffer to predicate, must not be null
|
|
||||||
* @param transformer the transformer for the buffer, must not be null
|
|
||||||
* @return a transformed buffer backed by the given buffer
|
|
||||||
* @throws IllegalArgumentException if the Buffer or Transformer is null
|
|
||||||
*/
|
|
||||||
public static <E> Buffer<E> transformingBuffer(final Buffer<E> buffer,
|
|
||||||
final Transformer<? super E, ? extends E> transformer) {
|
|
||||||
return TransformedBuffer.transformingBuffer(buffer, transformer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an empty <code>Buffer</code>.
|
|
||||||
*
|
|
||||||
* @param <E> the type of the elements in the buffer
|
|
||||||
* @return an empty {@link Buffer}
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked") // OK, empty buffer is compatible with any type
|
|
||||||
public static <E> Buffer<E> emptyBuffer() {
|
|
||||||
return (Buffer<E>) EMPTY_BUFFER;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections.buffer;
|
|
||||||
|
|
||||||
import org.apache.commons.collections.Buffer;
|
|
||||||
import org.apache.commons.collections.collection.AbstractCollectionDecorator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decorates another {@link Buffer} to provide additional behaviour.
|
|
||||||
* <p>
|
|
||||||
* Methods are forwarded directly to the decorated buffer.
|
|
||||||
*
|
|
||||||
* @param <E> the type of the elements in the buffer
|
|
||||||
* @since 3.0
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public abstract class AbstractBufferDecorator<E> extends AbstractCollectionDecorator<E>
|
|
||||||
implements Buffer<E> {
|
|
||||||
|
|
||||||
/** Serialization version */
|
|
||||||
private static final long serialVersionUID = -2629815475789577029L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor only used in deserialization, do not use otherwise.
|
|
||||||
* @since 3.1
|
|
||||||
*/
|
|
||||||
protected AbstractBufferDecorator() {
|
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor that wraps (not copies).
|
|
||||||
*
|
|
||||||
* @param buffer the buffer to decorate, must not be null
|
|
||||||
* @throws IllegalArgumentException if list is null
|
|
||||||
*/
|
|
||||||
protected AbstractBufferDecorator(final Buffer<E> buffer) {
|
|
||||||
super(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the buffer being decorated.
|
|
||||||
*
|
|
||||||
* @return the decorated buffer
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected Buffer<E> decorated() {
|
|
||||||
return (Buffer<E>) super.decorated();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
|
|
||||||
public E get() {
|
|
||||||
return decorated().get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public E remove() {
|
|
||||||
return decorated().remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,243 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections.buffer;
|
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
import org.apache.commons.collections.Buffer;
|
|
||||||
import org.apache.commons.collections.BufferUnderflowException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decorates another {@link Buffer} to make {@link #get()} and
|
|
||||||
* {@link #remove()} block when the <code>Buffer</code> is empty.
|
|
||||||
* <p>
|
|
||||||
* If either <code>get</code> or <code>remove</code> is called on an empty
|
|
||||||
* {@link Buffer}, the calling thread waits for notification that
|
|
||||||
* an <code>add</code> or <code>addAll</code> operation has completed.
|
|
||||||
* <p>
|
|
||||||
* When one or more entries are added to an empty {@link Buffer},
|
|
||||||
* all threads blocked in <code>get</code> or <code>remove</code> are notified.
|
|
||||||
* There is no guarantee that concurrent blocked <code>get</code> or
|
|
||||||
* <code>remove</code> requests will be "unblocked" and receive data in the
|
|
||||||
* order that they arrive.
|
|
||||||
* <p>
|
|
||||||
* This class is Serializable from Commons Collections 3.1.
|
|
||||||
* This class contains an extra field in 3.2, however the serialization
|
|
||||||
* specification will handle this gracefully.
|
|
||||||
*
|
|
||||||
* @param <E> the type of the elements in the buffer
|
|
||||||
* @version $Id$
|
|
||||||
* @since 3.0
|
|
||||||
*/
|
|
||||||
public class BlockingBuffer<E> extends SynchronizedBuffer<E> {
|
|
||||||
|
|
||||||
/** Serialization version. */
|
|
||||||
private static final long serialVersionUID = 1719328905017860541L;
|
|
||||||
/** The timeout value in milliseconds. */
|
|
||||||
private final long timeout;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory method to create a blocking buffer.
|
|
||||||
*
|
|
||||||
* @param <E> the type of the elements in the buffer
|
|
||||||
* @param buffer the buffer to decorate, must not be null
|
|
||||||
* @return a new blocking Buffer
|
|
||||||
* @throws IllegalArgumentException if buffer is null
|
|
||||||
*/
|
|
||||||
public static <E> BlockingBuffer<E> blockingBuffer(final Buffer<E> buffer) {
|
|
||||||
return new BlockingBuffer<E>(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory method to create a blocking buffer with a timeout value.
|
|
||||||
*
|
|
||||||
* @param <E> the type of the elements in the buffer
|
|
||||||
* @param buffer the buffer to decorate, must not be null
|
|
||||||
* @param timeoutMillis the timeout value in milliseconds, zero or less for no timeout
|
|
||||||
* @return a new blocking buffer
|
|
||||||
* @throws IllegalArgumentException if the buffer is null
|
|
||||||
* @since 3.2
|
|
||||||
*/
|
|
||||||
public static <E> BlockingBuffer<E> blockingBuffer(final Buffer<E> buffer, final long timeoutMillis) {
|
|
||||||
return new BlockingBuffer<E>(buffer, timeoutMillis);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Constructor that wraps (not copies).
|
|
||||||
*
|
|
||||||
* @param buffer the buffer to decorate, must not be null
|
|
||||||
* @throws IllegalArgumentException if the buffer is null
|
|
||||||
*/
|
|
||||||
protected BlockingBuffer(final Buffer<E> buffer) {
|
|
||||||
super(buffer);
|
|
||||||
this.timeout = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor that wraps (not copies).
|
|
||||||
*
|
|
||||||
* @param buffer the buffer to decorate, must not be null
|
|
||||||
* @param timeoutMillis the timeout value in milliseconds, zero or less for no timeout
|
|
||||||
* @throws IllegalArgumentException if the buffer is null
|
|
||||||
* @since 3.2
|
|
||||||
*/
|
|
||||||
protected BlockingBuffer(final Buffer<E> buffer, final long timeoutMillis) {
|
|
||||||
super(buffer);
|
|
||||||
this.timeout = timeoutMillis < 0 ? 0 : timeoutMillis;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
@Override
|
|
||||||
public boolean add(final E o) {
|
|
||||||
synchronized (lock) {
|
|
||||||
final boolean result = collection.add(o);
|
|
||||||
lock.notifyAll();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean addAll(final Collection<? extends E> c) {
|
|
||||||
synchronized (lock) {
|
|
||||||
final boolean result = collection.addAll(c);
|
|
||||||
lock.notifyAll();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the next value from the buffer, waiting until an object is
|
|
||||||
* added if the buffer is empty. This method uses the default timeout
|
|
||||||
* set in the constructor.
|
|
||||||
*
|
|
||||||
* @throws BufferUnderflowException if an interrupt is received
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public E get() {
|
|
||||||
synchronized (lock) {
|
|
||||||
while (collection.isEmpty()) {
|
|
||||||
try {
|
|
||||||
if (timeout <= 0) {
|
|
||||||
lock.wait();
|
|
||||||
} else {
|
|
||||||
return get(timeout);
|
|
||||||
}
|
|
||||||
} catch (final InterruptedException e) {
|
|
||||||
final PrintWriter out = new PrintWriter(new StringWriter());
|
|
||||||
e.printStackTrace(out);
|
|
||||||
throw new BufferUnderflowException("Caused by InterruptedException: " + out.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return decorated().get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the next value from the buffer, waiting until an object is
|
|
||||||
* added for up to the specified timeout value if the buffer is empty.
|
|
||||||
*
|
|
||||||
* @param timeout the timeout value in milliseconds
|
|
||||||
* @return the next object in the buffer
|
|
||||||
* @throws BufferUnderflowException if an interrupt is received
|
|
||||||
* @throws BufferUnderflowException if the timeout expires
|
|
||||||
* @since 3.2
|
|
||||||
*/
|
|
||||||
public E get(final long timeout) {
|
|
||||||
synchronized (lock) {
|
|
||||||
final long expiration = System.currentTimeMillis() + timeout;
|
|
||||||
long timeLeft = expiration - System.currentTimeMillis();
|
|
||||||
while (timeLeft > 0 && collection.isEmpty()) {
|
|
||||||
try {
|
|
||||||
lock.wait(timeLeft);
|
|
||||||
timeLeft = expiration - System.currentTimeMillis();
|
|
||||||
} catch(final InterruptedException e) {
|
|
||||||
final PrintWriter out = new PrintWriter(new StringWriter());
|
|
||||||
e.printStackTrace(out);
|
|
||||||
throw new BufferUnderflowException("Caused by InterruptedException: " + out.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (collection.isEmpty()) {
|
|
||||||
throw new BufferUnderflowException("Timeout expired");
|
|
||||||
}
|
|
||||||
return decorated().get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the next value from the buffer, waiting until an object is
|
|
||||||
* added if the buffer is empty. This method uses the default timeout
|
|
||||||
* set in the constructor.
|
|
||||||
*
|
|
||||||
* @throws BufferUnderflowException if an interrupt is received
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public E remove() {
|
|
||||||
synchronized (lock) {
|
|
||||||
while (collection.isEmpty()) {
|
|
||||||
try {
|
|
||||||
if (timeout <= 0) {
|
|
||||||
lock.wait();
|
|
||||||
} else {
|
|
||||||
return remove(timeout);
|
|
||||||
}
|
|
||||||
} catch (final InterruptedException e) {
|
|
||||||
final PrintWriter out = new PrintWriter(new StringWriter());
|
|
||||||
e.printStackTrace(out);
|
|
||||||
throw new BufferUnderflowException("Caused by InterruptedException: " + out.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return decorated().remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the next value from the buffer, waiting until an object is
|
|
||||||
* added for up to the specified timeout value if the buffer is empty.
|
|
||||||
*
|
|
||||||
* @param timeout the timeout value in milliseconds
|
|
||||||
* @return the next object in the buffer, which is also removed
|
|
||||||
* @throws BufferUnderflowException if an interrupt is received
|
|
||||||
* @throws BufferUnderflowException if the timeout expires
|
|
||||||
* @since 3.2
|
|
||||||
*/
|
|
||||||
public E remove(final long timeout) {
|
|
||||||
synchronized (lock) {
|
|
||||||
final long expiration = System.currentTimeMillis() + timeout;
|
|
||||||
long timeLeft = expiration - System.currentTimeMillis();
|
|
||||||
while (timeLeft > 0 && collection.isEmpty()) {
|
|
||||||
try {
|
|
||||||
lock.wait(timeLeft);
|
|
||||||
timeLeft = expiration - System.currentTimeMillis();
|
|
||||||
} catch(final InterruptedException e) {
|
|
||||||
final PrintWriter out = new PrintWriter(new StringWriter());
|
|
||||||
e.printStackTrace(out);
|
|
||||||
throw new BufferUnderflowException("Caused by InterruptedException: " + out.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (collection.isEmpty()) {
|
|
||||||
throw new BufferUnderflowException("Timeout expired");
|
|
||||||
}
|
|
||||||
return decorated().remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,213 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections.buffer;
|
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.io.StringWriter;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
import org.apache.commons.collections.BoundedCollection;
|
|
||||||
import org.apache.commons.collections.Buffer;
|
|
||||||
import org.apache.commons.collections.BufferOverflowException;
|
|
||||||
import org.apache.commons.collections.BufferUnderflowException;
|
|
||||||
import org.apache.commons.collections.iterators.AbstractIteratorDecorator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decorates another {@link Buffer} to ensure a fixed maximum size.
|
|
||||||
* <p>
|
|
||||||
* Note: This class should only be used if you need to add bounded
|
|
||||||
* behaviour to another buffer. If you just want a bounded buffer then
|
|
||||||
* you should use {@link BoundedFifoBuffer} or {@link CircularFifoBuffer}.
|
|
||||||
* <p>
|
|
||||||
* The decoration methods allow you to specify a timeout value.
|
|
||||||
* This alters the behaviour of the add methods when the buffer is full.
|
|
||||||
* Normally, when the buffer is full, the add method will throw an exception.
|
|
||||||
* With a timeout, the add methods will wait for up to the timeout period
|
|
||||||
* to try and add the elements.
|
|
||||||
*
|
|
||||||
* @since 3.2
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public class BoundedBuffer<E> extends SynchronizedBuffer<E> implements BoundedCollection<E> {
|
|
||||||
|
|
||||||
/** The serialization version. */
|
|
||||||
private static final long serialVersionUID = 1536432911093974264L;
|
|
||||||
|
|
||||||
/** The maximum size. */
|
|
||||||
private final int maximumSize;
|
|
||||||
/** The timeout milliseconds. */
|
|
||||||
private final long timeout;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory method to create a bounded buffer.
|
|
||||||
* <p>
|
|
||||||
* When the buffer is full, it will immediately throw a
|
|
||||||
* <code>BufferOverflowException</code> on calling {@link #add(Object)}.
|
|
||||||
*
|
|
||||||
* @param <E> the type of the elements in the buffer
|
|
||||||
* @param buffer the buffer to decorate, must not be null
|
|
||||||
* @param maximumSize the maximum size, must be size one or greater
|
|
||||||
* @return a new bounded buffer
|
|
||||||
* @throws IllegalArgumentException if the buffer is null
|
|
||||||
* @throws IllegalArgumentException if the maximum size is zero or less
|
|
||||||
*/
|
|
||||||
public static <E> BoundedBuffer<E> boundedBuffer(final Buffer<E> buffer, final int maximumSize) {
|
|
||||||
return new BoundedBuffer<E>(buffer, maximumSize, 0L);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory method to create a bounded buffer that blocks for a maximum
|
|
||||||
* amount of time.
|
|
||||||
*
|
|
||||||
* @param <E> the type of the elements in the buffer
|
|
||||||
* @param buffer the buffer to decorate, must not be null
|
|
||||||
* @param maximumSize the maximum size, must be size one or greater
|
|
||||||
* @param timeout the maximum amount of time to wait in milliseconds
|
|
||||||
* @return a new bounded buffer
|
|
||||||
* @throws IllegalArgumentException if the buffer is null
|
|
||||||
* @throws IllegalArgumentException if the maximum size is zero or less
|
|
||||||
*/
|
|
||||||
public static <E> BoundedBuffer<E> boundedBuffer(final Buffer<E> buffer, final int maximumSize,
|
|
||||||
final long timeout) {
|
|
||||||
return new BoundedBuffer<E>(buffer, maximumSize, timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Constructor that wraps (not copies) another buffer, making it bounded
|
|
||||||
* waiting only up to a maximum amount of time.
|
|
||||||
*
|
|
||||||
* @param buffer the buffer to wrap, must not be null
|
|
||||||
* @param maximumSize the maximum size, must be size one or greater
|
|
||||||
* @param timeout the maximum amount of time to wait
|
|
||||||
* @throws IllegalArgumentException if the buffer is null
|
|
||||||
* @throws IllegalArgumentException if the maximum size is zero or less
|
|
||||||
*/
|
|
||||||
protected BoundedBuffer(final Buffer<E> buffer, final int maximumSize, final long timeout) {
|
|
||||||
super(buffer);
|
|
||||||
if (maximumSize < 1) {
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
}
|
|
||||||
this.maximumSize = maximumSize;
|
|
||||||
this.timeout = timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
@Override
|
|
||||||
public E remove() {
|
|
||||||
synchronized (lock) {
|
|
||||||
final E returnValue = decorated().remove();
|
|
||||||
lock.notifyAll();
|
|
||||||
return returnValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean add(final E o) {
|
|
||||||
synchronized (lock) {
|
|
||||||
timeoutWait(1);
|
|
||||||
return decorated().add(o);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean addAll(final Collection<? extends E> c) {
|
|
||||||
synchronized (lock) {
|
|
||||||
timeoutWait(c.size());
|
|
||||||
return decorated().addAll(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<E> iterator() {
|
|
||||||
return new NotifyingIterator(collection.iterator());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Waits up to the specified timeout period that the given number of additions
|
|
||||||
* can be made to the buffer.
|
|
||||||
*
|
|
||||||
* @param nAdditions the number of additions
|
|
||||||
* @throws BufferOverflowException if the number of additions would overflow the buffer,
|
|
||||||
* or the timeout has expired
|
|
||||||
*/
|
|
||||||
private void timeoutWait(final int nAdditions) {
|
|
||||||
// method synchronized by callers
|
|
||||||
if (nAdditions > maximumSize) {
|
|
||||||
throw new BufferOverflowException(
|
|
||||||
"Buffer size cannot exceed " + maximumSize);
|
|
||||||
}
|
|
||||||
if (timeout <= 0) {
|
|
||||||
// no wait period (immediate timeout)
|
|
||||||
if (decorated().size() + nAdditions > maximumSize) {
|
|
||||||
throw new BufferOverflowException(
|
|
||||||
"Buffer size cannot exceed " + maximumSize);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final long expiration = System.currentTimeMillis() + timeout;
|
|
||||||
long timeLeft = expiration - System.currentTimeMillis();
|
|
||||||
while (timeLeft > 0 && decorated().size() + nAdditions > maximumSize) {
|
|
||||||
try {
|
|
||||||
lock.wait(timeLeft);
|
|
||||||
timeLeft = expiration - System.currentTimeMillis();
|
|
||||||
} catch (final InterruptedException ex) {
|
|
||||||
final PrintWriter out = new PrintWriter(new StringWriter());
|
|
||||||
ex.printStackTrace(out);
|
|
||||||
throw new BufferUnderflowException(
|
|
||||||
"Caused by InterruptedException: " + out.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (decorated().size() + nAdditions > maximumSize) {
|
|
||||||
throw new BufferOverflowException("Timeout expired");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFull() {
|
|
||||||
// size() is synchronized
|
|
||||||
return size() == maxSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int maxSize() {
|
|
||||||
return maximumSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* BoundedBuffer iterator.
|
|
||||||
*/
|
|
||||||
private class NotifyingIterator extends AbstractIteratorDecorator<E> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new {@link NotifyingIterator}.
|
|
||||||
*
|
|
||||||
* @param it the decorated {@link Iterator}
|
|
||||||
*/
|
|
||||||
public NotifyingIterator(final Iterator<E> it) {
|
|
||||||
super(it);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void remove() {
|
|
||||||
synchronized (lock) {
|
|
||||||
iterator.remove();
|
|
||||||
lock.notifyAll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,404 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections.buffer;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.AbstractCollection;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
|
|
||||||
import org.apache.commons.collections.BoundedCollection;
|
|
||||||
import org.apache.commons.collections.Buffer;
|
|
||||||
import org.apache.commons.collections.BufferOverflowException;
|
|
||||||
import org.apache.commons.collections.BufferUnderflowException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The {@link BoundedFifoBuffer} is a very efficient implementation of a
|
|
||||||
* {@link Buffer} with a fixed size.
|
|
||||||
* <p>
|
|
||||||
* The removal order of a {@link BoundedFifoBuffer} is based on the
|
|
||||||
* insertion order; elements are removed in the same order in which they
|
|
||||||
* were added. The iteration order is the same as the removal order.
|
|
||||||
* <p>
|
|
||||||
* The {@link #add(Object)}, {@link #remove()} and {@link #get()} operations
|
|
||||||
* all perform in constant time. All other operations perform in linear
|
|
||||||
* time or worse.
|
|
||||||
* <p>
|
|
||||||
* Note that this implementation is not synchronized. The following can be
|
|
||||||
* used to provide synchronized access to your <code>BoundedFifoBuffer</code>:
|
|
||||||
* <pre>
|
|
||||||
* Buffer fifo = BufferUtils.synchronizedBuffer(new BoundedFifoBuffer());
|
|
||||||
* </pre>
|
|
||||||
* <p>
|
|
||||||
* This buffer prevents null objects from being added.
|
|
||||||
* <p>
|
|
||||||
* This class is Serializable from Commons Collections 3.1.
|
|
||||||
*
|
|
||||||
* @since 3.0 (previously in main package v2.1)
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public class BoundedFifoBuffer<E> extends AbstractCollection<E>
|
|
||||||
implements Buffer<E>, BoundedCollection<E>, Serializable {
|
|
||||||
|
|
||||||
/** Serialization version */
|
|
||||||
private static final long serialVersionUID = 5603722811189451017L;
|
|
||||||
|
|
||||||
/** Underlying storage array */
|
|
||||||
private transient E[] elements;
|
|
||||||
|
|
||||||
/** Array index of first (oldest) buffer element */
|
|
||||||
private transient int start = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Index mod maxElements of the array position following the last buffer
|
|
||||||
* element. Buffer elements start at elements[start] and "wrap around"
|
|
||||||
* elements[maxElements-1], ending at elements[decrement(end)].
|
|
||||||
* For example, elements = {c,a,b}, start=1, end=1 corresponds to
|
|
||||||
* the buffer [a,b,c].
|
|
||||||
*/
|
|
||||||
private transient int end = 0;
|
|
||||||
|
|
||||||
/** Flag to indicate if the buffer is currently full. */
|
|
||||||
private transient boolean full = false;
|
|
||||||
|
|
||||||
/** Capacity of the buffer */
|
|
||||||
private final int maxElements;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new <code>BoundedFifoBuffer</code> big enough to hold
|
|
||||||
* 32 elements.
|
|
||||||
*/
|
|
||||||
public BoundedFifoBuffer() {
|
|
||||||
this(32);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new <code>BoundedFifoBuffer</code> big enough to hold
|
|
||||||
* the specified number of elements.
|
|
||||||
*
|
|
||||||
* @param size the maximum number of elements for this fifo
|
|
||||||
* @throws IllegalArgumentException if the size is less than 1
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public BoundedFifoBuffer(final int size) {
|
|
||||||
if (size <= 0) {
|
|
||||||
throw new IllegalArgumentException("The size must be greater than 0");
|
|
||||||
}
|
|
||||||
elements = (E[]) new Object[size];
|
|
||||||
maxElements = elements.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new <code>BoundedFifoBuffer</code> big enough to hold all
|
|
||||||
* of the elements in the specified collection. That collection's
|
|
||||||
* elements will also be added to the buffer.
|
|
||||||
*
|
|
||||||
* @param coll the collection whose elements to add, may not be null
|
|
||||||
* @throws NullPointerException if the collection is null
|
|
||||||
*/
|
|
||||||
public BoundedFifoBuffer(final Collection<? extends E> coll) {
|
|
||||||
this(coll.size());
|
|
||||||
addAll(coll);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Write the buffer out using a custom routine.
|
|
||||||
*
|
|
||||||
* @param out the output stream
|
|
||||||
* @throws IOException if an I/O error occurs while writing to the output stream
|
|
||||||
*/
|
|
||||||
private void writeObject(final ObjectOutputStream out) throws IOException {
|
|
||||||
out.defaultWriteObject();
|
|
||||||
out.writeInt(size());
|
|
||||||
for (final E e : this) {
|
|
||||||
out.writeObject(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read the buffer in using a custom routine.
|
|
||||||
*
|
|
||||||
* @param in the input stream
|
|
||||||
* @throws IOException if an I/O error occurs while writing to the output stream
|
|
||||||
* @throws ClassNotFoundException if the class of a serialized object can not be found
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
|
|
||||||
in.defaultReadObject();
|
|
||||||
elements = (E[]) new Object[maxElements];
|
|
||||||
final int size = in.readInt();
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
elements[i] = (E) in.readObject();
|
|
||||||
}
|
|
||||||
start = 0;
|
|
||||||
full = size == maxElements;
|
|
||||||
if (full) {
|
|
||||||
end = 0;
|
|
||||||
} else {
|
|
||||||
end = size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Returns the number of elements stored in the buffer.
|
|
||||||
*
|
|
||||||
* @return this buffer's size
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int size() {
|
|
||||||
int size = 0;
|
|
||||||
|
|
||||||
if (end < start) {
|
|
||||||
size = maxElements - start + end;
|
|
||||||
} else if (end == start) {
|
|
||||||
size = full ? maxElements : 0;
|
|
||||||
} else {
|
|
||||||
size = end - start;
|
|
||||||
}
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if this buffer is empty; false otherwise.
|
|
||||||
*
|
|
||||||
* @return true if this buffer is empty
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return size() == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if this collection is full and no new elements can be added.
|
|
||||||
*
|
|
||||||
* @return <code>true</code> if the collection is full
|
|
||||||
*/
|
|
||||||
public boolean isFull() {
|
|
||||||
return size() == maxElements;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the maximum size of the collection (the bound).
|
|
||||||
*
|
|
||||||
* @return the maximum number of elements the collection can hold
|
|
||||||
*/
|
|
||||||
public int maxSize() {
|
|
||||||
return maxElements;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears this buffer.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
full = false;
|
|
||||||
start = 0;
|
|
||||||
end = 0;
|
|
||||||
Arrays.fill(elements, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the given element to this buffer.
|
|
||||||
*
|
|
||||||
* @param element the element to add
|
|
||||||
* @return true, always
|
|
||||||
* @throws NullPointerException if the given element is null
|
|
||||||
* @throws BufferOverflowException if this buffer is full
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean add(final E element) {
|
|
||||||
if (null == element) {
|
|
||||||
throw new NullPointerException("Attempted to add null object to buffer");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (full) {
|
|
||||||
throw new BufferOverflowException("The buffer cannot hold more than " + maxElements + " objects.");
|
|
||||||
}
|
|
||||||
|
|
||||||
elements[end++] = element;
|
|
||||||
|
|
||||||
if (end >= maxElements) {
|
|
||||||
end = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (end == start) {
|
|
||||||
full = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the least recently inserted element in this buffer.
|
|
||||||
*
|
|
||||||
* @return the least recently inserted element
|
|
||||||
* @throws BufferUnderflowException if the buffer is empty
|
|
||||||
*/
|
|
||||||
public E get() {
|
|
||||||
if (isEmpty()) {
|
|
||||||
throw new BufferUnderflowException("The buffer is already empty");
|
|
||||||
}
|
|
||||||
return elements[start];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the element at the specified position in this buffer.
|
|
||||||
*
|
|
||||||
* @param index the position of the element in the buffer
|
|
||||||
* @return the element at position {@code index}
|
|
||||||
* @throws NoSuchElementException if the requested position is outside the range [0, size)
|
|
||||||
*/
|
|
||||||
public E get(final int index) {
|
|
||||||
final int sz = size();
|
|
||||||
if (index < 0 || index >= sz) {
|
|
||||||
throw new NoSuchElementException(
|
|
||||||
String.format("The specified index (%1$d) is outside the available range [0, %2$d)",
|
|
||||||
index, sz));
|
|
||||||
}
|
|
||||||
|
|
||||||
final int idx = (start + index) % maxElements;
|
|
||||||
return elements[idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the least recently inserted element from this buffer.
|
|
||||||
*
|
|
||||||
* @return the least recently inserted element
|
|
||||||
* @throws BufferUnderflowException if the buffer is empty
|
|
||||||
*/
|
|
||||||
public E remove() {
|
|
||||||
if (isEmpty()) {
|
|
||||||
throw new BufferUnderflowException("The buffer is already empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
final E element = elements[start];
|
|
||||||
|
|
||||||
if (null != element) {
|
|
||||||
elements[start++] = null;
|
|
||||||
|
|
||||||
if (start >= maxElements) {
|
|
||||||
start = 0;
|
|
||||||
}
|
|
||||||
full = false;
|
|
||||||
}
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Increments the internal index.
|
|
||||||
*
|
|
||||||
* @param index the index to increment
|
|
||||||
* @return the updated index
|
|
||||||
*/
|
|
||||||
private int increment(int index) {
|
|
||||||
index++;
|
|
||||||
if (index >= maxElements) {
|
|
||||||
index = 0;
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decrements the internal index.
|
|
||||||
*
|
|
||||||
* @param index the index to decrement
|
|
||||||
* @return the updated index
|
|
||||||
*/
|
|
||||||
private int decrement(int index) {
|
|
||||||
index--;
|
|
||||||
if (index < 0) {
|
|
||||||
index = maxElements - 1;
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an iterator over this buffer's elements.
|
|
||||||
*
|
|
||||||
* @return an iterator over this buffer's elements
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Iterator<E> iterator() {
|
|
||||||
return new Iterator<E>() {
|
|
||||||
|
|
||||||
private int index = start;
|
|
||||||
private int lastReturnedIndex = -1;
|
|
||||||
private boolean isFirst = full;
|
|
||||||
|
|
||||||
public boolean hasNext() {
|
|
||||||
return isFirst || index != end;
|
|
||||||
}
|
|
||||||
|
|
||||||
public E next() {
|
|
||||||
if (!hasNext()) {
|
|
||||||
throw new NoSuchElementException();
|
|
||||||
}
|
|
||||||
isFirst = false;
|
|
||||||
lastReturnedIndex = index;
|
|
||||||
index = increment(index);
|
|
||||||
return elements[lastReturnedIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove() {
|
|
||||||
if (lastReturnedIndex == -1) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
// First element can be removed quickly
|
|
||||||
if (lastReturnedIndex == start) {
|
|
||||||
BoundedFifoBuffer.this.remove();
|
|
||||||
lastReturnedIndex = -1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int pos = lastReturnedIndex + 1;
|
|
||||||
if (start < lastReturnedIndex && pos < end) {
|
|
||||||
// shift in one part
|
|
||||||
System.arraycopy(elements, pos, elements,
|
|
||||||
lastReturnedIndex, end - pos);
|
|
||||||
} else {
|
|
||||||
// Other elements require us to shift the subsequent elements
|
|
||||||
while (pos != end) {
|
|
||||||
if (pos >= maxElements) {
|
|
||||||
elements[pos - 1] = elements[0];
|
|
||||||
pos = 0;
|
|
||||||
} else {
|
|
||||||
elements[decrement(pos)] = elements[pos];
|
|
||||||
pos = increment(pos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lastReturnedIndex = -1;
|
|
||||||
end = decrement(end);
|
|
||||||
elements[end] = null;
|
|
||||||
full = false;
|
|
||||||
index = decrement(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,94 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections.buffer;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* CircularFifoBuffer is a first in first out buffer with a fixed size that
|
|
||||||
* replaces its oldest element if full.
|
|
||||||
* <p>
|
|
||||||
* The removal order of a {@link CircularFifoBuffer} is based on the
|
|
||||||
* insertion order; elements are removed in the same order in which they
|
|
||||||
* were added. The iteration order is the same as the removal order.
|
|
||||||
* <p>
|
|
||||||
* The {@link #add(Object)}, {@link #remove()} and {@link #get()} operations
|
|
||||||
* all perform in constant time. All other operations perform in linear
|
|
||||||
* time or worse.
|
|
||||||
* <p>
|
|
||||||
* Note that this implementation is not synchronized. The following can be
|
|
||||||
* used to provide synchronized access to your <code>CircularFifoBuffer</code>:
|
|
||||||
* <pre>
|
|
||||||
* Buffer fifo = BufferUtils.synchronizedBuffer(new CircularFifoBuffer());
|
|
||||||
* </pre>
|
|
||||||
* <p>
|
|
||||||
* This buffer prevents null objects from being added.
|
|
||||||
* <p>
|
|
||||||
* This class is Serializable from Commons Collections 3.1.
|
|
||||||
*
|
|
||||||
* @since 3.0
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public class CircularFifoBuffer<E> extends BoundedFifoBuffer<E> {
|
|
||||||
|
|
||||||
/** Serialization version */
|
|
||||||
private static final long serialVersionUID = -8423413834657610406L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor that creates a buffer with the default size of 32.
|
|
||||||
*/
|
|
||||||
public CircularFifoBuffer() {
|
|
||||||
super(32);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor that creates a buffer with the specified size.
|
|
||||||
*
|
|
||||||
* @param size the size of the buffer (cannot be changed)
|
|
||||||
* @throws IllegalArgumentException if the size is less than 1
|
|
||||||
*/
|
|
||||||
public CircularFifoBuffer(final int size) {
|
|
||||||
super(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor that creates a buffer from the specified collection.
|
|
||||||
* The collection size also sets the buffer size
|
|
||||||
*
|
|
||||||
* @param coll the collection to copy into the buffer, may not be null
|
|
||||||
* @throws NullPointerException if the collection is null
|
|
||||||
*/
|
|
||||||
public CircularFifoBuffer(final Collection<E> coll) {
|
|
||||||
super(coll);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If the buffer is full, the least recently added element is discarded so
|
|
||||||
* that a new element can be inserted.
|
|
||||||
*
|
|
||||||
* @param element the element to add
|
|
||||||
* @return true, always
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean add(final E element) {
|
|
||||||
if (isFull()) {
|
|
||||||
remove();
|
|
||||||
}
|
|
||||||
return super.add(element);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,98 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections.buffer;
|
|
||||||
|
|
||||||
import org.apache.commons.collections.Buffer;
|
|
||||||
import org.apache.commons.collections.Predicate;
|
|
||||||
import org.apache.commons.collections.collection.PredicatedCollection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decorates another {@link Buffer} to validate that additions
|
|
||||||
* match a specified predicate.
|
|
||||||
* <p>
|
|
||||||
* This buffer exists to provide validation for the decorated buffer.
|
|
||||||
* It is normally created to decorate an empty buffer.
|
|
||||||
* If an object cannot be added to the buffer, an IllegalArgumentException is thrown.
|
|
||||||
* <p>
|
|
||||||
* One usage would be to ensure that no null entries are added to the buffer.
|
|
||||||
* <pre>Buffer buffer = PredicatedBuffer.decorate(new UnboundedFifoBuffer(), NotNullPredicate.INSTANCE);</pre>
|
|
||||||
* <p>
|
|
||||||
* This class is Serializable from Commons Collections 3.1.
|
|
||||||
*
|
|
||||||
* @since 3.0
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public class PredicatedBuffer<E> extends PredicatedCollection<E> implements Buffer<E> {
|
|
||||||
|
|
||||||
/** Serialization version */
|
|
||||||
private static final long serialVersionUID = 2307609000539943581L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory method to create a predicated (validating) buffer.
|
|
||||||
* <p>
|
|
||||||
* If there are any elements already in the buffer being decorated, they
|
|
||||||
* are validated.
|
|
||||||
*
|
|
||||||
* @param <E> the type of the elements in the buffer
|
|
||||||
* @param buffer the buffer to decorate, must not be null
|
|
||||||
* @param predicate the predicate to use for validation, must not be null
|
|
||||||
* @return a new predicated Buffer
|
|
||||||
* @throws IllegalArgumentException if buffer or predicate is null
|
|
||||||
* @throws IllegalArgumentException if the buffer contains invalid elements
|
|
||||||
*/
|
|
||||||
public static <E> PredicatedBuffer<E> predicatedBuffer(final Buffer<E> buffer,
|
|
||||||
final Predicate<? super E> predicate) {
|
|
||||||
return new PredicatedBuffer<E>(buffer, predicate);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Constructor that wraps (not copies).
|
|
||||||
* <p>
|
|
||||||
* If there are any elements already in the collection being decorated, they
|
|
||||||
* are validated.
|
|
||||||
*
|
|
||||||
* @param buffer the buffer to decorate, must not be null
|
|
||||||
* @param predicate the predicate to use for validation, must not be null
|
|
||||||
* @throws IllegalArgumentException if buffer or predicate is null
|
|
||||||
* @throws IllegalArgumentException if the buffer contains invalid elements
|
|
||||||
*/
|
|
||||||
protected PredicatedBuffer(final Buffer<E> buffer, final Predicate<? super E> predicate) {
|
|
||||||
super(buffer, predicate);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the buffer being decorated.
|
|
||||||
*
|
|
||||||
* @return the decorated buffer
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected Buffer<E> decorated() {
|
|
||||||
return (Buffer<E>) super.decorated();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
|
|
||||||
public E get() {
|
|
||||||
return decorated().get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public E remove() {
|
|
||||||
return decorated().remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,544 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections.buffer;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.AbstractCollection;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
|
|
||||||
import org.apache.commons.collections.Buffer;
|
|
||||||
import org.apache.commons.collections.BufferUnderflowException;
|
|
||||||
import org.apache.commons.collections.comparators.ComparableComparator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Binary heap implementation of {@link Buffer} that provides for
|
|
||||||
* removal based on <code>Comparator</code> ordering.
|
|
||||||
* <p>
|
|
||||||
* The removal order of a binary heap is based on either the natural sort
|
|
||||||
* order of its elements or a specified {@link Comparator}. The
|
|
||||||
* {@link #remove()} method always returns the first element as determined
|
|
||||||
* by the sort order. (The <code>ascendingOrder</code> flag in the constructors
|
|
||||||
* can be used to reverse the sort order, in which case {@link #remove()}
|
|
||||||
* will always remove the last element.) The removal order is
|
|
||||||
* <i>not</i> the same as the order of iteration; elements are
|
|
||||||
* returned by the iterator in no particular order.
|
|
||||||
* <p>
|
|
||||||
* The {@link #add(Object)} and {@link #remove()} operations perform
|
|
||||||
* in logarithmic time. The {@link #get()} operation performs in constant
|
|
||||||
* time. All other operations perform in linear time or worse.
|
|
||||||
* <p>
|
|
||||||
* Note that this implementation is not synchronized. Use
|
|
||||||
* {@link org.apache.commons.collections.BufferUtils#synchronizedBuffer(Buffer)} or
|
|
||||||
* {@link org.apache.commons.collections.buffer.SynchronizedBuffer#synchronizedBuffer(Buffer)}
|
|
||||||
* to provide synchronized access to a <code>PriorityBuffer</code>:
|
|
||||||
* <pre>
|
|
||||||
* Buffer heap = SynchronizedBuffer.decorate(new PriorityBuffer());
|
|
||||||
* </pre>
|
|
||||||
* <p>
|
|
||||||
* This class is Serializable from Commons Collections 3.2.
|
|
||||||
*
|
|
||||||
* @since 3.0 (previously BinaryHeap v1.0)
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public class PriorityBuffer<E> extends AbstractCollection<E> implements Buffer<E>, Serializable {
|
|
||||||
|
|
||||||
/** Serialization lock. */
|
|
||||||
private static final long serialVersionUID = 6891186490470027896L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The default capacity for the buffer.
|
|
||||||
*/
|
|
||||||
private static final int DEFAULT_CAPACITY = 13;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The elements in this buffer.
|
|
||||||
*/
|
|
||||||
protected E[] elements;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The number of elements currently in this buffer.
|
|
||||||
*/
|
|
||||||
protected int size;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If true, the first element as determined by the sort order will
|
|
||||||
* be returned. If false, the last element as determined by the
|
|
||||||
* sort order will be returned.
|
|
||||||
*/
|
|
||||||
protected boolean ascendingOrder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The comparator used to order the elements
|
|
||||||
*/
|
|
||||||
protected Comparator<? super E> comparator;
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Constructs a new empty buffer that sorts in ascending order by the
|
|
||||||
* natural order of the objects added.
|
|
||||||
*/
|
|
||||||
public PriorityBuffer() {
|
|
||||||
this(DEFAULT_CAPACITY, true, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new empty buffer that sorts in ascending order using the
|
|
||||||
* specified comparator.
|
|
||||||
*
|
|
||||||
* @param comparator the comparator used to order the elements,
|
|
||||||
* null means use natural order
|
|
||||||
*/
|
|
||||||
public PriorityBuffer(final Comparator<? super E> comparator) {
|
|
||||||
this(DEFAULT_CAPACITY, true, comparator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new empty buffer specifying the sort order and using the
|
|
||||||
* natural order of the objects added.
|
|
||||||
*
|
|
||||||
* @param ascendingOrder if <code>true</code> the heap is created as a
|
|
||||||
* minimum heap; otherwise, the heap is created as a maximum heap
|
|
||||||
*/
|
|
||||||
public PriorityBuffer(final boolean ascendingOrder) {
|
|
||||||
this(DEFAULT_CAPACITY, ascendingOrder, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new empty buffer specifying the sort order and comparator.
|
|
||||||
*
|
|
||||||
* @param ascendingOrder true to use the order imposed by the given
|
|
||||||
* comparator; false to reverse that order
|
|
||||||
* @param comparator the comparator used to order the elements,
|
|
||||||
* null means use natural order
|
|
||||||
*/
|
|
||||||
public PriorityBuffer(final boolean ascendingOrder, final Comparator<? super E> comparator) {
|
|
||||||
this(DEFAULT_CAPACITY, ascendingOrder, comparator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new empty buffer that sorts in ascending order by the
|
|
||||||
* natural order of the objects added, specifying an initial capacity.
|
|
||||||
*
|
|
||||||
* @param capacity the initial capacity for the buffer, greater than zero
|
|
||||||
* @throws IllegalArgumentException if <code>capacity</code> is <= <code>0</code>
|
|
||||||
*/
|
|
||||||
public PriorityBuffer(final int capacity) {
|
|
||||||
this(capacity, true, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new empty buffer that sorts in ascending order using the
|
|
||||||
* specified comparator and initial capacity.
|
|
||||||
*
|
|
||||||
* @param capacity the initial capacity for the buffer, greater than zero
|
|
||||||
* @param comparator the comparator used to order the elements,
|
|
||||||
* null means use natural order
|
|
||||||
* @throws IllegalArgumentException if <code>capacity</code> is <= <code>0</code>
|
|
||||||
*/
|
|
||||||
public PriorityBuffer(final int capacity, final Comparator<? super E> comparator) {
|
|
||||||
this(capacity, true, comparator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new empty buffer that specifying initial capacity and
|
|
||||||
* sort order, using the natural order of the objects added.
|
|
||||||
*
|
|
||||||
* @param capacity the initial capacity for the buffer, greater than zero
|
|
||||||
* @param ascendingOrder if <code>true</code> the heap is created as a
|
|
||||||
* minimum heap; otherwise, the heap is created as a maximum heap.
|
|
||||||
* @throws IllegalArgumentException if <code>capacity</code> is <code><= 0</code>
|
|
||||||
*/
|
|
||||||
public PriorityBuffer(final int capacity, final boolean ascendingOrder) {
|
|
||||||
this(capacity, ascendingOrder, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a new empty buffer that specifying initial capacity,
|
|
||||||
* sort order and comparator.
|
|
||||||
*
|
|
||||||
* @param capacity the initial capacity for the buffer, greater than zero
|
|
||||||
* @param ascendingOrder true to use the order imposed by the given
|
|
||||||
* comparator; false to reverse that order
|
|
||||||
* @param comparator the comparator used to order the elements,
|
|
||||||
* null means use natural order
|
|
||||||
* @throws IllegalArgumentException if <code>capacity</code> is <code><= 0</code>
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public PriorityBuffer(final int capacity, final boolean ascendingOrder, final Comparator<? super E> comparator) {
|
|
||||||
super();
|
|
||||||
if (capacity <= 0) {
|
|
||||||
throw new IllegalArgumentException("invalid capacity");
|
|
||||||
}
|
|
||||||
this.ascendingOrder = ascendingOrder;
|
|
||||||
|
|
||||||
//+1 as 0 is noop
|
|
||||||
this.elements = (E[]) new Object[capacity + 1];
|
|
||||||
this.comparator = (Comparator<? super E>) (comparator == null ? ComparableComparator.INSTANCE : comparator);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Checks whether the heap is ascending or descending order.
|
|
||||||
*
|
|
||||||
* @return true if ascending order (a min heap)
|
|
||||||
*/
|
|
||||||
public boolean isAscendingOrder() {
|
|
||||||
return ascendingOrder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the comparator being used for this buffer, null is natural order.
|
|
||||||
*
|
|
||||||
* @return the comparator in use, null is natural order
|
|
||||||
*/
|
|
||||||
public Comparator<? super E> comparator() {
|
|
||||||
return comparator;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Returns the number of elements in this buffer.
|
|
||||||
*
|
|
||||||
* @return the number of elements in this buffer
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int size() {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears all elements from the buffer.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void clear() {
|
|
||||||
elements = (E[]) new Object[elements.length]; // for gc
|
|
||||||
size = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an element to the buffer.
|
|
||||||
* <p>
|
|
||||||
* The element added will be sorted according to the comparator in use.
|
|
||||||
*
|
|
||||||
* @param element the element to be added
|
|
||||||
* @return true always
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean add(final E element) {
|
|
||||||
if (isAtCapacity()) {
|
|
||||||
grow();
|
|
||||||
}
|
|
||||||
// percolate element to its place in tree
|
|
||||||
if (ascendingOrder) {
|
|
||||||
percolateUpMinHeap(element);
|
|
||||||
} else {
|
|
||||||
percolateUpMaxHeap(element);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the next element to be removed without actually removing it (peek).
|
|
||||||
*
|
|
||||||
* @return the next element
|
|
||||||
* @throws BufferUnderflowException if the buffer is empty
|
|
||||||
*/
|
|
||||||
public E get() {
|
|
||||||
if (isEmpty()) {
|
|
||||||
throw new BufferUnderflowException();
|
|
||||||
}
|
|
||||||
return elements[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets and removes the next element (pop).
|
|
||||||
*
|
|
||||||
* @return the next element
|
|
||||||
* @throws BufferUnderflowException if the buffer is empty
|
|
||||||
*/
|
|
||||||
public E remove() {
|
|
||||||
final E result = get();
|
|
||||||
elements[1] = elements[size--];
|
|
||||||
|
|
||||||
// set the unused element to 'null' so that the garbage collector
|
|
||||||
// can free the object if not used anywhere else.(remove reference)
|
|
||||||
elements[size + 1] = null;
|
|
||||||
|
|
||||||
if (size != 0) {
|
|
||||||
// percolate top element to it's place in tree
|
|
||||||
if (ascendingOrder) {
|
|
||||||
percolateDownMinHeap(1);
|
|
||||||
} else {
|
|
||||||
percolateDownMaxHeap(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Tests if the buffer is at capacity.
|
|
||||||
*
|
|
||||||
* @return <code>true</code> if buffer is full; <code>false</code> otherwise.
|
|
||||||
*/
|
|
||||||
protected boolean isAtCapacity() {
|
|
||||||
//+1 as element 0 is noop
|
|
||||||
return elements.length == size + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Percolates element down heap from the position given by the index.
|
|
||||||
* <p>
|
|
||||||
* Assumes it is a minimum heap.
|
|
||||||
*
|
|
||||||
* @param index the index for the element
|
|
||||||
*/
|
|
||||||
protected void percolateDownMinHeap(final int index) {
|
|
||||||
final E element = elements[index];
|
|
||||||
int hole = index;
|
|
||||||
|
|
||||||
while (hole * 2 <= size) {
|
|
||||||
int child = hole * 2;
|
|
||||||
|
|
||||||
// if we have a right child and that child can not be percolated
|
|
||||||
// up then move onto other child
|
|
||||||
if (child != size && compare(elements[child + 1], elements[child]) < 0) {
|
|
||||||
child++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we found resting place of bubble then terminate search
|
|
||||||
if (compare(elements[child], element) >= 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
elements[hole] = elements[child];
|
|
||||||
hole = child;
|
|
||||||
}
|
|
||||||
|
|
||||||
elements[hole] = element;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Percolates element down heap from the position given by the index.
|
|
||||||
* <p>
|
|
||||||
* Assumes it is a maximum heap.
|
|
||||||
*
|
|
||||||
* @param index the index of the element
|
|
||||||
*/
|
|
||||||
protected void percolateDownMaxHeap(final int index) {
|
|
||||||
final E element = elements[index];
|
|
||||||
int hole = index;
|
|
||||||
|
|
||||||
while (hole * 2 <= size) {
|
|
||||||
int child = hole * 2;
|
|
||||||
|
|
||||||
// if we have a right child and that child can not be percolated
|
|
||||||
// up then move onto other child
|
|
||||||
if (child != size && compare(elements[child + 1], elements[child]) > 0) {
|
|
||||||
child++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we found resting place of bubble then terminate search
|
|
||||||
if (compare(elements[child], element) <= 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
elements[hole] = elements[child];
|
|
||||||
hole = child;
|
|
||||||
}
|
|
||||||
|
|
||||||
elements[hole] = element;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Percolates element up heap from the position given by the index.
|
|
||||||
* <p>
|
|
||||||
* Assumes it is a minimum heap.
|
|
||||||
*
|
|
||||||
* @param index the index of the element to be percolated up
|
|
||||||
*/
|
|
||||||
protected void percolateUpMinHeap(final int index) {
|
|
||||||
int hole = index;
|
|
||||||
final E element = elements[hole];
|
|
||||||
while (hole > 1 && compare(element, elements[hole / 2]) < 0) {
|
|
||||||
// save element that is being pushed down
|
|
||||||
// as the element "bubble" is percolated up
|
|
||||||
final int next = hole / 2;
|
|
||||||
elements[hole] = elements[next];
|
|
||||||
hole = next;
|
|
||||||
}
|
|
||||||
elements[hole] = element;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Percolates a new element up heap from the bottom.
|
|
||||||
* <p>
|
|
||||||
* Assumes it is a minimum heap.
|
|
||||||
*
|
|
||||||
* @param element the element
|
|
||||||
*/
|
|
||||||
protected void percolateUpMinHeap(final E element) {
|
|
||||||
elements[++size] = element;
|
|
||||||
percolateUpMinHeap(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Percolates element up heap from from the position given by the index.
|
|
||||||
* <p>
|
|
||||||
* Assume it is a maximum heap.
|
|
||||||
*
|
|
||||||
* @param index the index of the element to be percolated up
|
|
||||||
*/
|
|
||||||
protected void percolateUpMaxHeap(final int index) {
|
|
||||||
int hole = index;
|
|
||||||
final E element = elements[hole];
|
|
||||||
|
|
||||||
while (hole > 1 && compare(element, elements[hole / 2]) > 0) {
|
|
||||||
// save element that is being pushed down
|
|
||||||
// as the element "bubble" is percolated up
|
|
||||||
final int next = hole / 2;
|
|
||||||
elements[hole] = elements[next];
|
|
||||||
hole = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
elements[hole] = element;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Percolates a new element up heap from the bottom.
|
|
||||||
* <p>
|
|
||||||
* Assume it is a maximum heap.
|
|
||||||
*
|
|
||||||
* @param element the element
|
|
||||||
*/
|
|
||||||
protected void percolateUpMaxHeap(final E element) {
|
|
||||||
elements[++size] = element;
|
|
||||||
percolateUpMaxHeap(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compares two objects using the comparator if specified, or the
|
|
||||||
* natural order otherwise.
|
|
||||||
*
|
|
||||||
* @param a the first object
|
|
||||||
* @param b the second object
|
|
||||||
* @return -ve if a less than b, 0 if they are equal, +ve if a greater than b
|
|
||||||
*/
|
|
||||||
protected int compare(final E a, final E b) {
|
|
||||||
return comparator.compare(a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Increases the size of the heap to support additional elements
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected void grow() {
|
|
||||||
final E[] array = (E[]) new Object[elements.length * 2];
|
|
||||||
System.arraycopy(elements, 0, array, 0, elements.length);
|
|
||||||
elements = array;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Returns an iterator over this heap's elements.
|
|
||||||
*
|
|
||||||
* @return an iterator over this heap's elements
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Iterator<E> iterator() {
|
|
||||||
return new Iterator<E>() {
|
|
||||||
|
|
||||||
private int index = 1;
|
|
||||||
private int lastReturnedIndex = -1;
|
|
||||||
|
|
||||||
public boolean hasNext() {
|
|
||||||
return index <= size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public E next() {
|
|
||||||
if (!hasNext()) {
|
|
||||||
throw new NoSuchElementException();
|
|
||||||
}
|
|
||||||
lastReturnedIndex = index;
|
|
||||||
index++;
|
|
||||||
return elements[lastReturnedIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove() {
|
|
||||||
if (lastReturnedIndex == -1) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
elements[ lastReturnedIndex ] = elements[ size ];
|
|
||||||
elements[ size ] = null;
|
|
||||||
size--;
|
|
||||||
if( size != 0 && lastReturnedIndex <= size) {
|
|
||||||
int compareToParent = 0;
|
|
||||||
if (lastReturnedIndex > 1) {
|
|
||||||
compareToParent = compare(elements[lastReturnedIndex],
|
|
||||||
elements[lastReturnedIndex / 2]);
|
|
||||||
}
|
|
||||||
if (ascendingOrder) {
|
|
||||||
if (lastReturnedIndex > 1 && compareToParent < 0) {
|
|
||||||
percolateUpMinHeap(lastReturnedIndex);
|
|
||||||
} else {
|
|
||||||
percolateDownMinHeap(lastReturnedIndex);
|
|
||||||
}
|
|
||||||
} else { // max heap
|
|
||||||
if (lastReturnedIndex > 1 && compareToParent > 0) {
|
|
||||||
percolateUpMaxHeap(lastReturnedIndex);
|
|
||||||
} else {
|
|
||||||
percolateDownMaxHeap(lastReturnedIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
index--;
|
|
||||||
lastReturnedIndex = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a string representation of this heap. The returned string
|
|
||||||
* is similar to those produced by standard JDK collections.
|
|
||||||
*
|
|
||||||
* @return a string representation of this heap
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
final StringBuilder sb = new StringBuilder();
|
|
||||||
|
|
||||||
sb.append("[ ");
|
|
||||||
|
|
||||||
for (int i = 1; i < size + 1; i++) {
|
|
||||||
if (i != 1) {
|
|
||||||
sb.append(", ");
|
|
||||||
}
|
|
||||||
sb.append(elements[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.append(" ]");
|
|
||||||
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,99 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections.buffer;
|
|
||||||
|
|
||||||
import org.apache.commons.collections.Buffer;
|
|
||||||
import org.apache.commons.collections.collection.SynchronizedCollection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decorates another {@link Buffer} to synchronize its behaviour
|
|
||||||
* for a multi-threaded environment.
|
|
||||||
* <p>
|
|
||||||
* Methods are synchronized, then forwarded to the decorated buffer.
|
|
||||||
* <p>
|
|
||||||
* This class is Serializable from Commons Collections 3.1.
|
|
||||||
*
|
|
||||||
* @param <E> the type of the elements in the buffer
|
|
||||||
* @since 3.0
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public class SynchronizedBuffer<E>
|
|
||||||
extends SynchronizedCollection<E>
|
|
||||||
implements Buffer<E> {
|
|
||||||
|
|
||||||
/** Serialization version */
|
|
||||||
private static final long serialVersionUID = -6859936183953626253L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory method to create a synchronized buffer.
|
|
||||||
*
|
|
||||||
* @param <E> the type of the elements in the buffer
|
|
||||||
* @param buffer the buffer to decorate, must not be null
|
|
||||||
* @return a new synchronized Buffer
|
|
||||||
* @throws IllegalArgumentException if buffer is null
|
|
||||||
*/
|
|
||||||
public static <E> SynchronizedBuffer<E> synchronizedBuffer(final Buffer<E> buffer) {
|
|
||||||
return new SynchronizedBuffer<E>(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Constructor that wraps (not copies).
|
|
||||||
*
|
|
||||||
* @param buffer the buffer to decorate, must not be null
|
|
||||||
* @throws IllegalArgumentException if the buffer is null
|
|
||||||
*/
|
|
||||||
protected SynchronizedBuffer(final Buffer<E> buffer) {
|
|
||||||
super(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor that wraps (not copies).
|
|
||||||
*
|
|
||||||
* @param buffer the buffer to decorate, must not be null
|
|
||||||
* @param lock the lock object to use, must not be null
|
|
||||||
* @throws IllegalArgumentException if the buffer is null
|
|
||||||
*/
|
|
||||||
protected SynchronizedBuffer(final Buffer<E> buffer, final Object lock) {
|
|
||||||
super(buffer, lock);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the buffer being decorated.
|
|
||||||
*
|
|
||||||
* @return the decorated buffer
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected Buffer<E> decorated() {
|
|
||||||
return (Buffer<E>) super.decorated();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
|
|
||||||
public E get() {
|
|
||||||
synchronized (lock) {
|
|
||||||
return decorated().get();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public E remove() {
|
|
||||||
synchronized (lock) {
|
|
||||||
return decorated().remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,123 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections.buffer;
|
|
||||||
|
|
||||||
import org.apache.commons.collections.Buffer;
|
|
||||||
import org.apache.commons.collections.Transformer;
|
|
||||||
import org.apache.commons.collections.collection.TransformedCollection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decorates another {@link Buffer} to transform objects that are added.
|
|
||||||
* <p>
|
|
||||||
* The add methods are affected by this class.
|
|
||||||
* Thus objects must be removed or searched for using their transformed form.
|
|
||||||
* For example, if the transformation converts Strings to Integers, you must
|
|
||||||
* use the Integer form to remove objects.
|
|
||||||
* <p>
|
|
||||||
* This class is Serializable from Commons Collections 3.1.
|
|
||||||
*
|
|
||||||
* @since 3.0
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public class TransformedBuffer<E> extends TransformedCollection<E> implements Buffer<E> {
|
|
||||||
|
|
||||||
/** Serialization version */
|
|
||||||
private static final long serialVersionUID = -7901091318986132033L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory method to create a transforming buffer.
|
|
||||||
* <p>
|
|
||||||
* If there are any elements already in the buffer being decorated, they
|
|
||||||
* are NOT transformed.
|
|
||||||
* Contrast this with {@link #transformedBuffer(Buffer, Transformer)}.
|
|
||||||
*
|
|
||||||
* @param <E> the type of the elements in the buffer
|
|
||||||
* @param buffer the buffer to decorate, must not be null
|
|
||||||
* @param transformer the transformer to use for conversion, must not be null
|
|
||||||
* @return a new transformed Buffer
|
|
||||||
* @throws IllegalArgumentException if buffer or transformer is null
|
|
||||||
*/
|
|
||||||
public static <E> TransformedBuffer<E> transformingBuffer(final Buffer<E> buffer,
|
|
||||||
final Transformer<? super E, ? extends E> transformer) {
|
|
||||||
return new TransformedBuffer<E>(buffer, transformer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory method to create a transforming buffer that will transform
|
|
||||||
* existing contents of the specified buffer.
|
|
||||||
* <p>
|
|
||||||
* If there are any elements already in the buffer being decorated, they
|
|
||||||
* will be transformed by this method.
|
|
||||||
* Contrast this with {@link #transformingBuffer(Buffer, Transformer)}.
|
|
||||||
*
|
|
||||||
* @param <E> the type of the elements in the buffer
|
|
||||||
* @param buffer the buffer to decorate, must not be null
|
|
||||||
* @param transformer the transformer to use for conversion, must not be null
|
|
||||||
* @return a new transformed Buffer
|
|
||||||
* @throws IllegalArgumentException if buffer or transformer is null
|
|
||||||
* @since 4.0
|
|
||||||
*/
|
|
||||||
public static <E> TransformedBuffer<E> transformedBuffer(final Buffer<E> buffer,
|
|
||||||
final Transformer<? super E, ? extends E> transformer) {
|
|
||||||
// throws IAE if buffer or transformer is null
|
|
||||||
final TransformedBuffer<E> decorated = new TransformedBuffer<E>(buffer, transformer);
|
|
||||||
if (buffer.size() > 0) {
|
|
||||||
@SuppressWarnings("unchecked") // buffer is type <E>
|
|
||||||
final E[] values = (E[]) buffer.toArray();
|
|
||||||
buffer.clear();
|
|
||||||
for (final E value : values) {
|
|
||||||
decorated.decorated().add(transformer.transform(value));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return decorated;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Constructor that wraps (not copies).
|
|
||||||
* <p>
|
|
||||||
* If there are any elements already in the buffer being decorated, they
|
|
||||||
* are NOT transformed.
|
|
||||||
*
|
|
||||||
* @param buffer the buffer to decorate, must not be null
|
|
||||||
* @param transformer the transformer to use for conversion, must not be null
|
|
||||||
* @throws IllegalArgumentException if buffer or transformer is null
|
|
||||||
*/
|
|
||||||
protected TransformedBuffer(final Buffer<E> buffer, final Transformer<? super E, ? extends E> transformer) {
|
|
||||||
super(buffer, transformer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the decorated buffer.
|
|
||||||
*
|
|
||||||
* @return the decorated buffer
|
|
||||||
*/
|
|
||||||
protected Buffer<E> getBuffer() {
|
|
||||||
return (Buffer<E>) collection;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
|
|
||||||
public E get() {
|
|
||||||
return getBuffer().get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public E remove() {
|
|
||||||
return getBuffer().remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,318 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections.buffer;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.AbstractCollection;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
|
|
||||||
import org.apache.commons.collections.Buffer;
|
|
||||||
import org.apache.commons.collections.BufferUnderflowException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UnboundedFifoBuffer is a very efficient implementation of
|
|
||||||
* {@link Buffer} that can grow to any size.
|
|
||||||
* According to performance testing, it exhibits a constant access time, but it
|
|
||||||
* also outperforms ArrayList when used for the same purpose.
|
|
||||||
* <p>
|
|
||||||
* The removal order of an {@link UnboundedFifoBuffer} is based on the insertion
|
|
||||||
* order; elements are removed in the same order in which they were added.
|
|
||||||
* The iteration order is the same as the removal order.
|
|
||||||
* <p>
|
|
||||||
* The {@link #remove()} and {@link #get()} operations perform in constant time.
|
|
||||||
* The {@link #add(Object)} operation performs in amortized constant time. All
|
|
||||||
* other operations perform in linear time or worse.
|
|
||||||
* <p>
|
|
||||||
* Note that this implementation is not synchronized. The following can be
|
|
||||||
* used to provide synchronized access to your <code>UnboundedFifoBuffer</code>:
|
|
||||||
* <pre>
|
|
||||||
* Buffer fifo = BufferUtils.synchronizedBuffer(new UnboundedFifoBuffer());
|
|
||||||
* </pre>
|
|
||||||
* <p>
|
|
||||||
* This buffer prevents null objects from being added.
|
|
||||||
* <p>
|
|
||||||
* This class is Serializable from Commons Collections 3.1.
|
|
||||||
*
|
|
||||||
* @since 3.0 (previously in main package v2.1)
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public class UnboundedFifoBuffer<E> extends AbstractCollection<E> implements Buffer<E>, Serializable {
|
|
||||||
// invariant: buffer.length > size()
|
|
||||||
// ie.buffer always has at least one empty entry
|
|
||||||
|
|
||||||
/** Serialization version */
|
|
||||||
private static final long serialVersionUID = -3482960336579541419L;
|
|
||||||
|
|
||||||
/** The array of objects in the buffer. */
|
|
||||||
protected transient E[] buffer;
|
|
||||||
|
|
||||||
/** The current head index. */
|
|
||||||
protected transient int head;
|
|
||||||
|
|
||||||
/** The current tail index. */
|
|
||||||
protected transient int tail;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs an UnboundedFifoBuffer with the default number of elements.
|
|
||||||
* It is exactly the same as performing the following:
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* new UnboundedFifoBuffer(32);
|
|
||||||
* </pre>
|
|
||||||
*/
|
|
||||||
public UnboundedFifoBuffer() {
|
|
||||||
this(32);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs an UnboundedFifoBuffer with the specified number of elements.
|
|
||||||
* The integer must be a positive integer.
|
|
||||||
*
|
|
||||||
* @param initialSize the initial size of the buffer
|
|
||||||
* @throws IllegalArgumentException if the size is less than 1
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public UnboundedFifoBuffer(final int initialSize) {
|
|
||||||
if (initialSize <= 0) {
|
|
||||||
throw new IllegalArgumentException("The size must be greater than 0");
|
|
||||||
}
|
|
||||||
buffer = (E[]) new Object[initialSize + 1];
|
|
||||||
head = 0;
|
|
||||||
tail = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Write the buffer out using a custom routine.
|
|
||||||
*
|
|
||||||
* @param out the output stream
|
|
||||||
* @throws IOException if an I/O error occurs while writing to the output stream
|
|
||||||
*/
|
|
||||||
private void writeObject(final ObjectOutputStream out) throws IOException {
|
|
||||||
out.defaultWriteObject();
|
|
||||||
out.writeInt(size());
|
|
||||||
out.writeInt(buffer.length);
|
|
||||||
for (final E e : this) {
|
|
||||||
out.writeObject(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read the buffer in using a custom routine.
|
|
||||||
*
|
|
||||||
* @param in the input stream
|
|
||||||
* @throws IOException if an I/O error occurs while reading from the input stream
|
|
||||||
* @throws ClassNotFoundException if the class of a serialized object can not be found
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
|
|
||||||
in.defaultReadObject();
|
|
||||||
final int size = in.readInt();
|
|
||||||
final int length = in.readInt();
|
|
||||||
buffer = (E[]) new Object[length];
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
buffer[i] = (E) in.readObject();
|
|
||||||
}
|
|
||||||
head = 0;
|
|
||||||
tail = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Returns the number of elements stored in the buffer.
|
|
||||||
*
|
|
||||||
* @return this buffer's size
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public int size() {
|
|
||||||
int size = 0;
|
|
||||||
|
|
||||||
if (tail < head) {
|
|
||||||
size = buffer.length - head + tail;
|
|
||||||
} else {
|
|
||||||
size = tail - head;
|
|
||||||
}
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if this buffer is empty; false otherwise.
|
|
||||||
*
|
|
||||||
* @return true if this buffer is empty
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean isEmpty() {
|
|
||||||
return size() == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the given element to this buffer.
|
|
||||||
*
|
|
||||||
* @param obj the element to add
|
|
||||||
* @return true, always
|
|
||||||
* @throws NullPointerException if the given element is null
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public boolean add(final E obj) {
|
|
||||||
if (obj == null) {
|
|
||||||
throw new NullPointerException("Attempted to add null object to buffer");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (size() + 1 >= buffer.length) {
|
|
||||||
// copy contents to a new buffer array
|
|
||||||
final E[] tmp = (E[]) new Object[(buffer.length - 1) * 2 + 1];
|
|
||||||
int j = 0;
|
|
||||||
// move head to element zero in the new array
|
|
||||||
for (int i = head; i != tail;) {
|
|
||||||
tmp[j] = buffer[i];
|
|
||||||
buffer[i] = null;
|
|
||||||
|
|
||||||
j++;
|
|
||||||
i = increment(i);
|
|
||||||
}
|
|
||||||
buffer = tmp;
|
|
||||||
head = 0;
|
|
||||||
tail = j;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer[tail] = obj;
|
|
||||||
tail = increment(tail);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the next object in the buffer.
|
|
||||||
*
|
|
||||||
* @return the next object in the buffer
|
|
||||||
* @throws BufferUnderflowException if this buffer is empty
|
|
||||||
*/
|
|
||||||
public E get() {
|
|
||||||
if (isEmpty()) {
|
|
||||||
throw new BufferUnderflowException("The buffer is already empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer[head];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the next object from the buffer
|
|
||||||
*
|
|
||||||
* @return the removed object
|
|
||||||
* @throws BufferUnderflowException if this buffer is empty
|
|
||||||
*/
|
|
||||||
public E remove() {
|
|
||||||
if (isEmpty()) {
|
|
||||||
throw new BufferUnderflowException("The buffer is already empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
final E element = buffer[head];
|
|
||||||
if (element != null) {
|
|
||||||
buffer[head] = null;
|
|
||||||
head = increment(head);
|
|
||||||
}
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Increments the internal index.
|
|
||||||
*
|
|
||||||
* @param index the index to increment
|
|
||||||
* @return the updated index
|
|
||||||
*/
|
|
||||||
private int increment(int index) {
|
|
||||||
index++;
|
|
||||||
if (index >= buffer.length) {
|
|
||||||
index = 0;
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decrements the internal index.
|
|
||||||
*
|
|
||||||
* @param index the index to decrement
|
|
||||||
* @return the updated index
|
|
||||||
*/
|
|
||||||
private int decrement(int index) {
|
|
||||||
index--;
|
|
||||||
if (index < 0) {
|
|
||||||
index = buffer.length - 1;
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an iterator over this buffer's elements.
|
|
||||||
*
|
|
||||||
* @return an iterator over this buffer's elements
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Iterator<E> iterator() {
|
|
||||||
return new Iterator<E>() {
|
|
||||||
|
|
||||||
private int index = head;
|
|
||||||
private int lastReturnedIndex = -1;
|
|
||||||
|
|
||||||
public boolean hasNext() {
|
|
||||||
return index != tail;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public E next() {
|
|
||||||
if (!hasNext()) {
|
|
||||||
throw new NoSuchElementException();
|
|
||||||
}
|
|
||||||
lastReturnedIndex = index;
|
|
||||||
index = increment(index);
|
|
||||||
return buffer[lastReturnedIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void remove() {
|
|
||||||
if (lastReturnedIndex == -1) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
|
|
||||||
// First element can be removed quickly
|
|
||||||
if (lastReturnedIndex == head) {
|
|
||||||
UnboundedFifoBuffer.this.remove();
|
|
||||||
lastReturnedIndex = -1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Other elements require us to shift the subsequent elements
|
|
||||||
int i = increment(lastReturnedIndex);
|
|
||||||
while (i != tail) {
|
|
||||||
buffer[decrement(i)] = buffer[i];
|
|
||||||
i = increment(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
lastReturnedIndex = -1;
|
|
||||||
tail = decrement(tail);
|
|
||||||
buffer[tail] = null;
|
|
||||||
index = decrement(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,142 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections.buffer;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
|
||||||
|
|
||||||
import org.apache.commons.collections.Buffer;
|
|
||||||
import org.apache.commons.collections.Unmodifiable;
|
|
||||||
import org.apache.commons.collections.iterators.UnmodifiableIterator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Decorates another {@link Buffer} to ensure it can't be altered.
|
|
||||||
* <p>
|
|
||||||
* This class is Serializable from Commons Collections 3.1.
|
|
||||||
* <p>
|
|
||||||
* Attempts to modify it will result in an UnsupportedOperationException.
|
|
||||||
*
|
|
||||||
* @since 3.0
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public final class UnmodifiableBuffer<E>
|
|
||||||
extends AbstractBufferDecorator<E>
|
|
||||||
implements Unmodifiable, Serializable {
|
|
||||||
|
|
||||||
/** Serialization version */
|
|
||||||
private static final long serialVersionUID = 1832948656215393357L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory method to create an unmodifiable buffer.
|
|
||||||
* <p>
|
|
||||||
* If the buffer passed in is already unmodifiable, it is returned.
|
|
||||||
*
|
|
||||||
* @param <E> the type of the elements in the buffer
|
|
||||||
* @param buffer the buffer to decorate, must not be null
|
|
||||||
* @return an unmodifiable Buffer
|
|
||||||
* @throws IllegalArgumentException if buffer is null
|
|
||||||
*/
|
|
||||||
public static <E> Buffer<E> unmodifiableBuffer(final Buffer<E> buffer) {
|
|
||||||
if (buffer instanceof Unmodifiable) {
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
return new UnmodifiableBuffer<E>(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Constructor that wraps (not copies).
|
|
||||||
*
|
|
||||||
* @param buffer the buffer to decorate, must not be null
|
|
||||||
* @throws IllegalArgumentException if buffer is null
|
|
||||||
*/
|
|
||||||
private UnmodifiableBuffer(final Buffer<E> buffer) {
|
|
||||||
super(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Write the collection out using a custom routine.
|
|
||||||
*
|
|
||||||
* @param out the output stream
|
|
||||||
* @throws IOException if an I/O error occurs while writing to the output stream
|
|
||||||
*/
|
|
||||||
private void writeObject(final ObjectOutputStream out) throws IOException {
|
|
||||||
out.defaultWriteObject();
|
|
||||||
out.writeObject(collection);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read the collection in using a custom routine.
|
|
||||||
*
|
|
||||||
* @param in the input stream
|
|
||||||
* @throws IOException if an I/O error occurs while reading from the input stream
|
|
||||||
* @throws ClassNotFoundException if the class of a serialized object can not be found
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
|
|
||||||
in.defaultReadObject();
|
|
||||||
collection = (Collection<E>) in.readObject();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
@Override
|
|
||||||
public Iterator<E> iterator() {
|
|
||||||
return UnmodifiableIterator.unmodifiableIterator(decorated().iterator());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean add(final Object object) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean addAll(final Collection<? extends E> coll) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean remove(final Object object) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean removeAll(final Collection<?> coll) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean retainAll(final Collection<?> coll) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
@Override
|
|
||||||
public E remove() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* This package contains implementations of the
|
|
||||||
* {@link org.apache.commons.collections.Buffer Buffer} interface.
|
|
||||||
* <p>
|
|
||||||
* The following implementations are provided in the package:
|
|
||||||
* <ul>
|
|
||||||
* <li>PriorityBuffer - provides for removal based on a comparator ordering
|
|
||||||
* <li>BoundedFifoBuffer - implements a buffer with a fixed size that throws exceptions when full
|
|
||||||
* <li>CircularFifoBuffer - implements a buffer with a fixed size that discards oldest when full
|
|
||||||
* <li>UnboundedFifoBuffer - implements a buffer that grows in size if necessary
|
|
||||||
* </ul>
|
|
||||||
* <p>
|
|
||||||
* The following decorators are provided in the package:
|
|
||||||
* <ul>
|
|
||||||
* <li>Synchronized - synchronizes method access for multi-threaded environments
|
|
||||||
* <li>Unmodifiable - ensures the collection cannot be altered
|
|
||||||
* <li>Predicated - ensures that only elements that are valid according to a predicate can be added
|
|
||||||
* <li>Transformed - transforms elements added to the buffer
|
|
||||||
* <li>Blocking - blocks on get and remove until an element is available
|
|
||||||
* </ul>
|
|
||||||
*
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
package org.apache.commons.collections.buffer;
|
|
|
@ -1,68 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections;
|
|
||||||
|
|
||||||
import junit.framework.Test;
|
|
||||||
|
|
||||||
import org.apache.commons.collections.buffer.PredicatedBuffer;
|
|
||||||
import org.apache.commons.collections.ArrayStack;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests for BufferUtils.
|
|
||||||
*
|
|
||||||
* @version $Revision$
|
|
||||||
*
|
|
||||||
* @author Unknown
|
|
||||||
*/
|
|
||||||
public class BufferUtilsTest extends BulkTest {
|
|
||||||
|
|
||||||
public BufferUtilsTest(final String name) {
|
|
||||||
super(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static Test suite() {
|
|
||||||
return BulkTest.makeSuite(BufferUtilsTest.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testNothing() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testpredicatedBuffer() {
|
|
||||||
// final Predicate<Object> predicate = new Predicate<Object>() {
|
|
||||||
// public boolean evaluate(final Object o) {
|
|
||||||
// return o instanceof String;
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
// Buffer<Object> buffer = BufferUtils.predicatedBuffer(new ArrayStack<Object>(), predicate);
|
|
||||||
// assertTrue("returned object should be a PredicatedBuffer",
|
|
||||||
// buffer instanceof PredicatedBuffer);
|
|
||||||
// try {
|
|
||||||
// buffer = BufferUtils.predicatedBuffer(new ArrayStack<Object>(), null);
|
|
||||||
// fail("Expecting IllegalArgumentException for null predicate.");
|
|
||||||
// } catch (final IllegalArgumentException ex) {
|
|
||||||
// // expected
|
|
||||||
// }
|
|
||||||
// try {
|
|
||||||
// buffer = BufferUtils.predicatedBuffer(null, predicate);
|
|
||||||
// fail("Expecting IllegalArgumentException for null buffer.");
|
|
||||||
// } catch (final IllegalArgumentException ex) {
|
|
||||||
// // expected
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,576 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections.buffer;
|
|
||||||
|
|
||||||
import org.apache.commons.collections.AbstractObjectTest;
|
|
||||||
import org.apache.commons.collections.Buffer;
|
|
||||||
import org.apache.commons.collections.BufferUnderflowException;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extension of {@link AbstractObjectTest} for exercising the
|
|
||||||
* {@link BlockingBuffer} implementation.
|
|
||||||
*
|
|
||||||
* @since 3.0
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public class BlockingBufferTest<E> extends AbstractObjectTest {
|
|
||||||
|
|
||||||
public BlockingBufferTest(final String testName) {
|
|
||||||
super(testName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Buffer<E> makeObject() {
|
|
||||||
return BlockingBuffer.blockingBuffer(new MyBuffer<E>());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEqualsCheckable() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected E makeElement() {
|
|
||||||
return (E) new Object();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link BlockingBuffer#get()} in combination with
|
|
||||||
* {@link BlockingBuffer#add(Object)}.
|
|
||||||
*/
|
|
||||||
public void testGetWithAdd() {
|
|
||||||
final Buffer<E> blockingBuffer = makeObject();
|
|
||||||
final E obj = makeElement();
|
|
||||||
new DelayedAdd<E>(blockingBuffer, obj).start();
|
|
||||||
|
|
||||||
// verify does not throw BufferUnderflowException; should block until other thread has added to the buffer .
|
|
||||||
assertSame(obj, blockingBuffer.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testGetWithAddTimeout() {
|
|
||||||
final Buffer<E> blockingBuffer = BlockingBuffer.blockingBuffer(new MyBuffer<E>(), 500);
|
|
||||||
final E obj = makeElement();
|
|
||||||
new DelayedAdd<E>(blockingBuffer, obj, 100).start();
|
|
||||||
|
|
||||||
// verify does not throw BufferUnderflowException; should block until other thread has added to the buffer .
|
|
||||||
assertSame(obj, blockingBuffer.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link BlockingBuffer#get()} in combination with
|
|
||||||
* {@link BlockingBuffer#addAll(java.util.Collection)}.
|
|
||||||
*/
|
|
||||||
public void testGetWithAddAll() {
|
|
||||||
final Buffer<E> blockingBuffer = makeObject();
|
|
||||||
final E obj = makeElement();
|
|
||||||
new DelayedAddAll<E>(blockingBuffer, obj).start();
|
|
||||||
|
|
||||||
// verify does not throw BufferUnderflowException; should block until other thread has added to the buffer .
|
|
||||||
assertSame(obj, blockingBuffer.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testGetWithAddAllTimeout() {
|
|
||||||
final Buffer<E> blockingBuffer = BlockingBuffer.blockingBuffer(new MyBuffer<E>(), 500);
|
|
||||||
final E obj = makeElement();
|
|
||||||
new DelayedAddAll<E>(blockingBuffer, obj, 100).start();
|
|
||||||
|
|
||||||
// verify does not throw BufferUnderflowException; should block until other thread has added to the buffer .
|
|
||||||
assertSame(obj, blockingBuffer.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link BlockingBuffer#remove()} in combination with
|
|
||||||
* {@link BlockingBuffer#add(Object)}.
|
|
||||||
*/
|
|
||||||
public void testRemoveWithAdd() {
|
|
||||||
final Buffer<E> blockingBuffer = makeObject();
|
|
||||||
final E obj = makeElement();
|
|
||||||
new DelayedAdd<E>(blockingBuffer, obj).start();
|
|
||||||
|
|
||||||
// verify does not throw BufferUnderflowException; should block until other thread has added to the buffer .
|
|
||||||
assertSame(obj, blockingBuffer.remove());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testRemoveWithAddTimeout() {
|
|
||||||
final Buffer<E> blockingBuffer = BlockingBuffer.blockingBuffer(new MyBuffer<E>(), 100);
|
|
||||||
final E obj = makeElement();
|
|
||||||
new DelayedAdd<E>(blockingBuffer, obj, 500).start();
|
|
||||||
try {
|
|
||||||
blockingBuffer.remove();
|
|
||||||
} catch (final BufferUnderflowException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link BlockingBuffer#remove()} in combination with
|
|
||||||
* {@link BlockingBuffer#addAll(java.util.Collection)}.
|
|
||||||
*/
|
|
||||||
public void testRemoveWithAddAll() {
|
|
||||||
final Buffer<E> blockingBuffer = makeObject();
|
|
||||||
final E obj = makeElement();
|
|
||||||
new DelayedAddAll<E>(blockingBuffer, obj).start();
|
|
||||||
|
|
||||||
// verify does not throw BufferUnderflowException; should block until other thread has added to the buffer .
|
|
||||||
assertSame(obj, blockingBuffer.remove());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testRemoveWithAddAllTimeout() {
|
|
||||||
final Buffer<E> blockingBuffer = BlockingBuffer.blockingBuffer(new MyBuffer<E>(), 100);
|
|
||||||
final E obj = makeElement();
|
|
||||||
new DelayedAddAll<E>(blockingBuffer, obj, 500).start();
|
|
||||||
try {
|
|
||||||
blockingBuffer.remove();
|
|
||||||
} catch (final BufferUnderflowException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link BlockingBuffer#get()} in combination with
|
|
||||||
* {@link BlockingBuffer#add(Object)} using multiple read threads. <p/> Two
|
|
||||||
* read threads should block on an empty buffer until one object is added
|
|
||||||
* then both threads should complete.
|
|
||||||
*/
|
|
||||||
public void testBlockedGetWithAdd() {
|
|
||||||
final Buffer<E> blockingBuffer = makeObject();
|
|
||||||
final E obj = makeElement();
|
|
||||||
|
|
||||||
// run methods will get and compare -- must wait for add
|
|
||||||
final Thread thread1 = new ReadThread<E>(blockingBuffer, obj);
|
|
||||||
final Thread thread2 = new ReadThread<E>(blockingBuffer, obj);
|
|
||||||
thread1.start();
|
|
||||||
thread2.start();
|
|
||||||
|
|
||||||
// give hungry read threads ample time to hang
|
|
||||||
delay();
|
|
||||||
|
|
||||||
// notifyAll should allow both read threads to complete
|
|
||||||
blockingBuffer.add(obj);
|
|
||||||
|
|
||||||
// allow notified threads to complete
|
|
||||||
delay();
|
|
||||||
|
|
||||||
// There should not be any threads waiting.
|
|
||||||
if (thread1.isAlive() || thread2.isAlive()) {
|
|
||||||
fail("Live thread(s) when both should be dead.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link BlockingBuffer#get()} in combination with
|
|
||||||
* {@link BlockingBuffer#addAll(java.util.Collection)} using multiple read
|
|
||||||
* threads. <p/> Two read threads should block on an empty buffer until a
|
|
||||||
* singleton is added then both threads should complete.
|
|
||||||
*/
|
|
||||||
public void testBlockedGetWithAddAll() {
|
|
||||||
final Buffer<E> blockingBuffer = makeObject();
|
|
||||||
final E obj = makeElement();
|
|
||||||
|
|
||||||
// run methods will get and compare -- must wait for addAll
|
|
||||||
final Thread thread1 = new ReadThread<E>(blockingBuffer, obj);
|
|
||||||
final Thread thread2 = new ReadThread<E>(blockingBuffer, obj);
|
|
||||||
thread1.start();
|
|
||||||
thread2.start();
|
|
||||||
|
|
||||||
// give hungry read threads ample time to hang
|
|
||||||
delay();
|
|
||||||
|
|
||||||
// notifyAll should allow both read threads to complete
|
|
||||||
blockingBuffer.addAll(Collections.singleton(obj));
|
|
||||||
|
|
||||||
// allow notified threads to complete
|
|
||||||
delay();
|
|
||||||
|
|
||||||
// There should not be any threads waiting.
|
|
||||||
if (thread1.isAlive() || thread2.isAlive()) {
|
|
||||||
fail("Live thread(s) when both should be dead.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests interrupted {@link BlockingBuffer#get()}.
|
|
||||||
*/
|
|
||||||
public void testInterruptedGet() {
|
|
||||||
final Buffer<E> blockingBuffer = makeObject();
|
|
||||||
final E obj = makeElement();
|
|
||||||
|
|
||||||
// spawn a read thread to wait on the empty buffer
|
|
||||||
final ArrayList<String> exceptionList = new ArrayList<String>();
|
|
||||||
final Thread thread = new ReadThread<E>(blockingBuffer, obj, exceptionList);
|
|
||||||
thread.start();
|
|
||||||
|
|
||||||
// Interrupting the thread should cause it to throw BufferUnderflowException
|
|
||||||
thread.interrupt();
|
|
||||||
|
|
||||||
// Chill, so thread can throw and add message to exceptionList
|
|
||||||
delay();
|
|
||||||
assertTrue("Thread interrupt should have led to underflow", exceptionList
|
|
||||||
.contains("BufferUnderFlow"));
|
|
||||||
if (thread.isAlive()) {
|
|
||||||
fail("Read thread has hung.");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link BlockingBuffer#remove()} in combination with
|
|
||||||
* {@link BlockingBuffer#add(Object)} using multiple read threads. <p/> Two
|
|
||||||
* read threads should block on an empty buffer until one object is added
|
|
||||||
* then one thread should complete. The remaining thread should complete
|
|
||||||
* after the addition of a second object.
|
|
||||||
*/
|
|
||||||
public void testBlockedRemoveWithAdd() {
|
|
||||||
final Buffer<E> blockingBuffer = makeObject();
|
|
||||||
final E obj = makeElement();
|
|
||||||
|
|
||||||
// run methods will remove and compare -- must wait for add
|
|
||||||
final Thread thread1 = new ReadThread<E>(blockingBuffer, obj, null, "remove");
|
|
||||||
final Thread thread2 = new ReadThread<E>(blockingBuffer, obj, null, "remove");
|
|
||||||
thread1.start();
|
|
||||||
thread2.start();
|
|
||||||
|
|
||||||
// give hungry read threads ample time to hang
|
|
||||||
delay();
|
|
||||||
blockingBuffer.add(obj);
|
|
||||||
|
|
||||||
// allow notified threads to complete
|
|
||||||
delay();
|
|
||||||
|
|
||||||
// There should be one thread waiting.
|
|
||||||
assertTrue("There is one thread waiting", thread1.isAlive() ^ thread2.isAlive());
|
|
||||||
blockingBuffer.add(obj);
|
|
||||||
|
|
||||||
// allow notified thread to complete
|
|
||||||
delay();
|
|
||||||
|
|
||||||
// There should not be any threads waiting.
|
|
||||||
if (thread1.isAlive() || thread2.isAlive()) {
|
|
||||||
fail("Live thread(s) when both should be dead.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link BlockingBuffer#remove()} in combination with
|
|
||||||
* {@link BlockingBuffer#addAll(java.util.Collection)} using multiple read
|
|
||||||
* threads. <p/> Two read threads should block on an empty buffer until a
|
|
||||||
* singleton collection is added then one thread should complete. The
|
|
||||||
* remaining thread should complete after the addition of a second
|
|
||||||
* singleton.
|
|
||||||
*/
|
|
||||||
public void testBlockedRemoveWithAddAll1() {
|
|
||||||
final Buffer<E> blockingBuffer = makeObject();
|
|
||||||
final E obj = makeElement();
|
|
||||||
|
|
||||||
// run methods will remove and compare -- must wait for addAll
|
|
||||||
final Thread thread1 = new ReadThread<E>(blockingBuffer, obj, null, "remove");
|
|
||||||
final Thread thread2 = new ReadThread<E>(blockingBuffer, obj, null, "remove");
|
|
||||||
thread1.start();
|
|
||||||
thread2.start();
|
|
||||||
|
|
||||||
// give hungry read threads ample time to hang
|
|
||||||
delay();
|
|
||||||
blockingBuffer.addAll(Collections.singleton(obj));
|
|
||||||
|
|
||||||
// allow notified threads to complete
|
|
||||||
delay();
|
|
||||||
|
|
||||||
// There should be one thread waiting.
|
|
||||||
assertTrue("There is one thread waiting", thread1.isAlive() ^ thread2.isAlive());
|
|
||||||
blockingBuffer.addAll(Collections.singleton(obj));
|
|
||||||
|
|
||||||
// allow notified thread to complete
|
|
||||||
delay();
|
|
||||||
|
|
||||||
// There should not be any threads waiting.
|
|
||||||
if (thread1.isAlive() || thread2.isAlive()) {
|
|
||||||
fail("Live thread(s) when both should be dead.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests {@link BlockingBuffer#remove()} in combination with
|
|
||||||
* {@link BlockingBuffer#addAll(java.util.Collection)} using multiple read
|
|
||||||
* threads. <p/> Two read threads should block on an empty buffer until a
|
|
||||||
* collection with two distinct objects is added then both threads should
|
|
||||||
* complete. Each thread should have read a different object.
|
|
||||||
*/
|
|
||||||
public void testBlockedRemoveWithAddAll2() {
|
|
||||||
final Buffer<E> blockingBuffer = makeObject();
|
|
||||||
final E obj1 = makeElement();
|
|
||||||
final E obj2 = makeElement();
|
|
||||||
final Set<E> objs = Collections.synchronizedSet(new HashSet<E>());
|
|
||||||
objs.add(obj1);
|
|
||||||
objs.add(obj2);
|
|
||||||
|
|
||||||
// run methods will remove and compare -- must wait for addAll
|
|
||||||
final Thread thread1 = new ReadThread<E>(blockingBuffer, objs, "remove");
|
|
||||||
final Thread thread2 = new ReadThread<E>(blockingBuffer, objs, "remove");
|
|
||||||
thread1.start();
|
|
||||||
thread2.start();
|
|
||||||
|
|
||||||
// give hungry read threads ample time to hang
|
|
||||||
delay();
|
|
||||||
blockingBuffer.addAll(objs);
|
|
||||||
|
|
||||||
// allow notified threads to complete
|
|
||||||
delay();
|
|
||||||
assertEquals("Both objects were removed", 0, objs.size());
|
|
||||||
|
|
||||||
// There should not be any threads waiting.
|
|
||||||
if (thread1.isAlive() || thread2.isAlive()) {
|
|
||||||
fail("Live thread(s) when both should be dead.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests interrupted remove.
|
|
||||||
*/
|
|
||||||
public void testInterruptedRemove() {
|
|
||||||
final Buffer<E> blockingBuffer = makeObject();
|
|
||||||
final E obj = makeElement();
|
|
||||||
|
|
||||||
// spawn a read thread to wait on the empty buffer
|
|
||||||
final ArrayList<String> exceptionList = new ArrayList<String>();
|
|
||||||
final Thread thread = new ReadThread<E>(blockingBuffer, obj, exceptionList, "remove");
|
|
||||||
thread.start();
|
|
||||||
|
|
||||||
// Interrupting the thread should cause it to throw BufferUnderflowException
|
|
||||||
thread.interrupt();
|
|
||||||
|
|
||||||
// Chill, so thread can throw and add message to exceptionList
|
|
||||||
delay();
|
|
||||||
assertTrue("Thread interrupt should have led to underflow", exceptionList
|
|
||||||
.contains("BufferUnderFlow"));
|
|
||||||
if (thread.isAlive()) {
|
|
||||||
fail("Read thread has hung.");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testTimeoutGet() {
|
|
||||||
final BlockingBuffer<E> buffer = new BlockingBuffer<E>(new MyBuffer<E>());
|
|
||||||
try {
|
|
||||||
buffer.get(100);
|
|
||||||
fail("Get should have timed out.");
|
|
||||||
} catch (final BufferUnderflowException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testTimeoutRemove() {
|
|
||||||
final BlockingBuffer<E> buffer = new BlockingBuffer<E>(new MyBuffer<E>());
|
|
||||||
try {
|
|
||||||
buffer.remove(100);
|
|
||||||
fail("Get should have timed out.");
|
|
||||||
} catch (final BufferUnderflowException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static class DelayedAdd<E> extends Thread {
|
|
||||||
|
|
||||||
Buffer<E> buffer;
|
|
||||||
|
|
||||||
E obj;
|
|
||||||
|
|
||||||
long delay = 1000;
|
|
||||||
|
|
||||||
public DelayedAdd(final Buffer<E> buffer, final E obj, final long delay) {
|
|
||||||
this.buffer = buffer;
|
|
||||||
this.obj = obj;
|
|
||||||
this.delay = delay;
|
|
||||||
}
|
|
||||||
|
|
||||||
DelayedAdd(final Buffer<E> buffer, final E obj) {
|
|
||||||
super();
|
|
||||||
this.buffer = buffer;
|
|
||||||
this.obj = obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
// wait for other thread to block on get() or remove()
|
|
||||||
Thread.sleep(delay);
|
|
||||||
} catch (final InterruptedException e) {
|
|
||||||
}
|
|
||||||
buffer.add(obj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static class DelayedAddAll<E> extends Thread {
|
|
||||||
|
|
||||||
Buffer<E> buffer;
|
|
||||||
|
|
||||||
E obj;
|
|
||||||
|
|
||||||
long delay = 100;
|
|
||||||
|
|
||||||
public DelayedAddAll(final Buffer<E> buffer, final E obj, final long delay) {
|
|
||||||
this.buffer = buffer;
|
|
||||||
this.obj = obj;
|
|
||||||
this.delay = delay;
|
|
||||||
}
|
|
||||||
|
|
||||||
DelayedAddAll(final Buffer<E> buffer, final E obj) {
|
|
||||||
super();
|
|
||||||
this.buffer = buffer;
|
|
||||||
this.obj = obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
// wait for other thread to block on get() or remove()
|
|
||||||
Thread.sleep(delay);
|
|
||||||
} catch (final InterruptedException e) {
|
|
||||||
}
|
|
||||||
buffer.addAll(Collections.singleton(obj));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static class ReadThread<E> extends Thread {
|
|
||||||
|
|
||||||
Buffer<E> buffer;
|
|
||||||
|
|
||||||
Object obj;
|
|
||||||
|
|
||||||
ArrayList<String> exceptionList = null;
|
|
||||||
|
|
||||||
String action = "get";
|
|
||||||
|
|
||||||
Set<E> objs;
|
|
||||||
|
|
||||||
ReadThread(final Buffer<E> buffer, final Object obj) {
|
|
||||||
super();
|
|
||||||
this.buffer = buffer;
|
|
||||||
this.obj = obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReadThread(final Buffer<E> buffer, final Object obj, final ArrayList<String> exceptionList) {
|
|
||||||
super();
|
|
||||||
this.buffer = buffer;
|
|
||||||
this.obj = obj;
|
|
||||||
this.exceptionList = exceptionList;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReadThread(final Buffer<E> buffer, final Object obj, final ArrayList<String> exceptionList, final String action) {
|
|
||||||
super();
|
|
||||||
this.buffer = buffer;
|
|
||||||
this.obj = obj;
|
|
||||||
this.exceptionList = exceptionList;
|
|
||||||
this.action = action;
|
|
||||||
}
|
|
||||||
|
|
||||||
ReadThread(final Buffer<E> buffer, final Set<E> objs, final String action) {
|
|
||||||
super();
|
|
||||||
this.buffer = buffer;
|
|
||||||
this.objs = objs;
|
|
||||||
this.action = action;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
if (action == "get") {
|
|
||||||
assertSame(obj, buffer.get());
|
|
||||||
} else {
|
|
||||||
if (null != obj) {
|
|
||||||
assertSame(obj, buffer.remove());
|
|
||||||
} else {
|
|
||||||
assertTrue(objs.remove(buffer.remove()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (final BufferUnderflowException ex) {
|
|
||||||
exceptionList.add("BufferUnderFlow");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
protected static class MyBuffer<E> extends LinkedList<E> implements Buffer<E> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generated serial version ID.
|
|
||||||
*/
|
|
||||||
private static final long serialVersionUID = -1772433262105175184L;
|
|
||||||
|
|
||||||
public E get() {
|
|
||||||
if (isEmpty()) {
|
|
||||||
throw new BufferUnderflowException();
|
|
||||||
}
|
|
||||||
return get(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public E remove() {
|
|
||||||
if (isEmpty()) {
|
|
||||||
throw new BufferUnderflowException();
|
|
||||||
}
|
|
||||||
return remove(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void delay() {
|
|
||||||
try {
|
|
||||||
Thread.sleep( 200 );
|
|
||||||
} catch (final InterruptedException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getCompatibilityVersion() {
|
|
||||||
return "3.1";
|
|
||||||
}
|
|
||||||
|
|
||||||
// public void testCreate() throws Exception {
|
|
||||||
// Buffer buffer = BlockingBuffer.decorate(new UnboundedFifoBuffer());
|
|
||||||
// writeExternalFormToDisk((java.io.Serializable) buffer,
|
|
||||||
// "D:/dev/collections/data/test/BlockingBuffer.emptyCollection.version3.1.obj");
|
|
||||||
// buffer = BlockingBuffer.decorate(new UnboundedFifoBuffer());
|
|
||||||
// buffer.add("A");
|
|
||||||
// buffer.add("B");
|
|
||||||
// buffer.add("C");
|
|
||||||
// writeExternalFormToDisk((java.io.Serializable) buffer,
|
|
||||||
// "D:/dev/collections/data/test/BlockingBuffer.fullCollection.version3.1.obj");
|
|
||||||
// }
|
|
||||||
}
|
|
|
@ -1,221 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections.buffer;
|
|
||||||
|
|
||||||
import org.apache.commons.collections.AbstractObjectTest;
|
|
||||||
import org.apache.commons.collections.BoundedCollection;
|
|
||||||
import org.apache.commons.collections.Buffer;
|
|
||||||
import org.apache.commons.collections.BufferOverflowException;
|
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
public class BoundedBufferTest<E> extends AbstractObjectTest {
|
|
||||||
|
|
||||||
public BoundedBufferTest(final String testName) {
|
|
||||||
super(testName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getCompatibilityVersion() {
|
|
||||||
return "3.2";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEqualsCheckable() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Buffer<E> makeObject() {
|
|
||||||
return BoundedBuffer.boundedBuffer(new UnboundedFifoBuffer<E>(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testMaxSize() {
|
|
||||||
final Buffer<E> bounded = BoundedBuffer.boundedBuffer(new UnboundedFifoBuffer<E>(), 2, 500);
|
|
||||||
final BoundedCollection<?> bc = (BoundedCollection<?>) bounded;
|
|
||||||
assertEquals(2, bc.maxSize());
|
|
||||||
assertEquals(false, bc.isFull());
|
|
||||||
bounded.add((E) "A");
|
|
||||||
assertEquals(false, bc.isFull());
|
|
||||||
bounded.add((E) "B");
|
|
||||||
assertEquals(true, bc.isFull());
|
|
||||||
bounded.remove();
|
|
||||||
assertEquals(false, bc.isFull());
|
|
||||||
try {
|
|
||||||
BoundedBuffer.boundedBuffer(new UnboundedFifoBuffer<E>(), 0);
|
|
||||||
fail();
|
|
||||||
} catch (final IllegalArgumentException ex) {}
|
|
||||||
try {
|
|
||||||
BoundedBuffer.boundedBuffer(new UnboundedFifoBuffer<E>(), -1);
|
|
||||||
fail();
|
|
||||||
} catch (final IllegalArgumentException ex) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testAddToFullBufferNoTimeout() {
|
|
||||||
final Buffer<E> bounded = makeObject();
|
|
||||||
bounded.add((E) "Hello");
|
|
||||||
try {
|
|
||||||
bounded.add((E) "World");
|
|
||||||
fail();
|
|
||||||
} catch (final BufferOverflowException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testAddAllToFullBufferNoTimeout() {
|
|
||||||
final Buffer<E> bounded = makeObject();
|
|
||||||
bounded.add((E) "Hello");
|
|
||||||
try {
|
|
||||||
bounded.addAll(Collections.singleton((E) "World"));
|
|
||||||
fail();
|
|
||||||
} catch (final BufferOverflowException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testAddAllToEmptyBufferExceedMaxSizeNoTimeout() {
|
|
||||||
final Buffer<E> bounded = makeObject();
|
|
||||||
try {
|
|
||||||
bounded.addAll(Collections.nCopies(2, (E) "test"));
|
|
||||||
fail();
|
|
||||||
} catch (final BufferOverflowException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testAddToFullBufferRemoveViaIterator() {
|
|
||||||
final Buffer<E> bounded = BoundedBuffer.boundedBuffer(new UnboundedFifoBuffer<E>(), 1, 500);
|
|
||||||
bounded.add((E) "Hello");
|
|
||||||
new DelayedIteratorRemove(bounded, 200).start();
|
|
||||||
bounded.add((E) "World");
|
|
||||||
assertEquals(1, bounded.size());
|
|
||||||
assertEquals("World", bounded.get());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testAddAllToFullBufferRemoveViaIterator() {
|
|
||||||
final Buffer<E> bounded = BoundedBuffer.boundedBuffer(new UnboundedFifoBuffer<E>(), 2, 500);
|
|
||||||
bounded.add((E) "Hello");
|
|
||||||
bounded.add((E) "World");
|
|
||||||
new DelayedIteratorRemove(bounded, 200, 2).start();
|
|
||||||
bounded.addAll(Arrays.asList((E[]) new String[] { "Foo", "Bar" }));
|
|
||||||
assertEquals(2, bounded.size());
|
|
||||||
assertEquals("Foo", bounded.remove());
|
|
||||||
assertEquals("Bar", bounded.remove());
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testAddToFullBufferWithTimeout() {
|
|
||||||
final Buffer<E> bounded = BoundedBuffer.boundedBuffer(new UnboundedFifoBuffer<E>(), 1, 500);
|
|
||||||
bounded.add((E) "Hello");
|
|
||||||
new DelayedRemove(bounded, 200).start();
|
|
||||||
bounded.add((E) "World");
|
|
||||||
assertEquals(1, bounded.size());
|
|
||||||
assertEquals("World", bounded.get());
|
|
||||||
try {
|
|
||||||
bounded.add((E) "!");
|
|
||||||
fail();
|
|
||||||
} catch (final BufferOverflowException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testAddAllToFullBufferWithTimeout() {
|
|
||||||
final Buffer<E> bounded = BoundedBuffer.boundedBuffer(new UnboundedFifoBuffer<E>(), 2, 500);
|
|
||||||
bounded.add((E) "Hello");
|
|
||||||
bounded.add((E) "World");
|
|
||||||
new DelayedRemove(bounded, 200, 2).start();
|
|
||||||
|
|
||||||
bounded.addAll(Arrays.asList((E[]) new String[] { "Foo", "Bar" }));
|
|
||||||
assertEquals(2, bounded.size());
|
|
||||||
assertEquals("Foo", bounded.get());
|
|
||||||
try {
|
|
||||||
bounded.add((E) "!");
|
|
||||||
fail();
|
|
||||||
} catch (final BufferOverflowException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class DelayedIteratorRemove extends Thread {
|
|
||||||
|
|
||||||
private final Buffer<?> buffer;
|
|
||||||
|
|
||||||
private final long delay;
|
|
||||||
|
|
||||||
private final int nToRemove;
|
|
||||||
|
|
||||||
public DelayedIteratorRemove(final Buffer<?> buffer, final long delay, final int nToRemove) {
|
|
||||||
this.buffer = buffer;
|
|
||||||
this.delay = delay;
|
|
||||||
this.nToRemove = nToRemove;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DelayedIteratorRemove(final Buffer<?> buffer, final long delay) {
|
|
||||||
this(buffer, delay, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
Thread.sleep(delay);
|
|
||||||
final Iterator<?> iter = buffer.iterator();
|
|
||||||
for (int i = 0; i < nToRemove; ++i) {
|
|
||||||
iter.next();
|
|
||||||
iter.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (final InterruptedException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class DelayedRemove extends Thread {
|
|
||||||
|
|
||||||
private final Buffer<?> buffer;
|
|
||||||
|
|
||||||
private final long delay;
|
|
||||||
|
|
||||||
private final int nToRemove;
|
|
||||||
|
|
||||||
public DelayedRemove(final Buffer<?> buffer, final long delay, final int nToRemove) {
|
|
||||||
this.buffer = buffer;
|
|
||||||
this.delay = delay;
|
|
||||||
this.nToRemove = nToRemove;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DelayedRemove(final Buffer<?> buffer, final long delay) {
|
|
||||||
this(buffer, delay, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
Thread.sleep(delay);
|
|
||||||
for (int i = 0; i < nToRemove; ++i) {
|
|
||||||
buffer.remove();
|
|
||||||
}
|
|
||||||
} catch (final InterruptedException e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,123 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections.buffer;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
import junit.framework.Test;
|
|
||||||
|
|
||||||
import org.apache.commons.collections.BufferOverflowException;
|
|
||||||
import org.apache.commons.collections.BulkTest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runs tests against a full BoundedFifoBuffer, since many of the algorithms
|
|
||||||
* differ depending on whether the fifo is full or not.
|
|
||||||
*
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public class BoundedFifoBuffer2Test<E> extends BoundedFifoBufferTest<E> {
|
|
||||||
|
|
||||||
public BoundedFifoBuffer2Test(final String n) {
|
|
||||||
super(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Test suite() {
|
|
||||||
return BulkTest.makeSuite(BoundedFifoBuffer2Test.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a BoundedFifoBuffer that's filled to capacity.
|
|
||||||
* Any attempt to add to the returned buffer will result in a
|
|
||||||
* BufferOverflowException.
|
|
||||||
*
|
|
||||||
* @return a full BoundedFifoBuffer
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Collection<E> makeFullCollection() {
|
|
||||||
return new BoundedFifoBuffer<E>(Arrays.asList(getFullElements()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overridden to skip the add tests. All of them would fail with a
|
|
||||||
* BufferOverflowException.
|
|
||||||
*
|
|
||||||
* @return false
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean isAddSupported() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overridden because the add operations raise BufferOverflowException
|
|
||||||
* instead of UnsupportedOperationException.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void testUnsupportedAdd() {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests to make sure the add operations raise BufferOverflowException.
|
|
||||||
*/
|
|
||||||
public void testBufferOverflow() {
|
|
||||||
resetFull();
|
|
||||||
try {
|
|
||||||
getCollection().add(getOtherElements()[0]);
|
|
||||||
fail("add should raise BufferOverflow.");
|
|
||||||
} catch (final BufferOverflowException e) {
|
|
||||||
// expected
|
|
||||||
}
|
|
||||||
verify();
|
|
||||||
|
|
||||||
try {
|
|
||||||
getCollection().addAll(Arrays.asList(getOtherElements()));
|
|
||||||
fail("addAll should raise BufferOverflow.");
|
|
||||||
} catch (final BufferOverflowException e) {
|
|
||||||
// expected
|
|
||||||
}
|
|
||||||
verify();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests is full
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testIsFull() {
|
|
||||||
resetFull();
|
|
||||||
assertEquals(true, getCollection().isFull());
|
|
||||||
getCollection().remove();
|
|
||||||
assertEquals(false, getCollection().isFull());
|
|
||||||
getCollection().add((E) "jj");
|
|
||||||
assertEquals(true, getCollection().isFull());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests max size
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testMaxSize() {
|
|
||||||
resetFull();
|
|
||||||
assertEquals(getFullElements().length, getCollection().maxSize());
|
|
||||||
getCollection().remove();
|
|
||||||
assertEquals(getFullElements().length, getCollection().maxSize());
|
|
||||||
getCollection().add((E) "jj");
|
|
||||||
assertEquals(getFullElements().length, getCollection().maxSize());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,251 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections.buffer;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
|
|
||||||
import junit.framework.Test;
|
|
||||||
|
|
||||||
import org.apache.commons.collections.BufferUnderflowException;
|
|
||||||
import org.apache.commons.collections.BulkTest;
|
|
||||||
import org.apache.commons.collections.collection.AbstractCollectionTest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test cases for BoundedFifoBuffer.
|
|
||||||
*
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public class BoundedFifoBufferTest<E> extends AbstractCollectionTest<E> {
|
|
||||||
|
|
||||||
public BoundedFifoBufferTest(final String n) {
|
|
||||||
super(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Test suite() {
|
|
||||||
return BulkTest.makeSuite(BoundedFifoBufferTest.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Runs through the regular verifications, but also verifies that
|
|
||||||
* the buffer contains the same elements in the same sequence as the
|
|
||||||
* list.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void verify() {
|
|
||||||
super.verify();
|
|
||||||
final Iterator<E> iterator1 = getCollection().iterator();
|
|
||||||
final Iterator<E> iterator2 = getConfirmed().iterator();
|
|
||||||
while (iterator2.hasNext()) {
|
|
||||||
assertTrue(iterator1.hasNext());
|
|
||||||
final E o1 = iterator1.next();
|
|
||||||
final E o2 = iterator2.next();
|
|
||||||
assertEquals(o1, o2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Overridden because UnboundedFifoBuffer doesn't allow null elements.
|
|
||||||
* @return false
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean isNullSupported() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overridden because UnboundedFifoBuffer isn't fail fast.
|
|
||||||
* @return false
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean isFailFastSupported() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Returns an empty ArrayList.
|
|
||||||
*
|
|
||||||
* @return an empty ArrayList
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public List<E> makeConfirmedCollection() {
|
|
||||||
return new ArrayList<E>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a full ArrayList.
|
|
||||||
*
|
|
||||||
* @return a full ArrayList
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public List<E> makeConfirmedFullCollection() {
|
|
||||||
final List<E> c = makeConfirmedCollection();
|
|
||||||
c.addAll(java.util.Arrays.asList(getFullElements()));
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an empty BoundedFifoBuffer that won't overflow.
|
|
||||||
*
|
|
||||||
* @return an empty BoundedFifoBuffer
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public BoundedFifoBuffer<E> makeObject() {
|
|
||||||
return new BoundedFifoBuffer<E>(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Tests that the removal operation actually removes the first element.
|
|
||||||
*/
|
|
||||||
public void testBoundedFifoBufferRemove() {
|
|
||||||
resetFull();
|
|
||||||
final int size = getConfirmed().size();
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
final E o1 = getCollection().remove();
|
|
||||||
final E o2 = getConfirmed().remove(0);
|
|
||||||
assertEquals("Removed objects should be equal", o1, o2);
|
|
||||||
verify();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
getCollection().remove();
|
|
||||||
fail("Empty buffer should raise Underflow.");
|
|
||||||
} catch (final BufferUnderflowException e) {
|
|
||||||
// expected
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests that the constructor correctly throws an exception.
|
|
||||||
*/
|
|
||||||
public void testConstructorException1() {
|
|
||||||
try {
|
|
||||||
new BoundedFifoBuffer<E>(0);
|
|
||||||
} catch (final IllegalArgumentException ex) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests that the constructor correctly throws an exception.
|
|
||||||
*/
|
|
||||||
public void testConstructorException2() {
|
|
||||||
try {
|
|
||||||
new BoundedFifoBuffer<E>(-20);
|
|
||||||
} catch (final IllegalArgumentException ex) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests that the constructor correctly throws an exception.
|
|
||||||
*/
|
|
||||||
public void testConstructorException3() {
|
|
||||||
try {
|
|
||||||
new BoundedFifoBuffer<E>(null);
|
|
||||||
} catch (final NullPointerException ex) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests that the get(index) method correctly throws an exception.
|
|
||||||
*/
|
|
||||||
public void testGetException() {
|
|
||||||
resetFull();
|
|
||||||
try {
|
|
||||||
getCollection().get(-1);
|
|
||||||
fail();
|
|
||||||
} catch (final NoSuchElementException ex) {
|
|
||||||
// expected
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
getCollection().get(getCollection().size());
|
|
||||||
fail();
|
|
||||||
} catch (final NoSuchElementException ex) {
|
|
||||||
// expected
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testGetIndex() {
|
|
||||||
resetFull();
|
|
||||||
|
|
||||||
final BoundedFifoBuffer<E> buffer = getCollection();
|
|
||||||
final List<E> confirmed = getConfirmed();
|
|
||||||
for (int i = 0; i < confirmed.size(); i++) {
|
|
||||||
assertEquals(confirmed.get(i), buffer.get(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove the first two elements and check again
|
|
||||||
buffer.remove();
|
|
||||||
buffer.remove();
|
|
||||||
|
|
||||||
for (int i = 0; i < buffer.size(); i++) {
|
|
||||||
assertEquals(confirmed.get(i + 2), buffer.get(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getCompatibilityVersion() {
|
|
||||||
return "3.1";
|
|
||||||
}
|
|
||||||
|
|
||||||
// BZ 33071 -- gets start=end=1 before removal of interior element
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testShift() {
|
|
||||||
final BoundedFifoBuffer<E> fifo = new BoundedFifoBuffer<E>(3);
|
|
||||||
fifo.add((E) "a");
|
|
||||||
fifo.add((E) "b");
|
|
||||||
fifo.add((E) "c");
|
|
||||||
fifo.remove();
|
|
||||||
fifo.add((E) "e");
|
|
||||||
fifo.remove("c");
|
|
||||||
}
|
|
||||||
|
|
||||||
// public void testCreate() throws Exception {
|
|
||||||
// resetEmpty();
|
|
||||||
// writeExternalFormToDisk((java.io.Serializable) collection, "D:/dev/collections/data/test/BoundedFifoBuffer.emptyCollection.version3.1.obj");
|
|
||||||
// resetFull();
|
|
||||||
// writeExternalFormToDisk((java.io.Serializable) collection, "D:/dev/collections/data/test/BoundedFifoBuffer.fullCollection.version3.1.obj");
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public BoundedFifoBuffer<E> getCollection() {
|
|
||||||
return (BoundedFifoBuffer<E>) super.getCollection();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public List<E> getConfirmed() {
|
|
||||||
return (List<E>) super.getConfirmed();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,461 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections.buffer;
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.ObjectInputStream;
|
|
||||||
import java.io.ObjectOutputStream;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import junit.framework.Test;
|
|
||||||
import org.apache.commons.collections.Buffer;
|
|
||||||
import org.apache.commons.collections.BufferUnderflowException;
|
|
||||||
import org.apache.commons.collections.BulkTest;
|
|
||||||
import org.apache.commons.collections.collection.AbstractCollectionTest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test cases for CircularFifoBuffer.
|
|
||||||
*
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public class CircularFifoBufferTest<E> extends AbstractCollectionTest<E> {
|
|
||||||
|
|
||||||
public CircularFifoBufferTest(final String n) {
|
|
||||||
super(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Test suite() {
|
|
||||||
return BulkTest.makeSuite(CircularFifoBufferTest.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Runs through the regular verifications, but also verifies that
|
|
||||||
* the buffer contains the same elements in the same sequence as the
|
|
||||||
* list.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void verify() {
|
|
||||||
super.verify();
|
|
||||||
final Iterator<E> iterator1 = getCollection().iterator();
|
|
||||||
final Iterator<E> iterator2 = getConfirmed().iterator();
|
|
||||||
while (iterator2.hasNext()) {
|
|
||||||
assertTrue(iterator1.hasNext());
|
|
||||||
final Object o1 = iterator1.next();
|
|
||||||
final Object o2 = iterator2.next();
|
|
||||||
assertEquals(o1, o2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Overridden because UnboundedFifoBuffer doesn't allow null elements.
|
|
||||||
* @return false
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean isNullSupported() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overridden because UnboundedFifoBuffer isn't fail fast.
|
|
||||||
* @return false
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean isFailFastSupported() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Returns an empty ArrayList.
|
|
||||||
*
|
|
||||||
* @return an empty ArrayList
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Collection<E> makeConfirmedCollection() {
|
|
||||||
return new ArrayList<E>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a full ArrayList.
|
|
||||||
*
|
|
||||||
* @return a full ArrayList
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Collection<E> makeConfirmedFullCollection() {
|
|
||||||
final Collection<E> c = makeConfirmedCollection();
|
|
||||||
c.addAll(java.util.Arrays.asList(getFullElements()));
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an empty BoundedFifoBuffer that won't overflow.
|
|
||||||
*
|
|
||||||
* @return an empty BoundedFifoBuffer
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Collection<E> makeObject() {
|
|
||||||
return new CircularFifoBuffer<E>(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Tests that the removal operation actually removes the first element.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testCircularFifoBufferCircular() {
|
|
||||||
final List<E> list = new ArrayList<E>();
|
|
||||||
list.add((E) "A");
|
|
||||||
list.add((E) "B");
|
|
||||||
list.add((E) "C");
|
|
||||||
final Buffer<E> buf = new CircularFifoBuffer<E>(list);
|
|
||||||
|
|
||||||
assertEquals(true, buf.contains("A"));
|
|
||||||
assertEquals(true, buf.contains("B"));
|
|
||||||
assertEquals(true, buf.contains("C"));
|
|
||||||
|
|
||||||
buf.add((E) "D");
|
|
||||||
|
|
||||||
assertEquals(false, buf.contains("A"));
|
|
||||||
assertEquals(true, buf.contains("B"));
|
|
||||||
assertEquals(true, buf.contains("C"));
|
|
||||||
assertEquals(true, buf.contains("D"));
|
|
||||||
|
|
||||||
assertEquals("B", buf.get());
|
|
||||||
assertEquals("B", buf.remove());
|
|
||||||
assertEquals("C", buf.remove());
|
|
||||||
assertEquals("D", buf.remove());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests that the removal operation actually removes the first element.
|
|
||||||
*/
|
|
||||||
public void testCircularFifoBufferRemove() {
|
|
||||||
resetFull();
|
|
||||||
final int size = getConfirmed().size();
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
final Object o1 = getCollection().remove();
|
|
||||||
final Object o2 = getConfirmed().remove(0);
|
|
||||||
assertEquals("Removed objects should be equal", o1, o2);
|
|
||||||
verify();
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
getCollection().remove();
|
|
||||||
fail("Empty buffer should raise Underflow.");
|
|
||||||
} catch (final BufferUnderflowException e) {
|
|
||||||
// expected
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests that the constructor correctly throws an exception.
|
|
||||||
*/
|
|
||||||
public void testConstructorException1() {
|
|
||||||
try {
|
|
||||||
new CircularFifoBuffer<E>(0);
|
|
||||||
} catch (final IllegalArgumentException ex) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests that the constructor correctly throws an exception.
|
|
||||||
*/
|
|
||||||
public void testConstructorException2() {
|
|
||||||
try {
|
|
||||||
new CircularFifoBuffer<E>(-20);
|
|
||||||
} catch (final IllegalArgumentException ex) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests that the constructor correctly throws an exception.
|
|
||||||
*/
|
|
||||||
public void testConstructorException3() {
|
|
||||||
try {
|
|
||||||
new CircularFifoBuffer<E>(null);
|
|
||||||
} catch (final NullPointerException ex) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testRemoveError1() throws Exception {
|
|
||||||
// based on bug 33071
|
|
||||||
final CircularFifoBuffer<E> fifo = new CircularFifoBuffer<E>(5);
|
|
||||||
fifo.add((E) "1");
|
|
||||||
fifo.add((E) "2");
|
|
||||||
fifo.add((E) "3");
|
|
||||||
fifo.add((E) "4");
|
|
||||||
fifo.add((E) "5");
|
|
||||||
|
|
||||||
assertEquals("[1, 2, 3, 4, 5]", fifo.toString());
|
|
||||||
|
|
||||||
fifo.remove("3");
|
|
||||||
assertEquals("[1, 2, 4, 5]", fifo.toString());
|
|
||||||
|
|
||||||
fifo.remove("4");
|
|
||||||
assertEquals("[1, 2, 5]", fifo.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testRemoveError2() throws Exception {
|
|
||||||
// based on bug 33071
|
|
||||||
final CircularFifoBuffer<E> fifo = new CircularFifoBuffer<E>(5);
|
|
||||||
fifo.add((E) "1");
|
|
||||||
fifo.add((E) "2");
|
|
||||||
fifo.add((E) "3");
|
|
||||||
fifo.add((E) "4");
|
|
||||||
fifo.add((E) "5");
|
|
||||||
fifo.add((E) "6");
|
|
||||||
|
|
||||||
assertEquals(5, fifo.size());
|
|
||||||
assertEquals("[2, 3, 4, 5, 6]", fifo.toString());
|
|
||||||
|
|
||||||
fifo.remove("3");
|
|
||||||
assertEquals("[2, 4, 5, 6]", fifo.toString());
|
|
||||||
|
|
||||||
fifo.remove("4");
|
|
||||||
assertEquals("[2, 5, 6]", fifo.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testRemoveError3() throws Exception {
|
|
||||||
// based on bug 33071
|
|
||||||
final CircularFifoBuffer<E> fifo = new CircularFifoBuffer<E>(5);
|
|
||||||
fifo.add((E) "1");
|
|
||||||
fifo.add((E) "2");
|
|
||||||
fifo.add((E) "3");
|
|
||||||
fifo.add((E) "4");
|
|
||||||
fifo.add((E) "5");
|
|
||||||
|
|
||||||
assertEquals("[1, 2, 3, 4, 5]", fifo.toString());
|
|
||||||
|
|
||||||
fifo.remove("3");
|
|
||||||
assertEquals("[1, 2, 4, 5]", fifo.toString());
|
|
||||||
|
|
||||||
fifo.add((E) "6");
|
|
||||||
fifo.add((E) "7");
|
|
||||||
assertEquals("[2, 4, 5, 6, 7]", fifo.toString());
|
|
||||||
|
|
||||||
fifo.remove("4");
|
|
||||||
assertEquals("[2, 5, 6, 7]", fifo.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testRemoveError4() throws Exception {
|
|
||||||
// based on bug 33071
|
|
||||||
final CircularFifoBuffer<E> fifo = new CircularFifoBuffer<E>(5);
|
|
||||||
fifo.add((E) "1");
|
|
||||||
fifo.add((E) "2");
|
|
||||||
fifo.add((E) "3");
|
|
||||||
fifo.add((E) "4");
|
|
||||||
fifo.add((E) "5"); // end=0
|
|
||||||
fifo.add((E) "6"); // end=1
|
|
||||||
fifo.add((E) "7"); // end=2
|
|
||||||
|
|
||||||
assertEquals("[3, 4, 5, 6, 7]", fifo.toString());
|
|
||||||
|
|
||||||
fifo.remove("4"); // remove element in middle of array, after start
|
|
||||||
assertEquals("[3, 5, 6, 7]", fifo.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testRemoveError5() throws Exception {
|
|
||||||
// based on bug 33071
|
|
||||||
final CircularFifoBuffer<E> fifo = new CircularFifoBuffer<E>(5);
|
|
||||||
fifo.add((E) "1");
|
|
||||||
fifo.add((E) "2");
|
|
||||||
fifo.add((E) "3");
|
|
||||||
fifo.add((E) "4");
|
|
||||||
fifo.add((E) "5"); // end=0
|
|
||||||
fifo.add((E) "6"); // end=1
|
|
||||||
fifo.add((E) "7"); // end=2
|
|
||||||
|
|
||||||
assertEquals("[3, 4, 5, 6, 7]", fifo.toString());
|
|
||||||
|
|
||||||
fifo.remove("5"); // remove element at last pos in array
|
|
||||||
assertEquals("[3, 4, 6, 7]", fifo.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testRemoveError6() throws Exception {
|
|
||||||
// based on bug 33071
|
|
||||||
final CircularFifoBuffer<E> fifo = new CircularFifoBuffer<E>(5);
|
|
||||||
fifo.add((E) "1");
|
|
||||||
fifo.add((E) "2");
|
|
||||||
fifo.add((E) "3");
|
|
||||||
fifo.add((E) "4");
|
|
||||||
fifo.add((E) "5"); // end=0
|
|
||||||
fifo.add((E) "6"); // end=1
|
|
||||||
fifo.add((E) "7"); // end=2
|
|
||||||
|
|
||||||
assertEquals("[3, 4, 5, 6, 7]", fifo.toString());
|
|
||||||
|
|
||||||
fifo.remove("6"); // remove element at position zero in array
|
|
||||||
assertEquals("[3, 4, 5, 7]", fifo.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testRemoveError7() throws Exception {
|
|
||||||
// based on bug 33071
|
|
||||||
final CircularFifoBuffer<E> fifo = new CircularFifoBuffer<E>(5);
|
|
||||||
fifo.add((E) "1");
|
|
||||||
fifo.add((E) "2");
|
|
||||||
fifo.add((E) "3");
|
|
||||||
fifo.add((E) "4");
|
|
||||||
fifo.add((E) "5"); // end=0
|
|
||||||
fifo.add((E) "6"); // end=1
|
|
||||||
fifo.add((E) "7"); // end=2
|
|
||||||
|
|
||||||
assertEquals("[3, 4, 5, 6, 7]", fifo.toString());
|
|
||||||
|
|
||||||
fifo.remove("7"); // remove element at position one in array
|
|
||||||
assertEquals("[3, 4, 5, 6]", fifo.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testRemoveError8() throws Exception {
|
|
||||||
// based on bug 33071
|
|
||||||
final CircularFifoBuffer<E> fifo = new CircularFifoBuffer<E>(5);
|
|
||||||
fifo.add((E) "1");
|
|
||||||
fifo.add((E) "2");
|
|
||||||
fifo.add((E) "3");
|
|
||||||
fifo.add((E) "4");
|
|
||||||
fifo.add((E) "5"); // end=0
|
|
||||||
fifo.add((E) "6"); // end=1
|
|
||||||
fifo.add((E) "7"); // end=2
|
|
||||||
fifo.add((E) "8"); // end=3
|
|
||||||
|
|
||||||
assertEquals("[4, 5, 6, 7, 8]", fifo.toString());
|
|
||||||
|
|
||||||
fifo.remove("7"); // remove element at position one in array, need to shift 8
|
|
||||||
assertEquals("[4, 5, 6, 8]", fifo.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testRemoveError9() throws Exception {
|
|
||||||
// based on bug 33071
|
|
||||||
final CircularFifoBuffer<E> fifo = new CircularFifoBuffer<E>(5);
|
|
||||||
fifo.add((E) "1");
|
|
||||||
fifo.add((E) "2");
|
|
||||||
fifo.add((E) "3");
|
|
||||||
fifo.add((E) "4");
|
|
||||||
fifo.add((E) "5"); // end=0
|
|
||||||
fifo.add((E) "6"); // end=1
|
|
||||||
fifo.add((E) "7"); // end=2
|
|
||||||
fifo.add((E) "8"); // end=3
|
|
||||||
|
|
||||||
assertEquals("[4, 5, 6, 7, 8]", fifo.toString());
|
|
||||||
|
|
||||||
fifo.remove("8"); // remove element at position two in array
|
|
||||||
assertEquals("[4, 5, 6, 7]", fifo.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testRepeatedSerialization() throws Exception {
|
|
||||||
// bug 31433
|
|
||||||
final CircularFifoBuffer<E> b = new CircularFifoBuffer<E>(2);
|
|
||||||
b.add((E) "a");
|
|
||||||
assertEquals(1, b.size());
|
|
||||||
assertEquals(true, b.contains("a"));
|
|
||||||
|
|
||||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
|
||||||
new ObjectOutputStream(bos).writeObject(b);
|
|
||||||
|
|
||||||
final CircularFifoBuffer<E> b2 = (CircularFifoBuffer<E>) new ObjectInputStream(
|
|
||||||
new ByteArrayInputStream(bos.toByteArray())).readObject();
|
|
||||||
|
|
||||||
assertEquals(1, b2.size());
|
|
||||||
assertEquals(true, b2.contains("a"));
|
|
||||||
b2.add((E) "b");
|
|
||||||
assertEquals(2, b2.size());
|
|
||||||
assertEquals(true, b2.contains("a"));
|
|
||||||
assertEquals(true, b2.contains("b"));
|
|
||||||
|
|
||||||
bos = new ByteArrayOutputStream();
|
|
||||||
new ObjectOutputStream(bos).writeObject(b2);
|
|
||||||
|
|
||||||
final CircularFifoBuffer<E> b3 = (CircularFifoBuffer<E>) new ObjectInputStream(
|
|
||||||
new ByteArrayInputStream(bos.toByteArray())).readObject();
|
|
||||||
|
|
||||||
assertEquals(2, b3.size());
|
|
||||||
assertEquals(true, b3.contains("a"));
|
|
||||||
assertEquals(true, b3.contains("b"));
|
|
||||||
b3.add((E) "c");
|
|
||||||
assertEquals(2, b3.size());
|
|
||||||
assertEquals(true, b3.contains("b"));
|
|
||||||
assertEquals(true, b3.contains("c"));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testGetIndex() {
|
|
||||||
resetFull();
|
|
||||||
|
|
||||||
final CircularFifoBuffer<E> buffer = getCollection();
|
|
||||||
final List<E> confirmed = getConfirmed();
|
|
||||||
for (int i = 0; i < confirmed.size(); i++) {
|
|
||||||
assertEquals(confirmed.get(i), buffer.get(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove the first two elements and check again
|
|
||||||
buffer.remove();
|
|
||||||
buffer.remove();
|
|
||||||
|
|
||||||
for (int i = 0; i < buffer.size(); i++) {
|
|
||||||
assertEquals(confirmed.get(i + 2), buffer.get(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getCompatibilityVersion() {
|
|
||||||
return "3.1";
|
|
||||||
}
|
|
||||||
|
|
||||||
// public void testCreate() throws Exception {
|
|
||||||
// resetEmpty();
|
|
||||||
// writeExternalFormToDisk((java.io.Serializable) collection, "D:/dev/collections/data/test/CircularFifoBuffer.emptyCollection.version3.1.obj");
|
|
||||||
// resetFull();
|
|
||||||
// writeExternalFormToDisk((java.io.Serializable) collection, "D:/dev/collections/data/test/CircularFifoBuffer.fullCollection.version3.1.obj");
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public CircularFifoBuffer<E> getCollection() {
|
|
||||||
return (CircularFifoBuffer<E>) super.getCollection();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public List<E> getConfirmed() {
|
|
||||||
return (List<E>) super.getConfirmed();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,130 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections.buffer;
|
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.EmptyStackException;
|
|
||||||
|
|
||||||
import org.apache.commons.collections.Buffer;
|
|
||||||
import org.apache.commons.collections.BufferUnderflowException;
|
|
||||||
import org.apache.commons.collections.Predicate;
|
|
||||||
import org.apache.commons.collections.collection.PredicatedCollectionTest;
|
|
||||||
import org.apache.commons.collections.ArrayStack;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extension of {@link PredicatedCollectionTest} for exercising the
|
|
||||||
* {@link PredicatedBuffer} implementation.
|
|
||||||
*
|
|
||||||
* @since 3.0
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public class PredicatedBufferTest<E> extends PredicatedCollectionTest<E> {
|
|
||||||
|
|
||||||
public PredicatedBufferTest(final String testName) {
|
|
||||||
super(testName);
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------
|
|
||||||
|
|
||||||
protected Buffer<E> decorateCollection(final Buffer<E> buffer, final Predicate<E> predicate) {
|
|
||||||
return PredicatedBuffer.predicatedBuffer(buffer, predicate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Buffer<E> makeObject() {
|
|
||||||
return decorateCollection(new LifoStackAsBuffer<E>(), truePredicate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<E> makeConfirmedCollection() {
|
|
||||||
return new ArrayStack<E>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<E> makeConfirmedFullCollection() {
|
|
||||||
final ArrayStack<E> list = new ArrayStack<E>();
|
|
||||||
list.addAll(java.util.Arrays.asList(getFullElements()));
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------------------------------------
|
|
||||||
|
|
||||||
public Buffer<E> makeTestBuffer() {
|
|
||||||
return decorateCollection(new LifoStackAsBuffer<E>(), testPredicate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testGet() {
|
|
||||||
final Buffer<E> buffer = makeTestBuffer();
|
|
||||||
try {
|
|
||||||
buffer.get();
|
|
||||||
fail("Expecting BufferUnderflowException");
|
|
||||||
} catch (final BufferUnderflowException ex) {
|
|
||||||
// expected
|
|
||||||
}
|
|
||||||
buffer.add((E) "one");
|
|
||||||
buffer.add((E) "two");
|
|
||||||
buffer.add((E) "three");
|
|
||||||
assertEquals("Buffer get", "three", buffer.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testRemove() {
|
|
||||||
final Buffer<E> buffer = makeTestBuffer();
|
|
||||||
buffer.add((E) "one");
|
|
||||||
assertEquals("Buffer get", "one", buffer.remove());
|
|
||||||
try {
|
|
||||||
buffer.remove();
|
|
||||||
fail("Expecting BufferUnderflowException");
|
|
||||||
} catch (final BufferUnderflowException ex) {
|
|
||||||
// expected
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getCompatibilityVersion() {
|
|
||||||
return "3.1";
|
|
||||||
}
|
|
||||||
|
|
||||||
// public void testCreate() throws Exception {
|
|
||||||
// resetEmpty();
|
|
||||||
// writeExternalFormToDisk((java.io.Serializable) collection, "D:/dev/collections/data/test/PredicatedBuffer.emptyCollection.version3.1.obj");
|
|
||||||
// resetFull();
|
|
||||||
// writeExternalFormToDisk((java.io.Serializable) collection, "D:/dev/collections/data/test/PredicatedBuffer.fullCollection.version3.1.obj");
|
|
||||||
// }
|
|
||||||
|
|
||||||
private static class LifoStackAsBuffer<E> extends ArrayStack<E> implements Buffer<E> {
|
|
||||||
|
|
||||||
public E get() {
|
|
||||||
try {
|
|
||||||
return peek();
|
|
||||||
} catch (EmptyStackException e) {
|
|
||||||
throw new BufferUnderflowException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public E remove() {
|
|
||||||
try {
|
|
||||||
return pop();
|
|
||||||
} catch (EmptyStackException e) {
|
|
||||||
throw new BufferUnderflowException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,416 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections.buffer;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
import org.apache.commons.collections.Buffer;
|
|
||||||
import org.apache.commons.collections.BufferUnderflowException;
|
|
||||||
import org.apache.commons.collections.ComparatorUtils;
|
|
||||||
import org.apache.commons.collections.collection.AbstractCollectionTest;
|
|
||||||
import org.apache.commons.collections.comparators.ComparableComparator;
|
|
||||||
import org.apache.commons.collections.comparators.ReverseComparator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests the PriorityBuffer.
|
|
||||||
*
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("boxing")
|
|
||||||
public class PriorityBufferTest<E> extends AbstractCollectionTest<E> {
|
|
||||||
|
|
||||||
public PriorityBufferTest(final String testName) {
|
|
||||||
super(testName);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void verify() {
|
|
||||||
super.verify();
|
|
||||||
final PriorityBuffer<E> heap = getCollection();
|
|
||||||
|
|
||||||
Comparator<? super E> c = heap.comparator;
|
|
||||||
if (c == null) {
|
|
||||||
c = ComparatorUtils.NATURAL_COMPARATOR;
|
|
||||||
}
|
|
||||||
if (!heap.ascendingOrder) {
|
|
||||||
c = ComparatorUtils.reversedComparator(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
final E[] tree = heap.elements;
|
|
||||||
for (int i = 1; i <= heap.size; i++) {
|
|
||||||
final E parent = tree[i];
|
|
||||||
if (i * 2 <= heap.size) {
|
|
||||||
assertTrue("Parent is less than or equal to its left child", c.compare(parent, tree[i * 2]) <= 0);
|
|
||||||
}
|
|
||||||
if (i * 2 + 1 < heap.size) {
|
|
||||||
assertTrue("Parent is less than or equal to its right child", c.compare(parent, tree[i * 2 + 1]) <= 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Overridden because BinaryBuffer isn't fail fast.
|
|
||||||
* @return false
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean isFailFastSupported() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
@Override
|
|
||||||
public Collection<E> makeConfirmedCollection() {
|
|
||||||
return new ArrayList<E>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<E> makeConfirmedFullCollection() {
|
|
||||||
final ArrayList<E> list = new ArrayList<E>();
|
|
||||||
list.addAll(Arrays.asList(getFullElements()));
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a new, empty {@link Object} to used for testing.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Buffer<E> makeObject() {
|
|
||||||
return new PriorityBuffer<E>();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public E[] getFullElements() {
|
|
||||||
return (E[]) getFullNonNullStringElements();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public E[] getOtherElements() {
|
|
||||||
return (E[]) getOtherNonNullStringElements();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
public void testBufferEmpty() {
|
|
||||||
resetEmpty();
|
|
||||||
final Buffer<E> buffer = getCollection();
|
|
||||||
|
|
||||||
assertEquals(0, buffer.size());
|
|
||||||
assertEquals(true, buffer.isEmpty());
|
|
||||||
try {
|
|
||||||
buffer.get();
|
|
||||||
fail();
|
|
||||||
} catch (final BufferUnderflowException ex) {}
|
|
||||||
|
|
||||||
try {
|
|
||||||
buffer.remove();
|
|
||||||
fail();
|
|
||||||
} catch (final BufferUnderflowException ex) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testBasicOps() {
|
|
||||||
final PriorityBuffer<E> heap = new PriorityBuffer<E>();
|
|
||||||
heap.add((E) "a");
|
|
||||||
heap.add((E) "c");
|
|
||||||
heap.add((E) "e");
|
|
||||||
heap.add((E) "b");
|
|
||||||
heap.add((E) "d");
|
|
||||||
heap.add((E) "n");
|
|
||||||
heap.add((E) "m");
|
|
||||||
heap.add((E) "l");
|
|
||||||
heap.add((E) "k");
|
|
||||||
heap.add((E) "j");
|
|
||||||
heap.add((E) "i");
|
|
||||||
heap.add((E) "h");
|
|
||||||
heap.add((E) "g");
|
|
||||||
heap.add((E) "f");
|
|
||||||
|
|
||||||
assertTrue("heap should not be empty after adds", !heap.isEmpty());
|
|
||||||
|
|
||||||
for (int i = 0; i < 14; i++) {
|
|
||||||
assertEquals(
|
|
||||||
"get using default constructor should return minimum value in the binary heap",
|
|
||||||
String.valueOf((char) ('a' + i)),
|
|
||||||
heap.get());
|
|
||||||
|
|
||||||
assertEquals(
|
|
||||||
"remove using default constructor should return minimum value in the binary heap",
|
|
||||||
String.valueOf((char) ('a' + i)),
|
|
||||||
heap.remove());
|
|
||||||
|
|
||||||
if (i + 1 < 14) {
|
|
||||||
assertTrue("heap should not be empty before all elements are removed", !heap.isEmpty());
|
|
||||||
} else {
|
|
||||||
assertTrue("heap should be empty after all elements are removed", heap.isEmpty());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
heap.get();
|
|
||||||
fail("NoSuchElementException should be thrown if get is called after all elements are removed");
|
|
||||||
} catch (final BufferUnderflowException ex) {}
|
|
||||||
|
|
||||||
try {
|
|
||||||
heap.remove();
|
|
||||||
fail("NoSuchElementException should be thrown if remove is called after all elements are removed");
|
|
||||||
} catch (final BufferUnderflowException ex) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testBasicComparatorOps() {
|
|
||||||
final PriorityBuffer<E> heap = new PriorityBuffer<E>(new ReverseComparator<E>((Comparator<E>) ComparableComparator.INSTANCE));
|
|
||||||
|
|
||||||
assertTrue("heap should be empty after create", heap.isEmpty());
|
|
||||||
|
|
||||||
try {
|
|
||||||
heap.get();
|
|
||||||
fail("NoSuchElementException should be thrown if get is called before any elements are added");
|
|
||||||
} catch (final BufferUnderflowException ex) {}
|
|
||||||
|
|
||||||
try {
|
|
||||||
heap.remove();
|
|
||||||
fail("NoSuchElementException should be thrown if remove is called before any elements are added");
|
|
||||||
} catch (final BufferUnderflowException ex) {}
|
|
||||||
|
|
||||||
heap.add((E) "a");
|
|
||||||
heap.add((E) "c");
|
|
||||||
heap.add((E) "e");
|
|
||||||
heap.add((E) "b");
|
|
||||||
heap.add((E) "d");
|
|
||||||
heap.add((E) "n");
|
|
||||||
heap.add((E) "m");
|
|
||||||
heap.add((E) "l");
|
|
||||||
heap.add((E) "k");
|
|
||||||
heap.add((E) "j");
|
|
||||||
heap.add((E) "i");
|
|
||||||
heap.add((E) "h");
|
|
||||||
heap.add((E) "g");
|
|
||||||
heap.add((E) "f");
|
|
||||||
|
|
||||||
assertTrue("heap should not be empty after adds", !heap.isEmpty());
|
|
||||||
|
|
||||||
for (int i = 0; i < 14; i++) {
|
|
||||||
|
|
||||||
// note: since we're using a comparator that reverses items, the
|
|
||||||
// "minimum" item is "n", and the "maximum" item is "a".
|
|
||||||
|
|
||||||
assertEquals(
|
|
||||||
"get using default constructor should return minimum value in the binary heap",
|
|
||||||
String.valueOf((char) ('n' - i)),
|
|
||||||
heap.get());
|
|
||||||
|
|
||||||
assertEquals(
|
|
||||||
"remove using default constructor should return minimum value in the binary heap",
|
|
||||||
String.valueOf((char) ('n' - i)),
|
|
||||||
heap.remove());
|
|
||||||
|
|
||||||
if (i + 1 < 14) {
|
|
||||||
assertTrue("heap should not be empty before all elements are removed", !heap.isEmpty());
|
|
||||||
} else {
|
|
||||||
assertTrue("heap should be empty after all elements are removed", heap.isEmpty());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
heap.get();
|
|
||||||
fail("NoSuchElementException should be thrown if get is called after all elements are removed");
|
|
||||||
} catch (final BufferUnderflowException ex) {}
|
|
||||||
|
|
||||||
try {
|
|
||||||
heap.remove();
|
|
||||||
fail("NoSuchElementException should be thrown if remove is called after all elements are removed");
|
|
||||||
} catch (final BufferUnderflowException ex) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Illustrates bad internal heap state reported in Bugzilla PR #235818.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testAddRemove() {
|
|
||||||
resetEmpty();
|
|
||||||
final PriorityBuffer heap = getCollection();
|
|
||||||
heap.add(0);
|
|
||||||
heap.add(2);
|
|
||||||
heap.add(4);
|
|
||||||
heap.add(3);
|
|
||||||
heap.add(8);
|
|
||||||
heap.add(10);
|
|
||||||
heap.add(12);
|
|
||||||
heap.add(3);
|
|
||||||
getConfirmed().addAll(heap);
|
|
||||||
// System.out.println(heap);
|
|
||||||
heap.remove(10);
|
|
||||||
getConfirmed().remove(10);
|
|
||||||
// System.out.println(heap);
|
|
||||||
verify();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate heaps staring with Integers from 0 - heapSize - 1.
|
|
||||||
* Then perform random add / remove operations, checking
|
|
||||||
* heap order after modifications. Alternates minHeaps, maxHeaps.
|
|
||||||
*
|
|
||||||
* Based on code provided by Steve Phelps in PR #25818
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void testRandom() {
|
|
||||||
final int iterations = 500;
|
|
||||||
final int heapSize = 100;
|
|
||||||
final int operations = 20;
|
|
||||||
final Random randGenerator = new Random();
|
|
||||||
PriorityBuffer<Integer> h = null;
|
|
||||||
for (int i = 0; i < iterations; i++) {
|
|
||||||
if (i < iterations / 2) {
|
|
||||||
h = new PriorityBuffer<Integer>(true);
|
|
||||||
} else {
|
|
||||||
h = new PriorityBuffer<Integer>(false);
|
|
||||||
}
|
|
||||||
for (int r = 0; r < heapSize; r++) {
|
|
||||||
h.add(randGenerator.nextInt(heapSize));
|
|
||||||
}
|
|
||||||
for (int r = 0; r < operations; r++) {
|
|
||||||
h.remove(new Integer(r));
|
|
||||||
h.add(randGenerator.nextInt(heapSize));
|
|
||||||
}
|
|
||||||
checkOrder(h);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pops all elements from the heap and verifies that the elements come off
|
|
||||||
* in the correct order. NOTE: this method empties the heap.
|
|
||||||
*/
|
|
||||||
protected void checkOrder(final PriorityBuffer<?> h) {
|
|
||||||
Integer lastNum = null;
|
|
||||||
Integer num = null;
|
|
||||||
while (!h.isEmpty()) {
|
|
||||||
num = (Integer) h.remove();
|
|
||||||
if (h.ascendingOrder) {
|
|
||||||
assertTrue(lastNum == null || num.intValue() >= lastNum.intValue());
|
|
||||||
} else { // max heap
|
|
||||||
assertTrue(lastNum == null || num.intValue() <= lastNum.intValue());
|
|
||||||
}
|
|
||||||
lastNum = num;
|
|
||||||
num = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a string showing the contents of the heap formatted as a tree.
|
|
||||||
* Makes no attempt at padding levels or handling wrapping.
|
|
||||||
*/
|
|
||||||
protected String showTree(final PriorityBuffer<?> h) {
|
|
||||||
int count = 1;
|
|
||||||
final StringBuilder buffer = new StringBuilder();
|
|
||||||
for (int offset = 1; count < h.size() + 1; offset *= 2) {
|
|
||||||
for (int i = offset; i < offset * 2; i++) {
|
|
||||||
if (i < h.elements.length && h.elements[i] != null) {
|
|
||||||
buffer.append(h.elements[i] + " ");
|
|
||||||
}
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
buffer.append('\n');
|
|
||||||
}
|
|
||||||
return buffer.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates 500 randomly initialized heaps of size 100
|
|
||||||
* and tests that after serializing and restoring them to a byte array
|
|
||||||
* that the following conditions hold:
|
|
||||||
*
|
|
||||||
* - the size of the restored heap is the same
|
|
||||||
* as the size of the orignal heap
|
|
||||||
*
|
|
||||||
* - all elements in the original heap are present in the restored heap
|
|
||||||
*
|
|
||||||
* - the heap order of the restored heap is intact as
|
|
||||||
* verified by checkOrder()
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testSerialization() {
|
|
||||||
final int iterations = 500;
|
|
||||||
final int heapSize = 100;
|
|
||||||
PriorityBuffer h;
|
|
||||||
final Random randGenerator = new Random();
|
|
||||||
for (int i = 0; i < iterations; i++) {
|
|
||||||
if (i < iterations / 2) {
|
|
||||||
h = new PriorityBuffer<E>(true);
|
|
||||||
} else {
|
|
||||||
h = new PriorityBuffer<E>(false);
|
|
||||||
}
|
|
||||||
for (int r = 0; r < heapSize; r++) {
|
|
||||||
h.add(new Integer(randGenerator.nextInt(heapSize)));
|
|
||||||
}
|
|
||||||
assertTrue(h.size() == heapSize);
|
|
||||||
final PriorityBuffer<?> h1 = serializeAndRestore(h);
|
|
||||||
assertTrue(h1.size() == heapSize);
|
|
||||||
final Iterator<?> hit = h.iterator();
|
|
||||||
while (hit.hasNext()) {
|
|
||||||
final Integer n = (Integer) hit.next();
|
|
||||||
assertTrue(h1.contains(n));
|
|
||||||
}
|
|
||||||
checkOrder(h1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public PriorityBuffer<?> serializeAndRestore(final PriorityBuffer<E> h) {
|
|
||||||
PriorityBuffer<?> h1 = null;
|
|
||||||
try {
|
|
||||||
final byte[] objekt = writeExternalFormToBytes(h);
|
|
||||||
h1 = (PriorityBuffer<?>) readExternalFormFromBytes(objekt);
|
|
||||||
} catch (final IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
fail(e.toString());
|
|
||||||
} catch (final ClassNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
fail(e.toString());
|
|
||||||
}
|
|
||||||
return h1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getCompatibilityVersion() {
|
|
||||||
return "3.2";
|
|
||||||
}
|
|
||||||
|
|
||||||
// public void testCreate() throws Exception {
|
|
||||||
// resetEmpty();
|
|
||||||
// writeExternalFormToDisk((java.io.Serializable) collection, "C:/commons/collections/data/test/PriorityBuffer.emptyCollection.version3.2.obj");
|
|
||||||
// resetFull();
|
|
||||||
// writeExternalFormToDisk((java.io.Serializable) collection, "C:/commons/collections/data/test/PriorityBuffer.fullCollection.version3.2.obj");
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public PriorityBuffer<E> getCollection() {
|
|
||||||
return (PriorityBuffer<E>) super.getCollection();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,81 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections.buffer;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
import org.apache.commons.collections.ArrayStack;
|
|
||||||
import org.apache.commons.collections.Buffer;
|
|
||||||
import org.apache.commons.collections.collection.AbstractCollectionTest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extension of {@link AbstractCollectionTest} for exercising the
|
|
||||||
* {@link SynchronizedBuffer} implementation.
|
|
||||||
*
|
|
||||||
* @since 3.1
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public class SynchronizedBufferTest<E> extends AbstractCollectionTest<E> {
|
|
||||||
|
|
||||||
public SynchronizedBufferTest(final String testName) {
|
|
||||||
super(testName);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
@Override
|
|
||||||
public Buffer<E> makeObject() {
|
|
||||||
return SynchronizedBuffer.synchronizedBuffer(new UnboundedFifoBuffer<E>());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<E> makeFullCollection() {
|
|
||||||
final Buffer<E> buffer = new UnboundedFifoBuffer<E>();
|
|
||||||
buffer.addAll(Arrays.asList(getFullElements()));
|
|
||||||
return SynchronizedBuffer.synchronizedBuffer(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<E> makeConfirmedCollection() {
|
|
||||||
return new ArrayStack<E>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<E> makeConfirmedFullCollection() {
|
|
||||||
final ArrayStack<E> list = new ArrayStack<E>();
|
|
||||||
list.addAll(Arrays.asList(getFullElements()));
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isNullSupported() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getCompatibilityVersion() {
|
|
||||||
return "3.1";
|
|
||||||
}
|
|
||||||
|
|
||||||
// public void testCreate() throws Exception {
|
|
||||||
// resetEmpty();
|
|
||||||
// writeExternalFormToDisk((java.io.Serializable) collection, "D:/dev/collections/data/test/SynchronizedBuffer.emptyCollection.version3.1.obj");
|
|
||||||
// resetFull();
|
|
||||||
// writeExternalFormToDisk((java.io.Serializable) collection, "D:/dev/collections/data/test/SynchronizedBuffer.fullCollection.version3.1.obj");
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,72 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections.buffer;
|
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
|
||||||
import org.apache.commons.collections.Buffer;
|
|
||||||
import org.apache.commons.collections.collection.TransformedCollectionTest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extension of {@link TestCase} for exercising the {@link TransformedBuffer}
|
|
||||||
* implementation.
|
|
||||||
*
|
|
||||||
* @since 3.0
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public class TransformedBufferTest extends TestCase {
|
|
||||||
|
|
||||||
public TransformedBufferTest(final String testName) {
|
|
||||||
super(testName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testTransformedBuffer() {
|
|
||||||
final Buffer<Object> buffer = TransformedBuffer.transformingBuffer(new CircularFifoBuffer<Object>(), TransformedCollectionTest.STRING_TO_INTEGER_TRANSFORMER);
|
|
||||||
assertEquals(0, buffer.size());
|
|
||||||
final Object[] els = new Object[] { "1", "3", "5", "7", "2", "4", "6" };
|
|
||||||
for (int i = 0; i < els.length; i++) {
|
|
||||||
buffer.add(els[i]);
|
|
||||||
assertEquals(i + 1, buffer.size());
|
|
||||||
assertEquals(true, buffer.contains(new Integer((String) els[i])));
|
|
||||||
assertEquals(false, buffer.contains(els[i]));
|
|
||||||
}
|
|
||||||
|
|
||||||
assertEquals(false, buffer.remove(els[0]));
|
|
||||||
assertEquals(true, buffer.remove(new Integer((String) els[0])));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testTransformedBuffer_decorateTransform() {
|
|
||||||
final Buffer originalBuffer = new CircularFifoBuffer();
|
|
||||||
final Object[] els = new Object[] {"1", "3", "5", "7", "2", "4", "6"};
|
|
||||||
for (final Object el : els) {
|
|
||||||
originalBuffer.add(el);
|
|
||||||
}
|
|
||||||
final Buffer<?> buffer = TransformedBuffer.transformedBuffer(originalBuffer, TransformedCollectionTest.STRING_TO_INTEGER_TRANSFORMER);
|
|
||||||
assertEquals(els.length, buffer.size());
|
|
||||||
for (final Object el : els) {
|
|
||||||
assertEquals(true, buffer.contains(new Integer((String) el)));
|
|
||||||
assertEquals(false, buffer.contains(el));
|
|
||||||
}
|
|
||||||
|
|
||||||
assertEquals(false, buffer.remove(els[0]));
|
|
||||||
assertEquals(true, buffer.remove(new Integer((String) els[0])));
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCompatibilityVersion() {
|
|
||||||
return "3.1";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,472 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections.buffer;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import junit.framework.Test;
|
|
||||||
|
|
||||||
import org.apache.commons.collections.BulkTest;
|
|
||||||
import org.apache.commons.collections.collection.AbstractCollectionTest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test cases for UnboundedFifoBuffer.
|
|
||||||
*
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public class UnboundedFifoBufferTest<E> extends AbstractCollectionTest<E> {
|
|
||||||
|
|
||||||
public UnboundedFifoBufferTest(final String n) {
|
|
||||||
super(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Test suite() {
|
|
||||||
return BulkTest.makeSuite(UnboundedFifoBufferTest.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Verifies that the ArrayList has the same elements in the same
|
|
||||||
* sequence as the UnboundedFifoBuffer.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void verify() {
|
|
||||||
super.verify();
|
|
||||||
final Iterator<E> iterator1 = getCollection().iterator();
|
|
||||||
final Iterator<E> iterator2 = getConfirmed().iterator();
|
|
||||||
while (iterator2.hasNext()) {
|
|
||||||
assertTrue(iterator1.hasNext());
|
|
||||||
final Object o1 = iterator1.next();
|
|
||||||
final Object o2 = iterator2.next();
|
|
||||||
assertEquals(o1, o2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Overridden because UnboundedFifoBuffer doesn't allow null elements.
|
|
||||||
* @return false
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean isNullSupported() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overridden because UnboundedFifoBuffer isn't fail fast.
|
|
||||||
* @return false
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public boolean isFailFastSupported() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Returns an empty ArrayList.
|
|
||||||
*
|
|
||||||
* @return an empty ArrayList
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Collection<E> makeConfirmedCollection() {
|
|
||||||
return new ArrayList<E>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a full ArrayList.
|
|
||||||
*
|
|
||||||
* @return a full ArrayList
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Collection<E> makeConfirmedFullCollection() {
|
|
||||||
final Collection<E> c = makeConfirmedCollection();
|
|
||||||
c.addAll(java.util.Arrays.asList(getFullElements()));
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an empty UnboundedFifoBuffer with a small capacity.
|
|
||||||
*
|
|
||||||
* @return an empty UnboundedFifoBuffer
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Collection<E> makeObject() {
|
|
||||||
return new UnboundedFifoBuffer<E>(5);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
/**
|
|
||||||
* Tests that UnboundedFifoBuffer removes elements in the right order.
|
|
||||||
*/
|
|
||||||
public void testUnboundedFifoBufferRemove() {
|
|
||||||
resetFull();
|
|
||||||
final int size = getConfirmed().size();
|
|
||||||
for (int i = 0; i < size; i++) {
|
|
||||||
final E o1 = getCollection().remove();
|
|
||||||
final E o2 = getConfirmed().remove(0);
|
|
||||||
assertEquals("Removed objects should be equal", o1, o2);
|
|
||||||
verify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests that the constructor correctly throws an exception.
|
|
||||||
*/
|
|
||||||
public void testConstructorException1() {
|
|
||||||
try {
|
|
||||||
new UnboundedFifoBuffer<E>(0);
|
|
||||||
} catch (final IllegalArgumentException ex) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tests that the constructor correctly throws an exception.
|
|
||||||
*/
|
|
||||||
public void testConstructorException2() {
|
|
||||||
try {
|
|
||||||
new UnboundedFifoBuffer<E>(-20);
|
|
||||||
} catch (final IllegalArgumentException ex) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fail();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testInternalStateAdd() {
|
|
||||||
final UnboundedFifoBuffer<E> test = new UnboundedFifoBuffer<E>(2);
|
|
||||||
assertEquals(3, test.buffer.length);
|
|
||||||
assertEquals(0, test.head);
|
|
||||||
assertEquals(0, test.tail);
|
|
||||||
test.add((E) "A");
|
|
||||||
assertEquals(3, test.buffer.length);
|
|
||||||
assertEquals(0, test.head);
|
|
||||||
assertEquals(1, test.tail);
|
|
||||||
test.add((E) "B");
|
|
||||||
assertEquals(3, test.buffer.length);
|
|
||||||
assertEquals(0, test.head);
|
|
||||||
assertEquals(2, test.tail);
|
|
||||||
test.add((E) "C"); // forces buffer increase
|
|
||||||
assertEquals(5, test.buffer.length);
|
|
||||||
assertEquals(0, test.head);
|
|
||||||
assertEquals(3, test.tail);
|
|
||||||
test.add((E) "D");
|
|
||||||
assertEquals(5, test.buffer.length);
|
|
||||||
assertEquals(0, test.head);
|
|
||||||
assertEquals(4, test.tail);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testInternalStateAddWithWrap() {
|
|
||||||
final UnboundedFifoBuffer<E> test = new UnboundedFifoBuffer<E>(3);
|
|
||||||
assertEquals(4, test.buffer.length);
|
|
||||||
assertEquals(0, test.head);
|
|
||||||
assertEquals(0, test.tail);
|
|
||||||
test.add((E) "A");
|
|
||||||
assertEquals(4, test.buffer.length);
|
|
||||||
assertEquals(0, test.head);
|
|
||||||
assertEquals(1, test.tail);
|
|
||||||
test.add((E) "B");
|
|
||||||
assertEquals(4, test.buffer.length);
|
|
||||||
assertEquals(0, test.head);
|
|
||||||
assertEquals(2, test.tail);
|
|
||||||
test.add((E) "C");
|
|
||||||
assertEquals(4, test.buffer.length);
|
|
||||||
assertEquals(0, test.head);
|
|
||||||
assertEquals(3, test.tail);
|
|
||||||
test.remove("A");
|
|
||||||
assertEquals(4, test.buffer.length);
|
|
||||||
assertEquals(1, test.head);
|
|
||||||
assertEquals(3, test.tail);
|
|
||||||
test.remove("B");
|
|
||||||
assertEquals(4, test.buffer.length);
|
|
||||||
assertEquals(2, test.head);
|
|
||||||
assertEquals(3, test.tail);
|
|
||||||
test.add((E) "D");
|
|
||||||
assertEquals(4, test.buffer.length);
|
|
||||||
assertEquals(2, test.head);
|
|
||||||
assertEquals(0, test.tail);
|
|
||||||
test.add((E) "E");
|
|
||||||
assertEquals(4, test.buffer.length);
|
|
||||||
assertEquals(2, test.head);
|
|
||||||
assertEquals(1, test.tail);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testInternalStateRemove1() {
|
|
||||||
final UnboundedFifoBuffer<E> test = new UnboundedFifoBuffer<E>(4);
|
|
||||||
test.add((E) "A");
|
|
||||||
test.add((E) "B");
|
|
||||||
test.add((E) "C");
|
|
||||||
assertEquals(5, test.buffer.length);
|
|
||||||
assertEquals(0, test.head);
|
|
||||||
assertEquals(3, test.tail);
|
|
||||||
|
|
||||||
test.remove("A");
|
|
||||||
assertEquals(5, test.buffer.length);
|
|
||||||
assertEquals(1, test.head);
|
|
||||||
assertEquals(3, test.tail);
|
|
||||||
|
|
||||||
test.add((E) "D");
|
|
||||||
assertEquals(5, test.buffer.length);
|
|
||||||
assertEquals(1, test.head);
|
|
||||||
assertEquals(4, test.tail);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testInternalStateRemove2() {
|
|
||||||
final UnboundedFifoBuffer<E> test = new UnboundedFifoBuffer<E>(4);
|
|
||||||
test.add((E) "A");
|
|
||||||
test.add((E) "B");
|
|
||||||
test.add((E) "C");
|
|
||||||
assertEquals(5, test.buffer.length);
|
|
||||||
assertEquals(0, test.head);
|
|
||||||
assertEquals(3, test.tail);
|
|
||||||
|
|
||||||
test.remove("B");
|
|
||||||
assertEquals(5, test.buffer.length);
|
|
||||||
assertEquals(0, test.head);
|
|
||||||
assertEquals(2, test.tail);
|
|
||||||
|
|
||||||
test.add((E) "D");
|
|
||||||
assertEquals(5, test.buffer.length);
|
|
||||||
assertEquals(0, test.head);
|
|
||||||
assertEquals(3, test.tail);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testInternalStateIteratorRemove1() {
|
|
||||||
final UnboundedFifoBuffer<E> test = new UnboundedFifoBuffer<E>(4);
|
|
||||||
test.add((E) "A");
|
|
||||||
test.add((E) "B");
|
|
||||||
test.add((E) "C");
|
|
||||||
assertEquals(5, test.buffer.length);
|
|
||||||
assertEquals(0, test.head);
|
|
||||||
assertEquals(3, test.tail);
|
|
||||||
|
|
||||||
final Iterator<E> it = test.iterator();
|
|
||||||
it.next();
|
|
||||||
it.remove();
|
|
||||||
assertEquals(5, test.buffer.length);
|
|
||||||
assertEquals(1, test.head);
|
|
||||||
assertEquals(3, test.tail);
|
|
||||||
|
|
||||||
test.add((E) "D");
|
|
||||||
assertEquals(5, test.buffer.length);
|
|
||||||
assertEquals(1, test.head);
|
|
||||||
assertEquals(4, test.tail);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testInternalStateIteratorRemove2() {
|
|
||||||
final UnboundedFifoBuffer<E> test = new UnboundedFifoBuffer<E>(4);
|
|
||||||
test.add((E) "A");
|
|
||||||
test.add((E) "B");
|
|
||||||
test.add((E) "C");
|
|
||||||
|
|
||||||
final Iterator<E> it = test.iterator();
|
|
||||||
it.next();
|
|
||||||
it.next();
|
|
||||||
it.remove();
|
|
||||||
assertEquals(5, test.buffer.length);
|
|
||||||
assertEquals(0, test.head);
|
|
||||||
assertEquals(2, test.tail);
|
|
||||||
|
|
||||||
test.add((E) "D");
|
|
||||||
assertEquals(5, test.buffer.length);
|
|
||||||
assertEquals(0, test.head);
|
|
||||||
assertEquals(3, test.tail);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testInternalStateIteratorRemoveWithTailAtEnd1() {
|
|
||||||
final UnboundedFifoBuffer<E> test = new UnboundedFifoBuffer<E>(3);
|
|
||||||
test.add((E) "A");
|
|
||||||
test.add((E) "B");
|
|
||||||
test.add((E) "C");
|
|
||||||
test.remove("A");
|
|
||||||
test.add((E) "D");
|
|
||||||
assertEquals(4, test.buffer.length);
|
|
||||||
assertEquals(1, test.head);
|
|
||||||
assertEquals(0, test.tail);
|
|
||||||
|
|
||||||
final Iterator<E> it = test.iterator();
|
|
||||||
assertEquals("B", it.next());
|
|
||||||
it.remove();
|
|
||||||
assertEquals(4, test.buffer.length);
|
|
||||||
assertEquals(2, test.head);
|
|
||||||
assertEquals(0, test.tail);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testInternalStateIteratorRemoveWithTailAtEnd2() {
|
|
||||||
final UnboundedFifoBuffer<E> test = new UnboundedFifoBuffer<E>(3);
|
|
||||||
test.add((E) "A");
|
|
||||||
test.add((E) "B");
|
|
||||||
test.add((E) "C");
|
|
||||||
test.remove("A");
|
|
||||||
test.add((E) "D");
|
|
||||||
assertEquals(4, test.buffer.length);
|
|
||||||
assertEquals(1, test.head);
|
|
||||||
assertEquals(0, test.tail);
|
|
||||||
|
|
||||||
final Iterator<E> it = test.iterator();
|
|
||||||
assertEquals("B", it.next());
|
|
||||||
assertEquals("C", it.next());
|
|
||||||
it.remove();
|
|
||||||
assertEquals(4, test.buffer.length);
|
|
||||||
assertEquals(1, test.head);
|
|
||||||
assertEquals(3, test.tail);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testInternalStateIteratorRemoveWithTailAtEnd3() {
|
|
||||||
final UnboundedFifoBuffer<E> test = new UnboundedFifoBuffer<E>(3);
|
|
||||||
test.add((E) "A");
|
|
||||||
test.add((E) "B");
|
|
||||||
test.add((E) "C");
|
|
||||||
test.remove("A");
|
|
||||||
test.add((E) "D");
|
|
||||||
assertEquals(4, test.buffer.length);
|
|
||||||
assertEquals(1, test.head);
|
|
||||||
assertEquals(0, test.tail);
|
|
||||||
|
|
||||||
final Iterator<E> it = test.iterator();
|
|
||||||
assertEquals("B", it.next());
|
|
||||||
assertEquals("C", it.next());
|
|
||||||
assertEquals("D", it.next());
|
|
||||||
it.remove();
|
|
||||||
assertEquals(4, test.buffer.length);
|
|
||||||
assertEquals(1, test.head);
|
|
||||||
assertEquals(3, test.tail);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testInternalStateIteratorRemoveWithWrap1() {
|
|
||||||
final UnboundedFifoBuffer<E> test = new UnboundedFifoBuffer<E>(3);
|
|
||||||
test.add((E) "A");
|
|
||||||
test.add((E) "B");
|
|
||||||
test.add((E) "C");
|
|
||||||
test.remove("A");
|
|
||||||
test.remove("B");
|
|
||||||
test.add((E) "D");
|
|
||||||
test.add((E) "E");
|
|
||||||
assertEquals(4, test.buffer.length);
|
|
||||||
assertEquals(2, test.head);
|
|
||||||
assertEquals(1, test.tail);
|
|
||||||
|
|
||||||
final Iterator<E> it = test.iterator();
|
|
||||||
assertEquals("C", it.next());
|
|
||||||
it.remove();
|
|
||||||
assertEquals(4, test.buffer.length);
|
|
||||||
assertEquals(3, test.head);
|
|
||||||
assertEquals(1, test.tail);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testInternalStateIteratorRemoveWithWrap2() {
|
|
||||||
final UnboundedFifoBuffer<E> test = new UnboundedFifoBuffer<E>(3);
|
|
||||||
test.add((E) "A");
|
|
||||||
test.add((E) "B");
|
|
||||||
test.add((E) "C");
|
|
||||||
test.remove("A");
|
|
||||||
test.remove("B");
|
|
||||||
test.add((E) "D");
|
|
||||||
test.add((E) "E");
|
|
||||||
assertEquals(4, test.buffer.length);
|
|
||||||
assertEquals(2, test.head);
|
|
||||||
assertEquals(1, test.tail);
|
|
||||||
|
|
||||||
final Iterator<E> it = test.iterator();
|
|
||||||
assertEquals("C", it.next());
|
|
||||||
assertEquals("D", it.next());
|
|
||||||
it.remove();
|
|
||||||
assertEquals(4, test.buffer.length);
|
|
||||||
assertEquals(2, test.head);
|
|
||||||
assertEquals(0, test.tail);
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testInternalStateIteratorRemoveWithWrap3() {
|
|
||||||
final UnboundedFifoBuffer<E> test = new UnboundedFifoBuffer<E>(3);
|
|
||||||
test.add((E) "A");
|
|
||||||
test.add((E) "B");
|
|
||||||
test.add((E) "C");
|
|
||||||
test.remove("A");
|
|
||||||
test.remove("B");
|
|
||||||
test.add((E) "D");
|
|
||||||
test.add((E) "E");
|
|
||||||
assertEquals(4, test.buffer.length);
|
|
||||||
assertEquals(2, test.head);
|
|
||||||
assertEquals(1, test.tail);
|
|
||||||
|
|
||||||
final Iterator<E> it = test.iterator();
|
|
||||||
assertEquals("C", it.next());
|
|
||||||
assertEquals("D", it.next());
|
|
||||||
assertEquals("E", it.next());
|
|
||||||
it.remove();
|
|
||||||
assertEquals(4, test.buffer.length);
|
|
||||||
assertEquals(2, test.head);
|
|
||||||
assertEquals(0, test.tail);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void testCollections220() throws Exception {
|
|
||||||
UnboundedFifoBuffer<String> buffer = new UnboundedFifoBuffer<String>();
|
|
||||||
|
|
||||||
buffer = (UnboundedFifoBuffer<String>) serializeDeserialize(buffer);
|
|
||||||
|
|
||||||
// test size() gets incremented
|
|
||||||
buffer.add("Foo");
|
|
||||||
assertEquals(1, buffer.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
@Override
|
|
||||||
public String getCompatibilityVersion() {
|
|
||||||
return "3.1";
|
|
||||||
}
|
|
||||||
|
|
||||||
// public void testCreate() throws Exception {
|
|
||||||
// resetEmpty();
|
|
||||||
// writeExternalFormToDisk((java.io.Serializable) collection, "D:/dev/collections/data/test/UnboundedFifoBuffer.emptyCollection.version3.1.obj");
|
|
||||||
// resetFull();
|
|
||||||
// writeExternalFormToDisk((java.io.Serializable) collection, "D:/dev/collections/data/test/UnboundedFifoBuffer.fullCollection.version3.1.obj");
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public UnboundedFifoBuffer<E> getCollection() {
|
|
||||||
return (UnboundedFifoBuffer<E>) super.getCollection();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public List<E> getConfirmed() {
|
|
||||||
return (List<E>) super.getConfirmed();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,106 +0,0 @@
|
||||||
/*
|
|
||||||
* 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.commons.collections.buffer;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
import org.apache.commons.collections.ArrayStack;
|
|
||||||
import org.apache.commons.collections.Buffer;
|
|
||||||
import org.apache.commons.collections.collection.AbstractCollectionTest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extension of {@link AbstractCollectionTest} for exercising the
|
|
||||||
* {@link UnmodifiableBuffer} implementation.
|
|
||||||
*
|
|
||||||
* @since 3.1
|
|
||||||
* @version $Id$
|
|
||||||
*/
|
|
||||||
public class UnmodifiableBufferTest<E> extends AbstractCollectionTest<E> {
|
|
||||||
|
|
||||||
public UnmodifiableBufferTest(final String testName) {
|
|
||||||
super(testName);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
|
||||||
@Override
|
|
||||||
public Collection<E> makeObject() {
|
|
||||||
return UnmodifiableBuffer.unmodifiableBuffer(new UnboundedFifoBuffer<E>());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<E> makeFullCollection() {
|
|
||||||
final Buffer<E> buffer = new UnboundedFifoBuffer<E>();
|
|
||||||
buffer.addAll(Arrays.asList(getFullElements()));
|
|
||||||
return UnmodifiableBuffer.unmodifiableBuffer(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<E> makeConfirmedCollection() {
|
|
||||||
return new ArrayStack<E>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<E> makeConfirmedFullCollection() {
|
|
||||||
final ArrayStack<E> list = new ArrayStack<E>();
|
|
||||||
list.addAll(Arrays.asList(getFullElements()));
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAddSupported() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isRemoveSupported() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isNullSupported() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void testBufferRemove() {
|
|
||||||
resetEmpty();
|
|
||||||
try {
|
|
||||||
getCollection().remove();
|
|
||||||
fail();
|
|
||||||
} catch (final UnsupportedOperationException ex) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getCompatibilityVersion() {
|
|
||||||
return "3.1";
|
|
||||||
}
|
|
||||||
|
|
||||||
// public void testCreate() throws Exception {
|
|
||||||
// resetEmpty();
|
|
||||||
// writeExternalFormToDisk((java.io.Serializable) collection, "D:/dev/collections/data/test/UnmodifiableBuffer.emptyCollection.version3.1.obj");
|
|
||||||
// resetFull();
|
|
||||||
// writeExternalFormToDisk((java.io.Serializable) collection, "D:/dev/collections/data/test/UnmodifiableBuffer.fullCollection.version3.1.obj");
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Buffer<E> getCollection() {
|
|
||||||
return (Buffer<E>) super.getCollection();
|
|
||||||
}
|
|
||||||
}
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue