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-util-se Show documentation
Show all versions of abacus-util-se 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.Internal;
// TODO: Auto-generated Javadoc
/**
* 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
public final class ObjectPool extends AbstractMap {
/** The capacity. */
final int capacity;
/** The table. */
private final Entry[] table;
/** The index mask. */
private final int indexMask;
/** The size. */
private int size = 0;
/** The key set. */
private Set keySet = null;
/** The values. */
private Collection values = null;
/** The entry set. */
private Set> entrySet;
/**
* Instantiates a new object pool.
*
* @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) {
if ((key == null) || (value == null)) {
throw new NullPointerException();
}
final int hash = hash(key);
final int i = hash & indexMask;
synchronized (table) {
// 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 extends K, ? extends V> m) {
V value = null;
for (K key : m.keySet()) {
value = m.get(key);
if (value != null) {
put(key, value);
}
}
}
/**
*
* @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 true, if successful
*/
@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 true, if successful
*/
@Override
public boolean containsValue(Object value) {
if (value == null) {
return false;
}
for (int i = 0, len = table.length; i < len; i++) {
for (Entry entry = table[i]; 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) {
tmp = N.newHashSet(N.initHashCapacity(size));
for (int i = 0, len = table.length; i < len; i++) {
for (Entry entry = table[i]; 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) {
tmp = N.newHashSet(size < ((int) (Integer.MAX_VALUE / 1.25) - 1) ? (int) (size * 1.25) + 1 : Integer.MAX_VALUE /*N.initHashCapacity(size)*/);
V value = null;
for (int i = 0, len = table.length; i < len; i++) {
for (Entry entry = table[i]; 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) {
tmp = N.newHashSet(N.initHashCapacity(size));
for (int i = 0, len = table.length; i < len; i++) {
for (Entry entry = table[i]; 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 final 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 true, if successful
*/
@Override
public final boolean equals(Object obj) {
if (obj == this) {
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();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy