1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Update go-patricia to 2.1.0

This includes a fix for the minor v2 API change introduced by 341a37095f. 👍

Signed-off-by: Andrew "Tianon" Page <admwiggin@gmail.com>
This commit is contained in:
Tianon Gravi 2015-05-02 23:25:57 -06:00
parent 0ad6f90127
commit b447fef7ec
8 changed files with 108 additions and 45 deletions

View file

@ -45,7 +45,7 @@ clone git github.com/gorilla/context 14f550f51a
clone git github.com/gorilla/mux e444e69cbd
clone git github.com/tchap/go-patricia v1.0.1
clone git github.com/tchap/go-patricia v2.1.0
clone hg code.google.com/p/go.net 84a4013f96e0

View file

@ -14,12 +14,6 @@ var (
ErrAmbiguousPrefix = errors.New("Multiple IDs found with provided prefix")
)
func init() {
// Change patricia max prefix per node length,
// because our len(ID) always 64
patricia.MaxPrefixPerNode = 64
}
// TruncIndex allows the retrieval of string identifiers by any of their unique prefixes.
// This is used to retrieve image and container IDs by more convenient shorthand prefixes.
type TruncIndex struct {
@ -31,8 +25,11 @@ type TruncIndex struct {
// NewTruncIndex creates a new TruncIndex and initializes with a list of IDs
func NewTruncIndex(ids []string) (idx *TruncIndex) {
idx = &TruncIndex{
ids: make(map[string]struct{}),
trie: patricia.NewTrie(),
ids: make(map[string]struct{}),
// Change patricia max prefix per node length,
// because our len(ID) always 64
trie: patricia.NewTrie(patricia.MaxPrefixPerNode(64)),
}
for _, id := range ids {
idx.addID(id)

View file

@ -50,9 +50,12 @@ printItem := func(prefix patricia.Prefix, item patricia.Item) error {
return nil
}
// Create a new tree.
// Create a new default trie (using the default parameter values).
trie := NewTrie()
// Create a new custom trie.
trie := NewTrie(MaxPrefixPerNode(16), MaxChildrenPerSparseNode(10))
// Insert some items.
trie.Insert(Prefix("Pepa Novak"), 1)
trie.Insert(Prefix("Pepa Sindelar"), 2)
@ -67,12 +70,12 @@ key = Prefix("Karel")
fmt.Printf("Anybody called %q here? %v\n", key, trie.MatchSubtree(key))
// Anybody called "Karel" here? true
// Walk the tree.
// Walk the tree in alphabetical order.
trie.Visit(printItem)
// "Karel Hynek Macha": 4
// "Karel Macha": 3
// "Pepa Novak": 1
// "Pepa Sindelar": 2
// "Karel Macha": 3
// "Karel Hynek Macha": 4
// Walk a subtree.
trie.VisitSubtree(Prefix("Pepa"), printItem)
@ -96,8 +99,8 @@ trie.Delete(Prefix("Karel Macha"))
// Walk again.
trie.Visit(printItem)
// "Pepa Sindelar": 2
// "Karel Hynek Macha": 10
// "Pepa Sindelar": 2
// Delete a subtree.
trie.DeleteSubtree(Prefix("Pepa"))

View file

@ -5,11 +5,7 @@
package patricia
// Max prefix length that is kept in a single trie node.
var MaxPrefixPerNode = 10
// Max children to keep in a node in the sparse mode.
const MaxChildrenPerSparseNode = 8
import "sort"
type childList interface {
length() int
@ -21,13 +17,28 @@ type childList interface {
walk(prefix *Prefix, visitor VisitorFunc) error
}
type sparseChildList struct {
children []*Trie
type tries []*Trie
func (t tries) Len() int {
return len(t)
}
func newSparseChildList() childList {
func (t tries) Less(i, j int) bool {
strings := sort.StringSlice{string(t[i].prefix), string(t[j].prefix)}
return strings.Less(0, 1)
}
func (t tries) Swap(i, j int) {
t[i], t[j] = t[j], t[i]
}
type sparseChildList struct {
children tries
}
func newSparseChildList(maxChildrenPerSparseNode int) childList {
return &sparseChildList{
children: make([]*Trie, 0, MaxChildrenPerSparseNode),
children: make(tries, 0, DefaultMaxChildrenPerSparseNode),
}
}
@ -82,6 +93,9 @@ func (list *sparseChildList) next(b byte) *Trie {
}
func (list *sparseChildList) walk(prefix *Prefix, visitor VisitorFunc) error {
sort.Sort(list.children)
for _, child := range list.children {
*prefix = append(*prefix, child.prefix...)
if child.item != nil {

View file

@ -13,6 +13,11 @@ import (
// Trie
//------------------------------------------------------------------------------
const (
DefaultMaxPrefixPerNode = 10
DefaultMaxChildrenPerSparseNode = 8
)
type (
Prefix []byte
Item interface{}
@ -27,15 +32,44 @@ type Trie struct {
prefix Prefix
item Item
maxPrefixPerNode int
maxChildrenPerSparseNode int
children childList
}
// Public API ------------------------------------------------------------------
type Option func(*Trie)
// Trie constructor.
func NewTrie() *Trie {
return &Trie{
children: newSparseChildList(),
func NewTrie(options ...Option) *Trie {
trie := &Trie{}
for _, opt := range options {
opt(trie)
}
if trie.maxPrefixPerNode <= 0 {
trie.maxPrefixPerNode = DefaultMaxPrefixPerNode
}
if trie.maxChildrenPerSparseNode <= 0 {
trie.maxChildrenPerSparseNode = DefaultMaxChildrenPerSparseNode
}
trie.children = newSparseChildList(trie.maxChildrenPerSparseNode)
return trie
}
func MaxPrefixPerNode(value int) Option {
return func(trie *Trie) {
trie.maxPrefixPerNode = value
}
}
func MaxChildrenPerSparseNode(value int) Option {
return func(trie *Trie) {
trie.maxChildrenPerSparseNode = value
}
}
@ -85,7 +119,8 @@ func (trie *Trie) MatchSubtree(key Prefix) (matched bool) {
return
}
// Visit calls visitor on every node containing a non-nil item.
// Visit calls visitor on every node containing a non-nil item
// in alphabetical order.
//
// If an error is returned from visitor, the function stops visiting the tree
// and returns that error, unless it is a special error - SkipSubtree. In that
@ -233,7 +268,7 @@ func (trie *Trie) DeleteSubtree(prefix Prefix) (deleted bool) {
// If we are in the root of the trie, reset the trie.
if parent == nil {
root.prefix = nil
root.children = newSparseChildList()
root.children = newSparseChildList(trie.maxPrefixPerNode)
return true
}
@ -257,12 +292,12 @@ func (trie *Trie) put(key Prefix, item Item, replace bool) (inserted bool) {
)
if node.prefix == nil {
if len(key) <= MaxPrefixPerNode {
if len(key) <= trie.maxPrefixPerNode {
node.prefix = key
goto InsertItem
}
node.prefix = key[:MaxPrefixPerNode]
key = key[MaxPrefixPerNode:]
node.prefix = key[:trie.maxPrefixPerNode]
key = key[trie.maxPrefixPerNode:]
goto AppendChild
}
@ -306,14 +341,14 @@ AppendChild:
// This loop starts with empty node.prefix that needs to be filled.
for len(key) != 0 {
child := NewTrie()
if len(key) <= MaxPrefixPerNode {
if len(key) <= trie.maxPrefixPerNode {
child.prefix = key
node.children = node.children.add(child)
node = child
goto InsertItem
} else {
child.prefix = key[:MaxPrefixPerNode]
key = key[MaxPrefixPerNode:]
child.prefix = key[:trie.maxPrefixPerNode]
key = key[trie.maxPrefixPerNode:]
node.children = node.children.add(child)
node = child
}
@ -344,7 +379,7 @@ func (trie *Trie) compact() *Trie {
}
// Make sure the combined prefixes fit into a single node.
if len(trie.prefix)+len(child.prefix) > MaxPrefixPerNode {
if len(trie.prefix)+len(child.prefix) > trie.maxPrefixPerNode {
return trie
}

View file

@ -55,7 +55,7 @@ func TestTrie_InsertDensePreceeding(t *testing.T) {
trie := NewTrie()
start := byte(70)
// create a dense node
for i := byte(0); i <= MaxChildrenPerSparseNode; i++ {
for i := byte(0); i <= DefaultMaxChildrenPerSparseNode; i++ {
if !trie.Insert(Prefix([]byte{start + i}), true) {
t.Errorf("insert failed, prefix=%v", start+i)
}

View file

@ -300,10 +300,10 @@ func TestTrie_VisitReturnError(t *testing.T) {
someErr := errors.New("Something exploded")
if err := trie.Visit(func(prefix Prefix, item Item) error {
t.Logf("VISITING prefix=%q, item=%v", prefix, item)
if item.(int) == 0 {
if item.(int) == 3 {
return someErr
}
if item.(int) != 0 {
if item.(int) != 3 {
t.Errorf("Unexpected prefix encountered, %q", prefix)
}
return nil
@ -598,10 +598,10 @@ func ExampleTrie() {
// Walk the tree.
trie.Visit(printItem)
// "Karel Hynek Macha": 4
// "Karel Macha": 3
// "Pepa Novak": 1
// "Pepa Sindelar": 2
// "Karel Macha": 3
// "Karel Hynek Macha": 4
// Walk a subtree.
trie.VisitSubtree(Prefix("Pepa"), printItem)
@ -625,8 +625,8 @@ func ExampleTrie() {
// Walk again.
trie.Visit(printItem)
// "Pepa Sindelar": 2
// "Karel Hynek Macha": 10
// "Pepa Sindelar": 2
// Delete a subtree.
trie.DeleteSubtree(Prefix("Pepa"))
@ -638,16 +638,16 @@ func ExampleTrie() {
// Output:
// "Pepa Novak" present? true
// Anybody called "Karel" here? true
// "Pepa Novak": 1
// "Pepa Sindelar": 2
// "Karel Macha": 3
// "Karel Hynek Macha": 4
// "Karel Macha": 3
// "Pepa Novak": 1
// "Pepa Sindelar": 2
// "Pepa Novak": 1
// "Pepa Sindelar": 2
// "Karel Hynek Macha": 10
// "Karel Hynek Macha": 10
// "Pepa Sindelar": 2
// "Karel Hynek Macha": 10
// "Pepa Sindelar": 2
// "Karel Hynek Macha": 10
}

View file

@ -13,6 +13,20 @@ import (
// Tests -----------------------------------------------------------------------
func TestTrie_ConstructorOptions(t *testing.T) {
trie := NewTrie(MaxPrefixPerNode(16), MaxChildrenPerSparseNode(10))
if trie.maxPrefixPerNode != 16 {
t.Errorf("Unexpected trie.maxPrefixPerNode value, expected=%v, got=%v",
16, trie.maxPrefixPerNode)
}
if trie.maxChildrenPerSparseNode != 10 {
t.Errorf("Unexpected trie.maxChildrenPerSparseNode value, expected=%v, got=%v",
10, trie.maxChildrenPerSparseNode)
}
}
func TestTrie_GetNonexistentPrefix(t *testing.T) {
trie := NewTrie()