/* * @(#)CacheTable.java 1.16 03/12/19 * * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package com.sun.corba.se.impl.orbutil; import org.omg.CORBA.INTERNAL; import org.omg.CORBA.CompletionStatus; import com.sun.corba.se.spi.logging.CORBALogDomains; import com.sun.corba.se.spi.orb.ORB; import com.sun.corba.se.impl.logging.ORBUtilSystemException; public class CacheTable { class Entry { java.lang.Object key; int val; Entry next; // this chains the collision list of table "map" Entry rnext; // this chains the collision list of table "rmap" public Entry(java.lang.Object k, int v) { key = k; val = v; next = null; rnext = null; } } private boolean noReverseMap; // size must be power of 2 static final int INITIAL_SIZE = 16; static final int MAX_SIZE = 1 << 30; int size; int entryCount; private Entry [] map; private Entry [] rmap; private ORB orb; private ORBUtilSystemException wrapper; private CacheTable() {} public CacheTable(ORB orb, boolean u) { //System.out.println("using new cache table"); this.orb = orb; wrapper = ORBUtilSystemException.get(orb, CORBALogDomains.RPC_ENCODING); noReverseMap = u; size = INITIAL_SIZE; entryCount = 0; initTables(); } private void initTables() { map = new Entry[size]; rmap = noReverseMap ? null : new Entry[size]; } private void grow() { if (size == MAX_SIZE) return; Entry [] oldMap = map; int oldSize = size; size <<= 1; initTables(); // now rehash the entries into the new table for (int i = 0; i < oldSize; i++) { for (Entry e = oldMap[i]; e != null; e = e.next) put_table(e.key, e.val); } } private int moduloTableSize(int h) { // these are the "supplemental hash function" copied from // java.util.HashMap, supposed to be "critical" h += ~(h << 9); h ^= (h >>> 14); h += (h << 4); h ^= (h >>> 10); return h & (size - 1); } private int hash(java.lang.Object key) { return moduloTableSize(System.identityHashCode(key)); } private int hash(int val) { return moduloTableSize(val); } public final void put(java.lang.Object key, int val) { if (put_table(key, val)) { entryCount++; if (entryCount > size * 3 / 4) grow(); } } private boolean put_table(java.lang.Object key, int val) { int index = hash(key); for (Entry e = map[index]; e != null; e = e.next) { if (e.key == key) { if (e.val != val) { throw wrapper.duplicateIndirectionOffset(); } // if we get here we are trying to put in the same key/val pair // this is a no-op, so we just return return false; } } // this means the key is not present in our table // then it shouldnt be present in our reverse table either Entry newEntry = new Entry(key, val); newEntry.next = map[index]; map[index] = newEntry; if (!noReverseMap) { int rindex = hash(val); newEntry.rnext = rmap[rindex]; rmap[rindex] = newEntry; } return true; } public final boolean containsKey(java.lang.Object key) { return (getVal(key) != -1); } public final int getVal(java.lang.Object key) { int index = hash(key); for (Entry e = map[index]; e != null; e = e.next) { if (e.key == key) return e.val; } return -1; } public final boolean containsVal(int val) { return (getKey(val) != null); } public final boolean containsOrderedVal(int val) { return containsVal(val); } public final java.lang.Object getKey(int val) { int index = hash(val); for (Entry e = rmap[index]; e != null; e = e.rnext) { if (e.val == val) return e.key; } return null; } public void done() { map = null; rmap = null; } }