/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: EPoint.java
* Written by: Dmitry Nadezhin, Sun Microsystems.
*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
*
* Electric(tm) is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Electric(tm) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.database.geometry;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import com.sun.electric.util.math.DBMath;
import com.sun.electric.util.math.GenMath;
/**
* The <code>ECoord</code> immutable class defines a point in Electric database.
* Coordiates are snapped to grid according to <code>DBMath.round</code> method.
*/
class ECoord implements Serializable {
/**
* True to gather search values.
*/
private static final boolean GATHER_SEARCHES = false;
/**
* Value in grid units.
*/
private final long gridValue;
/**
* Value in lambda units.
*/
private final transient double lambdaValue;
/**
* True if coordinate is "small int"
*/
private final boolean isSmall;
private static ECoord[] hash = new ECoord[2];
private static int hashSize = 0;
private static final float LOAD_FACTOR = 0.75f;
// Statistics
private static int numSearches, numConflicts, numRetries;
private static long[] searches = new long[1];
/**
* Zero coordinate value.
*/
static final ECoord ZERO = fromGrid(0);
/** Creates a new instance of ECoord */
private ECoord(long gridValue) {
this.gridValue = gridValue;
lambdaValue = DBMath.gridToLambda(gridValue);
isSmall = GenMath.isSmallInt(gridValue);
}
private Object readResolve() {
return fromGrid(gridValue);
}
/**
* Returns ECoord value in lambda units.
* @return ECoord value in lambda units.
*/
double lambdaValue() { return lambdaValue; }
/**
* Returns ECoord value in grid units.
* @return ECoord value in grid units.
*/
long gridValue() { return gridValue; }
/**
* Returns true if ECoord value in grid units is a "small int".
* @return true if ECoord value in grid units is a "small int".
* @See com.sun.electric.database.geometry.GenMath.MIN_SMALL_COORD
* @See com.sun.electric.database.geometry.GenMath.MAX_SMALL_COORD
*/
boolean isSmall() { return isSmall; }
/**
* Returns <code>ECoord</code> from specified lambda value
* snapped to the grid.
* @param v specified lambda value
* @return Snapped ECoord
*/
static ECoord fromLambda(double lambdaValue) {
return fromGrid(DBMath.lambdaToGrid(lambdaValue));
}
/**
* Returns <code>ECoord</code> from specified double value
* snapped to the grid.
* @param v specified double value
* @return Snapped ECoord
*/
static ECoord fromGrid(long gridValue) {
if (GATHER_SEARCHES)
putSearch(gridValue);
numSearches++;
ECoord[] hashCopy = hash;
int hashCode = hash((int)gridValue);
int i = hashCode & (hash.length - 1);
ECoord c = hashCopy[i];
if (c != null) {
if (c.gridValue == gridValue) return c;
int h2 = h2(hashCode);
for (;;) {
numConflicts++;
i = (i + h2) & (hash.length - 1);
c = hashCopy[i];
if (c == null) break;
if (c.gridValue == gridValue) return c;
}
}
synchronized (ECoord.class) {
if (hashCopy != hash || hash[i] != null) {
numRetries++;
return fromGrid(gridValue); // retry after synchronization
}
hashSize++;
ECoord result = hash[i] = new ECoord(gridValue);
if (hash.length*LOAD_FACTOR < hashSize)
rehash();
return result;
}
}
/**
* Returns a <code>String</code> that represents the value
* of this <code>ECoord</code>.
* @return a string representation of this <code>ECoord</code>.
*/
@Override
public String toString() {
return Double.toString(lambdaValue);
}
private static void rehash() {
ECoord[] newHash = new ECoord[hash.length*2];
int mask = newHash.length - 1;
for (ECoord c: hash) {
if (c == null) continue;
int hash = hash((int)c.gridValue);
int h2 = h2(hash);
int i = hash & mask;
while (newHash[i] != null)
i = (i + h2) & mask;
newHash[i] = c;
}
hash = newHash;
}
static int hash(int h) {
h += ~(h << 9);
h ^= (h >>> 14);
h += (h << 4);
h ^= (h >>> 10);
return h;
}
static int h2(int h) {
return 1;
// return (h >> 23) & 0x1FF | 1;
}
private static synchronized void putSearch(long gridValue) {
if (numSearches == searches.length) {
long[] newSearches = new long[numSearches*2];
System.arraycopy(searches, 0, newSearches, 0, numSearches);
searches = newSearches;
}
searches[numSearches] = gridValue;
}
static void dumpSearches(DataOutputStream out) throws IOException {
for (int i = 0; i < numSearches; i++)
out.writeLong(searches[i]);
printStatistics();
}
static void printStatistics() {
System.out.println("ECoord: numSearches=" + numSearches +
" numConflicts=" + numConflicts + "(" + (numConflicts*100/numSearches) + "%) numInserts=" + hashSize + " hashSize=" + hash.length);
if (numRetries > 0)
System.out.println(numRetries + " RETRIES !!!");
}
private static void testHash(ArrayList<Long> input) {
long startTime = System.currentTimeMillis();
for (Long l: input) {
fromLambda(l.doubleValue());
// valueOf(l.longValue());
}
long stopTime = System.currentTimeMillis();
int count = 0;
for (ECoord c: hash) {
if (c == null) continue;
assert c == fromGrid(c.gridValue);
count++;
}
assert count == hashSize;
printStatistics();
System.out.println("t=" + (stopTime - startTime));
}
public static void main(String[] args) {
try {
DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream("ecoord.dat")));
ArrayList<Long> input = new ArrayList<Long>();
while (in.available() > 0)
input.add(Long.valueOf(in.readLong()));
in.close();
for (int i = 0; i < 2; i++) {
System.gc();
try {
Thread.sleep(100);
} catch (InterruptedException e) {}
}
testHash(input);
} catch(IOException e) {
e.printStackTrace();
}
}
}