Class: Sqreen::Trie
- Inherits:
-
Struct
- Object
- Struct
- Sqreen::Trie
- Defined in:
- lib/sqreen/trie.rb
Instance Attribute Summary collapse
-
#family ⇒ Object
Returns the value of attribute family.
-
#head ⇒ Object
Returns the value of attribute head.
-
#max_num_bits ⇒ Object
readonly
Returns the value of attribute max_num_bits.
-
#num_active_nodes ⇒ Object
Returns the value of attribute num_active_nodes.
Instance Method Summary collapse
-
#initialize(*args) ⇒ Trie
constructor
A new instance of Trie.
- #insert(arg_prefix) ⇒ Object
- #search_best(addr, family) ⇒ Object
- #search_matching(addr, family) ⇒ Object
-
#to_dot(header = true) ⇒ Object
generate pdf with ‘dot -Tpdf <input> > foo.pdf`.
Constructor Details
#initialize(*args) ⇒ Trie
Returns a new instance of Trie.
15 16 17 18 19 20 |
# File 'lib/sqreen/trie.rb', line 15 def initialize(*args) super self.family ||= Socket::AF_INET self.num_active_nodes = 0 @max_num_bits = family == Socket::AF_INET ? 32 : 128 end |
Instance Attribute Details
#family ⇒ Object
Returns the value of attribute family
12 13 14 |
# File 'lib/sqreen/trie.rb', line 12 def family @family end |
#head ⇒ Object
Returns the value of attribute head
12 13 14 |
# File 'lib/sqreen/trie.rb', line 12 def head @head end |
#max_num_bits ⇒ Object (readonly)
Returns the value of attribute max_num_bits.
13 14 15 |
# File 'lib/sqreen/trie.rb', line 13 def max_num_bits @max_num_bits end |
#num_active_nodes ⇒ Object
Returns the value of attribute num_active_nodes
12 13 14 |
# File 'lib/sqreen/trie.rb', line 12 def num_active_nodes @num_active_nodes end |
Instance Method Details
#insert(arg_prefix) ⇒ Object
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/sqreen/trie.rb', line 22 def insert(arg_prefix) raise 'family mismatch' if arg_prefix.family != family if head.nil? node = Node.new( arg_prefix.bitlen, # bit arg_prefix, nil, nil, nil, #l , r, parent ) self.head = node self.num_active_nodes += 1 return node end arg_addr = arg_prefix.address arg_bitlen = arg_prefix.bitlen xcur = self.head # descend until we find the end of the tree or go past the # bitlen of the prefix we're adding while xcur.bit < arg_bitlen || xcur.empty? if bit_set?(arg_addr, xcur.bit) break if xcur.r.nil? xcur = xcur.r else break if xcur.l.nil? xcur = xcur.l end end trie_addr = xcur.prefix.address # find first bit that differs between addr and trie_addr cmp_bit_end = [arg_bitlen, xcur.bit].min # after last to be compared differ_bit = (0...cmp_bit_end).find do |i| bit_set?(arg_addr, i) ^ bit_set?(trie_addr, i) end differ_bit = cmp_bit_end if differ_bit.nil? # go up till we find the parent before the bits differ xparent = xcur.parent while !xparent.nil? && xparent.bit >= differ_bit xcur = xparent xparent = xcur.parent end # case 1: replace current node's prefix if differ_bit == arg_bitlen && xcur.bit == arg_bitlen xcur.prefix = arg_prefix return xcur end xnew = Node.new(arg_prefix.bitlen, arg_prefix, nil, nil, nil) self.num_active_nodes += 1 # case 2: append below found node if xcur.bit == differ_bit xnew.parent = xcur if bit_set?(arg_addr, xcur.bit) xcur.r = xnew else xcur.l = xnew end return xnew end # case 3: take place of found node if arg_bitlen == differ_bit if bit_set?(trie_addr, arg_bitlen) xnew.r = xcur else xnew.l = xcur end xnew.parent = xcur.parent if xcur.parent.nil? self.head = xnew elsif xcur.parent.r.equal?(xcur) xcur.parent.r = xnew else xcur.parent.l = xnew end xcur.parent = xnew return xnew end # case 4: need to add intermediate node to be parent of the # both xnew and xcur # last arg is the parent of the new node xglue = Node.new(differ_bit, nil, nil, nil, xcur.parent) self.num_active_nodes += 1 if bit_set?(arg_addr, differ_bit) xglue.r = xnew xglue.l = xcur else xglue.r = xcur xglue.l = xnew end xnew.parent = xglue if xcur.parent.nil? self.head = xglue elsif xcur.equal?(xcur.parent.r) xcur.parent.r = xglue else xcur.parent.l = xglue end xcur.parent = xglue xnew end |
#search_best(addr, family) ⇒ Object
172 173 174 175 176 177 178 179 180 |
# File 'lib/sqreen/trie.rb', line 172 def search_best(addr, family) nodes = search_common(addr, family) for i in (nodes.size - 1).downto(0) xcur = nodes[i] return node_to_ip_addr(xcur) if xcur.prefix.matches?(addr, family) end nil end |
#search_matching(addr, family) ⇒ Object
182 183 184 185 186 187 |
# File 'lib/sqreen/trie.rb', line 182 def search_matching(addr, family) nodes = search_common(addr, family) nodes.select { |xcur| xcur.prefix.matches?(addr, family) } .map { |xcur| node_to_ip_addr(xcur) } .reverse end |
#to_dot(header = true) ⇒ Object
generate pdf with ‘dot -Tpdf <input> > foo.pdf`
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/sqreen/trie.rb', line 144 def to_dot(header = true) res = '' res = "graph trie {\n" if header next_name = 'a' obj_label_map = Hash.new do |h, k| h[k] = next_name next_name = next_name.next h[k] end head.walk(max_num_bits, true) do |node| node_name = obj_label_map[node.object_id] if node.empty? label = "<glue at bit #{node.bit}>" else ip_addr = IPAddr.new(node.prefix.address, node.prefix.family) label = ip_addr.to_s + '/' + node.prefix.bitlen.to_s end res += "#{node_name} [label=\"#{label}\"]\n" res += "#{node_name} -- #{obj_label_map[node.l.object_id]} [label=\"l\"]\n" if node.l res += "#{node_name} -- #{obj_label_map[node.r.object_id]} [label=\"r\"]\n" if node.r end res += "}\n" if header res end |