/* * Licensed under the Apache License, Version 2.0 (the "License"); * * You may not use this file except in compliance with the License. * * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * limitations under the License. * * Contributions from 2013-2017 where performed either by US government * employees, or under US Veterans Health Administration contracts. * * US Veterans Health Administration contributions by government employees * are work of the U.S. Government and are not subject to copyright * protection in the United States. Portions contributed by government * employees are USGovWork (17USC ยง105). Not subject to copyright. * * Contribution by contractors to the US Veterans Health Administration * during this period are contractually contributed under the * Apache License, Version 2.0. * * See: https://www.usa.gov/government-works * * Contributions prior to 2013: * * Copyright (C) International Health Terminology Standards Development Organisation. * Licensed under the Apache License, Version 2.0. * */ /* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package sh.isaac.api.collections; //~--- non-JDK imports -------------------------------------------------------- import org.apache.mahout.math.map.HashFunctions; import org.apache.mahout.math.map.OpenIntIntHashMap; //~--- classes ---------------------------------------------------------------- /** * The Class NativeIntIntHashMap. * * @author kec */ public class NativeIntIntHashMap extends OpenIntIntHashMap { /** The Constant serialVersionUID. */ private static final long serialVersionUID = 1L; //~--- constructors -------------------------------------------------------- /** * Instantiates a new native int int hash map. */ public NativeIntIntHashMap() {} /** * Instantiates a new native int int hash map. * * @param initialCapacity the initial capacity */ public NativeIntIntHashMap(int initialCapacity) { super(initialCapacity); } /** * Instantiates a new native int int hash map. * * @param initialCapacity the initial capacity * @param minLoadFactor the min load factor * @param maxLoadFactor the max load factor */ public NativeIntIntHashMap(int initialCapacity, double minLoadFactor, double maxLoadFactor) { super(initialCapacity, minLoadFactor, maxLoadFactor); } //~--- methods ------------------------------------------------------------- /** * Index of insertion. * * @param key the key * @return the int */ @Override protected int indexOfInsertion(int key) { return indexOfInsertion(key, this.table, this.state); } /** * Index of insertion. * * @param key the key * @param newTable the new table * @param newState the new state * @return the int */ protected int indexOfInsertion(int key, int[] newTable, byte[] newState) { final int length = newTable.length; final int hash = HashFunctions.hash(key) & 0x7FFFFFFF; int i = hash % length; int decrement = hash % (length - 2); // double hashing, see http://www.eece.unm.edu/faculty/heileman/hash/node4.html // int decrement = (hash / length) % length; if (decrement == 0) { decrement = 1; } // stop if we find a removed or free slot, or if we find the key itself // do NOT skip over removed slots (yes, open addressing is like that...) while ((newState[i] == FULL) && (newTable[i] != key)) { i -= decrement; // hashCollisions++; if (i < 0) { i += length; } } if (newState[i] == REMOVED) { // stop if we find a free slot, or if we find the key itself. // do skip over removed slots (yes, open addressing is like that...) // assertion: there is at least one FREE slot. final int j = i; while ((newState[i] != FREE) && ((newState[i] == REMOVED) || (newTable[i] != key))) { i -= decrement; // hashCollisions++; if (i < 0) { i += length; } } if (newState[i] == FREE) { i = j; } } if (newState[i] == FULL) { // key already contained at slot i. // return a negative number identifying the slot. return -i - 1; } // not already contained, should be inserted at slot i. // return a number >= 0 identifying the slot. return i; } /** * Reimplement rehash so that tables are not exposed until after copying is * complete. * * @param newCapacity the new capacity */ @Override protected void rehash(int newCapacity) { final int oldCapacity = this.table.length; // if (oldCapacity == newCapacity) return; final int[] oldTable = this.table; final int[] oldValues = this.values; final byte[] oldState = this.state; final int[] newTable = new int[newCapacity]; final int[] newValues = new int[newCapacity]; final byte[] newState = new byte[newCapacity]; for (int i = oldCapacity; i-- > 0; ) { if (oldState[i] == FULL) { final int element = oldTable[i]; final int index = indexOfInsertion(element, newTable, newState); newTable[index] = element; newValues[index] = oldValues[i]; newState[index] = FULL; } } updateData(newTable, newValues, newState, newCapacity); } /** * Update data. * * @param newTable the new table * @param newValues the new values * @param newState the new state * @param newCapacity the new capacity */ protected void updateData(int[] newTable, int[] newValues, byte[] newState, int newCapacity) { this.values = newValues; this.state = newState; this.table = newTable; this.lowWaterMark = chooseLowWaterMark(newCapacity, this.minLoadFactor); this.highWaterMark = chooseHighWaterMark(newCapacity, this.maxLoadFactor); this.freeEntries = newCapacity - this.distinct; // delta } //~--- get methods --------------------------------------------------------- /** * Gets the distinct. * * @return the distinct */ public int getDistinct() { return this.distinct; } //~--- set methods --------------------------------------------------------- /** * Sets the distinct. * * @param distinct the new distinct */ public void setDistinct(int distinct) { this.distinct = distinct; } //~--- get methods --------------------------------------------------------- /** * Gets the free entries. * * @return the free entries */ public int getFreeEntries() { return this.freeEntries; } //~--- set methods --------------------------------------------------------- /** * Sets the free entries. * * @param freeEntries the new free entries */ public void setFreeEntries(int freeEntries) { this.freeEntries = freeEntries; } //~--- get methods --------------------------------------------------------- /** * Gets the state. * * @return the state */ public byte[] getState() { return this.state; } //~--- set methods --------------------------------------------------------- /** * Sets the state. * * @param state the new state */ public void setState(byte[] state) { this.state = state; } //~--- get methods --------------------------------------------------------- /** * Gets the table. * * @return the table */ public int[] getTable() { return this.table; } //~--- set methods --------------------------------------------------------- /** * Sets the table. * * @param table the new table */ public void setTable(int[] table) { this.table = table; } //~--- get methods --------------------------------------------------------- /** * Gets the values. * * @return the values */ public int[] getValues() { return this.values; } //~--- set methods --------------------------------------------------------- /** * Sets the values. * * @param values the new values */ public void setValues(int[] values) { this.values = values; } }