/* * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. * @LastModified: Nov 2017 */ /* * 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 com.sun.org.apache.xerces.internal.util; /** * This class is an unsynchronized hash table primary used for String * to Object mapping. *

* The hash code uses the same algorithm as SymbolTable class. * * @author Elena Litani */ public class SymbolHash { // // Constants // /** Default table size. */ protected static final int TABLE_SIZE = 101; /** Maximum hash collisions per bucket. */ protected static final int MAX_HASH_COLLISIONS = 40; protected static final int MULTIPLIERS_SIZE = 1 << 5; protected static final int MULTIPLIERS_MASK = MULTIPLIERS_SIZE - 1; // // Data // /** Actual table size **/ protected int fTableSize; /** Buckets. */ protected Entry[] fBuckets; /** Number of elements. */ protected int fNum = 0; /** * Array of randomly selected hash function multipliers or null * if the default String.hashCode() function should be used. */ protected int[] fHashMultipliers; // // Constructors // /** Constructs a key table with the default size. */ public SymbolHash() { this(TABLE_SIZE); } /** * Constructs a key table with a given size. * * @param size the size of the key table. */ public SymbolHash(int size) { fTableSize = size; fBuckets = new Entry[fTableSize]; } // // Public methods // /** * Adds the key/value mapping to the key table. If the key already exists, * the previous value associated with this key is overwritten by the new * value. * * @param key * @param value */ public void put(Object key, Object value) { // search for identical key int collisionCount = 0; final int hash = hash(key); int bucket = hash % fTableSize; for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) { if (key.equals(entry.key)) { // replace old value entry.value = value; return; } ++collisionCount; } if (fNum >= fTableSize) { // Rehash the table if the number of entries // would exceed the number of buckets. rehash(); bucket = hash % fTableSize; } else if (collisionCount >= MAX_HASH_COLLISIONS && key instanceof String) { // Select a new hash function and rehash the table if // MAX_HASH_COLLISIONS is exceeded. rebalance(); bucket = hash(key) % fTableSize; } // create new entry Entry entry = new Entry(key, value, fBuckets[bucket]); fBuckets[bucket] = entry; ++fNum; } /** * Get the value associated with the given key. * * @param key * @return the value associated with the given key. */ public Object get(Object key) { int bucket = hash(key) % fTableSize; Entry entry = search(key, bucket); if (entry != null) { return entry.value; } return null; } /** * Get the number of key/value pairs stored in this table. * * @return the number of key/value pairs stored in this table. */ public int getLength() { return fNum; } /** * Add all values to the given array. The array must have enough entry. * * @param elements the array to store the elements * @param from where to start store element in the array * @return number of elements copied to the array */ public int getValues(Object[] elements, int from) { for (int i=0, j=0; i 0;) { for (Entry old = oldTable[i]; old != null; ) { Entry e = old; old = old.next; int index = hash(e.key) % newCapacity; e.next = newTable[index]; newTable[index] = e; } } } // // Classes // /** * This class is a key table entry. Each entry acts as a node * in a linked list. */ protected static final class Entry { // key/value public Object key; public Object value; /** The next entry. */ public Entry next; public Entry() { key = null; value = null; next = null; } public Entry(Object key, Object value, Entry next) { this.key = key; this.value = value; this.next = next; } public Entry makeClone() { Entry entry = new Entry(); entry.key = key; entry.value = value; if (next != null) entry.next = next.makeClone(); return entry; } } // entry } // class SymbolHash