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:
parent
0ad6f90127
commit
b447fef7ec
8 changed files with 108 additions and 45 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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"))
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue