--- /dev/null
+package org.simantics.scl.runtime;
+
+import gnu.trove.map.hash.TCustomHashMap;
+import gnu.trove.set.hash.THashSet;
+import gnu.trove.strategy.HashingStrategy;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+
+import org.simantics.scl.runtime.function.Function;
+import org.simantics.scl.runtime.function.FunctionImpl1;
+import org.simantics.scl.runtime.function.FunctionImpl2;
+import org.simantics.scl.runtime.tuple.Tuple2;
+
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class Lists {
+
+ public static List map(Function f, List l) {
+ ArrayList result = new ArrayList(l.size());
+ for(Object a : l)
+ result.add(f.apply(a));
+ return result;
+ }
+
+ public static void iter(Function f, List l) {
+ for(Object a : l)
+ f.apply(a);
+ }
+
+ public static List filter(Function p, List l) {
+ ArrayList result = new ArrayList(Math.min(10, l.size()));
+ for(Object a : l)
+ if((Boolean)p.apply(a))
+ result.add(a);
+ return result;
+ }
+
+ public static List filterJust(List l) {
+ ArrayList result = new ArrayList(Math.min(10, l.size()));
+ for(Object a : l)
+ if(a != null)
+ result.add(a);
+ return result;
+ }
+
+ public static List reverse(List l) {
+ ArrayList result = new ArrayList(l.size());
+ for(int i=l.size()-1;i>=0;--i)
+ result.add(l.get(i));
+ return result;
+ }
+
+ public static Object foldl(Function f, Object initial, List l) {
+ for(Object a : l)
+ initial = f.apply(initial, a);
+ return initial;
+ }
+
+ // (b -> Maybe (a, b)) -> b -> [a]
+ public static List unfoldr(Function f, Object state) {
+ ArrayList result = new ArrayList();
+ while(true) {
+ Object r = f.apply(state);
+ if(r == null)
+ return result;
+ Tuple2 t = (Tuple2)r;
+ result.add(t.c0);
+ state = t.c1;
+ }
+ }
+
+ public static Object foldr(Function f, Object initial, List l) {
+ for(int i=l.size()-1;i>=0;--i)
+ initial = f.apply(initial, l.get(i));
+ return initial;
+ }
+
+ public static Object foldl1(Function f, List l) {
+ Iterator it = l.iterator();
+ Object initial = it.next();
+ while(it.hasNext())
+ initial = f.apply(initial, it.next());
+ return initial;
+ }
+
+ public static Object foldr1(Function f, List l) {
+ int i=l.size()-1;
+ Object initial = l.get(i);
+ for(--i;i>=0;--i)
+ initial = f.apply(initial, l.get(i));
+ return initial;
+ }
+
+ public static List _pp(List a, List b) {
+ ArrayList result = new ArrayList(a.size() + b.size());
+ result.addAll(a);
+ result.addAll(b);
+ return result;
+ }
+
+ public static List concat(List l) {
+ int size = 0;
+ for(Object e : l)
+ size += ((List)e).size();
+ ArrayList result = new ArrayList(size);
+ for(Object e : l)
+ result.addAll((List)e);
+ return result;
+ }
+
+ public static List append(List a, List b) {
+ ArrayList result = new ArrayList(a.size() + b.size());
+ result.addAll(a);
+ result.addAll(b);
+ return result;
+ }
+
+ public static List concatMap(Function f, List l) {
+ return concat(map(f, l));
+ }
+
+ public static int length(List l) {
+ return l.size();
+ }
+
+ public static boolean forall(Function p, List l) {
+ for(Object e : l)
+ if(!(Boolean)p.apply(e))
+ return false;
+ return true;
+ }
+
+ public static boolean exists(Function p, List l) {
+ for(Object e : l)
+ if((Boolean)p.apply(e))
+ return true;
+ return false;
+ }
+
+ public static Object get(List l, double i) {
+ return l.get((int)i);
+ }
+
+ public static List build(Function f) {
+ return (List)f.apply(new ArrayList(),
+ new FunctionImpl2() {
+ @Override
+ public Object apply(Object p0, Object p1) {
+ ((List)p0).add(p1);
+ return p0;
+ }
+ });
+ }
+
+ public static List range(int from, int to) {
+ ArrayList result = new ArrayList();
+ while(from <= to) {
+ result.add(from);
+ ++from;
+ }
+ return result;
+ }
+
+ public static List newList() {
+ return new ArrayList(2);
+ }
+
+ public static void add(List a, Object b) {
+ a.add(b);
+ }
+
+ public static List zip(List a, List b) {
+ int len = Math.min(a.size(), b.size());
+ ArrayList result = new ArrayList(len);
+ for(int i=0;i<len;++i)
+ result.add(new Tuple2(a.get(i), b.get(i)));
+ return result;
+ }
+
+ public static List zipWith(Function f, List a, List b) {
+ int len = Math.min(a.size(), b.size());
+ ArrayList result = new ArrayList(len);
+ for(int i=0;i<len;++i)
+ result.add(f.apply(a.get(i), b.get(i)));
+ return result;
+ }
+
+ public static Tuple2 unzip(List in) {
+ int len = in.size();
+ ArrayList a = new ArrayList(len);
+ ArrayList b = new ArrayList(len);
+ for(int i=0;i<len;++i) {
+ Tuple2 tuple = (Tuple2)in.get(i);
+ a.add(tuple.c0);
+ b.add(tuple.c1);
+ }
+ return new Tuple2(a, b);
+ }
+
+ public static Function indexWith(final Function hash, final Function eq, List<Tuple2> l) {
+ final TCustomHashMap<Object,Object> map = new TCustomHashMap<Object,Object>(
+ new HashingStrategy<Object>() {
+ private static final long serialVersionUID = 3130052128660420673L;
+
+ @Override
+ public int computeHashCode(Object object) {
+ return (Integer)hash.apply(object);
+ }
+
+ @Override
+ public boolean equals(Object o1, Object o2) {
+ return (Boolean)eq.apply(o1, o2);
+ }
+ });
+ for(Tuple2 t : l)
+ map.put(t.c0, t.c1);
+ return new FunctionImpl1<Object,Object>() {
+ @Override
+ public Object apply(Object p0) {
+ return map.get(p0);
+ }
+ };
+ }
+
+ // groupWith :: (a -> Integer) -> (a -> a -> Boolean) -> (a -> b) -> [a] -> [(b, [a])]
+ @SuppressWarnings("serial")
+ public static ArrayList<Tuple2> groupWith(final Function hash, final Function eq, Function keyFunction, Function valueFunction, List<Object> input) {
+ final TCustomHashMap<Object,ArrayList<Object>> map = new TCustomHashMap<Object,ArrayList<Object>>(
+ new HashingStrategy<Object>() {
+ @Override
+ public int computeHashCode(Object object) {
+ return (Integer)hash.apply(object);
+ }
+
+ @Override
+ public boolean equals(Object o1, Object o2) {
+ return (Boolean)eq.apply(o1, o2);
+ }
+ });
+ ArrayList<Tuple2> result = new ArrayList<Tuple2>();
+ for(Object o : input) {
+ Object key = keyFunction.apply(o);
+ ArrayList<Object> l = map.get(key);
+ if(l == null) {
+ l = new ArrayList<Object>();
+ map.put(key, l);
+ result.add(new Tuple2(key, l));
+ }
+ l.add(valueFunction.apply(o));
+ }
+ return result;
+ }
+
+ public static List sortWith(final Function compare, List l) {
+ Object[] result = l.toArray(new Object[l.size()]);
+ Arrays.sort(result, new Comparator() {
+ @Override
+ public int compare(Object o1, Object o2) {
+ return (Integer)compare.apply(o1, o2);
+ }
+ });
+ return Arrays.asList(result);
+ }
+
+ public static List uniqueWith(Function compare, List l) {
+ ArrayList result = new ArrayList(Math.min(10, l.size()));
+ outerLoop:
+ for(int i=0;i<l.size();++i) {
+ Object el = l.get(i);
+ for(int j=0;j<result.size();++j)
+ if(compare.apply(el, result.get(j)).equals(Boolean.TRUE))
+ continue outerLoop;
+ result.add(el);
+ }
+ return result;
+ }
+
+ public static List deleteAllBy(Function compare, List a, List b) {
+ ArrayList result = new ArrayList(Math.min(10, a.size()));
+ outerLoop:
+ for(Object el : a) {
+ for(Object el2 : b)
+ if(compare.apply(el, el2).equals(Boolean.TRUE))
+ continue outerLoop;
+ result.add(el);
+ }
+ return result;
+ }
+
+ public static List<Object> unique(List<Object> l) {
+ THashSet<Object> set = new THashSet<Object>();
+ for(Object el : l)
+ set.add(el);
+ return Arrays.asList(set.toArray(new Object[set.size()]));
+ }
+}