helper class. array-like random access and fast shift. good for sliding windows (e.g. keeping coverage over last 100 bases while sliding along the reference)
git-svn-id: file:///humgen/gsa-scr1/gsa-engineering/svn_contents/trunk@942 348d0f76-0448-11de-a6fe-93d51630548a
This commit is contained in:
parent
3d6e738a60
commit
13eb868536
|
|
@ -0,0 +1,206 @@
|
|||
package org.broadinstitute.sting.playground.utils;
|
||||
|
||||
|
||||
import org.broadinstitute.sting.utils.StingException;
|
||||
|
||||
/** This class, closely resembling a deque (except that it is not dynamically grown),
|
||||
* provides an object with array-like interface and efficient
|
||||
* implementation of shift operation. Use this class when some kind of sliding window is required:
|
||||
* e.g. an array (window) is populated from some stream of data, and then the window is shifted.
|
||||
* If most of the data in the window remains the same so that only a few old elements sjould be popped from
|
||||
* and a few new elements pushed onto the array, both re-populating the whole array from the data and
|
||||
* shifting a regular array would be grossly inefficient. Instead, shiftData(int N) method of circular array
|
||||
* efficiently pops out N first elements and makes last N elements available.
|
||||
*
|
||||
* Consider an example of reading a character stream A,B,C,D,....,Z into an array with requirement of keeping
|
||||
* last 5 letters. First, we would read first 5 letters same way as we would with a regular array:<br><br>
|
||||
*
|
||||
* <code>
|
||||
* CircularArray a(5);<br>
|
||||
* for ( int i = 0; i < 5; i++ ) a.set(i, readChar());<br>
|
||||
* </code>
|
||||
* <br>
|
||||
* and then on the arrival of each next character we shift the array:<br><br>
|
||||
*
|
||||
* <code>
|
||||
* a.shiftData(1); a.set(4, readChar() );<br>
|
||||
* </code>
|
||||
* <br>
|
||||
* After the lines from the above example are executed, the array will <i>logically</i> look as:<br>
|
||||
*
|
||||
* B,C,D,E,F,<br><br>
|
||||
*
|
||||
* e.g. as if we had a regular array, shifted it one element down and added new element on the top.
|
||||
*
|
||||
*
|
||||
* @author asivache
|
||||
*
|
||||
*/
|
||||
public class CircularArray <T> {
|
||||
|
||||
|
||||
private Object[] data ;
|
||||
private int offset;
|
||||
|
||||
/** Creates an array of fixed length */
|
||||
public CircularArray(int length) {
|
||||
if ( length <= 0 ) throw new StingException("CircularArray length must be positive. Passed: "+length);
|
||||
data = new Object[length];
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
/** Returns length of the array */
|
||||
public int length() {
|
||||
return data.length;
|
||||
}
|
||||
|
||||
/** Gets i-th element of the array
|
||||
*
|
||||
* @throws IndexOutOfBoundsException if value of i is illegal
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public T get(int i) {
|
||||
if ( i < 0 || i >= data.length )
|
||||
throw new IndexOutOfBoundsException("Length of CircularArray: "+data.length+"; element requested: "+i);
|
||||
return (T)(data [ ( offset + i ) % data.length ]);
|
||||
}
|
||||
|
||||
/** Sets i-th element of the array to the specified value.
|
||||
*
|
||||
* @throws IndexOutOfBoundsException if value of i is illegal
|
||||
*/
|
||||
public void set(int i, T value) {
|
||||
if ( i < 0 || i >= data.length )
|
||||
throw new IndexOutOfBoundsException("Length of CircularArray: "+data.length+"; set element request at: "+i);
|
||||
data [ ( offset + i ) % data.length ] = value;
|
||||
}
|
||||
|
||||
/** Set all elements to null.
|
||||
*
|
||||
*/
|
||||
public void clear() {
|
||||
for ( int i = 0 ; i < data.length ; i++ ) data[i] = null;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
/** Efficient shift-down of the array data. After this operation, array.get(0), array.get(1), etc will
|
||||
* be returning what array.get(shift), array.get(shift+1),... were returning before the shift was performed,
|
||||
* and last shift elements of the array will be reset to 0.
|
||||
* @param shift
|
||||
*/
|
||||
public void shiftData(int shift) {
|
||||
if ( shift >= data.length ) {
|
||||
// if we shift by more than the length of stored data, we lose
|
||||
// all that data completely, so we just re-initialize the array.
|
||||
// This is not the operating mode CircularArray is intended for
|
||||
// but we can handle it, just in case.
|
||||
for ( int i = 0 ; i < data.length ; i++ ) data[i] = null;
|
||||
offset = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// shift < data.length, so at least some data should be preserved
|
||||
|
||||
final int newOffset = ( offset+shift ) % data.length;
|
||||
if ( newOffset < offset ) {
|
||||
// wrap-around!
|
||||
for ( int i = offset ; i < data.length ; i++ ) data[i] = null;
|
||||
for ( int i = 0; i < newOffset ; i++ ) data[i] = null;
|
||||
} else {
|
||||
for ( int i = offset ; i < newOffset ; i++ ) data[i] = null;
|
||||
}
|
||||
offset = newOffset;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Implements primitive int type-based circular array. See CircularArray for details.
|
||||
*
|
||||
* @author asivache
|
||||
*
|
||||
*/
|
||||
public static class Int {
|
||||
private int [] data ;
|
||||
private int offset;
|
||||
|
||||
/** Creates an array of fixed length */
|
||||
public Int(int length) {
|
||||
if ( length <= 0 ) throw new StingException("CircularArray length must be positive. Passed: "+length);
|
||||
data = new int[length]; // automaticaly initialized to zeros
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
/** Returns length of the array */
|
||||
public int length() {
|
||||
return data.length;
|
||||
}
|
||||
|
||||
/** Gets i-th element of the array
|
||||
*
|
||||
* @throws IndexOutOfBoundsException if value of i is illegal
|
||||
*/
|
||||
public int get(int i) {
|
||||
if ( i < 0 || i >= data.length )
|
||||
throw new IndexOutOfBoundsException("Length of CircularArray: "+data.length+"; element requested: "+i);
|
||||
return data [ ( offset + i ) % data.length ];
|
||||
}
|
||||
|
||||
/** Sets i-th element of the array to the specified value.
|
||||
*
|
||||
* @throws IndexOutOfBoundsException if value of i is illegal
|
||||
*/
|
||||
public void set(int i, int value) {
|
||||
if ( i < 0 || i >= data.length )
|
||||
throw new IndexOutOfBoundsException("Length of CircularArray: "+data.length+"; set element request at: "+i);
|
||||
data [ ( offset + i ) % data.length ] = value;
|
||||
}
|
||||
|
||||
/** Increments i-th element of the array by the specified value (value can be negative).
|
||||
*
|
||||
* @throws IndexOutOfBoundsException if i is illegal
|
||||
*/
|
||||
public void increment(int i, int value) {
|
||||
if ( i < 0 || i >= data.length )
|
||||
throw new IndexOutOfBoundsException("Length of CircularArray: "+data.length+"; increment element request at: "+i);
|
||||
data [ ( offset + i ) % data.length ] += value;
|
||||
}
|
||||
|
||||
/** Set all elements to 0.
|
||||
*
|
||||
*/
|
||||
public void clear() {
|
||||
for ( int i = 0 ; i < data.length ; i++ ) data[i] = 0;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
/** Efficient shift-down of the array data. After this operation, array.get(0), array.get(1), etc will
|
||||
* be returning what array.get(shift), array.get(shift+1),... were returning before the shift was performed,
|
||||
* and last shift elements of the array will be reset to 0.
|
||||
* @param shift
|
||||
*/
|
||||
public void shiftData(int shift) {
|
||||
if ( shift >= data.length ) {
|
||||
// if we shift by more than the length of stored data, we lose
|
||||
// all that data completely, so we just re-initialize the array.
|
||||
// This is not the operating mode CircularArray is intended for
|
||||
// but we can handle it, just in case.
|
||||
for ( int i = 0 ; i < data.length ; i++ ) data[i] = 0;
|
||||
offset = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// shift < data.length, so at least some data should be preserved
|
||||
|
||||
final int newOffset = ( offset+shift ) % data.length;
|
||||
if ( newOffset < offset ) {
|
||||
// wrap-around!
|
||||
for ( int i = offset ; i < data.length ; i++ ) data[i] = 0;
|
||||
for ( int i = 0; i < newOffset ; i++ ) data[i] = 0;
|
||||
} else {
|
||||
for ( int i = offset ; i < newOffset ; i++ ) data[i] = 0;
|
||||
}
|
||||
offset = newOffset;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue