lib/gitrb/trie.rb in gitrb-0.1.5 vs lib/gitrb/trie.rb in gitrb-0.1.6
- old
+ new
@@ -2,74 +2,93 @@
class Trie
include Enumerable
attr_reader :key, :value
- def initialize(key = '', value = nil, children = [])
+ def initialize(key = nil, value = nil, children = [])
@key = key
@value = value
@children = children
end
+ def children
+ @children.compact
+ end
+
def clear
- @key = ''
- @value = nil
- @children.clear
+ @key = @value = nil
+ @children = []
end
+ def empty?
+ self.size == 0
+ end
+
+ def each(&block)
+ yield(@value) if @value
+ children.each {|child| child.each(&block) }
+ end
+
+ def size
+ children.inject(@value ? 1 : 0) {|sum, child| sum + child.size }
+ end
+
def find(key)
- if key.empty?
- self
- else
- child = @children[key[0].ord]
- if child && key[0...child.key.length] == child.key
- child.find(key[child.key.length..-1])
+ if @key
+ if @key.index(key) == 0
+ self
+ elsif key.index(@key) == 0
+ child = @children[index(key)]
+ child ? child.find(key) : Trie.new
else
- nil
+ Trie.new
end
+ else
+ self
end
end
def insert(key, value)
- if key.empty?
+ if !@key
+ @key = key
@value = value
- self
- else
- idx = key[0].ord
- child = @children[idx]
- if child
- child.split(key) if key[0...child.key.length] != child.key
- child.insert(key[child.key.length..-1], value)
+ elsif @key == key
+ @value = value
+ elsif @key.index(key) == 0
+ child = Trie.new(@key, @value, @children)
+ @children = []
+ @children[@key[key.length].ord] = child
+ @key = key
+ @value = value
+ elsif key.index(@key) == 0
+ i = index(key)
+ if @children[i]
+ @children[i].insert(key, value)
else
- @children[idx] = Trie.new(key, value)
+ @children[i] = Trie.new(key, value)
end
- end
- end
+ else
+ n = 0
+ n += 1 while key[n] == @key[n]
- def each(&block)
- yield(@value) if !@key.empty?
- @children.compact.each {|c| c.each(&block) }
- end
+ child1 = Trie.new(@key, @value, @children)
+ child2 = Trie.new(key, value)
- def values
- to_a
+ @value = nil
+ @key = @key[0...n]
+ @children = []
+ @children[index(child1.key)] = child1
+ @children[index(child2.key)] = child2
+ end
end
- def dup
- Trie.new(@key.dup, @value ? @value.dup : nil, @children.map {|c| c ? c.dup : nil })
- end
-
def inspect
"#<Gitrb::Trie @key=#{@key.inspect}, @value=#{@value.inspect}, @children=#{@children.compact.inspect}>"
end
- def split(key)
- prefix = 0
- prefix += 1 while key[prefix] == @key[prefix]
- child = Trie.new(@key[prefix..-1], @value, @children)
- @children = []
- @children[@key[prefix].ord] = child
- @key = @key[0...prefix]
- @value = nil
+ private
+
+ def index(key)
+ key[@key.length].ord
end
end
end