poset: add lookup services in Map to search using keys inhierarchies.
authorJean Privat <jean@pryen.org>
Thu, 15 Jun 2017 19:37:18 +0000 (15:37 -0400)
committerJean Privat <jean@pryen.org>
Thu, 15 Jun 2017 20:48:14 +0000 (16:48 -0400)
3 main methods:

* `Map::lookup_all_values` collect all values of the greaters of an element
* `Map::lookup_values` collect only the values of the most specific greaters of an element
* `MultiHashMap::lookup_joined_values` collect and join the values of the most specific greaters of an element

Since many models entities in nitc are in some poset, these services could be used
to add and retrieve metadata while automatically taking in account inheritance or importation.

Signed-off-by: Jean Privat <jean@pryen.org>

lib/more_collections.nit
lib/poset.nit

index 81688d9..184419c 100644 (file)
@@ -16,6 +16,7 @@
 module more_collections is serialize
 
 import serialization
+import poset
 
 # Simple way to store an `HashMap[K, Array[V]]`
 #
@@ -102,6 +103,35 @@ class MultiHashMap[K, V]
                        if x.is_empty then keys.remove(k)
                end
        end
+
+       # Search the values in `pe.greaters` from the most smaller elements that have a value.
+       #
+       # Elements without values are ignored.
+       #
+       # Basically, values defined in nearest greater elements of `pe` are inherited.
+       #
+       # ~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["E", "D", "C", "B", "A"])
+       # pos.add_chain(["D", "X", "B"])
+       #
+       # var map = new MultiHashMap[String, String]
+       # map["A"].append(["a", "1"])
+       # map["C"].append(["c", "2"])
+       # map["X"].append(["x", "2"])
+       # map["E"].add "e"
+       #
+       # assert map.lookup_joined_values(pos["B"]).has_exactly(["a", "1"])
+       # assert map.lookup_joined_values(pos["C"]).has_exactly(["c", "2"])
+       # assert map.lookup_joined_values(pos["D"]).has_exactly(["c", "x", "2"])
+       # ~~~
+       fun lookup_joined_values(pe: POSetElement[K]): Set[V]
+       do
+               var res = new Set[V]
+               for k in pe.poset.select_smallest(filter_keys(pe.greaters)) do res.add_all self[k]
+               return res
+
+       end
 end
 
 # Simple way to store an `HashMap[K1, HashMap[K2, V]]`
index 98205ac..767b27d 100644 (file)
@@ -729,3 +729,84 @@ class POSetElement[E]
                end
        end
 end
+
+redef class MapRead[K, V]
+       # Return all elements of `keys` that have a value.
+       #
+       # ~~~
+       # var map = new Map[String, String]
+       # map["A"] = "a"
+       # map["B"] = "b"
+       # map["C"] = "c"
+       #
+       # assert map.filter_keys(["B"]) == ["B"]
+       # assert map.filter_keys(["A", "Z", "C"]) == ["A", "C"]
+       # assert map.filter_keys(["X", "Y", "Z"]).is_empty
+       # ~~~
+       #
+       # `has_key` is used to filter.
+       fun filter_keys(keys: Collection[nullable Object]): Array[K]
+       do
+               var res = new Array[K]
+               for e in keys do
+                       if has_key(e) then res.add e
+               end
+               return res
+       end
+
+       # Search all the values in `pe.greaters`.
+       #
+       # Elements without values are ignored.
+       #
+       # Basically, values defined in all greater elements of `pe` are inherited.
+       #
+       # ~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["E", "D", "C", "B", "A"])
+       # pos.add_chain(["D", "X", "B"])
+       #
+       # var map = new HashMap[String, String]
+       # map["A"] = "a"
+       # map["C"] = "c"
+       # map["X"] = "x"
+       # map["E"] = "e"
+       #
+       # assert map.lookup_all_values(pos["B"]).has_exactly(["a"])
+       # assert map.lookup_all_values(pos["C"]).has_exactly(["a", "c"])
+       # assert map.lookup_all_values(pos["D"]).has_exactly(["a", "c", "x"])
+       # ~~~
+       fun lookup_all_values(pe: POSetElement[K]): Set[V]
+       do
+               var res = new Set[V]
+               for k in filter_keys(pe.greaters) do res.add self[k]
+               return res
+       end
+
+       # Combine the values in `pe.greaters` from the most smaller elements that have a value.
+       #
+       # Elements without values are ignored.
+       #
+       # Basically, values defined in nearest greater elements of `pe` are inherited.
+       #
+       # ~~~
+       # var pos = new POSet[String]
+       # pos.add_chain(["E", "D", "C", "B", "A"])
+       # pos.add_chain(["D", "X", "B"])
+       #
+       # var map = new HashMap[String, String]
+       # map["A"] = "a"
+       # map["C"] = "c"
+       # map["X"] = "x"
+       # map["E"] = "e"
+       #
+       # assert map.lookup_values(pos["B"]).has_exactly(["a"])
+       # assert map.lookup_values(pos["C"]).has_exactly(["c"])
+       # assert map.lookup_values(pos["D"]).has_exactly(["c", "x"])
+       # ~~~
+       fun lookup_values(pe: POSetElement[K]): Set[V]
+       do
+               var res = new Set[V]
+               for k in pe.poset.select_smallest(filter_keys(pe.greaters)) do res.add self[k]
+               return res
+       end
+end