X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.utils.datastructures%2Fsrc%2Forg%2Fsimantics%2Futils%2Fdatastructures%2Fpersistent%2FImmutableSet.java;fp=bundles%2Forg.simantics.utils.datastructures%2Fsrc%2Forg%2Fsimantics%2Futils%2Fdatastructures%2Fpersistent%2FImmutableSet.java;h=3ee830b3d1cb161726d0c0c0ccac6b12587c6f54;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/persistent/ImmutableSet.java b/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/persistent/ImmutableSet.java new file mode 100644 index 000000000..3ee830b3d --- /dev/null +++ b/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/persistent/ImmutableSet.java @@ -0,0 +1,445 @@ +/******************************************************************************* + * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * in Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.utils.datastructures.persistent; + +import gnu.trove.procedure.TObjectProcedure; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Random; +import java.util.Set; + +public class ImmutableSet> { + + @SuppressWarnings({ "rawtypes" }) + static final ImmutableSet EMPTY = new EmptyImmutableSet(); + + private static class EmptyImmutableSet> extends ImmutableSet { + public EmptyImmutableSet() { + isBlack = true; + } + + protected org.simantics.utils.datastructures.persistent.ImmutableSet addRec(T obj) { + return new ImmutableSet(obj); + } + + protected org.simantics.utils.datastructures.persistent.ImmutableSet removeRec(T obj) { + return null; + } + + public boolean contains(T obj) { + return false; + } + + @Override + public boolean forEach(TObjectProcedure arg0) { + return true; + } + + @Override + void print(int arg0) { + } + } + + ImmutableSet left; + T key; + ImmutableSet right; + boolean isBlack; + + protected ImmutableSet( + ImmutableSet left, + T key, + ImmutableSet right, + boolean isBlack) { + this.left = left; + this.right = right; + this.key = key; + this.isBlack = isBlack; + } + + @SuppressWarnings("unchecked") + public ImmutableSet(T key) { + this(EMPTY, key, EMPTY, false); + } + + @SuppressWarnings("unchecked") + public static > ImmutableSet of(T ... array) { + if(array.length == 0) + return EMPTY; + ImmutableSet ret = new ImmutableSet(array[0]); + for(int i=1;i> ImmutableSet of(Collection c) { + Iterator it = c.iterator(); + if(!it.hasNext()) + return EMPTY; + ImmutableSet ret = new ImmutableSet(it.next()); + while(it.hasNext()) + ret = ret.add(it.next()); + return ret; + } + + private ImmutableSet() { + } + + public boolean contains(T obj) { + int cmp = obj.compareTo(key); + if(cmp < 0) + return left.contains(obj); + else if(cmp > 0) + return right.contains(obj); + else + return true; + } + + protected ImmutableSet addRec(T obj) { + int cmp = obj.compareTo(key); + if(cmp < 0) { + ImmutableSet newLeft = left.addRec(obj); + if(newLeft == left) + return this; + if(isBlack) + return balance(newLeft, key, right); + else + return red(newLeft, key, right); + } + else if(cmp > 0) { + ImmutableSet newRight = right.addRec(obj); + if(newRight == right) + return this; + if(isBlack) + return balance(left, key, newRight); + else + return red(left, key, newRight); + } + else + return this; + } + + /** + * Assumes this is a black nonempty node. + * + * Removes obj from the tree. The returned tree has always + * one black node less in every branch (even if nothing is + * removed). + * + * @param obj + * @return + */ + protected ImmutableSet removeRec(T obj) { + int cmp = obj.compareTo(key); + if(cmp < 0) { + ImmutableSet newLeft = left.removeRec(obj); + if(newLeft == null) + return null; + else if(left.isBlack) + return balleft(newLeft, key, right); + else + return red(newLeft, key, right); + } + else if(cmp > 0) { + ImmutableSet newRight = right.removeRec(obj); + if(newRight == null) + return null; + else if(right.isBlack) + return balright(left, key, newRight); + else + return red(left, key, newRight); + } + else + return append(left, right); + } + + /** + * Assumes a and b have the same black depth and keys in a are strictly less + * than keys in b. Creates a new tree with the same black depth as a and b. + * + * @param + * @param a + * @param b + * @return + */ + protected static > ImmutableSet append(ImmutableSet a, ImmutableSet b) { + if(a==EMPTY) + return b; + if(b==EMPTY) + return a; + if(a.isBlack) { + if(b.isBlack) { + ImmutableSet middle = append(a.right, b.left); + if(middle.isBlack) + return balleft(a.left, a.key, black(middle, b.key, b.right)); + else + return red(black(a.left, a.key, middle.left), middle.key, black(middle.right, b.key, b.right)); + } + else + return red(append(a, b.left), b.key, b.right); + } + else { + if(b.isBlack) + return red(a.left, a.key, append(a.right, b)); + else { + ImmutableSet middle = append(a.right, b.left); + if(middle.isBlack) + return red(a.left, a.key, red(middle, b.key, b.right)); + else + return red(red(a.left, a.key, middle.left), middle.key, red(middle.right, b.key, b.right)); + } + } + } + + public T getFirst() { + if(left == EMPTY) + return key; + else + return left.getFirst(); + } + + static private > ImmutableSet balance( + ImmutableSet left, + T key, + ImmutableSet right) { + if(!left.isBlack) { + if(!left.left.isBlack) + return red( + toBlack(left.left), + left.key, + black(left.right, key, right) + ); + else if(!left.right.isBlack) + return red( + black(left.left, left.key, left.right.left), + left.right.key, + black(left.right.right, key, right) + ); + } + if(!right.isBlack) { + if(!right.left.isBlack) + return red( + black(left, key, right.left.left), + right.left.key, + black(right.left.right, right.key, right.right) + ); + else if(!right.right.isBlack) + return red( + black(left, key, right.left), + right.key, + toBlack(right.right) + ); + } + return black(left, key, right); + } + + static private > ImmutableSet black( + ImmutableSet left, + T key, + ImmutableSet right) { + return new ImmutableSet(left, key, right, true); + } + + static private > ImmutableSet red( + ImmutableSet left, + T key, + ImmutableSet right) { + return new ImmutableSet(left, key, right, false); + } + + static private > ImmutableSet toBlack(ImmutableSet tree) { + if(tree.isBlack) + return tree; + else + return black(tree.left, tree.key, tree.right); + } + + static private > ImmutableSet toRed(ImmutableSet tree) { + if(tree.isBlack) + return red(tree.left, tree.key, tree.right); + else + return tree; + } + + + static private > ImmutableSet balleft( + ImmutableSet left, + T key, + ImmutableSet right) { + if(left.isBlack) { + if(right.isBlack) + return balance(left, key, toRed(right)); + else + return red(black(left, key, right.left.left), right.left.key, balance(right.left.right, right.key, toRed(right.right))); + } + else + return red(toBlack(left), key, right); + } + + static private > ImmutableSet balright( + ImmutableSet left, + T key, + ImmutableSet right) { + if(right.isBlack) { + if(left.isBlack) + return balance(toRed(left), key, right); + else + return red(balance(toRed(left.left), left.key, left.right.left), left.right.key, black(left.right.right, key, right)); + } + else + return red(left, key, toBlack(right)); + } + + public ImmutableSet add(T obj) { + ImmutableSet tree = addRec(obj); + tree.isBlack = true; + return tree; + } + + public ImmutableSet remove(T obj) { + ImmutableSet tree = removeRec(obj); + if(tree == null) + return this; + if(tree.isBlack) + return tree; + else + return black(tree.left, tree.key, tree.right); + } + + public boolean forEach(TObjectProcedure procedure) { + if(left.forEach(procedure)) + if(procedure.execute(key)) + return right.forEach(procedure); + return false; + } + + public ImmutableSet addAll(Iterable c) { + ImmutableSet ret = this; + for(T t : c) + ret = ret.add(t); + return ret; + } + + static class AddAll> implements TObjectProcedure { + + ImmutableSet result; + + public AddAll(ImmutableSet result) { + this.result = result; + } + + @Override + public boolean execute(T arg0) { + result = result.add(arg0); + return true; + } + + } + + public ImmutableSet addAll(ImmutableSet c) { + if(this==EMPTY) + return c; + if(c==EMPTY) + return this; + AddAll proc = new AddAll(this); + c.forEach(proc); + return proc.result; + } + + /************************************************************************** + * + * Testing + * + ************************************************************************** + */ + + void print(int indentation) { + left.print(indentation + 1); + for(int i=0;i> ImmutableSet empty() { + return EMPTY; + } + + public void validate() { + validateRec(); + if(!isBlack) + System.out.println("Root is not black"); + } + + @SuppressWarnings("unchecked") + public static void main(String[] args) { + ImmutableSet set = ImmutableSet.EMPTY; + final Set set2 = new HashSet(); + + Random random = new Random(); + for(int i=0;i<10000;++i) { + int r1 = random.nextInt(1000); + int r2 = random.nextInt(1000); + set = set.add(r1); + set = set.remove(r2); + set2.add(r1); + set2.remove(r2); + set.validate(); + + for(Integer v : set2) + if(!set.contains(v)) + System.out.println("set2 has more elements"); + set.forEach(new TObjectProcedure() { + + @Override + public boolean execute(Integer arg0) { + if(!set2.contains(arg0)) + System.out.println("set has more elements"); + return true; + } + + }); + } + + /* + map.forEach(new TObjectProcedure() { + + @Override + public boolean execute(Integer arg0) { + System.out.println(arg0); + return true; + } + + }); + */ + } + +}