org.jboss.marshalling.util.IdentityIntSet 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).
/*
* 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 set.
*/
public final class IdentityIntSet 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 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 IdentityIntSet(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];
resizeCount = (int) ((double) initialCapacity * (double) loadFactor);
}
/**
* Clone this set.
*
* @return a cloned set
*/
@SuppressWarnings({ "unchecked" })
public IdentityIntSet clone() {
try {
final IdentityIntSet clone = (IdentityIntSet) super.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 IdentityIntSet(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 IdentityIntSet(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 IdentityIntSet() {
this(0.5f);
}
/**
* Check to see if this set contains a value.
*
* @param key the key
* @return {@code true} if the object is present in the set
*/
public boolean contains(T key) {
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 true;
}
if (v == null) {
// not found
return false;
}
hc = (hc + 1) & mask;
}
}
/**
* Add a value into the set, if it's not already in there.
*
* @param key the key
* @return {@code true} if the object was added, or {@code false} if it was already in the set
*/
public boolean add(T key) {
final Object[] keys = this.keys;
final int mask = keys.length - 1;
Object v;
int hc = System.identityHashCode(key) & mask;
for (int idx = hc;; idx = hc++ & mask) {
v = keys[idx];
if (v == null) {
keys[idx] = key;
if (++count > resizeCount) {
resize();
}
return true;
}
if (v == key) {
return false;
}
}
}
private void resize() {
final Object[] oldKeys = keys;
final int oldsize = oldKeys.length;
if (oldsize >= 0x40000000) {
throw new IllegalStateException("Table full");
}
final int newsize = oldsize << 1;
final int mask = newsize - 1;
final Object[] newKeys = new Object[newsize];
keys = newKeys;
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;
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("Set 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(") }");
} else {
builder.append("(blank)");
}
builder.append('\n');
}
return builder.toString();
}
}