mirror of https://github.com/docker/docs.git
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
|
@ -45,7 +45,7 @@ clone git github.com/gorilla/context 14f550f51a
|
||||||
|
|
||||||
clone git github.com/gorilla/mux e444e69cbd
|
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
|
clone hg code.google.com/p/go.net 84a4013f96e0
|
||||||
|
|
||||||
|
|
|
@ -14,12 +14,6 @@ var (
|
||||||
ErrAmbiguousPrefix = errors.New("Multiple IDs found with provided prefix")
|
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.
|
// 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.
|
// This is used to retrieve image and container IDs by more convenient shorthand prefixes.
|
||||||
type TruncIndex struct {
|
type TruncIndex struct {
|
||||||
|
@ -31,8 +25,11 @@ type TruncIndex struct {
|
||||||
// NewTruncIndex creates a new TruncIndex and initializes with a list of IDs
|
// NewTruncIndex creates a new TruncIndex and initializes with a list of IDs
|
||||||
func NewTruncIndex(ids []string) (idx *TruncIndex) {
|
func NewTruncIndex(ids []string) (idx *TruncIndex) {
|
||||||
idx = &TruncIndex{
|
idx = &TruncIndex{
|
||||||
ids: make(map[string]struct{}),
|
ids: make(map[string]struct{}),
|
||||||
trie: patricia.NewTrie(),
|
|
||||||
|
// Change patricia max prefix per node length,
|
||||||
|
// because our len(ID) always 64
|
||||||
|
trie: patricia.NewTrie(patricia.MaxPrefixPerNode(64)),
|
||||||
}
|
}
|
||||||
for _, id := range ids {
|
for _, id := range ids {
|
||||||
idx.addID(id)
|
idx.addID(id)
|
||||||
|
|
|
@ -50,9 +50,12 @@ printItem := func(prefix patricia.Prefix, item patricia.Item) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new tree.
|
// Create a new default trie (using the default parameter values).
|
||||||
trie := NewTrie()
|
trie := NewTrie()
|
||||||
|
|
||||||
|
// Create a new custom trie.
|
||||||
|
trie := NewTrie(MaxPrefixPerNode(16), MaxChildrenPerSparseNode(10))
|
||||||
|
|
||||||
// Insert some items.
|
// Insert some items.
|
||||||
trie.Insert(Prefix("Pepa Novak"), 1)
|
trie.Insert(Prefix("Pepa Novak"), 1)
|
||||||
trie.Insert(Prefix("Pepa Sindelar"), 2)
|
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))
|
fmt.Printf("Anybody called %q here? %v\n", key, trie.MatchSubtree(key))
|
||||||
// Anybody called "Karel" here? true
|
// Anybody called "Karel" here? true
|
||||||
|
|
||||||
// Walk the tree.
|
// Walk the tree in alphabetical order.
|
||||||
trie.Visit(printItem)
|
trie.Visit(printItem)
|
||||||
|
// "Karel Hynek Macha": 4
|
||||||
|
// "Karel Macha": 3
|
||||||
// "Pepa Novak": 1
|
// "Pepa Novak": 1
|
||||||
// "Pepa Sindelar": 2
|
// "Pepa Sindelar": 2
|
||||||
// "Karel Macha": 3
|
|
||||||
// "Karel Hynek Macha": 4
|
|
||||||
|
|
||||||
// Walk a subtree.
|
// Walk a subtree.
|
||||||
trie.VisitSubtree(Prefix("Pepa"), printItem)
|
trie.VisitSubtree(Prefix("Pepa"), printItem)
|
||||||
|
@ -96,8 +99,8 @@ trie.Delete(Prefix("Karel Macha"))
|
||||||
|
|
||||||
// Walk again.
|
// Walk again.
|
||||||
trie.Visit(printItem)
|
trie.Visit(printItem)
|
||||||
// "Pepa Sindelar": 2
|
|
||||||
// "Karel Hynek Macha": 10
|
// "Karel Hynek Macha": 10
|
||||||
|
// "Pepa Sindelar": 2
|
||||||
|
|
||||||
// Delete a subtree.
|
// Delete a subtree.
|
||||||
trie.DeleteSubtree(Prefix("Pepa"))
|
trie.DeleteSubtree(Prefix("Pepa"))
|
||||||
|
|
|
@ -5,11 +5,7 @@
|
||||||
|
|
||||||
package patricia
|
package patricia
|
||||||
|
|
||||||
// Max prefix length that is kept in a single trie node.
|
import "sort"
|
||||||
var MaxPrefixPerNode = 10
|
|
||||||
|
|
||||||
// Max children to keep in a node in the sparse mode.
|
|
||||||
const MaxChildrenPerSparseNode = 8
|
|
||||||
|
|
||||||
type childList interface {
|
type childList interface {
|
||||||
length() int
|
length() int
|
||||||
|
@ -21,13 +17,28 @@ type childList interface {
|
||||||
walk(prefix *Prefix, visitor VisitorFunc) error
|
walk(prefix *Prefix, visitor VisitorFunc) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type sparseChildList struct {
|
type tries []*Trie
|
||||||
children []*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{
|
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 {
|
func (list *sparseChildList) walk(prefix *Prefix, visitor VisitorFunc) error {
|
||||||
|
|
||||||
|
sort.Sort(list.children)
|
||||||
|
|
||||||
for _, child := range list.children {
|
for _, child := range list.children {
|
||||||
*prefix = append(*prefix, child.prefix...)
|
*prefix = append(*prefix, child.prefix...)
|
||||||
if child.item != nil {
|
if child.item != nil {
|
||||||
|
|
|
@ -13,6 +13,11 @@ import (
|
||||||
// Trie
|
// Trie
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultMaxPrefixPerNode = 10
|
||||||
|
DefaultMaxChildrenPerSparseNode = 8
|
||||||
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
Prefix []byte
|
Prefix []byte
|
||||||
Item interface{}
|
Item interface{}
|
||||||
|
@ -27,15 +32,44 @@ type Trie struct {
|
||||||
prefix Prefix
|
prefix Prefix
|
||||||
item Item
|
item Item
|
||||||
|
|
||||||
|
maxPrefixPerNode int
|
||||||
|
maxChildrenPerSparseNode int
|
||||||
|
|
||||||
children childList
|
children childList
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public API ------------------------------------------------------------------
|
// Public API ------------------------------------------------------------------
|
||||||
|
|
||||||
|
type Option func(*Trie)
|
||||||
|
|
||||||
// Trie constructor.
|
// Trie constructor.
|
||||||
func NewTrie() *Trie {
|
func NewTrie(options ...Option) *Trie {
|
||||||
return &Trie{
|
trie := &Trie{}
|
||||||
children: newSparseChildList(),
|
|
||||||
|
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
|
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
|
// 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
|
// 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 we are in the root of the trie, reset the trie.
|
||||||
if parent == nil {
|
if parent == nil {
|
||||||
root.prefix = nil
|
root.prefix = nil
|
||||||
root.children = newSparseChildList()
|
root.children = newSparseChildList(trie.maxPrefixPerNode)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,12 +292,12 @@ func (trie *Trie) put(key Prefix, item Item, replace bool) (inserted bool) {
|
||||||
)
|
)
|
||||||
|
|
||||||
if node.prefix == nil {
|
if node.prefix == nil {
|
||||||
if len(key) <= MaxPrefixPerNode {
|
if len(key) <= trie.maxPrefixPerNode {
|
||||||
node.prefix = key
|
node.prefix = key
|
||||||
goto InsertItem
|
goto InsertItem
|
||||||
}
|
}
|
||||||
node.prefix = key[:MaxPrefixPerNode]
|
node.prefix = key[:trie.maxPrefixPerNode]
|
||||||
key = key[MaxPrefixPerNode:]
|
key = key[trie.maxPrefixPerNode:]
|
||||||
goto AppendChild
|
goto AppendChild
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,14 +341,14 @@ AppendChild:
|
||||||
// This loop starts with empty node.prefix that needs to be filled.
|
// This loop starts with empty node.prefix that needs to be filled.
|
||||||
for len(key) != 0 {
|
for len(key) != 0 {
|
||||||
child := NewTrie()
|
child := NewTrie()
|
||||||
if len(key) <= MaxPrefixPerNode {
|
if len(key) <= trie.maxPrefixPerNode {
|
||||||
child.prefix = key
|
child.prefix = key
|
||||||
node.children = node.children.add(child)
|
node.children = node.children.add(child)
|
||||||
node = child
|
node = child
|
||||||
goto InsertItem
|
goto InsertItem
|
||||||
} else {
|
} else {
|
||||||
child.prefix = key[:MaxPrefixPerNode]
|
child.prefix = key[:trie.maxPrefixPerNode]
|
||||||
key = key[MaxPrefixPerNode:]
|
key = key[trie.maxPrefixPerNode:]
|
||||||
node.children = node.children.add(child)
|
node.children = node.children.add(child)
|
||||||
node = child
|
node = child
|
||||||
}
|
}
|
||||||
|
@ -344,7 +379,7 @@ func (trie *Trie) compact() *Trie {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure the combined prefixes fit into a single node.
|
// 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
|
return trie
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ func TestTrie_InsertDensePreceeding(t *testing.T) {
|
||||||
trie := NewTrie()
|
trie := NewTrie()
|
||||||
start := byte(70)
|
start := byte(70)
|
||||||
// create a dense node
|
// 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) {
|
if !trie.Insert(Prefix([]byte{start + i}), true) {
|
||||||
t.Errorf("insert failed, prefix=%v", start+i)
|
t.Errorf("insert failed, prefix=%v", start+i)
|
||||||
}
|
}
|
||||||
|
|
|
@ -300,10 +300,10 @@ func TestTrie_VisitReturnError(t *testing.T) {
|
||||||
someErr := errors.New("Something exploded")
|
someErr := errors.New("Something exploded")
|
||||||
if err := trie.Visit(func(prefix Prefix, item Item) error {
|
if err := trie.Visit(func(prefix Prefix, item Item) error {
|
||||||
t.Logf("VISITING prefix=%q, item=%v", prefix, item)
|
t.Logf("VISITING prefix=%q, item=%v", prefix, item)
|
||||||
if item.(int) == 0 {
|
if item.(int) == 3 {
|
||||||
return someErr
|
return someErr
|
||||||
}
|
}
|
||||||
if item.(int) != 0 {
|
if item.(int) != 3 {
|
||||||
t.Errorf("Unexpected prefix encountered, %q", prefix)
|
t.Errorf("Unexpected prefix encountered, %q", prefix)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -598,10 +598,10 @@ func ExampleTrie() {
|
||||||
|
|
||||||
// Walk the tree.
|
// Walk the tree.
|
||||||
trie.Visit(printItem)
|
trie.Visit(printItem)
|
||||||
|
// "Karel Hynek Macha": 4
|
||||||
|
// "Karel Macha": 3
|
||||||
// "Pepa Novak": 1
|
// "Pepa Novak": 1
|
||||||
// "Pepa Sindelar": 2
|
// "Pepa Sindelar": 2
|
||||||
// "Karel Macha": 3
|
|
||||||
// "Karel Hynek Macha": 4
|
|
||||||
|
|
||||||
// Walk a subtree.
|
// Walk a subtree.
|
||||||
trie.VisitSubtree(Prefix("Pepa"), printItem)
|
trie.VisitSubtree(Prefix("Pepa"), printItem)
|
||||||
|
@ -625,8 +625,8 @@ func ExampleTrie() {
|
||||||
|
|
||||||
// Walk again.
|
// Walk again.
|
||||||
trie.Visit(printItem)
|
trie.Visit(printItem)
|
||||||
// "Pepa Sindelar": 2
|
|
||||||
// "Karel Hynek Macha": 10
|
// "Karel Hynek Macha": 10
|
||||||
|
// "Pepa Sindelar": 2
|
||||||
|
|
||||||
// Delete a subtree.
|
// Delete a subtree.
|
||||||
trie.DeleteSubtree(Prefix("Pepa"))
|
trie.DeleteSubtree(Prefix("Pepa"))
|
||||||
|
@ -638,16 +638,16 @@ func ExampleTrie() {
|
||||||
// Output:
|
// Output:
|
||||||
// "Pepa Novak" present? true
|
// "Pepa Novak" present? true
|
||||||
// Anybody called "Karel" here? true
|
// Anybody called "Karel" here? true
|
||||||
// "Pepa Novak": 1
|
|
||||||
// "Pepa Sindelar": 2
|
|
||||||
// "Karel Macha": 3
|
|
||||||
// "Karel Hynek Macha": 4
|
// "Karel Hynek Macha": 4
|
||||||
|
// "Karel Macha": 3
|
||||||
|
// "Pepa Novak": 1
|
||||||
|
// "Pepa Sindelar": 2
|
||||||
// "Pepa Novak": 1
|
// "Pepa Novak": 1
|
||||||
// "Pepa Sindelar": 2
|
// "Pepa Sindelar": 2
|
||||||
// "Karel Hynek Macha": 10
|
// "Karel Hynek Macha": 10
|
||||||
// "Karel Hynek Macha": 10
|
// "Karel Hynek Macha": 10
|
||||||
// "Pepa Sindelar": 2
|
|
||||||
// "Karel Hynek Macha": 10
|
// "Karel Hynek Macha": 10
|
||||||
|
// "Pepa Sindelar": 2
|
||||||
// "Karel Hynek Macha": 10
|
// "Karel Hynek Macha": 10
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,20 @@ import (
|
||||||
|
|
||||||
// Tests -----------------------------------------------------------------------
|
// 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) {
|
func TestTrie_GetNonexistentPrefix(t *testing.T) {
|
||||||
trie := NewTrie()
|
trie := NewTrie()
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue