Documentation
¶
Overview ¶
Package bst provides a sorted string-keyed collection and cursor helpers.
Index ¶
- type BST
- type Cursor
- type Entry
- type SyncBST
- func (b *SyncBST[T]) Cursor(fn func(*Cursor[T]) error) (err error)
- func (b *SyncBST[T]) ForEach(fn func(T) error) (err error)
- func (b *SyncBST[T]) Get(key string) (out T, ok bool)
- func (b *SyncBST[T]) Insert(val T)
- func (b *SyncBST[T]) Length() (n int)
- func (b *SyncBST[T]) MarshalJSON() (bs []byte, err error)
- func (b *SyncBST[T]) Remove(key string)
- func (b *SyncBST[T]) UnmarshalJSON(bs []byte) (err error)
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type BST ¶
type BST[T Entry] []T
BST is a sorted collection of entries keyed by string.
It stores entries in key order and uses binary search for lookups.
Example ¶
tree := make(BST[testEntry], 0, 1024) _ = tree
func (BST[T]) Cursor ¶
Cursor returns a cursor positioned over b.
Example ¶
tree := make(BST[testEntry], 0, 4)
tree.Insert(testEntry{K: "a", V: "alpha"})
tree.Insert(testEntry{K: "b", V: "bravo"})
tree.Insert(testEntry{K: "c", V: "charlie"})
tree.Insert(testEntry{K: "d", V: "delta"})
_ = tree.Cursor()
func (BST[T]) ForEach ¶
ForEach calls fn for each entry in key order until fn returns an error.
Example ¶
tree := make(BST[testEntry], 0, 4)
tree.Insert(testEntry{K: "a", V: "alpha"})
tree.Insert(testEntry{K: "b", V: "bravo"})
tree.Insert(testEntry{K: "c", V: "charlie"})
tree.Insert(testEntry{K: "d", V: "delta"})
if err := tree.ForEach(func(te testEntry) error {
fmt.Printf("exampleBST.ForEach(): %v\n", te)
return nil
}); err != nil {
log.Fatal(err)
}
Output: exampleBST.ForEach(): {a alpha} exampleBST.ForEach(): {b bravo} exampleBST.ForEach(): {c charlie} exampleBST.ForEach(): {d delta}
func (BST[T]) Get ¶
Get returns the entry with the given key.
Example ¶
tree := make(BST[testEntry], 0, 4)
tree.Insert(testEntry{K: "a", V: "alpha"})
tree.Insert(testEntry{K: "b", V: "bravo"})
tree.Insert(testEntry{K: "c", V: "charlie"})
tree.Insert(testEntry{K: "d", V: "delta"})
val, ok := tree.Get("a")
fmt.Printf("exampleBST.Get(%q): %v / %v\n", "a", val, ok)
Output: exampleBST.Get("a"): {a alpha} / true
func (*BST[T]) Insert ¶
func (b *BST[T]) Insert(val T)
Insert adds val to b or replaces the existing entry with the same key.
Example ¶
tree := make(BST[testEntry], 0, 4)
tree.Insert(testEntry{K: "a", V: "alpha"})
tree.Insert(testEntry{K: "b", V: "bravo"})
tree.Insert(testEntry{K: "c", V: "charlie"})
tree.Insert(testEntry{K: "d", V: "delta"})
fmt.Printf("exampleBST: %v\n", tree)
Output: exampleBST: [{a alpha} {b bravo} {c charlie} {d delta}]
func (*BST[T]) Remove ¶
Remove deletes the entry with the given key from b.
Example ¶
tree := make(BST[testEntry], 0, 4)
tree.Insert(testEntry{K: "a", V: "alpha"})
tree.Insert(testEntry{K: "b", V: "bravo"})
tree.Insert(testEntry{K: "c", V: "charlie"})
tree.Insert(testEntry{K: "d", V: "delta"})
tree.Remove("b")
fmt.Printf("exampleBS.Remove(): %v\n", tree)
Output: exampleBS.Remove(): [{a alpha} {c charlie} {d delta}]
func (*BST[T]) UnmarshalJSON ¶ added in v1.1.2
Example ¶
var tree BST[testEntry]
if err := json.Unmarshal([]byte(`[{"key":"c","value":"charlie"},{"key":"a","value":"alpha"},{"key":"b","value":"bravo"}]`), &tree); err != nil {
log.Fatal(err)
}
fmt.Printf("exampleBST.UnmarshalJSON(): %v\n", tree)
Output: exampleBST.UnmarshalJSON(): [{a alpha} {b bravo} {c charlie}]
type Cursor ¶
type Cursor[T Entry] struct { // contains filtered or unexported fields }
Cursor navigates entries in a BST.
Example ¶
tree := make(BST[testEntry], 0, 4)
tree.Insert(testEntry{K: "a", V: "alpha"})
tree.Insert(testEntry{K: "b", V: "bravo"})
tree.Insert(testEntry{K: "c", V: "charlie"})
tree.Insert(testEntry{K: "d", V: "delta"})
_ = tree.Cursor()
func (*Cursor[T]) First ¶ added in v0.10.5
First moves the cursor to the first entry.
Example ¶
tree := make(BST[testEntry], 0, 4)
tree.Insert(testEntry{K: "a", V: "alpha"})
tree.Insert(testEntry{K: "b", V: "bravo"})
tree.Insert(testEntry{K: "c", V: "charlie"})
tree.Insert(testEntry{K: "d", V: "delta"})
cursor := tree.Cursor()
val, ok := cursor.First()
fmt.Printf("cursor.First(): %v / %v\n", val, ok)
Output: cursor.First(): {a alpha} / true
func (*Cursor[T]) Last ¶ added in v0.10.5
Last moves the cursor to the last entry.
Example ¶
tree := make(BST[testEntry], 0, 4)
tree.Insert(testEntry{K: "a", V: "alpha"})
tree.Insert(testEntry{K: "b", V: "bravo"})
tree.Insert(testEntry{K: "c", V: "charlie"})
tree.Insert(testEntry{K: "d", V: "delta"})
cursor := tree.Cursor()
val, ok := cursor.Last()
fmt.Printf("cursor.Last(): %v / %v\n", val, ok)
Output: cursor.Last(): {d delta} / true
func (*Cursor[T]) Next ¶
Next moves the cursor to the next entry relative to the current index.
After Seek miss, Next uses the insertion index semantics from Seek. Examples:
- miss before first: Next() returns the second entry (if present)
- miss between entries: Next() returns (zero, false)
- miss after last: Next() returns (zero, false)
Example ¶
tree := make(BST[testEntry], 0, 4)
tree.Insert(testEntry{K: "a", V: "alpha"})
tree.Insert(testEntry{K: "b", V: "bravo"})
tree.Insert(testEntry{K: "c", V: "charlie"})
tree.Insert(testEntry{K: "d", V: "delta"})
cursor := tree.Cursor()
_, _ = cursor.Seek("c")
val, ok := cursor.Next()
fmt.Printf("cursor.Next(): %v / %v\n", val, ok)
Output: cursor.Next(): {d delta} / true
func (*Cursor[T]) Prev ¶
Prev moves the cursor to the previous entry relative to the current index.
After Seek miss, Prev uses the insertion index semantics from Seek. Examples:
- miss before first: Prev() returns (zero, false)
- miss between entries: Prev() returns the lower neighbor
- miss after last: Prev() returns the last entry
Example ¶
tree := make(BST[testEntry], 0, 4)
tree.Insert(testEntry{K: "a", V: "alpha"})
tree.Insert(testEntry{K: "b", V: "bravo"})
tree.Insert(testEntry{K: "c", V: "charlie"})
tree.Insert(testEntry{K: "d", V: "delta"})
cursor := tree.Cursor()
_, _ = cursor.Seek("d")
val, ok := cursor.Prev()
fmt.Printf("cursor.Prev(): %v / %v\n", val, ok)
Output: cursor.Prev(): {c charlie} / true
func (*Cursor[T]) Seek ¶
Seek positions the cursor using BST search semantics and returns a value at or after key.
If key is present, Seek returns the matching entry and ok=true.
If key is missing but there is a later entry, Seek returns that next larger entry and ok=true.
If key is after the last entry, Seek returns (zero, false).
Note: ok reports whether a value was found at or after key, not whether key matched exactly.
Example ¶
tree := make(BST[testEntry], 0, 4)
tree.Insert(testEntry{K: "a", V: "alpha"})
tree.Insert(testEntry{K: "b", V: "bravo"})
tree.Insert(testEntry{K: "c", V: "charlie"})
tree.Insert(testEntry{K: "d", V: "delta"})
cursor := tree.Cursor()
val, ok := cursor.Seek("d")
fmt.Printf("cursor.Seek(%q): %v / %v\n", "d", val, ok)
Output: cursor.Seek("d"): {d delta} / true
type Entry ¶
type Entry interface {
// Key returns the entry's sort key.
Key() string
}
Entry is a value that can be stored in a BST.
type SyncBST ¶
type SyncBST[T Entry] struct { // contains filtered or unexported fields }
SyncBST wraps a BST with an RWMutex for concurrent access.
The zero value is ready to use:
var s SyncBST[T]
A nil *SyncBST is not valid. Calling methods on a nil pointer panics.
Example ¶
tree := NewSync[testEntry](1024) _ = tree
func NewSync ¶
NewSync creates a SyncBST preallocated with capacity length.
length must be >= 0. A negative length panics (same behavior as make with a negative capacity).
func (*SyncBST[T]) Cursor ¶
Cursor calls fn with a cursor while holding a read lock.
fn executes before the read lock is released. Calling write methods on the same SyncBST instance from fn (for example Insert or Remove) can self-deadlock.
Example ¶
tree := NewSync[testEntry](1024)
tree.Insert(testEntry{K: "a", V: "alpha"})
tree.Insert(testEntry{K: "b", V: "bravo"})
tree.Insert(testEntry{K: "c", V: "charlie"})
tree.Insert(testEntry{K: "d", V: "delta"})
if err := tree.Cursor(func(cursor *Cursor[testEntry]) error {
val, ok := cursor.Seek("b")
fmt.Printf("cursor.Seek(%q): %v / %v\n", "b", val, ok)
return nil
}); err != nil {
log.Fatal(err)
}
Output: cursor.Seek("b"): {b bravo} / true
func (*SyncBST[T]) ForEach ¶
ForEach calls fn for each entry in key order while holding a read lock.
fn executes before the read lock is released. Calling write methods on the same SyncBST instance from fn (for example Insert or Remove) can self-deadlock.
Example ¶
tree := NewSync[testEntry](1024)
tree.Insert(testEntry{K: "a", V: "alpha"})
tree.Insert(testEntry{K: "b", V: "bravo"})
tree.Insert(testEntry{K: "c", V: "charlie"})
tree.Insert(testEntry{K: "d", V: "delta"})
if err := tree.ForEach(func(te testEntry) error {
fmt.Printf("exampleSyncBST.ForEach(): %v\n", te)
return nil
}); err != nil {
log.Fatal(err)
}
Output: exampleSyncBST.ForEach(): {a alpha} exampleSyncBST.ForEach(): {b bravo} exampleSyncBST.ForEach(): {c charlie} exampleSyncBST.ForEach(): {d delta}
func (*SyncBST[T]) Get ¶
Get returns the entry with the given key under a read lock.
Example ¶
tree := NewSync[testEntry](1024)
tree.Insert(testEntry{K: "a", V: "alpha"})
tree.Insert(testEntry{K: "b", V: "bravo"})
tree.Insert(testEntry{K: "c", V: "charlie"})
tree.Insert(testEntry{K: "d", V: "delta"})
val, ok := tree.Get("a")
fmt.Printf("exampleSyncBST.Get(%q): %v / %v\n", "a", val, ok)
Output: exampleSyncBST.Get("a"): {a alpha} / true
func (*SyncBST[T]) Insert ¶
func (b *SyncBST[T]) Insert(val T)
Insert adds val or replaces the existing entry with the same key under a write lock.
Example ¶
tree := NewSync[testEntry](1024)
tree.Insert(testEntry{K: "a", V: "alpha"})
tree.Insert(testEntry{K: "b", V: "bravo"})
tree.Insert(testEntry{K: "c", V: "charlie"})
tree.Insert(testEntry{K: "d", V: "delta"})
func (*SyncBST[T]) MarshalJSON ¶ added in v1.1.2
Example ¶
tree := NewSync[testEntry](0)
tree.Insert(testEntry{K: "b", V: "bravo"})
tree.Insert(testEntry{K: "a", V: "alpha"})
bs, err := json.Marshal(tree)
if err != nil {
log.Fatal(err)
}
fmt.Printf("exampleSyncBST.MarshalJSON(): %s\n", bs)
Output: exampleSyncBST.MarshalJSON(): [{"key":"a","value":"alpha"},{"key":"b","value":"bravo"}]
func (*SyncBST[T]) Remove ¶
Remove deletes the entry with the given key under a write lock.
Example ¶
tree := NewSync[testEntry](1024)
tree.Insert(testEntry{K: "a", V: "alpha"})
tree.Insert(testEntry{K: "b", V: "bravo"})
tree.Insert(testEntry{K: "c", V: "charlie"})
tree.Insert(testEntry{K: "d", V: "delta"})
tree.Remove("b")
fmt.Printf("exampleSyncBST.Length(): %d\n", tree.Length())
Output: exampleSyncBST.Length(): 3
func (*SyncBST[T]) UnmarshalJSON ¶ added in v1.1.2
Example ¶
var tree SyncBST[testEntry]
if err := json.Unmarshal([]byte(`[{"key":"c","value":"charlie"},{"key":"a","value":"alpha"}]`), &tree); err != nil {
log.Fatal(err)
}
if err := tree.ForEach(func(te testEntry) error {
fmt.Printf("exampleSyncBST.UnmarshalJSON(): %v\n", te)
return nil
}); err != nil {
log.Fatal(err)
}
Output: exampleSyncBST.UnmarshalJSON(): {a alpha} exampleSyncBST.UnmarshalJSON(): {c charlie}

