All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.landawn.abacus.util.ObjectPool Maven / Gradle / Ivy

Go to download

A general programming library in Java/Android. It's easy to learn and simple to use with concise and powerful APIs.

There is a newer version: 2.1.12
Show newest version
/*
 * 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 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