com.gemstone.gemfire.internal.admin.ListenerIdMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gemfire-core Show documentation
Show all versions of gemfire-core Show documentation
TIBCO ComputeDB store based off Pivotal GemFireXD
/*
* Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
*
* 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. See accompanying
* LICENSE file.
*/
package com.gemstone.gemfire.internal.admin;
import com.gemstone.gemfire.internal.i18n.LocalizedStrings;
import java.lang.Math;
/**
* A ListenerIdMap
maps ints to an Object
.
* This is an optimization because using a {@link java.util.HashMap}
* for this purposed proved to be too slow because of all of the
* {@link Integer}s that had to be created.
*/
public class ListenerIdMap {
/** The contents of the map */
protected Entry[] table;
/** The total number of mappings in the map */
private int count;
/** Once the number of mappings in the map exceeds the threshold,
* the map is rehased. The threshold is the capacity *
* loadFactor.
*/
private int threshold;
/** The load factor of the map */
private float loadFactor;
//////////////////// Constructors ////////////////////
/**
* Creates a new, empty map with the given initial capacity (number
* of buckets) and load factor.
*/
public ListenerIdMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0) {
throw new IllegalArgumentException(LocalizedStrings.ListenerIdMap_ILLEGAL_INITIAL_CAPACITY_0.toLocalizedString(Integer.valueOf(initialCapacity)));
}
if (loadFactor <= 0 || Float.isNaN(loadFactor)) {
throw new IllegalArgumentException(LocalizedStrings.ListenerIdMap_ILLEGAL_LOAD_FACTOR_0.toLocalizedString(new Float(loadFactor)));
}
if (initialCapacity==0) {
initialCapacity = 1;
}
this.loadFactor = loadFactor;
table = new Entry[initialCapacity];
threshold = (int)(initialCapacity * loadFactor);
}
/**
* Creates a new, empty map with the default initial capacity (11
* buckets) and load factor (0.75).
*/
public ListenerIdMap() {
this(11, 0.75f);
}
//////////////////// Instance Methods ////////////////////
/**
* Returns the number of mappings in this map
*/
public int size() {
return this.count;
}
/**
* Returns true
if this map contains a mapping for the
* given key.
*
* @throws IllegalArgumentException
* key
is less than zero
*/
public boolean containsKey(int key) {
Entry[] table = this.table;
int bucket = Math.abs(key) % table.length;
for (Entry e = table[bucket]; e != null; e = e.next) {
if (e.key == key) {
return true;
}
}
return false;
}
/**
* Returns the object to which the given key is mapped. If no
* object is mapped to the given key, null
is returned.
*
* @throws IllegalArgumentException
* key
is less than zero
*/
public Object get(int key) {
Entry[] table = this.table;
int bucket = Math.abs(key) % table.length;
for (Entry e = table[bucket]; e != null; e = e.next) {
if (e.key == key) {
return e.value;
}
}
return null;
}
/**
* Rehashes this map into a new map with a large number of buckets.
* It is called when the number of entries in the map exceeds the
* capacity and load factor.
*/
private void rehash() {
int oldCapacity = table.length;
Entry oldMap[] = table;
int newCapacity = oldCapacity * 2 + 1;
Entry newMap[] = new Entry[newCapacity];
threshold = (int)(newCapacity * loadFactor);
table = newMap;
for (int i = oldCapacity ; i-- > 0 ;) {
for (Entry old = oldMap[i] ; old != null ; ) {
Entry e = old;
old = old.next;
int index = Math.abs(e.key) % newCapacity;
e.next = newMap[index];
newMap[index] = e;
}
}
}
/**
* Creates a mapping between the given key (object id) and an
* object. Returns the previous value, or null
if
* there was none.
*
* @throws IllegalArgumentException
* key
is less than zero
*/
public Object put(int key, Object value) {
Entry[] table = this.table;
// Is the key already in the table?
int bucket = Math.abs(key) % table.length;
for (Entry e = table[bucket]; e != null; e = e.next) {
if (e.key == key) {
Object old = e.value;
e.value = value;
return old;
}
}
// Adjust the table, if necessary
if (this.count >= this.threshold) {
rehash();
table = this.table;
bucket = Math.abs(key) % table.length;
}
Entry e = new Entry();
e.key = key;
e.value = value;
e.next = table[bucket];
table[bucket] = e;
count++;
return null;
}
/**
* Removes the mapping for the given key. Returns the object to
* which the key was mapped, or null
otherwise.
*/
public Object remove(int key) {
Entry[] table = this.table;
int bucket = Math.abs(key) % table.length;
for (Entry e = table[bucket], prev = null; e != null;
prev = e, e = e.next) {
if (key == e.key) {
if (prev != null)
prev.next = e.next;
else
table[bucket] = e.next;
count--;
Object oldValue = e.value;
e.value = null;
return oldValue;
}
}
return null;
}
/**
* Returns all of the objects in the map
*/
public Object[] values() {
Object[] values = new Object[this.size()];
Entry[] table = this.table;
int i = 0;
for (int bucket = 0; bucket < table.length; bucket++) {
for (Entry e = table[bucket]; e != null; e = e.next) {
values[i++] = e.value;
}
}
return values;
}
/**
* Returns all of the entries in the map
*/
public ListenerIdMap.Entry[] entries() {
Entry[] entries = new Entry[this.size()];
Entry[] table = this.table;
int i = 0;
for (int bucket = 0; bucket < table.length; bucket++) {
for (Entry e = table[bucket]; e != null; e = e.next) {
entries[i++] = e;
}
}
return entries;
}
/**
* Returns an iterator over the {@link Entry}s of this map. Note
* that this iterator is not fail-fast. That is, it is the
* user's responsibility to ensure that the map does not change
* while he is iterating over it.
*/
public EntryIterator iterator() {
return new EntryIterator();
}
/////////////////////// Inner Classes ///////////////////////
/**
* Inner class that represents an entry in the map
*/
public static class Entry {
/** The key of the entry */
int key;
/** The value of the entry */
Object value;
/** The next entry in the collision chain */
Entry next;
public int getKey() {
return this.key;
}
public Object getValue() {
return this.value;
}
}
/**
* A class for iterating over the contents of an
* ObjIdMap
*/
public class EntryIterator {
/** The current collision chain we're traversing */
private int index;
/** The next Entry we'll iterate over */
private Entry next;
//////////////////// Instance Methods ////////////////////
/**
* Returns the next Entry to visit. Will return null
* after we have iterated through all of the entries.
*/
public Entry next() {
while (this.next == null && this.index < table.length) {
if (table[index] != null) {
this.next = table[index];
}
this.index++;
}
Entry oldNext = this.next;
if (oldNext != null) {
this.next = oldNext.next;
}
return oldNext;
}
}
}