698 lines
21 KiB
Java
698 lines
21 KiB
Java
|
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||
|
*
|
||
|
* ***** BEGIN LICENSE BLOCK *****
|
||
|
* Version: MPL 1.1/GPL 2.0
|
||
|
*
|
||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||
|
* 1.1 (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.mozilla.org/MPL/
|
||
|
*
|
||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||
|
* for the specific language governing rights and limitations under the
|
||
|
* License.
|
||
|
*
|
||
|
* The Original Code is Rhino code, released
|
||
|
* May 6, 1999.
|
||
|
*
|
||
|
* The Initial Developer of the Original Code is
|
||
|
* Netscape Communications Corporation.
|
||
|
* Portions created by the Initial Developer are Copyright (C) 1997-2000
|
||
|
* the Initial Developer. All Rights Reserved.
|
||
|
*
|
||
|
* Contributor(s):
|
||
|
* Igor Bukanov
|
||
|
*
|
||
|
* Alternatively, the contents of this file may be used under the terms of
|
||
|
* the GNU General Public License Version 2 or later (the "GPL"), in which
|
||
|
* case the provisions of the GPL are applicable instead of those above. If
|
||
|
* you wish to allow use of your version of this file only under the terms of
|
||
|
* the GPL and not to allow others to use your version of this file under the
|
||
|
* MPL, indicate your decision by deleting the provisions above and replacing
|
||
|
* them with the notice and other provisions required by the GPL. If you do
|
||
|
* not delete the provisions above, a recipient may use your version of this
|
||
|
* file under either the MPL or the GPL.
|
||
|
*
|
||
|
* ***** END LICENSE BLOCK ***** */
|
||
|
|
||
|
package org.mozilla.javascript;
|
||
|
|
||
|
import java.io.Serializable;
|
||
|
import java.io.IOException;
|
||
|
import java.io.ObjectInputStream;
|
||
|
import java.io.ObjectOutputStream;
|
||
|
|
||
|
/**
|
||
|
* Map to associate objects to integers.
|
||
|
* The map does not synchronize any of its operation, so either use
|
||
|
* it from a single thread or do own synchronization or perform all mutation
|
||
|
* operations on one thread before passing the map to others
|
||
|
*
|
||
|
* @author Igor Bukanov
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
public class ObjToIntMap implements Serializable
|
||
|
{
|
||
|
static final long serialVersionUID = -1542220580748809402L;
|
||
|
|
||
|
// Map implementation via hashtable,
|
||
|
// follows "The Art of Computer Programming" by Donald E. Knuth
|
||
|
|
||
|
// ObjToIntMap is a copy cat of ObjToIntMap with API adjusted to object keys
|
||
|
|
||
|
public static class Iterator {
|
||
|
|
||
|
Iterator(ObjToIntMap master) {
|
||
|
this.master = master;
|
||
|
}
|
||
|
|
||
|
final void init(Object[] keys, int[] values, int keyCount) {
|
||
|
this.keys = keys;
|
||
|
this.values = values;
|
||
|
this.cursor = -1;
|
||
|
this.remaining = keyCount;
|
||
|
}
|
||
|
|
||
|
public void start() {
|
||
|
master.initIterator(this);
|
||
|
next();
|
||
|
}
|
||
|
|
||
|
public boolean done() {
|
||
|
return remaining < 0;
|
||
|
}
|
||
|
|
||
|
public void next() {
|
||
|
if (remaining == -1) Kit.codeBug();
|
||
|
if (remaining == 0) {
|
||
|
remaining = -1;
|
||
|
cursor = -1;
|
||
|
}else {
|
||
|
for (++cursor; ; ++cursor) {
|
||
|
Object key = keys[cursor];
|
||
|
if (key != null && key != DELETED) {
|
||
|
--remaining;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public Object getKey() {
|
||
|
Object key = keys[cursor];
|
||
|
if (key == UniqueTag.NULL_VALUE) { key = null; }
|
||
|
return key;
|
||
|
}
|
||
|
|
||
|
public int getValue() {
|
||
|
return values[cursor];
|
||
|
}
|
||
|
|
||
|
public void setValue(int value) {
|
||
|
values[cursor] = value;
|
||
|
}
|
||
|
|
||
|
ObjToIntMap master;
|
||
|
private int cursor;
|
||
|
private int remaining;
|
||
|
private Object[] keys;
|
||
|
private int[] values;
|
||
|
}
|
||
|
|
||
|
public ObjToIntMap() {
|
||
|
this(4);
|
||
|
}
|
||
|
|
||
|
public ObjToIntMap(int keyCountHint) {
|
||
|
if (keyCountHint < 0) Kit.codeBug();
|
||
|
// Table grow when number of stored keys >= 3/4 of max capacity
|
||
|
int minimalCapacity = keyCountHint * 4 / 3;
|
||
|
int i;
|
||
|
for (i = 2; (1 << i) < minimalCapacity; ++i) { }
|
||
|
power = i;
|
||
|
if (check && power < 2) Kit.codeBug();
|
||
|
}
|
||
|
|
||
|
public boolean isEmpty() {
|
||
|
return keyCount == 0;
|
||
|
}
|
||
|
|
||
|
public int size() {
|
||
|
return keyCount;
|
||
|
}
|
||
|
|
||
|
public boolean has(Object key) {
|
||
|
if (key == null) { key = UniqueTag.NULL_VALUE; }
|
||
|
return 0 <= findIndex(key);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get integer value assigned with key.
|
||
|
* @return key integer value or defaultValue if key is absent
|
||
|
*/
|
||
|
public int get(Object key, int defaultValue) {
|
||
|
if (key == null) { key = UniqueTag.NULL_VALUE; }
|
||
|
int index = findIndex(key);
|
||
|
if (0 <= index) {
|
||
|
return values[index];
|
||
|
}
|
||
|
return defaultValue;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get integer value assigned with key.
|
||
|
* @return key integer value
|
||
|
* @throws RuntimeException if key does not exist
|
||
|
*/
|
||
|
public int getExisting(Object key) {
|
||
|
if (key == null) { key = UniqueTag.NULL_VALUE; }
|
||
|
int index = findIndex(key);
|
||
|
if (0 <= index) {
|
||
|
return values[index];
|
||
|
}
|
||
|
// Key must exist
|
||
|
Kit.codeBug();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
public void put(Object key, int value) {
|
||
|
if (key == null) { key = UniqueTag.NULL_VALUE; }
|
||
|
int index = ensureIndex(key);
|
||
|
values[index] = value;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* If table already contains a key that equals to keyArg, return that key
|
||
|
* while setting its value to zero, otherwise add keyArg with 0 value to
|
||
|
* the table and return it.
|
||
|
*/
|
||
|
public Object intern(Object keyArg) {
|
||
|
boolean nullKey = false;
|
||
|
if (keyArg == null) {
|
||
|
nullKey = true;
|
||
|
keyArg = UniqueTag.NULL_VALUE;
|
||
|
}
|
||
|
int index = ensureIndex(keyArg);
|
||
|
values[index] = 0;
|
||
|
return (nullKey) ? null : keys[index];
|
||
|
}
|
||
|
|
||
|
public void remove(Object key) {
|
||
|
if (key == null) { key = UniqueTag.NULL_VALUE; }
|
||
|
int index = findIndex(key);
|
||
|
if (0 <= index) {
|
||
|
keys[index] = DELETED;
|
||
|
--keyCount;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void clear() {
|
||
|
int i = keys.length;
|
||
|
while (i != 0) {
|
||
|
keys[--i] = null;
|
||
|
}
|
||
|
keyCount = 0;
|
||
|
occupiedCount = 0;
|
||
|
}
|
||
|
|
||
|
public Iterator newIterator() {
|
||
|
return new Iterator(this);
|
||
|
}
|
||
|
|
||
|
// The sole purpose of the method is to avoid accessing private fields
|
||
|
// from the Iterator inner class to workaround JDK 1.1 compiler bug which
|
||
|
// generates code triggering VerifierError on recent JVMs
|
||
|
final void initIterator(Iterator i) {
|
||
|
i.init(keys, values, keyCount);
|
||
|
}
|
||
|
|
||
|
/** Return array of present keys */
|
||
|
public Object[] getKeys() {
|
||
|
Object[] array = new Object[keyCount];
|
||
|
getKeys(array, 0);
|
||
|
return array;
|
||
|
}
|
||
|
|
||
|
public void getKeys(Object[] array, int offset) {
|
||
|
int count = keyCount;
|
||
|
for (int i = 0; count != 0; ++i) {
|
||
|
Object key = keys[i];
|
||
|
if (key != null && key != DELETED) {
|
||
|
if (key == UniqueTag.NULL_VALUE) { key = null; }
|
||
|
array[offset] = key;
|
||
|
++offset;
|
||
|
--count;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static int tableLookupStep(int fraction, int mask, int power) {
|
||
|
int shift = 32 - 2 * power;
|
||
|
if (shift >= 0) {
|
||
|
return ((fraction >>> shift) & mask) | 1;
|
||
|
}
|
||
|
else {
|
||
|
return (fraction & (mask >>> -shift)) | 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private int findIndex(Object key) {
|
||
|
if (keys != null) {
|
||
|
int hash = key.hashCode();
|
||
|
int fraction = hash * A;
|
||
|
int index = fraction >>> (32 - power);
|
||
|
Object test = keys[index];
|
||
|
if (test != null) {
|
||
|
int N = 1 << power;
|
||
|
if (test == key
|
||
|
|| (values[N + index] == hash && test.equals(key)))
|
||
|
{
|
||
|
return index;
|
||
|
}
|
||
|
// Search in table after first failed attempt
|
||
|
int mask = N - 1;
|
||
|
int step = tableLookupStep(fraction, mask, power);
|
||
|
int n = 0;
|
||
|
for (;;) {
|
||
|
if (check) {
|
||
|
if (n >= occupiedCount) Kit.codeBug();
|
||
|
++n;
|
||
|
}
|
||
|
index = (index + step) & mask;
|
||
|
test = keys[index];
|
||
|
if (test == null) {
|
||
|
break;
|
||
|
}
|
||
|
if (test == key
|
||
|
|| (values[N + index] == hash && test.equals(key)))
|
||
|
{
|
||
|
return index;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
// Insert key that is not present to table without deleted entries
|
||
|
// and enough free space
|
||
|
private int insertNewKey(Object key, int hash) {
|
||
|
if (check && occupiedCount != keyCount) Kit.codeBug();
|
||
|
if (check && keyCount == 1 << power) Kit.codeBug();
|
||
|
int fraction = hash * A;
|
||
|
int index = fraction >>> (32 - power);
|
||
|
int N = 1 << power;
|
||
|
if (keys[index] != null) {
|
||
|
int mask = N - 1;
|
||
|
int step = tableLookupStep(fraction, mask, power);
|
||
|
int firstIndex = index;
|
||
|
do {
|
||
|
if (check && keys[index] == DELETED) Kit.codeBug();
|
||
|
index = (index + step) & mask;
|
||
|
if (check && firstIndex == index) Kit.codeBug();
|
||
|
} while (keys[index] != null);
|
||
|
}
|
||
|
keys[index] = key;
|
||
|
values[N + index] = hash;
|
||
|
++occupiedCount;
|
||
|
++keyCount;
|
||
|
|
||
|
return index;
|
||
|
}
|
||
|
|
||
|
private void rehashTable() {
|
||
|
if (keys == null) {
|
||
|
if (check && keyCount != 0) Kit.codeBug();
|
||
|
if (check && occupiedCount != 0) Kit.codeBug();
|
||
|
int N = 1 << power;
|
||
|
keys = new Object[N];
|
||
|
values = new int[2 * N];
|
||
|
}
|
||
|
else {
|
||
|
// Check if removing deleted entries would free enough space
|
||
|
if (keyCount * 2 >= occupiedCount) {
|
||
|
// Need to grow: less then half of deleted entries
|
||
|
++power;
|
||
|
}
|
||
|
int N = 1 << power;
|
||
|
Object[] oldKeys = keys;
|
||
|
int[] oldValues = values;
|
||
|
int oldN = oldKeys.length;
|
||
|
keys = new Object[N];
|
||
|
values = new int[2 * N];
|
||
|
|
||
|
int remaining = keyCount;
|
||
|
occupiedCount = keyCount = 0;
|
||
|
for (int i = 0; remaining != 0; ++i) {
|
||
|
Object key = oldKeys[i];
|
||
|
if (key != null && key != DELETED) {
|
||
|
int keyHash = oldValues[oldN + i];
|
||
|
int index = insertNewKey(key, keyHash);
|
||
|
values[index] = oldValues[i];
|
||
|
--remaining;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Ensure key index creating one if necessary
|
||
|
private int ensureIndex(Object key) {
|
||
|
int hash = key.hashCode();
|
||
|
int index = -1;
|
||
|
int firstDeleted = -1;
|
||
|
if (keys != null) {
|
||
|
int fraction = hash * A;
|
||
|
index = fraction >>> (32 - power);
|
||
|
Object test = keys[index];
|
||
|
if (test != null) {
|
||
|
int N = 1 << power;
|
||
|
if (test == key
|
||
|
|| (values[N + index] == hash && test.equals(key)))
|
||
|
{
|
||
|
return index;
|
||
|
}
|
||
|
if (test == DELETED) {
|
||
|
firstDeleted = index;
|
||
|
}
|
||
|
|
||
|
// Search in table after first failed attempt
|
||
|
int mask = N - 1;
|
||
|
int step = tableLookupStep(fraction, mask, power);
|
||
|
int n = 0;
|
||
|
for (;;) {
|
||
|
if (check) {
|
||
|
if (n >= occupiedCount) Kit.codeBug();
|
||
|
++n;
|
||
|
}
|
||
|
index = (index + step) & mask;
|
||
|
test = keys[index];
|
||
|
if (test == null) {
|
||
|
break;
|
||
|
}
|
||
|
if (test == key
|
||
|
|| (values[N + index] == hash && test.equals(key)))
|
||
|
{
|
||
|
return index;
|
||
|
}
|
||
|
if (test == DELETED && firstDeleted < 0) {
|
||
|
firstDeleted = index;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// Inserting of new key
|
||
|
if (check && keys != null && keys[index] != null)
|
||
|
Kit.codeBug();
|
||
|
if (firstDeleted >= 0) {
|
||
|
index = firstDeleted;
|
||
|
}
|
||
|
else {
|
||
|
// Need to consume empty entry: check occupation level
|
||
|
if (keys == null || occupiedCount * 4 >= (1 << power) * 3) {
|
||
|
// Too litle unused entries: rehash
|
||
|
rehashTable();
|
||
|
return insertNewKey(key, hash);
|
||
|
}
|
||
|
++occupiedCount;
|
||
|
}
|
||
|
keys[index] = key;
|
||
|
values[(1 << power) + index] = hash;
|
||
|
++keyCount;
|
||
|
return index;
|
||
|
}
|
||
|
|
||
|
private void writeObject(ObjectOutputStream out)
|
||
|
throws IOException
|
||
|
{
|
||
|
out.defaultWriteObject();
|
||
|
|
||
|
int count = keyCount;
|
||
|
for (int i = 0; count != 0; ++i) {
|
||
|
Object key = keys[i];
|
||
|
if (key != null && key != DELETED) {
|
||
|
--count;
|
||
|
out.writeObject(key);
|
||
|
out.writeInt(values[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void readObject(ObjectInputStream in)
|
||
|
throws IOException, ClassNotFoundException
|
||
|
{
|
||
|
in.defaultReadObject();
|
||
|
|
||
|
int writtenKeyCount = keyCount;
|
||
|
if (writtenKeyCount != 0) {
|
||
|
keyCount = 0;
|
||
|
int N = 1 << power;
|
||
|
keys = new Object[N];
|
||
|
values = new int[2 * N];
|
||
|
for (int i = 0; i != writtenKeyCount; ++i) {
|
||
|
Object key = in.readObject();
|
||
|
int hash = key.hashCode();
|
||
|
int index = insertNewKey(key, hash);
|
||
|
values[index] = in.readInt();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// A == golden_ratio * (1 << 32) = ((sqrt(5) - 1) / 2) * (1 << 32)
|
||
|
// See Knuth etc.
|
||
|
private static final int A = 0x9e3779b9;
|
||
|
|
||
|
private static final Object DELETED = new Object();
|
||
|
|
||
|
// Structure of kyes and values arrays (N == 1 << power):
|
||
|
// keys[0 <= i < N]: key value or null or DELETED mark
|
||
|
// values[0 <= i < N]: value of key at keys[i]
|
||
|
// values[N <= i < 2*N]: hash code of key at keys[i-N]
|
||
|
|
||
|
private transient Object[] keys;
|
||
|
private transient int[] values;
|
||
|
|
||
|
private int power;
|
||
|
private int keyCount;
|
||
|
private transient int occupiedCount; // == keyCount + deleted_count
|
||
|
|
||
|
// If true, enables consitency checks
|
||
|
private static final boolean check = false;
|
||
|
|
||
|
/* TEST START
|
||
|
|
||
|
public static void main(String[] args) {
|
||
|
if (!check) {
|
||
|
System.err.println("Set check to true and re-run");
|
||
|
throw new RuntimeException("Set check to true and re-run");
|
||
|
}
|
||
|
|
||
|
ObjToIntMap map;
|
||
|
map = new ObjToIntMap(0);
|
||
|
testHash(map, 3);
|
||
|
map = new ObjToIntMap(0);
|
||
|
testHash(map, 10 * 1000);
|
||
|
map = new ObjToIntMap();
|
||
|
testHash(map, 10 * 1000);
|
||
|
map = new ObjToIntMap(30 * 1000);
|
||
|
testHash(map, 10 * 100);
|
||
|
map.clear();
|
||
|
testHash(map, 4);
|
||
|
map = new ObjToIntMap(0);
|
||
|
testHash(map, 10 * 100);
|
||
|
}
|
||
|
|
||
|
private static void testHash(ObjToIntMap map, int N) {
|
||
|
System.out.print("."); System.out.flush();
|
||
|
for (int i = 0; i != N; ++i) {
|
||
|
Object key = testKey(i);
|
||
|
check(-1 == map.get(key, -1));
|
||
|
map.put(key, i);
|
||
|
check(i == map.get(key, -1));
|
||
|
}
|
||
|
|
||
|
System.out.print("."); System.out.flush();
|
||
|
for (int i = 0; i != N; ++i) {
|
||
|
Object key = testKey(i);
|
||
|
map.put(key, i);
|
||
|
check(i == map.get(key, -1));
|
||
|
}
|
||
|
|
||
|
check(map.size() == N);
|
||
|
|
||
|
System.out.print("."); System.out.flush();
|
||
|
Object[] keys = map.getKeys();
|
||
|
check(keys.length == N);
|
||
|
for (int i = 0; i != N; ++i) {
|
||
|
Object key = keys[i];
|
||
|
check(map.has(key));
|
||
|
}
|
||
|
|
||
|
|
||
|
System.out.print("."); System.out.flush();
|
||
|
for (int i = 0; i != N; ++i) {
|
||
|
Object key = testKey(i);
|
||
|
check(i == map.get(key, -1));
|
||
|
}
|
||
|
|
||
|
int Nsqrt = -1;
|
||
|
for (int i = 0; ; ++i) {
|
||
|
if (i * i >= N) {
|
||
|
Nsqrt = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
System.out.print("."); System.out.flush();
|
||
|
for (int i = 0; i != N; ++i) {
|
||
|
Object key = testKey(i * i);
|
||
|
map.put(key, i);
|
||
|
check(i == map.get(key, -1));
|
||
|
}
|
||
|
|
||
|
check(map.size() == 2 * N - Nsqrt);
|
||
|
|
||
|
System.out.print("."); System.out.flush();
|
||
|
for (int i = 0; i != N; ++i) {
|
||
|
Object key = testKey(i * i);
|
||
|
check(i == map.get(key, -1));
|
||
|
}
|
||
|
|
||
|
System.out.print("."); System.out.flush();
|
||
|
for (int i = 0; i != N; ++i) {
|
||
|
Object key = testKey(-1 - i * i);
|
||
|
map.put(key, i);
|
||
|
check(i == map.get(key, -1));
|
||
|
}
|
||
|
|
||
|
check(map.size() == 3 * N - Nsqrt);
|
||
|
|
||
|
System.out.print("."); System.out.flush();
|
||
|
for (int i = 0; i != N; ++i) {
|
||
|
Object key = testKey(-1 - i * i);
|
||
|
map.remove(key);
|
||
|
check(!map.has(key));
|
||
|
}
|
||
|
|
||
|
check(map.size() == 2 * N - Nsqrt);
|
||
|
|
||
|
System.out.print("."); System.out.flush();
|
||
|
for (int i = 0; i != N; ++i) {
|
||
|
Object key = testKey(i * i);
|
||
|
check(i == map.get(key, -1));
|
||
|
}
|
||
|
|
||
|
System.out.print("."); System.out.flush();
|
||
|
for (int i = 0; i != N; ++i) {
|
||
|
Object key = testKey(i);
|
||
|
int j = intSqrt(i);
|
||
|
if (j * j == i) {
|
||
|
check(j == map.get(key, -1));
|
||
|
}else {
|
||
|
check(i == map.get(key, -1));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
System.out.print("."); System.out.flush();
|
||
|
for (int i = 0; i != N; ++i) {
|
||
|
Object key = testKey(i * i);
|
||
|
map.remove(key);
|
||
|
check(-2 == map.get(key, -2));
|
||
|
}
|
||
|
|
||
|
System.out.print("."); System.out.flush();
|
||
|
for (int i = 0; i != N; ++i) {
|
||
|
Object key = testKey(i);
|
||
|
map.put(key, i);
|
||
|
check(i == map.get(key, -2));
|
||
|
}
|
||
|
|
||
|
check(map.size() == N);
|
||
|
|
||
|
System.out.print("."); System.out.flush();
|
||
|
for (int i = 0; i != N; ++i) {
|
||
|
Object key = testKey(i);
|
||
|
check(i == map.get(key, -1));
|
||
|
}
|
||
|
|
||
|
System.out.print("."); System.out.flush();
|
||
|
ObjToIntMap copy = (ObjToIntMap)writeAndRead(map);
|
||
|
check(copy.size() == N);
|
||
|
|
||
|
for (int i = 0; i != N; ++i) {
|
||
|
Object key = testKey(i);
|
||
|
check(i == copy.get(key, -1));
|
||
|
}
|
||
|
|
||
|
System.out.print("."); System.out.flush();
|
||
|
checkSameMaps(copy, map);
|
||
|
|
||
|
System.out.println(); System.out.flush();
|
||
|
}
|
||
|
|
||
|
private static void checkSameMaps(ObjToIntMap map1, ObjToIntMap map2) {
|
||
|
check(map1.size() == map2.size());
|
||
|
Object[] keys = map1.getKeys();
|
||
|
check(keys.length == map1.size());
|
||
|
for (int i = 0; i != keys.length; ++i) {
|
||
|
check(map1.get(keys[i], -1) == map2.get(keys[i], -1));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private static void check(boolean condition) {
|
||
|
if (!condition) Kit.codeBug();
|
||
|
}
|
||
|
|
||
|
private static Object[] testPool;
|
||
|
|
||
|
private static Object testKey(int i) {
|
||
|
int MAX_POOL = 100;
|
||
|
if (0 <= i && i < MAX_POOL) {
|
||
|
if (testPool != null && testPool[i] != null) {
|
||
|
return testPool[i];
|
||
|
}
|
||
|
}
|
||
|
Object x = new Double(i + 0.5);
|
||
|
if (0 <= i && i < MAX_POOL) {
|
||
|
if (testPool == null) {
|
||
|
testPool = new Object[MAX_POOL];
|
||
|
}
|
||
|
testPool[i] = x;
|
||
|
}
|
||
|
return x;
|
||
|
}
|
||
|
|
||
|
private static int intSqrt(int i) {
|
||
|
int approx = (int)Math.sqrt(i) + 1;
|
||
|
while (approx * approx > i) {
|
||
|
--approx;
|
||
|
}
|
||
|
return approx;
|
||
|
}
|
||
|
|
||
|
private static Object writeAndRead(Object obj) {
|
||
|
try {
|
||
|
java.io.ByteArrayOutputStream
|
||
|
bos = new java.io.ByteArrayOutputStream();
|
||
|
java.io.ObjectOutputStream
|
||
|
out = new java.io.ObjectOutputStream(bos);
|
||
|
out.writeObject(obj);
|
||
|
out.close();
|
||
|
byte[] data = bos.toByteArray();
|
||
|
java.io.ByteArrayInputStream
|
||
|
bis = new java.io.ByteArrayInputStream(data);
|
||
|
java.io.ObjectInputStream
|
||
|
in = new java.io.ObjectInputStream(bis);
|
||
|
Object result = in.readObject();
|
||
|
in.close();
|
||
|
return result;
|
||
|
}catch (Exception ex) {
|
||
|
throw new RuntimeException("Unexpected");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// TEST END */
|
||
|
|
||
|
}
|