/** * Copyright (c) 2009 International Health Terminology Standards Development * Organisation * * 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. */ /** * Copyright CSIRO Australian e-Health Research Centre (http://aehrc.com). * All rights reserved. Use is subject to license terms and conditions. */ package au.csiro.snorocket.core.util; import java.util.Arrays; public final class FastConceptMap<V> implements IConceptMap<V> { /** * Serialisation version. */ private static final long serialVersionUID = 1L; private final static int EMPTY = -1; private final static Object TOMBSTOMB = null; private final static int REPROBE_LIMIT = 10; private int[] _keys; private Object[] _values; private int _size; public FastConceptMap(final int size, String label) { this(); } public FastConceptMap() { clear(); } public void clear() { reallocate(2); } private void reallocate(final int size) { _keys = new int[size]; Arrays.fill(_keys, EMPTY); _values = new Object[size]; Arrays.fill(_values, TOMBSTOMB); _size = 0; } public boolean containsKey(final int key) { return null != get(key); } @SuppressWarnings("unchecked") public V get(int key) { final int len = _keys.length; final int mask = len - 1; int reprobe_count = 0; int idx = key & mask; while (true) { final int K = _keys[idx]; if (EMPTY == K) { return null; } if (key == K) { final Object val = _values[idx]; return TOMBSTOMB == val ? null : (V) val; } if (++reprobe_count > (REPROBE_LIMIT + (len >> 2))) { break; } idx = (idx + 1) & mask; } resize(); return get(key); } private void resize() { grow(_keys.length * 2); } public IntIterator keyIterator() { return new IntIterator() { int next = 0; public boolean hasNext() { while (next < _keys.length && (EMPTY == _keys[next] || TOMBSTOMB == _values[next])) { next++; } return next < _keys.length; } public int next() { return hasNext() ? _keys[next++] : EMPTY; } }; } public void put(int key, V value) { final int len = _keys.length; final int mask = len - 1; int reprobe_count = 0; int idx = key & mask; while (true) { final int K = _keys[idx]; if (EMPTY == K) { _keys[idx] = key; _values[idx] = value; _size++; return; } if (key == K) { if (TOMBSTOMB == _values[idx]) { _size++; } _values[idx] = value; return; } if (++reprobe_count > (REPROBE_LIMIT + (len >> 2))) { break; } idx = (idx + 1) & mask; } resize(); put(key, value); } public void remove(int key) { final int mask = _keys.length - 1; int idx = key & mask; while (true) { final int K = _keys[idx]; if (EMPTY == K) { return; } if (key == K) { if (TOMBSTOMB != _values[idx]) { _size--; _values[idx] = TOMBSTOMB; } return; } idx = (idx + 1) & mask; } } public int size() { return _size; } @SuppressWarnings("unchecked") public void grow(final int newSize) { final int[] oldKeys = _keys; final Object[] oldValues = _values; reallocate(newSize); // System.err.println("resize from " + oldSize + " to " + newSize); // new Exception().printStackTrace(); for (int i = 0; i < oldKeys.length; i++) { final int key = oldKeys[i]; final Object val = oldValues[i]; if (EMPTY != key && TOMBSTOMB != val) { put(key, (V) val); } } } }