/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.ignite.internal.util; import java.util.Arrays; /** * Lightweight identity hash table which maps objects to integer handles, * assigned in ascending order. */ public class GridHandleTable { /** Number of mappings in table/next available handle. */ private int size; /** Size threshold determining when to expand hash spine. */ private int threshold; /** Factor for computing size threshold. */ private final float loadFactor; /** Maps hash value -> candidate handle value. */ private int[] spine; /** Maps handle value -> next candidate handle value. */ private int[] next; /** Maps handle value -> associated object. */ private Object[] objs; /** */ private int[] spineEmpty; /** */ private int[] nextEmpty; /** * Creates new HandleTable with given capacity and load factor. * * @param initCap Initial capacity. * @param loadFactor Load factor. */ public GridHandleTable(int initCap, float loadFactor) { this.loadFactor = loadFactor; spine = new int[initCap]; next = new int[initCap]; objs = new Object[initCap]; spineEmpty = new int[initCap]; nextEmpty = new int[initCap]; Arrays.fill(spineEmpty, -1); Arrays.fill(nextEmpty, -1); threshold = (int)(initCap * loadFactor); clear(); } /** * Looks up and returns handle associated with given object, or -1 if * no mapping found. * * @param obj Object. * @return Handle. */ public int lookup(Object obj) { int idx = hash(obj) % spine.length; if (size > 0) { for (int i = spine[idx]; i >= 0; i = next[i]) if (objs[i] == obj) return i; } if (size >= next.length) growEntries(); if (size >= threshold) { growSpine(); idx = hash(obj) % spine.length; } insert(obj, size, idx); size++; return -1; } /** * Resets table to its initial (empty) state. */ public void clear() { System.arraycopy(spineEmpty, 0, spine, 0, spineEmpty.length); System.arraycopy(nextEmpty, 0, next, 0, nextEmpty.length); Arrays.fill(objs, null); size = 0; } /** * @return Returns objects that were added to handles table. */ public Object[] objects() { return objs; } /** * Inserts mapping object -> handle mapping into table. Assumes table * is large enough to accommodate new mapping. * * @param obj Object. * @param handle Handle. * @param idx Index. */ private void insert(Object obj, int handle, int idx) { objs[handle] = obj; next[handle] = spine[idx]; spine[idx] = handle; } /** * Expands the hash "spine" - equivalent to increasing the number of * buckets in a conventional hash table. */ private void growSpine() { int size = (spine.length << 1) + 1; spine = new int[size]; spineEmpty = new int[size]; threshold = (int)(spine.length * loadFactor); Arrays.fill(spineEmpty, -1); System.arraycopy(spineEmpty, 0, spine, 0, spineEmpty.length); for (int i = 0; i < this.size; i++) { Object obj = objs[i]; int idx = hash(obj) % spine.length; insert(objs[i], i, idx); } } /** * Increases hash table capacity by lengthening entry arrays. */ private void growEntries() { int newLen = (next.length << 1) + 1; int[] newNext = new int[newLen]; System.arraycopy(next, 0, newNext, 0, size); next = newNext; nextEmpty = new int[newLen]; Arrays.fill(nextEmpty, -1); Object[] newObjs = new Object[newLen]; System.arraycopy(objs, 0, newObjs, 0, size); objs = newObjs; } /** * Returns hash value for given object. * * @param obj Object. * @return Hash value. */ private int hash(Object obj) { return System.identityHashCode(obj) & 0x7FFFFFFF; } }