/*
* Copyright (C) 2009-2012 University of Freiburg
*
* This file is part of SMTInterpol.
*
* SMTInterpol is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* SMTInterpol 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with SMTInterpol. If not, see <http://www.gnu.org/licenses/>.
*/
package de.uni_freiburg.informatik.ultimate.smtinterpol.util;
/**
* An allocator for integers. It allocates integers from a given interval with
* the guarantee that you always get the lowest not-allocated integer.
*
* You might increase the interval by freeing a value which has previously not
* been part of the allocation interval, but you should never double free the
* same integer without allocating it in between.
* @author Juergen Christ
*/
public class IntAllocator {
private static class IntervalNode {
int mLow,mUp;
IntervalNode mLeft,mRight;
public IntervalNode(int low,int up) {
mLow = low;
mUp = up;
mLeft = mRight = null;
}
}
private IntervalNode mRoot;
/**
* Create an allocator for the interval <code>[low,up)</code>
* @param low Lower interval bound (inclusive).
* @param up Upper interval bound (exclusive).
*/
public IntAllocator(int low,int up) {
mRoot = new IntervalNode(low,up);
}
public boolean isEmpty() {
return mRoot == null;
}
/**
* Allocate the lowest unallocated integer managed by this allocator.
* @return Lowest unallocated integer.
*/
public int alloc() {
if (mRoot.mLow == mRoot.mUp) {
throw new RuntimeException("Allocation on empty IntAllocator");
}
IntervalNode allocNode = mRoot;
IntervalNode parent = null;
while (allocNode.mLeft != null) {
parent = allocNode;
allocNode = allocNode.mLeft;
}
final int res = allocNode.mLow++;
if (allocNode.mLow == allocNode.mUp) {
if (parent == null) {
// empty allocator
mRoot = allocNode.mRight;
} else {
parent.mLeft = allocNode.mRight;
}
}
return res;
}
/**
* Allocate a sequence of integer.
* @param n Number of integers to allocate.
* @return Allocated integers.
*/
public int[] alloc(int n) {
final int[] res = new int[n];
for (int i = 0; i < n; ++i) {
res[i] = alloc();
}
return res;
}
/**
* Free one integer.
* @param val Integer to free.
*/
public void free(int val) {
if (mRoot == null) {
mRoot = new IntervalNode(val,val + 1);
} else {
IntervalNode insert = mRoot;
while (true) {
if (val + 1 == insert.mLow) {
// lower extend
insert.mLow = val;
joinLeft(insert);
return;
} else if (val == insert.mUp) {
++insert.mUp;
joinRight(insert);
return;
} else if (val < insert.mLow) {
if (insert.mLeft == null) {
insert.mLeft = new IntervalNode(val,val + 1);
return;
}
insert = insert.mLeft;
} else {
if (insert.mRight == null) {
insert.mRight = new IntervalNode(val,val + 1);
return;
}
insert = insert.mRight;
}
}
}
}
/**
* Free a sequence of integers.
* @param vals Sequence to free.
*/
public void free(int[] vals) {
for (final int val : vals) {
free(val);
}
}
private void joinLeft(IntervalNode insert) {
IntervalNode prev = insert.mLeft;
if (prev == null) {
return;
}
IntervalNode parent = insert;
while (prev.mRight != null) {
parent = prev;
prev = prev.mRight;
}
if (insert.mLow == prev.mUp) {
insert.mLow = prev.mLow;
// Remove prev
if (parent == insert) {
parent.mLeft = prev.mLeft;
} else {
parent.mRight = prev.mLeft;
}
}
}
private void joinRight(IntervalNode insert) {
IntervalNode next = insert.mRight;
if (next == null) {
return;
}
IntervalNode parent = insert;
while (next.mLeft != null) {
parent = next;
next = next.mLeft;
}
if (insert.mUp == next.mLow) {
insert.mUp = next.mUp;
// Remove next
if (parent == insert) {
parent.mRight = next.mRight;
} else {
parent.mLeft = next.mRight;
}
}
}
/**
* Get the highest allocated value.
* @return Highest allocated value.
*/
public int peekLast() {
if (mRoot.mLow == mRoot.mUp) {
return mRoot.mLow - 1;
}
IntervalNode allocNode = mRoot;
while (allocNode.mRight != null) {
allocNode = allocNode.mRight;
}
return allocNode.mLow - 1;
}
}