parser: `Visitor::visit` does not accepts `null`
[nit.git] / src / poset.nit
index 65bd98a..0a4a4b9 100644 (file)
@@ -24,18 +24,14 @@ module poset
 #  * transitivity: `self.has_edge(e,f)' and `self.has_edge(f,g)' implies `self.has_edge(e,g)'
 class POSet[E: Object]
        super NaiveCollection[E]
+       super AbstractSorter[E]
 
-       redef fun iterator do return nodes.iterator
+       redef fun iterator do return elements.keys.iterator
 
        # All the nodes
-       private var nodes: Set[E] = new HashSet[E]
-       private var tos: HashMap[E, Set[E]] = new HashMap[E, Set[E]]
-       private var froms: HashMap[E, Set[E]] = new HashMap[E, Set[E]]
-       private var dtos: HashMap[E, Set[E]] = new HashMap[E, Set[E]]
-       private var dfroms: HashMap[E, Set[E]] = new HashMap[E, Set[E]]
        private var elements: HashMap[E, POSetElement[E]] = new HashMap[E, POSetElement[E]]
 
-       redef fun has(e) do return self.nodes.has(e)
+       redef fun has(e) do return self.elements.keys.has(e)
 
        # Add a node (an element) to the posed
        # The new element is added unconnected to any other nodes (it is both a new root and a new leaf).
@@ -43,15 +39,10 @@ class POSet[E: Object]
        # If `e' is already present in the POSet then just return the POSetElement (usually you will prefer []) is this case.
        fun add_node(e: E): POSetElement[E]
        do
-               if nodes.has(e) then return self.elements[e]
-               nodes.add(e)
-               tos[e] = new HashSet[E]
-               tos[e].add(e)
-               froms[e] = new HashSet[E]
-               froms[e].add(e)
-               dtos[e] = new HashSet[E]
-               dfroms[e] = new HashSet[E]
-               var poe = new POSetElement[E](self, e, nodes.length)
+               if elements.keys.has(e) then return self.elements[e]
+               var poe = new POSetElement[E](self, e, elements.length)
+               poe.tos.add(e)
+               poe.froms.add(e)
                self.elements[e] = poe
                return poe
        end
@@ -69,7 +60,7 @@ class POSet[E: Object]
        # REQUIRE: has(e)
        fun [](e: E): POSetElement[E]
        do
-               assert nodes.has(e)
+               assert elements.keys.has(e)
                return self.elements[e]
        end
 
@@ -81,48 +72,56 @@ class POSet[E: Object]
        # FIXME: Do somethind clever to manage loops.
        fun add_edge(f, t: E)
        do
-               add_node(f)
-               add_node(t)
+               var fe = add_node(f)
+               var te = add_node(t)
                # Skip if edge already present
-               if tos[f].has(t) then return
+               if fe.tos.has(t) then return
                # Add the edge and close the transitivity
-               for ff in froms[f] do
-                       for tt in tos[t] do
-                               froms[tt].add ff
-                               tos[ff].add tt
+               for ff in fe.froms do
+                       var ffe = self.elements[ff]
+                       for tt in te.tos do
+                               var tte = self.elements[tt]
+                               tte.froms.add ff
+                               ffe.tos.add tt
                        end
                end
                # Update the transitive reduction
-               if tos[t].has(f) then return # Skip the reduction if there is a loop
+               if te.tos.has(f) then return # Skip the reduction if there is a loop
 
-               for x in dfroms[t].to_a do
-                       if tos[x].has(f) then
-                               dfroms[t].remove(x)
-                               dtos[x].remove(t)
+               for x in te.dfroms.to_a do
+                       var xe = self.elements[x]
+                       if xe.tos.has(f) then
+                               te.dfroms.remove(x)
+                               xe.dtos.remove(t)
                        end
                end
