X-Git-Url: http://nitlanguage.org diff --git a/lib/ordered_tree.nit b/lib/ordered_tree.nit index 7216474..86940af 100644 --- a/lib/ordered_tree.nit +++ b/lib/ordered_tree.nit @@ -70,17 +70,47 @@ class OrderedTree[E: Object] # For each element, the ordered array of its direct sub-elements. var sub = new HashMap[E, Array[E]] + # The parent of each element. + # + # Roots have `null` as parent. + private var parents = new HashMap[E, nullable E] + + redef fun length do return parents.length + + redef fun has(e) do return parents.has_key(e) + + # The parent of the element `e` + # + # Roots have `null` as parent. + # + # ~~~ + # var tree = new OrderedTree[Int] + # tree.add(1, 2) + # assert tree.parent(2) == 1 + # assert tree.parent(1) == null + # ~~~ + fun parent(e: E): nullable E do return parents[e] + # Add a new element `e` in the tree. + # # `p` is the parent of `e`. - # if `p` is null, then `e` is a root element. + # If `p` is null, then `e` is a root element. + # + # If `e` is already in the tree, it is detached from its old + # parent and attached to the new parent `p`. fun add(p: nullable E, e: E) do + detach(e) + parents[e] = p if p == null then roots.add(e) - else if sub.has_key(p) then - sub[p].add(e) else - sub[p] = [e] + if not has(p) then add(null, p) + if sub.has_key(p) then + sub[p].add(e) + else + sub[p] = [e] + end end end @@ -90,13 +120,34 @@ class OrderedTree[E: Object] for e in es do add(p, e) end + # Temporary remove `e`. + # + # Children of `e` are left untouched in the tree. + # This make the tree inconstant until `e` is added back. + private fun detach(e: E) + do + var old_parent = parents.get_or_null(e) + if old_parent != null then + var subs = sub[old_parent] + subs.remove(e) + if subs.is_empty then + # remove the sub when all children are detached + # so that `==` and `hash` are sane + # Otherwise an empty array will be considered + # differently than no array. + sub.keys.remove(old_parent) + end + else if roots.has(e) then + roots.remove(e) + end + end + # print the full tree on `o` # Write a ASCII-style tree and use the `display` method to label elements redef fun write_to(stream: Writer) do for r in roots do - stream.write display(r) - stream.write "\n" + write_line(stream, r, "") sub_write_to(stream, r, "") end end @@ -105,18 +156,33 @@ class OrderedTree[E: Object] do if not sub.has_key(e) then return var subs = sub[e] + if subs.is_empty then return var last = subs.last for e2 in subs do if e2 != last then - o.write "{prefix}|--{display(e2)}\n" + write_line(o, e2, prefix+"|--") sub_write_to(o, e2, prefix+"| ") else - o.write "{prefix}`--{display(e2)}\n" + write_line(o, e2, prefix+"`--") sub_write_to(o, e2, prefix+" ") end end end + # Write the full line for the element `e` in `o`. + # + # Basically it does: + # + # ~~~nitish + # o.write "{prefix}{display(e)}\n" + # ~~~ + # + # Usually, you should redefine `display` to change the display of an element. + protected fun write_line(o: Writer, e: E, prefix: String) + do + o.write "{prefix}{display(e)}\n" + end + # Sort roots and other elements using a comparator method # This method basically sorts roots then each group of children fun sort_with(comparator: Comparator)