Signed-off-by: Cristian Staretu <cristian.staretu@gmail.com>
| ... | ... |
@@ -53,7 +53,7 @@ clone git github.com/gorilla/mux e444e69cbd |
| 53 | 53 |
clone git github.com/kr/pty 5cf931ef8f |
| 54 | 54 |
clone git github.com/mattn/go-shellwords v1.0.0 |
| 55 | 55 |
clone git github.com/mattn/go-sqlite3 v1.1.0 |
| 56 |
-clone git github.com/tchap/go-patricia v2.1.0 |
|
| 56 |
+clone git github.com/tchap/go-patricia v2.2.4 |
|
| 57 | 57 |
clone git github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3 |
| 58 | 58 |
# forked golang.org/x/net package includes a patch for lazy loading trace templates |
| 59 | 59 |
clone git golang.org/x/net 2beffdc2e92c8a3027590f898fe88f69af48a3f8 https://github.com/tonistiigi/net.git |
| ... | ... |
@@ -5,16 +5,22 @@ |
| 5 | 5 |
|
| 6 | 6 |
package patricia |
| 7 | 7 |
|
| 8 |
-import "sort" |
|
| 8 |
+import ( |
|
| 9 |
+ "fmt" |
|
| 10 |
+ "io" |
|
| 11 |
+ "sort" |
|
| 12 |
+) |
|
| 9 | 13 |
|
| 10 | 14 |
type childList interface {
|
| 11 | 15 |
length() int |
| 12 | 16 |
head() *Trie |
| 13 | 17 |
add(child *Trie) childList |
| 18 |
+ remove(b byte) |
|
| 14 | 19 |
replace(b byte, child *Trie) |
| 15 |
- remove(child *Trie) |
|
| 16 | 20 |
next(b byte) *Trie |
| 17 | 21 |
walk(prefix *Prefix, visitor VisitorFunc) error |
| 22 |
+ print(w io.Writer, indent int) |
|
| 23 |
+ total() int |
|
| 18 | 24 |
} |
| 19 | 25 |
|
| 20 | 26 |
type tries []*Trie |
| ... | ... |
@@ -38,7 +44,7 @@ type sparseChildList struct {
|
| 38 | 38 |
|
| 39 | 39 |
func newSparseChildList(maxChildrenPerSparseNode int) childList {
|
| 40 | 40 |
return &sparseChildList{
|
| 41 |
- children: make(tries, 0, DefaultMaxChildrenPerSparseNode), |
|
| 41 |
+ children: make(tries, 0, maxChildrenPerSparseNode), |
|
| 42 | 42 |
} |
| 43 | 43 |
} |
| 44 | 44 |
|
| ... | ... |
@@ -61,26 +67,33 @@ func (list *sparseChildList) add(child *Trie) childList {
|
| 61 | 61 |
return newDenseChildList(list, child) |
| 62 | 62 |
} |
| 63 | 63 |
|
| 64 |
-func (list *sparseChildList) replace(b byte, child *Trie) {
|
|
| 65 |
- // Seek the child and replace it. |
|
| 64 |
+func (list *sparseChildList) remove(b byte) {
|
|
| 66 | 65 |
for i, node := range list.children {
|
| 67 | 66 |
if node.prefix[0] == b {
|
| 68 |
- list.children[i] = child |
|
| 67 |
+ list.children, list.children[len(list.children)-1] = |
|
| 68 |
+ append(list.children[:i], list.children[i+1:]...), |
|
| 69 |
+ nil |
|
| 69 | 70 |
return |
| 70 | 71 |
} |
| 71 | 72 |
} |
| 73 |
+ |
|
| 74 |
+ // This is not supposed to be reached. |
|
| 75 |
+ panic("removing non-existent child")
|
|
| 72 | 76 |
} |
| 73 | 77 |
|
| 74 |
-func (list *sparseChildList) remove(child *Trie) {
|
|
| 78 |
+func (list *sparseChildList) replace(b byte, child *Trie) {
|
|
| 79 |
+ // Make a consistency check. |
|
| 80 |
+ if p0 := child.prefix[0]; p0 != b {
|
|
| 81 |
+ panic(fmt.Errorf("child prefix mismatch: %v != %v", p0, b))
|
|
| 82 |
+ } |
|
| 83 |
+ |
|
| 84 |
+ // Seek the child and replace it. |
|
| 75 | 85 |
for i, node := range list.children {
|
| 76 |
- if node.prefix[0] == child.prefix[0] {
|
|
| 77 |
- list.children = append(list.children[:i], list.children[i+1:]...) |
|
| 86 |
+ if node.prefix[0] == b {
|
|
| 87 |
+ list.children[i] = child |
|
| 78 | 88 |
return |
| 79 | 89 |
} |
| 80 | 90 |
} |
| 81 |
- |
|
| 82 |
- // This is not supposed to be reached. |
|
| 83 |
- panic("removing non-existent child")
|
|
| 84 | 91 |
} |
| 85 | 92 |
|
| 86 | 93 |
func (list *sparseChildList) next(b byte) *Trie {
|
| ... | ... |
@@ -120,10 +133,30 @@ func (list *sparseChildList) walk(prefix *Prefix, visitor VisitorFunc) error {
|
| 120 | 120 |
return nil |
| 121 | 121 |
} |
| 122 | 122 |
|
| 123 |
+func (list *sparseChildList) total() int {
|
|
| 124 |
+ tot := 0 |
|
| 125 |
+ for _, child := range list.children {
|
|
| 126 |
+ if child != nil {
|
|
| 127 |
+ tot = tot + child.total() |
|
| 128 |
+ } |
|
| 129 |
+ } |
|
| 130 |
+ return tot |
|
| 131 |
+} |
|
| 132 |
+ |
|
| 133 |
+func (list *sparseChildList) print(w io.Writer, indent int) {
|
|
| 134 |
+ for _, child := range list.children {
|
|
| 135 |
+ if child != nil {
|
|
| 136 |
+ child.print(w, indent) |
|
| 137 |
+ } |
|
| 138 |
+ } |
|
| 139 |
+} |
|
| 140 |
+ |
|
| 123 | 141 |
type denseChildList struct {
|
| 124 |
- min int |
|
| 125 |
- max int |
|
| 126 |
- children []*Trie |
|
| 142 |
+ min int |
|
| 143 |
+ max int |
|
| 144 |
+ numChildren int |
|
| 145 |
+ headIndex int |
|
| 146 |
+ children []*Trie |
|
| 127 | 147 |
} |
| 128 | 148 |
|
| 129 | 149 |
func newDenseChildList(list *sparseChildList, child *Trie) childList {
|
| ... | ... |
@@ -155,57 +188,87 @@ func newDenseChildList(list *sparseChildList, child *Trie) childList {
|
| 155 | 155 |
} |
| 156 | 156 |
children[int(child.prefix[0])-min] = child |
| 157 | 157 |
|
| 158 |
- return &denseChildList{min, max, children}
|
|
| 158 |
+ return &denseChildList{
|
|
| 159 |
+ min: min, |
|
| 160 |
+ max: max, |
|
| 161 |
+ numChildren: list.length() + 1, |
|
| 162 |
+ headIndex: 0, |
|
| 163 |
+ children: children, |
|
| 164 |
+ } |
|
| 159 | 165 |
} |
| 160 | 166 |
|
| 161 | 167 |
func (list *denseChildList) length() int {
|
| 162 |
- return list.max - list.min + 1 |
|
| 168 |
+ return list.numChildren |
|
| 163 | 169 |
} |
| 164 | 170 |
|
| 165 | 171 |
func (list *denseChildList) head() *Trie {
|
| 166 |
- return list.children[0] |
|
| 172 |
+ return list.children[list.headIndex] |
|
| 167 | 173 |
} |
| 168 | 174 |
|
| 169 | 175 |
func (list *denseChildList) add(child *Trie) childList {
|
| 170 | 176 |
b := int(child.prefix[0]) |
| 177 |
+ var i int |
|
| 171 | 178 |
|
| 172 | 179 |
switch {
|
| 173 | 180 |
case list.min <= b && b <= list.max: |
| 174 | 181 |
if list.children[b-list.min] != nil {
|
| 175 | 182 |
panic("dense child list collision detected")
|
| 176 | 183 |
} |
| 177 |
- list.children[b-list.min] = child |
|
| 184 |
+ i = b - list.min |
|
| 185 |
+ list.children[i] = child |
|
| 178 | 186 |
|
| 179 | 187 |
case b < list.min: |
| 180 | 188 |
children := make([]*Trie, list.max-b+1) |
| 181 |
- children[0] = child |
|
| 189 |
+ i = 0 |
|
| 190 |
+ children[i] = child |
|
| 182 | 191 |
copy(children[list.min-b:], list.children) |
| 183 | 192 |
list.children = children |
| 184 | 193 |
list.min = b |
| 185 | 194 |
|
| 186 | 195 |
default: // b > list.max |
| 187 | 196 |
children := make([]*Trie, b-list.min+1) |
| 188 |
- children[b-list.min] = child |
|
| 197 |
+ i = b - list.min |
|
| 198 |
+ children[i] = child |
|
| 189 | 199 |
copy(children, list.children) |
| 190 | 200 |
list.children = children |
| 191 | 201 |
list.max = b |
| 192 | 202 |
} |
| 193 | 203 |
|
| 204 |
+ list.numChildren++ |
|
| 205 |
+ if i < list.headIndex {
|
|
| 206 |
+ list.headIndex = i |
|
| 207 |
+ } |
|
| 194 | 208 |
return list |
| 195 | 209 |
} |
| 196 | 210 |
|
| 197 |
-func (list *denseChildList) replace(b byte, child *Trie) {
|
|
| 198 |
- list.children[int(b)-list.min] = nil |
|
| 199 |
- list.children[int(child.prefix[0])-list.min] = child |
|
| 200 |
-} |
|
| 201 |
- |
|
| 202 |
-func (list *denseChildList) remove(child *Trie) {
|
|
| 203 |
- i := int(child.prefix[0]) - list.min |
|
| 211 |
+func (list *denseChildList) remove(b byte) {
|
|
| 212 |
+ i := int(b) - list.min |
|
| 204 | 213 |
if list.children[i] == nil {
|
| 205 | 214 |
// This is not supposed to be reached. |
| 206 | 215 |
panic("removing non-existent child")
|
| 207 | 216 |
} |
| 217 |
+ list.numChildren-- |
|
| 208 | 218 |
list.children[i] = nil |
| 219 |
+ |
|
| 220 |
+ // Update head index. |
|
| 221 |
+ if i == list.headIndex {
|
|
| 222 |
+ for ; i < len(list.children); i++ {
|
|
| 223 |
+ if list.children[i] != nil {
|
|
| 224 |
+ list.headIndex = i |
|
| 225 |
+ return |
|
| 226 |
+ } |
|
| 227 |
+ } |
|
| 228 |
+ } |
|
| 229 |
+} |
|
| 230 |
+ |
|
| 231 |
+func (list *denseChildList) replace(b byte, child *Trie) {
|
|
| 232 |
+ // Make a consistency check. |
|
| 233 |
+ if p0 := child.prefix[0]; p0 != b {
|
|
| 234 |
+ panic(fmt.Errorf("child prefix mismatch: %v != %v", p0, b))
|
|
| 235 |
+ } |
|
| 236 |
+ |
|
| 237 |
+ // Replace the child. |
|
| 238 |
+ list.children[int(b)-list.min] = child |
|
| 209 | 239 |
} |
| 210 | 240 |
|
| 211 | 241 |
func (list *denseChildList) next(b byte) *Trie {
|
| ... | ... |
@@ -242,3 +305,21 @@ func (list *denseChildList) walk(prefix *Prefix, visitor VisitorFunc) error {
|
| 242 | 242 |
|
| 243 | 243 |
return nil |
| 244 | 244 |
} |
| 245 |
+ |
|
| 246 |
+func (list *denseChildList) print(w io.Writer, indent int) {
|
|
| 247 |
+ for _, child := range list.children {
|
|
| 248 |
+ if child != nil {
|
|
| 249 |
+ child.print(w, indent) |
|
| 250 |
+ } |
|
| 251 |
+ } |
|
| 252 |
+} |
|
| 253 |
+ |
|
| 254 |
+func (list *denseChildList) total() int {
|
|
| 255 |
+ tot := 0 |
|
| 256 |
+ for _, child := range list.children {
|
|
| 257 |
+ if child != nil {
|
|
| 258 |
+ tot = tot + child.total() |
|
| 259 |
+ } |
|
| 260 |
+ } |
|
| 261 |
+ return tot |
|
| 262 |
+} |
| ... | ... |
@@ -6,7 +6,11 @@ |
| 6 | 6 |
package patricia |
| 7 | 7 |
|
| 8 | 8 |
import ( |
| 9 |
+ "bytes" |
|
| 9 | 10 |
"errors" |
| 11 |
+ "fmt" |
|
| 12 |
+ "io" |
|
| 13 |
+ "strings" |
|
| 10 | 14 |
) |
| 11 | 15 |
|
| 12 | 16 |
//------------------------------------------------------------------------------ |
| ... | ... |
@@ -130,6 +134,21 @@ func (trie *Trie) Visit(visitor VisitorFunc) error {
|
| 130 | 130 |
return trie.walk(nil, visitor) |
| 131 | 131 |
} |
| 132 | 132 |
|
| 133 |
+func (trie *Trie) size() int {
|
|
| 134 |
+ n := 0 |
|
| 135 |
+ |
|
| 136 |
+ trie.walk(nil, func(prefix Prefix, item Item) error {
|
|
| 137 |
+ n++ |
|
| 138 |
+ return nil |
|
| 139 |
+ }) |
|
| 140 |
+ |
|
| 141 |
+ return n |
|
| 142 |
+} |
|
| 143 |
+ |
|
| 144 |
+func (trie *Trie) total() int {
|
|
| 145 |
+ return 1 + trie.children.total() |
|
| 146 |
+} |
|
| 147 |
+ |
|
| 133 | 148 |
// VisitSubtree works much like Visit, but it only visits nodes matching prefix. |
| 134 | 149 |
func (trie *Trie) VisitSubtree(prefix Prefix, visitor VisitorFunc) error {
|
| 135 | 150 |
// Nil prefix not allowed. |
| ... | ... |
@@ -219,11 +238,17 @@ func (trie *Trie) Delete(key Prefix) (deleted bool) {
|
| 219 | 219 |
} |
| 220 | 220 |
|
| 221 | 221 |
// Find the relevant node. |
| 222 |
- parent, node, _, leftover := trie.findSubtree(key) |
|
| 223 |
- if len(leftover) != 0 {
|
|
| 222 |
+ path, found, _ := trie.findSubtreePath(key) |
|
| 223 |
+ if !found {
|
|
| 224 | 224 |
return false |
| 225 | 225 |
} |
| 226 | 226 |
|
| 227 |
+ node := path[len(path)-1] |
|
| 228 |
+ var parent *Trie |
|
| 229 |
+ if len(path) != 1 {
|
|
| 230 |
+ parent = path[len(path)-2] |
|
| 231 |
+ } |
|
| 232 |
+ |
|
| 227 | 233 |
// If the item is already set to nil, there is nothing to do. |
| 228 | 234 |
if node.item == nil {
|
| 229 | 235 |
return false |
| ... | ... |
@@ -232,7 +257,53 @@ func (trie *Trie) Delete(key Prefix) (deleted bool) {
|
| 232 | 232 |
// Delete the item. |
| 233 | 233 |
node.item = nil |
| 234 | 234 |
|
| 235 |
- // Compact since that might be possible now. |
|
| 235 |
+ // Initialise i before goto. |
|
| 236 |
+ // Will be used later in a loop. |
|
| 237 |
+ i := len(path) - 1 |
|
| 238 |
+ |
|
| 239 |
+ // In case there are some child nodes, we cannot drop the whole subtree. |
|
| 240 |
+ // We can try to compact nodes, though. |
|
| 241 |
+ if node.children.length() != 0 {
|
|
| 242 |
+ goto Compact |
|
| 243 |
+ } |
|
| 244 |
+ |
|
| 245 |
+ // In case we are at the root, just reset it and we are done. |
|
| 246 |
+ if parent == nil {
|
|
| 247 |
+ node.reset() |
|
| 248 |
+ return true |
|
| 249 |
+ } |
|
| 250 |
+ |
|
| 251 |
+ // We can drop a subtree. |
|
| 252 |
+ // Find the first ancestor that has its value set or it has 2 or more child nodes. |
|
| 253 |
+ // That will be the node where to drop the subtree at. |
|
| 254 |
+ for ; i >= 0; i-- {
|
|
| 255 |
+ if current := path[i]; current.item != nil || current.children.length() >= 2 {
|
|
| 256 |
+ break |
|
| 257 |
+ } |
|
| 258 |
+ } |
|
| 259 |
+ |
|
| 260 |
+ // Handle the case when there is no such node. |
|
| 261 |
+ // In other words, we can reset the whole tree. |
|
| 262 |
+ if i == -1 {
|
|
| 263 |
+ path[0].reset() |
|
| 264 |
+ return true |
|
| 265 |
+ } |
|
| 266 |
+ |
|
| 267 |
+ // We can just remove the subtree here. |
|
| 268 |
+ node = path[i] |
|
| 269 |
+ if i == 0 {
|
|
| 270 |
+ parent = nil |
|
| 271 |
+ } else {
|
|
| 272 |
+ parent = path[i-1] |
|
| 273 |
+ } |
|
| 274 |
+ // i+1 is always a valid index since i is never pointing to the last node. |
|
| 275 |
+ // The loop above skips at least the last node since we are sure that the item |
|
| 276 |
+ // is set to nil and it has no children, othewise we would be compacting instead. |
|
| 277 |
+ node.children.remove(path[i+1].prefix[0]) |
|
| 278 |
+ |
|
| 279 |
+Compact: |
|
| 280 |
+ // The node is set to the first non-empty ancestor, |
|
| 281 |
+ // so try to compact since that might be possible now. |
|
| 236 | 282 |
if compacted := node.compact(); compacted != node {
|
| 237 | 283 |
if parent == nil {
|
| 238 | 284 |
*node = *compacted |
| ... | ... |
@@ -267,18 +338,26 @@ func (trie *Trie) DeleteSubtree(prefix Prefix) (deleted bool) {
|
| 267 | 267 |
|
| 268 | 268 |
// If we are in the root of the trie, reset the trie. |
| 269 | 269 |
if parent == nil {
|
| 270 |
- root.prefix = nil |
|
| 271 |
- root.children = newSparseChildList(trie.maxPrefixPerNode) |
|
| 270 |
+ root.reset() |
|
| 272 | 271 |
return true |
| 273 | 272 |
} |
| 274 | 273 |
|
| 275 | 274 |
// Otherwise remove the root node from its parent. |
| 276 |
- parent.children.remove(root) |
|
| 275 |
+ parent.children.remove(root.prefix[0]) |
|
| 277 | 276 |
return true |
| 278 | 277 |
} |
| 279 | 278 |
|
| 280 | 279 |
// Internal helper methods ----------------------------------------------------- |
| 281 | 280 |
|
| 281 |
+func (trie *Trie) empty() bool {
|
|
| 282 |
+ return trie.item == nil && trie.children.length() == 0 |
|
| 283 |
+} |
|
| 284 |
+ |
|
| 285 |
+func (trie *Trie) reset() {
|
|
| 286 |
+ trie.prefix = nil |
|
| 287 |
+ trie.children = newSparseChildList(trie.maxPrefixPerNode) |
|
| 288 |
+} |
|
| 289 |
+ |
|
| 282 | 290 |
func (trie *Trie) put(key Prefix, item Item, replace bool) (inserted bool) {
|
| 283 | 291 |
// Nil prefix not allowed. |
| 284 | 292 |
if key == nil {
|
| ... | ... |
@@ -425,6 +504,43 @@ func (trie *Trie) findSubtree(prefix Prefix) (parent *Trie, root *Trie, found bo |
| 425 | 425 |
} |
| 426 | 426 |
} |
| 427 | 427 |
|
| 428 |
+func (trie *Trie) findSubtreePath(prefix Prefix) (path []*Trie, found bool, leftover Prefix) {
|
|
| 429 |
+ // Find the subtree matching prefix. |
|
| 430 |
+ root := trie |
|
| 431 |
+ var subtreePath []*Trie |
|
| 432 |
+ for {
|
|
| 433 |
+ // Append the current root to the path. |
|
| 434 |
+ subtreePath = append(subtreePath, root) |
|
| 435 |
+ |
|
| 436 |
+ // Compute what part of prefix matches. |
|
| 437 |
+ common := root.longestCommonPrefixLength(prefix) |
|
| 438 |
+ prefix = prefix[common:] |
|
| 439 |
+ |
|
| 440 |
+ // We used up the whole prefix, subtree found. |
|
| 441 |
+ if len(prefix) == 0 {
|
|
| 442 |
+ path = subtreePath |
|
| 443 |
+ found = true |
|
| 444 |
+ leftover = root.prefix[common:] |
|
| 445 |
+ return |
|
| 446 |
+ } |
|
| 447 |
+ |
|
| 448 |
+ // Partial match means that there is no subtree matching prefix. |
|
| 449 |
+ if common < len(root.prefix) {
|
|
| 450 |
+ leftover = root.prefix[common:] |
|
| 451 |
+ return |
|
| 452 |
+ } |
|
| 453 |
+ |
|
| 454 |
+ // There is some prefix left, move to the children. |
|
| 455 |
+ child := root.children.next(prefix[0]) |
|
| 456 |
+ if child == nil {
|
|
| 457 |
+ // There is nowhere to continue, there is no subtree matching prefix. |
|
| 458 |
+ return |
|
| 459 |
+ } |
|
| 460 |
+ |
|
| 461 |
+ root = child |
|
| 462 |
+ } |
|
| 463 |
+} |
|
| 464 |
+ |
|
| 428 | 465 |
func (trie *Trie) walk(actualRootPrefix Prefix, visitor VisitorFunc) error {
|
| 429 | 466 |
var prefix Prefix |
| 430 | 467 |
// Allocate a bit more space for prefix at the beginning. |
| ... | ... |
@@ -459,6 +575,17 @@ func (trie *Trie) longestCommonPrefixLength(prefix Prefix) (i int) {
|
| 459 | 459 |
return |
| 460 | 460 |
} |
| 461 | 461 |
|
| 462 |
+func (trie *Trie) dump() string {
|
|
| 463 |
+ writer := &bytes.Buffer{}
|
|
| 464 |
+ trie.print(writer, 0) |
|
| 465 |
+ return writer.String() |
|
| 466 |
+} |
|
| 467 |
+ |
|
| 468 |
+func (trie *Trie) print(writer io.Writer, indent int) {
|
|
| 469 |
+ fmt.Fprintf(writer, "%s%s %v\n", strings.Repeat(" ", indent), string(trie.prefix), trie.item)
|
|
| 470 |
+ trie.children.print(writer, indent+2) |
|
| 471 |
+} |
|
| 472 |
+ |
|
| 462 | 473 |
// Errors ---------------------------------------------------------------------- |
| 463 | 474 |
|
| 464 | 475 |
var ( |