src.it.unimi.dsi.fastutil.floats.FloatAVLTreeSet Maven / Gradle / Ivy
Show all versions of phoenix-server-hbase-2.6
/* Generic definitions */
/* Assertions (useful to generate conditional code) */
/* Current type and class (and size, if applicable) */
/* Value methods */
/* Interfaces (keys) */
/* Interfaces (values) */
/* Abstract implementations (keys) */
/* Abstract implementations (values) */
/* Static containers (keys) */
/* Static containers (values) */
/* Implementations */
/* Synchronized wrappers */
/* Unmodifiable wrappers */
/* Other wrappers */
/* Methods (keys) */
/* Methods (values) */
/* Methods (keys/values) */
/* Methods that have special names depending on keys (but the special names depend on values) */
/* Equality */
/* Object/Reference-only definitions (keys) */
/* Primitive-type-only definitions (keys) */
/* Object/Reference-only definitions (values) */
/*
* Copyright (C) 2002-2015 Sebastiano Vigna
*
* Licensed 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 it.unimi.dsi.fastutil.floats;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.SortedSet;
import java.util.NoSuchElementException;
/** A type-specific AVL tree set with a fast, small-footprint implementation.
*
* The iterators provided by this class are type-specific {@link it.unimi.dsi.fastutil.BidirectionalIterator bidirectional iterators}. Moreover, the iterator returned by iterator()
can
* be safely cast to a type-specific {@linkplain java.util.ListIterator list iterator}. */
public class FloatAVLTreeSet extends AbstractFloatSortedSet implements java.io.Serializable, Cloneable, FloatSortedSet {
/** A reference to the root entry. */
protected transient Entry tree;
/** Number of elements in this set. */
protected int count;
/** The entry of the first element of this set. */
protected transient Entry firstEntry;
/** The entry of the last element of this set. */
protected transient Entry lastEntry;
/** This set's comparator, as provided in the constructor. */
protected Comparator super Float> storedComparator;
/** This set's actual comparator; it may differ from {@link #storedComparator} because it is always a type-specific comparator, so it could be derived from the former by wrapping. */
protected transient FloatComparator actualComparator;
private static final long serialVersionUID = -7046029254386353130L;
private static final boolean ASSERTS = false;
{
allocatePaths();
}
/** Creates a new empty tree set. */
public FloatAVLTreeSet() {
tree = null;
count = 0;
}
/** Generates the comparator that will be actually used.
*
*
When a specific {@link Comparator} is specified and stored in {@link #storedComparator}, we must check whether it is type-specific. If it is so, we can used directly, and we store it in
* {@link #actualComparator}. Otherwise, we generate on-the-fly an anonymous class that wraps the non-specific {@link Comparator} and makes it into a type-specific one. */
private void setActualComparator() {
/*
* If the provided comparator is already type-specific, we use it. Otherwise, we use a wrapper anonymous class to fake that it is type-specific. */
if ( storedComparator == null || storedComparator instanceof FloatComparator ) actualComparator = (FloatComparator)storedComparator;
else actualComparator = new FloatComparator() {
public int compare( float k1, float k2 ) {
return storedComparator.compare( ( Float.valueOf( k1 ) ), ( Float.valueOf( k2 ) ) );
}
public int compare( Float ok1, Float ok2 ) {
return storedComparator.compare( ok1, ok2 );
}
};
}
/** Creates a new empty tree set with the given comparator.
*
* @param c a {@link Comparator} (even better, a type-specific comparator). */
public FloatAVLTreeSet( final Comparator super Float> c ) {
this();
storedComparator = c;
setActualComparator();
}
/** Creates a new tree set copying a given set.
*
* @param c a collection to be copied into the new tree set. */
public FloatAVLTreeSet( final Collection extends Float> c ) {
this();
addAll( c );
}
/** Creates a new tree set copying a given sorted set (and its {@link Comparator}).
*
* @param s a {@link SortedSet} to be copied into the new tree set. */
public FloatAVLTreeSet( final SortedSet s ) {
this( s.comparator() );
addAll( s );
}
/** Creates a new tree set copying a given type-specific collection.
*
* @param c a type-specific collection to be copied into the new tree set. */
public FloatAVLTreeSet( final FloatCollection c ) {
this();
addAll( c );
}
/** Creates a new tree set copying a given type-specific sorted set (and its {@link Comparator}).
*
* @param s a type-specific sorted set to be copied into the new tree set. */
public FloatAVLTreeSet( final FloatSortedSet s ) {
this( s.comparator() );
addAll( s );
}
/** Creates a new tree set using elements provided by a type-specific iterator.
*
* @param i a type-specific iterator whose elements will fill the set. */
public FloatAVLTreeSet( final FloatIterator i ) {
while ( i.hasNext() )
add( i.nextFloat() );
}
/** Creates a new tree set using elements provided by an iterator.
*
* @param i an iterator whose elements will fill the set. */
public FloatAVLTreeSet( final Iterator> i ) {
this( FloatIterators.asFloatIterator( i ) );
}
/** Creates a new tree set and fills it with the elements of a given array using a given {@link Comparator}.
*
* @param a an array whose elements will be used to fill the set.
* @param offset the first element to use.
* @param length the number of elements to use.
* @param c a {@link Comparator} (even better, a type-specific comparator). */
public FloatAVLTreeSet( final float[] a, final int offset, final int length, final Comparator super Float> c ) {
this( c );
FloatArrays.ensureOffsetLength( a, offset, length );
for ( int i = 0; i < length; i++ )
add( a[ offset + i ] );
}
/** Creates a new tree set and fills it with the elements of a given array.
*
* @param a an array whose elements will be used to fill the set.
* @param offset the first element to use.
* @param length the number of elements to use. */
public FloatAVLTreeSet( final float[] a, final int offset, final int length ) {
this( a, offset, length, null );
}
/** Creates a new tree set copying the elements of an array.
*
* @param a an array to be copied into the new tree set. */
public FloatAVLTreeSet( final float[] a ) {
this();
int i = a.length;
while ( i-- != 0 )
add( a[ i ] );
}
/** Creates a new tree set copying the elements of an array using a given {@link Comparator}.
*
* @param a an array to be copied into the new tree set.
* @param c a {@link Comparator} (even better, a type-specific comparator). */
public FloatAVLTreeSet( final float[] a, final Comparator super Float> c ) {
this( c );
int i = a.length;
while ( i-- != 0 )
add( a[ i ] );
}
/* The following methods implements some basic building blocks used by all accessors. They are (and should be maintained) identical to those used in AVLTreeMap.drv.
*
* The add()/remove() code is derived from Ben Pfaff's GNU libavl (http://www.msu.edu/~pfaffben/avl/). If you want to understand what's going on, you should have a look at the literate code
* contained therein first. */
/** Compares two keys in the right way.
*
* This method uses the {@link #actualComparator} if it is non-null
. Otherwise, it resorts to primitive type comparisons or to {@link Comparable#compareTo(Object) compareTo()}.
*
* @param k1 the first key.
* @param k2 the second key.
* @return a number smaller than, equal to or greater than 0, as usual (i.e., when k1 < k2, k1 = k2 or k1 > k2, respectively). */
final int compare( final float k1, final float k2 ) {
return actualComparator == null ? ( Float.compare( ( k1 ), ( k2 ) ) ) : actualComparator.compare( k1, k2 );
}
/** Returns the entry corresponding to the given key, if it is in the tree; null
, otherwise.
*
* @param k the key to search for.
* @return the corresponding entry, or null
if no entry with the given key exists. */
private Entry findKey( final float k ) {
Entry e = tree;
int cmp;
while ( e != null && ( cmp = compare( k, e.key ) ) != 0 )
e = cmp < 0 ? e.left() : e.right();
return e;
}
/** Locates a key.
*
* @param k a key.
* @return the last entry on a search for the given key; this will be the given key, if it present; otherwise, it will be either the smallest greater key or the greatest smaller key. */
final Entry locateKey( final float k ) {
Entry e = tree, last = tree;
int cmp = 0;
while ( e != null && ( cmp = compare( k, e.key ) ) != 0 ) {
last = e;
e = cmp < 0 ? e.left() : e.right();
}
return cmp == 0 ? e : last;
}
/** This vector remembers the path followed during the current insertion. It suffices for about 232 entries. */
private transient boolean dirPath[];
private void allocatePaths() {
dirPath = new boolean[ 48 ];
}
public boolean add( final float k ) {
if ( tree == null ) { // The case of the empty tree is treated separately.
count++;
tree = lastEntry = firstEntry = new Entry( k );
}
else {
Entry p = tree, q = null, y = tree, z = null, e = null, w = null;
int cmp, i = 0;
while ( true ) {
if ( ( cmp = compare( k, p.key ) ) == 0 ) return false;
if ( p.balance() != 0 ) {
i = 0;
z = q;
y = p;
}
if ( dirPath[ i++ ] = cmp > 0 ) {
if ( p.succ() ) {
count++;
e = new Entry( k );
if ( p.right == null ) lastEntry = e;
e.left = p;
e.right = p.right;
p.right( e );
break;
}
q = p;
p = p.right;
}
else {
if ( p.pred() ) {
count++;
e = new Entry( k );
if ( p.left == null ) firstEntry = e;
e.right = p;
e.left = p.left;
p.left( e );
break;
}
q = p;
p = p.left;
}
}
p = y;
i = 0;
while ( p != e ) {
if ( dirPath[ i ] ) p.incBalance();
else p.decBalance();
p = dirPath[ i++ ] ? p.right : p.left;
}
if ( y.balance() == -2 ) {
Entry x = y.left;
if ( x.balance() == -1 ) {
w = x;
if ( x.succ() ) {
x.succ( false );
y.pred( x );
}
else y.left = x.right;
x.right = y;
x.balance( 0 );
y.balance( 0 );
}
else {
if ( ASSERTS ) assert x.balance() == 1;
w = x.right;
x.right = w.left;
w.left = x;
y.left = w.right;
w.right = y;
if ( w.balance() == -1 ) {
x.balance( 0 );
y.balance( 1 );
}
else if ( w.balance() == 0 ) {
x.balance( 0 );
y.balance( 0 );
}
else {
x.balance( -1 );
y.balance( 0 );
}
w.balance( 0 );
if ( w.pred() ) {
x.succ( w );
w.pred( false );
}
if ( w.succ() ) {
y.pred( w );
w.succ( false );
}
}
}
else if ( y.balance() == +2 ) {
Entry x = y.right;
if ( x.balance() == 1 ) {
w = x;
if ( x.pred() ) {
x.pred( false );
y.succ( x );
}
else y.right = x.left;
x.left = y;
x.balance( 0 );
y.balance( 0 );
}
else {
if ( ASSERTS ) assert x.balance() == -1;
w = x.left;
x.left = w.right;
w.right = x;
y.right = w.left;
w.left = y;
if ( w.balance() == 1 ) {
x.balance( 0 );
y.balance( -1 );
}
else if ( w.balance() == 0 ) {
x.balance( 0 );
y.balance( 0 );
}
else {
x.balance( 1 );
y.balance( 0 );
}
w.balance( 0 );
if ( w.pred() ) {
y.succ( w );
w.pred( false );
}
if ( w.succ() ) {
x.pred( w );
w.succ( false );
}
}
}
else return true;
if ( z == null ) tree = w;
else {
if ( z.left == y ) z.left = w;
else z.right = w;
}
}
if ( ASSERTS ) checkTree( tree );
return true;
}
/** Finds the parent of an entry.
*
* @param e a node of the tree.
* @return the parent of the given node, or null
for the root. */
private Entry parent( final Entry e ) {
if ( e == tree ) return null;
Entry x, y, p;
x = y = e;
while ( true ) {
if ( y.succ() ) {
p = y.right;
if ( p == null || p.left != e ) {
while ( !x.pred() )
x = x.left;
p = x.left;
}
return p;
}
else if ( x.pred() ) {
p = x.left;
if ( p == null || p.right != e ) {
while ( !y.succ() )
y = y.right;
p = y.right;
}
return p;
}
x = x.left;
y = y.right;
}
}
public boolean remove( final float k ) {
if ( tree == null ) return false;
int cmp;
Entry p = tree, q = null;
boolean dir = false;
final float kk = k;
while ( true ) {
if ( ( cmp = compare( kk, p.key ) ) == 0 ) break;
else if ( dir = cmp > 0 ) {
q = p;
if ( ( p = p.right() ) == null ) return false;
}
else {
q = p;
if ( ( p = p.left() ) == null ) return false;
}
}
if ( p.left == null ) firstEntry = p.next();
if ( p.right == null ) lastEntry = p.prev();
if ( p.succ() ) {
if ( p.pred() ) {
if ( q != null ) {
if ( dir ) q.succ( p.right );
else q.pred( p.left );
}
else tree = dir ? p.right : p.left;
}
else {
p.prev().right = p.right;
if ( q != null ) {
if ( dir ) q.right = p.left;
else q.left = p.left;
}
else tree = p.left;
}
}
else {
Entry r = p.right;
if ( r.pred() ) {
r.left = p.left;
r.pred( p.pred() );
if ( !r.pred() ) r.prev().right = r;
if ( q != null ) {
if ( dir ) q.right = r;
else q.left = r;
}
else tree = r;
r.balance( p.balance() );
q = r;
dir = true;
}
else {
Entry s;
while ( true ) {
s = r.left;
if ( s.pred() ) break;
r = s;
}
if ( s.succ() ) r.pred( s );
else r.left = s.right;
s.left = p.left;
if ( !p.pred() ) {
p.prev().right = s;
s.pred( false );
}
s.right = p.right;
s.succ( false );
if ( q != null ) {
if ( dir ) q.right = s;
else q.left = s;
}
else tree = s;
s.balance( p.balance() );
q = r;
dir = false;
}
}
Entry y;
while ( q != null ) {
y = q;
q = parent( y );
if ( !dir ) {
dir = q != null && q.left != y;
y.incBalance();
if ( y.balance() == 1 ) break;
else if ( y.balance() == 2 ) {
Entry x = y.right;
if ( ASSERTS ) assert x != null;
if ( x.balance() == -1 ) {
Entry w;
if ( ASSERTS ) assert x.balance() == -1;
w = x.left;
x.left = w.right;
w.right = x;
y.right = w.left;
w.left = y;
if ( w.balance() == 1 ) {
x.balance( 0 );
y.balance( -1 );
}
else if ( w.balance() == 0 ) {
x.balance( 0 );
y.balance( 0 );
}
else {
if ( ASSERTS ) assert w.balance() == -1;
x.balance( 1 );
y.balance( 0 );
}
w.balance( 0 );
if ( w.pred() ) {
y.succ( w );
w.pred( false );
}
if ( w.succ() ) {
x.pred( w );
w.succ( false );
}
if ( q != null ) {
if ( dir ) q.right = w;
else q.left = w;
}
else tree = w;
}
else {
if ( q != null ) {
if ( dir ) q.right = x;
else q.left = x;
}
else tree = x;
if ( x.balance() == 0 ) {
y.right = x.left;
x.left = y;
x.balance( -1 );
y.balance( +1 );
break;
}
if ( ASSERTS ) assert x.balance() == 1;
if ( x.pred() ) {
y.succ( true );
x.pred( false );
}
else y.right = x.left;
x.left = y;
y.balance( 0 );
x.balance( 0 );
}
}
}
else {
dir = q != null && q.left != y;
y.decBalance();
if ( y.balance() == -1 ) break;
else if ( y.balance() == -2 ) {
Entry x = y.left;
if ( ASSERTS ) assert x != null;
if ( x.balance() == 1 ) {
Entry w;
if ( ASSERTS ) assert x.balance() == 1;
w = x.right;
x.right = w.left;
w.left = x;
y.left = w.right;
w.right = y;
if ( w.balance() == -1 ) {
x.balance( 0 );
y.balance( 1 );
}
else if ( w.balance() == 0 ) {
x.balance( 0 );
y.balance( 0 );
}
else {
if ( ASSERTS ) assert w.balance() == 1;
x.balance( -1 );
y.balance( 0 );
}
w.balance( 0 );
if ( w.pred() ) {
x.succ( w );
w.pred( false );
}
if ( w.succ() ) {
y.pred( w );
w.succ( false );
}
if ( q != null ) {
if ( dir ) q.right = w;
else q.left = w;
}
else tree = w;
}
else {
if ( q != null ) {
if ( dir ) q.right = x;
else q.left = x;
}
else tree = x;
if ( x.balance() == 0 ) {
y.left = x.right;
x.right = y;
x.balance( +1 );
y.balance( -1 );
break;
}
if ( ASSERTS ) assert x.balance() == -1;
if ( x.succ() ) {
y.pred( true );
x.succ( false );
}
else y.left = x.right;
x.right = y;
y.balance( 0 );
x.balance( 0 );
}
}
}
}
count--;
if ( ASSERTS ) checkTree( tree );
return true;
}
public boolean contains( final float k ) {
return findKey( k ) != null;
}
public void clear() {
count = 0;
tree = null;
firstEntry = lastEntry = null;
}
/** This class represent an entry in a tree set.
*
*
We use the only "metadata", i.e., {@link Entry#info}, to store information about balance, predecessor status and successor status.
*
*
Note that since the class is recursive, it can be considered equivalently a tree. */
private static final class Entry implements Cloneable {
/** If the bit in this mask is true, {@link #right} points to a successor. */
private final static int SUCC_MASK = 1 << 31;
/** If the bit in this mask is true, {@link #left} points to a predecessor. */
private final static int PRED_MASK = 1 << 30;
/** The bits in this mask hold the node balance info. You can get it just by casting to byte. */
private final static int BALANCE_MASK = 0xFF;
/** The key of this entry. */
float key;
/** The pointers to the left and right subtrees. */
Entry left, right;
/** This integers holds different information in different bits (see {@link #SUCC_MASK}, {@link #PRED_MASK} and {@link #BALANCE_MASK}). */
int info;
Entry() {}
/** Creates a new entry with the given key.
*
* @param k a key. */
Entry( final float k ) {
this.key = k;
info = SUCC_MASK | PRED_MASK;
}
/** Returns the left subtree.
*
* @return the left subtree (null
if the left subtree is empty). */
Entry left() {
return ( info & PRED_MASK ) != 0 ? null : left;
}
/** Returns the right subtree.
*
* @return the right subtree (null
if the right subtree is empty). */
Entry right() {
return ( info & SUCC_MASK ) != 0 ? null : right;
}
/** Checks whether the left pointer is really a predecessor.
*
* @return true if the left pointer is a predecessor. */
boolean pred() {
return ( info & PRED_MASK ) != 0;
}
/** Checks whether the right pointer is really a successor.
*
* @return true if the right pointer is a successor. */
boolean succ() {
return ( info & SUCC_MASK ) != 0;
}
/** Sets whether the left pointer is really a predecessor.
*
* @param pred if true then the left pointer will be considered a predecessor. */
void pred( final boolean pred ) {
if ( pred ) info |= PRED_MASK;
else info &= ~PRED_MASK;
}
/** Sets whether the right pointer is really a successor.
*
* @param succ if true then the right pointer will be considered a successor. */
void succ( final boolean succ ) {
if ( succ ) info |= SUCC_MASK;
else info &= ~SUCC_MASK;
}
/** Sets the left pointer to a predecessor.
*
* @param pred the predecessr. */
void pred( final Entry pred ) {
info |= PRED_MASK;
left = pred;
}
/** Sets the right pointer to a successor.
*
* @param succ the successor. */
void succ( final Entry succ ) {
info |= SUCC_MASK;
right = succ;
}
/** Sets the left pointer to the given subtree.
*
* @param left the new left subtree. */
void left( final Entry left ) {
info &= ~PRED_MASK;
this.left = left;
}
/** Sets the right pointer to the given subtree.
*
* @param right the new right subtree. */
void right( final Entry right ) {
info &= ~SUCC_MASK;
this.right = right;
}
/** Returns the current level of the node.
*
* @return the current level of this node. */
int balance() {
return (byte)info;
}
/** Sets the level of this node.
*
* @param level the new level of this node. */
void balance( int level ) {
info &= ~BALANCE_MASK;
info |= ( level & BALANCE_MASK );
}
/** Increments the level of this node. */
void incBalance() {
info = info & ~BALANCE_MASK | ( (byte)info + 1 ) & 0xFF;
}
/** Decrements the level of this node. */
protected void decBalance() {
info = info & ~BALANCE_MASK | ( (byte)info - 1 ) & 0xFF;
}
/** Computes the next entry in the set order.
*
* @return the next entry (null
) if this is the last entry). */
Entry next() {
Entry next = this.right;
if ( ( info & SUCC_MASK ) == 0 ) while ( ( next.info & PRED_MASK ) == 0 )
next = next.left;
return next;
}
/** Computes the previous entry in the set order.
*
* @return the previous entry (null
) if this is the first entry). */
Entry prev() {
Entry prev = this.left;
if ( ( info & PRED_MASK ) == 0 ) while ( ( prev.info & SUCC_MASK ) == 0 )
prev = prev.right;
return prev;
}
public Entry clone() {
Entry c;
try {
c = (Entry)super.clone();
}
catch ( CloneNotSupportedException cantHappen ) {
throw new InternalError();
}
c.key = key;
c.info = info;
return c;
}
public boolean equals( final Object o ) {
if ( !( o instanceof Entry ) ) return false;
Entry e = (Entry)o;
return ( Float.floatToIntBits( key ) == Float.floatToIntBits( e.key ) );
}
public int hashCode() {
return it.unimi.dsi.fastutil.HashCommon.float2int( key );
}
public String toString() {
return String.valueOf( key );
}
/*public void prettyPrint() { prettyPrint(0); }
*
* public void prettyPrint(int level) { if ( pred() ) { for (int i = 0; i < level; i++) System.err.print(" "); System.err.println("pred: " + left ); } else if (left != null)
* left.prettyPrint(level +1 ); for (int i = 0; i < level; i++) System.err.print(" "); System.err.println(key + " (" + level() + ")"); if ( succ() ) { for (int i = 0; i < level; i++)
* System.err.print(" "); System.err.println("succ: " + right ); } else if (right != null) right.prettyPrint(level + 1); } */
}
/*public void prettyPrint() { System.err.println("size: " + count); if (tree != null) tree.prettyPrint(); } */
public int size() {
return count;
}
public boolean isEmpty() {
return count == 0;
}
public float firstFloat() {
if ( tree == null ) throw new NoSuchElementException();
return firstEntry.key;
}
public float lastFloat() {
if ( tree == null ) throw new NoSuchElementException();
return lastEntry.key;
}
/** An iterator on the whole range.
*
*
This class can iterate in both directions on a threaded tree. */
private class SetIterator extends AbstractFloatListIterator {
/** The entry that will be returned by the next call to {@link java.util.ListIterator#previous()} (or null
if no previous entry exists). */
Entry prev;
/** The entry that will be returned by the next call to {@link java.util.ListIterator#next()} (or null
if no next entry exists). */
Entry next;
/** The last entry that was returned (or null
if we did not iterate or used {@link #remove()}). */
Entry curr;
/** The current index (in the sense of a {@link java.util.ListIterator}). Note that this value is not meaningful when this {@link SetIterator} has been created using the nonempty constructor. */
int index = 0;
SetIterator() {
next = firstEntry;
}
SetIterator( final float k ) {
if ( ( next = locateKey( k ) ) != null ) {
if ( compare( next.key, k ) <= 0 ) {
prev = next;
next = next.next();
}
else prev = next.prev();
}
}
public boolean hasNext() {
return next != null;
}
public boolean hasPrevious() {
return prev != null;
}
void updateNext() {
next = next.next();
}
Entry nextEntry() {
if ( !hasNext() ) throw new NoSuchElementException();
curr = prev = next;
index++;
updateNext();
return curr;
}
public float nextFloat() {
return nextEntry().key;
}
public float previousFloat() {
return previousEntry().key;
}
void updatePrevious() {
prev = prev.prev();
}
Entry previousEntry() {
if ( !hasPrevious() ) throw new NoSuchElementException();
curr = next = prev;
index--;
updatePrevious();
return curr;
}
public int nextIndex() {
return index;
}
public int previousIndex() {
return index - 1;
}
public void remove() {
if ( curr == null ) throw new IllegalStateException();
/*
* If the last operation was a next(), we are removing an entry that preceeds the current index, and thus we must decrement it. */
if ( curr == prev ) index--;
next = prev = curr;
updatePrevious();
updateNext();
FloatAVLTreeSet.this.remove( curr.key );
curr = null;
}
}
public FloatBidirectionalIterator iterator() {
return new SetIterator();
}
public FloatBidirectionalIterator iterator( final float from ) {
return new SetIterator( from );
}
public FloatComparator comparator() {
return actualComparator;
}
public FloatSortedSet headSet( final float to ) {
return new Subset( ( 0 ), true, to, false );
}
public FloatSortedSet tailSet( final float from ) {
return new Subset( from, false, ( 0 ), true );
}
public FloatSortedSet subSet( final float from, final float to ) {
return new Subset( from, false, to, false );
}
/** A subset with given range.
*
*
This class represents a subset. One has to specify the left/right limits (which can be set to -∞ or ∞). Since the subset is a view on the set, at a given moment it could happen
* that the limits of the range are not any longer in the main set. Thus, things such as {@link java.util.SortedSet#first()} or {@link java.util.SortedSet#size()} must be always computed
* on-the-fly. */
private final class Subset extends AbstractFloatSortedSet implements java.io.Serializable, FloatSortedSet {
private static final long serialVersionUID = -7046029254386353129L;
/** The start of the subset range, unless {@link #bottom} is true. */
float from;
/** The end of the subset range, unless {@link #top} is true. */
float to;
/** If true, the subset range starts from -∞. */
boolean bottom;
/** If true, the subset range goes to ∞. */
boolean top;
/** Creates a new subset with given key range.
*
* @param from the start of the subset range.
* @param bottom if true, the first parameter is ignored and the range starts from -∞.
* @param to the end of the subset range.
* @param top if true, the third parameter is ignored and the range goes to ∞. */
public Subset( final float from, final boolean bottom, final float to, final boolean top ) {
if ( !bottom && !top && FloatAVLTreeSet.this.compare( from, to ) > 0 ) throw new IllegalArgumentException( "Start element (" + from + ") is larger than end element (" + to + ")" );
this.from = from;
this.bottom = bottom;
this.to = to;
this.top = top;
}
public void clear() {
final SubsetIterator i = new SubsetIterator();
while ( i.hasNext() ) {
i.next();
i.remove();
}
}
/** Checks whether a key is in the subset range.
*
* @param k a key.
* @return true if is the key is in the subset range. */
final boolean in( final float k ) {
return ( bottom || FloatAVLTreeSet.this.compare( k, from ) >= 0 ) &&
( top || FloatAVLTreeSet.this.compare( k, to ) < 0 );
}
public boolean contains( final float k ) {
return in( k ) && FloatAVLTreeSet.this.contains( k );
}
public boolean add( final float k ) {
if ( !in( k ) ) throw new IllegalArgumentException( "Element (" + k + ") out of range [" + ( bottom ? "-" : String.valueOf( from ) ) + ", " + ( top ? "-" : String.valueOf( to ) ) + ")" );
return FloatAVLTreeSet.this.add( k );
}
public boolean remove( final float k ) {
if ( !in( k ) ) return false;
return FloatAVLTreeSet.this.remove( k );
}
public int size() {
final SubsetIterator i = new SubsetIterator();
int n = 0;
while ( i.hasNext() ) {
n++;
i.next();
}
return n;
}
public boolean isEmpty() {
return !new SubsetIterator().hasNext();
}
public FloatComparator comparator() {
return actualComparator;
}
public FloatBidirectionalIterator iterator() {
return new SubsetIterator();
}
public FloatBidirectionalIterator iterator( final float from ) {
return new SubsetIterator( from );
}
public FloatSortedSet headSet( final float to ) {
if ( top ) return new Subset( from, bottom, to, false );
return compare( to, this.to ) < 0 ? new Subset( from, bottom, to, false ) : this;
}
public FloatSortedSet tailSet( final float from ) {
if ( bottom ) return new Subset( from, false, to, top );
return compare( from, this.from ) > 0 ? new Subset( from, false, to, top ) : this;
}
public FloatSortedSet subSet( float from, float to ) {
if ( top && bottom ) return new Subset( from, false, to, false );
if ( !top ) to = compare( to, this.to ) < 0 ? to : this.to;
if ( !bottom ) from = compare( from, this.from ) > 0 ? from : this.from;
if ( !top && !bottom && from == this.from && to == this.to ) return this;
return new Subset( from, false, to, false );
}
/** Locates the first entry.
*
* @return the first entry of this subset, or null
if the subset is empty. */
public FloatAVLTreeSet.Entry firstEntry() {
if ( tree == null ) return null;
// If this subset goes to -infinity, we return the main set first entry; otherwise, we locate the start of the set.
FloatAVLTreeSet.Entry e;
if ( bottom ) e = firstEntry;
else {
e = locateKey( from );
// If we find either the start or something greater we're OK.
if ( compare( e.key, from ) < 0 ) e = e.next();
}
// Finally, if this subset doesn't go to infinity, we check that the resulting key isn't greater than the end.
if ( e == null || !top && compare( e.key, to ) >= 0 ) return null;
return e;
}
/** Locates the last entry.
*
* @return the last entry of this subset, or null
if the subset is empty. */
public FloatAVLTreeSet.Entry lastEntry() {
if ( tree == null ) return null;
// If this subset goes to infinity, we return the main set last entry; otherwise, we locate the end of the set.
FloatAVLTreeSet.Entry e;
if ( top ) e = lastEntry;
else {
e = locateKey( to );
// If we find something smaller than the end we're OK.
if ( compare( e.key, to ) >= 0 ) e = e.prev();
}
// Finally, if this subset doesn't go to -infinity, we check that the resulting key isn't smaller than the start.
if ( e == null || !bottom && compare( e.key, from ) < 0 ) return null;
return e;
}
public float firstFloat() {
FloatAVLTreeSet.Entry e = firstEntry();
if ( e == null ) throw new NoSuchElementException();
return e.key;
}
public float lastFloat() {
FloatAVLTreeSet.Entry e = lastEntry();
if ( e == null ) throw new NoSuchElementException();
return e.key;
}
/** An iterator for subranges.
*
*
This class inherits from {@link SetIterator}, but overrides the methods that update the pointer after a {@link java.util.ListIterator#next()} or {@link java.util.ListIterator#previous()}
* . If we would move out of the range of the subset we just overwrite the next or previous entry with null
. */
private final class SubsetIterator extends SetIterator {
SubsetIterator() {
next = firstEntry();
}
SubsetIterator( final float k ) {
this();
if ( next != null ) {
if ( !bottom && compare( k, next.key ) < 0 ) prev = null;
else if ( !top && compare( k, ( prev = lastEntry() ).key ) >= 0 ) next = null;
else {
next = locateKey( k );
if ( compare( next.key, k ) <= 0 ) {
prev = next;
next = next.next();
}
else prev = next.prev();
}
}
}
void updatePrevious() {
prev = prev.prev();
if ( !bottom && prev != null && FloatAVLTreeSet.this.compare( prev.key, from ) < 0 ) prev = null;
}
void updateNext() {
next = next.next();
if ( !top && next != null && FloatAVLTreeSet.this.compare( next.key, to ) >= 0 ) next = null;
}
}
}
/** Returns a deep copy of this tree set.
*
*
This method performs a deep copy of this tree set; the data stored in the set, however, is not cloned. Note that this makes a difference only for object keys.
*
* @return a deep copy of this tree set. */
public Object clone() {
FloatAVLTreeSet c;
try {
c = (FloatAVLTreeSet)super.clone();
}
catch ( CloneNotSupportedException cantHappen ) {
throw new InternalError();
}
c.allocatePaths();
if ( count != 0 ) {
// Also this apparently unfathomable code is derived from GNU libavl.
Entry e, p, q, rp = new Entry(), rq = new Entry();
p = rp;
rp.left( tree );
q = rq;
rq.pred( null );
while ( true ) {
if ( !p.pred() ) {
e = p.left.clone();
e.pred( q.left );
e.succ( q );
q.left( e );
p = p.left;
q = q.left;
}
else {
while ( p.succ() ) {
p = p.right;
if ( p == null ) {
q.right = null;
c.tree = rq.left;
c.firstEntry = c.tree;
while ( c.firstEntry.left != null )
c.firstEntry = c.firstEntry.left;
c.lastEntry = c.tree;
while ( c.lastEntry.right != null )
c.lastEntry = c.lastEntry.right;
return c;
}
q = q.right;
}
p = p.right;
q = q.right;
}
if ( !p.succ() ) {
e = p.right.clone();
e.succ( q.right );
e.pred( q );
q.right( e );
}
}
}
return c;
}
private void writeObject( java.io.ObjectOutputStream s ) throws java.io.IOException {
int n = count;
SetIterator i = new SetIterator();
s.defaultWriteObject();
while ( n-- != 0 )
s.writeFloat( i.nextFloat() );
}
/** Reads the given number of entries from the input stream, returning the corresponding tree.
*
* @param s the input stream.
* @param n the (positive) number of entries to read.
* @param pred the entry containing the key that preceeds the first key in the tree.
* @param succ the entry containing the key that follows the last key in the tree. */
private Entry readTree( final java.io.ObjectInputStream s, final int n, final Entry pred, final Entry succ ) throws java.io.IOException, ClassNotFoundException {
if ( n == 1 ) {
final Entry top = new Entry( s.readFloat() );
top.pred( pred );
top.succ( succ );
return top;
}
if ( n == 2 ) {
/*
* We handle separately this case so that recursion willalways* be on nonempty subtrees. */
final Entry top = new Entry( s.readFloat() );
top.right( new Entry( s.readFloat() ) );
top.right.pred( top );
top.balance( 1 );
top.pred( pred );
top.right.succ( succ );
return top;
}
// The right subtree is the largest one.
final int rightN = n / 2, leftN = n - rightN - 1;
final Entry top = new Entry();
top.left( readTree( s, leftN, pred, top ) );
top.key = s.readFloat();
top.right( readTree( s, rightN, top, succ ) );
if ( n == ( n & -n ) ) top.balance( 1 ); // Quick test for determining whether n is a power of 2.
return top;
}
private void readObject( java.io.ObjectInputStream s ) throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
/*
* The storedComparator is now correctly set, but we must restore on-the-fly the actualComparator. */
setActualComparator();
allocatePaths();
if ( count != 0 ) {
tree = readTree( s, count, null, null );
Entry e;
e = tree;
while ( e.left() != null )
e = e.left();
firstEntry = e;
e = tree;
while ( e.right() != null )
e = e.right();
lastEntry = e;
}
if ( ASSERTS ) checkTree( tree );
}
private static int checkTree( @SuppressWarnings("unused") Entry e ) {
return 0;
}
}