# 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
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
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)