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

org.jboss.marshalling.util.IdentityIntMap Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

The newest version!
/*
 * JBoss, Home of Professional Open Source.
 * Copyright 2014 Red Hat, Inc., and individual contributors
 * as indicated by the @author tags.
 *
 * 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 org.jboss.marshalling.util;

import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Arrays;

/**
 * An efficient identity object map whose keys are objects and whose values are {@code int}s.
 */
public final class IdentityIntMap implements Cloneable {

    private static final int DEFAULT_REINITIALIZE_CAPACITY_THRESHOLD = 1 << 16; // 65536
    private static final int REINITIALIZE_CAPACITY_THRESHOLD = AccessController.doPrivileged((PrivilegedAction) () -> {
        return Integer.getInteger("jboss.marshalling.identityint.reinitialize.capacity.threshold", DEFAULT_REINITIALIZE_CAPACITY_THRESHOLD);
    });

    private int[] values;
    private Object[] keys;
    private int count;
    private int resizeCount;

    private final int initialCapacity;
    private final float loadFactor;

    /**
     * Construct a new instance with the given initial capacity and load factor.
     *
     * @param initialCapacity the initial capacity
     * @param loadFactor the load factor
     */
    public IdentityIntMap(int initialCapacity, final float loadFactor) {
        if (initialCapacity < 1) {
            throw new IllegalArgumentException("initialCapacity must be > 0");
        }
        if (loadFactor <= 0.0f || loadFactor >= 1.0f) {
            throw new IllegalArgumentException("loadFactor must be > 0.0 and < 1.0");
        }
        if (initialCapacity < 16) {
            initialCapacity = 16;
        } else {
            // round up
            final int c = Integer.highestOneBit(initialCapacity) - 1;
            initialCapacity = Integer.highestOneBit(initialCapacity + c);
        }
        this.initialCapacity = initialCapacity;
        this.loadFactor = loadFactor;
        init();
    }

    private void init() {
        keys = new Object[initialCapacity];
        values = new int[initialCapacity];
        resizeCount = (int) ((double) initialCapacity * (double) loadFactor);
    }

    /**
     * Clone this map.
     *
     * @return a cloned map
     */
    @SuppressWarnings({ "unchecked" })
    public IdentityIntMap clone() {
        try {
            final IdentityIntMap clone = (IdentityIntMap) super.clone();
            clone.values = values.clone();
            clone.keys = keys.clone();
            return clone;
        } catch (CloneNotSupportedException e) {
            throw new IllegalStateException();
        }
    }

    /**
     * Construct a new instance with the given load factor and an initial capacity of 64.
     *
     * @param loadFactor the load factor
     */
    public IdentityIntMap(final float loadFactor) {
        this(64, loadFactor);
    }

    /**
     * Construct a new instance with the given initial capacity and a load factor of {@code 0.5}.
     *
     * @param initialCapacity the initial capacity
     */
    public IdentityIntMap(final int initialCapacity) {
        this(initialCapacity, 0.5f);
    }

    /**
     * Construct a new instance with an initial capacity of 64 and a load factor of {@code 0.5}.
     */
    public IdentityIntMap() {
        this(0.5f);
    }

    /**
     * Get a value from the map.
     *
     * @param key the key
     * @param defVal the value to return if the key is not found
     * @return the map value at the given key, or the value of {@code defVal} if it's not found
     */
    public int get(T key, int defVal) {
        final Object[] keys = this.keys;
        final int mask = keys.length - 1;
        int hc = System.identityHashCode(key) & mask;
        Object v;
        for (;;) {
            v = keys[hc];
            if (v == key) {
                return values[hc];
            }
            if (v == null) {
                // not found
                return defVal;
            }
            hc = (hc + 1) & mask;
        }
    }

    /**
     * Put a value into the map.  Any previous mapping is discarded silently.
     *
     * @param key the key
     * @param value the value to store
     */
    public void put(T key, int value) {
        final Object[] keys = this.keys;
        final int mask = keys.length - 1;
        final int[] values = this.values;
        Object v;
        int hc = System.identityHashCode(key) & mask;
        for (int idx = hc;; idx = hc++ & mask) {
            v = keys[idx];
            if (v == null) {
                keys[idx] = key;
                values[idx] = value;
                if (++count > resizeCount) {
                    resize();
                }
                return;
            }
            if (v == key) {
                values[idx] = value;
                return;
            }
        }
    }

    private void resize() {
        final Object[] oldKeys = keys;
        final int oldsize = oldKeys.length;
        final int[] oldValues = values;
        if (oldsize >= 0x40000000) {
            throw new IllegalStateException("Table full");
        }
        final int newsize = oldsize << 1;
        final int mask = newsize - 1;
        final Object[] newKeys = new Object[newsize];
        final int[] newValues = new int[newsize];
        keys = newKeys;
        values = newValues;
        if ((resizeCount <<= 1) == 0) {
            resizeCount = Integer.MAX_VALUE;
        }
        for (int oi = 0; oi < oldsize; oi ++) {
            final Object key = oldKeys[oi];
            if (key != null) {
                int ni = System.identityHashCode(key) & mask;
                for (;;) {
                    final Object v = newKeys[ni];
                    if (v == null) {
                        // found
                        newKeys[ni] = key;
                        newValues[ni] = oldValues[oi];
                        break;
                    }
                    ni = (ni + 1) & mask;
                }
            }
        }
    }

    public void clear() {
        if (keys.length > REINITIALIZE_CAPACITY_THRESHOLD) {
            // Reinitialize arrays if keys.length exceeds threshold
            init();
        } else {
            Arrays.fill(keys, null);
        }
        count = 0;
    }

    /**
     * Get a string summary representation of this map.
     *
     * @return a string representation
     */
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("Map length = ").append(keys.length).append(", count = ").append(count).append(", resize count = ").append(resizeCount).append('\n');
        for (int i = 0; i < keys.length; i ++) {
            builder.append('[').append(i).append("] = ");
            if (keys[i] != null) {
                final int hc = System.identityHashCode(keys[i]);
                builder.append("{ ").append(keys[i]).append(" (hash ").append(hc).append(", modulus ").append(hc % keys.length).append(") => ").append(values[i]).append(" }");
            } else {
                builder.append("(blank)");
            }
            builder.append('\n');
        }
        return builder.toString();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy