Update #47 - Singleplayer lag fixes

This commit is contained in:
lax1dude
2025-01-19 13:26:27 -08:00
parent 3f5ee57068
commit 1f0d593a8c
2052 changed files with 133581 additions and 2339 deletions

View File

@ -0,0 +1,51 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.ByteCursor;
import com.carrotsearch.hppc.predicates.BytePredicate;
import java.util.Arrays;
/** Common superclass for collections. */
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "AbstractKTypeCollection.java")
abstract class AbstractByteCollection implements ByteCollection {
/** Default implementation uses a predicate for removal. */
@Override
public int removeAll(final ByteLookupContainer c) {
return this.removeAll(c::contains);
}
/** Default implementation uses a predicate for retaining. */
@Override
public int retainAll(final ByteLookupContainer c) {
// We know c holds sub-types of byte and we're not modifying c, so go unchecked.
return this.removeAll(k -> !c.contains(k));
}
/**
* Default implementation redirects to {@link #removeAll(BytePredicate)} and negates the
* predicate.
*/
@Override
public int retainAll(final BytePredicate predicate) {
return removeAll(value -> !predicate.apply(value));
}
/** Default implementation of copying to an array. */
@Override
public byte[] toArray() {
byte[] array = (new byte[size()]);
int i = 0;
for (ByteCursor c : this) {
array[i++] = c.value;
}
return array;
}
/** Convert the contents of this container to a human-friendly string. */
@Override
public String toString() {
return Arrays.toString(this.toArray());
}
}

View File

@ -0,0 +1,51 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.CharCursor;
import com.carrotsearch.hppc.predicates.CharPredicate;
import java.util.Arrays;
/** Common superclass for collections. */
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "AbstractKTypeCollection.java")
abstract class AbstractCharCollection implements CharCollection {
/** Default implementation uses a predicate for removal. */
@Override
public int removeAll(final CharLookupContainer c) {
return this.removeAll(c::contains);
}
/** Default implementation uses a predicate for retaining. */
@Override
public int retainAll(final CharLookupContainer c) {
// We know c holds sub-types of char and we're not modifying c, so go unchecked.
return this.removeAll(k -> !c.contains(k));
}
/**
* Default implementation redirects to {@link #removeAll(CharPredicate)} and negates the
* predicate.
*/
@Override
public int retainAll(final CharPredicate predicate) {
return removeAll(value -> !predicate.apply(value));
}
/** Default implementation of copying to an array. */
@Override
public char[] toArray() {
char[] array = (new char[size()]);
int i = 0;
for (CharCursor c : this) {
array[i++] = c.value;
}
return array;
}
/** Convert the contents of this container to a human-friendly string. */
@Override
public String toString() {
return Arrays.toString(this.toArray());
}
}

View File

@ -0,0 +1,51 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.DoubleCursor;
import com.carrotsearch.hppc.predicates.DoublePredicate;
import java.util.Arrays;
/** Common superclass for collections. */
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "AbstractKTypeCollection.java")
abstract class AbstractDoubleCollection implements DoubleCollection {
/** Default implementation uses a predicate for removal. */
@Override
public int removeAll(final DoubleLookupContainer c) {
return this.removeAll(c::contains);
}
/** Default implementation uses a predicate for retaining. */
@Override
public int retainAll(final DoubleLookupContainer c) {
// We know c holds sub-types of double and we're not modifying c, so go unchecked.
return this.removeAll(k -> !c.contains(k));
}
/**
* Default implementation redirects to {@link #removeAll(DoublePredicate)} and negates the
* predicate.
*/
@Override
public int retainAll(final DoublePredicate predicate) {
return removeAll(value -> !predicate.apply(value));
}
/** Default implementation of copying to an array. */
@Override
public double[] toArray() {
double[] array = (new double[size()]);
int i = 0;
for (DoubleCursor c : this) {
array[i++] = c.value;
}
return array;
}
/** Convert the contents of this container to a human-friendly string. */
@Override
public String toString() {
return Arrays.toString(this.toArray());
}
}

View File

@ -0,0 +1,51 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.FloatCursor;
import com.carrotsearch.hppc.predicates.FloatPredicate;
import java.util.Arrays;
/** Common superclass for collections. */
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "AbstractKTypeCollection.java")
abstract class AbstractFloatCollection implements FloatCollection {
/** Default implementation uses a predicate for removal. */
@Override
public int removeAll(final FloatLookupContainer c) {
return this.removeAll(c::contains);
}
/** Default implementation uses a predicate for retaining. */
@Override
public int retainAll(final FloatLookupContainer c) {
// We know c holds sub-types of float and we're not modifying c, so go unchecked.
return this.removeAll(k -> !c.contains(k));
}
/**
* Default implementation redirects to {@link #removeAll(FloatPredicate)} and negates the
* predicate.
*/
@Override
public int retainAll(final FloatPredicate predicate) {
return removeAll(value -> !predicate.apply(value));
}
/** Default implementation of copying to an array. */
@Override
public float[] toArray() {
float[] array = (new float[size()]);
int i = 0;
for (FloatCursor c : this) {
array[i++] = c.value;
}
return array;
}
/** Convert the contents of this container to a human-friendly string. */
@Override
public String toString() {
return Arrays.toString(this.toArray());
}
}

View File

@ -0,0 +1,50 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.IntCursor;
import com.carrotsearch.hppc.predicates.IntPredicate;
import java.util.Arrays;
/** Common superclass for collections. */
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "AbstractKTypeCollection.java")
abstract class AbstractIntCollection implements IntCollection {
/** Default implementation uses a predicate for removal. */
@Override
public int removeAll(final IntLookupContainer c) {
return this.removeAll(c::contains);
}
/** Default implementation uses a predicate for retaining. */
@Override
public int retainAll(final IntLookupContainer c) {
// We know c holds sub-types of int and we're not modifying c, so go unchecked.
return this.removeAll(k -> !c.contains(k));
}
/**
* Default implementation redirects to {@link #removeAll(IntPredicate)} and negates the predicate.
*/
@Override
public int retainAll(final IntPredicate predicate) {
return removeAll(value -> !predicate.apply(value));
}
/** Default implementation of copying to an array. */
@Override
public int[] toArray() {
int[] array = (new int[size()]);
int i = 0;
for (IntCursor c : this) {
array[i++] = c.value;
}
return array;
}
/** Convert the contents of this container to a human-friendly string. */
@Override
public String toString() {
return Arrays.toString(this.toArray());
}
}

View File

@ -0,0 +1,71 @@
/*
* HPPC
*
* Copyright (C) 2010-2024 Carrot Search s.c. and contributors
* All rights reserved.
*
* Refer to the full license file "LICENSE.txt":
* https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt
*/
package com.carrotsearch.hppc;
import java.util.Iterator;
import java.util.NoSuchElementException;
/** Simplifies the implementation of iterators a bit. Modeled loosely after Google Guava's API. */
public abstract class AbstractIterator<E> implements Iterator<E> {
private static final int NOT_CACHED = 0;
private static final int CACHED = 1;
private static final int AT_END = 2;
/** Current iterator state. */
private int state = NOT_CACHED;
/** The next element to be returned from {@link #next()} if fetched. */
private E nextElement;
/** {@inheritDoc} */
@Override
public boolean hasNext() {
if (state == NOT_CACHED) {
state = CACHED;
nextElement = fetch();
}
return state == CACHED;
}
/** {@inheritDoc} */
@Override
public E next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
state = NOT_CACHED;
return nextElement;
}
/** Default implementation throws {@link UnsupportedOperationException}. */
@Override
public void remove() {
throw new UnsupportedOperationException();
}
/**
* Fetch next element. The implementation must return {@link #done()} when all elements have been
* fetched.
*
* @return Returns the next value for the iterator or chain-calls {@link #done()}.
*/
protected abstract E fetch();
/**
* Call when done.
*
* @return Returns a unique sentinel value to indicate end-of-iteration.
*/
protected final E done() {
state = AT_END;
return null;
}
}

View File

@ -0,0 +1,51 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.LongCursor;
import com.carrotsearch.hppc.predicates.LongPredicate;
import java.util.Arrays;
/** Common superclass for collections. */
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "AbstractKTypeCollection.java")
abstract class AbstractLongCollection implements LongCollection {
/** Default implementation uses a predicate for removal. */
@Override
public int removeAll(final LongLookupContainer c) {
return this.removeAll(c::contains);
}
/** Default implementation uses a predicate for retaining. */
@Override
public int retainAll(final LongLookupContainer c) {
// We know c holds sub-types of long and we're not modifying c, so go unchecked.
return this.removeAll(k -> !c.contains(k));
}
/**
* Default implementation redirects to {@link #removeAll(LongPredicate)} and negates the
* predicate.
*/
@Override
public int retainAll(final LongPredicate predicate) {
return removeAll(value -> !predicate.apply(value));
}
/** Default implementation of copying to an array. */
@Override
public long[] toArray() {
long[] array = (new long[size()]);
int i = 0;
for (LongCursor c : this) {
array[i++] = c.value;
}
return array;
}
/** Convert the contents of this container to a human-friendly string. */
@Override
public String toString() {
return Arrays.toString(this.toArray());
}
}

View File

@ -0,0 +1,66 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.ObjectCursor;
import com.carrotsearch.hppc.predicates.ObjectPredicate;
import java.util.Arrays;
/** Common superclass for collections. */
@SuppressWarnings("unchecked")
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "AbstractKTypeCollection.java")
abstract class AbstractObjectCollection<KType> implements ObjectCollection<KType> {
/** Default implementation uses a predicate for removal. */
@Override
public int removeAll(final ObjectLookupContainer<? super KType> c) {
return this.removeAll(c::contains);
}
/** Default implementation uses a predicate for retaining. */
@Override
public int retainAll(final ObjectLookupContainer<? super KType> c) {
// We know c holds sub-types of Object and we're not modifying c, so go unchecked.
return this.removeAll(k -> !c.contains(k));
}
/**
* Default implementation redirects to {@link #removeAll(ObjectPredicate)} and negates the
* predicate.
*/
@Override
public int retainAll(final ObjectPredicate<? super KType> predicate) {
return removeAll(value -> !predicate.apply(value));
}
/** Default implementation of copying to an array. */
@Override
public Object[] toArray() {
KType[] array = ((KType[]) new Object[size()]);
int i = 0;
for (ObjectCursor<KType> c : this) {
array[i++] = c.value;
}
return array;
}
public <T> T[] toArray(Class<T> componentClass) {
final int size = size();
final T[] array = (T[]) java.lang.reflect.Array.newInstance(componentClass, size);
int i = 0;
for (ObjectCursor<KType> c : this) {
array[i++] = (T) c.value;
}
return array;
}
/** Convert the contents of this container to a human-friendly string. */
@Override
public String toString() {
return Arrays.toString(this.toArray());
}
protected boolean equals(Object v1, Object v2) {
return (v1 == v2) || (v1 != null && v1.equals(v2));
}
}

View File

@ -0,0 +1,51 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.ShortCursor;
import com.carrotsearch.hppc.predicates.ShortPredicate;
import java.util.Arrays;
/** Common superclass for collections. */
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "AbstractKTypeCollection.java")
abstract class AbstractShortCollection implements ShortCollection {
/** Default implementation uses a predicate for removal. */
@Override
public int removeAll(final ShortLookupContainer c) {
return this.removeAll(c::contains);
}
/** Default implementation uses a predicate for retaining. */
@Override
public int retainAll(final ShortLookupContainer c) {
// We know c holds sub-types of short and we're not modifying c, so go unchecked.
return this.removeAll(k -> !c.contains(k));
}
/**
* Default implementation redirects to {@link #removeAll(ShortPredicate)} and negates the
* predicate.
*/
@Override
public int retainAll(final ShortPredicate predicate) {
return removeAll(value -> !predicate.apply(value));
}
/** Default implementation of copying to an array. */
@Override
public short[] toArray() {
short[] array = (new short[size()]);
int i = 0;
for (ShortCursor c : this) {
array[i++] = c.value;
}
return array;
}
/** Convert the contents of this container to a human-friendly string. */
@Override
public String toString() {
return Arrays.toString(this.toArray());
}
}

View File

@ -0,0 +1,31 @@
/*
* HPPC
*
* Copyright (C) 2010-2024 Carrot Search s.c. and contributors
* All rights reserved.
*
* Refer to the full license file "LICENSE.txt":
* https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt
*/
package com.carrotsearch.hppc;
/**
* Anything that could be accounted for memory usage
*
* <p>Partly forked from Lucene tag releases/lucene-solr/8.5.1
*/
public interface Accountable {
/**
* Allocated memory estimation
*
* @return Ram allocated in bytes
*/
long ramBytesAllocated();
/**
* Bytes that is actually been used
*
* @return Ram used in bytes
*/
long ramBytesUsed();
}

View File

@ -0,0 +1,27 @@
/*
* HPPC
*
* Copyright (C) 2010-2024 Carrot Search s.c. and contributors
* All rights reserved.
*
* Refer to the full license file "LICENSE.txt":
* https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt
*/
package com.carrotsearch.hppc;
/** Resizing (growth) strategy for array-backed buffers. */
public interface ArraySizingStrategy extends Accountable {
/**
* @param currentBufferLength Current size of the array (buffer). This number should comply with
* the strategy's policies (it is a result of initial rounding or further growCalls). It can
* also be zero, indicating the growth from an empty buffer.
* @param elementsCount Number of elements stored in the buffer.
* @param expectedAdditions Expected number of additions (resize hint).
* @return Must return a new size at least as big as to hold <code>
* elementsCount + expectedAdditions</code>.
* @throws BufferAllocationException If the sizing strategy cannot grow the buffer (for example
* due to constraints or memory limits).
*/
int grow(int currentBufferLength, int elementsCount, int expectedAdditions)
throws BufferAllocationException;
}

View File

@ -0,0 +1,120 @@
/*
* HPPC
*
* Copyright (C) 2010-2024 Carrot Search s.c. and contributors
* All rights reserved.
*
* Refer to the full license file "LICENSE.txt":
* https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt
*/
package com.carrotsearch.hppc;
/**
* Bit mixing utilities. The purpose of these methods is to evenly distribute key space over int32
* range.
*/
public final class BitMixer {
// Don't bother mixing very small key domains much.
public static int mix(byte key) {
return key * PHI_C32;
}
public static int mix(short key) {
return mixPhi(key);
}
public static int mix(char key) {
return mixPhi(key);
}
// Better mix for larger key domains.
public static int mix(int key) {
return mix32(key);
}
public static int mix(float key) {
return mix32(Float.floatToIntBits(key));
}
public static int mix(double key) {
return (int) mix64(Double.doubleToLongBits(key));
}
public static int mix(long key) {
return (int) mix64(key);
}
public static int mix(Object key) {
return key == null ? 0 : mix32(key.hashCode());
}
/** MH3's plain finalization step. */
public static int mix32(int k) {
k = (k ^ (k >>> 16)) * 0x85ebca6b;
k = (k ^ (k >>> 13)) * 0xc2b2ae35;
return k ^ (k >>> 16);
}
/**
* Computes David Stafford variant 9 of 64bit mix function (MH3 finalization step, with different
* shifts and constants).
*
* <p>Variant 9 is picked because it contains two 32-bit shifts which could be possibly optimized
* into better machine code.
*
* @see "http://zimbry.blogspot.com/2011/09/better-bit-mixing-improving-on.html"
*/
public static long mix64(long z) {
z = (z ^ (z >>> 32)) * 0x4cd6944c5cc20b6dL;
z = (z ^ (z >>> 29)) * 0xfc12c5b19d3259e9L;
return z ^ (z >>> 32);
}
/*
* Golden ratio bit mixers.
*/
private static final int PHI_C32 = 0x9e3779b9;
private static final long PHI_C64 = 0x9e3779b97f4a7c15L;
public static int mixPhi(byte k) {
final int h = k * PHI_C32;
return h ^ (h >>> 16);
}
public static int mixPhi(char k) {
final int h = k * PHI_C32;
return h ^ (h >>> 16);
}
public static int mixPhi(short k) {
final int h = k * PHI_C32;
return h ^ (h >>> 16);
}
public static int mixPhi(int k) {
final int h = k * PHI_C32;
return h ^ (h >>> 16);
}
public static int mixPhi(float k) {
final int h = Float.floatToIntBits(k) * PHI_C32;
return h ^ (h >>> 16);
}
public static int mixPhi(double k) {
final long h = Double.doubleToLongBits(k) * PHI_C64;
return (int) (h ^ (h >>> 32));
}
public static int mixPhi(long k) {
final long h = k * PHI_C64;
return (int) (h ^ (h >>> 32));
}
public static int mixPhi(Object k) {
final int h = (k == null ? 0 : k.hashCode() * PHI_C32);
return h ^ (h >>> 16);
}
}

View File

@ -0,0 +1,952 @@
/*
* HPPC
*
* Copyright (C) 2010-2024 Carrot Search s.c. and contributors
* All rights reserved.
*
* Refer to the full license file "LICENSE.txt":
* https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt
*/
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.IntCursor;
import com.carrotsearch.hppc.cursors.LongCursor;
import com.carrotsearch.hppc.predicates.IntPredicate;
import com.carrotsearch.hppc.predicates.LongPredicate;
import com.carrotsearch.hppc.procedures.IntProcedure;
import com.carrotsearch.hppc.procedures.LongProcedure;
import java.util.*;
/**
* An "open" BitSet implementation that allows direct access to the array of words storing the bits.
*
* <p>Unlike {@link java.util.BitSet}, the fact that bits are packed into an array of longs is part
* of the interface. This allows efficient implementation of other algorithms by someone other than
* the author. It also allows one to efficiently implement alternate serialization or interchange
* formats.
*
* <p>The index range for a bitset can easily exceed positive <code>int</code> range in Java
* (0x7fffffff), so many methods in this class accept or return a <code>long</code>. There are
* adapter methods that return views compatible with {@link LongLookupContainer} and {@link
* IntLookupContainer} interfaces.
*
* @see #asIntLookupContainer()
* @see #asLongLookupContainer()
*/
public class BitSet implements Cloneable {
/** The initial default number of bits. */
private static final long DEFAULT_NUM_BITS = 64;
/** Internal representation of bits in this bit set. */
public long[] bits;
/** The number of words (longs) used in the {@link #bits} array. */
public int wlen;
/** Constructs a bit set with the default capacity. */
public BitSet() {
this(DEFAULT_NUM_BITS);
}
/**
* Constructs an BitSet large enough to hold numBits.
*
* @param numBits Number of bits
*/
public BitSet(long numBits) {
bits = new long[bits2words(numBits)];
wlen = bits.length;
}
/**
* Constructs an BitSet from an existing long[].
*
* <p>The first 64 bits are in long[0], with bit index 0 at the least significant bit, and bit
* index 63 at the most significant. Given a bit index, the word containing it is long[index/64],
* and it is at bit number index%64 within that word.
*
* <p>numWords are the number of elements in the array that contain set bits (non-zero longs).
* numWords should be &lt;= bits.length, and any existing words in the array at position &gt;=
* numWords should be zero.
*
* @param bits underlying bits buffer
* @param numWords the number of elements in the array that contain set bits
*/
public BitSet(long[] bits, int numWords) {
this.bits = bits;
this.wlen = numWords;
}
/**
* Static constructor-like method similar to other (generic) collections.
*
* @return New instance.
*/
public static BitSet newInstance() {
return new BitSet();
}
/**
* @return Returns an iterator over all set bits of this bitset. The iterator should be faster
* than using a loop around {@link #nextSetBit(int)}.
*/
public BitSetIterator iterator() {
return new BitSetIterator(bits, wlen);
}
/**
* @return Returns the current capacity in bits (1 greater than the index of the last bit).
*/
public long capacity() {
return bits.length << 6;
}
/**
* @see #cardinality()
* @see java.util.BitSet#size()
* @return Returns the current capacity of this set. Included for compatibility. This is
* <b>not</b> equal to {@link #cardinality}.
*/
public long size() {
return capacity();
}
/**
* @see java.util.BitSet#length()
* @return Returns the "logical size" of this {@code BitSet}: the index of the highest set bit in
* the {@code BitSet} plus one.
*/
public long length() {
trimTrailingZeros();
if (wlen == 0) return 0;
return (((long) wlen - 1) << 6) + (64 - Long.numberOfLeadingZeros(bits[wlen - 1]));
}
/**
* @return Returns true if there are no set bits
*/
public boolean isEmpty() {
return cardinality() == 0;
}
/**
* @param index The index.
* @return Returns true or false for the specified bit index.
*/
public boolean get(int index) {
int i = index >> 6; // div 64
// signed shift will keep a negative index and force an
// array-index-out-of-bounds-exception, removing the need for an explicit check.
if (i >= bits.length) return false;
int bit = index & 0x3f; // mod 64
long bitmask = 1L << bit;
return (bits[i] & bitmask) != 0;
}
/**
* @param index The index.
* @return Returns true or false for the specified bit index.
*/
public boolean get(long index) {
int i = (int) (index >> 6); // div 64
if (i >= bits.length) return false;
int bit = (int) index & 0x3f; // mod 64
long bitmask = 1L << bit;
return (bits[i] & bitmask) != 0;
}
/**
* Sets a bit, expanding the set size if necessary.
*
* @param index the index to set
*/
public void set(long index) {
int wordNum = expandingWordNum(index);
int bit = (int) index & 0x3f;
long bitmask = 1L << bit;
bits[wordNum] |= bitmask;
}
/**
* Sets a range of bits, expanding the set size if necessary
*
* @param startIndex lower index
* @param endIndex one-past the last bit to set
*/
public void set(long startIndex, long endIndex) {
if (endIndex <= startIndex) return;
int startWord = (int) (startIndex >> 6);
// since endIndex is one past the end, this is index of the last
// word to be changed.
int endWord = expandingWordNum(endIndex - 1);
long startmask = -1L << startIndex;
long endmask = -1L >>> -endIndex; // 64-(endIndex&0x3f) is the same as -endIndex
// due to wrap
if (startWord == endWord) {
bits[startWord] |= (startmask & endmask);
return;
}
bits[startWord] |= startmask;
Arrays.fill(bits, startWord + 1, endWord, -1L);
bits[endWord] |= endmask;
}
protected int expandingWordNum(long index) {
int wordNum = (int) (index >> 6);
if (wordNum >= wlen) {
ensureCapacity(index + 1);
wlen = wordNum + 1;
}
return wordNum;
}
/** Clears all bits. */
public void clear() {
Arrays.fill(bits, 0);
this.wlen = 0;
}
/**
* clears a bit, allowing access beyond the current set size without changing the size.
*
* @param index the index to clear
*/
public void clear(long index) {
int wordNum = (int) (index >> 6); // div 64
if (wordNum >= wlen) return;
int bit = (int) index & 0x3f; // mod 64
long bitmask = 1L << bit;
bits[wordNum] &= ~bitmask;
}
/**
* Clears a range of bits. Clearing past the end does not change the size of the set.
*
* @param startIndex lower index
* @param endIndex one-past the last bit to clear
*/
public void clear(int startIndex, int endIndex) {
if (endIndex <= startIndex) return;
int startWord = (startIndex >> 6);
if (startWord >= wlen) return;
// since endIndex is one past the end, this is index of the last
// word to be changed.
int endWord = ((endIndex - 1) >> 6);
long startmask = -1L << startIndex;
long endmask = -1L >>> -endIndex; // 64-(endIndex&0x3f) is the same as -endIndex
// due to wrap
// invert masks since we are clearing
startmask = ~startmask;
endmask = ~endmask;
if (startWord == endWord) {
bits[startWord] &= (startmask | endmask);
return;
}
bits[startWord] &= startmask;
int middle = Math.min(wlen, endWord);
Arrays.fill(bits, startWord + 1, middle, 0L);
if (endWord < wlen) {
bits[endWord] &= endmask;
}
}
/**
* Clears a range of bits. Clearing past the end does not change the size of the set.
*
* @param startIndex lower index
* @param endIndex one-past the last bit to clear
*/
public void clear(long startIndex, long endIndex) {
if (endIndex <= startIndex) return;
int startWord = (int) (startIndex >> 6);
if (startWord >= wlen) return;
// since endIndex is one past the end, this is index of the last
// word to be changed.
int endWord = (int) ((endIndex - 1) >> 6);
long startmask = -1L << startIndex;
long endmask = -1L >>> -endIndex; // 64-(endIndex&0x3f) is the same as -endIndex
// due to wrap
// invert masks since we are clearing
startmask = ~startmask;
endmask = ~endmask;
if (startWord == endWord) {
bits[startWord] &= (startmask | endmask);
return;
}
bits[startWord] &= startmask;
int middle = Math.min(wlen, endWord);
Arrays.fill(bits, startWord + 1, middle, 0L);
if (endWord < wlen) {
bits[endWord] &= endmask;
}
}
/**
* Sets a bit and returns the previous value. The index should be less than the BitSet size.
*
* @param index the index to set
* @return previous state of the index
*/
public boolean getAndSet(int index) {
int wordNum = index >> 6; // div 64
int bit = index & 0x3f; // mod 64
long bitmask = 1L << bit;
boolean val = (bits[wordNum] & bitmask) != 0;
bits[wordNum] |= bitmask;
return val;
}
/**
* Sets a bit and returns the previous value. The index should be less than the BitSet size.
*
* @param index the index to set
* @return previous state of the index
*/
public boolean getAndSet(long index) {
int wordNum = (int) (index >> 6); // div 64
int bit = (int) index & 0x3f; // mod 64
long bitmask = 1L << bit;
boolean val = (bits[wordNum] & bitmask) != 0;
bits[wordNum] |= bitmask;
return val;
}
/**
* Flips a bit, expanding the set size if necessary.
*
* @param index the index to flip
*/
public void flip(long index) {
int wordNum = expandingWordNum(index);
int bit = (int) index & 0x3f; // mod 64
long bitmask = 1L << bit;
bits[wordNum] ^= bitmask;
}
/**
* flips a bit and returns the resulting bit value. The index should be less than the BitSet size.
*
* @param index the index to flip
* @return previous state of the index
*/
public boolean flipAndGet(int index) {
int wordNum = index >> 6; // div 64
int bit = index & 0x3f; // mod 64
long bitmask = 1L << bit;
bits[wordNum] ^= bitmask;
return (bits[wordNum] & bitmask) != 0;
}
/**
* flips a bit and returns the resulting bit value. The index should be less than the BitSet size.
*
* @param index the index to flip
* @return previous state of the index
*/
public boolean flipAndGet(long index) {
int wordNum = (int) (index >> 6); // div 64
int bit = (int) index & 0x3f; // mod 64
long bitmask = 1L << bit;
bits[wordNum] ^= bitmask;
return (bits[wordNum] & bitmask) != 0;
}
/**
* Flips a range of bits, expanding the set size if necessary
*
* @param startIndex lower index
* @param endIndex one-past the last bit to flip
*/
public void flip(long startIndex, long endIndex) {
if (endIndex <= startIndex) return;
int startWord = (int) (startIndex >> 6);
// since endIndex is one past the end, this is index of the last
// word to be changed.
int endWord = expandingWordNum(endIndex - 1);
long startmask = -1L << startIndex;
long endmask = -1L >>> -endIndex; // 64-(endIndex&0x3f) is the same as -endIndex
// due to wrap
if (startWord == endWord) {
bits[startWord] ^= (startmask & endmask);
return;
}
bits[startWord] ^= startmask;
for (int i = startWord + 1; i < endWord; i++) {
bits[i] = ~bits[i];
}
bits[endWord] ^= endmask;
}
/**
* @return the number of set bits
*/
public long cardinality() {
return BitUtil.pop_array(bits, 0, wlen);
}
/**
* @param a The first set
* @param b The second set
* @return Returns the popcount or cardinality of the intersection of the two sets. Neither set is
* modified.
*/
public static long intersectionCount(BitSet a, BitSet b) {
return BitUtil.pop_intersect(a.bits, b.bits, 0, Math.min(a.wlen, b.wlen));
}
/**
* @param a The first set
* @param b The second set
* @return Returns the popcount or cardinality of the union of the two sets. Neither set is
* modified.
*/
public static long unionCount(BitSet a, BitSet b) {
long tot = BitUtil.pop_union(a.bits, b.bits, 0, Math.min(a.wlen, b.wlen));
if (a.wlen < b.wlen) {
tot += BitUtil.pop_array(b.bits, a.wlen, b.wlen - a.wlen);
} else if (a.wlen > b.wlen) {
tot += BitUtil.pop_array(a.bits, b.wlen, a.wlen - b.wlen);
}
return tot;
}
/**
* @param a The first set
* @param b The second set
* @return Returns the popcount or cardinality of "a and not b" or "intersection(a, not(b))".
* Neither set is modified.
*/
public static long andNotCount(BitSet a, BitSet b) {
long tot = BitUtil.pop_andnot(a.bits, b.bits, 0, Math.min(a.wlen, b.wlen));
if (a.wlen > b.wlen) {
tot += BitUtil.pop_array(a.bits, b.wlen, a.wlen - b.wlen);
}
return tot;
}
/**
* @param a The first set
* @param b The second set
* @return Returns the popcount or cardinality of the exclusive-or of the two sets. Neither set is
* modified.
*/
public static long xorCount(BitSet a, BitSet b) {
long tot = BitUtil.pop_xor(a.bits, b.bits, 0, Math.min(a.wlen, b.wlen));
if (a.wlen < b.wlen) {
tot += BitUtil.pop_array(b.bits, a.wlen, b.wlen - a.wlen);
} else if (a.wlen > b.wlen) {
tot += BitUtil.pop_array(a.bits, b.wlen, a.wlen - b.wlen);
}
return tot;
}
/**
* @param index The index to start scanning from, inclusive.
* @return Returns the index of the first set bit starting at the index specified. -1 is returned
* if there are no more set bits.
*/
public int nextSetBit(int index) {
int i = index >> 6;
if (i >= wlen) return -1;
int subIndex = index & 0x3f; // index within the word
long word = bits[i] >> subIndex; // skip all the bits to the right of index
if (word != 0) {
return (i << 6) + subIndex + Long.numberOfTrailingZeros(word);
}
while (++i < wlen) {
word = bits[i];
if (word != 0) return (i << 6) + Long.numberOfTrailingZeros(word);
}
return -1;
}
/**
* @param index The index to start scanning from, inclusive.
* @return Returns the index of the first set bit starting at the index specified. -1 is returned
* if there are no more set bits.
*/
public long nextSetBit(long index) {
int i = (int) (index >>> 6);
if (i >= wlen) return -1;
int subIndex = (int) index & 0x3f; // index within the word
long word = bits[i] >>> subIndex; // skip all the bits to the right of index
if (word != 0) {
return (((long) i) << 6) + (subIndex + Long.numberOfTrailingZeros(word));
}
while (++i < wlen) {
word = bits[i];
if (word != 0) return (((long) i) << 6) + Long.numberOfTrailingZeros(word);
}
return -1;
}
@Override
public Object clone() {
try {
BitSet obs = (BitSet) super.clone();
obs.bits = (long[]) obs.bits.clone(); // hopefully an array clone is as
// fast(er) than arraycopy
return obs;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
/**
* this = this AND other
*
* @param other The bitset to intersect with.
*/
public void intersect(BitSet other) {
int newLen = Math.min(this.wlen, other.wlen);
long[] thisArr = this.bits;
long[] otherArr = other.bits;
// testing against zero can be more efficient
int pos = newLen;
while (--pos >= 0) {
thisArr[pos] &= otherArr[pos];
}
if (this.wlen > newLen) {
// fill zeros from the new shorter length to the old length
Arrays.fill(bits, newLen, this.wlen, 0);
}
this.wlen = newLen;
}
/**
* this = this OR other
*
* @param other The bitset to union with.
*/
public void union(BitSet other) {
int newLen = Math.max(wlen, other.wlen);
ensureCapacityWords(newLen);
long[] thisArr = this.bits;
long[] otherArr = other.bits;
int pos = Math.min(wlen, other.wlen);
while (--pos >= 0) {
thisArr[pos] |= otherArr[pos];
}
if (this.wlen < newLen) {
System.arraycopy(otherArr, this.wlen, thisArr, this.wlen, newLen - this.wlen);
}
this.wlen = newLen;
}
/**
* Remove all elements set in other: this = this AND_NOT other
*
* @param other The other bitset.
*/
public void remove(BitSet other) {
int idx = Math.min(wlen, other.wlen);
long[] thisArr = this.bits;
long[] otherArr = other.bits;
while (--idx >= 0) {
thisArr[idx] &= ~otherArr[idx];
}
}
/**
* this = this XOR other
*
* @param other The other bitset.
*/
public void xor(BitSet other) {
int newLen = Math.max(wlen, other.wlen);
ensureCapacityWords(newLen);
long[] thisArr = this.bits;
long[] otherArr = other.bits;
int pos = Math.min(wlen, other.wlen);
while (--pos >= 0) {
thisArr[pos] ^= otherArr[pos];
}
if (this.wlen < newLen) {
System.arraycopy(otherArr, this.wlen, thisArr, this.wlen, newLen - this.wlen);
}
this.wlen = newLen;
}
// some BitSet compatibility methods
// ** see {@link intersect} */
public void and(BitSet other) {
intersect(other);
}
// ** see {@link union} */
public void or(BitSet other) {
union(other);
}
// ** see {@link andNot} */
public void andNot(BitSet other) {
remove(other);
}
/**
* @param other The other bitset.
* @return true if the sets have any elements in common
*/
public boolean intersects(BitSet other) {
int pos = Math.min(this.wlen, other.wlen);
long[] thisArr = this.bits;
long[] otherArr = other.bits;
while (--pos >= 0) {
if ((thisArr[pos] & otherArr[pos]) != 0) return true;
}
return false;
}
/**
* Expand the long[] with the size given as a number of words (64 bit longs). getNumWords() is
* unchanged by this call.
*
* @param numWords The size to expand to (64-bit long words)
*/
public void ensureCapacityWords(int numWords) {
if (bits.length < numWords) {
bits = grow(bits, numWords);
}
}
public static long[] grow(long[] array, int minSize) {
if (array.length < minSize) {
long[] newArray = new long[getNextSize(minSize)];
System.arraycopy(array, 0, newArray, 0, array.length);
return newArray;
} else return array;
}
public static int getNextSize(int targetSize) {
/*
* This over-allocates proportional to the list size, making room for additional
* growth. The over-allocation is mild, but is enough to give linear-time
* amortized behavior over a long sequence of appends() in the presence of a
* poorly-performing system realloc(). The growth pattern is: 0, 4, 8, 16, 25, 35,
* 46, 58, 72, 88, ...
*/
return (targetSize >> 3) + (targetSize < 9 ? 3 : 6) + targetSize;
}
/**
* Ensure that the long[] is big enough to hold numBits, expanding it if necessary. getNumWords()
* is unchanged by this call.
*
* @param numBits The number of bits to expand to
*/
public void ensureCapacity(long numBits) {
ensureCapacityWords(bits2words(numBits));
}
/** Lowers {@link #wlen}, the number of words in use, by checking for trailing zero words. */
public void trimTrailingZeros() {
int idx = wlen - 1;
while (idx >= 0 && bits[idx] == 0) idx--;
wlen = idx + 1;
}
/*
* returns the number of 64 bit words it would take to hold numBits
*/
public static int bits2words(long numBits) {
return (int) (((numBits - 1) >>> 6) + 1);
}
/* returns true if both sets have the same bits set */
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof BitSet)) return false;
BitSet a;
BitSet b = (BitSet) o;
// make a the larger set.
if (b.wlen > this.wlen) {
a = b;
b = this;
} else {
a = this;
}
// check for any set bits out of the range of b
for (int i = a.wlen - 1; i >= b.wlen; i--) {
if (a.bits[i] != 0) return false;
}
for (int i = b.wlen - 1; i >= 0; i--) {
if (a.bits[i] != b.bits[i]) return false;
}
return true;
}
@Override
public int hashCode() {
// Start with a zero hash and use a mix that results in zero if the input is zero.
// This effectively truncates trailing zeros without an explicit check.
long h = 0;
for (int i = bits.length; --i >= 0; ) {
h ^= bits[i];
h = (h << 1) | (h >>> 63); // rotate left
}
// fold leftmost bits into right and add a constant to prevent
// empty sets from returning 0, which is too common.
return (int) ((h >> 32) ^ h) + 0x98761234;
}
@Override
public String toString() {
long bit = nextSetBit(0);
if (bit < 0) {
return "{}";
}
final StringBuilder builder = new StringBuilder();
builder.append("{");
builder.append(Long.toString(bit));
while ((bit = nextSetBit(bit + 1)) >= 0) {
builder.append(", ");
builder.append(Long.toString(bit));
}
builder.append("}");
return builder.toString();
}
/**
* Returns a view over this bitset data compatible with {@link IntLookupContainer}. A new object
* is always returned, but its methods reflect the current state of the bitset (the view is not a
* snapshot).
*
* <p>Methods of the returned {@link IntLookupContainer} may throw a {@link RuntimeException} if
* the cardinality of this bitset exceeds the int range.
*
* @return The view of this bitset as {@link IntLookupContainer}.
*/
public IntLookupContainer asIntLookupContainer() {
return new IntLookupContainer() {
@Override
public int size() {
return getCurrentCardinality();
}
@Override
public boolean isEmpty() {
return BitSet.this.isEmpty();
}
@Override
public Iterator<IntCursor> iterator() {
return new Iterator<IntCursor>() {
private long nextBitSet = BitSet.this.nextSetBit(0);
private final IntCursor cursor = new IntCursor();
@Override
public boolean hasNext() {
return nextBitSet >= 0;
}
@Override
public IntCursor next() {
final long value = nextBitSet;
if (value < 0) throw new NoSuchElementException();
if (value > Integer.MAX_VALUE)
throw new RuntimeException("BitSet range larger than maximum positive integer.");
nextBitSet = BitSet.this.nextSetBit(value + 1);
cursor.index = cursor.value = (int) value;
return cursor;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
@Override
public int[] toArray() {
final int[] data = new int[getCurrentCardinality()];
final BitSetIterator i = BitSet.this.iterator();
for (int j = 0, bit = i.nextSetBit(); bit >= 0; bit = i.nextSetBit()) {
data[j++] = bit;
}
return data;
}
@Override
public <T extends IntPredicate> T forEach(T predicate) {
final BitSetIterator i = BitSet.this.iterator();
for (int bit = i.nextSetBit(); bit >= 0; bit = i.nextSetBit()) {
if (predicate.apply(bit) == false) break;
}
return predicate;
}
@Override
public <T extends IntProcedure> T forEach(T procedure) {
final BitSetIterator i = BitSet.this.iterator();
for (int bit = i.nextSetBit(); bit >= 0; bit = i.nextSetBit()) {
procedure.apply(bit);
}
return procedure;
}
@Override
public boolean contains(int index) {
return index < 0 || BitSet.this.get(index);
}
/**
* Rounds the bitset's cardinality to an integer or throws a {@link RuntimeException} if the
* cardinality exceeds maximum int range.
*/
private int getCurrentCardinality() {
long cardinality = BitSet.this.cardinality();
if (cardinality > Integer.MAX_VALUE)
throw new RuntimeException(
"Bitset is larger than maximum positive integer: " + cardinality);
return (int) cardinality;
}
};
}
/**
* Returns a view over this bitset data compatible with {@link LongLookupContainer}. A new object
* is always returned, but its methods reflect the current state of the bitset (the view is not a
* snapshot).
*
* @return The view of this bitset as {@link LongLookupContainer}.
*/
public LongLookupContainer asLongLookupContainer() {
return new LongLookupContainer() {
@Override
public int size() {
return getCurrentCardinality();
}
@Override
public boolean isEmpty() {
return BitSet.this.isEmpty();
}
@Override
public Iterator<LongCursor> iterator() {
return new Iterator<LongCursor>() {
private long nextBitSet = BitSet.this.nextSetBit(0);
private final LongCursor cursor = new LongCursor();
@Override
public boolean hasNext() {
return nextBitSet >= 0;
}
@Override
public LongCursor next() {
final long value = nextBitSet;
if (value < 0) throw new NoSuchElementException();
nextBitSet = BitSet.this.nextSetBit(value + 1);
cursor.index = (int) value;
cursor.value = value;
return cursor;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
}
@Override
public long[] toArray() {
final long[] data = new long[getCurrentCardinality()];
final BitSet bset = BitSet.this;
int j = 0;
for (long bit = bset.nextSetBit((long) 0); bit >= 0; bit = bset.nextSetBit(bit + 1)) {
data[j++] = bit;
}
return data;
}
@Override
public <T extends LongPredicate> T forEach(T predicate) {
final BitSet bset = BitSet.this;
for (long bit = bset.nextSetBit((long) 0); bit >= 0; bit = bset.nextSetBit(bit + 1)) {
if (predicate.apply(bit) == false) break;
}
return predicate;
}
@Override
public <T extends LongProcedure> T forEach(T procedure) {
final BitSet bset = BitSet.this;
for (long bit = bset.nextSetBit((long) 0); bit >= 0; bit = bset.nextSetBit(bit + 1)) {
procedure.apply(bit);
}
return procedure;
}
@Override
public boolean contains(long index) {
return index < 0 || BitSet.this.get(index);
}
/**
* Rounds the bitset's cardinality to an integer or throws a {@link RuntimeException} if the
* cardinality exceeds maximum int range.
*/
private int getCurrentCardinality() {
long cardinality = BitSet.this.cardinality();
if (cardinality > Integer.MAX_VALUE)
throw new RuntimeException(
"Bitset is larger than maximum positive integer: " + cardinality);
return (int) cardinality;
}
};
}
}

View File

@ -0,0 +1,356 @@
/*
* HPPC
*
* Copyright (C) 2010-2024 Carrot Search s.c. and contributors
* All rights reserved.
*
* Refer to the full license file "LICENSE.txt":
* https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt
*/
package com.carrotsearch.hppc;
/**
* An iterator to iterate over set bits in an BitSet. This is faster than nextSetBit() for iterating
* over the complete set of bits, especially when the density of the bits set is high.
*/
public class BitSetIterator {
// The General Idea: instead of having an array per byte that has
// the offsets of the next set bit, that array could be
// packed inside a 32 bit integer (8 4 bit numbers). That
// should be faster than accessing an array for each index, and
// the total array size is kept smaller (256*sizeof(int))=1K
static final int[] bitlist = {
0x0,
0x1,
0x2,
0x21,
0x3,
0x31,
0x32,
0x321,
0x4,
0x41,
0x42,
0x421,
0x43,
0x431,
0x432,
0x4321,
0x5,
0x51,
0x52,
0x521,
0x53,
0x531,
0x532,
0x5321,
0x54,
0x541,
0x542,
0x5421,
0x543,
0x5431,
0x5432,
0x54321,
0x6,
0x61,
0x62,
0x621,
0x63,
0x631,
0x632,
0x6321,
0x64,
0x641,
0x642,
0x6421,
0x643,
0x6431,
0x6432,
0x64321,
0x65,
0x651,
0x652,
0x6521,
0x653,
0x6531,
0x6532,
0x65321,
0x654,
0x6541,
0x6542,
0x65421,
0x6543,
0x65431,
0x65432,
0x654321,
0x7,
0x71,
0x72,
0x721,
0x73,
0x731,
0x732,
0x7321,
0x74,
0x741,
0x742,
0x7421,
0x743,
0x7431,
0x7432,
0x74321,
0x75,
0x751,
0x752,
0x7521,
0x753,
0x7531,
0x7532,
0x75321,
0x754,
0x7541,
0x7542,
0x75421,
0x7543,
0x75431,
0x75432,
0x754321,
0x76,
0x761,
0x762,
0x7621,
0x763,
0x7631,
0x7632,
0x76321,
0x764,
0x7641,
0x7642,
0x76421,
0x7643,
0x76431,
0x76432,
0x764321,
0x765,
0x7651,
0x7652,
0x76521,
0x7653,
0x76531,
0x76532,
0x765321,
0x7654,
0x76541,
0x76542,
0x765421,
0x76543,
0x765431,
0x765432,
0x7654321,
0x8,
0x81,
0x82,
0x821,
0x83,
0x831,
0x832,
0x8321,
0x84,
0x841,
0x842,
0x8421,
0x843,
0x8431,
0x8432,
0x84321,
0x85,
0x851,
0x852,
0x8521,
0x853,
0x8531,
0x8532,
0x85321,
0x854,
0x8541,
0x8542,
0x85421,
0x8543,
0x85431,
0x85432,
0x854321,
0x86,
0x861,
0x862,
0x8621,
0x863,
0x8631,
0x8632,
0x86321,
0x864,
0x8641,
0x8642,
0x86421,
0x8643,
0x86431,
0x86432,
0x864321,
0x865,
0x8651,
0x8652,
0x86521,
0x8653,
0x86531,
0x86532,
0x865321,
0x8654,
0x86541,
0x86542,
0x865421,
0x86543,
0x865431,
0x865432,
0x8654321,
0x87,
0x871,
0x872,
0x8721,
0x873,
0x8731,
0x8732,
0x87321,
0x874,
0x8741,
0x8742,
0x87421,
0x8743,
0x87431,
0x87432,
0x874321,
0x875,
0x8751,
0x8752,
0x87521,
0x8753,
0x87531,
0x87532,
0x875321,
0x8754,
0x87541,
0x87542,
0x875421,
0x87543,
0x875431,
0x875432,
0x8754321,
0x876,
0x8761,
0x8762,
0x87621,
0x8763,
0x87631,
0x87632,
0x876321,
0x8764,
0x87641,
0x87642,
0x876421,
0x87643,
0x876431,
0x876432,
0x8764321,
0x8765,
0x87651,
0x87652,
0x876521,
0x87653,
0x876531,
0x876532,
0x8765321,
0x87654,
0x876541,
0x876542,
0x8765421,
0x876543,
0x8765431,
0x8765432,
0x87654321
};
/**
* *** the python code that generated bitlist def bits2int(val): arr=0 for shift in range(8,0,-1):
* if val & 0x80: arr = (arr << 4) | shift val = val << 1 return arr
*
* <p>def int_table(): tbl = [ hex(bits2int(val)).strip('L') for val in range(256) ] return
* ','.join(tbl) ****
*/
// hmmm, what about an iterator that finds zeros though,
// or a reverse iterator... should they be separate classes
// for efficiency, or have a common root interface? (or
// maybe both? could ask for a SetBitsIterator, etc...
private final long[] arr;
private final int words;
private int i = -1;
private long word;
private int wordShift;
private int indexArray;
public BitSetIterator(BitSet obs) {
this(obs.bits, obs.wlen);
}
public BitSetIterator(long[] bits, int numWords) {
arr = bits;
words = numWords;
}
// 64 bit shifts
private void shift() {
if ((int) word == 0) {
wordShift += 32;
word = word >>> 32;
}
if ((word & 0x0000FFFF) == 0) {
wordShift += 16;
word >>>= 16;
}
if ((word & 0x000000FF) == 0) {
wordShift += 8;
word >>>= 8;
}
indexArray = bitlist[(int) word & 0xff];
}
public static final int NO_MORE = -1;
public int nextSetBit() {
if (indexArray == 0) {
if (word != 0) {
word >>>= 8;
wordShift += 8;
}
while (word == 0) {
if (++i >= words) {
return NO_MORE;
}
word = arr[i];
wordShift = -1; // loop invariant code motion should move this
}
// after the first time, should I go with a linear search, or
// stick with the binary search in shift?
shift();
}
int bitIndex = (indexArray & 0x0f) + wordShift;
indexArray >>>= 4;
// should i<<6 be cached as a separate variable?
// it would only save one cycle in the best circumstances.
return (i << 6) + bitIndex;
}
}

View File

@ -0,0 +1,98 @@
/*
* HPPC
*
* Copyright (C) 2010-2024 Carrot Search s.c. and contributors
* All rights reserved.
*
* Refer to the full license file "LICENSE.txt":
* https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt
*/
package com.carrotsearch.hppc;
/** A variety of high efficiency bit twiddling routines. */
final class BitUtil {
private BitUtil() {} // no instance
// The pop methods used to rely on bit-manipulation tricks for speed but it
// turns out that it is faster to use the Long.bitCount method (which is an
// intrinsic since Java 6u18) in a naive loop, see LUCENE-2221
/** Returns the number of set bits in an array of longs. */
public static long pop_array(long[] arr, int wordOffset, int numWords) {
long popCount = 0;
for (int i = wordOffset, end = wordOffset + numWords; i < end; ++i) {
popCount += Long.bitCount(arr[i]);
}
return popCount;
}
/**
* Returns the popcount or cardinality of the two sets after an intersection. Neither array is
* modified.
*/
public static long pop_intersect(long[] arr1, long[] arr2, int wordOffset, int numWords) {
long popCount = 0;
for (int i = wordOffset, end = wordOffset + numWords; i < end; ++i) {
popCount += Long.bitCount(arr1[i] & arr2[i]);
}
return popCount;
}
/** Returns the popcount or cardinality of the union of two sets. Neither array is modified. */
public static long pop_union(long[] arr1, long[] arr2, int wordOffset, int numWords) {
long popCount = 0;
for (int i = wordOffset, end = wordOffset + numWords; i < end; ++i) {
popCount += Long.bitCount(arr1[i] | arr2[i]);
}
return popCount;
}
/** Returns the popcount or cardinality of A &amp; ~B. Neither array is modified. */
public static long pop_andnot(long[] arr1, long[] arr2, int wordOffset, int numWords) {
long popCount = 0;
for (int i = wordOffset, end = wordOffset + numWords; i < end; ++i) {
popCount += Long.bitCount(arr1[i] & ~arr2[i]);
}
return popCount;
}
/** Returns the popcount or cardinality of A ^ B Neither array is modified. */
public static long pop_xor(long[] arr1, long[] arr2, int wordOffset, int numWords) {
long popCount = 0;
for (int i = wordOffset, end = wordOffset + numWords; i < end; ++i) {
popCount += Long.bitCount(arr1[i] ^ arr2[i]);
}
return popCount;
}
/**
* returns the next highest power of two, or the current value if it's already a power of two or
* zero
*/
public static int nextHighestPowerOfTwo(int v) {
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
return v;
}
/**
* returns the next highest power of two, or the current value if it's already a power of two or
* zero
*/
public static long nextHighestPowerOfTwo(long v) {
v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v |= v >> 32;
v++;
return v;
}
}

View File

@ -0,0 +1,115 @@
/*
* HPPC
*
* Copyright (C) 2010-2024 Carrot Search s.c. and contributors
* All rights reserved.
*
* Refer to the full license file "LICENSE.txt":
* https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt
*/
package com.carrotsearch.hppc;
import java.util.ArrayList;
/**
* Array resizing proportional to the current buffer size, optionally kept within the given minimum
* and maximum growth limits. Java's {@link ArrayList} uses:
*
* <pre>
* minGrow = 1
* maxGrow = Integer.MAX_VALUE (unbounded)
* growRatio = 1.5f
* </pre>
*/
public final class BoundedProportionalArraySizingStrategy implements ArraySizingStrategy {
/** Instance of {@link BoundedProportionalArraySizingStrategy} with default values. */
public static final BoundedProportionalArraySizingStrategy DEFAULT_INSTANCE =
new BoundedProportionalArraySizingStrategy();
/**
* Maximum allocable array length (approximately the largest positive integer decreased by the
* array's object header).
*/
public static final int MAX_ARRAY_LENGTH =
Integer.MAX_VALUE - /* aligned array header + slack */ 32;
/** Minimum grow count. */
public static final int DEFAULT_MIN_GROW_COUNT = 10;
/** Maximum grow count (unbounded). */
public static final int DEFAULT_MAX_GROW_COUNT = MAX_ARRAY_LENGTH;
/** Default resize is by half the current buffer's size. */
public static final float DEFAULT_GROW_RATIO = 1.5f;
/** Minimum number of elements to grow, if limit exceeded. */
public final int minGrowCount;
/** Maximum number of elements to grow, if limit exceeded. */
public final int maxGrowCount;
/**
* The current buffer length is multiplied by this ratio to get the first estimate for the new
* size. To double the size of the current buffer, for example, set to <code>2</code>.
*/
public final float growRatio;
/** Create the default sizing strategy. */
public BoundedProportionalArraySizingStrategy() {
this(DEFAULT_MIN_GROW_COUNT, DEFAULT_MAX_GROW_COUNT, DEFAULT_GROW_RATIO);
}
/**
* Create the sizing strategy with custom policies.
*
* @param minGrow Minimum number of elements to grow by when expanding.
* @param maxGrow Maximum number of elements to grow by when expanding.
* @param ratio The ratio of expansion compared to the previous buffer size.
*/
public BoundedProportionalArraySizingStrategy(int minGrow, int maxGrow, float ratio) {
assert minGrow >= 1 : "Min grow must be >= 1.";
assert maxGrow >= minGrow : "Max grow must be >= min grow.";
assert ratio >= 1f : "Growth ratio must be >= 1 (was " + ratio + ").";
this.minGrowCount = minGrow;
this.maxGrowCount = maxGrow;
this.growRatio = ratio - 1.0f;
}
/**
* Grow according to {@link #growRatio}, {@link #minGrowCount} and {@link #maxGrowCount}.
*
* @param currentBufferLength The current length of the buffer.
* @param elementsCount The number of elements stored in the buffer.
* @param expectedAdditions The number of expected additions to the buffer.
* @return New buffer size.
*/
public int grow(int currentBufferLength, int elementsCount, int expectedAdditions) {
long growBy = (long) ((long) currentBufferLength * growRatio);
growBy = Math.max(growBy, minGrowCount);
growBy = Math.min(growBy, maxGrowCount);
long growTo = Math.min(MAX_ARRAY_LENGTH, growBy + currentBufferLength);
long newSize = Math.max((long) elementsCount + expectedAdditions, growTo);
if (newSize > MAX_ARRAY_LENGTH) {
throw new BufferAllocationException(
"Java array size exceeded (current length: %d, elements: %d, expected additions: %d)",
currentBufferLength, elementsCount, expectedAdditions);
}
return (int) newSize;
}
@Override
public long ramBytesAllocated() {
// int: minGrowCount, maxGrowCount
// float: growRatio
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER + Integer.BYTES * 2 + Float.BYTES;
}
@Override
public long ramBytesUsed() {
return ramBytesAllocated();
}
}

View File

@ -0,0 +1,41 @@
/*
* HPPC
*
* Copyright (C) 2010-2024 Carrot Search s.c. and contributors
* All rights reserved.
*
* Refer to the full license file "LICENSE.txt":
* https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt
*/
package com.carrotsearch.hppc;
import java.util.IllegalFormatException;
import java.util.Locale;
public class BufferAllocationException extends RuntimeException {
public BufferAllocationException(String message) {
super(message);
}
public BufferAllocationException(String message, Object... args) {
this(message, null, args);
}
public BufferAllocationException(String message, Throwable t, Object... args) {
super(formatMessage(message, t, args), t);
}
private static String formatMessage(String message, Throwable t, Object... args) {
try {
return String.format(Locale.ROOT, message, args);
} catch (IllegalFormatException e) {
BufferAllocationException substitute =
new BufferAllocationException(message + " [ILLEGAL FORMAT, ARGS SUPPRESSED]");
if (t != null) {
substitute.addSuppressed(t);
}
substitute.addSuppressed(e);
throw substitute;
}
}
}

View File

@ -0,0 +1,776 @@
package com.carrotsearch.hppc;
import static com.carrotsearch.hppc.Containers.*;
import com.carrotsearch.hppc.cursors.ByteCursor;
import com.carrotsearch.hppc.predicates.BytePredicate;
import com.carrotsearch.hppc.procedures.ByteProcedure;
import java.util.*;
/** An array-backed {@link ByteDeque}. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayDeque.java")
public class ByteArrayDeque extends AbstractByteCollection
implements ByteDeque, Preallocable, Cloneable, Accountable {
/** Reuse the same strategy instance. */
private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY =
BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE;
/** Internal array for storing elements of the deque. */
public byte[] buffer = ByteArrayList.EMPTY_ARRAY;
/**
* The index of the element at the head of the deque or an arbitrary number equal to tail if the
* deque is empty.
*/
public int head;
/** The index at which the next element would be added to the tail of the deque. */
public int tail;
/** Buffer resizing strategy. */
protected final ArraySizingStrategy resizer;
/** New instance with sane defaults. */
public ByteArrayDeque() {
this(DEFAULT_EXPECTED_ELEMENTS);
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
*/
public ByteArrayDeque(int expectedElements) {
this(expectedElements, DEFAULT_SIZING_STRATEGY);
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
* @param resizer Underlying buffer sizing strategy.
*/
public ByteArrayDeque(int expectedElements, ArraySizingStrategy resizer) {
assert resizer != null;
this.resizer = resizer;
ensureCapacity(expectedElements);
}
/**
* Creates a new deque from elements of another container, appending elements at the end of the
* deque in the iteration order.
*/
public ByteArrayDeque(ByteContainer container) {
this(container.size());
addLast(container);
}
/** {@inheritDoc} */
@Override
public void addFirst(byte e1) {
int h = oneLeft(head, buffer.length);
if (h == tail) {
ensureBufferSpace(1);
h = oneLeft(head, buffer.length);
}
buffer[head = h] = e1;
}
/**
* Vararg-signature method for adding elements at the front of this deque.
*
* <p><b>This method is handy, but costly if used in tight loops (anonymous array passing)</b>
*
* @param elements The elements to add.
*/
public final void addFirst(byte... elements) {
ensureBufferSpace(elements.length);
for (byte k : elements) {
addFirst(k);
}
}
/**
* Inserts all elements from the given container to the front of this deque.
*
* @param container The container to iterate over.
* @return Returns the number of elements actually added as a result of this call.
*/
public int addFirst(ByteContainer container) {
int size = container.size();
ensureBufferSpace(size);
for (ByteCursor cursor : container) {
addFirst(cursor.value);
}
return size;
}
/**
* Inserts all elements from the given iterable to the front of this deque.
*
* @param iterable The iterable to iterate over.
* @return Returns the number of elements actually added as a result of this call.
*/
public int addFirst(Iterable<? extends ByteCursor> iterable) {
int size = 0;
for (ByteCursor cursor : iterable) {
addFirst(cursor.value);
size++;
}
return size;
}
/** {@inheritDoc} */
@Override
public void addLast(byte e1) {
int t = oneRight(tail, buffer.length);
if (head == t) {
ensureBufferSpace(1);
t = oneRight(tail, buffer.length);
}
buffer[tail] = e1;
tail = t;
}
/**
* Vararg-signature method for adding elements at the end of this deque.
*
* <p><b>This method is handy, but costly if used in tight loops (anonymous array passing)</b>
*
* @param elements The elements to iterate over.
*/
public final void addLast(byte... elements) {
ensureBufferSpace(1);
for (byte k : elements) {
addLast(k);
}
}
/**
* Inserts all elements from the given container to the end of this deque.
*
* @param container The container to iterate over.
* @return Returns the number of elements actually added as a result of this call.
*/
public int addLast(ByteContainer container) {
int size = container.size();
ensureBufferSpace(size);
for (ByteCursor cursor : container) {
addLast(cursor.value);
}
return size;
}
/**
* Inserts all elements from the given iterable to the end of this deque.
*
* @param iterable The iterable to iterate over.
* @return Returns the number of elements actually added as a result of this call.
*/
public int addLast(Iterable<? extends ByteCursor> iterable) {
int size = 0;
for (ByteCursor cursor : iterable) {
addLast(cursor.value);
size++;
}
return size;
}
/** {@inheritDoc} */
@Override
public byte removeFirst() {
assert size() > 0 : "The deque is empty.";
final byte result = buffer[head];
buffer[head] = ((byte) 0);
head = oneRight(head, buffer.length);
return result;
}
/** {@inheritDoc} */
@Override
public byte removeLast() {
assert size() > 0 : "The deque is empty.";
tail = oneLeft(tail, buffer.length);
final byte result = buffer[tail];
buffer[tail] = ((byte) 0);
return result;
}
/** {@inheritDoc} */
@Override
public byte getFirst() {
assert size() > 0 : "The deque is empty.";
return buffer[head];
}
/** {@inheritDoc} */
@Override
public byte getLast() {
assert size() > 0 : "The deque is empty.";
return buffer[oneLeft(tail, buffer.length)];
}
/** {@inheritDoc} */
@Override
public int removeFirst(byte e1) {
final int index = bufferIndexOf(e1);
if (index >= 0) removeAtBufferIndex(index);
return index;
}
/**
* Return the index of the first (counting from head) element equal to <code>e1</code>. The index
* points to the {@link #buffer} array.
*
* @param e1 The element to look for.
* @return Returns the index of the first element equal to <code>e1</code> or <code>-1</code> if
* not found.
*/
public int bufferIndexOf(byte e1) {
final int last = tail;
final int bufLen = buffer.length;
for (int i = head; i != last; i = oneRight(i, bufLen)) {
if (((e1) == (buffer[i]))) {
return i;
}
}
return -1;
}
/** {@inheritDoc} */
@Override
public int removeLast(byte e1) {
final int index = lastBufferIndexOf(e1);
if (index >= 0) {
removeAtBufferIndex(index);
}
return index;
}
/**
* Return the index of the last (counting from tail) element equal to <code>e1</code>. The index
* points to the {@link #buffer} array.
*
* @param e1 The element to look for.
* @return Returns the index of the first element equal to <code>e1</code> or <code>-1</code> if
* not found.
*/
public int lastBufferIndexOf(byte e1) {
final int bufLen = buffer.length;
final int last = oneLeft(head, bufLen);
for (int i = oneLeft(tail, bufLen); i != last; i = oneLeft(i, bufLen)) {
if (((e1) == (buffer[i]))) return i;
}
return -1;
}
/** {@inheritDoc} */
@Override
public int removeAll(byte e1) {
int removed = 0;
final int last = tail;
final int bufLen = buffer.length;
int from, to;
for (from = to = head; from != last; from = oneRight(from, bufLen)) {
if (((e1) == (buffer[from]))) {
buffer[from] = ((byte) 0);
removed++;
continue;
}
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = ((byte) 0);
}
to = oneRight(to, bufLen);
}
tail = to;
return removed;
}
/**
* Removes the element at <code>index</code> in the internal {#link {@link #buffer} array,
* returning its value.
*
* @param index Index of the element to remove. The index must be located between {@link #head}
* and {@link #tail} in modulo {@link #buffer} arithmetic.
*/
public void removeAtBufferIndex(int index) {
assert (head <= tail ? index >= head && index < tail : index >= head || index < tail)
: "Index out of range (head=" + head + ", tail=" + tail + ", index=" + index + ").";
// Cache fields in locals (hopefully moved to registers).
final byte[] buffer = this.buffer;
final int bufLen = buffer.length;
final int lastIndex = bufLen - 1;
final int head = this.head;
final int tail = this.tail;
final int leftChunk = Math.abs(index - head) % bufLen;
final int rightChunk = Math.abs(tail - index) % bufLen;
if (leftChunk < rightChunk) {
if (index >= head) {
System.arraycopy(buffer, head, buffer, head + 1, leftChunk);
} else {
System.arraycopy(buffer, 0, buffer, 1, index);
buffer[0] = buffer[lastIndex];
System.arraycopy(buffer, head, buffer, head + 1, lastIndex - head);
}
buffer[head] = ((byte) 0);
this.head = oneRight(head, bufLen);
} else {
if (index < tail) {
System.arraycopy(buffer, index + 1, buffer, index, rightChunk);
} else {
System.arraycopy(buffer, index + 1, buffer, index, lastIndex - index);
buffer[lastIndex] = buffer[0];
System.arraycopy(buffer, 1, buffer, 0, tail);
}
buffer[tail] = ((byte) 0);
this.tail = oneLeft(tail, bufLen);
}
}
/** {@inheritDoc} */
@Override
public boolean isEmpty() {
return size() == 0;
}
/** {@inheritDoc} */
@Override
public int size() {
if (head <= tail) return tail - head;
else return (tail - head + buffer.length);
}
/**
* {@inheritDoc}
*
* <p>The internal array buffers are not released as a result of this call.
*
* @see #release()
*/
@Override
public void clear() {
if (head < tail) {
Arrays.fill(buffer, head, tail, ((byte) 0));
} else {
Arrays.fill(buffer, 0, tail, ((byte) 0));
Arrays.fill(buffer, head, buffer.length, ((byte) 0));
}
this.head = tail = 0;
}
/** Release internal buffers of this deque and reallocate with the default buffer. */
public void release() {
this.head = tail = 0;
buffer = ByteArrayList.EMPTY_ARRAY;
ensureBufferSpace(0);
}
/**
* Ensure this container can hold at least the given number of elements without resizing its
* buffers.
*
* @param expectedElements The total number of elements, inclusive.
*/
@Override
public void ensureCapacity(int expectedElements) {
ensureBufferSpace(expectedElements - size());
}
/**
* Ensures the internal buffer has enough free slots to store <code>expectedAdditions</code>.
* Increases internal buffer size if needed.
*/
protected void ensureBufferSpace(int expectedAdditions) {
final int bufferLen = buffer.length;
final int elementsCount = size();
if (elementsCount + expectedAdditions >= bufferLen) {
final int emptySlot = 1; // deque invariant: always an empty slot.
final int newSize = resizer.grow(bufferLen, elementsCount + emptySlot, expectedAdditions);
assert newSize >= (elementsCount + expectedAdditions + emptySlot)
: "Resizer failed to"
+ " return sensible new size: "
+ newSize
+ " <= "
+ (elementsCount + expectedAdditions);
try {
final byte[] newBuffer = (new byte[newSize]);
if (bufferLen > 0) {
toArray(newBuffer);
tail = elementsCount;
head = 0;
}
this.buffer = newBuffer;
} catch (OutOfMemoryError e) {
throw new BufferAllocationException(
"Not enough memory to allocate new buffers: %,d -> %,d", e, bufferLen, newSize);
}
}
}
/** {@inheritDoc} */
@Override
public byte[] toArray() {
final int size = size();
return toArray((new byte[size]));
}
/**
* Copies elements of this deque to an array. The content of the <code>target</code> array is
* filled from index 0 (head of the queue) to index <code>size() - 1</code> (tail of the queue).
*
* @param target The target array must be large enough to hold all elements.
* @return Returns the target argument for chaining.
*/
public byte[] toArray(byte[] target) {
assert target.length >= size() : "Target array must be >= " + size();
if (head < tail) {
// The contents is not wrapped around. Just copy.
System.arraycopy(buffer, head, target, 0, size());
} else if (head > tail) {
// The contents is split. Merge elements from the following indexes:
// [head...buffer.length - 1][0, tail - 1]
final int rightCount = buffer.length - head;
System.arraycopy(buffer, head, target, 0, rightCount);
System.arraycopy(buffer, 0, target, rightCount, tail);
}
return target;
}
/**
* Clone this object. The returned clone will reuse the same hash function and array resizing
* strategy.
*/
@Override
public ByteArrayDeque clone() {
try {
ByteArrayDeque cloned = (ByteArrayDeque) super.clone();
cloned.buffer = buffer.clone();
return cloned;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
/** Move one index to the left, wrapping around buffer. */
protected static int oneLeft(int index, int modulus) {
if (index >= 1) {
return index - 1;
}
return modulus - 1;
}
/** Move one index to the right, wrapping around buffer. */
protected static int oneRight(int index, int modulus) {
if (index + 1 == modulus) {
return 0;
}
return index + 1;
}
@Override
public long ramBytesAllocated() {
// int: head, tail
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ Integer.BYTES * 2
+ resizer.ramBytesAllocated()
+ RamUsageEstimator.shallowSizeOfArray(buffer);
}
@Override
public long ramBytesUsed() {
// int: head, tail
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ Integer.BYTES * 2
+ resizer.ramBytesUsed()
+ RamUsageEstimator.shallowUsedSizeOfArray(buffer, size());
}
/** An iterator implementation for {@link ObjectArrayDeque#iterator}. */
private final class ValueIterator extends AbstractIterator<ByteCursor> {
private final ByteCursor cursor;
private int remaining;
public ValueIterator() {
cursor = new ByteCursor();
cursor.index = oneLeft(head, buffer.length);
this.remaining = size();
}
@Override
protected ByteCursor fetch() {
if (remaining == 0) {
return done();
}
remaining--;
cursor.value = buffer[cursor.index = oneRight(cursor.index, buffer.length)];
return cursor;
}
}
/** An iterator implementation for {@link ObjectArrayDeque#descendingIterator()}. */
private final class DescendingValueIterator extends AbstractIterator<ByteCursor> {
private final ByteCursor cursor;
private int remaining;
public DescendingValueIterator() {
cursor = new ByteCursor();
cursor.index = tail;
this.remaining = size();
}
@Override
protected ByteCursor fetch() {
if (remaining == 0) return done();
remaining--;
cursor.value = buffer[cursor.index = oneLeft(cursor.index, buffer.length)];
return cursor;
}
}
/**
* Returns a cursor over the values of this deque (in head to tail order). The iterator is
* implemented as a cursor and it returns <b>the same cursor instance</b> on every call to {@link
* Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in
* the deque's buffer) use the cursor's public fields. An example is shown below.
*
* <pre>
* for (IntValueCursor c : intDeque) {
* System.out.println(&quot;buffer index=&quot; + c.index + &quot; value=&quot; + c.value);
* }
* </pre>
*/
public Iterator<ByteCursor> iterator() {
return new ValueIterator();
}
/**
* Returns a cursor over the values of this deque (in tail to head order). The iterator is
* implemented as a cursor and it returns <b>the same cursor instance</b> on every call to {@link
* Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in
* the deque's buffer) use the cursor's public fields. An example is shown below.
*
* <pre>
* for (Iterator&lt;IntCursor&gt; i = intDeque.descendingIterator(); i.hasNext();) {
* final IntCursor c = i.next();
* System.out.println(&quot;buffer index=&quot; + c.index + &quot; value=&quot; + c.value);
* }
* </pre>
*/
public Iterator<ByteCursor> descendingIterator() {
return new DescendingValueIterator();
}
/** {@inheritDoc} */
@Override
public <T extends ByteProcedure> T forEach(T procedure) {
forEach(procedure, head, tail);
return procedure;
}
/**
* Applies <code>procedure</code> to a slice of the deque, <code>fromIndex</code>, inclusive, to
* <code>toIndex</code>, exclusive.
*/
private void forEach(ByteProcedure procedure, int fromIndex, final int toIndex) {
final byte[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
procedure.apply(buffer[i]);
}
}
/** {@inheritDoc} */
@Override
public <T extends BytePredicate> T forEach(T predicate) {
int fromIndex = head;
int toIndex = tail;
final byte[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
if (!predicate.apply(buffer[i])) {
break;
}
}
return predicate;
}
/** Applies <code>procedure</code> to all elements of this deque, tail to head. */
@Override
public <T extends ByteProcedure> T descendingForEach(T procedure) {
descendingForEach(procedure, head, tail);
return procedure;
}
/**
* Applies <code>procedure</code> to a slice of the deque, <code>toIndex</code>, exclusive, down
* to <code>fromIndex</code>, inclusive.
*/
private void descendingForEach(ByteProcedure procedure, int fromIndex, final int toIndex) {
if (fromIndex == toIndex) return;
final byte[] buffer = this.buffer;
int i = toIndex;
do {
i = oneLeft(i, buffer.length);
procedure.apply(buffer[i]);
} while (i != fromIndex);
}
/** {@inheritDoc} */
@Override
public <T extends BytePredicate> T descendingForEach(T predicate) {
descendingForEach(predicate, head, tail);
return predicate;
}
/**
* Applies <code>predicate</code> to a slice of the deque, <code>toIndex</code>, exclusive, down
* to <code>fromIndex</code>, inclusive or until the predicate returns <code>false</code>.
*/
private void descendingForEach(BytePredicate predicate, int fromIndex, final int toIndex) {
if (fromIndex == toIndex) return;
final byte[] buffer = this.buffer;
int i = toIndex;
do {
i = oneLeft(i, buffer.length);
if (!predicate.apply(buffer[i])) {
break;
}
} while (i != fromIndex);
}
/** {@inheritDoc} */
@Override
public int removeAll(BytePredicate predicate) {
final byte[] buffer = this.buffer;
final int last = tail;
final int bufLen = buffer.length;
int removed = 0;
int from, to;
from = to = head;
try {
for (from = to = head; from != last; from = oneRight(from, bufLen)) {
if (predicate.apply(buffer[from])) {
buffer[from] = ((byte) 0);
removed++;
continue;
}
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = ((byte) 0);
}
to = oneRight(to, bufLen);
}
} finally {
// Keep the deque in consistent state even if the predicate throws an exception.
for (; from != last; from = oneRight(from, bufLen)) {
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = ((byte) 0);
}
to = oneRight(to, bufLen);
}
tail = to;
}
return removed;
}
/** {@inheritDoc} */
@Override
public boolean contains(byte e) {
int fromIndex = head;
int toIndex = tail;
final byte[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
if (((e) == (buffer[i]))) {
return true;
}
}
return false;
}
/** {@inheritDoc} */
@Override
public int hashCode() {
int h = 1;
int fromIndex = head;
int toIndex = tail;
final byte[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
h = 31 * h + BitMixer.mix(this.buffer[i]);
}
return h;
}
/**
* Returns <code>true</code> only if the other object is an instance of the same class and with
* the same elements.
*/
@Override
public boolean equals(Object obj) {
return (this == obj)
|| (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj)));
}
/** Compare order-aligned elements against another {@link ByteDeque}. */
protected boolean equalElements(ByteArrayDeque other) {
int max = size();
if (other.size() != max) {
return false;
}
Iterator<ByteCursor> i1 = this.iterator();
Iterator<? extends ByteCursor> i2 = other.iterator();
while (i1.hasNext() && i2.hasNext()) {
if (!((i1.next().value) == (i2.next().value))) {
return false;
}
}
return !i1.hasNext() && !i2.hasNext();
}
/** Create a new deque by pushing a variable number of arguments to the end of it. */
public static ByteArrayDeque from(byte... elements) {
final ByteArrayDeque coll = new ByteArrayDeque(elements.length);
coll.addLast(elements);
return coll;
}
}

View File

@ -0,0 +1,579 @@
package com.carrotsearch.hppc;
import static com.carrotsearch.hppc.Containers.*;
import com.carrotsearch.hppc.cursors.*;
import com.carrotsearch.hppc.predicates.BytePredicate;
import com.carrotsearch.hppc.procedures.*;
import java.util.*;
/** An array-backed list of bytes. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayList.java")
public class ByteArrayList extends AbstractByteCollection
implements ByteIndexedContainer, Preallocable, Cloneable, Accountable {
/** An immutable empty buffer (array). */
public static final byte[] EMPTY_ARRAY = new byte[0];
;
/** Reuse the same strategy instance. */
private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY =
BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE;
/**
* Internal array for storing the list. The array may be larger than the current size ({@link
* #size()}).
*/
public byte[] buffer = EMPTY_ARRAY;
/** Current number of elements stored in {@link #buffer}. */
public int elementsCount;
/** Buffer resizing strategy. */
protected final ArraySizingStrategy resizer;
/** New instance with sane defaults. */
public ByteArrayList() {
this(DEFAULT_EXPECTED_ELEMENTS);
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
*/
public ByteArrayList(int expectedElements) {
this(expectedElements, DEFAULT_SIZING_STRATEGY);
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
* @param resizer Underlying buffer sizing strategy.
*/
public ByteArrayList(int expectedElements, ArraySizingStrategy resizer) {
assert resizer != null;
this.resizer = resizer;
buffer = Arrays.copyOf(buffer, expectedElements);
}
/** Creates a new list from the elements of another container in its iteration order. */
public ByteArrayList(ByteContainer container) {
this(container.size());
addAll(container);
}
/** {@inheritDoc} */
@Override
public void add(byte e1) {
ensureBufferSpace(1);
buffer[elementsCount++] = e1;
}
/**
* Appends two elements at the end of the list. To add more than two elements, use <code>add
* </code> (vararg-version) or access the buffer directly (tight loop).
*/
public void add(byte e1, byte e2) {
ensureBufferSpace(2);
buffer[elementsCount++] = e1;
buffer[elementsCount++] = e2;
}
/** Add all elements from a range of given array to the list. */
public void add(byte[] elements, int start, int length) {
assert length >= 0 : "Length must be >= 0";
ensureBufferSpace(length);
System.arraycopy(elements, start, buffer, elementsCount, length);
elementsCount += length;
}
/**
* Vararg-signature method for adding elements at the end of the list.
*
* <p><b>This method is handy, but costly if used in tight loops (anonymous array passing)</b>
*/
public final void add(byte... elements) {
add(elements, 0, elements.length);
}
/** Adds all elements from another container. */
public int addAll(ByteContainer container) {
final int size = container.size();
ensureBufferSpace(size);
for (ByteCursor cursor : container) {
add(cursor.value);
}
return size;
}
/** Adds all elements from another iterable. */
public int addAll(Iterable<? extends ByteCursor> iterable) {
int size = 0;
for (ByteCursor cursor : iterable) {
add(cursor.value);
size++;
}
return size;
}
/** {@inheritDoc} */
@Override
public void insert(int index, byte e1) {
assert (index >= 0 && index <= size())
: "Index " + index + " out of bounds [" + 0 + ", " + size() + "].";
ensureBufferSpace(1);
System.arraycopy(buffer, index, buffer, index + 1, elementsCount - index);
buffer[index] = e1;
elementsCount++;
}
/** {@inheritDoc} */
@Override
public byte get(int index) {
assert (index >= 0 && index < size())
: "Index " + index + " out of bounds [" + 0 + ", " + size() + ").";
return buffer[index];
}
/** {@inheritDoc} */
@Override
public byte set(int index, byte e1) {
assert (index >= 0 && index < size())
: "Index " + index + " out of bounds [" + 0 + ", " + size() + ").";
final byte v = buffer[index];
buffer[index] = e1;
return v;
}
/** {@inheritDoc} */
@Override
public byte removeAt(int index) {
assert (index >= 0 && index < size())
: "Index " + index + " out of bounds [" + 0 + ", " + size() + ").";
final byte v = buffer[index];
System.arraycopy(buffer, index + 1, buffer, index, --elementsCount - index);
return v;
}
/** {@inheritDoc} */
@Override
public byte removeLast() {
assert elementsCount > 0;
final byte v = buffer[--elementsCount];
return v;
}
/** {@inheritDoc} */
@Override
public void removeRange(int fromIndex, int toIndex) {
assert (fromIndex >= 0 && fromIndex <= size())
: "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ").";
assert (toIndex >= 0 && toIndex <= size())
: "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "].";
assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex;
System.arraycopy(buffer, toIndex, buffer, fromIndex, elementsCount - toIndex);
final int count = toIndex - fromIndex;
elementsCount -= count;
}
/** {@inheritDoc} */
@Override
public boolean removeElement(byte e1) {
return removeFirst(e1) != -1;
}
/** {@inheritDoc} */
@Override
public int removeFirst(byte e1) {
final int index = indexOf(e1);
if (index >= 0) removeAt(index);
return index;
}
/** {@inheritDoc} */
@Override
public int removeLast(byte e1) {
final int index = lastIndexOf(e1);
if (index >= 0) removeAt(index);
return index;
}
/** {@inheritDoc} */
@Override
public int removeAll(byte e1) {
int to = 0;
for (int from = 0; from < elementsCount; from++) {
if (((e1) == (buffer[from]))) {
continue;
}
if (to != from) {
buffer[to] = buffer[from];
}
to++;
}
final int deleted = elementsCount - to;
this.elementsCount = to;
return deleted;
}
/** {@inheritDoc} */
@Override
public boolean contains(byte e1) {
return indexOf(e1) >= 0;
}
/** {@inheritDoc} */
@Override
public int indexOf(byte e1) {
for (int i = 0; i < elementsCount; i++) {
if (((e1) == (buffer[i]))) {
return i;
}
}
return -1;
}
/** {@inheritDoc} */
@Override
public int lastIndexOf(byte e1) {
for (int i = elementsCount - 1; i >= 0; i--) {
if (((e1) == (buffer[i]))) {
return i;
}
}
return -1;
}
/** {@inheritDoc} */
@Override
public boolean isEmpty() {
return elementsCount == 0;
}
/**
* Ensure this container can hold at least the given number of elements without resizing its
* buffers.
*
* @param expectedElements The total number of elements, inclusive.
*/
@Override
public void ensureCapacity(int expectedElements) {
final int bufferLen = (buffer == null ? 0 : buffer.length);
if (expectedElements > bufferLen) {
ensureBufferSpace(expectedElements - size());
}
}
/**
* Ensures the internal buffer has enough free slots to store <code>expectedAdditions</code>.
* Increases internal buffer size if needed.
*/
protected void ensureBufferSpace(int expectedAdditions) {
final int bufferLen = (buffer == null ? 0 : buffer.length);
if (elementsCount + expectedAdditions > bufferLen) {
final int newSize = resizer.grow(bufferLen, elementsCount, expectedAdditions);
assert newSize >= elementsCount + expectedAdditions
: "Resizer failed to"
+ " return sensible new size: "
+ newSize
+ " <= "
+ (elementsCount + expectedAdditions);
this.buffer = Arrays.copyOf(buffer, newSize);
}
}
/**
* Truncate or expand the list to the new size. If the list is truncated, the buffer will not be
* reallocated (use {@link #trimToSize()} if you need a truncated buffer), but the truncated
* values will be reset to the default value (zero). If the list is expanded, the elements beyond
* the current size are initialized with JVM-defaults (zero or <code>null</code> values).
*/
public void resize(int newSize) {
if (newSize <= buffer.length) {
if (newSize < elementsCount) {
Arrays.fill(buffer, newSize, elementsCount, ((byte) 0));
} else {
Arrays.fill(buffer, elementsCount, newSize, ((byte) 0));
}
} else {
ensureCapacity(newSize);
}
this.elementsCount = newSize;
}
/** {@inheritDoc} */
@Override
public int size() {
return elementsCount;
}
/** Trim the internal buffer to the current size. */
public void trimToSize() {
if (size() != this.buffer.length) {
this.buffer = toArray();
}
}
/**
* Sets the number of stored elements to zero. Releases and initializes the internal storage array
* to default values. To clear the list without cleaning the buffer, simply set the {@link
* #elementsCount} field to zero.
*/
@Override
public void clear() {
Arrays.fill(buffer, 0, elementsCount, ((byte) 0));
this.elementsCount = 0;
}
/** Sets the number of stored elements to zero and releases the internal storage array. */
@Override
public void release() {
this.buffer = EMPTY_ARRAY;
this.elementsCount = 0;
}
/**
* {@inheritDoc}
*
* <p>The returned array is sized to match exactly the number of elements of the stack.
*/
@Override
public byte[] toArray() {
return Arrays.copyOf(buffer, elementsCount);
}
/** {@inheritDoc} */
@Override
public ByteIndexedContainer sort() {
Arrays.sort(buffer, 0, elementsCount);
return this;
}
/** {@inheritDoc} */
@Override
public ByteIndexedContainer reverse() {
for (int i = 0, mid = elementsCount >> 1, j = elementsCount - 1; i < mid; i++, j--) {
byte tmp = buffer[i];
buffer[i] = buffer[j];
buffer[j] = tmp;
}
return this;
}
/**
* Clone this object. The returned clone will reuse the same hash function and array resizing
* strategy.
*/
@Override
public ByteArrayList clone() {
try {
final ByteArrayList cloned = (ByteArrayList) super.clone();
cloned.buffer = buffer.clone();
return cloned;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
/** {@inheritDoc} */
@Override
public int hashCode() {
int h = 1, max = elementsCount;
for (int i = 0; i < max; i++) {
h = 31 * h + BitMixer.mix(this.buffer[i]);
}
return h;
}
/**
* Returns <code>true</code> only if the other object is an instance of the same class and with
* the same elements.
*/
@Override
public boolean equals(Object obj) {
return (this == obj)
|| (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj)));
}
/** Compare index-aligned elements against another {@link ByteIndexedContainer}. */
protected boolean equalElements(ByteArrayList other) {
int max = size();
if (other.size() != max) {
return false;
}
for (int i = 0; i < max; i++) {
if (!((get(i)) == (other.get(i)))) {
return false;
}
}
return true;
}
@Override
public long ramBytesAllocated() {
// int: elementsCount
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ Integer.BYTES
+ resizer.ramBytesAllocated()
+ RamUsageEstimator.shallowSizeOfArray(buffer);
}
@Override
public long ramBytesUsed() {
// int: elementsCount
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ Integer.BYTES
+ resizer.ramBytesUsed()
+ RamUsageEstimator.shallowUsedSizeOfArray(buffer, elementsCount);
}
/** An iterator implementation for {@link ByteArrayList#iterator}. */
static final class ValueIterator extends AbstractIterator<ByteCursor> {
private final ByteCursor cursor;
private final byte[] buffer;
private final int size;
public ValueIterator(byte[] buffer, int size) {
this.cursor = new ByteCursor();
this.cursor.index = -1;
this.size = size;
this.buffer = buffer;
}
@Override
protected ByteCursor fetch() {
if (cursor.index + 1 == size) return done();
cursor.value = buffer[++cursor.index];
return cursor;
}
}
/** {@inheritDoc} */
@Override
public Iterator<ByteCursor> iterator() {
return new ValueIterator(buffer, size());
}
/** {@inheritDoc} */
@Override
public <T extends ByteProcedure> T forEach(T procedure) {
return forEach(procedure, 0, size());
}
/**
* Applies <code>procedure</code> to a slice of the list, <code>fromIndex</code>, inclusive, to
* <code>toIndex</code>, exclusive.
*/
public <T extends ByteProcedure> T forEach(T procedure, int fromIndex, final int toIndex) {
assert (fromIndex >= 0 && fromIndex <= size())
: "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ").";
assert (toIndex >= 0 && toIndex <= size())
: "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "].";
assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex;
final byte[] buffer = this.buffer;
for (int i = fromIndex; i < toIndex; i++) {
procedure.apply(buffer[i]);
}
return procedure;
}
/** {@inheritDoc} */
@Override
public int removeAll(BytePredicate predicate) {
final byte[] buffer = this.buffer;
final int elementsCount = this.elementsCount;
int to = 0;
int from = 0;
try {
for (; from < elementsCount; from++) {
if (predicate.apply(buffer[from])) {
buffer[from] = ((byte) 0);
continue;
}
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = ((byte) 0);
}
to++;
}
} finally {
// Keep the list in a consistent state, even if the predicate throws an exception.
for (; from < elementsCount; from++) {
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = ((byte) 0);
}
to++;
}
this.elementsCount = to;
}
return elementsCount - to;
}
/** {@inheritDoc} */
@Override
public <T extends BytePredicate> T forEach(T predicate) {
return forEach(predicate, 0, size());
}
/**
* Applies <code>predicate</code> to a slice of the list, <code>fromIndex</code>, inclusive, to
* <code>toIndex</code>, exclusive, or until predicate returns <code>false</code>.
*/
public <T extends BytePredicate> T forEach(T predicate, int fromIndex, final int toIndex) {
assert (fromIndex >= 0 && fromIndex <= size())
: "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ").";
assert (toIndex >= 0 && toIndex <= size())
: "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "].";
assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex;
final byte[] buffer = this.buffer;
for (int i = fromIndex; i < toIndex; i++) {
if (!predicate.apply(buffer[i])) break;
}
return predicate;
}
/**
* Create a list from a variable number of arguments or an array of <code>byte</code>. The
* elements are copied from the argument to the internal buffer.
*/
public static ByteArrayList from(byte... elements) {
final ByteArrayList list = new ByteArrayList(elements.length);
list.add(elements);
return list;
}
}

View File

@ -0,0 +1,33 @@
package com.carrotsearch.hppc;
/**
* Reused buffer visualization routines.
*
* @see ByteSet#visualizeKeyDistribution(int)
* @see ByteVTypeMap#visualizeKeyDistribution(int)
*/
class ByteBufferVisualizer {
static String visualizeKeyDistribution(byte[] buffer, int max, int characters) {
final StringBuilder b = new StringBuilder();
final char[] chars = ".123456789X".toCharArray();
for (int i = 1, start = -1; i <= characters; i++) {
int end = (int) ((long) i * max / characters);
if (start + 1 <= end) {
int taken = 0;
int slots = 0;
for (int slot = start + 1; slot <= end; slot++, slots++) {
if (!((buffer[slot]) == 0)) {
taken++;
}
}
b.append(chars[Math.min(chars.length - 1, taken * chars.length / slots)]);
start = end;
}
}
while (b.length() < characters) {
b.append(' ');
}
return b.toString();
}
}

View File

@ -0,0 +1,64 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.predicates.BytePredicate;
/**
* A collection allows basic, efficient operations on sets of elements (difference and
* intersection).
*/
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCollection.java")
public interface ByteCollection extends ByteContainer {
/**
* Removes all occurrences of <code>e</code> from this collection.
*
* @param e Element to be removed from this collection, if present.
* @return The number of removed elements as a result of this call.
*/
public int removeAll(byte e);
/**
* Removes all elements in this collection that are present in <code>c</code>.
*
* @return Returns the number of removed elements.
*/
public int removeAll(ByteLookupContainer c);
/**
* Removes all elements in this collection for which the given predicate returns <code>true</code>
* .
*
* @return Returns the number of removed elements.
*/
public int removeAll(BytePredicate predicate);
/**
* Keeps all elements in this collection that are present in <code>c</code>. Runs in time
* proportional to the number of elements in this collection. Equivalent of sets intersection.
*
* @return Returns the number of removed elements.
*/
public int retainAll(ByteLookupContainer c);
/**
* Keeps all elements in this collection for which the given predicate returns <code>true</code>.
*
* @return Returns the number of removed elements.
*/
public int retainAll(BytePredicate predicate);
/**
* Removes all elements from this collection.
*
* @see #release()
*/
public void clear();
/**
* Removes all elements from the collection and additionally releases any internal buffers.
* Typically, if the object is to be reused, a simple {@link #clear()} should be a better
* alternative since it'll avoid reallocation.
*
* @see #clear()
*/
public void release();
}

View File

@ -0,0 +1,76 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.ByteCursor;
import com.carrotsearch.hppc.predicates.BytePredicate;
import com.carrotsearch.hppc.procedures.ByteProcedure;
import java.util.Iterator;
/** A generic container holding <code>byte</code>s. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeContainer.java")
public interface ByteContainer extends Iterable<ByteCursor> {
/**
* Returns an iterator to a cursor traversing the collection. The order of traversal is not
* defined. More than one cursor may be active at a time. The behavior of iterators is undefined
* if structural changes are made to the underlying collection.
*
* <p>The iterator is implemented as a cursor and it returns <b>the same cursor instance</b> on
* every call to {@link Iterator#next()} (to avoid boxing of primitive types). To read the current
* list's value (or index in the list) use the cursor's public fields. An example is shown below.
*
* <pre>
* for (ByteCursor&lt;byte&gt; c : container) {
* System.out.println(&quot;index=&quot; + c.index + &quot; value=&quot; + c.value);
* }
* </pre>
*/
public Iterator<ByteCursor> iterator();
/**
* Lookup a given element in the container. This operation has no speed guarantees (may be linear
* with respect to the size of this container).
*
* @return Returns <code>true</code> if this container has an element equal to <code>e</code>.
*/
public boolean contains(byte e);
/**
* Return the current number of elements in this container. The time for calculating the
* container's size may take <code>O(n)</code> time, although implementing classes should try to
* maintain the current size and return in constant time.
*/
public int size();
/** Shortcut for <code>size() == 0</code>. */
public boolean isEmpty();
/**
* Copies all elements of this container to an array.
*
* <p>The returned array is always a copy, regardless of the storage used by the container.
*/
public byte[] toArray();
/**
* Applies a <code>procedure</code> to all container elements. Returns the argument (any subclass
* of {@link ByteProcedure}. This lets the caller to call methods of the argument by chaining the
* call (even if the argument is an anonymous type) to retrieve computed values, for example
* (IntContainer):
*
* <pre>
* int count = container.forEach(new IntProcedure() {
* int count; // this is a field declaration in an anonymous class.
*
* public void apply(int value) {
* count++;
* }
* }).count;
* </pre>
*/
public <T extends ByteProcedure> T forEach(T procedure);
/**
* Applies a <code>predicate</code> to container elements as long, as the predicate returns <code>
* true</code>. The iteration is interrupted otherwise.
*/
public <T extends BytePredicate> T forEach(T predicate);
}

View File

@ -0,0 +1,77 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.ByteCursor;
import com.carrotsearch.hppc.predicates.BytePredicate;
import com.carrotsearch.hppc.procedures.ByteProcedure;
import java.util.Deque;
import java.util.Iterator;
/**
* A linear collection that supports element insertion and removal at both ends.
*
* @see Deque
*/
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeDeque.java")
public interface ByteDeque extends ByteCollection {
/**
* Removes the first element that equals <code>e</code>.
*
* @return The deleted element's index or <code>-1</code> if the element was not found.
*/
public int removeFirst(byte e);
/**
* Removes the last element that equals <code>e</code>.
*
* @return The deleted element's index or <code>-1</code> if the element was not found.
*/
public int removeLast(byte e);
/** Inserts the specified element at the front of this deque. */
public void addFirst(byte e);
/** Inserts the specified element at the end of this deque. */
public void addLast(byte e);
/**
* Retrieves and removes the first element of this deque.
*
* @return the head (first) element of this deque.
*/
public byte removeFirst();
/**
* Retrieves and removes the last element of this deque.
*
* @return the tail of this deque.
*/
public byte removeLast();
/**
* Retrieves the first element of this deque but does not remove it.
*
* @return the head of this deque.
*/
public byte getFirst();
/**
* Retrieves the last element of this deque but does not remove it.
*
* @return the head of this deque.
*/
public byte getLast();
/**
* @return An iterator over elements in this deque in tail-to-head order.
*/
public Iterator<ByteCursor> descendingIterator();
/** Applies a <code>procedure</code> to all elements in tail-to-head order. */
public <T extends ByteProcedure> T descendingForEach(T procedure);
/**
* Applies a <code>predicate</code> to container elements as long, as the predicate returns <code>
* true</code>. The iteration is interrupted otherwise.
*/
public <T extends BytePredicate> T descendingForEach(T predicate);
}

View File

@ -0,0 +1,91 @@
package com.carrotsearch.hppc;
import java.util.RandomAccess;
/**
* An indexed container provides random access to elements based on an <code>index</code>. Indexes
* are zero-based.
*/
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "KTypeIndexedContainer.java")
public interface ByteIndexedContainer extends ByteCollection, RandomAccess {
/**
* Removes the first element that equals <code>e1</code>, returning whether an element has been
* removed.
*/
public boolean removeElement(byte e1);
/**
* Removes the first element that equals <code>e1</code>, returning its deleted position or <code>
* -1</code> if the element was not found.
*/
public int removeFirst(byte e1);
/**
* Removes the last element that equals <code>e1</code>, returning its deleted position or <code>
* -1</code> if the element was not found.
*/
public int removeLast(byte e1);
/**
* Returns the index of the first occurrence of the specified element in this list, or -1 if this
* list does not contain the element.
*/
public int indexOf(byte e1);
/**
* Returns the index of the last occurrence of the specified element in this list, or -1 if this
* list does not contain the element.
*/
public int lastIndexOf(byte e1);
/** Adds an element to the end of this container (the last index is incremented by one). */
public void add(byte e1);
/**
* Inserts the specified element at the specified position in this list.
*
* @param index The index at which the element should be inserted, shifting any existing and
* subsequent elements to the right.
*/
public void insert(int index, byte e1);
/**
* Replaces the element at the specified position in this list with the specified element.
*
* @return Returns the previous value in the list.
*/
public byte set(int index, byte e1);
/**
* @return Returns the element at index <code>index</code> from the list.
*/
public byte get(int index);
/**
* Removes the element at the specified position in this container and returns it.
*
* @see #removeFirst
* @see #removeLast
* @see #removeAll
*/
public byte removeAt(int index);
/** Removes and returns the last element of this container. This container must not be empty. */
public byte removeLast();
/**
* Removes from this container all of the elements with indexes between <code>fromIndex</code>,
* inclusive, and <code>toIndex</code>, exclusive.
*/
public void removeRange(int fromIndex, int toIndex);
/** Returns this container elements as a stream. */
/** Sorts the elements in this container and returns this container. */
public ByteIndexedContainer sort();
/** Reverses the elements in this container and returns this container. */
public ByteIndexedContainer reverse();
}

View File

@ -0,0 +1,12 @@
package com.carrotsearch.hppc;
/**
* Marker interface for containers that can check if they contain a given object in at least time
* <code>O(log n)</code> and ideally in amortized constant time <code>O(1)</code>.
*/
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "KTypeLookupContainer.java")
public interface ByteLookupContainer extends ByteContainer {
public boolean contains(byte e);
}

View File

@ -0,0 +1,137 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.ByteCursor;
/**
* A subclass of {@link ByteArrayList} adding stack-related utility methods. The top of the stack is
* at the <code>{@link #size()} - 1</code> element.
*/
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeStack.java")
public class ByteStack extends ByteArrayList {
/** New instance with sane defaults. */
public ByteStack() {
super();
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
*/
public ByteStack(int expectedElements) {
super(expectedElements);
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
* @param resizer Underlying buffer sizing strategy.
*/
public ByteStack(int expectedElements, ArraySizingStrategy resizer) {
super(expectedElements, resizer);
}
/** Create a stack by pushing all elements of another container to it. */
public ByteStack(ByteContainer container) {
super(container);
}
/** Adds one byte to the stack. */
public void push(byte e1) {
ensureBufferSpace(1);
buffer[elementsCount++] = e1;
}
/** Adds two bytes to the stack. */
public void push(byte e1, byte e2) {
ensureBufferSpace(2);
buffer[elementsCount++] = e1;
buffer[elementsCount++] = e2;
}
/** Adds three bytes to the stack. */
public void push(byte e1, byte e2, byte e3) {
ensureBufferSpace(3);
buffer[elementsCount++] = e1;
buffer[elementsCount++] = e2;
buffer[elementsCount++] = e3;
}
/** Adds four bytes to the stack. */
public void push(byte e1, byte e2, byte e3, byte e4) {
ensureBufferSpace(4);
buffer[elementsCount++] = e1;
buffer[elementsCount++] = e2;
buffer[elementsCount++] = e3;
buffer[elementsCount++] = e4;
}
/** Add a range of array elements to the stack. */
public void push(byte[] elements, int start, int len) {
assert start >= 0 && len >= 0;
ensureBufferSpace(len);
System.arraycopy(elements, start, buffer, elementsCount, len);
elementsCount += len;
}
/**
* Vararg-signature method for pushing elements at the top of the stack.
*
* <p><b>This method is handy, but costly if used in tight loops (anonymous array passing)</b>
*/
public final void push(byte... elements) {
push(elements, 0, elements.length);
}
/** Pushes all elements from another container to the top of the stack. */
public int pushAll(ByteContainer container) {
return addAll(container);
}
/** Pushes all elements from another iterable to the top of the stack. */
public int pushAll(Iterable<? extends ByteCursor> iterable) {
return addAll(iterable);
}
/** Discard an arbitrary number of elements from the top of the stack. */
public void discard(int count) {
assert elementsCount >= count;
elementsCount -= count;
}
/** Discard the top element from the stack. */
public void discard() {
assert elementsCount > 0;
elementsCount--;
}
/** Remove the top element from the stack and return it. */
public byte pop() {
return removeLast();
}
/** Peek at the top element on the stack. */
public byte peek() {
assert elementsCount > 0;
return buffer[elementsCount - 1];
}
/** Create a stack by pushing a variable number of arguments to it. */
public static ByteStack from(byte... elements) {
final ByteStack stack = new ByteStack(elements.length);
stack.push(elements);
return stack;
}
/** {@inheritDoc} */
@Override
public ByteStack clone() {
return (ByteStack) super.clone();
}
}

View File

@ -0,0 +1,776 @@
package com.carrotsearch.hppc;
import static com.carrotsearch.hppc.Containers.*;
import com.carrotsearch.hppc.cursors.CharCursor;
import com.carrotsearch.hppc.predicates.CharPredicate;
import com.carrotsearch.hppc.procedures.CharProcedure;
import java.util.*;
/** An array-backed {@link CharDeque}. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayDeque.java")
public class CharArrayDeque extends AbstractCharCollection
implements CharDeque, Preallocable, Cloneable, Accountable {
/** Reuse the same strategy instance. */
private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY =
BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE;
/** Internal array for storing elements of the deque. */
public char[] buffer = CharArrayList.EMPTY_ARRAY;
/**
* The index of the element at the head of the deque or an arbitrary number equal to tail if the
* deque is empty.
*/
public int head;
/** The index at which the next element would be added to the tail of the deque. */
public int tail;
/** Buffer resizing strategy. */
protected final ArraySizingStrategy resizer;
/** New instance with sane defaults. */
public CharArrayDeque() {
this(DEFAULT_EXPECTED_ELEMENTS);
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
*/
public CharArrayDeque(int expectedElements) {
this(expectedElements, DEFAULT_SIZING_STRATEGY);
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
* @param resizer Underlying buffer sizing strategy.
*/
public CharArrayDeque(int expectedElements, ArraySizingStrategy resizer) {
assert resizer != null;
this.resizer = resizer;
ensureCapacity(expectedElements);
}
/**
* Creates a new deque from elements of another container, appending elements at the end of the
* deque in the iteration order.
*/
public CharArrayDeque(CharContainer container) {
this(container.size());
addLast(container);
}
/** {@inheritDoc} */
@Override
public void addFirst(char e1) {
int h = oneLeft(head, buffer.length);
if (h == tail) {
ensureBufferSpace(1);
h = oneLeft(head, buffer.length);
}
buffer[head = h] = e1;
}
/**
* Vararg-signature method for adding elements at the front of this deque.
*
* <p><b>This method is handy, but costly if used in tight loops (anonymous array passing)</b>
*
* @param elements The elements to add.
*/
public final void addFirst(char... elements) {
ensureBufferSpace(elements.length);
for (char k : elements) {
addFirst(k);
}
}
/**
* Inserts all elements from the given container to the front of this deque.
*
* @param container The container to iterate over.
* @return Returns the number of elements actually added as a result of this call.
*/
public int addFirst(CharContainer container) {
int size = container.size();
ensureBufferSpace(size);
for (CharCursor cursor : container) {
addFirst(cursor.value);
}
return size;
}
/**
* Inserts all elements from the given iterable to the front of this deque.
*
* @param iterable The iterable to iterate over.
* @return Returns the number of elements actually added as a result of this call.
*/
public int addFirst(Iterable<? extends CharCursor> iterable) {
int size = 0;
for (CharCursor cursor : iterable) {
addFirst(cursor.value);
size++;
}
return size;
}
/** {@inheritDoc} */
@Override
public void addLast(char e1) {
int t = oneRight(tail, buffer.length);
if (head == t) {
ensureBufferSpace(1);
t = oneRight(tail, buffer.length);
}
buffer[tail] = e1;
tail = t;
}
/**
* Vararg-signature method for adding elements at the end of this deque.
*
* <p><b>This method is handy, but costly if used in tight loops (anonymous array passing)</b>
*
* @param elements The elements to iterate over.
*/
public final void addLast(char... elements) {
ensureBufferSpace(1);
for (char k : elements) {
addLast(k);
}
}
/**
* Inserts all elements from the given container to the end of this deque.
*
* @param container The container to iterate over.
* @return Returns the number of elements actually added as a result of this call.
*/
public int addLast(CharContainer container) {
int size = container.size();
ensureBufferSpace(size);
for (CharCursor cursor : container) {
addLast(cursor.value);
}
return size;
}
/**
* Inserts all elements from the given iterable to the end of this deque.
*
* @param iterable The iterable to iterate over.
* @return Returns the number of elements actually added as a result of this call.
*/
public int addLast(Iterable<? extends CharCursor> iterable) {
int size = 0;
for (CharCursor cursor : iterable) {
addLast(cursor.value);
size++;
}
return size;
}
/** {@inheritDoc} */
@Override
public char removeFirst() {
assert size() > 0 : "The deque is empty.";
final char result = buffer[head];
buffer[head] = ((char) 0);
head = oneRight(head, buffer.length);
return result;
}
/** {@inheritDoc} */
@Override
public char removeLast() {
assert size() > 0 : "The deque is empty.";
tail = oneLeft(tail, buffer.length);
final char result = buffer[tail];
buffer[tail] = ((char) 0);
return result;
}
/** {@inheritDoc} */
@Override
public char getFirst() {
assert size() > 0 : "The deque is empty.";
return buffer[head];
}
/** {@inheritDoc} */
@Override
public char getLast() {
assert size() > 0 : "The deque is empty.";
return buffer[oneLeft(tail, buffer.length)];
}
/** {@inheritDoc} */
@Override
public int removeFirst(char e1) {
final int index = bufferIndexOf(e1);
if (index >= 0) removeAtBufferIndex(index);
return index;
}
/**
* Return the index of the first (counting from head) element equal to <code>e1</code>. The index
* points to the {@link #buffer} array.
*
* @param e1 The element to look for.
* @return Returns the index of the first element equal to <code>e1</code> or <code>-1</code> if
* not found.
*/
public int bufferIndexOf(char e1) {
final int last = tail;
final int bufLen = buffer.length;
for (int i = head; i != last; i = oneRight(i, bufLen)) {
if (((e1) == (buffer[i]))) {
return i;
}
}
return -1;
}
/** {@inheritDoc} */
@Override
public int removeLast(char e1) {
final int index = lastBufferIndexOf(e1);
if (index >= 0) {
removeAtBufferIndex(index);
}
return index;
}
/**
* Return the index of the last (counting from tail) element equal to <code>e1</code>. The index
* points to the {@link #buffer} array.
*
* @param e1 The element to look for.
* @return Returns the index of the first element equal to <code>e1</code> or <code>-1</code> if
* not found.
*/
public int lastBufferIndexOf(char e1) {
final int bufLen = buffer.length;
final int last = oneLeft(head, bufLen);
for (int i = oneLeft(tail, bufLen); i != last; i = oneLeft(i, bufLen)) {
if (((e1) == (buffer[i]))) return i;
}
return -1;
}
/** {@inheritDoc} */
@Override
public int removeAll(char e1) {
int removed = 0;
final int last = tail;
final int bufLen = buffer.length;
int from, to;
for (from = to = head; from != last; from = oneRight(from, bufLen)) {
if (((e1) == (buffer[from]))) {
buffer[from] = ((char) 0);
removed++;
continue;
}
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = ((char) 0);
}
to = oneRight(to, bufLen);
}
tail = to;
return removed;
}
/**
* Removes the element at <code>index</code> in the internal {#link {@link #buffer} array,
* returning its value.
*
* @param index Index of the element to remove. The index must be located between {@link #head}
* and {@link #tail} in modulo {@link #buffer} arithmetic.
*/
public void removeAtBufferIndex(int index) {
assert (head <= tail ? index >= head && index < tail : index >= head || index < tail)
: "Index out of range (head=" + head + ", tail=" + tail + ", index=" + index + ").";
// Cache fields in locals (hopefully moved to registers).
final char[] buffer = this.buffer;
final int bufLen = buffer.length;
final int lastIndex = bufLen - 1;
final int head = this.head;
final int tail = this.tail;
final int leftChunk = Math.abs(index - head) % bufLen;
final int rightChunk = Math.abs(tail - index) % bufLen;
if (leftChunk < rightChunk) {
if (index >= head) {
System.arraycopy(buffer, head, buffer, head + 1, leftChunk);
} else {
System.arraycopy(buffer, 0, buffer, 1, index);
buffer[0] = buffer[lastIndex];
System.arraycopy(buffer, head, buffer, head + 1, lastIndex - head);
}
buffer[head] = ((char) 0);
this.head = oneRight(head, bufLen);
} else {
if (index < tail) {
System.arraycopy(buffer, index + 1, buffer, index, rightChunk);
} else {
System.arraycopy(buffer, index + 1, buffer, index, lastIndex - index);
buffer[lastIndex] = buffer[0];
System.arraycopy(buffer, 1, buffer, 0, tail);
}
buffer[tail] = ((char) 0);
this.tail = oneLeft(tail, bufLen);
}
}
/** {@inheritDoc} */
@Override
public boolean isEmpty() {
return size() == 0;
}
/** {@inheritDoc} */
@Override
public int size() {
if (head <= tail) return tail - head;
else return (tail - head + buffer.length);
}
/**
* {@inheritDoc}
*
* <p>The internal array buffers are not released as a result of this call.
*
* @see #release()
*/
@Override
public void clear() {
if (head < tail) {
Arrays.fill(buffer, head, tail, ((char) 0));
} else {
Arrays.fill(buffer, 0, tail, ((char) 0));
Arrays.fill(buffer, head, buffer.length, ((char) 0));
}
this.head = tail = 0;
}
/** Release internal buffers of this deque and reallocate with the default buffer. */
public void release() {
this.head = tail = 0;
buffer = CharArrayList.EMPTY_ARRAY;
ensureBufferSpace(0);
}
/**
* Ensure this container can hold at least the given number of elements without resizing its
* buffers.
*
* @param expectedElements The total number of elements, inclusive.
*/
@Override
public void ensureCapacity(int expectedElements) {
ensureBufferSpace(expectedElements - size());
}
/**
* Ensures the internal buffer has enough free slots to store <code>expectedAdditions</code>.
* Increases internal buffer size if needed.
*/
protected void ensureBufferSpace(int expectedAdditions) {
final int bufferLen = buffer.length;
final int elementsCount = size();
if (elementsCount + expectedAdditions >= bufferLen) {
final int emptySlot = 1; // deque invariant: always an empty slot.
final int newSize = resizer.grow(bufferLen, elementsCount + emptySlot, expectedAdditions);
assert newSize >= (elementsCount + expectedAdditions + emptySlot)
: "Resizer failed to"
+ " return sensible new size: "
+ newSize
+ " <= "
+ (elementsCount + expectedAdditions);
try {
final char[] newBuffer = (new char[newSize]);
if (bufferLen > 0) {
toArray(newBuffer);
tail = elementsCount;
head = 0;
}
this.buffer = newBuffer;
} catch (OutOfMemoryError e) {
throw new BufferAllocationException(
"Not enough memory to allocate new buffers: %,d -> %,d", e, bufferLen, newSize);
}
}
}
/** {@inheritDoc} */
@Override
public char[] toArray() {
final int size = size();
return toArray((new char[size]));
}
/**
* Copies elements of this deque to an array. The content of the <code>target</code> array is
* filled from index 0 (head of the queue) to index <code>size() - 1</code> (tail of the queue).
*
* @param target The target array must be large enough to hold all elements.
* @return Returns the target argument for chaining.
*/
public char[] toArray(char[] target) {
assert target.length >= size() : "Target array must be >= " + size();
if (head < tail) {
// The contents is not wrapped around. Just copy.
System.arraycopy(buffer, head, target, 0, size());
} else if (head > tail) {
// The contents is split. Merge elements from the following indexes:
// [head...buffer.length - 1][0, tail - 1]
final int rightCount = buffer.length - head;
System.arraycopy(buffer, head, target, 0, rightCount);
System.arraycopy(buffer, 0, target, rightCount, tail);
}
return target;
}
/**
* Clone this object. The returned clone will reuse the same hash function and array resizing
* strategy.
*/
@Override
public CharArrayDeque clone() {
try {
CharArrayDeque cloned = (CharArrayDeque) super.clone();
cloned.buffer = buffer.clone();
return cloned;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
/** Move one index to the left, wrapping around buffer. */
protected static int oneLeft(int index, int modulus) {
if (index >= 1) {
return index - 1;
}
return modulus - 1;
}
/** Move one index to the right, wrapping around buffer. */
protected static int oneRight(int index, int modulus) {
if (index + 1 == modulus) {
return 0;
}
return index + 1;
}
@Override
public long ramBytesAllocated() {
// int: head, tail
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ Integer.BYTES * 2
+ resizer.ramBytesAllocated()
+ RamUsageEstimator.shallowSizeOfArray(buffer);
}
@Override
public long ramBytesUsed() {
// int: head, tail
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ Integer.BYTES * 2
+ resizer.ramBytesUsed()
+ RamUsageEstimator.shallowUsedSizeOfArray(buffer, size());
}
/** An iterator implementation for {@link ObjectArrayDeque#iterator}. */
private final class ValueIterator extends AbstractIterator<CharCursor> {
private final CharCursor cursor;
private int remaining;
public ValueIterator() {
cursor = new CharCursor();
cursor.index = oneLeft(head, buffer.length);
this.remaining = size();
}
@Override
protected CharCursor fetch() {
if (remaining == 0) {
return done();
}
remaining--;
cursor.value = buffer[cursor.index = oneRight(cursor.index, buffer.length)];
return cursor;
}
}
/** An iterator implementation for {@link ObjectArrayDeque#descendingIterator()}. */
private final class DescendingValueIterator extends AbstractIterator<CharCursor> {
private final CharCursor cursor;
private int remaining;
public DescendingValueIterator() {
cursor = new CharCursor();
cursor.index = tail;
this.remaining = size();
}
@Override
protected CharCursor fetch() {
if (remaining == 0) return done();
remaining--;
cursor.value = buffer[cursor.index = oneLeft(cursor.index, buffer.length)];
return cursor;
}
}
/**
* Returns a cursor over the values of this deque (in head to tail order). The iterator is
* implemented as a cursor and it returns <b>the same cursor instance</b> on every call to {@link
* Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in
* the deque's buffer) use the cursor's public fields. An example is shown below.
*
* <pre>
* for (IntValueCursor c : intDeque) {
* System.out.println(&quot;buffer index=&quot; + c.index + &quot; value=&quot; + c.value);
* }
* </pre>
*/
public Iterator<CharCursor> iterator() {
return new ValueIterator();
}
/**
* Returns a cursor over the values of this deque (in tail to head order). The iterator is
* implemented as a cursor and it returns <b>the same cursor instance</b> on every call to {@link
* Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in
* the deque's buffer) use the cursor's public fields. An example is shown below.
*
* <pre>
* for (Iterator&lt;IntCursor&gt; i = intDeque.descendingIterator(); i.hasNext();) {
* final IntCursor c = i.next();
* System.out.println(&quot;buffer index=&quot; + c.index + &quot; value=&quot; + c.value);
* }
* </pre>
*/
public Iterator<CharCursor> descendingIterator() {
return new DescendingValueIterator();
}
/** {@inheritDoc} */
@Override
public <T extends CharProcedure> T forEach(T procedure) {
forEach(procedure, head, tail);
return procedure;
}
/**
* Applies <code>procedure</code> to a slice of the deque, <code>fromIndex</code>, inclusive, to
* <code>toIndex</code>, exclusive.
*/
private void forEach(CharProcedure procedure, int fromIndex, final int toIndex) {
final char[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
procedure.apply(buffer[i]);
}
}
/** {@inheritDoc} */
@Override
public <T extends CharPredicate> T forEach(T predicate) {
int fromIndex = head;
int toIndex = tail;
final char[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
if (!predicate.apply(buffer[i])) {
break;
}
}
return predicate;
}
/** Applies <code>procedure</code> to all elements of this deque, tail to head. */
@Override
public <T extends CharProcedure> T descendingForEach(T procedure) {
descendingForEach(procedure, head, tail);
return procedure;
}
/**
* Applies <code>procedure</code> to a slice of the deque, <code>toIndex</code>, exclusive, down
* to <code>fromIndex</code>, inclusive.
*/
private void descendingForEach(CharProcedure procedure, int fromIndex, final int toIndex) {
if (fromIndex == toIndex) return;
final char[] buffer = this.buffer;
int i = toIndex;
do {
i = oneLeft(i, buffer.length);
procedure.apply(buffer[i]);
} while (i != fromIndex);
}
/** {@inheritDoc} */
@Override
public <T extends CharPredicate> T descendingForEach(T predicate) {
descendingForEach(predicate, head, tail);
return predicate;
}
/**
* Applies <code>predicate</code> to a slice of the deque, <code>toIndex</code>, exclusive, down
* to <code>fromIndex</code>, inclusive or until the predicate returns <code>false</code>.
*/
private void descendingForEach(CharPredicate predicate, int fromIndex, final int toIndex) {
if (fromIndex == toIndex) return;
final char[] buffer = this.buffer;
int i = toIndex;
do {
i = oneLeft(i, buffer.length);
if (!predicate.apply(buffer[i])) {
break;
}
} while (i != fromIndex);
}
/** {@inheritDoc} */
@Override
public int removeAll(CharPredicate predicate) {
final char[] buffer = this.buffer;
final int last = tail;
final int bufLen = buffer.length;
int removed = 0;
int from, to;
from = to = head;
try {
for (from = to = head; from != last; from = oneRight(from, bufLen)) {
if (predicate.apply(buffer[from])) {
buffer[from] = ((char) 0);
removed++;
continue;
}
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = ((char) 0);
}
to = oneRight(to, bufLen);
}
} finally {
// Keep the deque in consistent state even if the predicate throws an exception.
for (; from != last; from = oneRight(from, bufLen)) {
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = ((char) 0);
}
to = oneRight(to, bufLen);
}
tail = to;
}
return removed;
}
/** {@inheritDoc} */
@Override
public boolean contains(char e) {
int fromIndex = head;
int toIndex = tail;
final char[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
if (((e) == (buffer[i]))) {
return true;
}
}
return false;
}
/** {@inheritDoc} */
@Override
public int hashCode() {
int h = 1;
int fromIndex = head;
int toIndex = tail;
final char[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
h = 31 * h + BitMixer.mix(this.buffer[i]);
}
return h;
}
/**
* Returns <code>true</code> only if the other object is an instance of the same class and with
* the same elements.
*/
@Override
public boolean equals(Object obj) {
return (this == obj)
|| (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj)));
}
/** Compare order-aligned elements against another {@link CharDeque}. */
protected boolean equalElements(CharArrayDeque other) {
int max = size();
if (other.size() != max) {
return false;
}
Iterator<CharCursor> i1 = this.iterator();
Iterator<? extends CharCursor> i2 = other.iterator();
while (i1.hasNext() && i2.hasNext()) {
if (!((i1.next().value) == (i2.next().value))) {
return false;
}
}
return !i1.hasNext() && !i2.hasNext();
}
/** Create a new deque by pushing a variable number of arguments to the end of it. */
public static CharArrayDeque from(char... elements) {
final CharArrayDeque coll = new CharArrayDeque(elements.length);
coll.addLast(elements);
return coll;
}
}

View File

@ -0,0 +1,579 @@
package com.carrotsearch.hppc;
import static com.carrotsearch.hppc.Containers.*;
import com.carrotsearch.hppc.cursors.*;
import com.carrotsearch.hppc.predicates.CharPredicate;
import com.carrotsearch.hppc.procedures.*;
import java.util.*;
/** An array-backed list of chars. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayList.java")
public class CharArrayList extends AbstractCharCollection
implements CharIndexedContainer, Preallocable, Cloneable, Accountable {
/** An immutable empty buffer (array). */
public static final char[] EMPTY_ARRAY = new char[0];
;
/** Reuse the same strategy instance. */
private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY =
BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE;
/**
* Internal array for storing the list. The array may be larger than the current size ({@link
* #size()}).
*/
public char[] buffer = EMPTY_ARRAY;
/** Current number of elements stored in {@link #buffer}. */
public int elementsCount;
/** Buffer resizing strategy. */
protected final ArraySizingStrategy resizer;
/** New instance with sane defaults. */
public CharArrayList() {
this(DEFAULT_EXPECTED_ELEMENTS);
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
*/
public CharArrayList(int expectedElements) {
this(expectedElements, DEFAULT_SIZING_STRATEGY);
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
* @param resizer Underlying buffer sizing strategy.
*/
public CharArrayList(int expectedElements, ArraySizingStrategy resizer) {
assert resizer != null;
this.resizer = resizer;
buffer = Arrays.copyOf(buffer, expectedElements);
}
/** Creates a new list from the elements of another container in its iteration order. */
public CharArrayList(CharContainer container) {
this(container.size());
addAll(container);
}
/** {@inheritDoc} */
@Override
public void add(char e1) {
ensureBufferSpace(1);
buffer[elementsCount++] = e1;
}
/**
* Appends two elements at the end of the list. To add more than two elements, use <code>add
* </code> (vararg-version) or access the buffer directly (tight loop).
*/
public void add(char e1, char e2) {
ensureBufferSpace(2);
buffer[elementsCount++] = e1;
buffer[elementsCount++] = e2;
}
/** Add all elements from a range of given array to the list. */
public void add(char[] elements, int start, int length) {
assert length >= 0 : "Length must be >= 0";
ensureBufferSpace(length);
System.arraycopy(elements, start, buffer, elementsCount, length);
elementsCount += length;
}
/**
* Vararg-signature method for adding elements at the end of the list.
*
* <p><b>This method is handy, but costly if used in tight loops (anonymous array passing)</b>
*/
public final void add(char... elements) {
add(elements, 0, elements.length);
}
/** Adds all elements from another container. */
public int addAll(CharContainer container) {
final int size = container.size();
ensureBufferSpace(size);
for (CharCursor cursor : container) {
add(cursor.value);
}
return size;
}
/** Adds all elements from another iterable. */
public int addAll(Iterable<? extends CharCursor> iterable) {
int size = 0;
for (CharCursor cursor : iterable) {
add(cursor.value);
size++;
}
return size;
}
/** {@inheritDoc} */
@Override
public void insert(int index, char e1) {
assert (index >= 0 && index <= size())
: "Index " + index + " out of bounds [" + 0 + ", " + size() + "].";
ensureBufferSpace(1);
System.arraycopy(buffer, index, buffer, index + 1, elementsCount - index);
buffer[index] = e1;
elementsCount++;
}
/** {@inheritDoc} */
@Override
public char get(int index) {
assert (index >= 0 && index < size())
: "Index " + index + " out of bounds [" + 0 + ", " + size() + ").";
return buffer[index];
}
/** {@inheritDoc} */
@Override
public char set(int index, char e1) {
assert (index >= 0 && index < size())
: "Index " + index + " out of bounds [" + 0 + ", " + size() + ").";
final char v = buffer[index];
buffer[index] = e1;
return v;
}
/** {@inheritDoc} */
@Override
public char removeAt(int index) {
assert (index >= 0 && index < size())
: "Index " + index + " out of bounds [" + 0 + ", " + size() + ").";
final char v = buffer[index];
System.arraycopy(buffer, index + 1, buffer, index, --elementsCount - index);
return v;
}
/** {@inheritDoc} */
@Override
public char removeLast() {
assert elementsCount > 0;
final char v = buffer[--elementsCount];
return v;
}
/** {@inheritDoc} */
@Override
public void removeRange(int fromIndex, int toIndex) {
assert (fromIndex >= 0 && fromIndex <= size())
: "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ").";
assert (toIndex >= 0 && toIndex <= size())
: "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "].";
assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex;
System.arraycopy(buffer, toIndex, buffer, fromIndex, elementsCount - toIndex);
final int count = toIndex - fromIndex;
elementsCount -= count;
}
/** {@inheritDoc} */
@Override
public boolean removeElement(char e1) {
return removeFirst(e1) != -1;
}
/** {@inheritDoc} */
@Override
public int removeFirst(char e1) {
final int index = indexOf(e1);
if (index >= 0) removeAt(index);
return index;
}
/** {@inheritDoc} */
@Override
public int removeLast(char e1) {
final int index = lastIndexOf(e1);
if (index >= 0) removeAt(index);
return index;
}
/** {@inheritDoc} */
@Override
public int removeAll(char e1) {
int to = 0;
for (int from = 0; from < elementsCount; from++) {
if (((e1) == (buffer[from]))) {
continue;
}
if (to != from) {
buffer[to] = buffer[from];
}
to++;
}
final int deleted = elementsCount - to;
this.elementsCount = to;
return deleted;
}
/** {@inheritDoc} */
@Override
public boolean contains(char e1) {
return indexOf(e1) >= 0;
}
/** {@inheritDoc} */
@Override
public int indexOf(char e1) {
for (int i = 0; i < elementsCount; i++) {
if (((e1) == (buffer[i]))) {
return i;
}
}
return -1;
}
/** {@inheritDoc} */
@Override
public int lastIndexOf(char e1) {
for (int i = elementsCount - 1; i >= 0; i--) {
if (((e1) == (buffer[i]))) {
return i;
}
}
return -1;
}
/** {@inheritDoc} */
@Override
public boolean isEmpty() {
return elementsCount == 0;
}
/**
* Ensure this container can hold at least the given number of elements without resizing its
* buffers.
*
* @param expectedElements The total number of elements, inclusive.
*/
@Override
public void ensureCapacity(int expectedElements) {
final int bufferLen = (buffer == null ? 0 : buffer.length);
if (expectedElements > bufferLen) {
ensureBufferSpace(expectedElements - size());
}
}
/**
* Ensures the internal buffer has enough free slots to store <code>expectedAdditions</code>.
* Increases internal buffer size if needed.
*/
protected void ensureBufferSpace(int expectedAdditions) {
final int bufferLen = (buffer == null ? 0 : buffer.length);
if (elementsCount + expectedAdditions > bufferLen) {
final int newSize = resizer.grow(bufferLen, elementsCount, expectedAdditions);
assert newSize >= elementsCount + expectedAdditions
: "Resizer failed to"
+ " return sensible new size: "
+ newSize
+ " <= "
+ (elementsCount + expectedAdditions);
this.buffer = Arrays.copyOf(buffer, newSize);
}
}
/**
* Truncate or expand the list to the new size. If the list is truncated, the buffer will not be
* reallocated (use {@link #trimToSize()} if you need a truncated buffer), but the truncated
* values will be reset to the default value (zero). If the list is expanded, the elements beyond
* the current size are initialized with JVM-defaults (zero or <code>null</code> values).
*/
public void resize(int newSize) {
if (newSize <= buffer.length) {
if (newSize < elementsCount) {
Arrays.fill(buffer, newSize, elementsCount, ((char) 0));
} else {
Arrays.fill(buffer, elementsCount, newSize, ((char) 0));
}
} else {
ensureCapacity(newSize);
}
this.elementsCount = newSize;
}
/** {@inheritDoc} */
@Override
public int size() {
return elementsCount;
}
/** Trim the internal buffer to the current size. */
public void trimToSize() {
if (size() != this.buffer.length) {
this.buffer = toArray();
}
}
/**
* Sets the number of stored elements to zero. Releases and initializes the internal storage array
* to default values. To clear the list without cleaning the buffer, simply set the {@link
* #elementsCount} field to zero.
*/
@Override
public void clear() {
Arrays.fill(buffer, 0, elementsCount, ((char) 0));
this.elementsCount = 0;
}
/** Sets the number of stored elements to zero and releases the internal storage array. */
@Override
public void release() {
this.buffer = EMPTY_ARRAY;
this.elementsCount = 0;
}
/**
* {@inheritDoc}
*
* <p>The returned array is sized to match exactly the number of elements of the stack.
*/
@Override
public char[] toArray() {
return Arrays.copyOf(buffer, elementsCount);
}
/** {@inheritDoc} */
@Override
public CharIndexedContainer sort() {
Arrays.sort(buffer, 0, elementsCount);
return this;
}
/** {@inheritDoc} */
@Override
public CharIndexedContainer reverse() {
for (int i = 0, mid = elementsCount >> 1, j = elementsCount - 1; i < mid; i++, j--) {
char tmp = buffer[i];
buffer[i] = buffer[j];
buffer[j] = tmp;
}
return this;
}
/**
* Clone this object. The returned clone will reuse the same hash function and array resizing
* strategy.
*/
@Override
public CharArrayList clone() {
try {
final CharArrayList cloned = (CharArrayList) super.clone();
cloned.buffer = buffer.clone();
return cloned;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
/** {@inheritDoc} */
@Override
public int hashCode() {
int h = 1, max = elementsCount;
for (int i = 0; i < max; i++) {
h = 31 * h + BitMixer.mix(this.buffer[i]);
}
return h;
}
/**
* Returns <code>true</code> only if the other object is an instance of the same class and with
* the same elements.
*/
@Override
public boolean equals(Object obj) {
return (this == obj)
|| (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj)));
}
/** Compare index-aligned elements against another {@link CharIndexedContainer}. */
protected boolean equalElements(CharArrayList other) {
int max = size();
if (other.size() != max) {
return false;
}
for (int i = 0; i < max; i++) {
if (!((get(i)) == (other.get(i)))) {
return false;
}
}
return true;
}
@Override
public long ramBytesAllocated() {
// int: elementsCount
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ Integer.BYTES
+ resizer.ramBytesAllocated()
+ RamUsageEstimator.shallowSizeOfArray(buffer);
}
@Override
public long ramBytesUsed() {
// int: elementsCount
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ Integer.BYTES
+ resizer.ramBytesUsed()
+ RamUsageEstimator.shallowUsedSizeOfArray(buffer, elementsCount);
}
/** An iterator implementation for {@link CharArrayList#iterator}. */
static final class ValueIterator extends AbstractIterator<CharCursor> {
private final CharCursor cursor;
private final char[] buffer;
private final int size;
public ValueIterator(char[] buffer, int size) {
this.cursor = new CharCursor();
this.cursor.index = -1;
this.size = size;
this.buffer = buffer;
}
@Override
protected CharCursor fetch() {
if (cursor.index + 1 == size) return done();
cursor.value = buffer[++cursor.index];
return cursor;
}
}
/** {@inheritDoc} */
@Override
public Iterator<CharCursor> iterator() {
return new ValueIterator(buffer, size());
}
/** {@inheritDoc} */
@Override
public <T extends CharProcedure> T forEach(T procedure) {
return forEach(procedure, 0, size());
}
/**
* Applies <code>procedure</code> to a slice of the list, <code>fromIndex</code>, inclusive, to
* <code>toIndex</code>, exclusive.
*/
public <T extends CharProcedure> T forEach(T procedure, int fromIndex, final int toIndex) {
assert (fromIndex >= 0 && fromIndex <= size())
: "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ").";
assert (toIndex >= 0 && toIndex <= size())
: "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "].";
assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex;
final char[] buffer = this.buffer;
for (int i = fromIndex; i < toIndex; i++) {
procedure.apply(buffer[i]);
}
return procedure;
}
/** {@inheritDoc} */
@Override
public int removeAll(CharPredicate predicate) {
final char[] buffer = this.buffer;
final int elementsCount = this.elementsCount;
int to = 0;
int from = 0;
try {
for (; from < elementsCount; from++) {
if (predicate.apply(buffer[from])) {
buffer[from] = ((char) 0);
continue;
}
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = ((char) 0);
}
to++;
}
} finally {
// Keep the list in a consistent state, even if the predicate throws an exception.
for (; from < elementsCount; from++) {
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = ((char) 0);
}
to++;
}
this.elementsCount = to;
}
return elementsCount - to;
}
/** {@inheritDoc} */
@Override
public <T extends CharPredicate> T forEach(T predicate) {
return forEach(predicate, 0, size());
}
/**
* Applies <code>predicate</code> to a slice of the list, <code>fromIndex</code>, inclusive, to
* <code>toIndex</code>, exclusive, or until predicate returns <code>false</code>.
*/
public <T extends CharPredicate> T forEach(T predicate, int fromIndex, final int toIndex) {
assert (fromIndex >= 0 && fromIndex <= size())
: "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ").";
assert (toIndex >= 0 && toIndex <= size())
: "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "].";
assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex;
final char[] buffer = this.buffer;
for (int i = fromIndex; i < toIndex; i++) {
if (!predicate.apply(buffer[i])) break;
}
return predicate;
}
/**
* Create a list from a variable number of arguments or an array of <code>char</code>. The
* elements are copied from the argument to the internal buffer.
*/
public static CharArrayList from(char... elements) {
final CharArrayList list = new CharArrayList(elements.length);
list.add(elements);
return list;
}
}

View File

@ -0,0 +1,33 @@
package com.carrotsearch.hppc;
/**
* Reused buffer visualization routines.
*
* @see CharSet#visualizeKeyDistribution(int)
* @see CharVTypeMap#visualizeKeyDistribution(int)
*/
class CharBufferVisualizer {
static String visualizeKeyDistribution(char[] buffer, int max, int characters) {
final StringBuilder b = new StringBuilder();
final char[] chars = ".123456789X".toCharArray();
for (int i = 1, start = -1; i <= characters; i++) {
int end = (int) ((long) i * max / characters);
if (start + 1 <= end) {
int taken = 0;
int slots = 0;
for (int slot = start + 1; slot <= end; slot++, slots++) {
if (!((buffer[slot]) == 0)) {
taken++;
}
}
b.append(chars[Math.min(chars.length - 1, taken * chars.length / slots)]);
start = end;
}
}
while (b.length() < characters) {
b.append(' ');
}
return b.toString();
}
}

View File

@ -0,0 +1,105 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.*;
import com.carrotsearch.hppc.predicates.*;
import com.carrotsearch.hppc.procedures.*;
import java.util.Iterator;
/**
* An associative container from keys to (one or possibly more) values.
*
* @see CharContainer
*/
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "KTypeVTypeAssociativeContainer.java")
public interface CharByteAssociativeContainer extends Iterable<CharByteCursor> {
/**
* Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as
* a cursor and it returns <b>the same cursor instance</b> on every call to {@link
* Iterator#next()}. To read the current key and value use the cursor's public fields. An example
* is shown below.
*
* <pre>
* for (IntShortCursor c : intShortMap) {
* System.out.println(&quot;index=&quot; + c.index + &quot; key=&quot; + c.key + &quot; value=&quot; + c.value);
* }</pre>
*
* <p>The <code>index</code> field inside the cursor gives the internal index inside the
* container's implementation. The interpretation of this index depends on to the container.
*/
@Override
public Iterator<CharByteCursor> iterator();
/**
* Returns <code>true</code> if this container has an association to a value for the given key.
*/
public boolean containsKey(char key);
/**
* @return Returns the current size (number of assigned keys) in the container.
*/
public int size();
/**
* @return Return <code>true</code> if this hash map contains no assigned keys.
*/
public boolean isEmpty();
/**
* Removes all keys (and associated values) present in a given container. An alias to:
*
* <pre>
* keys().removeAll(container)
* </pre>
*
* but with no additional overhead.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharContainer container);
/**
* Removes all keys (and associated values) for which the predicate returns <code>true</code>.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharPredicate predicate);
/**
* Removes all keys (and associated values) for which the predicate returns <code>true</code>.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharBytePredicate predicate);
/**
* Applies a given procedure to all keys-value pairs in this container. Returns the argument (any
* subclass of {@link CharByteProcedure}. This lets the caller call methods of the argument by
* chaining the call (even if the argument is an anonymous type) to retrieve computed values.
*/
public <T extends CharByteProcedure> T forEach(T procedure);
/**
* Applies a given predicate to all keys-value pairs in this container. Returns the argument (any
* subclass of {@link CharBytePredicate}. This lets the caller call methods of the argument by
* chaining the call (even if the argument is an anonymous type) to retrieve computed values.
*
* <p>The iteration is continued as long as the predicate returns <code>true</code>.
*/
public <T extends CharBytePredicate> T forEach(T predicate);
/**
* Returns a collection of keys of this container. The returned collection is a view over the key
* set and any modifications (if allowed) introduced to the collection will propagate to the
* associative container immediately.
*/
public CharCollection keys();
/**
* Returns a container view of all values present in this container. The returned collection is a
* view over the key set and any modifications (if allowed) introduced to the collection will
* propagate to the associative container immediately.
*/
public ByteContainer values();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,205 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.CharByteCursor;
/** An associative container with unique binding from keys to a single value. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java")
public interface CharByteMap extends CharByteAssociativeContainer {
/**
* @return Returns the value associated with the given key or the default value for the value
* type, if the key is not associated with any value. For numeric value types, this default
* value is 0, for object types it is {@code null}.
*/
public byte get(char key);
/**
* @return Returns the value associated with the given key or the provided default value if the
* key is not associated with any value.
*/
public byte getOrDefault(char key, byte defaultValue);
/**
* Place a given key and value in the container.
*
* @return The value previously stored under the given key in the map is returned.
*/
public byte put(char key, byte value);
/**
* If the specified key is not already associated with a value, associates it with the given
* value.
*
* @return {@code true} if {@code key} did not exist and {@code value} was placed in the map,
* {@code false} otherwise.
*/
public default boolean putIfAbsent(char key, byte value) {
int keyIndex = indexOf(key);
if (indexExists(keyIndex)) {
return false;
} else {
indexInsert(keyIndex, key, value);
return true;
}
}
/**
* Puts all keys from another container to this map, replacing the values of existing keys, if
* such keys are present.
*
* @return Returns the number of keys added to the map as a result of this call (not previously
* present in the map). Values of existing keys are overwritten.
*/
public int putAll(CharByteAssociativeContainer container);
/**
* Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if
* such keys are present.
*
* @return Returns the number of keys added to the map as a result of this call (not previously
* present in the map). Values of existing keys are overwritten.
*/
public int putAll(Iterable<? extends CharByteCursor> iterable);
/**
* If <code>key</code> exists, <code>putValue</code> is inserted into the map, otherwise any
* existing value is incremented by <code>additionValue</code>.
*
* @param key The key of the value to adjust.
* @param putValue The value to put if <code>key</code> does not exist.
* @param incrementValue The value to add to the existing value if <code>key</code> exists.
* @return Returns the current value associated with <code>key</code> (after changes).
*/
public byte putOrAdd(char key, byte putValue, byte incrementValue);
/**
* An equivalent of calling
*
* <pre>
* putOrAdd(key, additionValue, additionValue);
* </pre>
*
* @param key The key of the value to adjust.
* @param additionValue The value to put or add to the existing value if <code>key</code> exists.
* @return Returns the current value associated with <code>key</code> (after changes).
*/
public byte addTo(char key, byte additionValue);
/**
* Remove all values at the given key. The default value for the key type is returned if the value
* does not exist in the map.
*/
public byte remove(char key);
/**
* Compares the specified object with this set for equality. Returns {@code true} if and only if
* the specified object is also a {@link CharByteMap} and both objects contains exactly the same
* key-value pairs.
*/
public boolean equals(Object obj);
/**
* @return A hash code of elements stored in the map. The hash code is defined as a sum of hash
* codes of keys and values stored within the set). Because sum is commutative, this ensures
* that different order of elements in a set does not affect the hash code.
*/
public int hashCode();
/**
* Returns a logical "index" of a given key that can be used to speed up follow-up value setters
* or getters in certain scenarios (conditional logic).
*
* <p>The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be)
* contiguous.
*
* <p>The index is valid only between map modifications (it will not be affected by read-only
* operations like iteration or value retrievals).
*
* @see #indexExists
* @see #indexGet
* @see #indexInsert
* @see #indexReplace
* @param key The key to locate in the map.
* @return A non-negative value of the logical "index" of the key in the map or a negative value
* if the key did not exist.
*/
public int indexOf(char key);
/**
* @see #indexOf
* @param index The index of a given key, as returned from {@link #indexOf}.
* @return Returns <code>true</code> if the index corresponds to an existing key or false
* otherwise. This is equivalent to checking whether the index is a positive value (existing
* keys) or a negative value (non-existing keys).
*/
public boolean indexExists(int index);
/**
* Returns the value associated with an existing key.
*
* @see #indexOf
* @param index The index of an existing key.
* @return Returns the value currently associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public byte indexGet(int index);
/**
* Replaces the value associated with an existing key and returns any previous value stored for
* that key.
*
* @see #indexOf
* @param index The index of an existing key.
* @return Returns the previous value associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public byte indexReplace(int index, byte newValue);
/**
* Inserts a key-value pair for a key that is not present in the map. This method may help in
* avoiding double recalculation of the key's hash.
*
* @see #indexOf
* @param index The index of a previously non-existing key, as returned from {@link #indexOf}.
* @throws AssertionError If assertions are enabled and the index corresponds to an existing key.
*/
public void indexInsert(int index, char key, byte value);
/**
* Removes a key-value pair at an index previously acquired from {@link #indexOf}.
*
* @see #indexOf
* @param index The index of the key to remove, as returned from {@link #indexOf}.
* @return Returns the previous value associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public byte indexRemove(int index);
/**
* Clear all keys and values in the container.
*
* @see #release()
*/
public void clear();
/**
* Removes all elements from the collection and additionally releases any internal buffers.
* Typically, if the object is to be reused, a simple {@link #clear()} should be a better
* alternative since it'll avoid reallocation.
*
* @see #clear()
*/
public void release();
/**
* Visually depict the distribution of keys.
*
* @param characters The number of characters to "squeeze" the entire buffer into.
* @return Returns a sequence of characters where '.' depicts an empty fragment of the internal
* buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything
* between 1 and 9 is between.
*/
public String visualizeKeyDistribution(int characters);
}

View File

@ -0,0 +1,105 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.*;
import com.carrotsearch.hppc.predicates.*;
import com.carrotsearch.hppc.procedures.*;
import java.util.Iterator;
/**
* An associative container from keys to (one or possibly more) values.
*
* @see CharContainer
*/
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "KTypeVTypeAssociativeContainer.java")
public interface CharCharAssociativeContainer extends Iterable<CharCharCursor> {
/**
* Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as
* a cursor and it returns <b>the same cursor instance</b> on every call to {@link
* Iterator#next()}. To read the current key and value use the cursor's public fields. An example
* is shown below.
*
* <pre>
* for (IntShortCursor c : intShortMap) {
* System.out.println(&quot;index=&quot; + c.index + &quot; key=&quot; + c.key + &quot; value=&quot; + c.value);
* }</pre>
*
* <p>The <code>index</code> field inside the cursor gives the internal index inside the
* container's implementation. The interpretation of this index depends on to the container.
*/
@Override
public Iterator<CharCharCursor> iterator();
/**
* Returns <code>true</code> if this container has an association to a value for the given key.
*/
public boolean containsKey(char key);
/**
* @return Returns the current size (number of assigned keys) in the container.
*/
public int size();
/**
* @return Return <code>true</code> if this hash map contains no assigned keys.
*/
public boolean isEmpty();
/**
* Removes all keys (and associated values) present in a given container. An alias to:
*
* <pre>
* keys().removeAll(container)
* </pre>
*
* but with no additional overhead.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharContainer container);
/**
* Removes all keys (and associated values) for which the predicate returns <code>true</code>.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharPredicate predicate);
/**
* Removes all keys (and associated values) for which the predicate returns <code>true</code>.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharCharPredicate predicate);
/**
* Applies a given procedure to all keys-value pairs in this container. Returns the argument (any
* subclass of {@link CharCharProcedure}. This lets the caller call methods of the argument by
* chaining the call (even if the argument is an anonymous type) to retrieve computed values.
*/
public <T extends CharCharProcedure> T forEach(T procedure);
/**
* Applies a given predicate to all keys-value pairs in this container. Returns the argument (any
* subclass of {@link CharCharPredicate}. This lets the caller call methods of the argument by
* chaining the call (even if the argument is an anonymous type) to retrieve computed values.
*
* <p>The iteration is continued as long as the predicate returns <code>true</code>.
*/
public <T extends CharCharPredicate> T forEach(T predicate);
/**
* Returns a collection of keys of this container. The returned collection is a view over the key
* set and any modifications (if allowed) introduced to the collection will propagate to the
* associative container immediately.
*/
public CharCollection keys();
/**
* Returns a container view of all values present in this container. The returned collection is a
* view over the key set and any modifications (if allowed) introduced to the collection will
* propagate to the associative container immediately.
*/
public CharContainer values();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,205 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.CharCharCursor;
/** An associative container with unique binding from keys to a single value. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java")
public interface CharCharMap extends CharCharAssociativeContainer {
/**
* @return Returns the value associated with the given key or the default value for the value
* type, if the key is not associated with any value. For numeric value types, this default
* value is 0, for object types it is {@code null}.
*/
public char get(char key);
/**
* @return Returns the value associated with the given key or the provided default value if the
* key is not associated with any value.
*/
public char getOrDefault(char key, char defaultValue);
/**
* Place a given key and value in the container.
*
* @return The value previously stored under the given key in the map is returned.
*/
public char put(char key, char value);
/**
* If the specified key is not already associated with a value, associates it with the given
* value.
*
* @return {@code true} if {@code key} did not exist and {@code value} was placed in the map,
* {@code false} otherwise.
*/
public default boolean putIfAbsent(char key, char value) {
int keyIndex = indexOf(key);
if (indexExists(keyIndex)) {
return false;
} else {
indexInsert(keyIndex, key, value);
return true;
}
}
/**
* Puts all keys from another container to this map, replacing the values of existing keys, if
* such keys are present.
*
* @return Returns the number of keys added to the map as a result of this call (not previously
* present in the map). Values of existing keys are overwritten.
*/
public int putAll(CharCharAssociativeContainer container);
/**
* Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if
* such keys are present.
*
* @return Returns the number of keys added to the map as a result of this call (not previously
* present in the map). Values of existing keys are overwritten.
*/
public int putAll(Iterable<? extends CharCharCursor> iterable);
/**
* If <code>key</code> exists, <code>putValue</code> is inserted into the map, otherwise any
* existing value is incremented by <code>additionValue</code>.
*
* @param key The key of the value to adjust.
* @param putValue The value to put if <code>key</code> does not exist.
* @param incrementValue The value to add to the existing value if <code>key</code> exists.
* @return Returns the current value associated with <code>key</code> (after changes).
*/
public char putOrAdd(char key, char putValue, char incrementValue);
/**
* An equivalent of calling
*
* <pre>
* putOrAdd(key, additionValue, additionValue);
* </pre>
*
* @param key The key of the value to adjust.
* @param additionValue The value to put or add to the existing value if <code>key</code> exists.
* @return Returns the current value associated with <code>key</code> (after changes).
*/
public char addTo(char key, char additionValue);
/**
* Remove all values at the given key. The default value for the key type is returned if the value
* does not exist in the map.
*/
public char remove(char key);
/**
* Compares the specified object with this set for equality. Returns {@code true} if and only if
* the specified object is also a {@link CharCharMap} and both objects contains exactly the same
* key-value pairs.
*/
public boolean equals(Object obj);
/**
* @return A hash code of elements stored in the map. The hash code is defined as a sum of hash
* codes of keys and values stored within the set). Because sum is commutative, this ensures
* that different order of elements in a set does not affect the hash code.
*/
public int hashCode();
/**
* Returns a logical "index" of a given key that can be used to speed up follow-up value setters
* or getters in certain scenarios (conditional logic).
*
* <p>The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be)
* contiguous.
*
* <p>The index is valid only between map modifications (it will not be affected by read-only
* operations like iteration or value retrievals).
*
* @see #indexExists
* @see #indexGet
* @see #indexInsert
* @see #indexReplace
* @param key The key to locate in the map.
* @return A non-negative value of the logical "index" of the key in the map or a negative value
* if the key did not exist.
*/
public int indexOf(char key);
/**
* @see #indexOf
* @param index The index of a given key, as returned from {@link #indexOf}.
* @return Returns <code>true</code> if the index corresponds to an existing key or false
* otherwise. This is equivalent to checking whether the index is a positive value (existing
* keys) or a negative value (non-existing keys).
*/
public boolean indexExists(int index);
/**
* Returns the value associated with an existing key.
*
* @see #indexOf
* @param index The index of an existing key.
* @return Returns the value currently associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public char indexGet(int index);
/**
* Replaces the value associated with an existing key and returns any previous value stored for
* that key.
*
* @see #indexOf
* @param index The index of an existing key.
* @return Returns the previous value associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public char indexReplace(int index, char newValue);
/**
* Inserts a key-value pair for a key that is not present in the map. This method may help in
* avoiding double recalculation of the key's hash.
*
* @see #indexOf
* @param index The index of a previously non-existing key, as returned from {@link #indexOf}.
* @throws AssertionError If assertions are enabled and the index corresponds to an existing key.
*/
public void indexInsert(int index, char key, char value);
/**
* Removes a key-value pair at an index previously acquired from {@link #indexOf}.
*
* @see #indexOf
* @param index The index of the key to remove, as returned from {@link #indexOf}.
* @return Returns the previous value associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public char indexRemove(int index);
/**
* Clear all keys and values in the container.
*
* @see #release()
*/
public void clear();
/**
* Removes all elements from the collection and additionally releases any internal buffers.
* Typically, if the object is to be reused, a simple {@link #clear()} should be a better
* alternative since it'll avoid reallocation.
*
* @see #clear()
*/
public void release();
/**
* Visually depict the distribution of keys.
*
* @param characters The number of characters to "squeeze" the entire buffer into.
* @return Returns a sequence of characters where '.' depicts an empty fragment of the internal
* buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything
* between 1 and 9 is between.
*/
public String visualizeKeyDistribution(int characters);
}

View File

@ -0,0 +1,64 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.predicates.CharPredicate;
/**
* A collection allows basic, efficient operations on sets of elements (difference and
* intersection).
*/
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCollection.java")
public interface CharCollection extends CharContainer {
/**
* Removes all occurrences of <code>e</code> from this collection.
*
* @param e Element to be removed from this collection, if present.
* @return The number of removed elements as a result of this call.
*/
public int removeAll(char e);
/**
* Removes all elements in this collection that are present in <code>c</code>.
*
* @return Returns the number of removed elements.
*/
public int removeAll(CharLookupContainer c);
/**
* Removes all elements in this collection for which the given predicate returns <code>true</code>
* .
*
* @return Returns the number of removed elements.
*/
public int removeAll(CharPredicate predicate);
/**
* Keeps all elements in this collection that are present in <code>c</code>. Runs in time
* proportional to the number of elements in this collection. Equivalent of sets intersection.
*
* @return Returns the number of removed elements.
*/
public int retainAll(CharLookupContainer c);
/**
* Keeps all elements in this collection for which the given predicate returns <code>true</code>.
*
* @return Returns the number of removed elements.
*/
public int retainAll(CharPredicate predicate);
/**
* Removes all elements from this collection.
*
* @see #release()
*/
public void clear();
/**
* Removes all elements from the collection and additionally releases any internal buffers.
* Typically, if the object is to be reused, a simple {@link #clear()} should be a better
* alternative since it'll avoid reallocation.
*
* @see #clear()
*/
public void release();
}

View File

@ -0,0 +1,76 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.CharCursor;
import com.carrotsearch.hppc.predicates.CharPredicate;
import com.carrotsearch.hppc.procedures.CharProcedure;
import java.util.Iterator;
/** A generic container holding <code>char</code>s. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeContainer.java")
public interface CharContainer extends Iterable<CharCursor> {
/**
* Returns an iterator to a cursor traversing the collection. The order of traversal is not
* defined. More than one cursor may be active at a time. The behavior of iterators is undefined
* if structural changes are made to the underlying collection.
*
* <p>The iterator is implemented as a cursor and it returns <b>the same cursor instance</b> on
* every call to {@link Iterator#next()} (to avoid boxing of primitive types). To read the current
* list's value (or index in the list) use the cursor's public fields. An example is shown below.
*
* <pre>
* for (CharCursor&lt;char&gt; c : container) {
* System.out.println(&quot;index=&quot; + c.index + &quot; value=&quot; + c.value);
* }
* </pre>
*/
public Iterator<CharCursor> iterator();
/**
* Lookup a given element in the container. This operation has no speed guarantees (may be linear
* with respect to the size of this container).
*
* @return Returns <code>true</code> if this container has an element equal to <code>e</code>.
*/
public boolean contains(char e);
/**
* Return the current number of elements in this container. The time for calculating the
* container's size may take <code>O(n)</code> time, although implementing classes should try to
* maintain the current size and return in constant time.
*/
public int size();
/** Shortcut for <code>size() == 0</code>. */
public boolean isEmpty();
/**
* Copies all elements of this container to an array.
*
* <p>The returned array is always a copy, regardless of the storage used by the container.
*/
public char[] toArray();
/**
* Applies a <code>procedure</code> to all container elements. Returns the argument (any subclass
* of {@link CharProcedure}. This lets the caller to call methods of the argument by chaining the
* call (even if the argument is an anonymous type) to retrieve computed values, for example
* (IntContainer):
*
* <pre>
* int count = container.forEach(new IntProcedure() {
* int count; // this is a field declaration in an anonymous class.
*
* public void apply(int value) {
* count++;
* }
* }).count;
* </pre>
*/
public <T extends CharProcedure> T forEach(T procedure);
/**
* Applies a <code>predicate</code> to container elements as long, as the predicate returns <code>
* true</code>. The iteration is interrupted otherwise.
*/
public <T extends CharPredicate> T forEach(T predicate);
}

View File

@ -0,0 +1,77 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.CharCursor;
import com.carrotsearch.hppc.predicates.CharPredicate;
import com.carrotsearch.hppc.procedures.CharProcedure;
import java.util.Deque;
import java.util.Iterator;
/**
* A linear collection that supports element insertion and removal at both ends.
*
* @see Deque
*/
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeDeque.java")
public interface CharDeque extends CharCollection {
/**
* Removes the first element that equals <code>e</code>.
*
* @return The deleted element's index or <code>-1</code> if the element was not found.
*/
public int removeFirst(char e);
/**
* Removes the last element that equals <code>e</code>.
*
* @return The deleted element's index or <code>-1</code> if the element was not found.
*/
public int removeLast(char e);
/** Inserts the specified element at the front of this deque. */
public void addFirst(char e);
/** Inserts the specified element at the end of this deque. */
public void addLast(char e);
/**
* Retrieves and removes the first element of this deque.
*
* @return the head (first) element of this deque.
*/
public char removeFirst();
/**
* Retrieves and removes the last element of this deque.
*
* @return the tail of this deque.
*/
public char removeLast();
/**
* Retrieves the first element of this deque but does not remove it.
*
* @return the head of this deque.
*/
public char getFirst();
/**
* Retrieves the last element of this deque but does not remove it.
*
* @return the head of this deque.
*/
public char getLast();
/**
* @return An iterator over elements in this deque in tail-to-head order.
*/
public Iterator<CharCursor> descendingIterator();
/** Applies a <code>procedure</code> to all elements in tail-to-head order. */
public <T extends CharProcedure> T descendingForEach(T procedure);
/**
* Applies a <code>predicate</code> to container elements as long, as the predicate returns <code>
* true</code>. The iteration is interrupted otherwise.
*/
public <T extends CharPredicate> T descendingForEach(T predicate);
}

View File

@ -0,0 +1,105 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.*;
import com.carrotsearch.hppc.predicates.*;
import com.carrotsearch.hppc.procedures.*;
import java.util.Iterator;
/**
* An associative container from keys to (one or possibly more) values.
*
* @see CharContainer
*/
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "KTypeVTypeAssociativeContainer.java")
public interface CharDoubleAssociativeContainer extends Iterable<CharDoubleCursor> {
/**
* Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as
* a cursor and it returns <b>the same cursor instance</b> on every call to {@link
* Iterator#next()}. To read the current key and value use the cursor's public fields. An example
* is shown below.
*
* <pre>
* for (IntShortCursor c : intShortMap) {
* System.out.println(&quot;index=&quot; + c.index + &quot; key=&quot; + c.key + &quot; value=&quot; + c.value);
* }</pre>
*
* <p>The <code>index</code> field inside the cursor gives the internal index inside the
* container's implementation. The interpretation of this index depends on to the container.
*/
@Override
public Iterator<CharDoubleCursor> iterator();
/**
* Returns <code>true</code> if this container has an association to a value for the given key.
*/
public boolean containsKey(char key);
/**
* @return Returns the current size (number of assigned keys) in the container.
*/
public int size();
/**
* @return Return <code>true</code> if this hash map contains no assigned keys.
*/
public boolean isEmpty();
/**
* Removes all keys (and associated values) present in a given container. An alias to:
*
* <pre>
* keys().removeAll(container)
* </pre>
*
* but with no additional overhead.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharContainer container);
/**
* Removes all keys (and associated values) for which the predicate returns <code>true</code>.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharPredicate predicate);
/**
* Removes all keys (and associated values) for which the predicate returns <code>true</code>.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharDoublePredicate predicate);
/**
* Applies a given procedure to all keys-value pairs in this container. Returns the argument (any
* subclass of {@link CharDoubleProcedure}. This lets the caller call methods of the argument by
* chaining the call (even if the argument is an anonymous type) to retrieve computed values.
*/
public <T extends CharDoubleProcedure> T forEach(T procedure);
/**
* Applies a given predicate to all keys-value pairs in this container. Returns the argument (any
* subclass of {@link CharDoublePredicate}. This lets the caller call methods of the argument by
* chaining the call (even if the argument is an anonymous type) to retrieve computed values.
*
* <p>The iteration is continued as long as the predicate returns <code>true</code>.
*/
public <T extends CharDoublePredicate> T forEach(T predicate);
/**
* Returns a collection of keys of this container. The returned collection is a view over the key
* set and any modifications (if allowed) introduced to the collection will propagate to the
* associative container immediately.
*/
public CharCollection keys();
/**
* Returns a container view of all values present in this container. The returned collection is a
* view over the key set and any modifications (if allowed) introduced to the collection will
* propagate to the associative container immediately.
*/
public DoubleContainer values();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,205 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.CharDoubleCursor;
/** An associative container with unique binding from keys to a single value. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java")
public interface CharDoubleMap extends CharDoubleAssociativeContainer {
/**
* @return Returns the value associated with the given key or the default value for the value
* type, if the key is not associated with any value. For numeric value types, this default
* value is 0, for object types it is {@code null}.
*/
public double get(char key);
/**
* @return Returns the value associated with the given key or the provided default value if the
* key is not associated with any value.
*/
public double getOrDefault(char key, double defaultValue);
/**
* Place a given key and value in the container.
*
* @return The value previously stored under the given key in the map is returned.
*/
public double put(char key, double value);
/**
* If the specified key is not already associated with a value, associates it with the given
* value.
*
* @return {@code true} if {@code key} did not exist and {@code value} was placed in the map,
* {@code false} otherwise.
*/
public default boolean putIfAbsent(char key, double value) {
int keyIndex = indexOf(key);
if (indexExists(keyIndex)) {
return false;
} else {
indexInsert(keyIndex, key, value);
return true;
}
}
/**
* Puts all keys from another container to this map, replacing the values of existing keys, if
* such keys are present.
*
* @return Returns the number of keys added to the map as a result of this call (not previously
* present in the map). Values of existing keys are overwritten.
*/
public int putAll(CharDoubleAssociativeContainer container);
/**
* Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if
* such keys are present.
*
* @return Returns the number of keys added to the map as a result of this call (not previously
* present in the map). Values of existing keys are overwritten.
*/
public int putAll(Iterable<? extends CharDoubleCursor> iterable);
/**
* If <code>key</code> exists, <code>putValue</code> is inserted into the map, otherwise any
* existing value is incremented by <code>additionValue</code>.
*
* @param key The key of the value to adjust.
* @param putValue The value to put if <code>key</code> does not exist.
* @param incrementValue The value to add to the existing value if <code>key</code> exists.
* @return Returns the current value associated with <code>key</code> (after changes).
*/
public double putOrAdd(char key, double putValue, double incrementValue);
/**
* An equivalent of calling
*
* <pre>
* putOrAdd(key, additionValue, additionValue);
* </pre>
*
* @param key The key of the value to adjust.
* @param additionValue The value to put or add to the existing value if <code>key</code> exists.
* @return Returns the current value associated with <code>key</code> (after changes).
*/
public double addTo(char key, double additionValue);
/**
* Remove all values at the given key. The default value for the key type is returned if the value
* does not exist in the map.
*/
public double remove(char key);
/**
* Compares the specified object with this set for equality. Returns {@code true} if and only if
* the specified object is also a {@link CharDoubleMap} and both objects contains exactly the same
* key-value pairs.
*/
public boolean equals(Object obj);
/**
* @return A hash code of elements stored in the map. The hash code is defined as a sum of hash
* codes of keys and values stored within the set). Because sum is commutative, this ensures
* that different order of elements in a set does not affect the hash code.
*/
public int hashCode();
/**
* Returns a logical "index" of a given key that can be used to speed up follow-up value setters
* or getters in certain scenarios (conditional logic).
*
* <p>The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be)
* contiguous.
*
* <p>The index is valid only between map modifications (it will not be affected by read-only
* operations like iteration or value retrievals).
*
* @see #indexExists
* @see #indexGet
* @see #indexInsert
* @see #indexReplace
* @param key The key to locate in the map.
* @return A non-negative value of the logical "index" of the key in the map or a negative value
* if the key did not exist.
*/
public int indexOf(char key);
/**
* @see #indexOf
* @param index The index of a given key, as returned from {@link #indexOf}.
* @return Returns <code>true</code> if the index corresponds to an existing key or false
* otherwise. This is equivalent to checking whether the index is a positive value (existing
* keys) or a negative value (non-existing keys).
*/
public boolean indexExists(int index);
/**
* Returns the value associated with an existing key.
*
* @see #indexOf
* @param index The index of an existing key.
* @return Returns the value currently associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public double indexGet(int index);
/**
* Replaces the value associated with an existing key and returns any previous value stored for
* that key.
*
* @see #indexOf
* @param index The index of an existing key.
* @return Returns the previous value associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public double indexReplace(int index, double newValue);
/**
* Inserts a key-value pair for a key that is not present in the map. This method may help in
* avoiding double recalculation of the key's hash.
*
* @see #indexOf
* @param index The index of a previously non-existing key, as returned from {@link #indexOf}.
* @throws AssertionError If assertions are enabled and the index corresponds to an existing key.
*/
public void indexInsert(int index, char key, double value);
/**
* Removes a key-value pair at an index previously acquired from {@link #indexOf}.
*
* @see #indexOf
* @param index The index of the key to remove, as returned from {@link #indexOf}.
* @return Returns the previous value associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public double indexRemove(int index);
/**
* Clear all keys and values in the container.
*
* @see #release()
*/
public void clear();
/**
* Removes all elements from the collection and additionally releases any internal buffers.
* Typically, if the object is to be reused, a simple {@link #clear()} should be a better
* alternative since it'll avoid reallocation.
*
* @see #clear()
*/
public void release();
/**
* Visually depict the distribution of keys.
*
* @param characters The number of characters to "squeeze" the entire buffer into.
* @return Returns a sequence of characters where '.' depicts an empty fragment of the internal
* buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything
* between 1 and 9 is between.
*/
public String visualizeKeyDistribution(int characters);
}

View File

@ -0,0 +1,105 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.*;
import com.carrotsearch.hppc.predicates.*;
import com.carrotsearch.hppc.procedures.*;
import java.util.Iterator;
/**
* An associative container from keys to (one or possibly more) values.
*
* @see CharContainer
*/
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "KTypeVTypeAssociativeContainer.java")
public interface CharFloatAssociativeContainer extends Iterable<CharFloatCursor> {
/**
* Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as
* a cursor and it returns <b>the same cursor instance</b> on every call to {@link
* Iterator#next()}. To read the current key and value use the cursor's public fields. An example
* is shown below.
*
* <pre>
* for (IntShortCursor c : intShortMap) {
* System.out.println(&quot;index=&quot; + c.index + &quot; key=&quot; + c.key + &quot; value=&quot; + c.value);
* }</pre>
*
* <p>The <code>index</code> field inside the cursor gives the internal index inside the
* container's implementation. The interpretation of this index depends on to the container.
*/
@Override
public Iterator<CharFloatCursor> iterator();
/**
* Returns <code>true</code> if this container has an association to a value for the given key.
*/
public boolean containsKey(char key);
/**
* @return Returns the current size (number of assigned keys) in the container.
*/
public int size();
/**
* @return Return <code>true</code> if this hash map contains no assigned keys.
*/
public boolean isEmpty();
/**
* Removes all keys (and associated values) present in a given container. An alias to:
*
* <pre>
* keys().removeAll(container)
* </pre>
*
* but with no additional overhead.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharContainer container);
/**
* Removes all keys (and associated values) for which the predicate returns <code>true</code>.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharPredicate predicate);
/**
* Removes all keys (and associated values) for which the predicate returns <code>true</code>.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharFloatPredicate predicate);
/**
* Applies a given procedure to all keys-value pairs in this container. Returns the argument (any
* subclass of {@link CharFloatProcedure}. This lets the caller call methods of the argument by
* chaining the call (even if the argument is an anonymous type) to retrieve computed values.
*/
public <T extends CharFloatProcedure> T forEach(T procedure);
/**
* Applies a given predicate to all keys-value pairs in this container. Returns the argument (any
* subclass of {@link CharFloatPredicate}. This lets the caller call methods of the argument by
* chaining the call (even if the argument is an anonymous type) to retrieve computed values.
*
* <p>The iteration is continued as long as the predicate returns <code>true</code>.
*/
public <T extends CharFloatPredicate> T forEach(T predicate);
/**
* Returns a collection of keys of this container. The returned collection is a view over the key
* set and any modifications (if allowed) introduced to the collection will propagate to the
* associative container immediately.
*/
public CharCollection keys();
/**
* Returns a container view of all values present in this container. The returned collection is a
* view over the key set and any modifications (if allowed) introduced to the collection will
* propagate to the associative container immediately.
*/
public FloatContainer values();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,205 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.CharFloatCursor;
/** An associative container with unique binding from keys to a single value. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java")
public interface CharFloatMap extends CharFloatAssociativeContainer {
/**
* @return Returns the value associated with the given key or the default value for the value
* type, if the key is not associated with any value. For numeric value types, this default
* value is 0, for object types it is {@code null}.
*/
public float get(char key);
/**
* @return Returns the value associated with the given key or the provided default value if the
* key is not associated with any value.
*/
public float getOrDefault(char key, float defaultValue);
/**
* Place a given key and value in the container.
*
* @return The value previously stored under the given key in the map is returned.
*/
public float put(char key, float value);
/**
* If the specified key is not already associated with a value, associates it with the given
* value.
*
* @return {@code true} if {@code key} did not exist and {@code value} was placed in the map,
* {@code false} otherwise.
*/
public default boolean putIfAbsent(char key, float value) {
int keyIndex = indexOf(key);
if (indexExists(keyIndex)) {
return false;
} else {
indexInsert(keyIndex, key, value);
return true;
}
}
/**
* Puts all keys from another container to this map, replacing the values of existing keys, if
* such keys are present.
*
* @return Returns the number of keys added to the map as a result of this call (not previously
* present in the map). Values of existing keys are overwritten.
*/
public int putAll(CharFloatAssociativeContainer container);
/**
* Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if
* such keys are present.
*
* @return Returns the number of keys added to the map as a result of this call (not previously
* present in the map). Values of existing keys are overwritten.
*/
public int putAll(Iterable<? extends CharFloatCursor> iterable);
/**
* If <code>key</code> exists, <code>putValue</code> is inserted into the map, otherwise any
* existing value is incremented by <code>additionValue</code>.
*
* @param key The key of the value to adjust.
* @param putValue The value to put if <code>key</code> does not exist.
* @param incrementValue The value to add to the existing value if <code>key</code> exists.
* @return Returns the current value associated with <code>key</code> (after changes).
*/
public float putOrAdd(char key, float putValue, float incrementValue);
/**
* An equivalent of calling
*
* <pre>
* putOrAdd(key, additionValue, additionValue);
* </pre>
*
* @param key The key of the value to adjust.
* @param additionValue The value to put or add to the existing value if <code>key</code> exists.
* @return Returns the current value associated with <code>key</code> (after changes).
*/
public float addTo(char key, float additionValue);
/**
* Remove all values at the given key. The default value for the key type is returned if the value
* does not exist in the map.
*/
public float remove(char key);
/**
* Compares the specified object with this set for equality. Returns {@code true} if and only if
* the specified object is also a {@link CharFloatMap} and both objects contains exactly the same
* key-value pairs.
*/
public boolean equals(Object obj);
/**
* @return A hash code of elements stored in the map. The hash code is defined as a sum of hash
* codes of keys and values stored within the set). Because sum is commutative, this ensures
* that different order of elements in a set does not affect the hash code.
*/
public int hashCode();
/**
* Returns a logical "index" of a given key that can be used to speed up follow-up value setters
* or getters in certain scenarios (conditional logic).
*
* <p>The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be)
* contiguous.
*
* <p>The index is valid only between map modifications (it will not be affected by read-only
* operations like iteration or value retrievals).
*
* @see #indexExists
* @see #indexGet
* @see #indexInsert
* @see #indexReplace
* @param key The key to locate in the map.
* @return A non-negative value of the logical "index" of the key in the map or a negative value
* if the key did not exist.
*/
public int indexOf(char key);
/**
* @see #indexOf
* @param index The index of a given key, as returned from {@link #indexOf}.
* @return Returns <code>true</code> if the index corresponds to an existing key or false
* otherwise. This is equivalent to checking whether the index is a positive value (existing
* keys) or a negative value (non-existing keys).
*/
public boolean indexExists(int index);
/**
* Returns the value associated with an existing key.
*
* @see #indexOf
* @param index The index of an existing key.
* @return Returns the value currently associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public float indexGet(int index);
/**
* Replaces the value associated with an existing key and returns any previous value stored for
* that key.
*
* @see #indexOf
* @param index The index of an existing key.
* @return Returns the previous value associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public float indexReplace(int index, float newValue);
/**
* Inserts a key-value pair for a key that is not present in the map. This method may help in
* avoiding double recalculation of the key's hash.
*
* @see #indexOf
* @param index The index of a previously non-existing key, as returned from {@link #indexOf}.
* @throws AssertionError If assertions are enabled and the index corresponds to an existing key.
*/
public void indexInsert(int index, char key, float value);
/**
* Removes a key-value pair at an index previously acquired from {@link #indexOf}.
*
* @see #indexOf
* @param index The index of the key to remove, as returned from {@link #indexOf}.
* @return Returns the previous value associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public float indexRemove(int index);
/**
* Clear all keys and values in the container.
*
* @see #release()
*/
public void clear();
/**
* Removes all elements from the collection and additionally releases any internal buffers.
* Typically, if the object is to be reused, a simple {@link #clear()} should be a better
* alternative since it'll avoid reallocation.
*
* @see #clear()
*/
public void release();
/**
* Visually depict the distribution of keys.
*
* @param characters The number of characters to "squeeze" the entire buffer into.
* @return Returns a sequence of characters where '.' depicts an empty fragment of the internal
* buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything
* between 1 and 9 is between.
*/
public String visualizeKeyDistribution(int characters);
}

View File

@ -0,0 +1,787 @@
package com.carrotsearch.hppc;
import static com.carrotsearch.hppc.Containers.*;
import static com.carrotsearch.hppc.HashContainers.*;
import com.carrotsearch.hppc.cursors.*;
import com.carrotsearch.hppc.predicates.*;
import com.carrotsearch.hppc.procedures.*;
import java.util.*;
/**
* A hash set of <code>char</code>s, implemented using open addressing with linear probing for
* collision resolution.
*
* @see <a href="{@docRoot}/overview-summary.html#interfaces">HPPC interfaces diagram</a>
*/
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:16+0200", value = "KTypeHashSet.java")
public class CharHashSet extends AbstractCharCollection
implements CharLookupContainer, CharSet, Preallocable, Cloneable, Accountable {
/** The hash array holding keys. */
public char[] keys;
/**
* The number of stored keys (assigned key slots), excluding the special "empty" key, if any.
*
* @see #size()
* @see #hasEmptyKey
*/
protected int assigned;
/** Mask for slot scans in {@link #keys}. */
protected int mask;
/** Expand (rehash) {@link #keys} when {@link #assigned} hits this value. */
protected int resizeAt;
/** Special treatment for the "empty slot" key marker. */
protected boolean hasEmptyKey;
/** The load factor for {@link #keys}. */
protected double loadFactor;
/** Seed used to ensure the hash iteration order is different from an iteration to another. */
protected int iterationSeed;
/**
* New instance with sane defaults.
*
* @see #CharHashSet(int, double)
*/
public CharHashSet() {
this(DEFAULT_EXPECTED_ELEMENTS, DEFAULT_LOAD_FACTOR);
}
/**
* New instance with sane defaults.
*
* @see #CharHashSet(int, double)
*/
public CharHashSet(int expectedElements) {
this(expectedElements, DEFAULT_LOAD_FACTOR);
}
/**
* New instance with the provided defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause a rehash
* (inclusive).
* @param loadFactor The load factor for internal buffers. Insane load factors (zero, full
* capacity) are rejected by {@link #verifyLoadFactor(double)}.
*/
public CharHashSet(int expectedElements, double loadFactor) {
this.loadFactor = verifyLoadFactor(loadFactor);
iterationSeed = HashContainers.nextIterationSeed();
ensureCapacity(expectedElements);
}
/** New instance copying elements from another {@link CharContainer}. */
public CharHashSet(CharContainer container) {
this(container.size());
addAll(container);
}
/** {@inheritDoc} */
@Override
public boolean add(char key) {
if (((key) == 0)) {
assert ((keys[mask + 1]) == 0);
boolean added = !hasEmptyKey;
hasEmptyKey = true;
return added;
} else {
final char[] keys = this.keys;
final int mask = this.mask;
int slot = hashKey(key) & mask;
char existing;
while (!((existing = keys[slot]) == 0)) {
if (((key) == (existing))) {
return false;
}
slot = (slot + 1) & mask;
}
if (assigned == resizeAt) {
allocateThenInsertThenRehash(slot, key);
} else {
keys[slot] = key;
}
assigned++;
return true;
}
}
/**
* Adds all elements from the given list (vararg) to this set.
*
* @return Returns the number of elements actually added as a result of this call (not previously
* present in the set).
*/
public final int addAll(char... elements) {
ensureCapacity(elements.length);
int count = 0;
for (char e : elements) {
if (add(e)) {
count++;
}
}
return count;
}
/**
* Adds all elements from the given {@link CharContainer} to this set.
*
* @return Returns the number of elements actually added as a result of this call (not previously
* present in the set).
*/
public int addAll(CharContainer container) {
ensureCapacity(container.size());
return addAll((Iterable<? extends CharCursor>) container);
}
/**
* Adds all elements from the given iterable to this set.
*
* @return Returns the number of elements actually added as a result of this call (not previously
* present in the set).
*/
public int addAll(Iterable<? extends CharCursor> iterable) {
int count = 0;
for (CharCursor cursor : iterable) {
if (add(cursor.value)) {
count++;
}
}
return count;
}
/** {@inheritDoc} */
@Override
public char[] toArray() {
final char[] cloned = (new char[size()]);
int j = 0;
if (hasEmptyKey) {
cloned[j++] = ((char) 0);
}
final char[] keys = this.keys;
int seed = nextIterationSeed();
int inc = iterationIncrement(seed);
for (int i = 0, mask = this.mask, slot = seed & mask;
i <= mask;
i++, slot = (slot + inc) & mask) {
char existing;
if (!((existing = keys[slot]) == 0)) {
cloned[j++] = existing;
}
}
return cloned;
}
/** An alias for the (preferred) {@link #removeAll}. */
public boolean remove(char key) {
if (((key) == 0)) {
boolean hadEmptyKey = hasEmptyKey;
hasEmptyKey = false;
return hadEmptyKey;
} else {
final char[] keys = this.keys;
final int mask = this.mask;
int slot = hashKey(key) & mask;
char existing;
while (!((existing = keys[slot]) == 0)) {
if (((key) == (existing))) {
shiftConflictingKeys(slot);
return true;
}
slot = (slot + 1) & mask;
}
return false;
}
}
/** {@inheritDoc} */
@Override
public int removeAll(char key) {
return remove(key) ? 1 : 0;
}
/**
* Removes all keys present in a given container.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharContainer other) {
final int before = size();
// Try to iterate over the smaller set or over the container that isn't implementing
// efficient contains() lookup.
if (other.size() >= size() && other instanceof CharLookupContainer) {
if (hasEmptyKey && other.contains(((char) 0))) {
hasEmptyKey = false;
}
final char[] keys = this.keys;
for (int slot = 0, max = this.mask; slot <= max; ) {
char existing;
if (!((existing = keys[slot]) == 0) && other.contains(existing)) {
// Shift, do not increment slot.
shiftConflictingKeys(slot);
} else {
slot++;
}
}
} else {
for (CharCursor c : other) {
remove(c.value);
}
}
return before - size();
}
/** {@inheritDoc} */
@Override
public int removeAll(CharPredicate predicate) {
int before = size();
if (hasEmptyKey) {
if (predicate.apply(((char) 0))) {
hasEmptyKey = false;
}
}
final char[] keys = this.keys;
for (int slot = 0, max = this.mask; slot <= max; ) {
char existing;
if (!((existing = keys[slot]) == 0)) {
if (predicate.apply(existing)) {
shiftConflictingKeys(slot);
continue; // Repeat the check for the same slot i (shifted).
}
}
slot++;
}
return before - size();
}
/** {@inheritDoc} */
@Override
public boolean contains(char key) {
if (((key) == 0)) {
return hasEmptyKey;
} else {
final char[] keys = this.keys;
final int mask = this.mask;
int slot = hashKey(key) & mask;
char existing;
while (!((existing = keys[slot]) == 0)) {
if (((key) == (existing))) {
return true;
}
slot = (slot + 1) & mask;
}
return false;
}
}
/** {@inheritDoc} */
@Override
public void clear() {
assigned = 0;
hasEmptyKey = false;
Arrays.fill(keys, ((char) 0));
}
/** {@inheritDoc} */
@Override
public void release() {
assigned = 0;
hasEmptyKey = false;
keys = null;
ensureCapacity(Containers.DEFAULT_EXPECTED_ELEMENTS);
}
/** {@inheritDoc} */
@Override
public boolean isEmpty() {
return size() == 0;
}
/**
* Ensure this container can hold at least the given number of elements without resizing its
* buffers.
*
* @param expectedElements The total number of elements, inclusive.
*/
@Override
public void ensureCapacity(int expectedElements) {
if (expectedElements > resizeAt || keys == null) {
final char[] prevKeys = this.keys;
allocateBuffers(minBufferSize(expectedElements, loadFactor));
if (prevKeys != null && !isEmpty()) {
rehash(prevKeys);
}
}
}
/** {@inheritDoc} */
@Override
public int size() {
return assigned + (hasEmptyKey ? 1 : 0);
}
/** {@inheritDoc} */
@Override
public int hashCode() {
int h = hasEmptyKey ? 0xDEADBEEF : 0;
final char[] keys = this.keys;
for (int slot = mask; slot >= 0; slot--) {
char existing;
if (!((existing = keys[slot]) == 0)) {
h += BitMixer.mix(existing);
}
}
return h;
}
/** {@inheritDoc} */
@Override
public boolean equals(Object obj) {
return (this == obj)
|| (obj != null && getClass() == obj.getClass() && sameKeys(getClass().cast(obj)));
}
/** Return true if all keys of some other container exist in this container. */
private boolean sameKeys(CharSet other) {
if (other.size() != size()) {
return false;
}
for (CharCursor c : other) {
if (!contains(c.value)) {
return false;
}
}
return true;
}
/** {@inheritDoc} */
@Override
public CharHashSet clone() {
try {
CharHashSet cloned = (CharHashSet) super.clone();
cloned.keys = keys.clone();
cloned.hasEmptyKey = hasEmptyKey;
cloned.iterationSeed = HashContainers.nextIterationSeed();
return cloned;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
/** {@inheritDoc} */
@Override
public Iterator<CharCursor> iterator() {
return new EntryIterator();
}
@Override
public long ramBytesAllocated() {
// int: assigned, mask, keyMixer, resizeAt
// double: loadFactor
// boolean: hasEmptyKey
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ 4 * Integer.BYTES
+ Double.BYTES
+ 1
+ RamUsageEstimator.shallowSizeOfArray(keys);
}
@Override
public long ramBytesUsed() {
// int: assigned, mask, keyMixer, resizeAt
// double: loadFactor
// boolean: hasEmptyKey
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ 4 * Integer.BYTES
+ Double.BYTES
+ 1
+ RamUsageEstimator.shallowUsedSizeOfArray(keys, size());
}
/**
* Provides the next iteration seed used to build the iteration starting slot and offset
* increment. This method does not need to be synchronized, what matters is that each thread gets
* a sequence of varying seeds.
*/
protected int nextIterationSeed() {
return iterationSeed = BitMixer.mixPhi(iterationSeed);
}
/** An iterator implementation for {@link #iterator}. */
protected final class EntryIterator extends AbstractIterator<CharCursor> {
private final CharCursor cursor;
private final int increment;
private int index;
private int slot;
public EntryIterator() {
cursor = new CharCursor();
int seed = nextIterationSeed();
increment = iterationIncrement(seed);
slot = seed & mask;
}
@Override
protected CharCursor fetch() {
final int mask = CharHashSet.this.mask;
while (index <= mask) {
char existing;
index++;
slot = (slot + increment) & mask;
if (!((existing = keys[slot]) == 0)) {
cursor.index = slot;
cursor.value = existing;
return cursor;
}
}
if (index == mask + 1 && hasEmptyKey) {
cursor.index = index++;
cursor.value = ((char) 0);
return cursor;
}
return done();
}
}
/** {@inheritDoc} */
@Override
public <T extends CharProcedure> T forEach(T procedure) {
if (hasEmptyKey) {
procedure.apply(((char) 0));
}
final char[] keys = this.keys;
int seed = nextIterationSeed();
int inc = iterationIncrement(seed);
for (int i = 0, mask = this.mask, slot = seed & mask;
i <= mask;
i++, slot = (slot + inc) & mask) {
char existing;
if (!((existing = keys[slot]) == 0)) {
procedure.apply(existing);
}
}
return procedure;
}
/** {@inheritDoc} */
@Override
public <T extends CharPredicate> T forEach(T predicate) {
if (hasEmptyKey) {
if (!predicate.apply(((char) 0))) {
return predicate;
}
}
final char[] keys = this.keys;
int seed = nextIterationSeed();
int inc = iterationIncrement(seed);
for (int i = 0, mask = this.mask, slot = seed & mask;
i <= mask;
i++, slot = (slot + inc) & mask) {
char existing;
if (!((existing = keys[slot]) == 0)) {
if (!predicate.apply(existing)) {
break;
}
}
}
return predicate;
}
/**
* Create a set from a variable number of arguments or an array of <code>char</code>. The elements
* are copied from the argument to the internal buffer.
*/
public static CharHashSet from(char... elements) {
final CharHashSet set = new CharHashSet(elements.length);
set.addAll(elements);
return set;
}
/**
* Returns a hash code for the given key.
*
* <p>The output from this function should evenly distribute keys across the entire integer range.
*/
protected int hashKey(char key) {
assert !((key) == 0); // Handled as a special case (empty slot marker).
return BitMixer.mixPhi(key);
}
/**
* Returns a logical "index" of a given key that can be used to speed up follow-up logic in
* certain scenarios (conditional logic).
*
* <p>The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be)
* contiguous.
*
* <p>The index is valid only between modifications (it will not be affected by read-only
* operations).
*
* @see #indexExists
* @see #indexGet
* @see #indexInsert
* @see #indexReplace
* @param key The key to locate in the set.
* @return A non-negative value of the logical "index" of the key in the set or a negative value
* if the key did not exist.
*/
public int indexOf(char key) {
final int mask = this.mask;
if (((key) == 0)) {
return hasEmptyKey ? mask + 1 : ~(mask + 1);
} else {
final char[] keys = this.keys;
int slot = hashKey(key) & mask;
char existing;
while (!((existing = keys[slot]) == 0)) {
if (((key) == (existing))) {
return slot;
}
slot = (slot + 1) & mask;
}
return ~slot;
}
}
/**
* @see #indexOf
* @param index The index of a given key, as returned from {@link #indexOf}.
* @return Returns <code>true</code> if the index corresponds to an existing key or false
* otherwise. This is equivalent to checking whether the index is a positive value (existing
* keys) or a negative value (non-existing keys).
*/
public boolean indexExists(int index) {
assert index < 0 || index <= mask || (index == mask + 1 && hasEmptyKey);
return index >= 0;
}
/**
* Returns the exact value of the existing key. This method makes sense for sets of objects which
* define custom key-equality relationship.
*
* @see #indexOf
* @param index The index of an existing key.
* @return Returns the equivalent key currently stored in the set.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public char indexGet(int index) {
assert index >= 0 : "The index must point at an existing key.";
assert index <= mask || (index == mask + 1 && hasEmptyKey);
return keys[index];
}
/**
* Replaces the existing equivalent key with the given one and returns any previous value stored
* for that key.
*
* @see #indexOf
* @param index The index of an existing key.
* @param equivalentKey The key to put in the set as a replacement. Must be equivalent to the key
* currently stored at the provided index.
* @return Returns the previous key stored in the set.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public char indexReplace(int index, char equivalentKey) {
assert index >= 0 : "The index must point at an existing key.";
assert index <= mask || (index == mask + 1 && hasEmptyKey);
assert ((keys[index]) == (equivalentKey));
char previousValue = keys[index];
keys[index] = equivalentKey;
return previousValue;
}
/**
* Inserts a key for an index that is not present in the set. This method may help in avoiding
* double recalculation of the key's hash.
*
* @see #indexOf
* @param index The index of a previously non-existing key, as returned from {@link #indexOf}.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public void indexInsert(int index, char key) {
assert index < 0 : "The index must not point at an existing key.";
index = ~index;
if (((key) == 0)) {
assert index == mask + 1;
assert ((keys[index]) == 0);
hasEmptyKey = true;
} else {
assert ((keys[index]) == 0);
if (assigned == resizeAt) {
allocateThenInsertThenRehash(index, key);
} else {
keys[index] = key;
}
assigned++;
}
}
/**
* Removes a key at an index previously acquired from {@link #indexOf}.
*
* @see #indexOf
* @param index The index of the key to remove, as returned from {@link #indexOf}.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public void indexRemove(int index) {
assert index >= 0 : "The index must point at an existing key.";
assert index <= mask || (index == mask + 1 && hasEmptyKey);
if (index > mask) {
hasEmptyKey = false;
} else {
shiftConflictingKeys(index);
}
}
@Override
public String visualizeKeyDistribution(int characters) {
return CharBufferVisualizer.visualizeKeyDistribution(keys, mask, characters);
}
/**
* Validate load factor range and return it. Override and suppress if you need insane load
* factors.
*/
protected double verifyLoadFactor(double loadFactor) {
checkLoadFactor(loadFactor, MIN_LOAD_FACTOR, MAX_LOAD_FACTOR);
return loadFactor;
}
/** Rehash from old buffers to new buffers. */
protected void rehash(char[] fromKeys) {
assert HashContainers.checkPowerOfTwo(fromKeys.length - 1);
// Rehash all stored keys into the new buffers.
final char[] keys = this.keys;
final int mask = this.mask;
char existing;
for (int i = fromKeys.length - 1; --i >= 0; ) {
if (!((existing = fromKeys[i]) == 0)) {
int slot = hashKey(existing) & mask;
while (!((keys[slot]) == 0)) {
slot = (slot + 1) & mask;
}
keys[slot] = existing;
}
}
}
/**
* Allocate new internal buffers. This method attempts to allocate and assign internal buffers
* atomically (either allocations succeed or not).
*/
protected void allocateBuffers(int arraySize) {
assert Integer.bitCount(arraySize) == 1;
// Ensure no change is done if we hit an OOM.
char[] prevKeys = this.keys;
try {
int emptyElementSlot = 1;
this.keys = (new char[arraySize + emptyElementSlot]);
} catch (OutOfMemoryError e) {
this.keys = prevKeys;
throw new BufferAllocationException(
"Not enough memory to allocate buffers for rehashing: %,d -> %,d",
e, this.keys == null ? 0 : size(), arraySize);
}
this.resizeAt = expandAtCount(arraySize, loadFactor);
this.mask = arraySize - 1;
}
/**
* This method is invoked when there is a new key to be inserted into the buffer but there is not
* enough empty slots to do so.
*
* <p>New buffers are allocated. If this succeeds, we know we can proceed with rehashing so we
* assign the pending element to the previous buffer (possibly violating the invariant of having
* at least one empty slot) and rehash all keys, substituting new buffers at the end.
*/
protected void allocateThenInsertThenRehash(int slot, char pendingKey) {
assert assigned == resizeAt && ((keys[slot]) == 0) && !((pendingKey) == 0);
// Try to allocate new buffers first. If we OOM, we leave in a consistent state.
final char[] prevKeys = this.keys;
allocateBuffers(nextBufferSize(mask + 1, size(), loadFactor));
assert this.keys.length > prevKeys.length;
// We have succeeded at allocating new data so insert the pending key/value at
// the free slot in the old arrays before rehashing.
prevKeys[slot] = pendingKey;
// Rehash old keys, including the pending key.
rehash(prevKeys);
}
/** Shift all the slot-conflicting keys allocated to (and including) <code>slot</code>. */
protected void shiftConflictingKeys(int gapSlot) {
final char[] keys = this.keys;
final int mask = this.mask;
// Perform shifts of conflicting keys to fill in the gap.
int distance = 0;
while (true) {
final int slot = (gapSlot + (++distance)) & mask;
final char existing = keys[slot];
if (((existing) == 0)) {
break;
}
final int idealSlot = hashKey(existing);
final int shift = (slot - idealSlot) & mask;
if (shift >= distance) {
// Entry at this position was originally at or before the gap slot.
// Move the conflict-shifted entry to the gap's position and repeat the procedure
// for any entries to the right of the current position, treating it
// as the new gap.
keys[gapSlot] = existing;
gapSlot = slot;
distance = 0;
}
}
// Mark the last found gap slot without a conflict as empty.
keys[gapSlot] = ((char) 0);
assigned--;
}
}

View File

@ -0,0 +1,91 @@
package com.carrotsearch.hppc;
import java.util.RandomAccess;
/**
* An indexed container provides random access to elements based on an <code>index</code>. Indexes
* are zero-based.
*/
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "KTypeIndexedContainer.java")
public interface CharIndexedContainer extends CharCollection, RandomAccess {
/**
* Removes the first element that equals <code>e1</code>, returning whether an element has been
* removed.
*/
public boolean removeElement(char e1);
/**
* Removes the first element that equals <code>e1</code>, returning its deleted position or <code>
* -1</code> if the element was not found.
*/
public int removeFirst(char e1);
/**
* Removes the last element that equals <code>e1</code>, returning its deleted position or <code>
* -1</code> if the element was not found.
*/
public int removeLast(char e1);
/**
* Returns the index of the first occurrence of the specified element in this list, or -1 if this
* list does not contain the element.
*/
public int indexOf(char e1);
/**
* Returns the index of the last occurrence of the specified element in this list, or -1 if this
* list does not contain the element.
*/
public int lastIndexOf(char e1);
/** Adds an element to the end of this container (the last index is incremented by one). */
public void add(char e1);
/**
* Inserts the specified element at the specified position in this list.
*
* @param index The index at which the element should be inserted, shifting any existing and
* subsequent elements to the right.
*/
public void insert(int index, char e1);
/**
* Replaces the element at the specified position in this list with the specified element.
*
* @return Returns the previous value in the list.
*/
public char set(int index, char e1);
/**
* @return Returns the element at index <code>index</code> from the list.
*/
public char get(int index);
/**
* Removes the element at the specified position in this container and returns it.
*
* @see #removeFirst
* @see #removeLast
* @see #removeAll
*/
public char removeAt(int index);
/** Removes and returns the last element of this container. This container must not be empty. */
public char removeLast();
/**
* Removes from this container all of the elements with indexes between <code>fromIndex</code>,
* inclusive, and <code>toIndex</code>, exclusive.
*/
public void removeRange(int fromIndex, int toIndex);
/** Returns this container elements as a stream. */
/** Sorts the elements in this container and returns this container. */
public CharIndexedContainer sort();
/** Reverses the elements in this container and returns this container. */
public CharIndexedContainer reverse();
}

View File

@ -0,0 +1,105 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.*;
import com.carrotsearch.hppc.predicates.*;
import com.carrotsearch.hppc.procedures.*;
import java.util.Iterator;
/**
* An associative container from keys to (one or possibly more) values.
*
* @see CharContainer
*/
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "KTypeVTypeAssociativeContainer.java")
public interface CharIntAssociativeContainer extends Iterable<CharIntCursor> {
/**
* Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as
* a cursor and it returns <b>the same cursor instance</b> on every call to {@link
* Iterator#next()}. To read the current key and value use the cursor's public fields. An example
* is shown below.
*
* <pre>
* for (IntShortCursor c : intShortMap) {
* System.out.println(&quot;index=&quot; + c.index + &quot; key=&quot; + c.key + &quot; value=&quot; + c.value);
* }</pre>
*
* <p>The <code>index</code> field inside the cursor gives the internal index inside the
* container's implementation. The interpretation of this index depends on to the container.
*/
@Override
public Iterator<CharIntCursor> iterator();
/**
* Returns <code>true</code> if this container has an association to a value for the given key.
*/
public boolean containsKey(char key);
/**
* @return Returns the current size (number of assigned keys) in the container.
*/
public int size();
/**
* @return Return <code>true</code> if this hash map contains no assigned keys.
*/
public boolean isEmpty();
/**
* Removes all keys (and associated values) present in a given container. An alias to:
*
* <pre>
* keys().removeAll(container)
* </pre>
*
* but with no additional overhead.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharContainer container);
/**
* Removes all keys (and associated values) for which the predicate returns <code>true</code>.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharPredicate predicate);
/**
* Removes all keys (and associated values) for which the predicate returns <code>true</code>.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharIntPredicate predicate);
/**
* Applies a given procedure to all keys-value pairs in this container. Returns the argument (any
* subclass of {@link CharIntProcedure}. This lets the caller call methods of the argument by
* chaining the call (even if the argument is an anonymous type) to retrieve computed values.
*/
public <T extends CharIntProcedure> T forEach(T procedure);
/**
* Applies a given predicate to all keys-value pairs in this container. Returns the argument (any
* subclass of {@link CharIntPredicate}. This lets the caller call methods of the argument by
* chaining the call (even if the argument is an anonymous type) to retrieve computed values.
*
* <p>The iteration is continued as long as the predicate returns <code>true</code>.
*/
public <T extends CharIntPredicate> T forEach(T predicate);
/**
* Returns a collection of keys of this container. The returned collection is a view over the key
* set and any modifications (if allowed) introduced to the collection will propagate to the
* associative container immediately.
*/
public CharCollection keys();
/**
* Returns a container view of all values present in this container. The returned collection is a
* view over the key set and any modifications (if allowed) introduced to the collection will
* propagate to the associative container immediately.
*/
public IntContainer values();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,205 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.CharIntCursor;
/** An associative container with unique binding from keys to a single value. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java")
public interface CharIntMap extends CharIntAssociativeContainer {
/**
* @return Returns the value associated with the given key or the default value for the value
* type, if the key is not associated with any value. For numeric value types, this default
* value is 0, for object types it is {@code null}.
*/
public int get(char key);
/**
* @return Returns the value associated with the given key or the provided default value if the
* key is not associated with any value.
*/
public int getOrDefault(char key, int defaultValue);
/**
* Place a given key and value in the container.
*
* @return The value previously stored under the given key in the map is returned.
*/
public int put(char key, int value);
/**
* If the specified key is not already associated with a value, associates it with the given
* value.
*
* @return {@code true} if {@code key} did not exist and {@code value} was placed in the map,
* {@code false} otherwise.
*/
public default boolean putIfAbsent(char key, int value) {
int keyIndex = indexOf(key);
if (indexExists(keyIndex)) {
return false;
} else {
indexInsert(keyIndex, key, value);
return true;
}
}
/**
* Puts all keys from another container to this map, replacing the values of existing keys, if
* such keys are present.
*
* @return Returns the number of keys added to the map as a result of this call (not previously
* present in the map). Values of existing keys are overwritten.
*/
public int putAll(CharIntAssociativeContainer container);
/**
* Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if
* such keys are present.
*
* @return Returns the number of keys added to the map as a result of this call (not previously
* present in the map). Values of existing keys are overwritten.
*/
public int putAll(Iterable<? extends CharIntCursor> iterable);
/**
* If <code>key</code> exists, <code>putValue</code> is inserted into the map, otherwise any
* existing value is incremented by <code>additionValue</code>.
*
* @param key The key of the value to adjust.
* @param putValue The value to put if <code>key</code> does not exist.
* @param incrementValue The value to add to the existing value if <code>key</code> exists.
* @return Returns the current value associated with <code>key</code> (after changes).
*/
public int putOrAdd(char key, int putValue, int incrementValue);
/**
* An equivalent of calling
*
* <pre>
* putOrAdd(key, additionValue, additionValue);
* </pre>
*
* @param key The key of the value to adjust.
* @param additionValue The value to put or add to the existing value if <code>key</code> exists.
* @return Returns the current value associated with <code>key</code> (after changes).
*/
public int addTo(char key, int additionValue);
/**
* Remove all values at the given key. The default value for the key type is returned if the value
* does not exist in the map.
*/
public int remove(char key);
/**
* Compares the specified object with this set for equality. Returns {@code true} if and only if
* the specified object is also a {@link CharIntMap} and both objects contains exactly the same
* key-value pairs.
*/
public boolean equals(Object obj);
/**
* @return A hash code of elements stored in the map. The hash code is defined as a sum of hash
* codes of keys and values stored within the set). Because sum is commutative, this ensures
* that different order of elements in a set does not affect the hash code.
*/
public int hashCode();
/**
* Returns a logical "index" of a given key that can be used to speed up follow-up value setters
* or getters in certain scenarios (conditional logic).
*
* <p>The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be)
* contiguous.
*
* <p>The index is valid only between map modifications (it will not be affected by read-only
* operations like iteration or value retrievals).
*
* @see #indexExists
* @see #indexGet
* @see #indexInsert
* @see #indexReplace
* @param key The key to locate in the map.
* @return A non-negative value of the logical "index" of the key in the map or a negative value
* if the key did not exist.
*/
public int indexOf(char key);
/**
* @see #indexOf
* @param index The index of a given key, as returned from {@link #indexOf}.
* @return Returns <code>true</code> if the index corresponds to an existing key or false
* otherwise. This is equivalent to checking whether the index is a positive value (existing
* keys) or a negative value (non-existing keys).
*/
public boolean indexExists(int index);
/**
* Returns the value associated with an existing key.
*
* @see #indexOf
* @param index The index of an existing key.
* @return Returns the value currently associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public int indexGet(int index);
/**
* Replaces the value associated with an existing key and returns any previous value stored for
* that key.
*
* @see #indexOf
* @param index The index of an existing key.
* @return Returns the previous value associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public int indexReplace(int index, int newValue);
/**
* Inserts a key-value pair for a key that is not present in the map. This method may help in
* avoiding double recalculation of the key's hash.
*
* @see #indexOf
* @param index The index of a previously non-existing key, as returned from {@link #indexOf}.
* @throws AssertionError If assertions are enabled and the index corresponds to an existing key.
*/
public void indexInsert(int index, char key, int value);
/**
* Removes a key-value pair at an index previously acquired from {@link #indexOf}.
*
* @see #indexOf
* @param index The index of the key to remove, as returned from {@link #indexOf}.
* @return Returns the previous value associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public int indexRemove(int index);
/**
* Clear all keys and values in the container.
*
* @see #release()
*/
public void clear();
/**
* Removes all elements from the collection and additionally releases any internal buffers.
* Typically, if the object is to be reused, a simple {@link #clear()} should be a better
* alternative since it'll avoid reallocation.
*
* @see #clear()
*/
public void release();
/**
* Visually depict the distribution of keys.
*
* @param characters The number of characters to "squeeze" the entire buffer into.
* @return Returns a sequence of characters where '.' depicts an empty fragment of the internal
* buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything
* between 1 and 9 is between.
*/
public String visualizeKeyDistribution(int characters);
}

View File

@ -0,0 +1,105 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.*;
import com.carrotsearch.hppc.predicates.*;
import com.carrotsearch.hppc.procedures.*;
import java.util.Iterator;
/**
* An associative container from keys to (one or possibly more) values.
*
* @see CharContainer
*/
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "KTypeVTypeAssociativeContainer.java")
public interface CharLongAssociativeContainer extends Iterable<CharLongCursor> {
/**
* Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as
* a cursor and it returns <b>the same cursor instance</b> on every call to {@link
* Iterator#next()}. To read the current key and value use the cursor's public fields. An example
* is shown below.
*
* <pre>
* for (IntShortCursor c : intShortMap) {
* System.out.println(&quot;index=&quot; + c.index + &quot; key=&quot; + c.key + &quot; value=&quot; + c.value);
* }</pre>
*
* <p>The <code>index</code> field inside the cursor gives the internal index inside the
* container's implementation. The interpretation of this index depends on to the container.
*/
@Override
public Iterator<CharLongCursor> iterator();
/**
* Returns <code>true</code> if this container has an association to a value for the given key.
*/
public boolean containsKey(char key);
/**
* @return Returns the current size (number of assigned keys) in the container.
*/
public int size();
/**
* @return Return <code>true</code> if this hash map contains no assigned keys.
*/
public boolean isEmpty();
/**
* Removes all keys (and associated values) present in a given container. An alias to:
*
* <pre>
* keys().removeAll(container)
* </pre>
*
* but with no additional overhead.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharContainer container);
/**
* Removes all keys (and associated values) for which the predicate returns <code>true</code>.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharPredicate predicate);
/**
* Removes all keys (and associated values) for which the predicate returns <code>true</code>.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharLongPredicate predicate);
/**
* Applies a given procedure to all keys-value pairs in this container. Returns the argument (any
* subclass of {@link CharLongProcedure}. This lets the caller call methods of the argument by
* chaining the call (even if the argument is an anonymous type) to retrieve computed values.
*/
public <T extends CharLongProcedure> T forEach(T procedure);
/**
* Applies a given predicate to all keys-value pairs in this container. Returns the argument (any
* subclass of {@link CharLongPredicate}. This lets the caller call methods of the argument by
* chaining the call (even if the argument is an anonymous type) to retrieve computed values.
*
* <p>The iteration is continued as long as the predicate returns <code>true</code>.
*/
public <T extends CharLongPredicate> T forEach(T predicate);
/**
* Returns a collection of keys of this container. The returned collection is a view over the key
* set and any modifications (if allowed) introduced to the collection will propagate to the
* associative container immediately.
*/
public CharCollection keys();
/**
* Returns a container view of all values present in this container. The returned collection is a
* view over the key set and any modifications (if allowed) introduced to the collection will
* propagate to the associative container immediately.
*/
public LongContainer values();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,205 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.CharLongCursor;
/** An associative container with unique binding from keys to a single value. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java")
public interface CharLongMap extends CharLongAssociativeContainer {
/**
* @return Returns the value associated with the given key or the default value for the value
* type, if the key is not associated with any value. For numeric value types, this default
* value is 0, for object types it is {@code null}.
*/
public long get(char key);
/**
* @return Returns the value associated with the given key or the provided default value if the
* key is not associated with any value.
*/
public long getOrDefault(char key, long defaultValue);
/**
* Place a given key and value in the container.
*
* @return The value previously stored under the given key in the map is returned.
*/
public long put(char key, long value);
/**
* If the specified key is not already associated with a value, associates it with the given
* value.
*
* @return {@code true} if {@code key} did not exist and {@code value} was placed in the map,
* {@code false} otherwise.
*/
public default boolean putIfAbsent(char key, long value) {
int keyIndex = indexOf(key);
if (indexExists(keyIndex)) {
return false;
} else {
indexInsert(keyIndex, key, value);
return true;
}
}
/**
* Puts all keys from another container to this map, replacing the values of existing keys, if
* such keys are present.
*
* @return Returns the number of keys added to the map as a result of this call (not previously
* present in the map). Values of existing keys are overwritten.
*/
public int putAll(CharLongAssociativeContainer container);
/**
* Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if
* such keys are present.
*
* @return Returns the number of keys added to the map as a result of this call (not previously
* present in the map). Values of existing keys are overwritten.
*/
public int putAll(Iterable<? extends CharLongCursor> iterable);
/**
* If <code>key</code> exists, <code>putValue</code> is inserted into the map, otherwise any
* existing value is incremented by <code>additionValue</code>.
*
* @param key The key of the value to adjust.
* @param putValue The value to put if <code>key</code> does not exist.
* @param incrementValue The value to add to the existing value if <code>key</code> exists.
* @return Returns the current value associated with <code>key</code> (after changes).
*/
public long putOrAdd(char key, long putValue, long incrementValue);
/**
* An equivalent of calling
*
* <pre>
* putOrAdd(key, additionValue, additionValue);
* </pre>
*
* @param key The key of the value to adjust.
* @param additionValue The value to put or add to the existing value if <code>key</code> exists.
* @return Returns the current value associated with <code>key</code> (after changes).
*/
public long addTo(char key, long additionValue);
/**
* Remove all values at the given key. The default value for the key type is returned if the value
* does not exist in the map.
*/
public long remove(char key);
/**
* Compares the specified object with this set for equality. Returns {@code true} if and only if
* the specified object is also a {@link CharLongMap} and both objects contains exactly the same
* key-value pairs.
*/
public boolean equals(Object obj);
/**
* @return A hash code of elements stored in the map. The hash code is defined as a sum of hash
* codes of keys and values stored within the set). Because sum is commutative, this ensures
* that different order of elements in a set does not affect the hash code.
*/
public int hashCode();
/**
* Returns a logical "index" of a given key that can be used to speed up follow-up value setters
* or getters in certain scenarios (conditional logic).
*
* <p>The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be)
* contiguous.
*
* <p>The index is valid only between map modifications (it will not be affected by read-only
* operations like iteration or value retrievals).
*
* @see #indexExists
* @see #indexGet
* @see #indexInsert
* @see #indexReplace
* @param key The key to locate in the map.
* @return A non-negative value of the logical "index" of the key in the map or a negative value
* if the key did not exist.
*/
public int indexOf(char key);
/**
* @see #indexOf
* @param index The index of a given key, as returned from {@link #indexOf}.
* @return Returns <code>true</code> if the index corresponds to an existing key or false
* otherwise. This is equivalent to checking whether the index is a positive value (existing
* keys) or a negative value (non-existing keys).
*/
public boolean indexExists(int index);
/**
* Returns the value associated with an existing key.
*
* @see #indexOf
* @param index The index of an existing key.
* @return Returns the value currently associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public long indexGet(int index);
/**
* Replaces the value associated with an existing key and returns any previous value stored for
* that key.
*
* @see #indexOf
* @param index The index of an existing key.
* @return Returns the previous value associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public long indexReplace(int index, long newValue);
/**
* Inserts a key-value pair for a key that is not present in the map. This method may help in
* avoiding double recalculation of the key's hash.
*
* @see #indexOf
* @param index The index of a previously non-existing key, as returned from {@link #indexOf}.
* @throws AssertionError If assertions are enabled and the index corresponds to an existing key.
*/
public void indexInsert(int index, char key, long value);
/**
* Removes a key-value pair at an index previously acquired from {@link #indexOf}.
*
* @see #indexOf
* @param index The index of the key to remove, as returned from {@link #indexOf}.
* @return Returns the previous value associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public long indexRemove(int index);
/**
* Clear all keys and values in the container.
*
* @see #release()
*/
public void clear();
/**
* Removes all elements from the collection and additionally releases any internal buffers.
* Typically, if the object is to be reused, a simple {@link #clear()} should be a better
* alternative since it'll avoid reallocation.
*
* @see #clear()
*/
public void release();
/**
* Visually depict the distribution of keys.
*
* @param characters The number of characters to "squeeze" the entire buffer into.
* @return Returns a sequence of characters where '.' depicts an empty fragment of the internal
* buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything
* between 1 and 9 is between.
*/
public String visualizeKeyDistribution(int characters);
}

View File

@ -0,0 +1,12 @@
package com.carrotsearch.hppc;
/**
* Marker interface for containers that can check if they contain a given object in at least time
* <code>O(log n)</code> and ideally in amortized constant time <code>O(1)</code>.
*/
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "KTypeLookupContainer.java")
public interface CharLookupContainer extends CharContainer {
public boolean contains(char e);
}

View File

@ -0,0 +1,105 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.*;
import com.carrotsearch.hppc.predicates.*;
import com.carrotsearch.hppc.procedures.*;
import java.util.Iterator;
/**
* An associative container from keys to (one or possibly more) values.
*
* @see CharContainer
*/
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "KTypeVTypeAssociativeContainer.java")
public interface CharObjectAssociativeContainer<VType> extends Iterable<CharObjectCursor<VType>> {
/**
* Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as
* a cursor and it returns <b>the same cursor instance</b> on every call to {@link
* Iterator#next()}. To read the current key and value use the cursor's public fields. An example
* is shown below.
*
* <pre>
* for (IntShortCursor c : intShortMap) {
* System.out.println(&quot;index=&quot; + c.index + &quot; key=&quot; + c.key + &quot; value=&quot; + c.value);
* }</pre>
*
* <p>The <code>index</code> field inside the cursor gives the internal index inside the
* container's implementation. The interpretation of this index depends on to the container.
*/
@Override
public Iterator<CharObjectCursor<VType>> iterator();
/**
* Returns <code>true</code> if this container has an association to a value for the given key.
*/
public boolean containsKey(char key);
/**
* @return Returns the current size (number of assigned keys) in the container.
*/
public int size();
/**
* @return Return <code>true</code> if this hash map contains no assigned keys.
*/
public boolean isEmpty();
/**
* Removes all keys (and associated values) present in a given container. An alias to:
*
* <pre>
* keys().removeAll(container)
* </pre>
*
* but with no additional overhead.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharContainer container);
/**
* Removes all keys (and associated values) for which the predicate returns <code>true</code>.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharPredicate predicate);
/**
* Removes all keys (and associated values) for which the predicate returns <code>true</code>.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharObjectPredicate<? super VType> predicate);
/**
* Applies a given procedure to all keys-value pairs in this container. Returns the argument (any
* subclass of {@link CharObjectProcedure}. This lets the caller call methods of the argument by
* chaining the call (even if the argument is an anonymous type) to retrieve computed values.
*/
public <T extends CharObjectProcedure<? super VType>> T forEach(T procedure);
/**
* Applies a given predicate to all keys-value pairs in this container. Returns the argument (any
* subclass of {@link CharObjectPredicate}. This lets the caller call methods of the argument by
* chaining the call (even if the argument is an anonymous type) to retrieve computed values.
*
* <p>The iteration is continued as long as the predicate returns <code>true</code>.
*/
public <T extends CharObjectPredicate<? super VType>> T forEach(T predicate);
/**
* Returns a collection of keys of this container. The returned collection is a view over the key
* set and any modifications (if allowed) introduced to the collection will propagate to the
* associative container immediately.
*/
public CharCollection keys();
/**
* Returns a container view of all values present in this container. The returned collection is a
* view over the key set and any modifications (if allowed) introduced to the collection will
* propagate to the associative container immediately.
*/
public ObjectContainer<VType> values();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,181 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.CharObjectCursor;
/** An associative container with unique binding from keys to a single value. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java")
public interface CharObjectMap<VType> extends CharObjectAssociativeContainer<VType> {
/**
* @return Returns the value associated with the given key or the default value for the value
* type, if the key is not associated with any value. For numeric value types, this default
* value is 0, for object types it is {@code null}.
*/
public VType get(char key);
/**
* @return Returns the value associated with the given key or the provided default value if the
* key is not associated with any value.
*/
public VType getOrDefault(char key, VType defaultValue);
/**
* Place a given key and value in the container.
*
* @return The value previously stored under the given key in the map is returned.
*/
public VType put(char key, VType value);
/**
* If the specified key is not already associated with a value, associates it with the given
* value.
*
* @return {@code true} if {@code key} did not exist and {@code value} was placed in the map,
* {@code false} otherwise.
*/
public default boolean putIfAbsent(char key, VType value) {
int keyIndex = indexOf(key);
if (indexExists(keyIndex)) {
return false;
} else {
indexInsert(keyIndex, key, value);
return true;
}
}
/**
* Puts all keys from another container to this map, replacing the values of existing keys, if
* such keys are present.
*
* @return Returns the number of keys added to the map as a result of this call (not previously
* present in the map). Values of existing keys are overwritten.
*/
public int putAll(CharObjectAssociativeContainer<? extends VType> container);
/**
* Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if
* such keys are present.
*
* @return Returns the number of keys added to the map as a result of this call (not previously
* present in the map). Values of existing keys are overwritten.
*/
public int putAll(Iterable<? extends CharObjectCursor<? extends VType>> iterable);
/**
* Remove all values at the given key. The default value for the key type is returned if the value
* does not exist in the map.
*/
public VType remove(char key);
/**
* Compares the specified object with this set for equality. Returns {@code true} if and only if
* the specified object is also a {@link CharObjectMap} and both objects contains exactly the same
* key-value pairs.
*/
public boolean equals(Object obj);
/**
* @return A hash code of elements stored in the map. The hash code is defined as a sum of hash
* codes of keys and values stored within the set). Because sum is commutative, this ensures
* that different order of elements in a set does not affect the hash code.
*/
public int hashCode();
/**
* Returns a logical "index" of a given key that can be used to speed up follow-up value setters
* or getters in certain scenarios (conditional logic).
*
* <p>The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be)
* contiguous.
*
* <p>The index is valid only between map modifications (it will not be affected by read-only
* operations like iteration or value retrievals).
*
* @see #indexExists
* @see #indexGet
* @see #indexInsert
* @see #indexReplace
* @param key The key to locate in the map.
* @return A non-negative value of the logical "index" of the key in the map or a negative value
* if the key did not exist.
*/
public int indexOf(char key);
/**
* @see #indexOf
* @param index The index of a given key, as returned from {@link #indexOf}.
* @return Returns <code>true</code> if the index corresponds to an existing key or false
* otherwise. This is equivalent to checking whether the index is a positive value (existing
* keys) or a negative value (non-existing keys).
*/
public boolean indexExists(int index);
/**
* Returns the value associated with an existing key.
*
* @see #indexOf
* @param index The index of an existing key.
* @return Returns the value currently associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public VType indexGet(int index);
/**
* Replaces the value associated with an existing key and returns any previous value stored for
* that key.
*
* @see #indexOf
* @param index The index of an existing key.
* @return Returns the previous value associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public VType indexReplace(int index, VType newValue);
/**
* Inserts a key-value pair for a key that is not present in the map. This method may help in
* avoiding double recalculation of the key's hash.
*
* @see #indexOf
* @param index The index of a previously non-existing key, as returned from {@link #indexOf}.
* @throws AssertionError If assertions are enabled and the index corresponds to an existing key.
*/
public void indexInsert(int index, char key, VType value);
/**
* Removes a key-value pair at an index previously acquired from {@link #indexOf}.
*
* @see #indexOf
* @param index The index of the key to remove, as returned from {@link #indexOf}.
* @return Returns the previous value associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public VType indexRemove(int index);
/**
* Clear all keys and values in the container.
*
* @see #release()
*/
public void clear();
/**
* Removes all elements from the collection and additionally releases any internal buffers.
* Typically, if the object is to be reused, a simple {@link #clear()} should be a better
* alternative since it'll avoid reallocation.
*
* @see #clear()
*/
public void release();
/**
* Visually depict the distribution of keys.
*
* @param characters The number of characters to "squeeze" the entire buffer into.
* @return Returns a sequence of characters where '.' depicts an empty fragment of the internal
* buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything
* between 1 and 9 is between.
*/
public String visualizeKeyDistribution(int characters);
}

View File

@ -0,0 +1,33 @@
package com.carrotsearch.hppc;
/** A set of <code>char</code>s. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeSet.java")
public interface CharSet extends CharCollection {
/**
* Adds <code>k</code> to the set.
*
* @return Returns <code>true</code> if this element was not part of the set before. Returns
* <code>false</code> if an equal element is already part of the set, <b>does not replace the
* existing element</b> with the argument.
*/
public boolean add(char k);
/**
* Visually depict the distribution of keys.
*
* @param characters The number of characters to "squeeze" the entire buffer into.
* @return Returns a sequence of characters where '.' depicts an empty fragment of the internal
* buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything
* between 1 and 9 is between.
*/
public String visualizeKeyDistribution(int characters);
/**
* Adds all elements from the given {@link CharContainer} to this set.
*
* @return Returns the number of elements actually added as a result of this call (not previously
* present in the set).
* @since 0.9.1
*/
public int addAll(CharContainer container);
}

View File

@ -0,0 +1,105 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.*;
import com.carrotsearch.hppc.predicates.*;
import com.carrotsearch.hppc.procedures.*;
import java.util.Iterator;
/**
* An associative container from keys to (one or possibly more) values.
*
* @see CharContainer
*/
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "KTypeVTypeAssociativeContainer.java")
public interface CharShortAssociativeContainer extends Iterable<CharShortCursor> {
/**
* Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as
* a cursor and it returns <b>the same cursor instance</b> on every call to {@link
* Iterator#next()}. To read the current key and value use the cursor's public fields. An example
* is shown below.
*
* <pre>
* for (IntShortCursor c : intShortMap) {
* System.out.println(&quot;index=&quot; + c.index + &quot; key=&quot; + c.key + &quot; value=&quot; + c.value);
* }</pre>
*
* <p>The <code>index</code> field inside the cursor gives the internal index inside the
* container's implementation. The interpretation of this index depends on to the container.
*/
@Override
public Iterator<CharShortCursor> iterator();
/**
* Returns <code>true</code> if this container has an association to a value for the given key.
*/
public boolean containsKey(char key);
/**
* @return Returns the current size (number of assigned keys) in the container.
*/
public int size();
/**
* @return Return <code>true</code> if this hash map contains no assigned keys.
*/
public boolean isEmpty();
/**
* Removes all keys (and associated values) present in a given container. An alias to:
*
* <pre>
* keys().removeAll(container)
* </pre>
*
* but with no additional overhead.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharContainer container);
/**
* Removes all keys (and associated values) for which the predicate returns <code>true</code>.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharPredicate predicate);
/**
* Removes all keys (and associated values) for which the predicate returns <code>true</code>.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(CharShortPredicate predicate);
/**
* Applies a given procedure to all keys-value pairs in this container. Returns the argument (any
* subclass of {@link CharShortProcedure}. This lets the caller call methods of the argument by
* chaining the call (even if the argument is an anonymous type) to retrieve computed values.
*/
public <T extends CharShortProcedure> T forEach(T procedure);
/**
* Applies a given predicate to all keys-value pairs in this container. Returns the argument (any
* subclass of {@link CharShortPredicate}. This lets the caller call methods of the argument by
* chaining the call (even if the argument is an anonymous type) to retrieve computed values.
*
* <p>The iteration is continued as long as the predicate returns <code>true</code>.
*/
public <T extends CharShortPredicate> T forEach(T predicate);
/**
* Returns a collection of keys of this container. The returned collection is a view over the key
* set and any modifications (if allowed) introduced to the collection will propagate to the
* associative container immediately.
*/
public CharCollection keys();
/**
* Returns a container view of all values present in this container. The returned collection is a
* view over the key set and any modifications (if allowed) introduced to the collection will
* propagate to the associative container immediately.
*/
public ShortContainer values();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,205 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.CharShortCursor;
/** An associative container with unique binding from keys to a single value. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java")
public interface CharShortMap extends CharShortAssociativeContainer {
/**
* @return Returns the value associated with the given key or the default value for the value
* type, if the key is not associated with any value. For numeric value types, this default
* value is 0, for object types it is {@code null}.
*/
public short get(char key);
/**
* @return Returns the value associated with the given key or the provided default value if the
* key is not associated with any value.
*/
public short getOrDefault(char key, short defaultValue);
/**
* Place a given key and value in the container.
*
* @return The value previously stored under the given key in the map is returned.
*/
public short put(char key, short value);
/**
* If the specified key is not already associated with a value, associates it with the given
* value.
*
* @return {@code true} if {@code key} did not exist and {@code value} was placed in the map,
* {@code false} otherwise.
*/
public default boolean putIfAbsent(char key, short value) {
int keyIndex = indexOf(key);
if (indexExists(keyIndex)) {
return false;
} else {
indexInsert(keyIndex, key, value);
return true;
}
}
/**
* Puts all keys from another container to this map, replacing the values of existing keys, if
* such keys are present.
*
* @return Returns the number of keys added to the map as a result of this call (not previously
* present in the map). Values of existing keys are overwritten.
*/
public int putAll(CharShortAssociativeContainer container);
/**
* Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if
* such keys are present.
*
* @return Returns the number of keys added to the map as a result of this call (not previously
* present in the map). Values of existing keys are overwritten.
*/
public int putAll(Iterable<? extends CharShortCursor> iterable);
/**
* If <code>key</code> exists, <code>putValue</code> is inserted into the map, otherwise any
* existing value is incremented by <code>additionValue</code>.
*
* @param key The key of the value to adjust.
* @param putValue The value to put if <code>key</code> does not exist.
* @param incrementValue The value to add to the existing value if <code>key</code> exists.
* @return Returns the current value associated with <code>key</code> (after changes).
*/
public short putOrAdd(char key, short putValue, short incrementValue);
/**
* An equivalent of calling
*
* <pre>
* putOrAdd(key, additionValue, additionValue);
* </pre>
*
* @param key The key of the value to adjust.
* @param additionValue The value to put or add to the existing value if <code>key</code> exists.
* @return Returns the current value associated with <code>key</code> (after changes).
*/
public short addTo(char key, short additionValue);
/**
* Remove all values at the given key. The default value for the key type is returned if the value
* does not exist in the map.
*/
public short remove(char key);
/**
* Compares the specified object with this set for equality. Returns {@code true} if and only if
* the specified object is also a {@link CharShortMap} and both objects contains exactly the same
* key-value pairs.
*/
public boolean equals(Object obj);
/**
* @return A hash code of elements stored in the map. The hash code is defined as a sum of hash
* codes of keys and values stored within the set). Because sum is commutative, this ensures
* that different order of elements in a set does not affect the hash code.
*/
public int hashCode();
/**
* Returns a logical "index" of a given key that can be used to speed up follow-up value setters
* or getters in certain scenarios (conditional logic).
*
* <p>The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be)
* contiguous.
*
* <p>The index is valid only between map modifications (it will not be affected by read-only
* operations like iteration or value retrievals).
*
* @see #indexExists
* @see #indexGet
* @see #indexInsert
* @see #indexReplace
* @param key The key to locate in the map.
* @return A non-negative value of the logical "index" of the key in the map or a negative value
* if the key did not exist.
*/
public int indexOf(char key);
/**
* @see #indexOf
* @param index The index of a given key, as returned from {@link #indexOf}.
* @return Returns <code>true</code> if the index corresponds to an existing key or false
* otherwise. This is equivalent to checking whether the index is a positive value (existing
* keys) or a negative value (non-existing keys).
*/
public boolean indexExists(int index);
/**
* Returns the value associated with an existing key.
*
* @see #indexOf
* @param index The index of an existing key.
* @return Returns the value currently associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public short indexGet(int index);
/**
* Replaces the value associated with an existing key and returns any previous value stored for
* that key.
*
* @see #indexOf
* @param index The index of an existing key.
* @return Returns the previous value associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public short indexReplace(int index, short newValue);
/**
* Inserts a key-value pair for a key that is not present in the map. This method may help in
* avoiding double recalculation of the key's hash.
*
* @see #indexOf
* @param index The index of a previously non-existing key, as returned from {@link #indexOf}.
* @throws AssertionError If assertions are enabled and the index corresponds to an existing key.
*/
public void indexInsert(int index, char key, short value);
/**
* Removes a key-value pair at an index previously acquired from {@link #indexOf}.
*
* @see #indexOf
* @param index The index of the key to remove, as returned from {@link #indexOf}.
* @return Returns the previous value associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public short indexRemove(int index);
/**
* Clear all keys and values in the container.
*
* @see #release()
*/
public void clear();
/**
* Removes all elements from the collection and additionally releases any internal buffers.
* Typically, if the object is to be reused, a simple {@link #clear()} should be a better
* alternative since it'll avoid reallocation.
*
* @see #clear()
*/
public void release();
/**
* Visually depict the distribution of keys.
*
* @param characters The number of characters to "squeeze" the entire buffer into.
* @return Returns a sequence of characters where '.' depicts an empty fragment of the internal
* buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything
* between 1 and 9 is between.
*/
public String visualizeKeyDistribution(int characters);
}

View File

@ -0,0 +1,137 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.CharCursor;
/**
* A subclass of {@link CharArrayList} adding stack-related utility methods. The top of the stack is
* at the <code>{@link #size()} - 1</code> element.
*/
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeStack.java")
public class CharStack extends CharArrayList {
/** New instance with sane defaults. */
public CharStack() {
super();
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
*/
public CharStack(int expectedElements) {
super(expectedElements);
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
* @param resizer Underlying buffer sizing strategy.
*/
public CharStack(int expectedElements, ArraySizingStrategy resizer) {
super(expectedElements, resizer);
}
/** Create a stack by pushing all elements of another container to it. */
public CharStack(CharContainer container) {
super(container);
}
/** Adds one char to the stack. */
public void push(char e1) {
ensureBufferSpace(1);
buffer[elementsCount++] = e1;
}
/** Adds two chars to the stack. */
public void push(char e1, char e2) {
ensureBufferSpace(2);
buffer[elementsCount++] = e1;
buffer[elementsCount++] = e2;
}
/** Adds three chars to the stack. */
public void push(char e1, char e2, char e3) {
ensureBufferSpace(3);
buffer[elementsCount++] = e1;
buffer[elementsCount++] = e2;
buffer[elementsCount++] = e3;
}
/** Adds four chars to the stack. */
public void push(char e1, char e2, char e3, char e4) {
ensureBufferSpace(4);
buffer[elementsCount++] = e1;
buffer[elementsCount++] = e2;
buffer[elementsCount++] = e3;
buffer[elementsCount++] = e4;
}
/** Add a range of array elements to the stack. */
public void push(char[] elements, int start, int len) {
assert start >= 0 && len >= 0;
ensureBufferSpace(len);
System.arraycopy(elements, start, buffer, elementsCount, len);
elementsCount += len;
}
/**
* Vararg-signature method for pushing elements at the top of the stack.
*
* <p><b>This method is handy, but costly if used in tight loops (anonymous array passing)</b>
*/
public final void push(char... elements) {
push(elements, 0, elements.length);
}
/** Pushes all elements from another container to the top of the stack. */
public int pushAll(CharContainer container) {
return addAll(container);
}
/** Pushes all elements from another iterable to the top of the stack. */
public int pushAll(Iterable<? extends CharCursor> iterable) {
return addAll(iterable);
}
/** Discard an arbitrary number of elements from the top of the stack. */
public void discard(int count) {
assert elementsCount >= count;
elementsCount -= count;
}
/** Discard the top element from the stack. */
public void discard() {
assert elementsCount > 0;
elementsCount--;
}
/** Remove the top element from the stack and return it. */
public char pop() {
return removeLast();
}
/** Peek at the top element on the stack. */
public char peek() {
assert elementsCount > 0;
return buffer[elementsCount - 1];
}
/** Create a stack by pushing a variable number of arguments to it. */
public static CharStack from(char... elements) {
final CharStack stack = new CharStack(elements.length);
stack.push(elements);
return stack;
}
/** {@inheritDoc} */
@Override
public CharStack clone() {
return (CharStack) super.clone();
}
}

View File

@ -0,0 +1,68 @@
/*
* HPPC
*
* Copyright (C) 2010-2024 Carrot Search s.c. and contributors
* All rights reserved.
*
* Refer to the full license file "LICENSE.txt":
* https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt
*/
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.internals.SuppressForbidden;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Constants used as defaults in containers.
*
* @see HashContainers
*/
public final class Containers {
/** The default number of expected elements for containers. */
public static final int DEFAULT_EXPECTED_ELEMENTS = 4;
/**
* External initial seed value. We do not care about multiple assignments so not volatile.
*
* @see #randomSeed64()
*/
private static String testsSeedProperty;
/** Unique marker for {@link #testsSeedProperty}. */
private static final String NOT_AVAILABLE = new String();
private Containers() {}
/**
* Provides a (possibly) random initial seed for randomized stuff.
*
* <p>If <code>tests.seed</code> property is available and accessible, the returned value will be
* derived from the value of that property and will be constant to ensure reproducibility in
* presence of the randomized testing package.
*
* @see "https://github.com/carrotsearch/randomizedtesting"
*/
@SuppressForbidden
public static long randomSeed64() {
if (testsSeedProperty == null) {
testsSeedProperty = System.getProperty("tests.seed", NOT_AVAILABLE);
}
long initialSeed;
if (testsSeedProperty != NOT_AVAILABLE) {
initialSeed = testsSeedProperty.hashCode();
} else {
// Mix something that is changing over time (nanoTime)
// ... with something that is thread-local and relatively unique
// even for very short time-spans (new Object's address from a TLAB).
initialSeed = System.nanoTime() ^ System.identityHashCode(new Object());
}
return BitMixer.mix64(initialSeed);
}
/** Reset state for tests. */
static void test$reset() {
testsSeedProperty = null;
}
}

View File

@ -0,0 +1,776 @@
package com.carrotsearch.hppc;
import static com.carrotsearch.hppc.Containers.*;
import com.carrotsearch.hppc.cursors.DoubleCursor;
import com.carrotsearch.hppc.predicates.DoublePredicate;
import com.carrotsearch.hppc.procedures.DoubleProcedure;
import java.util.*;
/** An array-backed {@link DoubleDeque}. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayDeque.java")
public class DoubleArrayDeque extends AbstractDoubleCollection
implements DoubleDeque, Preallocable, Cloneable, Accountable {
/** Reuse the same strategy instance. */
private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY =
BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE;
/** Internal array for storing elements of the deque. */
public double[] buffer = DoubleArrayList.EMPTY_ARRAY;
/**
* The index of the element at the head of the deque or an arbitrary number equal to tail if the
* deque is empty.
*/
public int head;
/** The index at which the next element would be added to the tail of the deque. */
public int tail;
/** Buffer resizing strategy. */
protected final ArraySizingStrategy resizer;
/** New instance with sane defaults. */
public DoubleArrayDeque() {
this(DEFAULT_EXPECTED_ELEMENTS);
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
*/
public DoubleArrayDeque(int expectedElements) {
this(expectedElements, DEFAULT_SIZING_STRATEGY);
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
* @param resizer Underlying buffer sizing strategy.
*/
public DoubleArrayDeque(int expectedElements, ArraySizingStrategy resizer) {
assert resizer != null;
this.resizer = resizer;
ensureCapacity(expectedElements);
}
/**
* Creates a new deque from elements of another container, appending elements at the end of the
* deque in the iteration order.
*/
public DoubleArrayDeque(DoubleContainer container) {
this(container.size());
addLast(container);
}
/** {@inheritDoc} */
@Override
public void addFirst(double e1) {
int h = oneLeft(head, buffer.length);
if (h == tail) {
ensureBufferSpace(1);
h = oneLeft(head, buffer.length);
}
buffer[head = h] = e1;
}
/**
* Vararg-signature method for adding elements at the front of this deque.
*
* <p><b>This method is handy, but costly if used in tight loops (anonymous array passing)</b>
*
* @param elements The elements to add.
*/
public final void addFirst(double... elements) {
ensureBufferSpace(elements.length);
for (double k : elements) {
addFirst(k);
}
}
/**
* Inserts all elements from the given container to the front of this deque.
*
* @param container The container to iterate over.
* @return Returns the number of elements actually added as a result of this call.
*/
public int addFirst(DoubleContainer container) {
int size = container.size();
ensureBufferSpace(size);
for (DoubleCursor cursor : container) {
addFirst(cursor.value);
}
return size;
}
/**
* Inserts all elements from the given iterable to the front of this deque.
*
* @param iterable The iterable to iterate over.
* @return Returns the number of elements actually added as a result of this call.
*/
public int addFirst(Iterable<? extends DoubleCursor> iterable) {
int size = 0;
for (DoubleCursor cursor : iterable) {
addFirst(cursor.value);
size++;
}
return size;
}
/** {@inheritDoc} */
@Override
public void addLast(double e1) {
int t = oneRight(tail, buffer.length);
if (head == t) {
ensureBufferSpace(1);
t = oneRight(tail, buffer.length);
}
buffer[tail] = e1;
tail = t;
}
/**
* Vararg-signature method for adding elements at the end of this deque.
*
* <p><b>This method is handy, but costly if used in tight loops (anonymous array passing)</b>
*
* @param elements The elements to iterate over.
*/
public final void addLast(double... elements) {
ensureBufferSpace(1);
for (double k : elements) {
addLast(k);
}
}
/**
* Inserts all elements from the given container to the end of this deque.
*
* @param container The container to iterate over.
* @return Returns the number of elements actually added as a result of this call.
*/
public int addLast(DoubleContainer container) {
int size = container.size();
ensureBufferSpace(size);
for (DoubleCursor cursor : container) {
addLast(cursor.value);
}
return size;
}
/**
* Inserts all elements from the given iterable to the end of this deque.
*
* @param iterable The iterable to iterate over.
* @return Returns the number of elements actually added as a result of this call.
*/
public int addLast(Iterable<? extends DoubleCursor> iterable) {
int size = 0;
for (DoubleCursor cursor : iterable) {
addLast(cursor.value);
size++;
}
return size;
}
/** {@inheritDoc} */
@Override
public double removeFirst() {
assert size() > 0 : "The deque is empty.";
final double result = buffer[head];
buffer[head] = 0d;
head = oneRight(head, buffer.length);
return result;
}
/** {@inheritDoc} */
@Override
public double removeLast() {
assert size() > 0 : "The deque is empty.";
tail = oneLeft(tail, buffer.length);
final double result = buffer[tail];
buffer[tail] = 0d;
return result;
}
/** {@inheritDoc} */
@Override
public double getFirst() {
assert size() > 0 : "The deque is empty.";
return buffer[head];
}
/** {@inheritDoc} */
@Override
public double getLast() {
assert size() > 0 : "The deque is empty.";
return buffer[oneLeft(tail, buffer.length)];
}
/** {@inheritDoc} */
@Override
public int removeFirst(double e1) {
final int index = bufferIndexOf(e1);
if (index >= 0) removeAtBufferIndex(index);
return index;
}
/**
* Return the index of the first (counting from head) element equal to <code>e1</code>. The index
* points to the {@link #buffer} array.
*
* @param e1 The element to look for.
* @return Returns the index of the first element equal to <code>e1</code> or <code>-1</code> if
* not found.
*/
public int bufferIndexOf(double e1) {
final int last = tail;
final int bufLen = buffer.length;
for (int i = head; i != last; i = oneRight(i, bufLen)) {
if ((Double.doubleToLongBits(e1) == Double.doubleToLongBits(buffer[i]))) {
return i;
}
}
return -1;
}
/** {@inheritDoc} */
@Override
public int removeLast(double e1) {
final int index = lastBufferIndexOf(e1);
if (index >= 0) {
removeAtBufferIndex(index);
}
return index;
}
/**
* Return the index of the last (counting from tail) element equal to <code>e1</code>. The index
* points to the {@link #buffer} array.
*
* @param e1 The element to look for.
* @return Returns the index of the first element equal to <code>e1</code> or <code>-1</code> if
* not found.
*/
public int lastBufferIndexOf(double e1) {
final int bufLen = buffer.length;
final int last = oneLeft(head, bufLen);
for (int i = oneLeft(tail, bufLen); i != last; i = oneLeft(i, bufLen)) {
if ((Double.doubleToLongBits(e1) == Double.doubleToLongBits(buffer[i]))) return i;
}
return -1;
}
/** {@inheritDoc} */
@Override
public int removeAll(double e1) {
int removed = 0;
final int last = tail;
final int bufLen = buffer.length;
int from, to;
for (from = to = head; from != last; from = oneRight(from, bufLen)) {
if ((Double.doubleToLongBits(e1) == Double.doubleToLongBits(buffer[from]))) {
buffer[from] = 0d;
removed++;
continue;
}
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = 0d;
}
to = oneRight(to, bufLen);
}
tail = to;
return removed;
}
/**
* Removes the element at <code>index</code> in the internal {#link {@link #buffer} array,
* returning its value.
*
* @param index Index of the element to remove. The index must be located between {@link #head}
* and {@link #tail} in modulo {@link #buffer} arithmetic.
*/
public void removeAtBufferIndex(int index) {
assert (head <= tail ? index >= head && index < tail : index >= head || index < tail)
: "Index out of range (head=" + head + ", tail=" + tail + ", index=" + index + ").";
// Cache fields in locals (hopefully moved to registers).
final double[] buffer = this.buffer;
final int bufLen = buffer.length;
final int lastIndex = bufLen - 1;
final int head = this.head;
final int tail = this.tail;
final int leftChunk = Math.abs(index - head) % bufLen;
final int rightChunk = Math.abs(tail - index) % bufLen;
if (leftChunk < rightChunk) {
if (index >= head) {
System.arraycopy(buffer, head, buffer, head + 1, leftChunk);
} else {
System.arraycopy(buffer, 0, buffer, 1, index);
buffer[0] = buffer[lastIndex];
System.arraycopy(buffer, head, buffer, head + 1, lastIndex - head);
}
buffer[head] = 0d;
this.head = oneRight(head, bufLen);
} else {
if (index < tail) {
System.arraycopy(buffer, index + 1, buffer, index, rightChunk);
} else {
System.arraycopy(buffer, index + 1, buffer, index, lastIndex - index);
buffer[lastIndex] = buffer[0];
System.arraycopy(buffer, 1, buffer, 0, tail);
}
buffer[tail] = 0d;
this.tail = oneLeft(tail, bufLen);
}
}
/** {@inheritDoc} */
@Override
public boolean isEmpty() {
return size() == 0;
}
/** {@inheritDoc} */
@Override
public int size() {
if (head <= tail) return tail - head;
else return (tail - head + buffer.length);
}
/**
* {@inheritDoc}
*
* <p>The internal array buffers are not released as a result of this call.
*
* @see #release()
*/
@Override
public void clear() {
if (head < tail) {
Arrays.fill(buffer, head, tail, 0d);
} else {
Arrays.fill(buffer, 0, tail, 0d);
Arrays.fill(buffer, head, buffer.length, 0d);
}
this.head = tail = 0;
}
/** Release internal buffers of this deque and reallocate with the default buffer. */
public void release() {
this.head = tail = 0;
buffer = DoubleArrayList.EMPTY_ARRAY;
ensureBufferSpace(0);
}
/**
* Ensure this container can hold at least the given number of elements without resizing its
* buffers.
*
* @param expectedElements The total number of elements, inclusive.
*/
@Override
public void ensureCapacity(int expectedElements) {
ensureBufferSpace(expectedElements - size());
}
/**
* Ensures the internal buffer has enough free slots to store <code>expectedAdditions</code>.
* Increases internal buffer size if needed.
*/
protected void ensureBufferSpace(int expectedAdditions) {
final int bufferLen = buffer.length;
final int elementsCount = size();
if (elementsCount + expectedAdditions >= bufferLen) {
final int emptySlot = 1; // deque invariant: always an empty slot.
final int newSize = resizer.grow(bufferLen, elementsCount + emptySlot, expectedAdditions);
assert newSize >= (elementsCount + expectedAdditions + emptySlot)
: "Resizer failed to"
+ " return sensible new size: "
+ newSize
+ " <= "
+ (elementsCount + expectedAdditions);
try {
final double[] newBuffer = (new double[newSize]);
if (bufferLen > 0) {
toArray(newBuffer);
tail = elementsCount;
head = 0;
}
this.buffer = newBuffer;
} catch (OutOfMemoryError e) {
throw new BufferAllocationException(
"Not enough memory to allocate new buffers: %,d -> %,d", e, bufferLen, newSize);
}
}
}
/** {@inheritDoc} */
@Override
public double[] toArray() {
final int size = size();
return toArray((new double[size]));
}
/**
* Copies elements of this deque to an array. The content of the <code>target</code> array is
* filled from index 0 (head of the queue) to index <code>size() - 1</code> (tail of the queue).
*
* @param target The target array must be large enough to hold all elements.
* @return Returns the target argument for chaining.
*/
public double[] toArray(double[] target) {
assert target.length >= size() : "Target array must be >= " + size();
if (head < tail) {
// The contents is not wrapped around. Just copy.
System.arraycopy(buffer, head, target, 0, size());
} else if (head > tail) {
// The contents is split. Merge elements from the following indexes:
// [head...buffer.length - 1][0, tail - 1]
final int rightCount = buffer.length - head;
System.arraycopy(buffer, head, target, 0, rightCount);
System.arraycopy(buffer, 0, target, rightCount, tail);
}
return target;
}
/**
* Clone this object. The returned clone will reuse the same hash function and array resizing
* strategy.
*/
@Override
public DoubleArrayDeque clone() {
try {
DoubleArrayDeque cloned = (DoubleArrayDeque) super.clone();
cloned.buffer = buffer.clone();
return cloned;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
/** Move one index to the left, wrapping around buffer. */
protected static int oneLeft(int index, int modulus) {
if (index >= 1) {
return index - 1;
}
return modulus - 1;
}
/** Move one index to the right, wrapping around buffer. */
protected static int oneRight(int index, int modulus) {
if (index + 1 == modulus) {
return 0;
}
return index + 1;
}
@Override
public long ramBytesAllocated() {
// int: head, tail
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ Integer.BYTES * 2
+ resizer.ramBytesAllocated()
+ RamUsageEstimator.shallowSizeOfArray(buffer);
}
@Override
public long ramBytesUsed() {
// int: head, tail
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ Integer.BYTES * 2
+ resizer.ramBytesUsed()
+ RamUsageEstimator.shallowUsedSizeOfArray(buffer, size());
}
/** An iterator implementation for {@link ObjectArrayDeque#iterator}. */
private final class ValueIterator extends AbstractIterator<DoubleCursor> {
private final DoubleCursor cursor;
private int remaining;
public ValueIterator() {
cursor = new DoubleCursor();
cursor.index = oneLeft(head, buffer.length);
this.remaining = size();
}
@Override
protected DoubleCursor fetch() {
if (remaining == 0) {
return done();
}
remaining--;
cursor.value = buffer[cursor.index = oneRight(cursor.index, buffer.length)];
return cursor;
}
}
/** An iterator implementation for {@link ObjectArrayDeque#descendingIterator()}. */
private final class DescendingValueIterator extends AbstractIterator<DoubleCursor> {
private final DoubleCursor cursor;
private int remaining;
public DescendingValueIterator() {
cursor = new DoubleCursor();
cursor.index = tail;
this.remaining = size();
}
@Override
protected DoubleCursor fetch() {
if (remaining == 0) return done();
remaining--;
cursor.value = buffer[cursor.index = oneLeft(cursor.index, buffer.length)];
return cursor;
}
}
/**
* Returns a cursor over the values of this deque (in head to tail order). The iterator is
* implemented as a cursor and it returns <b>the same cursor instance</b> on every call to {@link
* Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in
* the deque's buffer) use the cursor's public fields. An example is shown below.
*
* <pre>
* for (IntValueCursor c : intDeque) {
* System.out.println(&quot;buffer index=&quot; + c.index + &quot; value=&quot; + c.value);
* }
* </pre>
*/
public Iterator<DoubleCursor> iterator() {
return new ValueIterator();
}
/**
* Returns a cursor over the values of this deque (in tail to head order). The iterator is
* implemented as a cursor and it returns <b>the same cursor instance</b> on every call to {@link
* Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in
* the deque's buffer) use the cursor's public fields. An example is shown below.
*
* <pre>
* for (Iterator&lt;IntCursor&gt; i = intDeque.descendingIterator(); i.hasNext();) {
* final IntCursor c = i.next();
* System.out.println(&quot;buffer index=&quot; + c.index + &quot; value=&quot; + c.value);
* }
* </pre>
*/
public Iterator<DoubleCursor> descendingIterator() {
return new DescendingValueIterator();
}
/** {@inheritDoc} */
@Override
public <T extends DoubleProcedure> T forEach(T procedure) {
forEach(procedure, head, tail);
return procedure;
}
/**
* Applies <code>procedure</code> to a slice of the deque, <code>fromIndex</code>, inclusive, to
* <code>toIndex</code>, exclusive.
*/
private void forEach(DoubleProcedure procedure, int fromIndex, final int toIndex) {
final double[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
procedure.apply(buffer[i]);
}
}
/** {@inheritDoc} */
@Override
public <T extends DoublePredicate> T forEach(T predicate) {
int fromIndex = head;
int toIndex = tail;
final double[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
if (!predicate.apply(buffer[i])) {
break;
}
}
return predicate;
}
/** Applies <code>procedure</code> to all elements of this deque, tail to head. */
@Override
public <T extends DoubleProcedure> T descendingForEach(T procedure) {
descendingForEach(procedure, head, tail);
return procedure;
}
/**
* Applies <code>procedure</code> to a slice of the deque, <code>toIndex</code>, exclusive, down
* to <code>fromIndex</code>, inclusive.
*/
private void descendingForEach(DoubleProcedure procedure, int fromIndex, final int toIndex) {
if (fromIndex == toIndex) return;
final double[] buffer = this.buffer;
int i = toIndex;
do {
i = oneLeft(i, buffer.length);
procedure.apply(buffer[i]);
} while (i != fromIndex);
}
/** {@inheritDoc} */
@Override
public <T extends DoublePredicate> T descendingForEach(T predicate) {
descendingForEach(predicate, head, tail);
return predicate;
}
/**
* Applies <code>predicate</code> to a slice of the deque, <code>toIndex</code>, exclusive, down
* to <code>fromIndex</code>, inclusive or until the predicate returns <code>false</code>.
*/
private void descendingForEach(DoublePredicate predicate, int fromIndex, final int toIndex) {
if (fromIndex == toIndex) return;
final double[] buffer = this.buffer;
int i = toIndex;
do {
i = oneLeft(i, buffer.length);
if (!predicate.apply(buffer[i])) {
break;
}
} while (i != fromIndex);
}
/** {@inheritDoc} */
@Override
public int removeAll(DoublePredicate predicate) {
final double[] buffer = this.buffer;
final int last = tail;
final int bufLen = buffer.length;
int removed = 0;
int from, to;
from = to = head;
try {
for (from = to = head; from != last; from = oneRight(from, bufLen)) {
if (predicate.apply(buffer[from])) {
buffer[from] = 0d;
removed++;
continue;
}
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = 0d;
}
to = oneRight(to, bufLen);
}
} finally {
// Keep the deque in consistent state even if the predicate throws an exception.
for (; from != last; from = oneRight(from, bufLen)) {
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = 0d;
}
to = oneRight(to, bufLen);
}
tail = to;
}
return removed;
}
/** {@inheritDoc} */
@Override
public boolean contains(double e) {
int fromIndex = head;
int toIndex = tail;
final double[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
if ((Double.doubleToLongBits(e) == Double.doubleToLongBits(buffer[i]))) {
return true;
}
}
return false;
}
/** {@inheritDoc} */
@Override
public int hashCode() {
int h = 1;
int fromIndex = head;
int toIndex = tail;
final double[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
h = 31 * h + BitMixer.mix(this.buffer[i]);
}
return h;
}
/**
* Returns <code>true</code> only if the other object is an instance of the same class and with
* the same elements.
*/
@Override
public boolean equals(Object obj) {
return (this == obj)
|| (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj)));
}
/** Compare order-aligned elements against another {@link DoubleDeque}. */
protected boolean equalElements(DoubleArrayDeque other) {
int max = size();
if (other.size() != max) {
return false;
}
Iterator<DoubleCursor> i1 = this.iterator();
Iterator<? extends DoubleCursor> i2 = other.iterator();
while (i1.hasNext() && i2.hasNext()) {
if (!(Double.doubleToLongBits(i1.next().value) == Double.doubleToLongBits(i2.next().value))) {
return false;
}
}
return !i1.hasNext() && !i2.hasNext();
}
/** Create a new deque by pushing a variable number of arguments to the end of it. */
public static DoubleArrayDeque from(double... elements) {
final DoubleArrayDeque coll = new DoubleArrayDeque(elements.length);
coll.addLast(elements);
return coll;
}
}

View File

@ -0,0 +1,586 @@
package com.carrotsearch.hppc;
import static com.carrotsearch.hppc.Containers.*;
import com.carrotsearch.hppc.cursors.*;
import com.carrotsearch.hppc.predicates.DoublePredicate;
import com.carrotsearch.hppc.procedures.*;
import java.util.*;
import java.util.stream.DoubleStream;
/** An array-backed list of doubles. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayList.java")
public class DoubleArrayList extends AbstractDoubleCollection
implements DoubleIndexedContainer, Preallocable, Cloneable, Accountable {
/** An immutable empty buffer (array). */
public static final double[] EMPTY_ARRAY = new double[0];
;
/** Reuse the same strategy instance. */
private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY =
BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE;
/**
* Internal array for storing the list. The array may be larger than the current size ({@link
* #size()}).
*/
public double[] buffer = EMPTY_ARRAY;
/** Current number of elements stored in {@link #buffer}. */
public int elementsCount;
/** Buffer resizing strategy. */
protected final ArraySizingStrategy resizer;
/** New instance with sane defaults. */
public DoubleArrayList() {
this(DEFAULT_EXPECTED_ELEMENTS);
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
*/
public DoubleArrayList(int expectedElements) {
this(expectedElements, DEFAULT_SIZING_STRATEGY);
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
* @param resizer Underlying buffer sizing strategy.
*/
public DoubleArrayList(int expectedElements, ArraySizingStrategy resizer) {
assert resizer != null;
this.resizer = resizer;
buffer = Arrays.copyOf(buffer, expectedElements);
}
/** Creates a new list from the elements of another container in its iteration order. */
public DoubleArrayList(DoubleContainer container) {
this(container.size());
addAll(container);
}
/** {@inheritDoc} */
@Override
public void add(double e1) {
ensureBufferSpace(1);
buffer[elementsCount++] = e1;
}
/**
* Appends two elements at the end of the list. To add more than two elements, use <code>add
* </code> (vararg-version) or access the buffer directly (tight loop).
*/
public void add(double e1, double e2) {
ensureBufferSpace(2);
buffer[elementsCount++] = e1;
buffer[elementsCount++] = e2;
}
/** Add all elements from a range of given array to the list. */
public void add(double[] elements, int start, int length) {
assert length >= 0 : "Length must be >= 0";
ensureBufferSpace(length);
System.arraycopy(elements, start, buffer, elementsCount, length);
elementsCount += length;
}
/**
* Vararg-signature method for adding elements at the end of the list.
*
* <p><b>This method is handy, but costly if used in tight loops (anonymous array passing)</b>
*/
public final void add(double... elements) {
add(elements, 0, elements.length);
}
/** Adds all elements from another container. */
public int addAll(DoubleContainer container) {
final int size = container.size();
ensureBufferSpace(size);
for (DoubleCursor cursor : container) {
add(cursor.value);
}
return size;
}
/** Adds all elements from another iterable. */
public int addAll(Iterable<? extends DoubleCursor> iterable) {
int size = 0;
for (DoubleCursor cursor : iterable) {
add(cursor.value);
size++;
}
return size;
}
/** {@inheritDoc} */
@Override
public void insert(int index, double e1) {
assert (index >= 0 && index <= size())
: "Index " + index + " out of bounds [" + 0 + ", " + size() + "].";
ensureBufferSpace(1);
System.arraycopy(buffer, index, buffer, index + 1, elementsCount - index);
buffer[index] = e1;
elementsCount++;
}
/** {@inheritDoc} */
@Override
public double get(int index) {
assert (index >= 0 && index < size())
: "Index " + index + " out of bounds [" + 0 + ", " + size() + ").";
return buffer[index];
}
/** {@inheritDoc} */
@Override
public double set(int index, double e1) {
assert (index >= 0 && index < size())
: "Index " + index + " out of bounds [" + 0 + ", " + size() + ").";
final double v = buffer[index];
buffer[index] = e1;
return v;
}
/** {@inheritDoc} */
@Override
public double removeAt(int index) {
assert (index >= 0 && index < size())
: "Index " + index + " out of bounds [" + 0 + ", " + size() + ").";
final double v = buffer[index];
System.arraycopy(buffer, index + 1, buffer, index, --elementsCount - index);
return v;
}
/** {@inheritDoc} */
@Override
public double removeLast() {
assert elementsCount > 0;
final double v = buffer[--elementsCount];
return v;
}
/** {@inheritDoc} */
@Override
public void removeRange(int fromIndex, int toIndex) {
assert (fromIndex >= 0 && fromIndex <= size())
: "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ").";
assert (toIndex >= 0 && toIndex <= size())
: "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "].";
assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex;
System.arraycopy(buffer, toIndex, buffer, fromIndex, elementsCount - toIndex);
final int count = toIndex - fromIndex;
elementsCount -= count;
}
/** {@inheritDoc} */
@Override
public boolean removeElement(double e1) {
return removeFirst(e1) != -1;
}
/** {@inheritDoc} */
@Override
public int removeFirst(double e1) {
final int index = indexOf(e1);
if (index >= 0) removeAt(index);
return index;
}
/** {@inheritDoc} */
@Override
public int removeLast(double e1) {
final int index = lastIndexOf(e1);
if (index >= 0) removeAt(index);
return index;
}
/** {@inheritDoc} */
@Override
public int removeAll(double e1) {
int to = 0;
for (int from = 0; from < elementsCount; from++) {
if ((Double.doubleToLongBits(e1) == Double.doubleToLongBits(buffer[from]))) {
continue;
}
if (to != from) {
buffer[to] = buffer[from];
}
to++;
}
final int deleted = elementsCount - to;
this.elementsCount = to;
return deleted;
}
/** {@inheritDoc} */
@Override
public boolean contains(double e1) {
return indexOf(e1) >= 0;
}
/** {@inheritDoc} */
@Override
public int indexOf(double e1) {
for (int i = 0; i < elementsCount; i++) {
if ((Double.doubleToLongBits(e1) == Double.doubleToLongBits(buffer[i]))) {
return i;
}
}
return -1;
}
/** {@inheritDoc} */
@Override
public int lastIndexOf(double e1) {
for (int i = elementsCount - 1; i >= 0; i--) {
if ((Double.doubleToLongBits(e1) == Double.doubleToLongBits(buffer[i]))) {
return i;
}
}
return -1;
}
/** {@inheritDoc} */
@Override
public boolean isEmpty() {
return elementsCount == 0;
}
/**
* Ensure this container can hold at least the given number of elements without resizing its
* buffers.
*
* @param expectedElements The total number of elements, inclusive.
*/
@Override
public void ensureCapacity(int expectedElements) {
final int bufferLen = (buffer == null ? 0 : buffer.length);
if (expectedElements > bufferLen) {
ensureBufferSpace(expectedElements - size());
}
}
/**
* Ensures the internal buffer has enough free slots to store <code>expectedAdditions</code>.
* Increases internal buffer size if needed.
*/
protected void ensureBufferSpace(int expectedAdditions) {
final int bufferLen = (buffer == null ? 0 : buffer.length);
if (elementsCount + expectedAdditions > bufferLen) {
final int newSize = resizer.grow(bufferLen, elementsCount, expectedAdditions);
assert newSize >= elementsCount + expectedAdditions
: "Resizer failed to"
+ " return sensible new size: "
+ newSize
+ " <= "
+ (elementsCount + expectedAdditions);
this.buffer = Arrays.copyOf(buffer, newSize);
}
}
/**
* Truncate or expand the list to the new size. If the list is truncated, the buffer will not be
* reallocated (use {@link #trimToSize()} if you need a truncated buffer), but the truncated
* values will be reset to the default value (zero). If the list is expanded, the elements beyond
* the current size are initialized with JVM-defaults (zero or <code>null</code> values).
*/
public void resize(int newSize) {
if (newSize <= buffer.length) {
if (newSize < elementsCount) {
Arrays.fill(buffer, newSize, elementsCount, 0d);
} else {
Arrays.fill(buffer, elementsCount, newSize, 0d);
}
} else {
ensureCapacity(newSize);
}
this.elementsCount = newSize;
}
/** {@inheritDoc} */
@Override
public int size() {
return elementsCount;
}
/** Trim the internal buffer to the current size. */
public void trimToSize() {
if (size() != this.buffer.length) {
this.buffer = toArray();
}
}
/**
* Sets the number of stored elements to zero. Releases and initializes the internal storage array
* to default values. To clear the list without cleaning the buffer, simply set the {@link
* #elementsCount} field to zero.
*/
@Override
public void clear() {
Arrays.fill(buffer, 0, elementsCount, 0d);
this.elementsCount = 0;
}
/** Sets the number of stored elements to zero and releases the internal storage array. */
@Override
public void release() {
this.buffer = EMPTY_ARRAY;
this.elementsCount = 0;
}
/**
* {@inheritDoc}
*
* <p>The returned array is sized to match exactly the number of elements of the stack.
*/
@Override
public double[] toArray() {
return Arrays.copyOf(buffer, elementsCount);
}
@Override
public DoubleStream stream() {
return Arrays.stream(buffer, 0, size());
}
/** {@inheritDoc} */
@Override
public DoubleIndexedContainer sort() {
Arrays.sort(buffer, 0, elementsCount);
return this;
}
/** {@inheritDoc} */
@Override
public DoubleIndexedContainer reverse() {
for (int i = 0, mid = elementsCount >> 1, j = elementsCount - 1; i < mid; i++, j--) {
double tmp = buffer[i];
buffer[i] = buffer[j];
buffer[j] = tmp;
}
return this;
}
/**
* Clone this object. The returned clone will reuse the same hash function and array resizing
* strategy.
*/
@Override
public DoubleArrayList clone() {
try {
final DoubleArrayList cloned = (DoubleArrayList) super.clone();
cloned.buffer = buffer.clone();
return cloned;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
/** {@inheritDoc} */
@Override
public int hashCode() {
int h = 1, max = elementsCount;
for (int i = 0; i < max; i++) {
h = 31 * h + BitMixer.mix(this.buffer[i]);
}
return h;
}
/**
* Returns <code>true</code> only if the other object is an instance of the same class and with
* the same elements.
*/
@Override
public boolean equals(Object obj) {
return (this == obj)
|| (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj)));
}
/** Compare index-aligned elements against another {@link DoubleIndexedContainer}. */
protected boolean equalElements(DoubleArrayList other) {
int max = size();
if (other.size() != max) {
return false;
}
for (int i = 0; i < max; i++) {
if (!(Double.doubleToLongBits(get(i)) == Double.doubleToLongBits(other.get(i)))) {
return false;
}
}
return true;
}
@Override
public long ramBytesAllocated() {
// int: elementsCount
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ Integer.BYTES
+ resizer.ramBytesAllocated()
+ RamUsageEstimator.shallowSizeOfArray(buffer);
}
@Override
public long ramBytesUsed() {
// int: elementsCount
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ Integer.BYTES
+ resizer.ramBytesUsed()
+ RamUsageEstimator.shallowUsedSizeOfArray(buffer, elementsCount);
}
/** An iterator implementation for {@link DoubleArrayList#iterator}. */
static final class ValueIterator extends AbstractIterator<DoubleCursor> {
private final DoubleCursor cursor;
private final double[] buffer;
private final int size;
public ValueIterator(double[] buffer, int size) {
this.cursor = new DoubleCursor();
this.cursor.index = -1;
this.size = size;
this.buffer = buffer;
}
@Override
protected DoubleCursor fetch() {
if (cursor.index + 1 == size) return done();
cursor.value = buffer[++cursor.index];
return cursor;
}
}
/** {@inheritDoc} */
@Override
public Iterator<DoubleCursor> iterator() {
return new ValueIterator(buffer, size());
}
/** {@inheritDoc} */
@Override
public <T extends DoubleProcedure> T forEach(T procedure) {
return forEach(procedure, 0, size());
}
/**
* Applies <code>procedure</code> to a slice of the list, <code>fromIndex</code>, inclusive, to
* <code>toIndex</code>, exclusive.
*/
public <T extends DoubleProcedure> T forEach(T procedure, int fromIndex, final int toIndex) {
assert (fromIndex >= 0 && fromIndex <= size())
: "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ").";
assert (toIndex >= 0 && toIndex <= size())
: "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "].";
assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex;
final double[] buffer = this.buffer;
for (int i = fromIndex; i < toIndex; i++) {
procedure.apply(buffer[i]);
}
return procedure;
}
/** {@inheritDoc} */
@Override
public int removeAll(DoublePredicate predicate) {
final double[] buffer = this.buffer;
final int elementsCount = this.elementsCount;
int to = 0;
int from = 0;
try {
for (; from < elementsCount; from++) {
if (predicate.apply(buffer[from])) {
buffer[from] = 0d;
continue;
}
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = 0d;
}
to++;
}
} finally {
// Keep the list in a consistent state, even if the predicate throws an exception.
for (; from < elementsCount; from++) {
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = 0d;
}
to++;
}
this.elementsCount = to;
}
return elementsCount - to;
}
/** {@inheritDoc} */
@Override
public <T extends DoublePredicate> T forEach(T predicate) {
return forEach(predicate, 0, size());
}
/**
* Applies <code>predicate</code> to a slice of the list, <code>fromIndex</code>, inclusive, to
* <code>toIndex</code>, exclusive, or until predicate returns <code>false</code>.
*/
public <T extends DoublePredicate> T forEach(T predicate, int fromIndex, final int toIndex) {
assert (fromIndex >= 0 && fromIndex <= size())
: "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ").";
assert (toIndex >= 0 && toIndex <= size())
: "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "].";
assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex;
final double[] buffer = this.buffer;
for (int i = fromIndex; i < toIndex; i++) {
if (!predicate.apply(buffer[i])) break;
}
return predicate;
}
/**
* Create a list from a variable number of arguments or an array of <code>double</code>. The
* elements are copied from the argument to the internal buffer.
*/
public static DoubleArrayList from(double... elements) {
final DoubleArrayList list = new DoubleArrayList(elements.length);
list.add(elements);
return list;
}
}

View File

@ -0,0 +1,33 @@
package com.carrotsearch.hppc;
/**
* Reused buffer visualization routines.
*
* @see DoubleSet#visualizeKeyDistribution(int)
* @see DoubleVTypeMap#visualizeKeyDistribution(int)
*/
class DoubleBufferVisualizer {
static String visualizeKeyDistribution(double[] buffer, int max, int characters) {
final StringBuilder b = new StringBuilder();
final char[] chars = ".123456789X".toCharArray();
for (int i = 1, start = -1; i <= characters; i++) {
int end = (int) ((long) i * max / characters);
if (start + 1 <= end) {
int taken = 0;
int slots = 0;
for (int slot = start + 1; slot <= end; slot++, slots++) {
if (!(Double.doubleToLongBits(buffer[slot]) == 0)) {
taken++;
}
}
b.append(chars[Math.min(chars.length - 1, taken * chars.length / slots)]);
start = end;
}
}
while (b.length() < characters) {
b.append(' ');
}
return b.toString();
}
}

View File

@ -0,0 +1,64 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.predicates.DoublePredicate;
/**
* A collection allows basic, efficient operations on sets of elements (difference and
* intersection).
*/
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCollection.java")
public interface DoubleCollection extends DoubleContainer {
/**
* Removes all occurrences of <code>e</code> from this collection.
*
* @param e Element to be removed from this collection, if present.
* @return The number of removed elements as a result of this call.
*/
public int removeAll(double e);
/**
* Removes all elements in this collection that are present in <code>c</code>.
*
* @return Returns the number of removed elements.
*/
public int removeAll(DoubleLookupContainer c);
/**
* Removes all elements in this collection for which the given predicate returns <code>true</code>
* .
*
* @return Returns the number of removed elements.
*/
public int removeAll(DoublePredicate predicate);
/**
* Keeps all elements in this collection that are present in <code>c</code>. Runs in time
* proportional to the number of elements in this collection. Equivalent of sets intersection.
*
* @return Returns the number of removed elements.
*/
public int retainAll(DoubleLookupContainer c);
/**
* Keeps all elements in this collection for which the given predicate returns <code>true</code>.
*
* @return Returns the number of removed elements.
*/
public int retainAll(DoublePredicate predicate);
/**
* Removes all elements from this collection.
*
* @see #release()
*/
public void clear();
/**
* Removes all elements from the collection and additionally releases any internal buffers.
* Typically, if the object is to be reused, a simple {@link #clear()} should be a better
* alternative since it'll avoid reallocation.
*
* @see #clear()
*/
public void release();
}

View File

@ -0,0 +1,76 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.DoubleCursor;
import com.carrotsearch.hppc.predicates.DoublePredicate;
import com.carrotsearch.hppc.procedures.DoubleProcedure;
import java.util.Iterator;
/** A generic container holding <code>double</code>s. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeContainer.java")
public interface DoubleContainer extends Iterable<DoubleCursor> {
/**
* Returns an iterator to a cursor traversing the collection. The order of traversal is not
* defined. More than one cursor may be active at a time. The behavior of iterators is undefined
* if structural changes are made to the underlying collection.
*
* <p>The iterator is implemented as a cursor and it returns <b>the same cursor instance</b> on
* every call to {@link Iterator#next()} (to avoid boxing of primitive types). To read the current
* list's value (or index in the list) use the cursor's public fields. An example is shown below.
*
* <pre>
* for (DoubleCursor&lt;double&gt; c : container) {
* System.out.println(&quot;index=&quot; + c.index + &quot; value=&quot; + c.value);
* }
* </pre>
*/
public Iterator<DoubleCursor> iterator();
/**
* Lookup a given element in the container. This operation has no speed guarantees (may be linear
* with respect to the size of this container).
*
* @return Returns <code>true</code> if this container has an element equal to <code>e</code>.
*/
public boolean contains(double e);
/**
* Return the current number of elements in this container. The time for calculating the
* container's size may take <code>O(n)</code> time, although implementing classes should try to
* maintain the current size and return in constant time.
*/
public int size();
/** Shortcut for <code>size() == 0</code>. */
public boolean isEmpty();
/**
* Copies all elements of this container to an array.
*
* <p>The returned array is always a copy, regardless of the storage used by the container.
*/
public double[] toArray();
/**
* Applies a <code>procedure</code> to all container elements. Returns the argument (any subclass
* of {@link DoubleProcedure}. This lets the caller to call methods of the argument by chaining
* the call (even if the argument is an anonymous type) to retrieve computed values, for example
* (IntContainer):
*
* <pre>
* int count = container.forEach(new IntProcedure() {
* int count; // this is a field declaration in an anonymous class.
*
* public void apply(int value) {
* count++;
* }
* }).count;
* </pre>
*/
public <T extends DoubleProcedure> T forEach(T procedure);
/**
* Applies a <code>predicate</code> to container elements as long, as the predicate returns <code>
* true</code>. The iteration is interrupted otherwise.
*/
public <T extends DoublePredicate> T forEach(T predicate);
}

View File

@ -0,0 +1,77 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.DoubleCursor;
import com.carrotsearch.hppc.predicates.DoublePredicate;
import com.carrotsearch.hppc.procedures.DoubleProcedure;
import java.util.Deque;
import java.util.Iterator;
/**
* A linear collection that supports element insertion and removal at both ends.
*
* @see Deque
*/
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeDeque.java")
public interface DoubleDeque extends DoubleCollection {
/**
* Removes the first element that equals <code>e</code>.
*
* @return The deleted element's index or <code>-1</code> if the element was not found.
*/
public int removeFirst(double e);
/**
* Removes the last element that equals <code>e</code>.
*
* @return The deleted element's index or <code>-1</code> if the element was not found.
*/
public int removeLast(double e);
/** Inserts the specified element at the front of this deque. */
public void addFirst(double e);
/** Inserts the specified element at the end of this deque. */
public void addLast(double e);
/**
* Retrieves and removes the first element of this deque.
*
* @return the head (first) element of this deque.
*/
public double removeFirst();
/**
* Retrieves and removes the last element of this deque.
*
* @return the tail of this deque.
*/
public double removeLast();
/**
* Retrieves the first element of this deque but does not remove it.
*
* @return the head of this deque.
*/
public double getFirst();
/**
* Retrieves the last element of this deque but does not remove it.
*
* @return the head of this deque.
*/
public double getLast();
/**
* @return An iterator over elements in this deque in tail-to-head order.
*/
public Iterator<DoubleCursor> descendingIterator();
/** Applies a <code>procedure</code> to all elements in tail-to-head order. */
public <T extends DoubleProcedure> T descendingForEach(T procedure);
/**
* Applies a <code>predicate</code> to container elements as long, as the predicate returns <code>
* true</code>. The iteration is interrupted otherwise.
*/
public <T extends DoublePredicate> T descendingForEach(T predicate);
}

View File

@ -0,0 +1,93 @@
package com.carrotsearch.hppc;
import java.util.RandomAccess;
import java.util.stream.DoubleStream;
/**
* An indexed container provides random access to elements based on an <code>index</code>. Indexes
* are zero-based.
*/
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "KTypeIndexedContainer.java")
public interface DoubleIndexedContainer extends DoubleCollection, RandomAccess {
/**
* Removes the first element that equals <code>e1</code>, returning whether an element has been
* removed.
*/
public boolean removeElement(double e1);
/**
* Removes the first element that equals <code>e1</code>, returning its deleted position or <code>
* -1</code> if the element was not found.
*/
public int removeFirst(double e1);
/**
* Removes the last element that equals <code>e1</code>, returning its deleted position or <code>
* -1</code> if the element was not found.
*/
public int removeLast(double e1);
/**
* Returns the index of the first occurrence of the specified element in this list, or -1 if this
* list does not contain the element.
*/
public int indexOf(double e1);
/**
* Returns the index of the last occurrence of the specified element in this list, or -1 if this
* list does not contain the element.
*/
public int lastIndexOf(double e1);
/** Adds an element to the end of this container (the last index is incremented by one). */
public void add(double e1);
/**
* Inserts the specified element at the specified position in this list.
*
* @param index The index at which the element should be inserted, shifting any existing and
* subsequent elements to the right.
*/
public void insert(int index, double e1);
/**
* Replaces the element at the specified position in this list with the specified element.
*
* @return Returns the previous value in the list.
*/
public double set(int index, double e1);
/**
* @return Returns the element at index <code>index</code> from the list.
*/
public double get(int index);
/**
* Removes the element at the specified position in this container and returns it.
*
* @see #removeFirst
* @see #removeLast
* @see #removeAll
*/
public double removeAt(int index);
/** Removes and returns the last element of this container. This container must not be empty. */
public double removeLast();
/**
* Removes from this container all of the elements with indexes between <code>fromIndex</code>,
* inclusive, and <code>toIndex</code>, exclusive.
*/
public void removeRange(int fromIndex, int toIndex);
/** Returns this container elements as a stream. */
public DoubleStream stream();
/** Sorts the elements in this container and returns this container. */
public DoubleIndexedContainer sort();
/** Reverses the elements in this container and returns this container. */
public DoubleIndexedContainer reverse();
}

View File

@ -0,0 +1,12 @@
package com.carrotsearch.hppc;
/**
* Marker interface for containers that can check if they contain a given object in at least time
* <code>O(log n)</code> and ideally in amortized constant time <code>O(1)</code>.
*/
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "KTypeLookupContainer.java")
public interface DoubleLookupContainer extends DoubleContainer {
public boolean contains(double e);
}

View File

@ -0,0 +1,600 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.DoubleCursor;
import com.carrotsearch.hppc.procedures.DoubleProcedure;
import java.util.Arrays;
import java.util.Iterator;
/**
* Space-efficient index that enables fast rank/range search operations on a sorted sequence of
* <code>double</code>.
*
* <p>Implementation of the PGM-Index described at <a
* href="https://pgm.di.unipi.it/">https://pgm.di.unipi.it/</a>, based on the paper
*
* <pre>
* Paolo Ferragina and Giorgio Vinciguerra.
* The PGM-index: a fully-dynamic compressed learned index with provable worst-case bounds.
* PVLDB, 13(8): 1162-1175, 2020.
* </pre>
*
* It provides {@code rank} and {@code range} search operations. {@code indexOf()} is faster than
* B+Tree, and the index is much more compact. {@code contains()} is between 4x to 7x slower than
* {@code IntHashSet#contains()}, but between 2.5x to 3x faster than {@link Arrays#binarySearch}.
*
* <p>Its compactness (40KB for 200MB of keys) makes it efficient for very large collections, the
* index fitting easily in the L2 cache. The {@code epsilon} parameter should be set according to
* the desired space-time trade-off. A smaller value makes the estimation more precise and the range
* smaller but at the cost of increased space usage. In practice, {@code epsilon} 64 is a good sweet
* spot.
*
* <p>Internally the index uses an optimal piecewise linear mapping from keys to their position in
* the sorted order. This mapping is represented as a sequence of linear models (segments) which are
* themselves recursively indexed by other piecewise linear mappings.
*/
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypePgmIndex.java")
public class DoublePgmIndex implements Accountable {
/** Empty immutable DoublePgmIndex. */
public static final DoublePgmIndex EMPTY = new DoubleEmptyPgmIndex();
/**
* Epsilon approximation range when searching the list of keys. Controls the size of the returned
* search range, strictly greater than 0. It should be set according to the desired space-time
* trade-off. A smaller value makes the estimation more precise and the range smaller but at the
* cost of increased space usage.
*
* <p>With EPSILON=64 the benchmark with 200MB of keys shows that this PGM index requires only 2%
* additional memory on average (40KB). It depends on the distribution of the keys. This epsilon
* value is good even for 2MB of keys. With EPSILON=32: +5% speed, but 4x space (160KB).
*/
public static final int EPSILON = 64;
/**
* Epsilon approximation range for the segments layers. Controls the size of the search range in
* the hierarchical segment lists, strictly greater than 0.
*/
public static final int EPSILON_RECURSIVE = 32;
/** Size of a key, measured in {@link Integer#BYTES} because the key is stored in an int[]. */
public static final int KEY_SIZE =
RamUsageEstimator.primitiveSizes.get(double.class) / Integer.BYTES;
/** 2x {@link #KEY_SIZE}. */
public static final int DOUBLE_KEY_SIZE = KEY_SIZE * 2;
/**
* Data size of a segment, measured in {@link Integer#BYTES}, because segments are stored in an
* int[].
*/
public static final int SEGMENT_DATA_SIZE = KEY_SIZE * 3;
/** Initial value of the exponential jump when scanning out of the epsilon range. */
public static final int BEYOND_EPSILON_JUMP = 16;
/**
* The list of keys for which this index is built. It is sorted and may contain duplicate
* elements.
*/
public final DoubleArrayList keys;
/** The size of the key set. That is, the number of distinct elements in {@link #keys}. */
public final int size;
/** The lowest key in {@link #keys}. */
public final double firstKey;
/** The highest key in {@link #keys}. */
public final double lastKey;
/** The epsilon range used to build this index. */
public final int epsilon;
/** The recursive epsilon range used to build this index. */
public final int epsilonRecursive;
/** The offsets in {@link #segmentData} of the first segment of each segment level. */
public final int[] levelOffsets;
/** The index data. It contains all the segments for all the levels. */
public final int[] segmentData;
private DoublePgmIndex(
DoubleArrayList keys,
int size,
int epsilon,
int epsilonRecursive,
int[] levelOffsets,
int[] segmentData) {
assert keys.size() > 0;
assert size > 0 && size <= keys.size();
assert epsilon > 0;
assert epsilonRecursive > 0;
this.keys = keys;
this.size = size;
firstKey = keys.get(0);
lastKey = keys.get(keys.size() - 1);
this.epsilon = epsilon;
this.epsilonRecursive = epsilonRecursive;
this.levelOffsets = levelOffsets;
this.segmentData = segmentData;
}
/** Empty set constructor. */
private DoublePgmIndex() {
keys = new DoubleArrayList(0);
size = 0;
firstKey = 0d;
lastKey = 0d;
epsilon = 0;
epsilonRecursive = 0;
levelOffsets = new int[0];
segmentData = levelOffsets;
}
/** Returns the size of the key set. That is, the number of distinct elements in {@link #keys}. */
public int size() {
return size;
}
/** Returns whether this key set is empty. */
public boolean isEmpty() {
return size() == 0;
}
/** Returns whether this key set contains the given key. */
public boolean contains(double key) {
return indexOf(key) >= 0;
}
/**
* Searches the specified key, and returns its index in the element list. If multiple elements are
* equal to the specified key, there is no guarantee which one will be found.
*
* @return The index of the searched key if it is present; otherwise, {@code (-(<i>insertion
* point</i>) - 1)}. The <i>insertion point</i> is defined as the point at which the key would
* be inserted into the list: the index of the first element greater than the key, or {@link
* #keys}#{@code size()} if all the elements are less than the specified key. Note that this
* guarantees that the return value will be &gt;= 0 if and only if the key is found.
*/
public int indexOf(double key) {
if (key < firstKey) {
return -1;
}
if (key > lastKey) {
return -keys.size() - 1;
}
final int[] segmentData = this.segmentData;
int segmentDataIndex = findSegment(key);
int nextIntercept = (int) getIntercept(segmentDataIndex + SEGMENT_DATA_SIZE, segmentData);
int index =
Math.min(
approximateIndex(key, segmentDataIndex, segmentData),
Math.min(nextIntercept, keys.size() - 1));
assert index >= 0 && index < keys.size();
double k = keys.get(index);
if (key < k) {
// Scan sequentially before the approximated index, within epsilon range.
final int fromIndex = Math.max(index - epsilon - 1, 0);
while (--index >= fromIndex) {
k = keys.get(index);
if (key > k) {
return -index - 2;
}
if ((Double.doubleToLongBits(key) == Double.doubleToLongBits(k))) {
return index;
}
}
// Continue scanning out of the epsilon range.
// This might happen in rare cases of precision error during the approximation
// computation for longs (we don't have long double 128 bits in Java).
// This might also happen in rare corner cases of large duplicate elements
// sequence at the epsilon range boundary.
index++;
int jump = BEYOND_EPSILON_JUMP;
do {
int loIndex = Math.max(index - jump, 0);
if (key >= keys.get(loIndex)) {
return Arrays.binarySearch(keys.buffer, loIndex, index, key);
}
index = loIndex;
jump <<= 1;
} while (index > 0);
return -1;
} else if ((Double.doubleToLongBits(key) == Double.doubleToLongBits(k))) {
return index;
} else {
// Scan sequentially after the approximated index, within epsilon range.
final int toIndex = Math.min(index + epsilon + 3, keys.size());
while (++index < toIndex) {
k = keys.get(index);
if (key < k) {
return -index - 1;
}
if ((Double.doubleToLongBits(key) == Double.doubleToLongBits(k))) {
return index;
}
}
// Continue scanning out of the epsilon range.
int jump = BEYOND_EPSILON_JUMP;
do {
int hiIndex = Math.min(index + jump, keys.size());
if (key <= keys.get(hiIndex)) {
return Arrays.binarySearch(keys.buffer, index, hiIndex, key);
}
index = hiIndex;
jump <<= 1;
} while (index < keys.size());
return -keys.size() - 1;
}
}
/**
* Returns, for any value {@code x}, the number of keys in the sorted list which are smaller than
* {@code x}. It is equal to {@link #indexOf} if {@code x} belongs to the list, or -{@link
* #indexOf}-1 otherwise.
*
* <p>If multiple elements are equal to the specified key, there is no guarantee which one will be
* found.
*
* @return The index of the searched key if it is present; otherwise, the {@code insertion point}.
* The <i>insertion point</i> is defined as the point at which the key would be inserted into
* the list: the index of the first element greater than the key, or {@link #keys}#{@code
* size()} if all the elements are less than the specified key. Note that this method always
* returns a value &gt;= 0.
*/
public int rank(double x) {
int index = indexOf(x);
return index >= 0 ? index : -index - 1;
}
/**
* Returns the number of keys in the list that are greater than or equal to {@code minKey}
* (inclusive), and less than or equal to {@code maxKey} (inclusive).
*/
public int rangeCardinality(double minKey, double maxKey) {
int fromIndex = rank(minKey);
int maxIndex = indexOf(maxKey);
int toIndex = maxIndex >= 0 ? maxIndex + 1 : -maxIndex - 1;
return Math.max(toIndex - fromIndex, 0);
}
/**
* Returns an iterator over the keys in the list that are greater than or equal to {@code minKey}
* (inclusive), and less than or equal to {@code maxKey} (inclusive).
*/
public Iterator<DoubleCursor> rangeIterator(double minKey, double maxKey) {
int fromIndex = rank(minKey);
return new RangeIterator(keys, fromIndex, maxKey);
}
/**
* Applies {@code procedure} to the keys in the list that are greater than or equal to {@code
* minKey} (inclusive), and less than or equal to {@code maxKey} (inclusive).
*/
public <T extends DoubleProcedure> T forEachInRange(T procedure, double minKey, double maxKey) {
final double[] buffer = keys.buffer;
double k;
for (int i = rank(minKey), size = keys.size(); i < size && (k = buffer[i]) <= maxKey; i++) {
procedure.apply(k);
}
return procedure;
}
/**
* Estimates the allocated memory. It does not count the memory for the list of keys, only for the
* index itself.
*/
@Override
public long ramBytesAllocated() {
// int: size, epsilon, epsilonRecursive
// double: firstKey, lastKey
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ 3 * Integer.BYTES
+ 2L * KEY_SIZE * Integer.BYTES
// + keys.ramBytesAllocated()
+ RamUsageEstimator.shallowSizeOfArray(levelOffsets)
+ RamUsageEstimator.shallowSizeOfArray(segmentData);
}
/**
* Estimates the bytes that are actually used. It does not count the memory for the list of keys,
* only for the index itself.
*/
@Override
public long ramBytesUsed() {
// int: size, epsilon, epsilonRecursive
// double: firstKey, lastKey
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ 3 * Integer.BYTES
+ 2L * KEY_SIZE * Integer.BYTES
// + keys.ramBytesUsed()
+ RamUsageEstimator.shallowSizeOfArray(levelOffsets)
+ RamUsageEstimator.shallowSizeOfArray(segmentData);
}
/**
* Finds the segment responsible for a given key, that is, the rightmost segment having its first
* key <= the searched key.
*
* @return the segment data index; or -1 if none.
*/
private int findSegment(double key) {
assert key >= firstKey && key <= lastKey;
final int epsilonRecursive = this.epsilonRecursive;
final int[] levelOffsets = this.levelOffsets;
final int[] segmentData = this.segmentData;
int level = levelOffsets.length - 1;
int segmentDataIndex = levelOffsets[level] * SEGMENT_DATA_SIZE;
while (--level >= 0) {
int nextIntercept = (int) getIntercept(segmentDataIndex + SEGMENT_DATA_SIZE, segmentData);
int index = Math.min(approximateIndex(key, segmentDataIndex, segmentData), nextIntercept);
assert index >= 0 && index <= levelOffsets[level + 1] - levelOffsets[level] - 1;
int sdIndex = (levelOffsets[level] + index) * SEGMENT_DATA_SIZE;
if (getKey(sdIndex, segmentData) <= key) {
// Scan sequentially segments after the approximated index, within the epsilon range.
final int levelNumSegments = levelOffsets[level + 1] - levelOffsets[level] - 1;
final int toIndex = Math.min(index + epsilonRecursive + 3, levelNumSegments);
while (index++ < toIndex && getKey(sdIndex + SEGMENT_DATA_SIZE, segmentData) <= key) {
sdIndex += SEGMENT_DATA_SIZE;
}
} else {
// Scan sequentially segments before the approximated index, within the epsilon range.
final int fromIndex = Math.max(index - epsilonRecursive - 1, 0);
while (index-- > fromIndex) {
sdIndex -= SEGMENT_DATA_SIZE;
if (getKey(sdIndex, segmentData) <= key) {
break;
}
}
}
segmentDataIndex = sdIndex;
}
assert segmentDataIndex >= 0;
return segmentDataIndex;
}
private int approximateIndex(double key, int segmentDataIndex, int[] segmentData) {
long intercept = getIntercept(segmentDataIndex, segmentData);
double sKey = getKey(segmentDataIndex, segmentData);
double slope = getSlope(segmentDataIndex, segmentData);
int index = (int) (slope * ((double) key - sKey) + intercept);
return Math.max(index, 0);
}
private static long getIntercept(int segmentDataIndex, int[] segmentData) {
return PgmIndexUtil.getIntercept(segmentDataIndex, segmentData, KEY_SIZE);
}
private double getKey(int segmentDataIndex, int[] segmentData) {
return PgmIndexUtil.getKey(segmentDataIndex + KEY_SIZE, segmentData, 0d);
}
private static double getSlope(int segmentDataIndex, int[] segmentData) {
return PgmIndexUtil.getSlope(segmentDataIndex + DOUBLE_KEY_SIZE, segmentData, KEY_SIZE);
}
/** Empty immutable PGM Index. */
private static class DoubleEmptyPgmIndex extends DoublePgmIndex {
private final Iterator<DoubleCursor> emptyIterator = new DoubleEmptyIterator();
@Override
public int indexOf(double key) {
return -1;
}
@Override
public Iterator<DoubleCursor> rangeIterator(double minKey, double maxKey) {
return emptyIterator;
}
@Override
public <T extends DoubleProcedure> T forEachInRange(T procedure, double minKey, double maxKey) {
return procedure;
}
private static class DoubleEmptyIterator extends AbstractIterator<DoubleCursor> {
@Override
protected DoubleCursor fetch() {
return done();
}
}
}
/** Iterator over a range of elements in a sorted array. */
protected static class RangeIterator extends AbstractIterator<DoubleCursor> {
private final double[] buffer;
private final int size;
private final DoubleCursor cursor;
private final double maxKey;
/** Range iterator from {@code fromIndex} (inclusive) to {@code maxKey} (inclusive). */
protected RangeIterator(DoubleArrayList keys, int fromIndex, double maxKey) {
this.buffer = keys.buffer;
this.size = keys.size();
this.cursor = new DoubleCursor();
this.cursor.index = fromIndex;
this.maxKey = maxKey;
}
@Override
protected DoubleCursor fetch() {
if (cursor.index >= size) {
return done();
}
cursor.value = buffer[cursor.index++];
if (cursor.value > maxKey) {
cursor.index = size;
return done();
}
return cursor;
}
}
/** Builds a {@link DoublePgmIndex} on a provided sorted list of keys. */
public static class DoubleBuilder implements PlaModel.SegmentConsumer, Accountable {
protected DoubleArrayList keys;
protected int epsilon = EPSILON;
protected int epsilonRecursive = EPSILON_RECURSIVE;
protected PlaModel plam;
protected int size;
protected IntArrayList segmentData;
protected int numSegments;
/** Sets the sorted list of keys to build the index for; duplicate elements are allowed. */
public DoubleBuilder setSortedKeys(DoubleArrayList keys) {
this.keys = keys;
return this;
}
/** Sets the sorted array of keys to build the index for; duplicate elements are allowed. */
public DoubleBuilder setSortedKeys(double[] keys, int length) {
DoubleArrayList keyList = new DoubleArrayList(0);
keyList.buffer = keys;
keyList.elementsCount = length;
return setSortedKeys(keyList);
}
/** Sets the epsilon range to use when learning the segments for the list of keys. */
public DoubleBuilder setEpsilon(int epsilon) {
if (epsilon <= 0) {
throw new IllegalArgumentException("epsilon must be > 0");
}
this.epsilon = epsilon;
return this;
}
/**
* Sets the recursive epsilon range to use when learning the segments for the segment levels.
*/
public DoubleBuilder setEpsilonRecursive(int epsilonRecursive) {
if (epsilonRecursive <= 0) {
throw new IllegalArgumentException("epsilonRecursive must be > 0");
}
this.epsilonRecursive = epsilonRecursive;
return this;
}
/** Builds the {@link DoublePgmIndex}; or {@link #EMPTY} if there are no keys in the list. */
public DoublePgmIndex build() {
if (keys == null || keys.size() == 0) {
return (DoublePgmIndex) EMPTY;
}
plam = new PlaModel(epsilon);
int segmentsInitialCapacity =
Math.min(
Math.max(keys.size() / (2 * epsilon * epsilon) * SEGMENT_DATA_SIZE, 16), 1 << 19);
segmentData = new IntArrayList(segmentsInitialCapacity);
IntArrayList levelOffsets = new IntArrayList(16);
int levelOffset = 0;
levelOffsets.add(levelOffset);
int levelNumSegments = buildFirstLevel();
while (levelNumSegments > 1) {
int nextLevelOffset = numSegments;
levelOffsets.add(nextLevelOffset);
levelNumSegments = buildUpperLevel(levelOffset, levelNumSegments);
levelOffset = nextLevelOffset;
}
int[] segmentDataFinal = segmentData.toArray();
int[] levelOffsetsFinal = levelOffsets.toArray();
return new DoublePgmIndex(
keys, size, epsilon, epsilonRecursive, levelOffsetsFinal, segmentDataFinal);
}
private int buildFirstLevel() {
assert numSegments == 0;
int numKeys = keys.size();
int size = 0;
double key = keys.get(0);
size++;
plam.addKey(key, 0, this);
for (int i = 1; i < numKeys; i++) {
double nextKey = keys.get(i);
if (!(Double.doubleToLongBits(nextKey) == Double.doubleToLongBits(key))) {
key = nextKey;
plam.addKey(key, i, this);
size++;
}
}
plam.finish(this);
addSentinelSegment(numKeys);
this.size = size;
return numSegments - 1;
}
private int buildUpperLevel(int levelOffset, int levelNumSegments) {
plam.setEpsilon(epsilonRecursive);
assert numSegments > 0;
int initialNumSegments = numSegments;
int segmentDataIndex = levelOffset * SEGMENT_DATA_SIZE;
double key = getKey(segmentDataIndex, segmentData.buffer);
plam.addKey(key, 0, this);
for (int i = 1; i < levelNumSegments; i++) {
segmentDataIndex += SEGMENT_DATA_SIZE;
double nextKey = getKey(segmentDataIndex, segmentData.buffer);
if (!(Double.doubleToLongBits(nextKey) == Double.doubleToLongBits(key))) {
key = nextKey;
plam.addKey(key, i, this);
}
}
plam.finish(this);
addSentinelSegment(levelNumSegments);
return numSegments - initialNumSegments - 1;
}
private double getKey(int segmentDataIndex, int[] segmentData) {
return PgmIndexUtil.getKey(segmentDataIndex + KEY_SIZE, segmentData, 0d);
}
/**
* Adds a sentinel segment that is used to give a limit for the position approximation, but does
* not count in the number of segments per level.
*/
private void addSentinelSegment(int endIndex) {
// This sentinel segment is used in findSegment().
accept(Double.MAX_VALUE, 0d, endIndex);
}
@Override
public void accept(double firstKey, double slope, long intercept) {
PgmIndexUtil.addIntercept(intercept, segmentData, KEY_SIZE);
PgmIndexUtil.addKey((double) firstKey, segmentData);
PgmIndexUtil.addSlope(slope, segmentData, KEY_SIZE);
numSegments++;
assert segmentData.size() == numSegments * SEGMENT_DATA_SIZE;
}
/**
* Estimates the allocated memory. It does not count the memory for the list of keys, only for
* the builder itself.
*/
@Override
public long ramBytesAllocated() {
// int: epsilon, epsilonRecursive, size, numSegments
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ 4 * Integer.BYTES
// + keys.ramBytesAllocated()
+ plam.ramBytesAllocated()
+ segmentData.ramBytesAllocated();
}
/**
* Estimates the bytes that are actually used. It does not count the memory for the list of
* keys, only for the builder itself.
*/
@Override
public long ramBytesUsed() {
// int: epsilon, epsilonRecursive, size, numSegments
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ 4 * Integer.BYTES
// + keys.ramBytesUsed()
+ plam.ramBytesUsed()
+ segmentData.ramBytesUsed();
}
}
}

View File

@ -0,0 +1,137 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.DoubleCursor;
/**
* A subclass of {@link DoubleArrayList} adding stack-related utility methods. The top of the stack
* is at the <code>{@link #size()} - 1</code> element.
*/
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeStack.java")
public class DoubleStack extends DoubleArrayList {
/** New instance with sane defaults. */
public DoubleStack() {
super();
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
*/
public DoubleStack(int expectedElements) {
super(expectedElements);
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
* @param resizer Underlying buffer sizing strategy.
*/
public DoubleStack(int expectedElements, ArraySizingStrategy resizer) {
super(expectedElements, resizer);
}
/** Create a stack by pushing all elements of another container to it. */
public DoubleStack(DoubleContainer container) {
super(container);
}
/** Adds one double to the stack. */
public void push(double e1) {
ensureBufferSpace(1);
buffer[elementsCount++] = e1;
}
/** Adds two doubles to the stack. */
public void push(double e1, double e2) {
ensureBufferSpace(2);
buffer[elementsCount++] = e1;
buffer[elementsCount++] = e2;
}
/** Adds three doubles to the stack. */
public void push(double e1, double e2, double e3) {
ensureBufferSpace(3);
buffer[elementsCount++] = e1;
buffer[elementsCount++] = e2;
buffer[elementsCount++] = e3;
}
/** Adds four doubles to the stack. */
public void push(double e1, double e2, double e3, double e4) {
ensureBufferSpace(4);
buffer[elementsCount++] = e1;
buffer[elementsCount++] = e2;
buffer[elementsCount++] = e3;
buffer[elementsCount++] = e4;
}
/** Add a range of array elements to the stack. */
public void push(double[] elements, int start, int len) {
assert start >= 0 && len >= 0;
ensureBufferSpace(len);
System.arraycopy(elements, start, buffer, elementsCount, len);
elementsCount += len;
}
/**
* Vararg-signature method for pushing elements at the top of the stack.
*
* <p><b>This method is handy, but costly if used in tight loops (anonymous array passing)</b>
*/
public final void push(double... elements) {
push(elements, 0, elements.length);
}
/** Pushes all elements from another container to the top of the stack. */
public int pushAll(DoubleContainer container) {
return addAll(container);
}
/** Pushes all elements from another iterable to the top of the stack. */
public int pushAll(Iterable<? extends DoubleCursor> iterable) {
return addAll(iterable);
}
/** Discard an arbitrary number of elements from the top of the stack. */
public void discard(int count) {
assert elementsCount >= count;
elementsCount -= count;
}
/** Discard the top element from the stack. */
public void discard() {
assert elementsCount > 0;
elementsCount--;
}
/** Remove the top element from the stack and return it. */
public double pop() {
return removeLast();
}
/** Peek at the top element on the stack. */
public double peek() {
assert elementsCount > 0;
return buffer[elementsCount - 1];
}
/** Create a stack by pushing a variable number of arguments to it. */
public static DoubleStack from(double... elements) {
final DoubleStack stack = new DoubleStack(elements.length);
stack.push(elements);
return stack;
}
/** {@inheritDoc} */
@Override
public DoubleStack clone() {
return (DoubleStack) super.clone();
}
}

View File

@ -0,0 +1,776 @@
package com.carrotsearch.hppc;
import static com.carrotsearch.hppc.Containers.*;
import com.carrotsearch.hppc.cursors.FloatCursor;
import com.carrotsearch.hppc.predicates.FloatPredicate;
import com.carrotsearch.hppc.procedures.FloatProcedure;
import java.util.*;
/** An array-backed {@link FloatDeque}. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayDeque.java")
public class FloatArrayDeque extends AbstractFloatCollection
implements FloatDeque, Preallocable, Cloneable, Accountable {
/** Reuse the same strategy instance. */
private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY =
BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE;
/** Internal array for storing elements of the deque. */
public float[] buffer = FloatArrayList.EMPTY_ARRAY;
/**
* The index of the element at the head of the deque or an arbitrary number equal to tail if the
* deque is empty.
*/
public int head;
/** The index at which the next element would be added to the tail of the deque. */
public int tail;
/** Buffer resizing strategy. */
protected final ArraySizingStrategy resizer;
/** New instance with sane defaults. */
public FloatArrayDeque() {
this(DEFAULT_EXPECTED_ELEMENTS);
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
*/
public FloatArrayDeque(int expectedElements) {
this(expectedElements, DEFAULT_SIZING_STRATEGY);
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
* @param resizer Underlying buffer sizing strategy.
*/
public FloatArrayDeque(int expectedElements, ArraySizingStrategy resizer) {
assert resizer != null;
this.resizer = resizer;
ensureCapacity(expectedElements);
}
/**
* Creates a new deque from elements of another container, appending elements at the end of the
* deque in the iteration order.
*/
public FloatArrayDeque(FloatContainer container) {
this(container.size());
addLast(container);
}
/** {@inheritDoc} */
@Override
public void addFirst(float e1) {
int h = oneLeft(head, buffer.length);
if (h == tail) {
ensureBufferSpace(1);
h = oneLeft(head, buffer.length);
}
buffer[head = h] = e1;
}
/**
* Vararg-signature method for adding elements at the front of this deque.
*
* <p><b>This method is handy, but costly if used in tight loops (anonymous array passing)</b>
*
* @param elements The elements to add.
*/
public final void addFirst(float... elements) {
ensureBufferSpace(elements.length);
for (float k : elements) {
addFirst(k);
}
}
/**
* Inserts all elements from the given container to the front of this deque.
*
* @param container The container to iterate over.
* @return Returns the number of elements actually added as a result of this call.
*/
public int addFirst(FloatContainer container) {
int size = container.size();
ensureBufferSpace(size);
for (FloatCursor cursor : container) {
addFirst(cursor.value);
}
return size;
}
/**
* Inserts all elements from the given iterable to the front of this deque.
*
* @param iterable The iterable to iterate over.
* @return Returns the number of elements actually added as a result of this call.
*/
public int addFirst(Iterable<? extends FloatCursor> iterable) {
int size = 0;
for (FloatCursor cursor : iterable) {
addFirst(cursor.value);
size++;
}
return size;
}
/** {@inheritDoc} */
@Override
public void addLast(float e1) {
int t = oneRight(tail, buffer.length);
if (head == t) {
ensureBufferSpace(1);
t = oneRight(tail, buffer.length);
}
buffer[tail] = e1;
tail = t;
}
/**
* Vararg-signature method for adding elements at the end of this deque.
*
* <p><b>This method is handy, but costly if used in tight loops (anonymous array passing)</b>
*
* @param elements The elements to iterate over.
*/
public final void addLast(float... elements) {
ensureBufferSpace(1);
for (float k : elements) {
addLast(k);
}
}
/**
* Inserts all elements from the given container to the end of this deque.
*
* @param container The container to iterate over.
* @return Returns the number of elements actually added as a result of this call.
*/
public int addLast(FloatContainer container) {
int size = container.size();
ensureBufferSpace(size);
for (FloatCursor cursor : container) {
addLast(cursor.value);
}
return size;
}
/**
* Inserts all elements from the given iterable to the end of this deque.
*
* @param iterable The iterable to iterate over.
* @return Returns the number of elements actually added as a result of this call.
*/
public int addLast(Iterable<? extends FloatCursor> iterable) {
int size = 0;
for (FloatCursor cursor : iterable) {
addLast(cursor.value);
size++;
}
return size;
}
/** {@inheritDoc} */
@Override
public float removeFirst() {
assert size() > 0 : "The deque is empty.";
final float result = buffer[head];
buffer[head] = 0f;
head = oneRight(head, buffer.length);
return result;
}
/** {@inheritDoc} */
@Override
public float removeLast() {
assert size() > 0 : "The deque is empty.";
tail = oneLeft(tail, buffer.length);
final float result = buffer[tail];
buffer[tail] = 0f;
return result;
}
/** {@inheritDoc} */
@Override
public float getFirst() {
assert size() > 0 : "The deque is empty.";
return buffer[head];
}
/** {@inheritDoc} */
@Override
public float getLast() {
assert size() > 0 : "The deque is empty.";
return buffer[oneLeft(tail, buffer.length)];
}
/** {@inheritDoc} */
@Override
public int removeFirst(float e1) {
final int index = bufferIndexOf(e1);
if (index >= 0) removeAtBufferIndex(index);
return index;
}
/**
* Return the index of the first (counting from head) element equal to <code>e1</code>. The index
* points to the {@link #buffer} array.
*
* @param e1 The element to look for.
* @return Returns the index of the first element equal to <code>e1</code> or <code>-1</code> if
* not found.
*/
public int bufferIndexOf(float e1) {
final int last = tail;
final int bufLen = buffer.length;
for (int i = head; i != last; i = oneRight(i, bufLen)) {
if ((Float.floatToIntBits(e1) == Float.floatToIntBits(buffer[i]))) {
return i;
}
}
return -1;
}
/** {@inheritDoc} */
@Override
public int removeLast(float e1) {
final int index = lastBufferIndexOf(e1);
if (index >= 0) {
removeAtBufferIndex(index);
}
return index;
}
/**
* Return the index of the last (counting from tail) element equal to <code>e1</code>. The index
* points to the {@link #buffer} array.
*
* @param e1 The element to look for.
* @return Returns the index of the first element equal to <code>e1</code> or <code>-1</code> if
* not found.
*/
public int lastBufferIndexOf(float e1) {
final int bufLen = buffer.length;
final int last = oneLeft(head, bufLen);
for (int i = oneLeft(tail, bufLen); i != last; i = oneLeft(i, bufLen)) {
if ((Float.floatToIntBits(e1) == Float.floatToIntBits(buffer[i]))) return i;
}
return -1;
}
/** {@inheritDoc} */
@Override
public int removeAll(float e1) {
int removed = 0;
final int last = tail;
final int bufLen = buffer.length;
int from, to;
for (from = to = head; from != last; from = oneRight(from, bufLen)) {
if ((Float.floatToIntBits(e1) == Float.floatToIntBits(buffer[from]))) {
buffer[from] = 0f;
removed++;
continue;
}
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = 0f;
}
to = oneRight(to, bufLen);
}
tail = to;
return removed;
}
/**
* Removes the element at <code>index</code> in the internal {#link {@link #buffer} array,
* returning its value.
*
* @param index Index of the element to remove. The index must be located between {@link #head}
* and {@link #tail} in modulo {@link #buffer} arithmetic.
*/
public void removeAtBufferIndex(int index) {
assert (head <= tail ? index >= head && index < tail : index >= head || index < tail)
: "Index out of range (head=" + head + ", tail=" + tail + ", index=" + index + ").";
// Cache fields in locals (hopefully moved to registers).
final float[] buffer = this.buffer;
final int bufLen = buffer.length;
final int lastIndex = bufLen - 1;
final int head = this.head;
final int tail = this.tail;
final int leftChunk = Math.abs(index - head) % bufLen;
final int rightChunk = Math.abs(tail - index) % bufLen;
if (leftChunk < rightChunk) {
if (index >= head) {
System.arraycopy(buffer, head, buffer, head + 1, leftChunk);
} else {
System.arraycopy(buffer, 0, buffer, 1, index);
buffer[0] = buffer[lastIndex];
System.arraycopy(buffer, head, buffer, head + 1, lastIndex - head);
}
buffer[head] = 0f;
this.head = oneRight(head, bufLen);
} else {
if (index < tail) {
System.arraycopy(buffer, index + 1, buffer, index, rightChunk);
} else {
System.arraycopy(buffer, index + 1, buffer, index, lastIndex - index);
buffer[lastIndex] = buffer[0];
System.arraycopy(buffer, 1, buffer, 0, tail);
}
buffer[tail] = 0f;
this.tail = oneLeft(tail, bufLen);
}
}
/** {@inheritDoc} */
@Override
public boolean isEmpty() {
return size() == 0;
}
/** {@inheritDoc} */
@Override
public int size() {
if (head <= tail) return tail - head;
else return (tail - head + buffer.length);
}
/**
* {@inheritDoc}
*
* <p>The internal array buffers are not released as a result of this call.
*
* @see #release()
*/
@Override
public void clear() {
if (head < tail) {
Arrays.fill(buffer, head, tail, 0f);
} else {
Arrays.fill(buffer, 0, tail, 0f);
Arrays.fill(buffer, head, buffer.length, 0f);
}
this.head = tail = 0;
}
/** Release internal buffers of this deque and reallocate with the default buffer. */
public void release() {
this.head = tail = 0;
buffer = FloatArrayList.EMPTY_ARRAY;
ensureBufferSpace(0);
}
/**
* Ensure this container can hold at least the given number of elements without resizing its
* buffers.
*
* @param expectedElements The total number of elements, inclusive.
*/
@Override
public void ensureCapacity(int expectedElements) {
ensureBufferSpace(expectedElements - size());
}
/**
* Ensures the internal buffer has enough free slots to store <code>expectedAdditions</code>.
* Increases internal buffer size if needed.
*/
protected void ensureBufferSpace(int expectedAdditions) {
final int bufferLen = buffer.length;
final int elementsCount = size();
if (elementsCount + expectedAdditions >= bufferLen) {
final int emptySlot = 1; // deque invariant: always an empty slot.
final int newSize = resizer.grow(bufferLen, elementsCount + emptySlot, expectedAdditions);
assert newSize >= (elementsCount + expectedAdditions + emptySlot)
: "Resizer failed to"
+ " return sensible new size: "
+ newSize
+ " <= "
+ (elementsCount + expectedAdditions);
try {
final float[] newBuffer = (new float[newSize]);
if (bufferLen > 0) {
toArray(newBuffer);
tail = elementsCount;
head = 0;
}
this.buffer = newBuffer;
} catch (OutOfMemoryError e) {
throw new BufferAllocationException(
"Not enough memory to allocate new buffers: %,d -> %,d", e, bufferLen, newSize);
}
}
}
/** {@inheritDoc} */
@Override
public float[] toArray() {
final int size = size();
return toArray((new float[size]));
}
/**
* Copies elements of this deque to an array. The content of the <code>target</code> array is
* filled from index 0 (head of the queue) to index <code>size() - 1</code> (tail of the queue).
*
* @param target The target array must be large enough to hold all elements.
* @return Returns the target argument for chaining.
*/
public float[] toArray(float[] target) {
assert target.length >= size() : "Target array must be >= " + size();
if (head < tail) {
// The contents is not wrapped around. Just copy.
System.arraycopy(buffer, head, target, 0, size());
} else if (head > tail) {
// The contents is split. Merge elements from the following indexes:
// [head...buffer.length - 1][0, tail - 1]
final int rightCount = buffer.length - head;
System.arraycopy(buffer, head, target, 0, rightCount);
System.arraycopy(buffer, 0, target, rightCount, tail);
}
return target;
}
/**
* Clone this object. The returned clone will reuse the same hash function and array resizing
* strategy.
*/
@Override
public FloatArrayDeque clone() {
try {
FloatArrayDeque cloned = (FloatArrayDeque) super.clone();
cloned.buffer = buffer.clone();
return cloned;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
/** Move one index to the left, wrapping around buffer. */
protected static int oneLeft(int index, int modulus) {
if (index >= 1) {
return index - 1;
}
return modulus - 1;
}
/** Move one index to the right, wrapping around buffer. */
protected static int oneRight(int index, int modulus) {
if (index + 1 == modulus) {
return 0;
}
return index + 1;
}
@Override
public long ramBytesAllocated() {
// int: head, tail
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ Integer.BYTES * 2
+ resizer.ramBytesAllocated()
+ RamUsageEstimator.shallowSizeOfArray(buffer);
}
@Override
public long ramBytesUsed() {
// int: head, tail
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ Integer.BYTES * 2
+ resizer.ramBytesUsed()
+ RamUsageEstimator.shallowUsedSizeOfArray(buffer, size());
}
/** An iterator implementation for {@link ObjectArrayDeque#iterator}. */
private final class ValueIterator extends AbstractIterator<FloatCursor> {
private final FloatCursor cursor;
private int remaining;
public ValueIterator() {
cursor = new FloatCursor();
cursor.index = oneLeft(head, buffer.length);
this.remaining = size();
}
@Override
protected FloatCursor fetch() {
if (remaining == 0) {
return done();
}
remaining--;
cursor.value = buffer[cursor.index = oneRight(cursor.index, buffer.length)];
return cursor;
}
}
/** An iterator implementation for {@link ObjectArrayDeque#descendingIterator()}. */
private final class DescendingValueIterator extends AbstractIterator<FloatCursor> {
private final FloatCursor cursor;
private int remaining;
public DescendingValueIterator() {
cursor = new FloatCursor();
cursor.index = tail;
this.remaining = size();
}
@Override
protected FloatCursor fetch() {
if (remaining == 0) return done();
remaining--;
cursor.value = buffer[cursor.index = oneLeft(cursor.index, buffer.length)];
return cursor;
}
}
/**
* Returns a cursor over the values of this deque (in head to tail order). The iterator is
* implemented as a cursor and it returns <b>the same cursor instance</b> on every call to {@link
* Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in
* the deque's buffer) use the cursor's public fields. An example is shown below.
*
* <pre>
* for (IntValueCursor c : intDeque) {
* System.out.println(&quot;buffer index=&quot; + c.index + &quot; value=&quot; + c.value);
* }
* </pre>
*/
public Iterator<FloatCursor> iterator() {
return new ValueIterator();
}
/**
* Returns a cursor over the values of this deque (in tail to head order). The iterator is
* implemented as a cursor and it returns <b>the same cursor instance</b> on every call to {@link
* Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in
* the deque's buffer) use the cursor's public fields. An example is shown below.
*
* <pre>
* for (Iterator&lt;IntCursor&gt; i = intDeque.descendingIterator(); i.hasNext();) {
* final IntCursor c = i.next();
* System.out.println(&quot;buffer index=&quot; + c.index + &quot; value=&quot; + c.value);
* }
* </pre>
*/
public Iterator<FloatCursor> descendingIterator() {
return new DescendingValueIterator();
}
/** {@inheritDoc} */
@Override
public <T extends FloatProcedure> T forEach(T procedure) {
forEach(procedure, head, tail);
return procedure;
}
/**
* Applies <code>procedure</code> to a slice of the deque, <code>fromIndex</code>, inclusive, to
* <code>toIndex</code>, exclusive.
*/
private void forEach(FloatProcedure procedure, int fromIndex, final int toIndex) {
final float[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
procedure.apply(buffer[i]);
}
}
/** {@inheritDoc} */
@Override
public <T extends FloatPredicate> T forEach(T predicate) {
int fromIndex = head;
int toIndex = tail;
final float[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
if (!predicate.apply(buffer[i])) {
break;
}
}
return predicate;
}
/** Applies <code>procedure</code> to all elements of this deque, tail to head. */
@Override
public <T extends FloatProcedure> T descendingForEach(T procedure) {
descendingForEach(procedure, head, tail);
return procedure;
}
/**
* Applies <code>procedure</code> to a slice of the deque, <code>toIndex</code>, exclusive, down
* to <code>fromIndex</code>, inclusive.
*/
private void descendingForEach(FloatProcedure procedure, int fromIndex, final int toIndex) {
if (fromIndex == toIndex) return;
final float[] buffer = this.buffer;
int i = toIndex;
do {
i = oneLeft(i, buffer.length);
procedure.apply(buffer[i]);
} while (i != fromIndex);
}
/** {@inheritDoc} */
@Override
public <T extends FloatPredicate> T descendingForEach(T predicate) {
descendingForEach(predicate, head, tail);
return predicate;
}
/**
* Applies <code>predicate</code> to a slice of the deque, <code>toIndex</code>, exclusive, down
* to <code>fromIndex</code>, inclusive or until the predicate returns <code>false</code>.
*/
private void descendingForEach(FloatPredicate predicate, int fromIndex, final int toIndex) {
if (fromIndex == toIndex) return;
final float[] buffer = this.buffer;
int i = toIndex;
do {
i = oneLeft(i, buffer.length);
if (!predicate.apply(buffer[i])) {
break;
}
} while (i != fromIndex);
}
/** {@inheritDoc} */
@Override
public int removeAll(FloatPredicate predicate) {
final float[] buffer = this.buffer;
final int last = tail;
final int bufLen = buffer.length;
int removed = 0;
int from, to;
from = to = head;
try {
for (from = to = head; from != last; from = oneRight(from, bufLen)) {
if (predicate.apply(buffer[from])) {
buffer[from] = 0f;
removed++;
continue;
}
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = 0f;
}
to = oneRight(to, bufLen);
}
} finally {
// Keep the deque in consistent state even if the predicate throws an exception.
for (; from != last; from = oneRight(from, bufLen)) {
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = 0f;
}
to = oneRight(to, bufLen);
}
tail = to;
}
return removed;
}
/** {@inheritDoc} */
@Override
public boolean contains(float e) {
int fromIndex = head;
int toIndex = tail;
final float[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
if ((Float.floatToIntBits(e) == Float.floatToIntBits(buffer[i]))) {
return true;
}
}
return false;
}
/** {@inheritDoc} */
@Override
public int hashCode() {
int h = 1;
int fromIndex = head;
int toIndex = tail;
final float[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
h = 31 * h + BitMixer.mix(this.buffer[i]);
}
return h;
}
/**
* Returns <code>true</code> only if the other object is an instance of the same class and with
* the same elements.
*/
@Override
public boolean equals(Object obj) {
return (this == obj)
|| (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj)));
}
/** Compare order-aligned elements against another {@link FloatDeque}. */
protected boolean equalElements(FloatArrayDeque other) {
int max = size();
if (other.size() != max) {
return false;
}
Iterator<FloatCursor> i1 = this.iterator();
Iterator<? extends FloatCursor> i2 = other.iterator();
while (i1.hasNext() && i2.hasNext()) {
if (!(Float.floatToIntBits(i1.next().value) == Float.floatToIntBits(i2.next().value))) {
return false;
}
}
return !i1.hasNext() && !i2.hasNext();
}
/** Create a new deque by pushing a variable number of arguments to the end of it. */
public static FloatArrayDeque from(float... elements) {
final FloatArrayDeque coll = new FloatArrayDeque(elements.length);
coll.addLast(elements);
return coll;
}
}

View File

@ -0,0 +1,579 @@
package com.carrotsearch.hppc;
import static com.carrotsearch.hppc.Containers.*;
import com.carrotsearch.hppc.cursors.*;
import com.carrotsearch.hppc.predicates.FloatPredicate;
import com.carrotsearch.hppc.procedures.*;
import java.util.*;
/** An array-backed list of floats. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayList.java")
public class FloatArrayList extends AbstractFloatCollection
implements FloatIndexedContainer, Preallocable, Cloneable, Accountable {
/** An immutable empty buffer (array). */
public static final float[] EMPTY_ARRAY = new float[0];
;
/** Reuse the same strategy instance. */
private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY =
BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE;
/**
* Internal array for storing the list. The array may be larger than the current size ({@link
* #size()}).
*/
public float[] buffer = EMPTY_ARRAY;
/** Current number of elements stored in {@link #buffer}. */
public int elementsCount;
/** Buffer resizing strategy. */
protected final ArraySizingStrategy resizer;
/** New instance with sane defaults. */
public FloatArrayList() {
this(DEFAULT_EXPECTED_ELEMENTS);
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
*/
public FloatArrayList(int expectedElements) {
this(expectedElements, DEFAULT_SIZING_STRATEGY);
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
* @param resizer Underlying buffer sizing strategy.
*/
public FloatArrayList(int expectedElements, ArraySizingStrategy resizer) {
assert resizer != null;
this.resizer = resizer;
buffer = Arrays.copyOf(buffer, expectedElements);
}
/** Creates a new list from the elements of another container in its iteration order. */
public FloatArrayList(FloatContainer container) {
this(container.size());
addAll(container);
}
/** {@inheritDoc} */
@Override
public void add(float e1) {
ensureBufferSpace(1);
buffer[elementsCount++] = e1;
}
/**
* Appends two elements at the end of the list. To add more than two elements, use <code>add
* </code> (vararg-version) or access the buffer directly (tight loop).
*/
public void add(float e1, float e2) {
ensureBufferSpace(2);
buffer[elementsCount++] = e1;
buffer[elementsCount++] = e2;
}
/** Add all elements from a range of given array to the list. */
public void add(float[] elements, int start, int length) {
assert length >= 0 : "Length must be >= 0";
ensureBufferSpace(length);
System.arraycopy(elements, start, buffer, elementsCount, length);
elementsCount += length;
}
/**
* Vararg-signature method for adding elements at the end of the list.
*
* <p><b>This method is handy, but costly if used in tight loops (anonymous array passing)</b>
*/
public final void add(float... elements) {
add(elements, 0, elements.length);
}
/** Adds all elements from another container. */
public int addAll(FloatContainer container) {
final int size = container.size();
ensureBufferSpace(size);
for (FloatCursor cursor : container) {
add(cursor.value);
}
return size;
}
/** Adds all elements from another iterable. */
public int addAll(Iterable<? extends FloatCursor> iterable) {
int size = 0;
for (FloatCursor cursor : iterable) {
add(cursor.value);
size++;
}
return size;
}
/** {@inheritDoc} */
@Override
public void insert(int index, float e1) {
assert (index >= 0 && index <= size())
: "Index " + index + " out of bounds [" + 0 + ", " + size() + "].";
ensureBufferSpace(1);
System.arraycopy(buffer, index, buffer, index + 1, elementsCount - index);
buffer[index] = e1;
elementsCount++;
}
/** {@inheritDoc} */
@Override
public float get(int index) {
assert (index >= 0 && index < size())
: "Index " + index + " out of bounds [" + 0 + ", " + size() + ").";
return buffer[index];
}
/** {@inheritDoc} */
@Override
public float set(int index, float e1) {
assert (index >= 0 && index < size())
: "Index " + index + " out of bounds [" + 0 + ", " + size() + ").";
final float v = buffer[index];
buffer[index] = e1;
return v;
}
/** {@inheritDoc} */
@Override
public float removeAt(int index) {
assert (index >= 0 && index < size())
: "Index " + index + " out of bounds [" + 0 + ", " + size() + ").";
final float v = buffer[index];
System.arraycopy(buffer, index + 1, buffer, index, --elementsCount - index);
return v;
}
/** {@inheritDoc} */
@Override
public float removeLast() {
assert elementsCount > 0;
final float v = buffer[--elementsCount];
return v;
}
/** {@inheritDoc} */
@Override
public void removeRange(int fromIndex, int toIndex) {
assert (fromIndex >= 0 && fromIndex <= size())
: "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ").";
assert (toIndex >= 0 && toIndex <= size())
: "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "].";
assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex;
System.arraycopy(buffer, toIndex, buffer, fromIndex, elementsCount - toIndex);
final int count = toIndex - fromIndex;
elementsCount -= count;
}
/** {@inheritDoc} */
@Override
public boolean removeElement(float e1) {
return removeFirst(e1) != -1;
}
/** {@inheritDoc} */
@Override
public int removeFirst(float e1) {
final int index = indexOf(e1);
if (index >= 0) removeAt(index);
return index;
}
/** {@inheritDoc} */
@Override
public int removeLast(float e1) {
final int index = lastIndexOf(e1);
if (index >= 0) removeAt(index);
return index;
}
/** {@inheritDoc} */
@Override
public int removeAll(float e1) {
int to = 0;
for (int from = 0; from < elementsCount; from++) {
if ((Float.floatToIntBits(e1) == Float.floatToIntBits(buffer[from]))) {
continue;
}
if (to != from) {
buffer[to] = buffer[from];
}
to++;
}
final int deleted = elementsCount - to;
this.elementsCount = to;
return deleted;
}
/** {@inheritDoc} */
@Override
public boolean contains(float e1) {
return indexOf(e1) >= 0;
}
/** {@inheritDoc} */
@Override
public int indexOf(float e1) {
for (int i = 0; i < elementsCount; i++) {
if ((Float.floatToIntBits(e1) == Float.floatToIntBits(buffer[i]))) {
return i;
}
}
return -1;
}
/** {@inheritDoc} */
@Override
public int lastIndexOf(float e1) {
for (int i = elementsCount - 1; i >= 0; i--) {
if ((Float.floatToIntBits(e1) == Float.floatToIntBits(buffer[i]))) {
return i;
}
}
return -1;
}
/** {@inheritDoc} */
@Override
public boolean isEmpty() {
return elementsCount == 0;
}
/**
* Ensure this container can hold at least the given number of elements without resizing its
* buffers.
*
* @param expectedElements The total number of elements, inclusive.
*/
@Override
public void ensureCapacity(int expectedElements) {
final int bufferLen = (buffer == null ? 0 : buffer.length);
if (expectedElements > bufferLen) {
ensureBufferSpace(expectedElements - size());
}
}
/**
* Ensures the internal buffer has enough free slots to store <code>expectedAdditions</code>.
* Increases internal buffer size if needed.
*/
protected void ensureBufferSpace(int expectedAdditions) {
final int bufferLen = (buffer == null ? 0 : buffer.length);
if (elementsCount + expectedAdditions > bufferLen) {
final int newSize = resizer.grow(bufferLen, elementsCount, expectedAdditions);
assert newSize >= elementsCount + expectedAdditions
: "Resizer failed to"
+ " return sensible new size: "
+ newSize
+ " <= "
+ (elementsCount + expectedAdditions);
this.buffer = Arrays.copyOf(buffer, newSize);
}
}
/**
* Truncate or expand the list to the new size. If the list is truncated, the buffer will not be
* reallocated (use {@link #trimToSize()} if you need a truncated buffer), but the truncated
* values will be reset to the default value (zero). If the list is expanded, the elements beyond
* the current size are initialized with JVM-defaults (zero or <code>null</code> values).
*/
public void resize(int newSize) {
if (newSize <= buffer.length) {
if (newSize < elementsCount) {
Arrays.fill(buffer, newSize, elementsCount, 0f);
} else {
Arrays.fill(buffer, elementsCount, newSize, 0f);
}
} else {
ensureCapacity(newSize);
}
this.elementsCount = newSize;
}
/** {@inheritDoc} */
@Override
public int size() {
return elementsCount;
}
/** Trim the internal buffer to the current size. */
public void trimToSize() {
if (size() != this.buffer.length) {
this.buffer = toArray();
}
}
/**
* Sets the number of stored elements to zero. Releases and initializes the internal storage array
* to default values. To clear the list without cleaning the buffer, simply set the {@link
* #elementsCount} field to zero.
*/
@Override
public void clear() {
Arrays.fill(buffer, 0, elementsCount, 0f);
this.elementsCount = 0;
}
/** Sets the number of stored elements to zero and releases the internal storage array. */
@Override
public void release() {
this.buffer = EMPTY_ARRAY;
this.elementsCount = 0;
}
/**
* {@inheritDoc}
*
* <p>The returned array is sized to match exactly the number of elements of the stack.
*/
@Override
public float[] toArray() {
return Arrays.copyOf(buffer, elementsCount);
}
/** {@inheritDoc} */
@Override
public FloatIndexedContainer sort() {
Arrays.sort(buffer, 0, elementsCount);
return this;
}
/** {@inheritDoc} */
@Override
public FloatIndexedContainer reverse() {
for (int i = 0, mid = elementsCount >> 1, j = elementsCount - 1; i < mid; i++, j--) {
float tmp = buffer[i];
buffer[i] = buffer[j];
buffer[j] = tmp;
}
return this;
}
/**
* Clone this object. The returned clone will reuse the same hash function and array resizing
* strategy.
*/
@Override
public FloatArrayList clone() {
try {
final FloatArrayList cloned = (FloatArrayList) super.clone();
cloned.buffer = buffer.clone();
return cloned;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
/** {@inheritDoc} */
@Override
public int hashCode() {
int h = 1, max = elementsCount;
for (int i = 0; i < max; i++) {
h = 31 * h + BitMixer.mix(this.buffer[i]);
}
return h;
}
/**
* Returns <code>true</code> only if the other object is an instance of the same class and with
* the same elements.
*/
@Override
public boolean equals(Object obj) {
return (this == obj)
|| (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj)));
}
/** Compare index-aligned elements against another {@link FloatIndexedContainer}. */
protected boolean equalElements(FloatArrayList other) {
int max = size();
if (other.size() != max) {
return false;
}
for (int i = 0; i < max; i++) {
if (!(Float.floatToIntBits(get(i)) == Float.floatToIntBits(other.get(i)))) {
return false;
}
}
return true;
}
@Override
public long ramBytesAllocated() {
// int: elementsCount
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ Integer.BYTES
+ resizer.ramBytesAllocated()
+ RamUsageEstimator.shallowSizeOfArray(buffer);
}
@Override
public long ramBytesUsed() {
// int: elementsCount
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ Integer.BYTES
+ resizer.ramBytesUsed()
+ RamUsageEstimator.shallowUsedSizeOfArray(buffer, elementsCount);
}
/** An iterator implementation for {@link FloatArrayList#iterator}. */
static final class ValueIterator extends AbstractIterator<FloatCursor> {
private final FloatCursor cursor;
private final float[] buffer;
private final int size;
public ValueIterator(float[] buffer, int size) {
this.cursor = new FloatCursor();
this.cursor.index = -1;
this.size = size;
this.buffer = buffer;
}
@Override
protected FloatCursor fetch() {
if (cursor.index + 1 == size) return done();
cursor.value = buffer[++cursor.index];
return cursor;
}
}
/** {@inheritDoc} */
@Override
public Iterator<FloatCursor> iterator() {
return new ValueIterator(buffer, size());
}
/** {@inheritDoc} */
@Override
public <T extends FloatProcedure> T forEach(T procedure) {
return forEach(procedure, 0, size());
}
/**
* Applies <code>procedure</code> to a slice of the list, <code>fromIndex</code>, inclusive, to
* <code>toIndex</code>, exclusive.
*/
public <T extends FloatProcedure> T forEach(T procedure, int fromIndex, final int toIndex) {
assert (fromIndex >= 0 && fromIndex <= size())
: "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ").";
assert (toIndex >= 0 && toIndex <= size())
: "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "].";
assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex;
final float[] buffer = this.buffer;
for (int i = fromIndex; i < toIndex; i++) {
procedure.apply(buffer[i]);
}
return procedure;
}
/** {@inheritDoc} */
@Override
public int removeAll(FloatPredicate predicate) {
final float[] buffer = this.buffer;
final int elementsCount = this.elementsCount;
int to = 0;
int from = 0;
try {
for (; from < elementsCount; from++) {
if (predicate.apply(buffer[from])) {
buffer[from] = 0f;
continue;
}
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = 0f;
}
to++;
}
} finally {
// Keep the list in a consistent state, even if the predicate throws an exception.
for (; from < elementsCount; from++) {
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = 0f;
}
to++;
}
this.elementsCount = to;
}
return elementsCount - to;
}
/** {@inheritDoc} */
@Override
public <T extends FloatPredicate> T forEach(T predicate) {
return forEach(predicate, 0, size());
}
/**
* Applies <code>predicate</code> to a slice of the list, <code>fromIndex</code>, inclusive, to
* <code>toIndex</code>, exclusive, or until predicate returns <code>false</code>.
*/
public <T extends FloatPredicate> T forEach(T predicate, int fromIndex, final int toIndex) {
assert (fromIndex >= 0 && fromIndex <= size())
: "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ").";
assert (toIndex >= 0 && toIndex <= size())
: "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "].";
assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex;
final float[] buffer = this.buffer;
for (int i = fromIndex; i < toIndex; i++) {
if (!predicate.apply(buffer[i])) break;
}
return predicate;
}
/**
* Create a list from a variable number of arguments or an array of <code>float</code>. The
* elements are copied from the argument to the internal buffer.
*/
public static FloatArrayList from(float... elements) {
final FloatArrayList list = new FloatArrayList(elements.length);
list.add(elements);
return list;
}
}

View File

@ -0,0 +1,33 @@
package com.carrotsearch.hppc;
/**
* Reused buffer visualization routines.
*
* @see FloatSet#visualizeKeyDistribution(int)
* @see FloatVTypeMap#visualizeKeyDistribution(int)
*/
class FloatBufferVisualizer {
static String visualizeKeyDistribution(float[] buffer, int max, int characters) {
final StringBuilder b = new StringBuilder();
final char[] chars = ".123456789X".toCharArray();
for (int i = 1, start = -1; i <= characters; i++) {
int end = (int) ((long) i * max / characters);
if (start + 1 <= end) {
int taken = 0;
int slots = 0;
for (int slot = start + 1; slot <= end; slot++, slots++) {
if (!(Float.floatToIntBits(buffer[slot]) == 0)) {
taken++;
}
}
b.append(chars[Math.min(chars.length - 1, taken * chars.length / slots)]);
start = end;
}
}
while (b.length() < characters) {
b.append(' ');
}
return b.toString();
}
}

View File

@ -0,0 +1,64 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.predicates.FloatPredicate;
/**
* A collection allows basic, efficient operations on sets of elements (difference and
* intersection).
*/
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCollection.java")
public interface FloatCollection extends FloatContainer {
/**
* Removes all occurrences of <code>e</code> from this collection.
*
* @param e Element to be removed from this collection, if present.
* @return The number of removed elements as a result of this call.
*/
public int removeAll(float e);
/**
* Removes all elements in this collection that are present in <code>c</code>.
*
* @return Returns the number of removed elements.
*/
public int removeAll(FloatLookupContainer c);
/**
* Removes all elements in this collection for which the given predicate returns <code>true</code>
* .
*
* @return Returns the number of removed elements.
*/
public int removeAll(FloatPredicate predicate);
/**
* Keeps all elements in this collection that are present in <code>c</code>. Runs in time
* proportional to the number of elements in this collection. Equivalent of sets intersection.
*
* @return Returns the number of removed elements.
*/
public int retainAll(FloatLookupContainer c);
/**
* Keeps all elements in this collection for which the given predicate returns <code>true</code>.
*
* @return Returns the number of removed elements.
*/
public int retainAll(FloatPredicate predicate);
/**
* Removes all elements from this collection.
*
* @see #release()
*/
public void clear();
/**
* Removes all elements from the collection and additionally releases any internal buffers.
* Typically, if the object is to be reused, a simple {@link #clear()} should be a better
* alternative since it'll avoid reallocation.
*
* @see #clear()
*/
public void release();
}

View File

@ -0,0 +1,76 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.FloatCursor;
import com.carrotsearch.hppc.predicates.FloatPredicate;
import com.carrotsearch.hppc.procedures.FloatProcedure;
import java.util.Iterator;
/** A generic container holding <code>float</code>s. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeContainer.java")
public interface FloatContainer extends Iterable<FloatCursor> {
/**
* Returns an iterator to a cursor traversing the collection. The order of traversal is not
* defined. More than one cursor may be active at a time. The behavior of iterators is undefined
* if structural changes are made to the underlying collection.
*
* <p>The iterator is implemented as a cursor and it returns <b>the same cursor instance</b> on
* every call to {@link Iterator#next()} (to avoid boxing of primitive types). To read the current
* list's value (or index in the list) use the cursor's public fields. An example is shown below.
*
* <pre>
* for (FloatCursor&lt;float&gt; c : container) {
* System.out.println(&quot;index=&quot; + c.index + &quot; value=&quot; + c.value);
* }
* </pre>
*/
public Iterator<FloatCursor> iterator();
/**
* Lookup a given element in the container. This operation has no speed guarantees (may be linear
* with respect to the size of this container).
*
* @return Returns <code>true</code> if this container has an element equal to <code>e</code>.
*/
public boolean contains(float e);
/**
* Return the current number of elements in this container. The time for calculating the
* container's size may take <code>O(n)</code> time, although implementing classes should try to
* maintain the current size and return in constant time.
*/
public int size();
/** Shortcut for <code>size() == 0</code>. */
public boolean isEmpty();
/**
* Copies all elements of this container to an array.
*
* <p>The returned array is always a copy, regardless of the storage used by the container.
*/
public float[] toArray();
/**
* Applies a <code>procedure</code> to all container elements. Returns the argument (any subclass
* of {@link FloatProcedure}. This lets the caller to call methods of the argument by chaining the
* call (even if the argument is an anonymous type) to retrieve computed values, for example
* (IntContainer):
*
* <pre>
* int count = container.forEach(new IntProcedure() {
* int count; // this is a field declaration in an anonymous class.
*
* public void apply(int value) {
* count++;
* }
* }).count;
* </pre>
*/
public <T extends FloatProcedure> T forEach(T procedure);
/**
* Applies a <code>predicate</code> to container elements as long, as the predicate returns <code>
* true</code>. The iteration is interrupted otherwise.
*/
public <T extends FloatPredicate> T forEach(T predicate);
}

View File

@ -0,0 +1,77 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.FloatCursor;
import com.carrotsearch.hppc.predicates.FloatPredicate;
import com.carrotsearch.hppc.procedures.FloatProcedure;
import java.util.Deque;
import java.util.Iterator;
/**
* A linear collection that supports element insertion and removal at both ends.
*
* @see Deque
*/
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeDeque.java")
public interface FloatDeque extends FloatCollection {
/**
* Removes the first element that equals <code>e</code>.
*
* @return The deleted element's index or <code>-1</code> if the element was not found.
*/
public int removeFirst(float e);
/**
* Removes the last element that equals <code>e</code>.
*
* @return The deleted element's index or <code>-1</code> if the element was not found.
*/
public int removeLast(float e);
/** Inserts the specified element at the front of this deque. */
public void addFirst(float e);
/** Inserts the specified element at the end of this deque. */
public void addLast(float e);
/**
* Retrieves and removes the first element of this deque.
*
* @return the head (first) element of this deque.
*/
public float removeFirst();
/**
* Retrieves and removes the last element of this deque.
*
* @return the tail of this deque.
*/
public float removeLast();
/**
* Retrieves the first element of this deque but does not remove it.
*
* @return the head of this deque.
*/
public float getFirst();
/**
* Retrieves the last element of this deque but does not remove it.
*
* @return the head of this deque.
*/
public float getLast();
/**
* @return An iterator over elements in this deque in tail-to-head order.
*/
public Iterator<FloatCursor> descendingIterator();
/** Applies a <code>procedure</code> to all elements in tail-to-head order. */
public <T extends FloatProcedure> T descendingForEach(T procedure);
/**
* Applies a <code>predicate</code> to container elements as long, as the predicate returns <code>
* true</code>. The iteration is interrupted otherwise.
*/
public <T extends FloatPredicate> T descendingForEach(T predicate);
}

View File

@ -0,0 +1,91 @@
package com.carrotsearch.hppc;
import java.util.RandomAccess;
/**
* An indexed container provides random access to elements based on an <code>index</code>. Indexes
* are zero-based.
*/
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "KTypeIndexedContainer.java")
public interface FloatIndexedContainer extends FloatCollection, RandomAccess {
/**
* Removes the first element that equals <code>e1</code>, returning whether an element has been
* removed.
*/
public boolean removeElement(float e1);
/**
* Removes the first element that equals <code>e1</code>, returning its deleted position or <code>
* -1</code> if the element was not found.
*/
public int removeFirst(float e1);
/**
* Removes the last element that equals <code>e1</code>, returning its deleted position or <code>
* -1</code> if the element was not found.
*/
public int removeLast(float e1);
/**
* Returns the index of the first occurrence of the specified element in this list, or -1 if this
* list does not contain the element.
*/
public int indexOf(float e1);
/**
* Returns the index of the last occurrence of the specified element in this list, or -1 if this
* list does not contain the element.
*/
public int lastIndexOf(float e1);
/** Adds an element to the end of this container (the last index is incremented by one). */
public void add(float e1);
/**
* Inserts the specified element at the specified position in this list.
*
* @param index The index at which the element should be inserted, shifting any existing and
* subsequent elements to the right.
*/
public void insert(int index, float e1);
/**
* Replaces the element at the specified position in this list with the specified element.
*
* @return Returns the previous value in the list.
*/
public float set(int index, float e1);
/**
* @return Returns the element at index <code>index</code> from the list.
*/
public float get(int index);
/**
* Removes the element at the specified position in this container and returns it.
*
* @see #removeFirst
* @see #removeLast
* @see #removeAll
*/
public float removeAt(int index);
/** Removes and returns the last element of this container. This container must not be empty. */
public float removeLast();
/**
* Removes from this container all of the elements with indexes between <code>fromIndex</code>,
* inclusive, and <code>toIndex</code>, exclusive.
*/
public void removeRange(int fromIndex, int toIndex);
/** Returns this container elements as a stream. */
/** Sorts the elements in this container and returns this container. */
public FloatIndexedContainer sort();
/** Reverses the elements in this container and returns this container. */
public FloatIndexedContainer reverse();
}

View File

@ -0,0 +1,12 @@
package com.carrotsearch.hppc;
/**
* Marker interface for containers that can check if they contain a given object in at least time
* <code>O(log n)</code> and ideally in amortized constant time <code>O(1)</code>.
*/
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "KTypeLookupContainer.java")
public interface FloatLookupContainer extends FloatContainer {
public boolean contains(float e);
}

View File

@ -0,0 +1,600 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.FloatCursor;
import com.carrotsearch.hppc.procedures.FloatProcedure;
import java.util.Arrays;
import java.util.Iterator;
/**
* Space-efficient index that enables fast rank/range search operations on a sorted sequence of
* <code>float</code>.
*
* <p>Implementation of the PGM-Index described at <a
* href="https://pgm.di.unipi.it/">https://pgm.di.unipi.it/</a>, based on the paper
*
* <pre>
* Paolo Ferragina and Giorgio Vinciguerra.
* The PGM-index: a fully-dynamic compressed learned index with provable worst-case bounds.
* PVLDB, 13(8): 1162-1175, 2020.
* </pre>
*
* It provides {@code rank} and {@code range} search operations. {@code indexOf()} is faster than
* B+Tree, and the index is much more compact. {@code contains()} is between 4x to 7x slower than
* {@code IntHashSet#contains()}, but between 2.5x to 3x faster than {@link Arrays#binarySearch}.
*
* <p>Its compactness (40KB for 200MB of keys) makes it efficient for very large collections, the
* index fitting easily in the L2 cache. The {@code epsilon} parameter should be set according to
* the desired space-time trade-off. A smaller value makes the estimation more precise and the range
* smaller but at the cost of increased space usage. In practice, {@code epsilon} 64 is a good sweet
* spot.
*
* <p>Internally the index uses an optimal piecewise linear mapping from keys to their position in
* the sorted order. This mapping is represented as a sequence of linear models (segments) which are
* themselves recursively indexed by other piecewise linear mappings.
*/
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypePgmIndex.java")
public class FloatPgmIndex implements Accountable {
/** Empty immutable FloatPgmIndex. */
public static final FloatPgmIndex EMPTY = new FloatEmptyPgmIndex();
/**
* Epsilon approximation range when searching the list of keys. Controls the size of the returned
* search range, strictly greater than 0. It should be set according to the desired space-time
* trade-off. A smaller value makes the estimation more precise and the range smaller but at the
* cost of increased space usage.
*
* <p>With EPSILON=64 the benchmark with 200MB of keys shows that this PGM index requires only 2%
* additional memory on average (40KB). It depends on the distribution of the keys. This epsilon
* value is good even for 2MB of keys. With EPSILON=32: +5% speed, but 4x space (160KB).
*/
public static final int EPSILON = 64;
/**
* Epsilon approximation range for the segments layers. Controls the size of the search range in
* the hierarchical segment lists, strictly greater than 0.
*/
public static final int EPSILON_RECURSIVE = 32;
/** Size of a key, measured in {@link Integer#BYTES} because the key is stored in an int[]. */
public static final int KEY_SIZE =
RamUsageEstimator.primitiveSizes.get(float.class) / Integer.BYTES;
/** 2x {@link #KEY_SIZE}. */
public static final int DOUBLE_KEY_SIZE = KEY_SIZE * 2;
/**
* Data size of a segment, measured in {@link Integer#BYTES}, because segments are stored in an
* int[].
*/
public static final int SEGMENT_DATA_SIZE = KEY_SIZE * 3;
/** Initial value of the exponential jump when scanning out of the epsilon range. */
public static final int BEYOND_EPSILON_JUMP = 16;
/**
* The list of keys for which this index is built. It is sorted and may contain duplicate
* elements.
*/
public final FloatArrayList keys;
/** The size of the key set. That is, the number of distinct elements in {@link #keys}. */
public final int size;
/** The lowest key in {@link #keys}. */
public final float firstKey;
/** The highest key in {@link #keys}. */
public final float lastKey;
/** The epsilon range used to build this index. */
public final int epsilon;
/** The recursive epsilon range used to build this index. */
public final int epsilonRecursive;
/** The offsets in {@link #segmentData} of the first segment of each segment level. */
public final int[] levelOffsets;
/** The index data. It contains all the segments for all the levels. */
public final int[] segmentData;
private FloatPgmIndex(
FloatArrayList keys,
int size,
int epsilon,
int epsilonRecursive,
int[] levelOffsets,
int[] segmentData) {
assert keys.size() > 0;
assert size > 0 && size <= keys.size();
assert epsilon > 0;
assert epsilonRecursive > 0;
this.keys = keys;
this.size = size;
firstKey = keys.get(0);
lastKey = keys.get(keys.size() - 1);
this.epsilon = epsilon;
this.epsilonRecursive = epsilonRecursive;
this.levelOffsets = levelOffsets;
this.segmentData = segmentData;
}
/** Empty set constructor. */
private FloatPgmIndex() {
keys = new FloatArrayList(0);
size = 0;
firstKey = 0f;
lastKey = 0f;
epsilon = 0;
epsilonRecursive = 0;
levelOffsets = new int[0];
segmentData = levelOffsets;
}
/** Returns the size of the key set. That is, the number of distinct elements in {@link #keys}. */
public int size() {
return size;
}
/** Returns whether this key set is empty. */
public boolean isEmpty() {
return size() == 0;
}
/** Returns whether this key set contains the given key. */
public boolean contains(float key) {
return indexOf(key) >= 0;
}
/**
* Searches the specified key, and returns its index in the element list. If multiple elements are
* equal to the specified key, there is no guarantee which one will be found.
*
* @return The index of the searched key if it is present; otherwise, {@code (-(<i>insertion
* point</i>) - 1)}. The <i>insertion point</i> is defined as the point at which the key would
* be inserted into the list: the index of the first element greater than the key, or {@link
* #keys}#{@code size()} if all the elements are less than the specified key. Note that this
* guarantees that the return value will be &gt;= 0 if and only if the key is found.
*/
public int indexOf(float key) {
if (key < firstKey) {
return -1;
}
if (key > lastKey) {
return -keys.size() - 1;
}
final int[] segmentData = this.segmentData;
int segmentDataIndex = findSegment(key);
int nextIntercept = (int) getIntercept(segmentDataIndex + SEGMENT_DATA_SIZE, segmentData);
int index =
Math.min(
approximateIndex(key, segmentDataIndex, segmentData),
Math.min(nextIntercept, keys.size() - 1));
assert index >= 0 && index < keys.size();
float k = keys.get(index);
if (key < k) {
// Scan sequentially before the approximated index, within epsilon range.
final int fromIndex = Math.max(index - epsilon - 1, 0);
while (--index >= fromIndex) {
k = keys.get(index);
if (key > k) {
return -index - 2;
}
if ((Float.floatToIntBits(key) == Float.floatToIntBits(k))) {
return index;
}
}
// Continue scanning out of the epsilon range.
// This might happen in rare cases of precision error during the approximation
// computation for longs (we don't have long double 128 bits in Java).
// This might also happen in rare corner cases of large duplicate elements
// sequence at the epsilon range boundary.
index++;
int jump = BEYOND_EPSILON_JUMP;
do {
int loIndex = Math.max(index - jump, 0);
if (key >= keys.get(loIndex)) {
return Arrays.binarySearch(keys.buffer, loIndex, index, key);
}
index = loIndex;
jump <<= 1;
} while (index > 0);
return -1;
} else if ((Float.floatToIntBits(key) == Float.floatToIntBits(k))) {
return index;
} else {
// Scan sequentially after the approximated index, within epsilon range.
final int toIndex = Math.min(index + epsilon + 3, keys.size());
while (++index < toIndex) {
k = keys.get(index);
if (key < k) {
return -index - 1;
}
if ((Float.floatToIntBits(key) == Float.floatToIntBits(k))) {
return index;
}
}
// Continue scanning out of the epsilon range.
int jump = BEYOND_EPSILON_JUMP;
do {
int hiIndex = Math.min(index + jump, keys.size());
if (key <= keys.get(hiIndex)) {
return Arrays.binarySearch(keys.buffer, index, hiIndex, key);
}
index = hiIndex;
jump <<= 1;
} while (index < keys.size());
return -keys.size() - 1;
}
}
/**
* Returns, for any value {@code x}, the number of keys in the sorted list which are smaller than
* {@code x}. It is equal to {@link #indexOf} if {@code x} belongs to the list, or -{@link
* #indexOf}-1 otherwise.
*
* <p>If multiple elements are equal to the specified key, there is no guarantee which one will be
* found.
*
* @return The index of the searched key if it is present; otherwise, the {@code insertion point}.
* The <i>insertion point</i> is defined as the point at which the key would be inserted into
* the list: the index of the first element greater than the key, or {@link #keys}#{@code
* size()} if all the elements are less than the specified key. Note that this method always
* returns a value &gt;= 0.
*/
public int rank(float x) {
int index = indexOf(x);
return index >= 0 ? index : -index - 1;
}
/**
* Returns the number of keys in the list that are greater than or equal to {@code minKey}
* (inclusive), and less than or equal to {@code maxKey} (inclusive).
*/
public int rangeCardinality(float minKey, float maxKey) {
int fromIndex = rank(minKey);
int maxIndex = indexOf(maxKey);
int toIndex = maxIndex >= 0 ? maxIndex + 1 : -maxIndex - 1;
return Math.max(toIndex - fromIndex, 0);
}
/**
* Returns an iterator over the keys in the list that are greater than or equal to {@code minKey}
* (inclusive), and less than or equal to {@code maxKey} (inclusive).
*/
public Iterator<FloatCursor> rangeIterator(float minKey, float maxKey) {
int fromIndex = rank(minKey);
return new RangeIterator(keys, fromIndex, maxKey);
}
/**
* Applies {@code procedure} to the keys in the list that are greater than or equal to {@code
* minKey} (inclusive), and less than or equal to {@code maxKey} (inclusive).
*/
public <T extends FloatProcedure> T forEachInRange(T procedure, float minKey, float maxKey) {
final float[] buffer = keys.buffer;
float k;
for (int i = rank(minKey), size = keys.size(); i < size && (k = buffer[i]) <= maxKey; i++) {
procedure.apply(k);
}
return procedure;
}
/**
* Estimates the allocated memory. It does not count the memory for the list of keys, only for the
* index itself.
*/
@Override
public long ramBytesAllocated() {
// int: size, epsilon, epsilonRecursive
// float: firstKey, lastKey
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ 3 * Integer.BYTES
+ 2L * KEY_SIZE * Integer.BYTES
// + keys.ramBytesAllocated()
+ RamUsageEstimator.shallowSizeOfArray(levelOffsets)
+ RamUsageEstimator.shallowSizeOfArray(segmentData);
}
/**
* Estimates the bytes that are actually used. It does not count the memory for the list of keys,
* only for the index itself.
*/
@Override
public long ramBytesUsed() {
// int: size, epsilon, epsilonRecursive
// float: firstKey, lastKey
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ 3 * Integer.BYTES
+ 2L * KEY_SIZE * Integer.BYTES
// + keys.ramBytesUsed()
+ RamUsageEstimator.shallowSizeOfArray(levelOffsets)
+ RamUsageEstimator.shallowSizeOfArray(segmentData);
}
/**
* Finds the segment responsible for a given key, that is, the rightmost segment having its first
* key <= the searched key.
*
* @return the segment data index; or -1 if none.
*/
private int findSegment(float key) {
assert key >= firstKey && key <= lastKey;
final int epsilonRecursive = this.epsilonRecursive;
final int[] levelOffsets = this.levelOffsets;
final int[] segmentData = this.segmentData;
int level = levelOffsets.length - 1;
int segmentDataIndex = levelOffsets[level] * SEGMENT_DATA_SIZE;
while (--level >= 0) {
int nextIntercept = (int) getIntercept(segmentDataIndex + SEGMENT_DATA_SIZE, segmentData);
int index = Math.min(approximateIndex(key, segmentDataIndex, segmentData), nextIntercept);
assert index >= 0 && index <= levelOffsets[level + 1] - levelOffsets[level] - 1;
int sdIndex = (levelOffsets[level] + index) * SEGMENT_DATA_SIZE;
if (getKey(sdIndex, segmentData) <= key) {
// Scan sequentially segments after the approximated index, within the epsilon range.
final int levelNumSegments = levelOffsets[level + 1] - levelOffsets[level] - 1;
final int toIndex = Math.min(index + epsilonRecursive + 3, levelNumSegments);
while (index++ < toIndex && getKey(sdIndex + SEGMENT_DATA_SIZE, segmentData) <= key) {
sdIndex += SEGMENT_DATA_SIZE;
}
} else {
// Scan sequentially segments before the approximated index, within the epsilon range.
final int fromIndex = Math.max(index - epsilonRecursive - 1, 0);
while (index-- > fromIndex) {
sdIndex -= SEGMENT_DATA_SIZE;
if (getKey(sdIndex, segmentData) <= key) {
break;
}
}
}
segmentDataIndex = sdIndex;
}
assert segmentDataIndex >= 0;
return segmentDataIndex;
}
private int approximateIndex(float key, int segmentDataIndex, int[] segmentData) {
long intercept = getIntercept(segmentDataIndex, segmentData);
float sKey = getKey(segmentDataIndex, segmentData);
double slope = getSlope(segmentDataIndex, segmentData);
int index = (int) (slope * ((double) key - sKey) + intercept);
return Math.max(index, 0);
}
private static long getIntercept(int segmentDataIndex, int[] segmentData) {
return PgmIndexUtil.getIntercept(segmentDataIndex, segmentData, KEY_SIZE);
}
private float getKey(int segmentDataIndex, int[] segmentData) {
return PgmIndexUtil.getKey(segmentDataIndex + KEY_SIZE, segmentData, 0f);
}
private static double getSlope(int segmentDataIndex, int[] segmentData) {
return PgmIndexUtil.getSlope(segmentDataIndex + DOUBLE_KEY_SIZE, segmentData, KEY_SIZE);
}
/** Empty immutable PGM Index. */
private static class FloatEmptyPgmIndex extends FloatPgmIndex {
private final Iterator<FloatCursor> emptyIterator = new FloatEmptyIterator();
@Override
public int indexOf(float key) {
return -1;
}
@Override
public Iterator<FloatCursor> rangeIterator(float minKey, float maxKey) {
return emptyIterator;
}
@Override
public <T extends FloatProcedure> T forEachInRange(T procedure, float minKey, float maxKey) {
return procedure;
}
private static class FloatEmptyIterator extends AbstractIterator<FloatCursor> {
@Override
protected FloatCursor fetch() {
return done();
}
}
}
/** Iterator over a range of elements in a sorted array. */
protected static class RangeIterator extends AbstractIterator<FloatCursor> {
private final float[] buffer;
private final int size;
private final FloatCursor cursor;
private final float maxKey;
/** Range iterator from {@code fromIndex} (inclusive) to {@code maxKey} (inclusive). */
protected RangeIterator(FloatArrayList keys, int fromIndex, float maxKey) {
this.buffer = keys.buffer;
this.size = keys.size();
this.cursor = new FloatCursor();
this.cursor.index = fromIndex;
this.maxKey = maxKey;
}
@Override
protected FloatCursor fetch() {
if (cursor.index >= size) {
return done();
}
cursor.value = buffer[cursor.index++];
if (cursor.value > maxKey) {
cursor.index = size;
return done();
}
return cursor;
}
}
/** Builds a {@link FloatPgmIndex} on a provided sorted list of keys. */
public static class FloatBuilder implements PlaModel.SegmentConsumer, Accountable {
protected FloatArrayList keys;
protected int epsilon = EPSILON;
protected int epsilonRecursive = EPSILON_RECURSIVE;
protected PlaModel plam;
protected int size;
protected IntArrayList segmentData;
protected int numSegments;
/** Sets the sorted list of keys to build the index for; duplicate elements are allowed. */
public FloatBuilder setSortedKeys(FloatArrayList keys) {
this.keys = keys;
return this;
}
/** Sets the sorted array of keys to build the index for; duplicate elements are allowed. */
public FloatBuilder setSortedKeys(float[] keys, int length) {
FloatArrayList keyList = new FloatArrayList(0);
keyList.buffer = keys;
keyList.elementsCount = length;
return setSortedKeys(keyList);
}
/** Sets the epsilon range to use when learning the segments for the list of keys. */
public FloatBuilder setEpsilon(int epsilon) {
if (epsilon <= 0) {
throw new IllegalArgumentException("epsilon must be > 0");
}
this.epsilon = epsilon;
return this;
}
/**
* Sets the recursive epsilon range to use when learning the segments for the segment levels.
*/
public FloatBuilder setEpsilonRecursive(int epsilonRecursive) {
if (epsilonRecursive <= 0) {
throw new IllegalArgumentException("epsilonRecursive must be > 0");
}
this.epsilonRecursive = epsilonRecursive;
return this;
}
/** Builds the {@link FloatPgmIndex}; or {@link #EMPTY} if there are no keys in the list. */
public FloatPgmIndex build() {
if (keys == null || keys.size() == 0) {
return (FloatPgmIndex) EMPTY;
}
plam = new PlaModel(epsilon);
int segmentsInitialCapacity =
Math.min(
Math.max(keys.size() / (2 * epsilon * epsilon) * SEGMENT_DATA_SIZE, 16), 1 << 19);
segmentData = new IntArrayList(segmentsInitialCapacity);
IntArrayList levelOffsets = new IntArrayList(16);
int levelOffset = 0;
levelOffsets.add(levelOffset);
int levelNumSegments = buildFirstLevel();
while (levelNumSegments > 1) {
int nextLevelOffset = numSegments;
levelOffsets.add(nextLevelOffset);
levelNumSegments = buildUpperLevel(levelOffset, levelNumSegments);
levelOffset = nextLevelOffset;
}
int[] segmentDataFinal = segmentData.toArray();
int[] levelOffsetsFinal = levelOffsets.toArray();
return new FloatPgmIndex(
keys, size, epsilon, epsilonRecursive, levelOffsetsFinal, segmentDataFinal);
}
private int buildFirstLevel() {
assert numSegments == 0;
int numKeys = keys.size();
int size = 0;
float key = keys.get(0);
size++;
plam.addKey(key, 0, this);
for (int i = 1; i < numKeys; i++) {
float nextKey = keys.get(i);
if (!(Float.floatToIntBits(nextKey) == Float.floatToIntBits(key))) {
key = nextKey;
plam.addKey(key, i, this);
size++;
}
}
plam.finish(this);
addSentinelSegment(numKeys);
this.size = size;
return numSegments - 1;
}
private int buildUpperLevel(int levelOffset, int levelNumSegments) {
plam.setEpsilon(epsilonRecursive);
assert numSegments > 0;
int initialNumSegments = numSegments;
int segmentDataIndex = levelOffset * SEGMENT_DATA_SIZE;
float key = getKey(segmentDataIndex, segmentData.buffer);
plam.addKey(key, 0, this);
for (int i = 1; i < levelNumSegments; i++) {
segmentDataIndex += SEGMENT_DATA_SIZE;
float nextKey = getKey(segmentDataIndex, segmentData.buffer);
if (!(Float.floatToIntBits(nextKey) == Float.floatToIntBits(key))) {
key = nextKey;
plam.addKey(key, i, this);
}
}
plam.finish(this);
addSentinelSegment(levelNumSegments);
return numSegments - initialNumSegments - 1;
}
private float getKey(int segmentDataIndex, int[] segmentData) {
return PgmIndexUtil.getKey(segmentDataIndex + KEY_SIZE, segmentData, 0f);
}
/**
* Adds a sentinel segment that is used to give a limit for the position approximation, but does
* not count in the number of segments per level.
*/
private void addSentinelSegment(int endIndex) {
// This sentinel segment is used in findSegment().
accept(Double.MAX_VALUE, 0d, endIndex);
}
@Override
public void accept(double firstKey, double slope, long intercept) {
PgmIndexUtil.addIntercept(intercept, segmentData, KEY_SIZE);
PgmIndexUtil.addKey((float) firstKey, segmentData);
PgmIndexUtil.addSlope(slope, segmentData, KEY_SIZE);
numSegments++;
assert segmentData.size() == numSegments * SEGMENT_DATA_SIZE;
}
/**
* Estimates the allocated memory. It does not count the memory for the list of keys, only for
* the builder itself.
*/
@Override
public long ramBytesAllocated() {
// int: epsilon, epsilonRecursive, size, numSegments
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ 4 * Integer.BYTES
// + keys.ramBytesAllocated()
+ plam.ramBytesAllocated()
+ segmentData.ramBytesAllocated();
}
/**
* Estimates the bytes that are actually used. It does not count the memory for the list of
* keys, only for the builder itself.
*/
@Override
public long ramBytesUsed() {
// int: epsilon, epsilonRecursive, size, numSegments
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ 4 * Integer.BYTES
// + keys.ramBytesUsed()
+ plam.ramBytesUsed()
+ segmentData.ramBytesUsed();
}
}
}

View File

@ -0,0 +1,137 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.FloatCursor;
/**
* A subclass of {@link FloatArrayList} adding stack-related utility methods. The top of the stack
* is at the <code>{@link #size()} - 1</code> element.
*/
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeStack.java")
public class FloatStack extends FloatArrayList {
/** New instance with sane defaults. */
public FloatStack() {
super();
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
*/
public FloatStack(int expectedElements) {
super(expectedElements);
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
* @param resizer Underlying buffer sizing strategy.
*/
public FloatStack(int expectedElements, ArraySizingStrategy resizer) {
super(expectedElements, resizer);
}
/** Create a stack by pushing all elements of another container to it. */
public FloatStack(FloatContainer container) {
super(container);
}
/** Adds one float to the stack. */
public void push(float e1) {
ensureBufferSpace(1);
buffer[elementsCount++] = e1;
}
/** Adds two floats to the stack. */
public void push(float e1, float e2) {
ensureBufferSpace(2);
buffer[elementsCount++] = e1;
buffer[elementsCount++] = e2;
}
/** Adds three floats to the stack. */
public void push(float e1, float e2, float e3) {
ensureBufferSpace(3);
buffer[elementsCount++] = e1;
buffer[elementsCount++] = e2;
buffer[elementsCount++] = e3;
}
/** Adds four floats to the stack. */
public void push(float e1, float e2, float e3, float e4) {
ensureBufferSpace(4);
buffer[elementsCount++] = e1;
buffer[elementsCount++] = e2;
buffer[elementsCount++] = e3;
buffer[elementsCount++] = e4;
}
/** Add a range of array elements to the stack. */
public void push(float[] elements, int start, int len) {
assert start >= 0 && len >= 0;
ensureBufferSpace(len);
System.arraycopy(elements, start, buffer, elementsCount, len);
elementsCount += len;
}
/**
* Vararg-signature method for pushing elements at the top of the stack.
*
* <p><b>This method is handy, but costly if used in tight loops (anonymous array passing)</b>
*/
public final void push(float... elements) {
push(elements, 0, elements.length);
}
/** Pushes all elements from another container to the top of the stack. */
public int pushAll(FloatContainer container) {
return addAll(container);
}
/** Pushes all elements from another iterable to the top of the stack. */
public int pushAll(Iterable<? extends FloatCursor> iterable) {
return addAll(iterable);
}
/** Discard an arbitrary number of elements from the top of the stack. */
public void discard(int count) {
assert elementsCount >= count;
elementsCount -= count;
}
/** Discard the top element from the stack. */
public void discard() {
assert elementsCount > 0;
elementsCount--;
}
/** Remove the top element from the stack and return it. */
public float pop() {
return removeLast();
}
/** Peek at the top element on the stack. */
public float peek() {
assert elementsCount > 0;
return buffer[elementsCount - 1];
}
/** Create a stack by pushing a variable number of arguments to it. */
public static FloatStack from(float... elements) {
final FloatStack stack = new FloatStack(elements.length);
stack.push(elements);
return stack;
}
/** {@inheritDoc} */
@Override
public FloatStack clone() {
return (FloatStack) super.clone();
}
}

View File

@ -0,0 +1,37 @@
/*
* HPPC
*
* Copyright (C) 2010-2024 Carrot Search s.c. and contributors
* All rights reserved.
*
* Refer to the full license file "LICENSE.txt":
* https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt
*/
package com.carrotsearch.hppc;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Documented
@Retention(SOURCE)
@Target({PACKAGE, TYPE, ANNOTATION_TYPE, METHOD, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, PARAMETER})
public @interface Generated {
/**
* The value element MUST have the name of the code generator. The recommended convention is to
* use the fully qualified name of the code generator. For example: com.acme.generator.CodeGen.
*/
String[] value();
/** Date when the source was generated. */
String date() default "";
/**
* A place holder for any comments that the code generator may want to include in the generated
* code.
*/
String comments() default "";
}

View File

@ -0,0 +1,112 @@
/*
* HPPC
*
* Copyright (C) 2010-2024 Carrot Search s.c. and contributors
* All rights reserved.
*
* Refer to the full license file "LICENSE.txt":
* https://github.com/carrotsearch/hppc/blob/master/LICENSE.txt
*/
package com.carrotsearch.hppc;
import java.util.concurrent.atomic.AtomicInteger;
public final class HashContainers {
/**
* Maximum array size for hash containers (power-of-two and still allocable in Java, not a
* negative int).
*/
public static final int MAX_HASH_ARRAY_LENGTH = 0x80000000 >>> 1;
/** Minimum hash buffer size. */
public static final int MIN_HASH_ARRAY_LENGTH = 4;
/** Default load factor. */
public static final float DEFAULT_LOAD_FACTOR = 0.75f;
/** Minimal sane load factor (99 empty slots per 100). */
public static final float MIN_LOAD_FACTOR = 1 / 100.0f;
/** Maximum sane load factor (1 empty slot per 100). */
public static final float MAX_LOAD_FACTOR = 99 / 100.0f;
private static final AtomicInteger ITERATION_SEED = new AtomicInteger();
/**
* Compute and return the maximum number of elements (inclusive) that can be stored in a hash
* container for a given load factor.
*/
public static int maxElements(double loadFactor) {
checkLoadFactor(loadFactor, 0, 1);
return expandAtCount(MAX_HASH_ARRAY_LENGTH, loadFactor) - 1;
}
/** */
static int minBufferSize(int elements, double loadFactor) {
if (elements < 0) {
throw new IllegalArgumentException("Number of elements must be >= 0: " + elements);
}
long length = (long) Math.ceil(elements / loadFactor);
if (length == elements) {
length++;
}
length = Math.max(MIN_HASH_ARRAY_LENGTH, BitUtil.nextHighestPowerOfTwo(length));
if (length > MAX_HASH_ARRAY_LENGTH) {
throw new BufferAllocationException(
"Maximum array size exceeded for this load factor (elements: %d, load factor: %f)",
elements, loadFactor);
}
return (int) length;
}
/** */
static int nextBufferSize(int arraySize, int elements, double loadFactor) {
assert checkPowerOfTwo(arraySize);
if (arraySize == MAX_HASH_ARRAY_LENGTH) {
throw new BufferAllocationException(
"Maximum array size exceeded for this load factor (elements: %d, load factor: %f)",
elements, loadFactor);
}
return (int) arraySize << 1;
}
/** */
static int expandAtCount(int arraySize, double loadFactor) {
assert checkPowerOfTwo(arraySize);
// Take care of hash container invariant (there has to be at least one empty slot to ensure
// the lookup loop finds either the element or an empty slot).
return Math.min(arraySize - 1, (int) Math.ceil(arraySize * loadFactor));
}
/** */
static void checkLoadFactor(
double loadFactor, double minAllowedInclusive, double maxAllowedInclusive) {
if (loadFactor < minAllowedInclusive || loadFactor > maxAllowedInclusive) {
throw new BufferAllocationException(
"The load factor should be in range [%.2f, %.2f]: %f",
minAllowedInclusive, maxAllowedInclusive, loadFactor);
}
}
/** */
static boolean checkPowerOfTwo(int arraySize) {
// These are internals, we can just assert without retrying.
assert arraySize > 1;
assert BitUtil.nextHighestPowerOfTwo(arraySize) == arraySize;
return true;
}
/** Provides the next hash iteration order seed. It is simply an incrementing atomic counter. */
static int nextIterationSeed() {
return ITERATION_SEED.incrementAndGet();
}
/** Computes a hash iteration order increment based on the provided seed. */
static int iterationIncrement(int seed) {
return 29 + ((seed & 7) << 1); // Small odd integer.
}
}

View File

@ -0,0 +1,776 @@
package com.carrotsearch.hppc;
import static com.carrotsearch.hppc.Containers.*;
import com.carrotsearch.hppc.cursors.IntCursor;
import com.carrotsearch.hppc.predicates.IntPredicate;
import com.carrotsearch.hppc.procedures.IntProcedure;
import java.util.*;
/** An array-backed {@link IntDeque}. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayDeque.java")
public class IntArrayDeque extends AbstractIntCollection
implements IntDeque, Preallocable, Cloneable, Accountable {
/** Reuse the same strategy instance. */
private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY =
BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE;
/** Internal array for storing elements of the deque. */
public int[] buffer = IntArrayList.EMPTY_ARRAY;
/**
* The index of the element at the head of the deque or an arbitrary number equal to tail if the
* deque is empty.
*/
public int head;
/** The index at which the next element would be added to the tail of the deque. */
public int tail;
/** Buffer resizing strategy. */
protected final ArraySizingStrategy resizer;
/** New instance with sane defaults. */
public IntArrayDeque() {
this(DEFAULT_EXPECTED_ELEMENTS);
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
*/
public IntArrayDeque(int expectedElements) {
this(expectedElements, DEFAULT_SIZING_STRATEGY);
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
* @param resizer Underlying buffer sizing strategy.
*/
public IntArrayDeque(int expectedElements, ArraySizingStrategy resizer) {
assert resizer != null;
this.resizer = resizer;
ensureCapacity(expectedElements);
}
/**
* Creates a new deque from elements of another container, appending elements at the end of the
* deque in the iteration order.
*/
public IntArrayDeque(IntContainer container) {
this(container.size());
addLast(container);
}
/** {@inheritDoc} */
@Override
public void addFirst(int e1) {
int h = oneLeft(head, buffer.length);
if (h == tail) {
ensureBufferSpace(1);
h = oneLeft(head, buffer.length);
}
buffer[head = h] = e1;
}
/**
* Vararg-signature method for adding elements at the front of this deque.
*
* <p><b>This method is handy, but costly if used in tight loops (anonymous array passing)</b>
*
* @param elements The elements to add.
*/
public final void addFirst(int... elements) {
ensureBufferSpace(elements.length);
for (int k : elements) {
addFirst(k);
}
}
/**
* Inserts all elements from the given container to the front of this deque.
*
* @param container The container to iterate over.
* @return Returns the number of elements actually added as a result of this call.
*/
public int addFirst(IntContainer container) {
int size = container.size();
ensureBufferSpace(size);
for (IntCursor cursor : container) {
addFirst(cursor.value);
}
return size;
}
/**
* Inserts all elements from the given iterable to the front of this deque.
*
* @param iterable The iterable to iterate over.
* @return Returns the number of elements actually added as a result of this call.
*/
public int addFirst(Iterable<? extends IntCursor> iterable) {
int size = 0;
for (IntCursor cursor : iterable) {
addFirst(cursor.value);
size++;
}
return size;
}
/** {@inheritDoc} */
@Override
public void addLast(int e1) {
int t = oneRight(tail, buffer.length);
if (head == t) {
ensureBufferSpace(1);
t = oneRight(tail, buffer.length);
}
buffer[tail] = e1;
tail = t;
}
/**
* Vararg-signature method for adding elements at the end of this deque.
*
* <p><b>This method is handy, but costly if used in tight loops (anonymous array passing)</b>
*
* @param elements The elements to iterate over.
*/
public final void addLast(int... elements) {
ensureBufferSpace(1);
for (int k : elements) {
addLast(k);
}
}
/**
* Inserts all elements from the given container to the end of this deque.
*
* @param container The container to iterate over.
* @return Returns the number of elements actually added as a result of this call.
*/
public int addLast(IntContainer container) {
int size = container.size();
ensureBufferSpace(size);
for (IntCursor cursor : container) {
addLast(cursor.value);
}
return size;
}
/**
* Inserts all elements from the given iterable to the end of this deque.
*
* @param iterable The iterable to iterate over.
* @return Returns the number of elements actually added as a result of this call.
*/
public int addLast(Iterable<? extends IntCursor> iterable) {
int size = 0;
for (IntCursor cursor : iterable) {
addLast(cursor.value);
size++;
}
return size;
}
/** {@inheritDoc} */
@Override
public int removeFirst() {
assert size() > 0 : "The deque is empty.";
final int result = buffer[head];
buffer[head] = 0;
head = oneRight(head, buffer.length);
return result;
}
/** {@inheritDoc} */
@Override
public int removeLast() {
assert size() > 0 : "The deque is empty.";
tail = oneLeft(tail, buffer.length);
final int result = buffer[tail];
buffer[tail] = 0;
return result;
}
/** {@inheritDoc} */
@Override
public int getFirst() {
assert size() > 0 : "The deque is empty.";
return buffer[head];
}
/** {@inheritDoc} */
@Override
public int getLast() {
assert size() > 0 : "The deque is empty.";
return buffer[oneLeft(tail, buffer.length)];
}
/** {@inheritDoc} */
@Override
public int removeFirst(int e1) {
final int index = bufferIndexOf(e1);
if (index >= 0) removeAtBufferIndex(index);
return index;
}
/**
* Return the index of the first (counting from head) element equal to <code>e1</code>. The index
* points to the {@link #buffer} array.
*
* @param e1 The element to look for.
* @return Returns the index of the first element equal to <code>e1</code> or <code>-1</code> if
* not found.
*/
public int bufferIndexOf(int e1) {
final int last = tail;
final int bufLen = buffer.length;
for (int i = head; i != last; i = oneRight(i, bufLen)) {
if (((e1) == (buffer[i]))) {
return i;
}
}
return -1;
}
/** {@inheritDoc} */
@Override
public int removeLast(int e1) {
final int index = lastBufferIndexOf(e1);
if (index >= 0) {
removeAtBufferIndex(index);
}
return index;
}
/**
* Return the index of the last (counting from tail) element equal to <code>e1</code>. The index
* points to the {@link #buffer} array.
*
* @param e1 The element to look for.
* @return Returns the index of the first element equal to <code>e1</code> or <code>-1</code> if
* not found.
*/
public int lastBufferIndexOf(int e1) {
final int bufLen = buffer.length;
final int last = oneLeft(head, bufLen);
for (int i = oneLeft(tail, bufLen); i != last; i = oneLeft(i, bufLen)) {
if (((e1) == (buffer[i]))) return i;
}
return -1;
}
/** {@inheritDoc} */
@Override
public int removeAll(int e1) {
int removed = 0;
final int last = tail;
final int bufLen = buffer.length;
int from, to;
for (from = to = head; from != last; from = oneRight(from, bufLen)) {
if (((e1) == (buffer[from]))) {
buffer[from] = 0;
removed++;
continue;
}
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = 0;
}
to = oneRight(to, bufLen);
}
tail = to;
return removed;
}
/**
* Removes the element at <code>index</code> in the internal {#link {@link #buffer} array,
* returning its value.
*
* @param index Index of the element to remove. The index must be located between {@link #head}
* and {@link #tail} in modulo {@link #buffer} arithmetic.
*/
public void removeAtBufferIndex(int index) {
assert (head <= tail ? index >= head && index < tail : index >= head || index < tail)
: "Index out of range (head=" + head + ", tail=" + tail + ", index=" + index + ").";
// Cache fields in locals (hopefully moved to registers).
final int[] buffer = this.buffer;
final int bufLen = buffer.length;
final int lastIndex = bufLen - 1;
final int head = this.head;
final int tail = this.tail;
final int leftChunk = Math.abs(index - head) % bufLen;
final int rightChunk = Math.abs(tail - index) % bufLen;
if (leftChunk < rightChunk) {
if (index >= head) {
System.arraycopy(buffer, head, buffer, head + 1, leftChunk);
} else {
System.arraycopy(buffer, 0, buffer, 1, index);
buffer[0] = buffer[lastIndex];
System.arraycopy(buffer, head, buffer, head + 1, lastIndex - head);
}
buffer[head] = 0;
this.head = oneRight(head, bufLen);
} else {
if (index < tail) {
System.arraycopy(buffer, index + 1, buffer, index, rightChunk);
} else {
System.arraycopy(buffer, index + 1, buffer, index, lastIndex - index);
buffer[lastIndex] = buffer[0];
System.arraycopy(buffer, 1, buffer, 0, tail);
}
buffer[tail] = 0;
this.tail = oneLeft(tail, bufLen);
}
}
/** {@inheritDoc} */
@Override
public boolean isEmpty() {
return size() == 0;
}
/** {@inheritDoc} */
@Override
public int size() {
if (head <= tail) return tail - head;
else return (tail - head + buffer.length);
}
/**
* {@inheritDoc}
*
* <p>The internal array buffers are not released as a result of this call.
*
* @see #release()
*/
@Override
public void clear() {
if (head < tail) {
Arrays.fill(buffer, head, tail, 0);
} else {
Arrays.fill(buffer, 0, tail, 0);
Arrays.fill(buffer, head, buffer.length, 0);
}
this.head = tail = 0;
}
/** Release internal buffers of this deque and reallocate with the default buffer. */
public void release() {
this.head = tail = 0;
buffer = IntArrayList.EMPTY_ARRAY;
ensureBufferSpace(0);
}
/**
* Ensure this container can hold at least the given number of elements without resizing its
* buffers.
*
* @param expectedElements The total number of elements, inclusive.
*/
@Override
public void ensureCapacity(int expectedElements) {
ensureBufferSpace(expectedElements - size());
}
/**
* Ensures the internal buffer has enough free slots to store <code>expectedAdditions</code>.
* Increases internal buffer size if needed.
*/
protected void ensureBufferSpace(int expectedAdditions) {
final int bufferLen = buffer.length;
final int elementsCount = size();
if (elementsCount + expectedAdditions >= bufferLen) {
final int emptySlot = 1; // deque invariant: always an empty slot.
final int newSize = resizer.grow(bufferLen, elementsCount + emptySlot, expectedAdditions);
assert newSize >= (elementsCount + expectedAdditions + emptySlot)
: "Resizer failed to"
+ " return sensible new size: "
+ newSize
+ " <= "
+ (elementsCount + expectedAdditions);
try {
final int[] newBuffer = (new int[newSize]);
if (bufferLen > 0) {
toArray(newBuffer);
tail = elementsCount;
head = 0;
}
this.buffer = newBuffer;
} catch (OutOfMemoryError e) {
throw new BufferAllocationException(
"Not enough memory to allocate new buffers: %,d -> %,d", e, bufferLen, newSize);
}
}
}
/** {@inheritDoc} */
@Override
public int[] toArray() {
final int size = size();
return toArray((new int[size]));
}
/**
* Copies elements of this deque to an array. The content of the <code>target</code> array is
* filled from index 0 (head of the queue) to index <code>size() - 1</code> (tail of the queue).
*
* @param target The target array must be large enough to hold all elements.
* @return Returns the target argument for chaining.
*/
public int[] toArray(int[] target) {
assert target.length >= size() : "Target array must be >= " + size();
if (head < tail) {
// The contents is not wrapped around. Just copy.
System.arraycopy(buffer, head, target, 0, size());
} else if (head > tail) {
// The contents is split. Merge elements from the following indexes:
// [head...buffer.length - 1][0, tail - 1]
final int rightCount = buffer.length - head;
System.arraycopy(buffer, head, target, 0, rightCount);
System.arraycopy(buffer, 0, target, rightCount, tail);
}
return target;
}
/**
* Clone this object. The returned clone will reuse the same hash function and array resizing
* strategy.
*/
@Override
public IntArrayDeque clone() {
try {
IntArrayDeque cloned = (IntArrayDeque) super.clone();
cloned.buffer = buffer.clone();
return cloned;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
/** Move one index to the left, wrapping around buffer. */
protected static int oneLeft(int index, int modulus) {
if (index >= 1) {
return index - 1;
}
return modulus - 1;
}
/** Move one index to the right, wrapping around buffer. */
protected static int oneRight(int index, int modulus) {
if (index + 1 == modulus) {
return 0;
}
return index + 1;
}
@Override
public long ramBytesAllocated() {
// int: head, tail
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ Integer.BYTES * 2
+ resizer.ramBytesAllocated()
+ RamUsageEstimator.shallowSizeOfArray(buffer);
}
@Override
public long ramBytesUsed() {
// int: head, tail
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ Integer.BYTES * 2
+ resizer.ramBytesUsed()
+ RamUsageEstimator.shallowUsedSizeOfArray(buffer, size());
}
/** An iterator implementation for {@link ObjectArrayDeque#iterator}. */
private final class ValueIterator extends AbstractIterator<IntCursor> {
private final IntCursor cursor;
private int remaining;
public ValueIterator() {
cursor = new IntCursor();
cursor.index = oneLeft(head, buffer.length);
this.remaining = size();
}
@Override
protected IntCursor fetch() {
if (remaining == 0) {
return done();
}
remaining--;
cursor.value = buffer[cursor.index = oneRight(cursor.index, buffer.length)];
return cursor;
}
}
/** An iterator implementation for {@link ObjectArrayDeque#descendingIterator()}. */
private final class DescendingValueIterator extends AbstractIterator<IntCursor> {
private final IntCursor cursor;
private int remaining;
public DescendingValueIterator() {
cursor = new IntCursor();
cursor.index = tail;
this.remaining = size();
}
@Override
protected IntCursor fetch() {
if (remaining == 0) return done();
remaining--;
cursor.value = buffer[cursor.index = oneLeft(cursor.index, buffer.length)];
return cursor;
}
}
/**
* Returns a cursor over the values of this deque (in head to tail order). The iterator is
* implemented as a cursor and it returns <b>the same cursor instance</b> on every call to {@link
* Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in
* the deque's buffer) use the cursor's public fields. An example is shown below.
*
* <pre>
* for (IntValueCursor c : intDeque) {
* System.out.println(&quot;buffer index=&quot; + c.index + &quot; value=&quot; + c.value);
* }
* </pre>
*/
public Iterator<IntCursor> iterator() {
return new ValueIterator();
}
/**
* Returns a cursor over the values of this deque (in tail to head order). The iterator is
* implemented as a cursor and it returns <b>the same cursor instance</b> on every call to {@link
* Iterator#next()} (to avoid boxing of primitive types). To read the current value (or index in
* the deque's buffer) use the cursor's public fields. An example is shown below.
*
* <pre>
* for (Iterator&lt;IntCursor&gt; i = intDeque.descendingIterator(); i.hasNext();) {
* final IntCursor c = i.next();
* System.out.println(&quot;buffer index=&quot; + c.index + &quot; value=&quot; + c.value);
* }
* </pre>
*/
public Iterator<IntCursor> descendingIterator() {
return new DescendingValueIterator();
}
/** {@inheritDoc} */
@Override
public <T extends IntProcedure> T forEach(T procedure) {
forEach(procedure, head, tail);
return procedure;
}
/**
* Applies <code>procedure</code> to a slice of the deque, <code>fromIndex</code>, inclusive, to
* <code>toIndex</code>, exclusive.
*/
private void forEach(IntProcedure procedure, int fromIndex, final int toIndex) {
final int[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
procedure.apply(buffer[i]);
}
}
/** {@inheritDoc} */
@Override
public <T extends IntPredicate> T forEach(T predicate) {
int fromIndex = head;
int toIndex = tail;
final int[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
if (!predicate.apply(buffer[i])) {
break;
}
}
return predicate;
}
/** Applies <code>procedure</code> to all elements of this deque, tail to head. */
@Override
public <T extends IntProcedure> T descendingForEach(T procedure) {
descendingForEach(procedure, head, tail);
return procedure;
}
/**
* Applies <code>procedure</code> to a slice of the deque, <code>toIndex</code>, exclusive, down
* to <code>fromIndex</code>, inclusive.
*/
private void descendingForEach(IntProcedure procedure, int fromIndex, final int toIndex) {
if (fromIndex == toIndex) return;
final int[] buffer = this.buffer;
int i = toIndex;
do {
i = oneLeft(i, buffer.length);
procedure.apply(buffer[i]);
} while (i != fromIndex);
}
/** {@inheritDoc} */
@Override
public <T extends IntPredicate> T descendingForEach(T predicate) {
descendingForEach(predicate, head, tail);
return predicate;
}
/**
* Applies <code>predicate</code> to a slice of the deque, <code>toIndex</code>, exclusive, down
* to <code>fromIndex</code>, inclusive or until the predicate returns <code>false</code>.
*/
private void descendingForEach(IntPredicate predicate, int fromIndex, final int toIndex) {
if (fromIndex == toIndex) return;
final int[] buffer = this.buffer;
int i = toIndex;
do {
i = oneLeft(i, buffer.length);
if (!predicate.apply(buffer[i])) {
break;
}
} while (i != fromIndex);
}
/** {@inheritDoc} */
@Override
public int removeAll(IntPredicate predicate) {
final int[] buffer = this.buffer;
final int last = tail;
final int bufLen = buffer.length;
int removed = 0;
int from, to;
from = to = head;
try {
for (from = to = head; from != last; from = oneRight(from, bufLen)) {
if (predicate.apply(buffer[from])) {
buffer[from] = 0;
removed++;
continue;
}
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = 0;
}
to = oneRight(to, bufLen);
}
} finally {
// Keep the deque in consistent state even if the predicate throws an exception.
for (; from != last; from = oneRight(from, bufLen)) {
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = 0;
}
to = oneRight(to, bufLen);
}
tail = to;
}
return removed;
}
/** {@inheritDoc} */
@Override
public boolean contains(int e) {
int fromIndex = head;
int toIndex = tail;
final int[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
if (((e) == (buffer[i]))) {
return true;
}
}
return false;
}
/** {@inheritDoc} */
@Override
public int hashCode() {
int h = 1;
int fromIndex = head;
int toIndex = tail;
final int[] buffer = this.buffer;
for (int i = fromIndex; i != toIndex; i = oneRight(i, buffer.length)) {
h = 31 * h + BitMixer.mix(this.buffer[i]);
}
return h;
}
/**
* Returns <code>true</code> only if the other object is an instance of the same class and with
* the same elements.
*/
@Override
public boolean equals(Object obj) {
return (this == obj)
|| (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj)));
}
/** Compare order-aligned elements against another {@link IntDeque}. */
protected boolean equalElements(IntArrayDeque other) {
int max = size();
if (other.size() != max) {
return false;
}
Iterator<IntCursor> i1 = this.iterator();
Iterator<? extends IntCursor> i2 = other.iterator();
while (i1.hasNext() && i2.hasNext()) {
if (!((i1.next().value) == (i2.next().value))) {
return false;
}
}
return !i1.hasNext() && !i2.hasNext();
}
/** Create a new deque by pushing a variable number of arguments to the end of it. */
public static IntArrayDeque from(int... elements) {
final IntArrayDeque coll = new IntArrayDeque(elements.length);
coll.addLast(elements);
return coll;
}
}

View File

@ -0,0 +1,586 @@
package com.carrotsearch.hppc;
import static com.carrotsearch.hppc.Containers.*;
import com.carrotsearch.hppc.cursors.*;
import com.carrotsearch.hppc.predicates.IntPredicate;
import com.carrotsearch.hppc.procedures.*;
import java.util.*;
import java.util.stream.IntStream;
/** An array-backed list of ints. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeArrayList.java")
public class IntArrayList extends AbstractIntCollection
implements IntIndexedContainer, Preallocable, Cloneable, Accountable {
/** An immutable empty buffer (array). */
public static final int[] EMPTY_ARRAY = new int[0];
;
/** Reuse the same strategy instance. */
private static final BoundedProportionalArraySizingStrategy DEFAULT_SIZING_STRATEGY =
BoundedProportionalArraySizingStrategy.DEFAULT_INSTANCE;
/**
* Internal array for storing the list. The array may be larger than the current size ({@link
* #size()}).
*/
public int[] buffer = EMPTY_ARRAY;
/** Current number of elements stored in {@link #buffer}. */
public int elementsCount;
/** Buffer resizing strategy. */
protected final ArraySizingStrategy resizer;
/** New instance with sane defaults. */
public IntArrayList() {
this(DEFAULT_EXPECTED_ELEMENTS);
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
*/
public IntArrayList(int expectedElements) {
this(expectedElements, DEFAULT_SIZING_STRATEGY);
}
/**
* New instance with sane defaults.
*
* @param expectedElements The expected number of elements guaranteed not to cause buffer
* expansion (inclusive).
* @param resizer Underlying buffer sizing strategy.
*/
public IntArrayList(int expectedElements, ArraySizingStrategy resizer) {
assert resizer != null;
this.resizer = resizer;
buffer = Arrays.copyOf(buffer, expectedElements);
}
/** Creates a new list from the elements of another container in its iteration order. */
public IntArrayList(IntContainer container) {
this(container.size());
addAll(container);
}
/** {@inheritDoc} */
@Override
public void add(int e1) {
ensureBufferSpace(1);
buffer[elementsCount++] = e1;
}
/**
* Appends two elements at the end of the list. To add more than two elements, use <code>add
* </code> (vararg-version) or access the buffer directly (tight loop).
*/
public void add(int e1, int e2) {
ensureBufferSpace(2);
buffer[elementsCount++] = e1;
buffer[elementsCount++] = e2;
}
/** Add all elements from a range of given array to the list. */
public void add(int[] elements, int start, int length) {
assert length >= 0 : "Length must be >= 0";
ensureBufferSpace(length);
System.arraycopy(elements, start, buffer, elementsCount, length);
elementsCount += length;
}
/**
* Vararg-signature method for adding elements at the end of the list.
*
* <p><b>This method is handy, but costly if used in tight loops (anonymous array passing)</b>
*/
public final void add(int... elements) {
add(elements, 0, elements.length);
}
/** Adds all elements from another container. */
public int addAll(IntContainer container) {
final int size = container.size();
ensureBufferSpace(size);
for (IntCursor cursor : container) {
add(cursor.value);
}
return size;
}
/** Adds all elements from another iterable. */
public int addAll(Iterable<? extends IntCursor> iterable) {
int size = 0;
for (IntCursor cursor : iterable) {
add(cursor.value);
size++;
}
return size;
}
/** {@inheritDoc} */
@Override
public void insert(int index, int e1) {
assert (index >= 0 && index <= size())
: "Index " + index + " out of bounds [" + 0 + ", " + size() + "].";
ensureBufferSpace(1);
System.arraycopy(buffer, index, buffer, index + 1, elementsCount - index);
buffer[index] = e1;
elementsCount++;
}
/** {@inheritDoc} */
@Override
public int get(int index) {
assert (index >= 0 && index < size())
: "Index " + index + " out of bounds [" + 0 + ", " + size() + ").";
return buffer[index];
}
/** {@inheritDoc} */
@Override
public int set(int index, int e1) {
assert (index >= 0 && index < size())
: "Index " + index + " out of bounds [" + 0 + ", " + size() + ").";
final int v = buffer[index];
buffer[index] = e1;
return v;
}
/** {@inheritDoc} */
@Override
public int removeAt(int index) {
assert (index >= 0 && index < size())
: "Index " + index + " out of bounds [" + 0 + ", " + size() + ").";
final int v = buffer[index];
System.arraycopy(buffer, index + 1, buffer, index, --elementsCount - index);
return v;
}
/** {@inheritDoc} */
@Override
public int removeLast() {
assert elementsCount > 0;
final int v = buffer[--elementsCount];
return v;
}
/** {@inheritDoc} */
@Override
public void removeRange(int fromIndex, int toIndex) {
assert (fromIndex >= 0 && fromIndex <= size())
: "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ").";
assert (toIndex >= 0 && toIndex <= size())
: "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "].";
assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex;
System.arraycopy(buffer, toIndex, buffer, fromIndex, elementsCount - toIndex);
final int count = toIndex - fromIndex;
elementsCount -= count;
}
/** {@inheritDoc} */
@Override
public boolean removeElement(int e1) {
return removeFirst(e1) != -1;
}
/** {@inheritDoc} */
@Override
public int removeFirst(int e1) {
final int index = indexOf(e1);
if (index >= 0) removeAt(index);
return index;
}
/** {@inheritDoc} */
@Override
public int removeLast(int e1) {
final int index = lastIndexOf(e1);
if (index >= 0) removeAt(index);
return index;
}
/** {@inheritDoc} */
@Override
public int removeAll(int e1) {
int to = 0;
for (int from = 0; from < elementsCount; from++) {
if (((e1) == (buffer[from]))) {
continue;
}
if (to != from) {
buffer[to] = buffer[from];
}
to++;
}
final int deleted = elementsCount - to;
this.elementsCount = to;
return deleted;
}
/** {@inheritDoc} */
@Override
public boolean contains(int e1) {
return indexOf(e1) >= 0;
}
/** {@inheritDoc} */
@Override
public int indexOf(int e1) {
for (int i = 0; i < elementsCount; i++) {
if (((e1) == (buffer[i]))) {
return i;
}
}
return -1;
}
/** {@inheritDoc} */
@Override
public int lastIndexOf(int e1) {
for (int i = elementsCount - 1; i >= 0; i--) {
if (((e1) == (buffer[i]))) {
return i;
}
}
return -1;
}
/** {@inheritDoc} */
@Override
public boolean isEmpty() {
return elementsCount == 0;
}
/**
* Ensure this container can hold at least the given number of elements without resizing its
* buffers.
*
* @param expectedElements The total number of elements, inclusive.
*/
@Override
public void ensureCapacity(int expectedElements) {
final int bufferLen = (buffer == null ? 0 : buffer.length);
if (expectedElements > bufferLen) {
ensureBufferSpace(expectedElements - size());
}
}
/**
* Ensures the internal buffer has enough free slots to store <code>expectedAdditions</code>.
* Increases internal buffer size if needed.
*/
protected void ensureBufferSpace(int expectedAdditions) {
final int bufferLen = (buffer == null ? 0 : buffer.length);
if (elementsCount + expectedAdditions > bufferLen) {
final int newSize = resizer.grow(bufferLen, elementsCount, expectedAdditions);
assert newSize >= elementsCount + expectedAdditions
: "Resizer failed to"
+ " return sensible new size: "
+ newSize
+ " <= "
+ (elementsCount + expectedAdditions);
this.buffer = Arrays.copyOf(buffer, newSize);
}
}
/**
* Truncate or expand the list to the new size. If the list is truncated, the buffer will not be
* reallocated (use {@link #trimToSize()} if you need a truncated buffer), but the truncated
* values will be reset to the default value (zero). If the list is expanded, the elements beyond
* the current size are initialized with JVM-defaults (zero or <code>null</code> values).
*/
public void resize(int newSize) {
if (newSize <= buffer.length) {
if (newSize < elementsCount) {
Arrays.fill(buffer, newSize, elementsCount, 0);
} else {
Arrays.fill(buffer, elementsCount, newSize, 0);
}
} else {
ensureCapacity(newSize);
}
this.elementsCount = newSize;
}
/** {@inheritDoc} */
@Override
public int size() {
return elementsCount;
}
/** Trim the internal buffer to the current size. */
public void trimToSize() {
if (size() != this.buffer.length) {
this.buffer = toArray();
}
}
/**
* Sets the number of stored elements to zero. Releases and initializes the internal storage array
* to default values. To clear the list without cleaning the buffer, simply set the {@link
* #elementsCount} field to zero.
*/
@Override
public void clear() {
Arrays.fill(buffer, 0, elementsCount, 0);
this.elementsCount = 0;
}
/** Sets the number of stored elements to zero and releases the internal storage array. */
@Override
public void release() {
this.buffer = EMPTY_ARRAY;
this.elementsCount = 0;
}
/**
* {@inheritDoc}
*
* <p>The returned array is sized to match exactly the number of elements of the stack.
*/
@Override
public int[] toArray() {
return Arrays.copyOf(buffer, elementsCount);
}
@Override
public IntStream stream() {
return Arrays.stream(buffer, 0, size());
}
/** {@inheritDoc} */
@Override
public IntIndexedContainer sort() {
Arrays.sort(buffer, 0, elementsCount);
return this;
}
/** {@inheritDoc} */
@Override
public IntIndexedContainer reverse() {
for (int i = 0, mid = elementsCount >> 1, j = elementsCount - 1; i < mid; i++, j--) {
int tmp = buffer[i];
buffer[i] = buffer[j];
buffer[j] = tmp;
}
return this;
}
/**
* Clone this object. The returned clone will reuse the same hash function and array resizing
* strategy.
*/
@Override
public IntArrayList clone() {
try {
final IntArrayList cloned = (IntArrayList) super.clone();
cloned.buffer = buffer.clone();
return cloned;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
/** {@inheritDoc} */
@Override
public int hashCode() {
int h = 1, max = elementsCount;
for (int i = 0; i < max; i++) {
h = 31 * h + BitMixer.mix(this.buffer[i]);
}
return h;
}
/**
* Returns <code>true</code> only if the other object is an instance of the same class and with
* the same elements.
*/
@Override
public boolean equals(Object obj) {
return (this == obj)
|| (obj != null && getClass() == obj.getClass() && equalElements(getClass().cast(obj)));
}
/** Compare index-aligned elements against another {@link IntIndexedContainer}. */
protected boolean equalElements(IntArrayList other) {
int max = size();
if (other.size() != max) {
return false;
}
for (int i = 0; i < max; i++) {
if (!((get(i)) == (other.get(i)))) {
return false;
}
}
return true;
}
@Override
public long ramBytesAllocated() {
// int: elementsCount
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ Integer.BYTES
+ resizer.ramBytesAllocated()
+ RamUsageEstimator.shallowSizeOfArray(buffer);
}
@Override
public long ramBytesUsed() {
// int: elementsCount
return RamUsageEstimator.NUM_BYTES_OBJECT_HEADER
+ Integer.BYTES
+ resizer.ramBytesUsed()
+ RamUsageEstimator.shallowUsedSizeOfArray(buffer, elementsCount);
}
/** An iterator implementation for {@link IntArrayList#iterator}. */
static final class ValueIterator extends AbstractIterator<IntCursor> {
private final IntCursor cursor;
private final int[] buffer;
private final int size;
public ValueIterator(int[] buffer, int size) {
this.cursor = new IntCursor();
this.cursor.index = -1;
this.size = size;
this.buffer = buffer;
}
@Override
protected IntCursor fetch() {
if (cursor.index + 1 == size) return done();
cursor.value = buffer[++cursor.index];
return cursor;
}
}
/** {@inheritDoc} */
@Override
public Iterator<IntCursor> iterator() {
return new ValueIterator(buffer, size());
}
/** {@inheritDoc} */
@Override
public <T extends IntProcedure> T forEach(T procedure) {
return forEach(procedure, 0, size());
}
/**
* Applies <code>procedure</code> to a slice of the list, <code>fromIndex</code>, inclusive, to
* <code>toIndex</code>, exclusive.
*/
public <T extends IntProcedure> T forEach(T procedure, int fromIndex, final int toIndex) {
assert (fromIndex >= 0 && fromIndex <= size())
: "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ").";
assert (toIndex >= 0 && toIndex <= size())
: "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "].";
assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex;
final int[] buffer = this.buffer;
for (int i = fromIndex; i < toIndex; i++) {
procedure.apply(buffer[i]);
}
return procedure;
}
/** {@inheritDoc} */
@Override
public int removeAll(IntPredicate predicate) {
final int[] buffer = this.buffer;
final int elementsCount = this.elementsCount;
int to = 0;
int from = 0;
try {
for (; from < elementsCount; from++) {
if (predicate.apply(buffer[from])) {
buffer[from] = 0;
continue;
}
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = 0;
}
to++;
}
} finally {
// Keep the list in a consistent state, even if the predicate throws an exception.
for (; from < elementsCount; from++) {
if (to != from) {
buffer[to] = buffer[from];
buffer[from] = 0;
}
to++;
}
this.elementsCount = to;
}
return elementsCount - to;
}
/** {@inheritDoc} */
@Override
public <T extends IntPredicate> T forEach(T predicate) {
return forEach(predicate, 0, size());
}
/**
* Applies <code>predicate</code> to a slice of the list, <code>fromIndex</code>, inclusive, to
* <code>toIndex</code>, exclusive, or until predicate returns <code>false</code>.
*/
public <T extends IntPredicate> T forEach(T predicate, int fromIndex, final int toIndex) {
assert (fromIndex >= 0 && fromIndex <= size())
: "Index " + fromIndex + " out of bounds [" + 0 + ", " + size() + ").";
assert (toIndex >= 0 && toIndex <= size())
: "Index " + toIndex + " out of bounds [" + 0 + ", " + size() + "].";
assert fromIndex <= toIndex : "fromIndex must be <= toIndex: " + fromIndex + ", " + toIndex;
final int[] buffer = this.buffer;
for (int i = fromIndex; i < toIndex; i++) {
if (!predicate.apply(buffer[i])) break;
}
return predicate;
}
/**
* Create a list from a variable number of arguments or an array of <code>int</code>. The elements
* are copied from the argument to the internal buffer.
*/
public static IntArrayList from(int... elements) {
final IntArrayList list = new IntArrayList(elements.length);
list.add(elements);
return list;
}
}

View File

@ -0,0 +1,33 @@
package com.carrotsearch.hppc;
/**
* Reused buffer visualization routines.
*
* @see IntSet#visualizeKeyDistribution(int)
* @see IntVTypeMap#visualizeKeyDistribution(int)
*/
class IntBufferVisualizer {
static String visualizeKeyDistribution(int[] buffer, int max, int characters) {
final StringBuilder b = new StringBuilder();
final char[] chars = ".123456789X".toCharArray();
for (int i = 1, start = -1; i <= characters; i++) {
int end = (int) ((long) i * max / characters);
if (start + 1 <= end) {
int taken = 0;
int slots = 0;
for (int slot = start + 1; slot <= end; slot++, slots++) {
if (!((buffer[slot]) == 0)) {
taken++;
}
}
b.append(chars[Math.min(chars.length - 1, taken * chars.length / slots)]);
start = end;
}
}
while (b.length() < characters) {
b.append(' ');
}
return b.toString();
}
}

View File

@ -0,0 +1,105 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.*;
import com.carrotsearch.hppc.predicates.*;
import com.carrotsearch.hppc.procedures.*;
import java.util.Iterator;
/**
* An associative container from keys to (one or possibly more) values.
*
* @see IntContainer
*/
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "KTypeVTypeAssociativeContainer.java")
public interface IntByteAssociativeContainer extends Iterable<IntByteCursor> {
/**
* Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as
* a cursor and it returns <b>the same cursor instance</b> on every call to {@link
* Iterator#next()}. To read the current key and value use the cursor's public fields. An example
* is shown below.
*
* <pre>
* for (IntShortCursor c : intShortMap) {
* System.out.println(&quot;index=&quot; + c.index + &quot; key=&quot; + c.key + &quot; value=&quot; + c.value);
* }</pre>
*
* <p>The <code>index</code> field inside the cursor gives the internal index inside the
* container's implementation. The interpretation of this index depends on to the container.
*/
@Override
public Iterator<IntByteCursor> iterator();
/**
* Returns <code>true</code> if this container has an association to a value for the given key.
*/
public boolean containsKey(int key);
/**
* @return Returns the current size (number of assigned keys) in the container.
*/
public int size();
/**
* @return Return <code>true</code> if this hash map contains no assigned keys.
*/
public boolean isEmpty();
/**
* Removes all keys (and associated values) present in a given container. An alias to:
*
* <pre>
* keys().removeAll(container)
* </pre>
*
* but with no additional overhead.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(IntContainer container);
/**
* Removes all keys (and associated values) for which the predicate returns <code>true</code>.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(IntPredicate predicate);
/**
* Removes all keys (and associated values) for which the predicate returns <code>true</code>.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(IntBytePredicate predicate);
/**
* Applies a given procedure to all keys-value pairs in this container. Returns the argument (any
* subclass of {@link IntByteProcedure}. This lets the caller call methods of the argument by
* chaining the call (even if the argument is an anonymous type) to retrieve computed values.
*/
public <T extends IntByteProcedure> T forEach(T procedure);
/**
* Applies a given predicate to all keys-value pairs in this container. Returns the argument (any
* subclass of {@link IntBytePredicate}. This lets the caller call methods of the argument by
* chaining the call (even if the argument is an anonymous type) to retrieve computed values.
*
* <p>The iteration is continued as long as the predicate returns <code>true</code>.
*/
public <T extends IntBytePredicate> T forEach(T predicate);
/**
* Returns a collection of keys of this container. The returned collection is a view over the key
* set and any modifications (if allowed) introduced to the collection will propagate to the
* associative container immediately.
*/
public IntCollection keys();
/**
* Returns a container view of all values present in this container. The returned collection is a
* view over the key set and any modifications (if allowed) introduced to the collection will
* propagate to the associative container immediately.
*/
public ByteContainer values();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,205 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.IntByteCursor;
/** An associative container with unique binding from keys to a single value. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java")
public interface IntByteMap extends IntByteAssociativeContainer {
/**
* @return Returns the value associated with the given key or the default value for the value
* type, if the key is not associated with any value. For numeric value types, this default
* value is 0, for object types it is {@code null}.
*/
public byte get(int key);
/**
* @return Returns the value associated with the given key or the provided default value if the
* key is not associated with any value.
*/
public byte getOrDefault(int key, byte defaultValue);
/**
* Place a given key and value in the container.
*
* @return The value previously stored under the given key in the map is returned.
*/
public byte put(int key, byte value);
/**
* If the specified key is not already associated with a value, associates it with the given
* value.
*
* @return {@code true} if {@code key} did not exist and {@code value} was placed in the map,
* {@code false} otherwise.
*/
public default boolean putIfAbsent(int key, byte value) {
int keyIndex = indexOf(key);
if (indexExists(keyIndex)) {
return false;
} else {
indexInsert(keyIndex, key, value);
return true;
}
}
/**
* Puts all keys from another container to this map, replacing the values of existing keys, if
* such keys are present.
*
* @return Returns the number of keys added to the map as a result of this call (not previously
* present in the map). Values of existing keys are overwritten.
*/
public int putAll(IntByteAssociativeContainer container);
/**
* Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if
* such keys are present.
*
* @return Returns the number of keys added to the map as a result of this call (not previously
* present in the map). Values of existing keys are overwritten.
*/
public int putAll(Iterable<? extends IntByteCursor> iterable);
/**
* If <code>key</code> exists, <code>putValue</code> is inserted into the map, otherwise any
* existing value is incremented by <code>additionValue</code>.
*
* @param key The key of the value to adjust.
* @param putValue The value to put if <code>key</code> does not exist.
* @param incrementValue The value to add to the existing value if <code>key</code> exists.
* @return Returns the current value associated with <code>key</code> (after changes).
*/
public byte putOrAdd(int key, byte putValue, byte incrementValue);
/**
* An equivalent of calling
*
* <pre>
* putOrAdd(key, additionValue, additionValue);
* </pre>
*
* @param key The key of the value to adjust.
* @param additionValue The value to put or add to the existing value if <code>key</code> exists.
* @return Returns the current value associated with <code>key</code> (after changes).
*/
public byte addTo(int key, byte additionValue);
/**
* Remove all values at the given key. The default value for the key type is returned if the value
* does not exist in the map.
*/
public byte remove(int key);
/**
* Compares the specified object with this set for equality. Returns {@code true} if and only if
* the specified object is also a {@link IntByteMap} and both objects contains exactly the same
* key-value pairs.
*/
public boolean equals(Object obj);
/**
* @return A hash code of elements stored in the map. The hash code is defined as a sum of hash
* codes of keys and values stored within the set). Because sum is commutative, this ensures
* that different order of elements in a set does not affect the hash code.
*/
public int hashCode();
/**
* Returns a logical "index" of a given key that can be used to speed up follow-up value setters
* or getters in certain scenarios (conditional logic).
*
* <p>The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be)
* contiguous.
*
* <p>The index is valid only between map modifications (it will not be affected by read-only
* operations like iteration or value retrievals).
*
* @see #indexExists
* @see #indexGet
* @see #indexInsert
* @see #indexReplace
* @param key The key to locate in the map.
* @return A non-negative value of the logical "index" of the key in the map or a negative value
* if the key did not exist.
*/
public int indexOf(int key);
/**
* @see #indexOf
* @param index The index of a given key, as returned from {@link #indexOf}.
* @return Returns <code>true</code> if the index corresponds to an existing key or false
* otherwise. This is equivalent to checking whether the index is a positive value (existing
* keys) or a negative value (non-existing keys).
*/
public boolean indexExists(int index);
/**
* Returns the value associated with an existing key.
*
* @see #indexOf
* @param index The index of an existing key.
* @return Returns the value currently associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public byte indexGet(int index);
/**
* Replaces the value associated with an existing key and returns any previous value stored for
* that key.
*
* @see #indexOf
* @param index The index of an existing key.
* @return Returns the previous value associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public byte indexReplace(int index, byte newValue);
/**
* Inserts a key-value pair for a key that is not present in the map. This method may help in
* avoiding double recalculation of the key's hash.
*
* @see #indexOf
* @param index The index of a previously non-existing key, as returned from {@link #indexOf}.
* @throws AssertionError If assertions are enabled and the index corresponds to an existing key.
*/
public void indexInsert(int index, int key, byte value);
/**
* Removes a key-value pair at an index previously acquired from {@link #indexOf}.
*
* @see #indexOf
* @param index The index of the key to remove, as returned from {@link #indexOf}.
* @return Returns the previous value associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public byte indexRemove(int index);
/**
* Clear all keys and values in the container.
*
* @see #release()
*/
public void clear();
/**
* Removes all elements from the collection and additionally releases any internal buffers.
* Typically, if the object is to be reused, a simple {@link #clear()} should be a better
* alternative since it'll avoid reallocation.
*
* @see #clear()
*/
public void release();
/**
* Visually depict the distribution of keys.
*
* @param characters The number of characters to "squeeze" the entire buffer into.
* @return Returns a sequence of characters where '.' depicts an empty fragment of the internal
* buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything
* between 1 and 9 is between.
*/
public String visualizeKeyDistribution(int characters);
}

View File

@ -0,0 +1,105 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.*;
import com.carrotsearch.hppc.predicates.*;
import com.carrotsearch.hppc.procedures.*;
import java.util.Iterator;
/**
* An associative container from keys to (one or possibly more) values.
*
* @see IntContainer
*/
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "KTypeVTypeAssociativeContainer.java")
public interface IntCharAssociativeContainer extends Iterable<IntCharCursor> {
/**
* Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as
* a cursor and it returns <b>the same cursor instance</b> on every call to {@link
* Iterator#next()}. To read the current key and value use the cursor's public fields. An example
* is shown below.
*
* <pre>
* for (IntShortCursor c : intShortMap) {
* System.out.println(&quot;index=&quot; + c.index + &quot; key=&quot; + c.key + &quot; value=&quot; + c.value);
* }</pre>
*
* <p>The <code>index</code> field inside the cursor gives the internal index inside the
* container's implementation. The interpretation of this index depends on to the container.
*/
@Override
public Iterator<IntCharCursor> iterator();
/**
* Returns <code>true</code> if this container has an association to a value for the given key.
*/
public boolean containsKey(int key);
/**
* @return Returns the current size (number of assigned keys) in the container.
*/
public int size();
/**
* @return Return <code>true</code> if this hash map contains no assigned keys.
*/
public boolean isEmpty();
/**
* Removes all keys (and associated values) present in a given container. An alias to:
*
* <pre>
* keys().removeAll(container)
* </pre>
*
* but with no additional overhead.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(IntContainer container);
/**
* Removes all keys (and associated values) for which the predicate returns <code>true</code>.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(IntPredicate predicate);
/**
* Removes all keys (and associated values) for which the predicate returns <code>true</code>.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(IntCharPredicate predicate);
/**
* Applies a given procedure to all keys-value pairs in this container. Returns the argument (any
* subclass of {@link IntCharProcedure}. This lets the caller call methods of the argument by
* chaining the call (even if the argument is an anonymous type) to retrieve computed values.
*/
public <T extends IntCharProcedure> T forEach(T procedure);
/**
* Applies a given predicate to all keys-value pairs in this container. Returns the argument (any
* subclass of {@link IntCharPredicate}. This lets the caller call methods of the argument by
* chaining the call (even if the argument is an anonymous type) to retrieve computed values.
*
* <p>The iteration is continued as long as the predicate returns <code>true</code>.
*/
public <T extends IntCharPredicate> T forEach(T predicate);
/**
* Returns a collection of keys of this container. The returned collection is a view over the key
* set and any modifications (if allowed) introduced to the collection will propagate to the
* associative container immediately.
*/
public IntCollection keys();
/**
* Returns a container view of all values present in this container. The returned collection is a
* view over the key set and any modifications (if allowed) introduced to the collection will
* propagate to the associative container immediately.
*/
public CharContainer values();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,205 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.IntCharCursor;
/** An associative container with unique binding from keys to a single value. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java")
public interface IntCharMap extends IntCharAssociativeContainer {
/**
* @return Returns the value associated with the given key or the default value for the value
* type, if the key is not associated with any value. For numeric value types, this default
* value is 0, for object types it is {@code null}.
*/
public char get(int key);
/**
* @return Returns the value associated with the given key or the provided default value if the
* key is not associated with any value.
*/
public char getOrDefault(int key, char defaultValue);
/**
* Place a given key and value in the container.
*
* @return The value previously stored under the given key in the map is returned.
*/
public char put(int key, char value);
/**
* If the specified key is not already associated with a value, associates it with the given
* value.
*
* @return {@code true} if {@code key} did not exist and {@code value} was placed in the map,
* {@code false} otherwise.
*/
public default boolean putIfAbsent(int key, char value) {
int keyIndex = indexOf(key);
if (indexExists(keyIndex)) {
return false;
} else {
indexInsert(keyIndex, key, value);
return true;
}
}
/**
* Puts all keys from another container to this map, replacing the values of existing keys, if
* such keys are present.
*
* @return Returns the number of keys added to the map as a result of this call (not previously
* present in the map). Values of existing keys are overwritten.
*/
public int putAll(IntCharAssociativeContainer container);
/**
* Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if
* such keys are present.
*
* @return Returns the number of keys added to the map as a result of this call (not previously
* present in the map). Values of existing keys are overwritten.
*/
public int putAll(Iterable<? extends IntCharCursor> iterable);
/**
* If <code>key</code> exists, <code>putValue</code> is inserted into the map, otherwise any
* existing value is incremented by <code>additionValue</code>.
*
* @param key The key of the value to adjust.
* @param putValue The value to put if <code>key</code> does not exist.
* @param incrementValue The value to add to the existing value if <code>key</code> exists.
* @return Returns the current value associated with <code>key</code> (after changes).
*/
public char putOrAdd(int key, char putValue, char incrementValue);
/**
* An equivalent of calling
*
* <pre>
* putOrAdd(key, additionValue, additionValue);
* </pre>
*
* @param key The key of the value to adjust.
* @param additionValue The value to put or add to the existing value if <code>key</code> exists.
* @return Returns the current value associated with <code>key</code> (after changes).
*/
public char addTo(int key, char additionValue);
/**
* Remove all values at the given key. The default value for the key type is returned if the value
* does not exist in the map.
*/
public char remove(int key);
/**
* Compares the specified object with this set for equality. Returns {@code true} if and only if
* the specified object is also a {@link IntCharMap} and both objects contains exactly the same
* key-value pairs.
*/
public boolean equals(Object obj);
/**
* @return A hash code of elements stored in the map. The hash code is defined as a sum of hash
* codes of keys and values stored within the set). Because sum is commutative, this ensures
* that different order of elements in a set does not affect the hash code.
*/
public int hashCode();
/**
* Returns a logical "index" of a given key that can be used to speed up follow-up value setters
* or getters in certain scenarios (conditional logic).
*
* <p>The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be)
* contiguous.
*
* <p>The index is valid only between map modifications (it will not be affected by read-only
* operations like iteration or value retrievals).
*
* @see #indexExists
* @see #indexGet
* @see #indexInsert
* @see #indexReplace
* @param key The key to locate in the map.
* @return A non-negative value of the logical "index" of the key in the map or a negative value
* if the key did not exist.
*/
public int indexOf(int key);
/**
* @see #indexOf
* @param index The index of a given key, as returned from {@link #indexOf}.
* @return Returns <code>true</code> if the index corresponds to an existing key or false
* otherwise. This is equivalent to checking whether the index is a positive value (existing
* keys) or a negative value (non-existing keys).
*/
public boolean indexExists(int index);
/**
* Returns the value associated with an existing key.
*
* @see #indexOf
* @param index The index of an existing key.
* @return Returns the value currently associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public char indexGet(int index);
/**
* Replaces the value associated with an existing key and returns any previous value stored for
* that key.
*
* @see #indexOf
* @param index The index of an existing key.
* @return Returns the previous value associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public char indexReplace(int index, char newValue);
/**
* Inserts a key-value pair for a key that is not present in the map. This method may help in
* avoiding double recalculation of the key's hash.
*
* @see #indexOf
* @param index The index of a previously non-existing key, as returned from {@link #indexOf}.
* @throws AssertionError If assertions are enabled and the index corresponds to an existing key.
*/
public void indexInsert(int index, int key, char value);
/**
* Removes a key-value pair at an index previously acquired from {@link #indexOf}.
*
* @see #indexOf
* @param index The index of the key to remove, as returned from {@link #indexOf}.
* @return Returns the previous value associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public char indexRemove(int index);
/**
* Clear all keys and values in the container.
*
* @see #release()
*/
public void clear();
/**
* Removes all elements from the collection and additionally releases any internal buffers.
* Typically, if the object is to be reused, a simple {@link #clear()} should be a better
* alternative since it'll avoid reallocation.
*
* @see #clear()
*/
public void release();
/**
* Visually depict the distribution of keys.
*
* @param characters The number of characters to "squeeze" the entire buffer into.
* @return Returns a sequence of characters where '.' depicts an empty fragment of the internal
* buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything
* between 1 and 9 is between.
*/
public String visualizeKeyDistribution(int characters);
}

View File

@ -0,0 +1,64 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.predicates.IntPredicate;
/**
* A collection allows basic, efficient operations on sets of elements (difference and
* intersection).
*/
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeCollection.java")
public interface IntCollection extends IntContainer {
/**
* Removes all occurrences of <code>e</code> from this collection.
*
* @param e Element to be removed from this collection, if present.
* @return The number of removed elements as a result of this call.
*/
public int removeAll(int e);
/**
* Removes all elements in this collection that are present in <code>c</code>.
*
* @return Returns the number of removed elements.
*/
public int removeAll(IntLookupContainer c);
/**
* Removes all elements in this collection for which the given predicate returns <code>true</code>
* .
*
* @return Returns the number of removed elements.
*/
public int removeAll(IntPredicate predicate);
/**
* Keeps all elements in this collection that are present in <code>c</code>. Runs in time
* proportional to the number of elements in this collection. Equivalent of sets intersection.
*
* @return Returns the number of removed elements.
*/
public int retainAll(IntLookupContainer c);
/**
* Keeps all elements in this collection for which the given predicate returns <code>true</code>.
*
* @return Returns the number of removed elements.
*/
public int retainAll(IntPredicate predicate);
/**
* Removes all elements from this collection.
*
* @see #release()
*/
public void clear();
/**
* Removes all elements from the collection and additionally releases any internal buffers.
* Typically, if the object is to be reused, a simple {@link #clear()} should be a better
* alternative since it'll avoid reallocation.
*
* @see #clear()
*/
public void release();
}

View File

@ -0,0 +1,76 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.IntCursor;
import com.carrotsearch.hppc.predicates.IntPredicate;
import com.carrotsearch.hppc.procedures.IntProcedure;
import java.util.Iterator;
/** A generic container holding <code>int</code>s. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeContainer.java")
public interface IntContainer extends Iterable<IntCursor> {
/**
* Returns an iterator to a cursor traversing the collection. The order of traversal is not
* defined. More than one cursor may be active at a time. The behavior of iterators is undefined
* if structural changes are made to the underlying collection.
*
* <p>The iterator is implemented as a cursor and it returns <b>the same cursor instance</b> on
* every call to {@link Iterator#next()} (to avoid boxing of primitive types). To read the current
* list's value (or index in the list) use the cursor's public fields. An example is shown below.
*
* <pre>
* for (IntCursor&lt;int&gt; c : container) {
* System.out.println(&quot;index=&quot; + c.index + &quot; value=&quot; + c.value);
* }
* </pre>
*/
public Iterator<IntCursor> iterator();
/**
* Lookup a given element in the container. This operation has no speed guarantees (may be linear
* with respect to the size of this container).
*
* @return Returns <code>true</code> if this container has an element equal to <code>e</code>.
*/
public boolean contains(int e);
/**
* Return the current number of elements in this container. The time for calculating the
* container's size may take <code>O(n)</code> time, although implementing classes should try to
* maintain the current size and return in constant time.
*/
public int size();
/** Shortcut for <code>size() == 0</code>. */
public boolean isEmpty();
/**
* Copies all elements of this container to an array.
*
* <p>The returned array is always a copy, regardless of the storage used by the container.
*/
public int[] toArray();
/**
* Applies a <code>procedure</code> to all container elements. Returns the argument (any subclass
* of {@link IntProcedure}. This lets the caller to call methods of the argument by chaining the
* call (even if the argument is an anonymous type) to retrieve computed values, for example
* (IntContainer):
*
* <pre>
* int count = container.forEach(new IntProcedure() {
* int count; // this is a field declaration in an anonymous class.
*
* public void apply(int value) {
* count++;
* }
* }).count;
* </pre>
*/
public <T extends IntProcedure> T forEach(T procedure);
/**
* Applies a <code>predicate</code> to container elements as long, as the predicate returns <code>
* true</code>. The iteration is interrupted otherwise.
*/
public <T extends IntPredicate> T forEach(T predicate);
}

View File

@ -0,0 +1,77 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.IntCursor;
import com.carrotsearch.hppc.predicates.IntPredicate;
import com.carrotsearch.hppc.procedures.IntProcedure;
import java.util.Deque;
import java.util.Iterator;
/**
* A linear collection that supports element insertion and removal at both ends.
*
* @see Deque
*/
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeDeque.java")
public interface IntDeque extends IntCollection {
/**
* Removes the first element that equals <code>e</code>.
*
* @return The deleted element's index or <code>-1</code> if the element was not found.
*/
public int removeFirst(int e);
/**
* Removes the last element that equals <code>e</code>.
*
* @return The deleted element's index or <code>-1</code> if the element was not found.
*/
public int removeLast(int e);
/** Inserts the specified element at the front of this deque. */
public void addFirst(int e);
/** Inserts the specified element at the end of this deque. */
public void addLast(int e);
/**
* Retrieves and removes the first element of this deque.
*
* @return the head (first) element of this deque.
*/
public int removeFirst();
/**
* Retrieves and removes the last element of this deque.
*
* @return the tail of this deque.
*/
public int removeLast();
/**
* Retrieves the first element of this deque but does not remove it.
*
* @return the head of this deque.
*/
public int getFirst();
/**
* Retrieves the last element of this deque but does not remove it.
*
* @return the head of this deque.
*/
public int getLast();
/**
* @return An iterator over elements in this deque in tail-to-head order.
*/
public Iterator<IntCursor> descendingIterator();
/** Applies a <code>procedure</code> to all elements in tail-to-head order. */
public <T extends IntProcedure> T descendingForEach(T procedure);
/**
* Applies a <code>predicate</code> to container elements as long, as the predicate returns <code>
* true</code>. The iteration is interrupted otherwise.
*/
public <T extends IntPredicate> T descendingForEach(T predicate);
}

View File

@ -0,0 +1,105 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.*;
import com.carrotsearch.hppc.predicates.*;
import com.carrotsearch.hppc.procedures.*;
import java.util.Iterator;
/**
* An associative container from keys to (one or possibly more) values.
*
* @see IntContainer
*/
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "KTypeVTypeAssociativeContainer.java")
public interface IntDoubleAssociativeContainer extends Iterable<IntDoubleCursor> {
/**
* Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as
* a cursor and it returns <b>the same cursor instance</b> on every call to {@link
* Iterator#next()}. To read the current key and value use the cursor's public fields. An example
* is shown below.
*
* <pre>
* for (IntShortCursor c : intShortMap) {
* System.out.println(&quot;index=&quot; + c.index + &quot; key=&quot; + c.key + &quot; value=&quot; + c.value);
* }</pre>
*
* <p>The <code>index</code> field inside the cursor gives the internal index inside the
* container's implementation. The interpretation of this index depends on to the container.
*/
@Override
public Iterator<IntDoubleCursor> iterator();
/**
* Returns <code>true</code> if this container has an association to a value for the given key.
*/
public boolean containsKey(int key);
/**
* @return Returns the current size (number of assigned keys) in the container.
*/
public int size();
/**
* @return Return <code>true</code> if this hash map contains no assigned keys.
*/
public boolean isEmpty();
/**
* Removes all keys (and associated values) present in a given container. An alias to:
*
* <pre>
* keys().removeAll(container)
* </pre>
*
* but with no additional overhead.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(IntContainer container);
/**
* Removes all keys (and associated values) for which the predicate returns <code>true</code>.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(IntPredicate predicate);
/**
* Removes all keys (and associated values) for which the predicate returns <code>true</code>.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(IntDoublePredicate predicate);
/**
* Applies a given procedure to all keys-value pairs in this container. Returns the argument (any
* subclass of {@link IntDoubleProcedure}. This lets the caller call methods of the argument by
* chaining the call (even if the argument is an anonymous type) to retrieve computed values.
*/
public <T extends IntDoubleProcedure> T forEach(T procedure);
/**
* Applies a given predicate to all keys-value pairs in this container. Returns the argument (any
* subclass of {@link IntDoublePredicate}. This lets the caller call methods of the argument by
* chaining the call (even if the argument is an anonymous type) to retrieve computed values.
*
* <p>The iteration is continued as long as the predicate returns <code>true</code>.
*/
public <T extends IntDoublePredicate> T forEach(T predicate);
/**
* Returns a collection of keys of this container. The returned collection is a view over the key
* set and any modifications (if allowed) introduced to the collection will propagate to the
* associative container immediately.
*/
public IntCollection keys();
/**
* Returns a container view of all values present in this container. The returned collection is a
* view over the key set and any modifications (if allowed) introduced to the collection will
* propagate to the associative container immediately.
*/
public DoubleContainer values();
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,205 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.IntDoubleCursor;
/** An associative container with unique binding from keys to a single value. */
@com.carrotsearch.hppc.Generated(date = "2024-06-04T15:20:17+0200", value = "KTypeVTypeMap.java")
public interface IntDoubleMap extends IntDoubleAssociativeContainer {
/**
* @return Returns the value associated with the given key or the default value for the value
* type, if the key is not associated with any value. For numeric value types, this default
* value is 0, for object types it is {@code null}.
*/
public double get(int key);
/**
* @return Returns the value associated with the given key or the provided default value if the
* key is not associated with any value.
*/
public double getOrDefault(int key, double defaultValue);
/**
* Place a given key and value in the container.
*
* @return The value previously stored under the given key in the map is returned.
*/
public double put(int key, double value);
/**
* If the specified key is not already associated with a value, associates it with the given
* value.
*
* @return {@code true} if {@code key} did not exist and {@code value} was placed in the map,
* {@code false} otherwise.
*/
public default boolean putIfAbsent(int key, double value) {
int keyIndex = indexOf(key);
if (indexExists(keyIndex)) {
return false;
} else {
indexInsert(keyIndex, key, value);
return true;
}
}
/**
* Puts all keys from another container to this map, replacing the values of existing keys, if
* such keys are present.
*
* @return Returns the number of keys added to the map as a result of this call (not previously
* present in the map). Values of existing keys are overwritten.
*/
public int putAll(IntDoubleAssociativeContainer container);
/**
* Puts all keys from an iterable cursor to this map, replacing the values of existing keys, if
* such keys are present.
*
* @return Returns the number of keys added to the map as a result of this call (not previously
* present in the map). Values of existing keys are overwritten.
*/
public int putAll(Iterable<? extends IntDoubleCursor> iterable);
/**
* If <code>key</code> exists, <code>putValue</code> is inserted into the map, otherwise any
* existing value is incremented by <code>additionValue</code>.
*
* @param key The key of the value to adjust.
* @param putValue The value to put if <code>key</code> does not exist.
* @param incrementValue The value to add to the existing value if <code>key</code> exists.
* @return Returns the current value associated with <code>key</code> (after changes).
*/
public double putOrAdd(int key, double putValue, double incrementValue);
/**
* An equivalent of calling
*
* <pre>
* putOrAdd(key, additionValue, additionValue);
* </pre>
*
* @param key The key of the value to adjust.
* @param additionValue The value to put or add to the existing value if <code>key</code> exists.
* @return Returns the current value associated with <code>key</code> (after changes).
*/
public double addTo(int key, double additionValue);
/**
* Remove all values at the given key. The default value for the key type is returned if the value
* does not exist in the map.
*/
public double remove(int key);
/**
* Compares the specified object with this set for equality. Returns {@code true} if and only if
* the specified object is also a {@link IntDoubleMap} and both objects contains exactly the same
* key-value pairs.
*/
public boolean equals(Object obj);
/**
* @return A hash code of elements stored in the map. The hash code is defined as a sum of hash
* codes of keys and values stored within the set). Because sum is commutative, this ensures
* that different order of elements in a set does not affect the hash code.
*/
public int hashCode();
/**
* Returns a logical "index" of a given key that can be used to speed up follow-up value setters
* or getters in certain scenarios (conditional logic).
*
* <p>The semantics of "indexes" are not strictly defined. Indexes may (and typically won't be)
* contiguous.
*
* <p>The index is valid only between map modifications (it will not be affected by read-only
* operations like iteration or value retrievals).
*
* @see #indexExists
* @see #indexGet
* @see #indexInsert
* @see #indexReplace
* @param key The key to locate in the map.
* @return A non-negative value of the logical "index" of the key in the map or a negative value
* if the key did not exist.
*/
public int indexOf(int key);
/**
* @see #indexOf
* @param index The index of a given key, as returned from {@link #indexOf}.
* @return Returns <code>true</code> if the index corresponds to an existing key or false
* otherwise. This is equivalent to checking whether the index is a positive value (existing
* keys) or a negative value (non-existing keys).
*/
public boolean indexExists(int index);
/**
* Returns the value associated with an existing key.
*
* @see #indexOf
* @param index The index of an existing key.
* @return Returns the value currently associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public double indexGet(int index);
/**
* Replaces the value associated with an existing key and returns any previous value stored for
* that key.
*
* @see #indexOf
* @param index The index of an existing key.
* @return Returns the previous value associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public double indexReplace(int index, double newValue);
/**
* Inserts a key-value pair for a key that is not present in the map. This method may help in
* avoiding double recalculation of the key's hash.
*
* @see #indexOf
* @param index The index of a previously non-existing key, as returned from {@link #indexOf}.
* @throws AssertionError If assertions are enabled and the index corresponds to an existing key.
*/
public void indexInsert(int index, int key, double value);
/**
* Removes a key-value pair at an index previously acquired from {@link #indexOf}.
*
* @see #indexOf
* @param index The index of the key to remove, as returned from {@link #indexOf}.
* @return Returns the previous value associated with the key.
* @throws AssertionError If assertions are enabled and the index does not correspond to an
* existing key.
*/
public double indexRemove(int index);
/**
* Clear all keys and values in the container.
*
* @see #release()
*/
public void clear();
/**
* Removes all elements from the collection and additionally releases any internal buffers.
* Typically, if the object is to be reused, a simple {@link #clear()} should be a better
* alternative since it'll avoid reallocation.
*
* @see #clear()
*/
public void release();
/**
* Visually depict the distribution of keys.
*
* @param characters The number of characters to "squeeze" the entire buffer into.
* @return Returns a sequence of characters where '.' depicts an empty fragment of the internal
* buffer and 'X' depicts full or nearly full capacity within the buffer's range and anything
* between 1 and 9 is between.
*/
public String visualizeKeyDistribution(int characters);
}

View File

@ -0,0 +1,105 @@
package com.carrotsearch.hppc;
import com.carrotsearch.hppc.cursors.*;
import com.carrotsearch.hppc.predicates.*;
import com.carrotsearch.hppc.procedures.*;
import java.util.Iterator;
/**
* An associative container from keys to (one or possibly more) values.
*
* @see IntContainer
*/
@com.carrotsearch.hppc.Generated(
date = "2024-06-04T15:20:17+0200",
value = "KTypeVTypeAssociativeContainer.java")
public interface IntFloatAssociativeContainer extends Iterable<IntFloatCursor> {
/**
* Returns a cursor over the entries (key-value pairs) in this map. The iterator is implemented as
* a cursor and it returns <b>the same cursor instance</b> on every call to {@link
* Iterator#next()}. To read the current key and value use the cursor's public fields. An example
* is shown below.
*
* <pre>
* for (IntShortCursor c : intShortMap) {
* System.out.println(&quot;index=&quot; + c.index + &quot; key=&quot; + c.key + &quot; value=&quot; + c.value);
* }</pre>
*
* <p>The <code>index</code> field inside the cursor gives the internal index inside the
* container's implementation. The interpretation of this index depends on to the container.
*/
@Override
public Iterator<IntFloatCursor> iterator();
/**
* Returns <code>true</code> if this container has an association to a value for the given key.
*/
public boolean containsKey(int key);
/**
* @return Returns the current size (number of assigned keys) in the container.
*/
public int size();
/**
* @return Return <code>true</code> if this hash map contains no assigned keys.
*/
public boolean isEmpty();
/**
* Removes all keys (and associated values) present in a given container. An alias to:
*
* <pre>
* keys().removeAll(container)
* </pre>
*
* but with no additional overhead.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(IntContainer container);
/**
* Removes all keys (and associated values) for which the predicate returns <code>true</code>.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(IntPredicate predicate);
/**
* Removes all keys (and associated values) for which the predicate returns <code>true</code>.
*
* @return Returns the number of elements actually removed as a result of this call.
*/
public int removeAll(IntFloatPredicate predicate);
/**
* Applies a given procedure to all keys-value pairs in this container. Returns the argument (any
* subclass of {@link IntFloatProcedure}. This lets the caller call methods of the argument by
* chaining the call (even if the argument is an anonymous type) to retrieve computed values.
*/
public <T extends IntFloatProcedure> T forEach(T procedure);
/**
* Applies a given predicate to all keys-value pairs in this container. Returns the argument (any
* subclass of {@link IntFloatPredicate}. This lets the caller call methods of the argument by
* chaining the call (even if the argument is an anonymous type) to retrieve computed values.
*
* <p>The iteration is continued as long as the predicate returns <code>true</code>.
*/
public <T extends IntFloatPredicate> T forEach(T predicate);
/**
* Returns a collection of keys of this container. The returned collection is a view over the key
* set and any modifications (if allowed) introduced to the collection will propagate to the
* associative container immediately.
*/
public IntCollection keys();
/**
* Returns a container view of all values present in this container. The returned collection is a
* view over the key set and any modifications (if allowed) introduced to the collection will
* propagate to the associative container immediately.
*/
public FloatContainer values();
}

Some files were not shown because too many files have changed in this diff Show More