-               for x in dtos[f].to_a do
-                       if froms[x].has(t) then
-                               dfroms[x].remove(f)
-                               dtos[f].remove(x)
+               for x in fe.dtos.to_a do
+                       var xe = self.elements[x]
+                       if xe.froms.has(t) then
+                               xe.dfroms.remove(f)
+                               fe.dtos.remove(x)
                        end
                end
-               dtos[f].add t
-               dfroms[t].add f
+               fe.dtos.add t
+               te.dfroms.add f
        end
 
        # Is there an edge (transitive or not) from `f' to `t'?
        # Since the POSet is reflexive, true is returned if `f == t'.
        fun has_edge(f,t: E): Bool
        do
-               return nodes.has(f) and tos[f].has(t)
+               if not elements.keys.has(f) then return false
+               var fe = self.elements[f]
+               return fe.tos.has(t)
        end
 
        # Is there a direct edge from `f' to `t'?
        # Note that because of loops, the result may not be the expected one.
        fun has_direct_edge(f,t: E): Bool
        do
-               return nodes.has(f) and dtos[f].has(t)
+               if not elements.keys.has(f) then return false
+               var fe = self.elements[f]
+               return fe.dtos.has(t)
        end
 
        # Display the POSet in a gaphical windows.
@@ -133,8 +132,10 @@ class POSet[E: Object]
                var f = new OProcess("dot", "-Txlib")
                #var f = stdout
                f.write "digraph \{\n"
-               for x in nodes do
-                       for y in dtos[x] do
+               for x in elements.keys do
+                       f.write "\"{x}\";\n"
+                       var xe = self.elements[x]
+                       for y in xe.dtos do
                                if self.has_edge(y,x) then
                                        f.write "\"{x}\" -> \"{y}\"[dir=both];\n"
                                else
@@ -154,9 +155,11 @@ class POSet[E: Object]
        # if a == b then return 0
        # else return -1 or 1
        # The total order is stable unless a new node or a new edge is added
-       fun compare(a, b: E): Int
+       redef fun compare(a, b: E): Int
        do
-               var res = tos[a].length <=> tos[b].length
+               var ae = self.elements[a]
+               var be = self.elements[b]
+               var res = ae.tos.length <=> be.tos.length
                if res != 0 then return res
                return elements[a].count <=> elements[b].count
        end
@@ -181,6 +184,11 @@ class POSetElement[E: Object]
        # The real object behind the view
        var element: E
 
+       private var tos = new HashSet[E]
+       private var froms = new HashSet[E]
+       private var dtos = new HashSet[E]
+       private var dfroms = new HashSet[E]
+
        # The rank of the
        # This attribute is used to force a total order for POSet#compare
        private var count: Int
@@ -189,37 +197,37 @@ class POSetElement[E: Object]
        # Since the POSet is reflexive, element is included in the set.
        fun greaters: Collection[E]
        do
-               return self.poset.tos[self.element]
+               return self.tos
        end
 
        # Return the set of all elements `t' that have a direct edge from `element' to `t'.
        fun direct_greaters: Collection[E]
        do
-               return self.poset.dtos[self.element]
+               return self.dtos
        end
 
        # Return the set of all elements `f' that have an edge from `f' to `element'.
        # Since the POSet is reflexive, element is included in the set.
        fun smallers: Collection[E]
        do
-               return self.poset.froms[self.element]
+               return self.froms
        end
 
        # Return the set of all elements `f' that have an edge from `f' to `element'.
        fun direct_smallers: Collection[E]
        do
-               return self.poset.dfroms[self.element]
+               return self.dfroms
        end
 
        # Is there an edge from `object' to `t'?
        fun <=(t: E): Bool
        do
-               return self.poset.tos[self.element].has(t)
+               return self.tos.has(t)
        end
 
        # Is `t != element' and is there an edge from `object' to `t'?
        fun <(t: E): Bool
        do
-               return t != self.element and self.poset.tos[self.element].has(t)
+               return t != self.element and self.tos.has(t)
        end
 end