]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/map/AssociativeMap.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.utils.datastructures / src / org / simantics / utils / datastructures / map / AssociativeMap.java
diff --git a/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/map/AssociativeMap.java b/bundles/org.simantics.utils.datastructures/src/org/simantics/utils/datastructures/map/AssociativeMap.java
new file mode 100644 (file)
index 0000000..97ae6ad
--- /dev/null
@@ -0,0 +1,194 @@
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
+ * in Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ *     VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.utils.datastructures.map;\r
+\r
+import gnu.trove.map.hash.THashMap;\r
+import gnu.trove.set.hash.THashSet;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Collections;\r
+\r
+/**\r
+ * Associative map of n-tuples. Tuple is the primitive of this data structure.\r
+ * It describes an association between objects.\r
+ * The number of fields in each tuple must match the level of associativity.\r
+ * <P>\r
+ * Associative map allows quick queries of tuples by pre-indexing its content.\r
+ * Indexing requires that the object is told ahead which combinations of fields\r
+ * to cache. Each combination is described with {@link Associativity} object\r
+ * at construction, and for each description a new hashmap is created.\r
+ * \r
+ * Example, fully associative map for 4-tuples, use\r
+ * \r
+ *   AssociativeMap map = new AssociativeMap( Associativity.fullAssociativity( 4 ) );\r
+ *   map.addStatements( new Tuple( cluster, subject, predicate, object ) );\r
+ * \r
+ * Example, BijectionMap\r
+ * \r
+ *   AssociativeMap bijectionMap =\r
+ *       new AssociativeMap( new Associativity(false, true), new Associativity(true, false) )\r
+ * \r
+ *   bijectionMap.addStatements( new Tuple("x", "y") );\r
+ * <P>\r
+ * Queries are described with {@link Tuple}-instances. null value describes\r
+ * open ended value and actual object restriction.\r
+ * \r
+ * Example, query for all Tuples with "x" as the first argument:\r
+ * \r
+ *   bijectionMap.getStatements(new Tuple("x", null), null);;\r
+ * \r
+ * @see Associativity\r
+ * @see Tuple\r
+ * @author Toni Kalajainen <toni.kalajainen@vtt.fi>\r
+ */\r
+public class AssociativeMap {\r
+\r
+    /** Number of dimensions */\r
+    int level;\r
+    /** Maps sorted by TupleQueryAssociativity, TupleQuery, Tuples */\r
+    THashMap<Tuple, THashSet<Tuple>> [] maps;\r
+    /** Tuple query for all statements */\r
+    Tuple tupleQueryAllTuples;\r
+    /** Associativities */\r
+    Associativity[] associativities;\r
+\r
+    /**\r
+     * Create partially associative map of n-tuples.\r
+     * \r
+     * @param associativenesses\r
+     */\r
+    @SuppressWarnings("unchecked")\r
+    public AssociativeMap(Associativity ... associativenesses)\r
+    {\r
+        if (associativenesses==null) throw new NullPointerException();\r
+        if (associativenesses.length==0) throw new IllegalArgumentException();\r
+        this.associativities = associativenesses;\r
+        level = associativenesses[0].getLevel();\r
+        for (int i=1; i<associativenesses.length; i++)\r
+            if (associativenesses[i].getLevel()!=level)\r
+                throw new IllegalArgumentException("Levels are different");\r
+\r
+        int count = (1 << level)-1;\r
+        maps = new THashMap[count];\r
+        for (Associativity a : associativenesses)\r
+        {\r
+            int associativity = a.dimensionAssociativity;\r
+            // omit last and replaces with the first\r
+            if (associativity == count) associativity = 0;\r
+            if (maps[associativity]!=null) continue;\r
+            THashMap<Tuple, THashSet<Tuple>> map = new THashMap<Tuple, THashSet<Tuple>>();\r
+            maps[associativity] = map;\r
+        }\r
+        tupleQueryAllTuples = new Tuple(new Object[level]);\r
+    }\r
+\r
+    public void add(Collection<Tuple> stms)\r
+    {\r
+        for (int associativity=0; associativity<maps.length; associativity++) {\r
+            THashMap<Tuple, THashSet<Tuple>> map = maps[associativity];\r
+            if (map==null) continue;\r
+            for (Tuple stm : stms) {\r
+                if (!stm.isFull()) throw new IllegalArgumentException("Tuple Query cannot be added.");\r
+                Tuple tupleQuery = createTupleQuery(stm, associativity);\r
+                THashSet<Tuple> set = map.get(tupleQuery);\r
+                if (set==null) map.put(tupleQuery, set = new THashSet<Tuple>());\r
+                set.add(stm);\r
+            }\r
+        }\r
+    }\r
+\r
+    public void add(Tuple...stms)\r
+    {\r
+        for (int associativity=0; associativity<maps.length; associativity++) {\r
+            THashMap<Tuple, THashSet<Tuple>> map = maps[associativity];\r
+            if (map==null) continue;\r
+            for (Tuple stm : stms) {\r
+                if (!stm.isFull()) throw new IllegalArgumentException("Tuple Query cannot be added.");\r
+                Tuple tupleQuery = createTupleQuery(stm, associativity);\r
+                THashSet<Tuple> set = map.get(tupleQuery);\r
+                if (set==null) map.put(tupleQuery, set = new THashSet<Tuple>());\r
+                set.add(stm);\r
+            }\r
+        }\r
+    }\r
+\r
+    public void remove(Collection<Tuple> stms) {\r
+        for (int associativity=0; associativity<maps.length; associativity++) {\r
+            THashMap<Tuple, THashSet<Tuple>> map = maps[associativity];\r
+            if (map==null) continue;\r
+            for (Tuple stm : stms) {\r
+                Tuple tupleQuery = createTupleQuery(stm, associativity);\r
+                THashSet<Tuple> set = map.get(tupleQuery);\r
+                if (set==null) continue;\r
+                set.remove(stm);\r
+            }\r
+        }\r
+    }\r
+\r
+    public Collection<Tuple> get(Tuple tupleQuery, Collection<Tuple> result)\r
+    throws UnsupportedOperationException\r
+    {\r
+        if (tupleQuery ==null || tupleQuery.getLevel() != level) throw new IllegalArgumentException();\r
+\r
+        /** Special case, query for existance of a specific tuple */\r
+        if (tupleQuery.associativity == maps.length) {\r
+            THashMap<Tuple, THashSet<Tuple>> map = maps[0];\r
+            if (map==null) throw new UnsupportedOperationException();\r
+            THashSet<Tuple> set = map.get(tupleQueryAllTuples);\r
+            if (result == null) {\r
+                if (set!=null && set.contains(tupleQuery))\r
+                    return Collections.singleton(tupleQuery);\r
+                else\r
+                    return Collections.emptySet();\r
+            } else {\r
+                if (set.contains(tupleQuery))\r
+                    result.add(tupleQuery);\r
+                return result;\r
+            }\r
+        }\r
+\r
+        THashMap<Tuple, THashSet<Tuple>> map = maps[tupleQuery.associativity];\r
+        if (map==null) throw new UnsupportedOperationException();\r
+        THashSet<Tuple> set = map.get(tupleQuery);\r
+        if (set==null) return Collections.emptySet();\r
+        if (result == null) result = new ArrayList<Tuple>(set.size());\r
+        for (Tuple t : set)\r
+            result.add(t);\r
+        return result;\r
+    }\r
+\r
+    public Associativity[] getAssociativities() {\r
+        return associativities;\r
+    }\r
+\r
+    private static Tuple createTupleQuery(Tuple tuple, int associativity)\r
+    {\r
+        if (tuple.associativity == associativity) return tuple;\r
+        int mask = 1;\r
+        int level = tuple.getLevel();\r
+        Object fields[] = new Object[level];\r
+        for (int i=0; i<level; i++)\r
+        {\r
+            if ((associativity & mask)>0)\r
+                fields[i] = tuple.getField(i);\r
+            mask <<= 1;\r
+        }\r
+        return new Tuple(fields);\r
+    }\r
+\r
+    public int getLevel() {\r
+        return level;\r
+    }\r
+\r
+}\r
+\r