Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.collections;
/**
* Lightweight hash map from key to value with limited
* functionality. This class lets you build a map from key to
* value. The value for a key may be overwritten and the put and get
* methods have the same semantics as for normal Java Maps, but there
* is no remove operation. Also, there is no iterator support, but
* keys and values can be accessed directly by index. The access order
* of keys and values are defined by the insert order of the keys. The
* goal of this class is to reduce the amount of object that are
* allocated by packing everything into two internal arrays. The keys
* and values are packed in an Object array and the hash table and
* entries are packed in an int array. The internal arrays are not
* created until space is needed. The default initial capacity is 16
* entries. If you know you need much more space than this, you can
* explicitly reserve more space before starting to insert values. The
* maximum load factor is 0.7 and drops slightly with increasing
* capacity.
*
* @author Havard Pettersen
*/
public final class Hashlet {
private static final int[] emptyHash = new int[1];
private int capacity = 0;
private int hashSize() { return (capacity + (capacity / 2) - 1); }
private int used = 0;
private Object[] store;
private int[] hash = emptyHash;
/**
* Create an empty Hashlet.
**/
public Hashlet() {}
/**
* Create a Hashlet that is a shallow copy of another Hashlet.
*
* @param hashlet the Hashlet to copy.
**/
public Hashlet(Hashlet hashlet) {
if (hashlet.used > 0) {
capacity = hashlet.capacity;
used = hashlet.used;
store = new Object[hashlet.store.length];
hash = new int[hashlet.hash.length];
System.arraycopy(hashlet.store, 0, store, 0, store.length);
System.arraycopy(hashlet.hash, 0, hash, 0, hash.length);
}
}
/**
* Reserve space for more key value pairs. This method is used by
* the put method to perform rehashing when needed. It can be
* invoked directly by the application to reduce the number of
* rehashes needed to insert a large number of entries.
*
* @param n the number of additional entries to reserve space for
**/
public void reserve(int n) {
if (used + n > capacity) {
final int c = capacity;
if (capacity == 0) {
capacity = 16;
}
while (used + n > capacity) {
capacity *= 2;
}
final Object[] s = store;
store = new Object[capacity * 2];
hash = new int[hashSize() + (capacity * 2)];
if (c > 0) {
System.arraycopy(s, 0, store, 0, used);
System.arraycopy(s, c, store, capacity, used);
for (int i = 0; i < used; i++) {
int prev = Math.abs(s[i].hashCode() % hashSize());
int entry = hash[prev];
while (entry != 0) {
prev = entry + 1;
entry = hash[prev];
}
final int insertIdx = (hashSize() + (i * 2));
hash[prev] = insertIdx;
hash[insertIdx] = i;
}
}
}
}
/**
* The current size. This is the number of key value pairs
* currently stored in this object.
*
* @return current size
**/
public int size() {
return used;
}
/**
* Obtain a key. Keys are accessed in the order they were first
* inserted.
*
* @return the requested key
* @param i the index of the key, must be in the range [0, size() - 1]
**/
@SuppressWarnings("unchecked")
public K key(int i) {
return (K) store[i];
}
/**
* Obtain a value. Values are accessed in the order in which
* theirs keys were first inserted.
*
* @return the requested value
* @param i the index of the value, must be in the range [0, size() - 1]
**/
@SuppressWarnings("unchecked")
public V value(int i) {
return (V) store[capacity + i];
}
/**
* This will replace the value at the index give.
*
* @param i the index of the value, must be in the range [0, size() - 1]
* @param value The new value you want to set for this index.
* @return previous value
*/
public V setValue(int i, V value) {
V prev = value(i);
store[capacity + i] = value;
return prev;
}
/**
* Associate a value with a specific key.
*
* @return the old value for the key, if it was already present
* @param key the key
* @param value the value
**/
public V put(K key, V value) {
reserve(1);
int prev = Math.abs(key.hashCode() % hashSize());
int entry = hash[prev];
while (entry != 0) {
final int idx = hash[entry];
if (store[idx].equals(key)) { // found entry
@SuppressWarnings("unchecked")
final V ret = (V) store[capacity + idx];
store[capacity + idx] = value;
return ret;
}
prev = entry + 1;
entry = hash[prev];
}
final int insertIdx = (hashSize() + (used * 2));
hash[prev] = insertIdx;
hash[insertIdx] = used;
store[used] = key;
store[capacity + (used++)] = value;
return null;
}
/**
* Obtain the value for a specific key.
*
* @return the value for a key, or null if not found
* @param key the key
**/
public V get(Object key) {
int index = getIndexOfKey(key);
return (index != -1) ? value(index) : null;
}
/**
* Finds the index where the key,value pair is stored.
* @param key to look for
* @return the index where the key is found or -1 if it is not found
*/
public int getIndexOfKey(Object key) {
int entry = hash[Math.abs(key.hashCode() % hashSize())];
while (entry != 0) {
final int idx = hash[entry];
if (store[idx].equals(key)) { // found entry
return idx;
}
entry = hash[entry + 1];
}
return -1;
}
@Override
public int hashCode() {
int h = 0;
for (int i = 0; i < used; i++) {
h += key(i).hashCode();
V v = value(i);
if (v != null) {
h += v.hashCode();
}
}
return h;
}
@Override
public boolean equals(Object o) {
if (! (o instanceof Hashlet) ) return false;
Hashlet rhs = (Hashlet) o;
if (used != rhs.used) return false;
for (int i = 0; i < used; i++) {
int bi = rhs.getIndexOfKey(key(i));
if (bi == -1) return false;
Object a = value(i);
Object b = rhs.value(bi);
boolean equal = (a == null) ? b == null : a.equals(b);
if ( !equal ) return false;
}
return true;
}
}