mirror of
http://git.eaglercraft.rip/eaglercraft/eaglercraft-1.8.git
synced 2025-04-30 02:01:59 -05:00
113 lines
3.6 KiB
Java
113 lines
3.6 KiB
Java
/*
|
|
* 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.
|
|
}
|
|
}
|