/*
Copyright 2014 Julia s.r.l.
This file is part of BeeDeeDee.
BeeDeeDee 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.
BeeDeeDee 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 BeeDeeDee. If not, see <http://www.gnu.org/licenses/>.
*/
package com.juliasoft.beedeedee.factories;
import static com.juliasoft.julia.checkers.nullness.assertions.NullnessAssertions.assertNonNull;
import java.util.Arrays;
class SimpleUniqueTable implements UniqueTable {
protected static final int VAR_OFFSET = 0;
protected static final int LOW_OFFSET = 1;
protected static final int HIGH_OFFSET = 2;
protected static final int NEXT_OFFSET = 3;
protected static final int HASHCODEAUX_OFFSET = 4;
protected static final int NODE_SIZE = 5;
protected volatile int[] ut;
protected volatile int[] H;
protected volatile int size;
protected volatile int nextPos;
protected volatile ComputationCache computationCache;
protected volatile RestrictCache restrictCache;
protected volatile ReplaceCache replaceCache;
protected volatile QuantCache quantCache;
protected volatile EquivCache equivCache;
protected volatile RenameWithLeaderCache rwlCache;
protected volatile SqueezeEquivCache squeezeEquivCache;
private final int[] hitCounters = new int[Operator.values().length];
private final int[] opCounters = new int[Operator.values().length];
protected int hashCodeAuxCounter;
protected SimpleUniqueTable(int size, int cacheSize) {
this.size = size;
this.ut = new int[size * getNodeSize()];
this.H = new int[size];
this.computationCache = new ComputationCache(cacheSize);
this.restrictCache = new RestrictCache(Math.max(1, cacheSize / 20));
this.replaceCache = new ReplaceCache(Math.max(1, cacheSize / 20));
this.quantCache = new QuantCache(Math.max(1, cacheSize / 20));
this.equivCache = new EquivCache(Math.max(1, cacheSize / 20));
this.rwlCache = new RenameWithLeaderCache(Math.max(1, cacheSize / 20));
this.squeezeEquivCache = new SqueezeEquivCache(Math.max(1, cacheSize / 20));
Arrays.fill(H, -1);
}
protected int getNodeSize() {
return NODE_SIZE;
}
@Override
public final int getSize() {
return size;
}
@Override
public final int getCacheSize() {
return computationCache.getSize();
}
@Override
public final int nodesCount() {
return nextPos;
}
@Override
public final void printStatistics() {
for (int i = 0; i < opCounters.length; i++) {
System.out.print(" +" + opCounters[i]);
System.out.print(" *" + hitCounters[i]);
}
}
/*
* Node accessor methods
*/
protected boolean isVarLowHigh(int id, int var, int low, int high) {
int pos = id * getNodeSize() + 2;
return ut[pos--] == high && ut[pos--] == low && ut[pos] == var;
}
@Override
public int var(int id) {
return ut[id * getNodeSize() + VAR_OFFSET];
}
@Override
public int low(int id) {
return ut[id * getNodeSize() + LOW_OFFSET];
}
@Override
public int high(int id) {
return ut[id * getNodeSize() + HIGH_OFFSET];
}
protected int next(int id) {
return ut[id * getNodeSize() + NEXT_OFFSET];
}
protected int hashCodeAux(int id) {
return ut[id * getNodeSize() + HASHCODEAUX_OFFSET];
}
/*
* Node mutator methods
*/
protected int setAtNextPos(int varNumber, int lowNode, int highNode, int next) {
int nextPos = this.nextPos++;
int pos = nextPos * getNodeSize();
int[] table = ut;
table[pos++] = varNumber;
table[pos++] = lowNode;
table[pos++] = highNode;
table[pos++] = next;
table[pos] = hashCodeAuxCounter++;
return nextPos;
}
protected void setNext(int node, int nextNode) {
ut[node * getNodeSize() + NEXT_OFFSET] = nextNode;
}
@Override
public String toString() {
String s = "";
int nextPos = this.nextPos * getNodeSize();
for (int i = 0; i < nextPos; i++) {
if (i % getNodeSize() == 0) {
s += i / getNodeSize() + ": \t" + var(i / getNodeSize()) + "\t";
} else {
s += ut[i] + "\t";
}
if ((i + 1) % getNodeSize() == 0) {
s += "\n";
}
}
return s;
}
@Override
public String toDot() {
String s = "digraph G {\n";
// skip terminals
for (int i = 0; i < nextPos; i++) {
s += i + " -> " + low(i) + " [style=dotted];\n";
s += i + " -> " + high(i) + ";\n";
}
s += "}\n";
return s;
}
/*
* Cache management
*/
@Override
public final int getFromCache(Operator op, int bdd1, int bdd2) {
assertNonNull(op);
return computationCache.get(op, bdd1, bdd2);
}
@Override
public final void putIntoCache(Operator op, int bdd1, int bdd2, int result) {
assertNonNull(op);
computationCache.put(op, bdd1, bdd2, result);
}
protected final int hash(int var, int low, int high) {
return hash(var, low, high, size);
}
protected int hash(int var, int low, int high, int size) {
int temp = (low ^ (high << 1) ^ var) % size;
if (temp < 0) {
temp = -temp;
if (temp > size)
return size - 1;
}
return temp;
/*
int num = low;
while (low > 0) {
low >>>= 1;
high <<= 1;
}
return (num |= high) >= 0 ? num % size : (-num) % size;
*/
}
@Override
public int get(int var, int low, int high) {
int bin, pos = hash(var, low, high);
if ((bin = H[pos]) < 0 || var(bin) > var)
return H[pos] = setAtNextPos(var, low, high, bin);
else
do {
if (isVarLowHigh(bin, var, low, high))
return bin;
int old = bin;
if ((bin = next(bin)) < 0 || var(bin) > var) {
setNext(old, nextPos);
return setAtNextPos(var, low, high, bin);
}
}
while (true);
}
public final RestrictCache getRestrictCache() {
return restrictCache;
}
public final ReplaceCache getReplaceCache() {
return replaceCache;
}
public final QuantCache getQuantCache() {
return quantCache;
}
}