gov.nasa.worldwind.util.CompoundVecBuffer Maven / Gradle / Ivy
The newest version!
/*
* Copyright (C) 2012 United States Government as represented by the Administrator of the
* National Aeronautics and Space Administration.
* All Rights Reserved.
*/
package gov.nasa.worldwind.util;
import gov.nasa.worldwind.geom.*;
import java.nio.IntBuffer;
import java.util.*;
/**
* CompoundVecBuffer defines an interface for storing and retrieving a collection of variable length {@link
* gov.nasa.worldwind.util.VecBuffer} objects. Each VecBuffer is retrieved via an index. The range of valid indices in a
* CompoundVecBuffer is [0, size() - 1], inclusive. Implementations of CompoundVecBuffer define how each VecBuffer is
* stored and retrieved according to its index.
*
* To retrieve a single VecBuffer given an index, invoke {@link #subBuffer(int)}. To retrieve a VecBuffer's size, in
* number of logical tuples, invoke {@link #subBufferSize(int)}.
*
* To create a new view of this CompoundVecBuffer from one or many VecBuffers, invoke one of the slice
* methods: - {@link #slice(int, int)} creates a view of this CompoundVecbufer given a contiguous sequence of
* VecBuffer indices.
- {@link #slice(int[], int, int)} creates a view of this CompoundVecBuffer given an array
* of VecBuffer indices.
*
* @author dcollins
* @version $Id: CompoundVecBuffer.java 1171 2013-02-11 21:45:02Z dcollins $
*/
public abstract class CompoundVecBuffer
{
protected static final int DEFAULT_INITIAL_CAPACITY = 16;
protected static final boolean ALLOCATE_DIRECT_BUFFERS = true;
protected int count;
protected int capacity;
protected IntBuffer offsets;
protected IntBuffer lengths;
/**
* Constructs a CompoundVecBuffer with the specified initial capacity.
*
* @param capacity the CompoundVecBuffer's initial capacity, in number of sub-buffers.
*
* @throws IllegalArgumentException if the capacity is less than 1.
*/
public CompoundVecBuffer(int capacity)
{
if (capacity < 1)
{
String message = Logging.getMessage("generic.CapacityIsInvalid", capacity);
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.capacity = capacity;
this.offsets = WWBufferUtil.newIntBuffer(capacity, ALLOCATE_DIRECT_BUFFERS);
this.lengths = WWBufferUtil.newIntBuffer(capacity, ALLOCATE_DIRECT_BUFFERS);
}
/** Constructs a CompoundVecBuffer with the default initial capacity. */
public CompoundVecBuffer()
{
this(DEFAULT_INITIAL_CAPACITY);
}
protected CompoundVecBuffer(CompoundVecBuffer that, int beginIndex, int endIndex)
{
int length = endIndex - beginIndex + 1;
this.count = length;
this.capacity = length;
this.offsets = WWBufferUtil.newIntBuffer(length, ALLOCATE_DIRECT_BUFFERS);
that.offsets.limit(endIndex + 1);
that.offsets.position(beginIndex);
this.offsets.put(that.offsets);
this.offsets.rewind();
that.offsets.clear();
this.lengths = WWBufferUtil.newIntBuffer(length, ALLOCATE_DIRECT_BUFFERS);
that.lengths.limit(endIndex + 1);
that.lengths.position(beginIndex);
this.lengths.put(that.lengths);
this.lengths.rewind();
that.lengths.clear();
}
protected CompoundVecBuffer(CompoundVecBuffer that, int[] indices, int offset, int length)
{
this.count = length;
this.capacity = length;
this.offsets = WWBufferUtil.newIntBuffer(length, ALLOCATE_DIRECT_BUFFERS);
this.lengths = WWBufferUtil.newIntBuffer(length, ALLOCATE_DIRECT_BUFFERS);
for (int i = offset; i < offset + length; i++)
{
this.offsets.put(that.offsets.get(indices[i]));
this.lengths.put(that.lengths.get(indices[i]));
}
this.offsets.rewind();
this.lengths.rewind();
}
/**
* Returns an empty CompoundVecBuffer. The returned CompoundVecBuffer has a size of zero and contains no
* sub-buffers.
*
* @param coordsPerVec the number of coordinates per logical vector.
*
* @return the empty CompoundVecBuffer.
*/
public static CompoundVecBuffer emptyCompoundVecBuffer(int coordsPerVec)
{
if (coordsPerVec < 1)
{
String message = Logging.getMessage("generic.ArgumentOutOfRange", coordsPerVec);
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
return new EmptyCompoundVecBuffer(coordsPerVec);
}
/**
* Returns the number of VecBuffers stored in this CompoundVecBuffer.
*
* @return the number of VecBuffers in this CompoundVecBuffer.
*/
public int size()
{
return this.count;
}
/**
* Returns the size in logical vectors of the VecBuffer with the specified index.
*
* @param index the index for the VecBuffer who's size is returned.
*
* @return the size of the specified VecBuffer.
*
* @throws IllegalArgumentException if the index is out of range.
*/
public abstract int subBufferSize(int index);
/**
* Returns the sub-buffer at the specified index as a {@link gov.nasa.worldwind.util.VecBuffer}.
*
* @param index the index of the VecBuffer to return.
*
* @return the VecBuffer at the specified index.
*
* @throws IllegalArgumentException if the index is out of range.
*/
public VecBuffer subBuffer(int index)
{
if (index < 0 || index >= this.count)
{
String message = Logging.getMessage("generic.indexOutOfRange", index);
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
int off = this.offsets.get(index);
int len = this.lengths.get(index);
if (len > 0)
{
return this.createSubBuffer(off, len);
}
else
{
return VecBuffer.emptyVecBuffer(this.getCoordsPerVec());
}
}
/**
* Returns a new logical view of this CompoundVecBuffer. The returned buffer has length endIndex - beginIndex
* + 1
and references this buffer's contents starting at beginIndex
, and ending at
* endIndex
. The returned buffer shares this buffers's backing data. Changes to this buffer are
* reflected in the returned buffer, and vice versa.
*
* @param beginIndex the index of the first sub-buffer to include in the subset.
* @param endIndex the index of the last sub-buffer to include in the subset.
*
* @return a new CompoundVecBuffer representing a subset of this CompoundVecBuffer.
*
* @throws IllegalArgumentException if beginIndex is out of range, if endIndex is out of range, or if beginIndex >
* endIndex.
*/
public CompoundVecBuffer slice(int beginIndex, int endIndex)
{
if (beginIndex < 0 || beginIndex >= this.count)
{
String message = Logging.getMessage("generic.indexOutOfRange", beginIndex);
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (endIndex < 0 || endIndex >= this.count)
{
String message = Logging.getMessage("generic.indexOutOfRange", endIndex);
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (beginIndex > endIndex)
{
String message = Logging.getMessage("generic.indexOutOfRange", beginIndex);
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
return this.createSlice(beginIndex, endIndex);
}
/**
* Returns a new logical view of this CompoundVecBuffer. The returned buffer's length is equal to the specified
* length
, and contains this buffer's contents for each index in indices
. The returned
* buffer shares this buffers's backing data. Changes to this buffer are reflected in the returned buffer, and vice
* versa.
*
* @param indices an array containing the indices include in the subset.
* @param offset the array starting index.
* @param length the number of array values to use.
*
* @return a new CompoundVecBuffer representing a subset of this CompoundVecBuffer.
*
* @throws IllegalArgumentException if the array of indices is null, if the offset or length are invalid, or if any
* of the indices is out of range.
*/
public CompoundVecBuffer slice(int[] indices, int offset, int length)
{
if (indices == null)
{
String message = Logging.getMessage("nullValue.ArrayIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (length < 0 || length > indices.length)
{
String message = Logging.getMessage("generic.LengthIsInvalid", length);
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (offset < 0 || offset + length > indices.length)
{
String message = Logging.getMessage("generic.OffsetIsInvalid", offset);
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
for (int i = offset; i < offset + length; i++)
{
if (indices[i] < 0 || indices[i] >= this.count)
{
String message = Logging.getMessage("generic.indexOutOfRange", indices[i]);
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
}
return this.createSlice(indices, offset, length);
}
/**
* Returns a new logical view of this CompoundVecBuffer. The returned buffer's length is equal to the length of
* indices
, and contains this buffer's contents for each index in indices
. The returned
* buffer shares this buffers's backing data. Changes to this buffer are reflected in the returned buffer, and vice
* versa.
*
* @param indices an array containing the indices include in the subset.
*
* @return a new CompoundVecBuffer representing a subset of this CompoundVecBuffer.
*
* @throws IllegalArgumentException if the array of indices is null, or if any of the indices is out of range.
*/
public CompoundVecBuffer slice(int[] indices)
{
if (indices == null)
{
String message = Logging.getMessage("nullValue.ArrayIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
return this.slice(indices, 0, indices.length);
}
/** Sets the number sub-buffers to zero. This does not free any memory associated with this CompoundVecBuffer. */
public void clear()
{
this.count = 0;
}
/**
* Returns the number of coordinates per logical vector element.
*
* @return the cardinality of a logical vector element.
*/
public abstract int getCoordsPerVec();
//**************************************************************//
//******************** Protected Interface *******************//
//**************************************************************//
protected abstract VecBuffer createSubBuffer(int offset, int length);
protected abstract CompoundVecBuffer createSlice(int[] indices, int offset, int length);
protected abstract CompoundVecBuffer createSlice(int beginIndex, int endIndex);
protected int addSubBuffer(int offset, int length)
{
int minCount = 1 + this.count;
if (minCount > this.capacity)
this.expandCapacity(minCount);
int index = this.count;
this.offsets.put(index, offset);
this.lengths.put(index, length);
this.count++;
return index;
}
protected void expandCapacity(int minCapacity)
{
int newCapacity = 2 * this.capacity;
// If the new capacity overflows the range of 32-bit integers, then use the largest 32-bit integer.
if (newCapacity < 0)
{
newCapacity = Integer.MAX_VALUE;
}
// If the new capacity is still not large enough for the minimum capacity specified, then just use the minimum
// capacity specified.
else if (newCapacity < minCapacity)
{
newCapacity = minCapacity;
}
this.offsets = WWBufferUtil.copyOf(this.offsets, newCapacity);
this.lengths = WWBufferUtil.copyOf(this.lengths, newCapacity);
this.capacity = newCapacity;
}
//**************************************************************//
//******************** Iterable Methods **********************//
//**************************************************************//
/**
* Returns an iterator over this buffer's logical vectors, as double[] coordinate arrays. The array returned from
* each call to Iterator.next() will be newly allocated, and will have length equal to coordsPerVec.
*
* @return iterator over this buffer's vectors, as double[] arrays.
*/
public Iterable getCoords()
{
return this.getCoords(this.getCoordsPerVec());
}
/**
* Returns an iterator over this buffer's logical vectors, as double[] coordinate arrays. The array returned from a
* call to Iterator.next() will be newly allocated, and will have length equal to coordsPerVec or minCoordsPerVec,
* whichever is larger. If minCoordsPerVec is larger than coordsPerVec, then the elements in the returned array will
* after index "coordsPerVec - 1" will be undefined.
*
* @param minCoordsPerVec the minimum number of coordinates returned in each double[] array.
*
* @return iterator over this buffer's vectors, as double[] arrays.
*/
public Iterable getCoords(final int minCoordsPerVec)
{
return new Iterable()
{
public Iterator iterator()
{
return new CompoundIterator(new CoordIterable(minCoordsPerVec));
}
};
}
/**
* Returns a reverse iterator over this buffer's logical vectors, as double[] coordinate arrays. The array returned
* from a call to Iterator.next() will be newly allocated, and will have length equal to coordsPerVec or
* minCoordsPerVec, whichever is larger. If minCoordsPerVec is larger than coordsPerVec, then the elements in the
* returned array will after index "coordsPerVec - 1" will be undefined.
*
* @param minCoordsPerVec the minimum number of coordinates returned in each double[] array.
*
* @return reverse iterator over this buffer's vectors, as double[] arrays.
*/
public Iterable getReverseCoords(final int minCoordsPerVec)
{
return new Iterable()
{
public Iterator iterator()
{
return new ReverseCompoundIterator(new CoordIterable(minCoordsPerVec));
}
};
}
/**
* Returns an iterator over this buffer's logical vectors, as Vec4 references.
*
* @return iterator over this buffer's vectors, as Vec4 references.
*/
public Iterable extends Vec4> getVectors()
{
return new Iterable()
{
public Iterator iterator()
{
return new CompoundIterator(new VectorIterable());
}
};
}
/**
* Returns a reverse iterator over this buffer's logical vectors, as Vec4 references.
*
* @return reverse iterator over this buffer's vectors, as Vec4 references.
*/
public Iterable extends Vec4> getReverseVectors()
{
return new Iterable()
{
public Iterator iterator()
{
return new ReverseCompoundIterator(new VectorIterable());
}
};
}
/**
* Returns an iterator over this buffer's logical vectors, as LatLon locations.
*
* @return iterator over this buffer's vectors, as LatLon locations.
*/
public Iterable extends LatLon> getLocations()
{
return new Iterable()
{
public Iterator iterator()
{
return new CompoundIterator(new LocationIterable());
}
};
}
/**
* Returns a reverse iterator over this buffer's logical vectors, as LatLon locations.
*
* @return reverse iterator over this buffer's vectors, as LatLon locations.
*/
public Iterable extends LatLon> getReverseLocations()
{
return new Iterable()
{
public Iterator iterator()
{
return new ReverseCompoundIterator(new LocationIterable());
}
};
}
/**
* Returns an iterator over this buffer's logical vectors, as geographic Positions.
*
* @return iterator over this buffer's vectors, as geographic Positions.
*/
public Iterable extends Position> getPositions()
{
return new Iterable()
{
public Iterator iterator()
{
return new CompoundIterator(new PositionIterable());
}
};
}
/**
* Returns a reverse iterator over this buffer's logical vectors, as geographic Positions.
*
* @return reverse iterator over this buffer's vectors, as geographic Positions.
*/
public Iterable extends Position> getReversePositions()
{
return new Iterable()
{
public Iterator iterator()
{
return new ReverseCompoundIterator(new PositionIterable());
}
};
}
//**************************************************************//
//******************** Iterator Implementations **************//
//**************************************************************//
protected class CompoundIterator implements Iterator
{
protected int subBuffer;
protected Iterator subIterator;
protected final int subBufferCount;
protected final SubBufferIterable subBufferIterable;
protected CompoundIterator(SubBufferIterable subBufferIterable)
{
this.subBuffer = 0;
this.subBufferCount = size();
this.subBufferIterable = subBufferIterable;
}
public boolean hasNext()
{
this.updateSubIterator();
return this.subIterator != null && this.subIterator.hasNext();
}
public T next()
{
this.updateSubIterator();
if (this.subIterator != null && this.subIterator.hasNext())
{
return this.subIterator.next();
}
else
{
throw new NoSuchElementException();
}
}
public void remove()
{
throw new UnsupportedOperationException();
}
protected void updateSubIterator()
{
while (this.subBuffer < this.subBufferCount && (this.subIterator == null || !this.subIterator.hasNext()))
{
this.subIterator = this.subBufferIterable.iterator(this.subBuffer);
this.subBuffer++;
}
}
}
protected class ReverseCompoundIterator extends CompoundIterator
{
public ReverseCompoundIterator(SubBufferIterable subBufferIterable)
{
super(subBufferIterable);
this.subBuffer = this.subBufferCount - 1;
}
protected void updateSubIterator()
{
while (this.subBuffer >= 0 && (this.subIterator == null || !this.subIterator.hasNext()))
{
this.subIterator = this.subBufferIterable.reverseIterator(this.subBuffer);
this.subBuffer--;
}
}
}
protected interface SubBufferIterable
{
Iterator iterator(int index);
Iterator reverseIterator(int index);
}
protected class CoordIterable implements SubBufferIterable
{
private int minCoordsPerVec;
public CoordIterable(int minCoordsPerVec)
{
this.minCoordsPerVec = minCoordsPerVec;
}
public Iterator iterator(int index)
{
return subBuffer(index).getCoords(this.minCoordsPerVec).iterator();
}
public Iterator reverseIterator(int index)
{
return subBuffer(index).getReverseCoords(this.minCoordsPerVec).iterator();
}
}
protected class VectorIterable implements SubBufferIterable
{
public Iterator iterator(int index)
{
return subBuffer(index).getVectors().iterator();
}
public Iterator reverseIterator(int index)
{
return subBuffer(index).getReverseVectors().iterator();
}
}
protected class LocationIterable implements SubBufferIterable
{
public Iterator iterator(int index)
{
return subBuffer(index).getLocations().iterator();
}
public Iterator reverseIterator(int index)
{
return subBuffer(index).getReverseLocations().iterator();
}
}
protected class PositionIterable implements SubBufferIterable
{
public Iterator iterator(int index)
{
return subBuffer(index).getPositions().iterator();
}
public Iterator reverseIterator(int index)
{
return subBuffer(index).getReversePositions().iterator();
}
}
//**************************************************************//
//******************** Empty CompoundVecBuffer ***************//
//**************************************************************//
protected static class EmptyCompoundVecBuffer extends CompoundVecBuffer
{
protected int coordsPerVec;
public EmptyCompoundVecBuffer(int coordsPerVec)
{
super(1);
if (coordsPerVec < 1)
{
String message = Logging.getMessage("generic.ArgumentOutOfRange", coordsPerVec);
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.coordsPerVec = coordsPerVec;
}
protected EmptyCompoundVecBuffer(EmptyCompoundVecBuffer that, int beginIndex, int endIndex)
{
super(that, beginIndex, endIndex);
}
protected EmptyCompoundVecBuffer(EmptyCompoundVecBuffer that, int[] indices, int offset, int length)
{
super(that, indices, offset, length);
}
public int subBufferSize(int index)
{
if (index < 0 || index >= this.count)
{
String message = Logging.getMessage("generic.indexOutOfRange", index);
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
return 0;
}
public int getCoordsPerVec()
{
return this.coordsPerVec;
}
protected VecBuffer createSubBuffer(int offset, int length)
{
return VecBuffer.emptyVecBuffer(this.coordsPerVec);
}
protected CompoundVecBuffer createSlice(int[] indices, int offset, int length)
{
return new EmptyCompoundVecBuffer(this, indices, offset, length);
}
protected CompoundVecBuffer createSlice(int beginIndex, int endIndex)
{
return new EmptyCompoundVecBuffer(this, beginIndex, endIndex);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy