/**
* Fortika - Robust Group Communication
* Copyright (C) 2002-2006 Sergio Mena de la Cruz (EPFL) (sergio.mena@epfl.ch)
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package framework;
import java.util.Iterator;
import java.util.SortedSet;
import java.util.TreeSet;
/**
* Stores a set of non-negative long integers.
* The subset of type 0, 1, 2, ..., k takes up only a small constant amount
* of memory.
*/
public class CompressedLongSet
//implements Serializable
{
transient SortedSet set;
long filled;
// Does not implement the SortedSet interface.
// Provides similar type safe methods instead.
// XXX: provide a full set of methods.
public CompressedLongSet() {
set = new TreeSet();
filled = 0;
}
public CompressedLongSet(CompressedLongSet right) {
set = new TreeSet(right.set);
filled = right.filled;
}
public void add(long i) {
if (i < 0) {
throw new IllegalArgumentException();
}
if (i < filled) {
return;
} else if (i == filled) {
do {
filled++;
} while (set.remove(new Long(filled)));
} else {
// assert i > filled;
set.add(new Long(i));
}
}
public boolean contains(long i) {
if (i < 0) {
throw new IllegalArgumentException();
}
return (i < filled) ? true : set.contains(new Long(i));
}
/**
* Length of full sequence starting from 0. In other words,
* if this method returns k, then the set contains 0, 1, 2, ..., k-1.
*/
public long getFilled() {
return filled;
}
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("[");
boolean first = true;
if (filled > 0) {
if (filled == 1) {
sb.append("0");
} else {
sb.append("0-"+(filled-1));
}
first = false;
}
Iterator it = set.iterator();
while (it.hasNext()) {
if (!first) {
sb.append(",");
} else {
first = false;
}
sb.append(it.next());
}
sb.append("]");
return sb.toString();
}
public int hashCode() {
return ( (int)((31*filled) & Integer.MAX_VALUE) + set.hashCode() );
}
public boolean equals(Object o) {
if (!(o instanceof CompressedLongSet)) {
return false;
}
CompressedLongSet right = (CompressedLongSet)o;
return filled == right.filled && set.equals(right.set);
}
private synchronized void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException
{
s.defaultWriteObject();
try {
s.writeLong(set.size());
} catch (RuntimeException ex) {
try {
System.out.println("set "+set);
System.out.println("set.size() "+set.size());
} catch (Exception ex2) {
}
throw ex;
}
Iterator it = set.iterator();
while (it.hasNext()) {
long next = ((Long)it.next()).longValue();
s.writeLong(next);
}
}
private synchronized void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException
{
s.defaultReadObject();
// XXX: add sanity checks
long size = s.readLong();
set = new TreeSet();
for (long i=0; i<size; i++) {
long next = s.readLong();
set.add(new Long(next));
}
}
/**
* For testing.
*/
public static void main(String[] args) {
CompressedLongSet set = new CompressedLongSet();
check(set.toString(), "[]");
set.add(3);
check(set.toString(), "[3]");
set.add(0);
check(set.toString(), "[0,3]");
set.add(1);
check(set.toString(), "[0-1,3]");
set.add(2);
check(set.toString(), "[0-3]");
set.add(6);
check(set.toString(), "[0-3,6]");
check(""+set.contains(0), "true");
check(""+set.contains(1), "true");
check(""+set.contains(2), "true");
check(""+set.contains(3), "true");
check(""+set.contains(4), "false");
check(""+set.contains(5), "false");
check(""+set.contains(6), "true");
check(""+set.contains(7), "false");
}
private static void check(String s1, String s2) {
if (!s1.equals(s2)) {
System.out.println("The result of an operation should be\n "
+ s2 +"\nnot\n "+ s1 + " !");
System.exit(1);
}
}
}