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=c671aa95188ac59e3797d986eee075d170658f9e;hb=0ae2b770234dfc3cbb18bd38f324125cf0faca07;hp=3ee830b3d1cb161726d0c0c0ccac6b12587c6f54;hpb=24e2b34260f219f0d1644ca7a138894980e25b14;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 index 3ee830b3d..c671aa951 100644 --- 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 @@ -1,445 +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; - } - - }); - */ - } - -} +/******************************************************************************* + * 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; + } + + }); + */ + } + +}