Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.hazelcast.util.SortedHashMap Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2013, Hazelcast, 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.
*/
package com.hazelcast.util;
import java.util.*;
public class SortedHashMap extends AbstractMap {
static final int MAXIMUM_CAPACITY = 1 << 30;
static final int DEFAULT_INITIAL_CAPACITY = 16;
static final float DEFAULT_LOAD_FACTOR = 0.75f;
int modCount = 0;
Entry[] table;
private transient Entry header = null;
int size;
int threshold;
final float loadFactor;
final OrderingType orderingType;
public enum OrderingType {
NONE, LRU, LFU, HASH
}
public SortedHashMap() {
this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, OrderingType.NONE);
}
public SortedHashMap(int initialCapacity) {
this(initialCapacity, DEFAULT_LOAD_FACTOR, OrderingType.NONE);
}
public SortedHashMap(int initialCapacity, OrderingType orderingType) {
this(initialCapacity, DEFAULT_LOAD_FACTOR, orderingType);
}
public SortedHashMap(int initialCapacity, float loadFactor, OrderingType orderingType) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
// Find a power of 2 >= initialCapacity
int capacity = 1;
while (capacity < initialCapacity)
capacity <<= 1;
this.orderingType = orderingType;
this.loadFactor = loadFactor;
threshold = (int) (capacity * loadFactor);
table = new Entry[capacity];
header = new Entry(-1, null, null, null);
header.before = header.after = header;
}
public V put(K key, V value) {
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
public static void touch(SortedHashMap linkedMap, Object key, OrderingType orderingType) {
Entry e = linkedMap.getEntry(key);
if (e != null) {
e.touch(linkedMap, orderingType);
}
}
public static void moveToTop(SortedHashMap linkedMap, Object key) {
Entry e = linkedMap.getEntry(key);
if (e != null) {
e.moveToTop(linkedMap);
}
}
public static OrderingType getOrderingTypeByName(String orderingType) {
return OrderingType.valueOf(orderingType.toUpperCase());
}
public boolean containsKey(Object key) {
return getEntry(key) != null;
}
public V get(Object key) {
Entry e = getEntry(key);
if (e == null)
return null;
e.recordAccess(this);
return e.value;
}
Entry getEntry(Object k) {
int hash = hash(k.hashCode());
int i = indexFor(hash, table.length);
Entry e = table[i];
while (e != null && !(e.hash == hash && eq(k, e.key)))
e = e.next;
return e;
}
static boolean eq(Object x, Object y) {
return x == y || x.equals(y);
}
public void clear() {
modCount++;
Entry[] tab = table;
for (int i = 0; i < tab.length; i++)
tab[i] = null;
size = 0;
header.before = header.after = header;
}
public V remove(Object key) {
Entry e = removeEntryForKey(key);
return (e == null ? null : e.value);
}
Entry removeEntryForKey(Object k) {
int hash = hash(k.hashCode());
int i = indexFor(hash, table.length);
Entry prev = table[i];
Entry e = prev;
while (e != null) {
Entry next = e.next;
if ((e.hash == hash) && (k == e.key || k.equals(e.key))) {
modCount++;
size--;
if (prev == e)
table[i] = next;
else
prev.next = next;
e.recordRemoval(this);
return e;
}
prev = e;
e = next;
}
return e;
}
Entry removeMapping(Object o) {
if (!(o instanceof Map.Entry))
return null;
Map.Entry entry = (Map.Entry) o;
Object k = entry.getKey();
int hash = hash(k.hashCode());
int i = indexFor(hash, table.length);
Entry prev = table[i];
Entry e = prev;
while (e != null) {
Entry next = e.next;
if (e.hash == hash && e.equals(entry)) {
modCount++;
size--;
if (prev == e)
table[i] = next;
else
prev.next = next;
e.recordRemoval(this);
return e;
}
prev = e;
e = next;
}
return e;
}
void addEntry(int hash, K key, V value, int bucketIndex) {
createEntry(hash, key, value, bucketIndex);
Entry eldest = header.after;
if (removeEldestEntry(eldest)) {
removeEntryForKey(eldest.key);
} else {
if (size >= threshold)
resize(2 * table.length);
}
}
protected boolean removeEldestEntry(Map.Entry eldest) {
return false;
}
void createEntry(int hash, K key, V value, int bucketIndex) {
Entry old = table[bucketIndex];
Entry e = new Entry(hash, key, value, old);
table[bucketIndex] = e;
e.addBefore(header);
size++;
}
void resize(int newCapacity) {
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
Entry[] newTable = new Entry[newCapacity];
transfer(newTable);
table = newTable;
threshold = (int) (newCapacity * loadFactor);
}
void transfer(Entry[] newTable) {
int newCapacity = newTable.length;
for (Entry e = header.after; e != header; e = e.after) {
int index = indexFor(e.hash, newCapacity);
e.next = newTable[index];
newTable[index] = e;
}
}
static int hash(int h) {
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
static int indexFor(int h, int length) {
return h & (length - 1);
}
public boolean containsValue(Object value) {
// Overridden to take advantage of faster iterator
if (value == null) {
for (Entry e = header.after; e != header; e = e.after)
if (e.value == null)
return true;
} else {
for (Entry e = header.after; e != header; e = e.after)
if (value.equals(e.value))
return true;
}
return false;
}
static class Entry implements Map.Entry {
K key;
V value;
Entry next;
Entry after;
Entry before;
long accessCount = 1;
long lastAccess = 0;
int hash = -1;
Entry(int hash, K key, V value, Entry next) {
this.key = key;
this.value = value;
this.hash = hash;
this.next = next;
lastAccess = Clock.currentTimeMillis();
}
public K getKey() {
return key;
}
public V getValue() {
return value;
}
public V setValue(V value) {
this.value = value;
return value;
}
public boolean equals(Object o) {
if (!(o instanceof Map.Entry)) {
return false;
}
Map.Entry e = (Map.Entry) o;
Object k1 = getKey();
Object k2 = e.getKey();
if (k1 == k2 || (k1 != null && k1.equals(k2))) {
Object v1 = getValue();
Object v2 = e.getValue();
if (v1 == v2 || (v1 != null && v1.equals(v2))) {
return true;
}
}
return false;
}
public int hashCode() {
return key.hashCode();
}
public String toString() {
return "Entry key=" + getKey() + ", value=" + getValue();
}
private void remove() {
before.after = after;
after.before = before;
}
private void addBefore(Entry existingEntry) {
after = existingEntry;
before = existingEntry.before;
before.after = this;
after.before = this;
}
private void addAfter(Entry existingEntry) {
addBefore(existingEntry.after);
}
/**
* This method is invoked by the superclass whenever the value
* of a pre-existing entry is read by Map.get or modified by Map.set.
* If the enclosing Map is access-ordered, it moves the entry
* to the end of the list; otherwise, it does nothing.
*
* @param lm
*/
void recordAccess(SortedHashMap lm) {
touch(lm, lm.orderingType);
}
void touch(SortedHashMap lm, OrderingType orderingType) {
if (orderingType != OrderingType.NONE) {
lastAccess = Clock.currentTimeMillis();
accessCount++;
lm.modCount++;
if (orderingType == OrderingType.LFU) {
moveLFU(lm);
} else if (orderingType == OrderingType.LRU) {
moveLRU(lm);
} else if (orderingType == OrderingType.HASH) {
moveHash(lm);
} else throw new RuntimeException("Unknown orderingType:" + lm.orderingType);
}
}
void moveLRU(SortedHashMap lm) {
remove();
addBefore(lm.header);
}
void moveLFU(SortedHashMap lm) {
Entry nextOne = after;
boolean shouldMove = false;
while (nextOne != null && accessCount >= nextOne.accessCount && nextOne != lm.header) {
shouldMove = true;
nextOne = nextOne.after;
}
if (shouldMove) {
remove();
addBefore(nextOne);
}
}
void moveHash(SortedHashMap lm) {
Entry nextOne = after;
boolean shouldMove = false;
while (nextOne != null && nextOne != lm.header && value.hashCode() >= nextOne.value.hashCode()) {
shouldMove = true;
nextOne = nextOne.after;
}
if (shouldMove) {
remove();
addBefore(nextOne);
}
}
void moveToTop(SortedHashMap lm) {
remove();
addAfter(lm.header);
}
void recordRemoval(SortedHashMap lm) {
remove();
}
}
private abstract class LinkedHashIterator implements Iterator {
Entry nextEntry = header.after;
Entry lastReturned = null;
int expectedModCount = modCount;
public boolean hasNext() {
return nextEntry != header;
}
public void remove() {
if (lastReturned == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
SortedHashMap.this.remove(lastReturned.key);
lastReturned = null;
expectedModCount = modCount;
}
Entry nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (nextEntry == header)
throw new NoSuchElementException();
Entry e = lastReturned = nextEntry;
nextEntry = e.after;
return e;
}
}
private class KeyIterator extends LinkedHashIterator {
public K next() {
return nextEntry().getKey();
}
}
private class ValueIterator extends LinkedHashIterator {
public V next() {
return nextEntry().value;
}
}
private class EntryIterator extends LinkedHashIterator> {
public Map.Entry next() {
return nextEntry();
}
}
// These Overrides alter the behavior of superclass view iterator() methods
Iterator newKeyIterator() {
return new KeyIterator();
}
Iterator newValueIterator() {
return new ValueIterator();
}
Iterator> newEntryIterator() {
return new EntryIterator();
}
private transient Set> entrySet = null;
transient volatile Set keySet = null;
transient volatile Collection values = null;
public Set keySet() {
Set ks = keySet;
return (ks != null ? ks : (keySet = new KeySet()));
}
private class KeySet extends AbstractSet {
public Iterator iterator() {
return newKeyIterator();
}
public int size() {
return size;
}
public boolean contains(Object o) {
return containsKey(o);
}
public boolean remove(Object o) {
return SortedHashMap.this.removeEntryForKey(o) != null;
}
public void clear() {
SortedHashMap.this.clear();
}
}
public Collection values() {
Collection vs = values;
return (vs != null ? vs : (values = new Values()));
}
private class Values extends AbstractCollection {
public Iterator iterator() {
return newValueIterator();
}
public int size() {
return size;
}
public boolean contains(Object o) {
return containsValue(o);
}
public void clear() {
SortedHashMap.this.clear();
}
}
public Set> entrySet() {
Set> es = entrySet;
return (es != null ? es : (entrySet = (Set>) new EntrySet()));
}
private class EntrySet extends AbstractSet {
public Iterator iterator() {
return newEntryIterator();
}
public boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry e = (Map.Entry) o;
Entry candidate = getEntry(e.getKey());
return candidate != null && candidate.equals(e);
}
public boolean remove(Object o) {
return removeMapping(o) != null;
}
public int size() {
return size;
}
public void clear() {
SortedHashMap.this.clear();
}
}
}