bst

package module
v1.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 30, 2026 License: MIT Imports: 3 Imported by: 1

README

bst   GoDoc Coverage Go Report Card MIT licensed

banner

bst is a Go library that provides a sorted string-keyed collection with binary-search lookups.

It stores entries in key order, supports in-place insert/replace semantics, and includes cursor helpers for neighbor traversal.

For concurrent access, SyncBST wraps the tree with an RWMutex and provides the same operations under read/write locks.

Motivation

Go gives you maps for fast keyed lookup, but maps do not preserve ordering.

If your workload needs:

  • Stable key ordering
  • Predictable iteration order
  • Keyed lookup
  • Neighbor navigation (Prev/Next)

then a sorted structure like bst can be a better fit.

Examples

Initialize BST
func ExampleBST() {
	tree := make(BST[testEntry], 0, 1024)

	_ = tree
}
BST.Insert
func ExampleBST_Insert() {
	tree := make(BST[testEntry], 0, 4)
	tree.Insert(testEntry{key: "a", value: "alpha"})
	tree.Insert(testEntry{key: "b", value: "bravo"})
	tree.Insert(testEntry{key: "c", value: "charlie"})
	tree.Insert(testEntry{key: "d", value: "delta"})

	fmt.Printf("exampleBST: %v\n", tree)

	// Output:
	// exampleBST: [{a alpha} {b bravo} {c charlie} {d delta}]
}
BST.Get
func ExampleBST_Get() {
	tree := make(BST[testEntry], 0, 4)
	tree.Insert(testEntry{key: "a", value: "alpha"})
	tree.Insert(testEntry{key: "b", value: "bravo"})
	tree.Insert(testEntry{key: "c", value: "charlie"})
	tree.Insert(testEntry{key: "d", value: "delta"})

	val, ok := tree.Get("a")
	fmt.Printf("exampleBST.Get(%q): %v / %v\n", "a", val, ok)

	// Output:
	// exampleBST.Get("a"): {a alpha} / true
}
BST.ForEach
func ExampleBST_ForEach() {
	tree := make(BST[testEntry], 0, 4)
	tree.Insert(testEntry{key: "a", value: "alpha"})
	tree.Insert(testEntry{key: "b", value: "bravo"})
	tree.Insert(testEntry{key: "c", value: "charlie"})
	tree.Insert(testEntry{key: "d", value: "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}
}
BST.Cursor
func ExampleBST_Cursor() {
	tree := make(BST[testEntry], 0, 4)
	tree.Insert(testEntry{key: "a", value: "alpha"})
	tree.Insert(testEntry{key: "b", value: "bravo"})
	tree.Insert(testEntry{key: "c", value: "charlie"})
	tree.Insert(testEntry{key: "d", value: "delta"})

	_ = tree.Cursor()
}
BST.Remove
func ExampleBST_Remove() {
	tree := make(BST[testEntry], 0, 4)
	tree.Insert(testEntry{key: "a", value: "alpha"})
	tree.Insert(testEntry{key: "b", value: "bravo"})
	tree.Insert(testEntry{key: "c", value: "charlie"})
	tree.Insert(testEntry{key: "d", value: "delta"})

	tree.Remove("b")
	fmt.Printf("exampleBS.Remove(): %v\n", tree)

	// Output:
	// exampleBS.Remove(): [{a alpha} {c charlie} {d delta}]
}
BST.UnmarshalJSON

Inbound JSON entries are sorted by Key() during unmarshal before assignment.

func ExampleBST_UnmarshalJSON() {
	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}]
}
Cursor.Seek
func ExampleCursor_Seek() {
	tree := make(BST[testEntry], 0, 4)
	tree.Insert(testEntry{key: "a", value: "alpha"})
	tree.Insert(testEntry{key: "b", value: "bravo"})
	tree.Insert(testEntry{key: "c", value: "charlie"})
	tree.Insert(testEntry{key: "d", value: "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
}
Cursor.Prev
func ExampleCursor_Prev() {
	tree := make(BST[testEntry], 0, 4)
	tree.Insert(testEntry{key: "a", value: "alpha"})
	tree.Insert(testEntry{key: "b", value: "bravo"})
	tree.Insert(testEntry{key: "c", value: "charlie"})
	tree.Insert(testEntry{key: "d", value: "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
}
Cursor.Next
func ExampleCursor_Next() {
	tree := make(BST[testEntry], 0, 4)
	tree.Insert(testEntry{key: "a", value: "alpha"})
	tree.Insert(testEntry{key: "b", value: "bravo"})
	tree.Insert(testEntry{key: "c", value: "charlie"})
	tree.Insert(testEntry{key: "d", value: "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
}
Cursor.First
func ExampleCursor_First() {
	tree := make(BST[testEntry], 0, 4)
	tree.Insert(testEntry{key: "a", value: "alpha"})
	tree.Insert(testEntry{key: "b", value: "bravo"})
	tree.Insert(testEntry{key: "c", value: "charlie"})
	tree.Insert(testEntry{key: "d", value: "delta"})
	cursor := tree.Cursor()

	val, ok := cursor.First()
	fmt.Printf("cursor.First(): %v / %v\n", val, ok)

	// Output:
	// cursor.First(): {a alpha} / true
}
Cursor.Last
func ExampleCursor_Last() {
	tree := make(BST[testEntry], 0, 4)
	tree.Insert(testEntry{key: "a", value: "alpha"})
	tree.Insert(testEntry{key: "b", value: "bravo"})
	tree.Insert(testEntry{key: "c", value: "charlie"})
	tree.Insert(testEntry{key: "d", value: "delta"})
	cursor := tree.Cursor()

	val, ok := cursor.Last()
	fmt.Printf("cursor.Last(): %v / %v\n", val, ok)

	// Output:
	// cursor.Last(): {d delta} / true
}
Initialize SyncBST
func ExampleSyncBST() {
	tree := NewSync[testEntry](1024)

	_ = tree
}

SyncBST has a usable zero value, so this is also valid:

func ExampleSyncBST_ZeroValue() {
	var tree SyncBST[testEntry]

	tree.Insert(testEntry{key: "a", value: "alpha"})
}

Use a non-nil value for method calls. var tree *SyncBST[testEntry] is nil, and calling methods on it panics.

NewSync(length int) follows Go's make behavior: negative length panics.

SyncBST.Insert
func ExampleSyncBST_Insert() {
	tree := NewSync[testEntry](1024)

	tree.Insert(testEntry{key: "a", value: "alpha"})
	tree.Insert(testEntry{key: "b", value: "bravo"})
	tree.Insert(testEntry{key: "c", value: "charlie"})
	tree.Insert(testEntry{key: "d", value: "delta"})
}
SyncBST.Get
func ExampleSyncBST_Get() {
	tree := NewSync[testEntry](1024)
	tree.Insert(testEntry{key: "a", value: "alpha"})
	tree.Insert(testEntry{key: "b", value: "bravo"})
	tree.Insert(testEntry{key: "c", value: "charlie"})
	tree.Insert(testEntry{key: "d", value: "delta"})

	val, ok := tree.Get("a")
	fmt.Printf("exampleSyncBST.Get(%q): %v / %v\n", "a", val, ok)

	// Output:
	// exampleSyncBST.Get("a"): {a alpha} / true
}
SyncBST.ForEach
func ExampleSyncBST_ForEach() {
	tree := NewSync[testEntry](1024)
	tree.Insert(testEntry{key: "a", value: "alpha"})
	tree.Insert(testEntry{key: "b", value: "bravo"})
	tree.Insert(testEntry{key: "c", value: "charlie"})
	tree.Insert(testEntry{key: "d", value: "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}
}

SyncBST.ForEach runs the callback while RLock is held. Do not call Insert or Remove on that same SyncBST from inside the callback, or you can self-deadlock.

SyncBST.Cursor
func ExampleSyncBST_Cursor() {
	tree := NewSync[testEntry](1024)
	tree.Insert(testEntry{key: "a", value: "alpha"})
	tree.Insert(testEntry{key: "b", value: "bravo"})
	tree.Insert(testEntry{key: "c", value: "charlie"})
	tree.Insert(testEntry{key: "d", value: "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
}

SyncBST.Cursor runs the callback while RLock is held. Do not call Insert or Remove on that same SyncBST from inside the callback, or you can self-deadlock.

SyncBST.Remove
func ExampleSyncBST_Remove() {
	tree := NewSync[testEntry](1024)
	tree.Insert(testEntry{key: "a", value: "alpha"})
	tree.Insert(testEntry{key: "b", value: "bravo"})
	tree.Insert(testEntry{key: "c", value: "charlie"})
	tree.Insert(testEntry{key: "d", value: "delta"})

	tree.Remove("b")
	fmt.Printf("exampleSyncBST.Length(): %d\n", tree.Length())

	// Output:
	// exampleSyncBST.Length(): 3
}
SyncBST.MarshalJSON
func ExampleSyncBST_MarshalJSON() {
	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"}]
}
SyncBST.UnmarshalJSON

Inbound JSON entries are sorted by Key() during unmarshal before assignment.

func ExampleSyncBST_UnmarshalJSON() {
	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}
}

Core Concepts

Sorted storage

Entries are always maintained in ascending Key() order.

Lookup and update behavior

Get uses binary search.

Insert replaces an existing entry when keys match, otherwise inserts at the sorted position.

Deterministic iteration

ForEach always walks entries in key order.

Cursor navigation

A cursor can seek to a key, then move to adjacent entries with Prev and Next.

Concurrency model

BST is not synchronized.

SyncBST provides thread-safe access by wrapping operations with an RWMutex.

SyncBST.ForEach and SyncBST.Cursor hold RLock for the entire callback execution. Callbacks should be read-only with respect to the same SyncBST instance. Calling Insert or Remove from those callbacks can self-deadlock.

AI Usage and Authorship

This project is intentionally human-authored for all logic.

To be explicit:

  • AI does not write or modify non-test code in this repository.
  • AI does not make architectural or behavioral decisions.
  • AI may assist with documentation, comments, and test scaffolding only.
  • All implementation logic is written and reviewed by human maintainers.

These boundaries are enforced in AGENTS.md and are part of this repository's contribution discipline.

Contributors

  • Human maintainers: library design, implementation, and behavior decisions.
  • ChatGPT Codex: documentation, test coverage support, and comments.
  • Google Gemini: README artwork generation.

footer

Documentation

Overview

Package bst provides a sorted string-keyed collection and cursor helpers.

Index

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

func (b BST[T]) Cursor() (out *Cursor[T])

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

func (b BST[T]) ForEach(fn func(T) error) (err error)

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

func (b BST[T]) Get(key string) (out T, ok bool)

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

func (b *BST[T]) Remove(key string)

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

func (b *BST[T]) UnmarshalJSON(bs []byte) (err error)
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

func (c *Cursor[T]) First() (val T, ok bool)

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

func (c *Cursor[T]) Last() (val T, ok bool)

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

func (c *Cursor[T]) Next() (val T, ok bool)

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

func (c *Cursor[T]) Prev() (val T, ok bool)

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

func (c *Cursor[T]) Seek(key string) (val T, ok bool)

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

func NewSync[T Entry](length int) (out *SyncBST[T])

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

func (b *SyncBST[T]) Cursor(fn func(*Cursor[T]) error) (err error)

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

func (b *SyncBST[T]) ForEach(fn func(T) error) (err error)

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

func (b *SyncBST[T]) Get(key string) (out T, ok bool)

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]) Length

func (b *SyncBST[T]) Length() (n int)

Length returns the number of entries under a read lock.

func (*SyncBST[T]) MarshalJSON added in v1.1.2

func (b *SyncBST[T]) MarshalJSON() (bs []byte, err error)
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

func (b *SyncBST[T]) Remove(key string)

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

func (b *SyncBST[T]) UnmarshalJSON(bs []byte) (err error)
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}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL