From 76c10dada86fd807d36ccafca393e945e381696a Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Sat, 12 Nov 2016 02:13:42 +0000 Subject: initial --- lib/msgthr/container.rb | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 lib/msgthr/container.rb (limited to 'lib/msgthr/container.rb') diff --git a/lib/msgthr/container.rb b/lib/msgthr/container.rb new file mode 100644 index 0000000..30f6775 --- /dev/null +++ b/lib/msgthr/container.rb @@ -0,0 +1,73 @@ +# Copyright (C) 2016 all contributors +# License: GPL-2.0+ + +# An internal container class, this is exposed for sorting APIs +# but should not be initialized in your own code. +class Msgthr::Container + + # Unique message identifier, typically the Message-Id header for mail + # and news messages. This may be any hashable object, Integer values + # are allowed and will not be coerced to string values. + attr_reader :mid + + # Opaque data pointer, may be used by the user for any purpose. + # This may be +nil+ to denote missing (aka "ghost") messages. + attr_accessor :msg + + attr_accessor :children # :nodoc: + attr_accessor :parent # :nodoc: + + def initialize(mid) # :nodoc: + @mid = mid + @children = {} # becomes an Array after order! + @parent = nil + @msg = nil # opaque + end + + # returns the topmost message container with an opaque message pointer + # in it. This may be +nil+ if none are available. + def topmost + q = [ self ] + while cont = q.shift + return cont if cont.msg + q.concat(cont.children.values) + end + nil + end + + def add_child(child) # :nodoc: + raise 'cannot become child of self' if child == self + cid = child.mid + + # reparenting: + parent = child.parent and parent.children.delete(cid) + + @children[cid] = child + child.parent = self + end + + def has_descendent(child) # :nodoc: + seen = Hash.new(0) + while child + return true if self == child || (seen[child] += 1) != 0 + child = child.parent + end + false + end + + def order! # :nodoc: + seen = { @mid => true } + q = [ self ] + while cur = q.shift + c = [] + cur.children.each do |cmid, cont| + next if seen[cmid] + c << cont + seen[cmid] = true + end.clear + yield(c) if c.size > 1 + cur.children = c + q.concat(c) + end + end +end -- cgit v1.2.3-24-ge0c7