com.landawn.abacus.util.ObjectPool Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of abacus-common Show documentation
Show all versions of abacus-common Show documentation
A general programming library in Java/Android. It's easy to learn and simple to use with concise and powerful APIs.
/*
* Copyright (C) 2015 HaiYang Li
*
* 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.landawn.abacus.util;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import com.landawn.abacus.annotation.Beta;
import com.landawn.abacus.annotation.Internal;
/**
* It's is a multiple-thread safety map with fixed size. it's designed for frequent get and few add/remove operation
* with a few limited keys.
*
* @author Haiyang Li
* @param the key type
* @param the value type
* @since 0.8
*/
@Internal
@Beta
@SuppressWarnings("java:S2160")
public final class ObjectPool extends AbstractMap {
final int capacity;
private final Entry[] table;
private final int indexMask;
private int _size = 0; //NOSONAR
private transient Set _keySet = null; //NOSONAR
private transient Collection _values = null; //NOSONAR
private transient Set> _entrySet; //NOSONAR
/**
*
*
* @param capacity
*/
@SuppressWarnings("unchecked")
public ObjectPool(int capacity) {
this.capacity = capacity;
this.table = new Entry[capacity];
this.indexMask = table.length - 1;
}
/**
*
* @param key
* @return
*/
@Override
public V get(Object key) {
final int hash = hash(key);
final int i = hash & indexMask;
for (Entry entry = table[i]; entry != null; entry = entry.next) {
if ((hash == entry.hash) && key.equals(entry.key)) {
return entry.value;
}
}
return null;
}
/**
*
* @param key
* @param value
* @return
*/
@Override
public V put(K key, V value) {
synchronized (table) {
return internalPut(key, value);
}
}
private V internalPut(K key, V value) {
if ((key == null) || (value == null)) {
throw new NullPointerException();
}
final int hash = hash(key);
final int i = hash & indexMask;
// if (size() > capacity) {
// throw new IndexOutOfBoundsException("Object pool is full with capacity=" + capacity);
// }
//
for (Entry entry = table[i]; entry != null; entry = entry.next) {
if ((hash == entry.hash) && key.equals(entry.key)) {
V previousValue = entry.value;
entry.value = value;
return previousValue;
}
}
Entry entry = new Entry<>(hash, key, value, table[i]);
table[i] = entry;
_keySet = null;
_values = null;
_entrySet = null;
_size++;
return null;
}
/**
*
* @param m
*/
@Override
public void putAll(Map m) {
synchronized (table) {
for (Map.Entry entry : m.entrySet()) {
if (entry.getValue() != null) {
internalPut(entry.getKey(), entry.getValue());
}
}
}
}
/**
*
* @param key
* @return
*/
@Override
public V remove(Object key) {
if (_size == 0) {
return null;
}
final int hash = hash(key);
final int i = hash & indexMask;
synchronized (table) {
Entry prev = table[i];
Entry e = prev;
while (e != null) {
Entry next = e.next;
if ((hash == e.hash) && key.equals(e.key)) {
if (prev == e) {
table[i] = next;
} else {
prev.next = next;
}
_keySet = null;
_values = null;
_entrySet = null;
_size--;
return e.value;
}
prev = e;
e = next;
}
return null;
}
}
/**
*
* @param key
* @return
*/
@Override
public boolean containsKey(Object key) {
final int hash = hash(key);
final int i = hash & indexMask;
for (Entry entry = table[i]; entry != null; entry = entry.next) {
if ((hash == entry.hash) && (entry.value != null) && key.equals(entry.key)) {
return true;
}
}
return false;
}
/**
*
* @param value
* @return
*/
@Override
public boolean containsValue(Object value) {
if (value == null) {
return false;
}
for (Entry element : table) {
for (Entry entry = element; entry != null; entry = entry.next) {
if ((entry.value != null) && value.equals(entry.value)) {
return true;
}
}
}
return false;
}
/**
*
*
* @return
*/
@Override
public Set keySet() {
Set tmp = _keySet;
if (tmp == null) {
synchronized (table) {
tmp = N.newHashSet(_size);
for (Entry element : table) {
for (Entry entry = element; entry != null; entry = entry.next) {
if (entry.value != null) {
tmp.add(entry.key);
}
}
}
tmp = Collections.unmodifiableSet(tmp);
_keySet = tmp;
}
}
return tmp;
}
/**
*
*
* @return
*/
@Override
public Collection values() {
Collection tmp = _values;
if (tmp == null) {
synchronized (table) {
tmp = N.newHashSet(_size);
V value = null;
for (Entry element : table) {
for (Entry entry = element; entry != null; entry = entry.next) {
value = entry.value;
if (value != null) {
tmp.add(value);
}
}
}
tmp = Collections.unmodifiableCollection(tmp);
_values = tmp;
}
}
return tmp;
}
/**
*
*
* @return
*/
@Override
public Set> entrySet() {
Set> tmp = _entrySet;
if (tmp == null) {
synchronized (table) {
tmp = N.newHashSet(_size);
for (Entry element : table) {
for (Entry entry = element; entry != null; entry = entry.next) {
if (entry.value != null) {
tmp.add(entry);
}
}
}
tmp = Collections.unmodifiableSet(tmp);
_entrySet = tmp;
}
}
return tmp;
}
/**
*
*
* @return
*/
@Override
public int size() {
return _size;
}
/**
* Checks if is empty.
*
* @return true, if is empty
*/
@Override
public boolean isEmpty() {
return _size == 0;
}
/**
* Clear.
*/
@Override
public void clear() {
synchronized (table) {
Arrays.fill(table, null);
_keySet = null;
_values = null;
_entrySet = null;
_size = 0;
}
}
/**
*
* @param key
* @return
*/
static int hash(Object key) {
int h;
return (key == null) ? 0 : ((h = key.hashCode()) ^ (h >>> 16));
}
/**
* The Class Entry.
*
* @param the key type
* @param the value type
*/
static class Entry implements Map.Entry {
/** The key. */
final K key;
/** The value. */
V value;
/** The next. */
Entry next;
/** The hash. */
int hash;
/**
* Creates new entry.
*
* @param h
* @param k
* @param v
* @param n
*/
Entry(int h, K k, V v, Entry n) {
value = v;
next = n;
key = k;
hash = h;
}
/**
* Gets the key.
*
* @return
*/
@Override
public final K getKey() {
return key;
}
/**
* Gets the value.
*
* @return
*/
@Override
public final V getValue() {
return value;
}
/**
* Sets the value.
*
* @param newValue
* @return
*/
@Override
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
/**
*
* @param obj
* @return
*/
@Override
public final boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof Map.Entry) {
Map.Entry other = (Map.Entry) obj;
return N.equals(getKey(), other.getKey()) && N.equals(getValue(), other.getValue());
}
return false;
}
/**
*
* @return
*/
@Override
public final int hashCode() {
return N.hashCode(getKey()) ^ N.hashCode(getValue());
}
/**
*
* @return
*/
@Override
public final String toString() {
return getKey() + "=" + getValue();
}
}
}