btree
May 12, 2026 ยท View on GitHub
Due to recent spikes in bot activity, the Issues and Pull Requests tabs have been disabled. For priority support, contact me directly.
btree
An efficient B-tree implementation in Go.
Features
- Support for Generics (Go 1.18+).
MapandSettypes for ordered key-value maps and sets,- Fast bulk loading for pre-ordered data using the
Load()method. Copy()method with copy-on-write support.- Path hinting optimization for operations with nearby keys.
- Allows for array-like operations. (Counted B-tree)
Using
To start using this package, install Go and run:
$ go get github.com/tidwall/btree
B-tree types
This package includes the following types of B-trees:
-
btree.Map: A fast B-tree for storing ordered key value pairs. -
btree.Set: LikeMap, but only for storing keys. -
btree.BTreeG: A feature-rich B-tree for storing data using a custom comparator. Thread-safe. -
btree.BTree: LikeBTreeGbut uses theinterface{}type for data. Backwards compatible. Thread-safe.
btree.Map
// Basic
Set(key, value) // insert or replace an item
Get(key, value) // get an existing item
Delete(key) // delete an item
Len() // return the number of items in the map
// Iteration
Scan(iter) // scan items in ascending order
Reverse(iter) // scan items in descending order
Ascend(key, iter) // scan items in ascending order that are >= to key
Descend(key, iter) // scan items in descending order that are <= to key.
Iter() // returns a read-only iterator for for-loops.
// Array-like operations
GetAt(index) // returns the item at index
DeleteAt(index) // deletes the item at index
// Bulk-loading
Load(key, value) // load presorted items into tree
Example
package main
import (
"fmt"
"github.com/tidwall/btree"
)
func main() {
// create a map
var users btree.Map[string, string]
// add some users
users.Set("user:4", "Andrea")
users.Set("user:6", "Andy")
users.Set("user:2", "Andy")
users.Set("user:1", "Jane")
users.Set("user:5", "Janet")
users.Set("user:3", "Steve")
// Iterate over the maps and print each user
users.Scan(func(key, value string) bool {
fmt.Printf("%s %s\n", key, value)
return true
})
fmt.Printf("\n")
// Delete a couple
users.Delete("user:5")
users.Delete("user:1")
// print the map again
users.Scan(func(key, value string) bool {
fmt.Printf("%s %s\n", key, value)
return true
})
fmt.Printf("\n")
// Output:
// user:1 Jane
// user:2 Andy
// user:3 Steve
// user:4 Andrea
// user:5 Janet
// user:6 Andy
//
// user:2 Andy
// user:3 Steve
// user:4 Andrea
// user:6 Andy
}
btree.Set
// Basic
Insert(key) // insert an item
Contains(key) // test if item exists
Delete(key) // delete an item
Len() // return the number of items in the set
// Iteration
Scan(iter) // scan items in ascending order
Reverse(iter) // scan items in descending order
Ascend(key, iter) // scan items in ascending order that are >= to key
Descend(key, iter) // scan items in descending order that are <= to key.
Iter() // returns a read-only iterator for for-loops.
// Array-like operations
GetAt(index) // returns the item at index
DeleteAt(index) // deletes the item at index
// Bulk-loading
Load(key) // load presorted item into tree
Example
package main
import (
"fmt"
"github.com/tidwall/btree"
)
func main() {
// create a set
var names btree.Set[string]
// add some names
names.Insert("Jane")
names.Insert("Andrea")
names.Insert("Steve")
names.Insert("Andy")
names.Insert("Janet")
names.Insert("Andy")
// Iterate over the maps and print each user
names.Scan(func(key string) bool {
fmt.Printf("%s\n", key)
return true
})
fmt.Printf("\n")
// Delete a couple
names.Delete("Steve")
names.Delete("Andy")
// print the map again
names.Scan(func(key string) bool {
fmt.Printf("%s\n", key)
return true
})
fmt.Printf("\n")
// Output:
// Andrea
// Andy
// Jane
// Janet
// Steve
//
// Andrea
// Jane
// Janet
}
btree.BTreeG
// Basic
Set(item) // insert or replace an item
Get(item) // get an existing item
Delete(item) // delete an item
Len() // return the number of items in the btree
// Iteration
Scan(iter) // scan items in ascending order
Reverse(iter) // scan items in descending order
Ascend(key, iter) // scan items in ascending order that are >= to key
Descend(key, iter) // scan items in descending order that are <= to key.
Iter() // returns a read-only iterator for for-loops.
// Array-like operations
GetAt(index) // returns the item at index
DeleteAt(index) // deletes the item at index
// Bulk-loading
Load(item) // load presorted items into tree
// Path hinting
SetHint(item, *hint) // insert or replace an existing item
GetHint(item, *hint) // get an existing item
DeleteHint(item, *hint) // delete an item
AscendHint(key, iter, *hint)
DescendHint(key, iter, *hint)
SeekHint(key, iter, *hint)
// Copy-on-write
Copy() // copy the btree
Example
package main
import (
"fmt"
"github.com/tidwall/btree"
)
type Item struct {
Key, Val string
}
// byKeys is a comparison function that compares item keys and returns true
// when a is less than b.
func byKeys(a, b Item) bool {
return a.Key < b.Key
}
// byVals is a comparison function that compares item values and returns true
// when a is less than b.
func byVals(a, b Item) bool {
if a.Val < b.Val {
return true
}
if a.Val > b.Val {
return false
}
// Both vals are equal so we should fall though
// and let the key comparison take over.
return byKeys(a, b)
}
func main() {
// Create a tree for keys and a tree for values.
// The "keys" tree will be sorted on the Keys field.
// The "values" tree will be sorted on the Values field.
keys := btree.NewBTreeG[Item](byKeys)
vals := btree.NewBTreeG[Item](byVals)
// Create some items.
users := []Item{
Item{Key: "user:1", Val: "Jane"},
Item{Key: "user:2", Val: "Andy"},
Item{Key: "user:3", Val: "Steve"},
Item{Key: "user:4", Val: "Andrea"},
Item{Key: "user:5", Val: "Janet"},
Item{Key: "user:6", Val: "Andy"},
}
// Insert each user into both trees
for _, user := range users {
keys.Set(user)
vals.Set(user)
}
// Iterate over each user in the key tree
keys.Scan(func(item Item) bool {
fmt.Printf("%s %s\n", item.Key, item.Val)
return true
})
fmt.Printf("\n")
// Iterate over each user in the val tree
vals.Scan(func(item Item) bool {
fmt.Printf("%s %s\n", item.Key, item.Val)
return true
})
// Output:
// user:1 Jane
// user:2 Andy
// user:3 Steve
// user:4 Andrea
// user:5 Janet
// user:6 Andy
//
// user:4 Andrea
// user:2 Andy
// user:6 Andy
// user:1 Jane
// user:5 Janet
// user:3 Steve
}
btree.BTree
// Basic
Set(item) // insert or replace an item
Get(item) // get an existing item
Delete(item) // delete an item
Len() // return the number of items in the btree
// Iteration
Scan(iter) // scan items in ascending order
Reverse(iter) // scan items in descending order
Ascend(key, iter) // scan items in ascending order that are >= to key
Descend(key, iter) // scan items in descending order that are <= to key.
Iter() // returns a read-only iterator for for-loops.
// Array-like operations
GetAt(index) // returns the item at index
DeleteAt(index) // deletes the item at index
// Bulk-loading
Load(item) // load presorted items into tree
// Path hinting
SetHint(item, *hint) // insert or replace an existing item
GetHint(item, *hint) // get an existing item
DeleteHint(item, *hint) // delete an item
AscendHint(key, iter, *hint)
DescendHint(key, iter, *hint)
SeekHint(key, iter, *hint)
// Copy-on-write
Copy() // copy the btree
Example
package main
import (
"fmt"
"github.com/tidwall/btree"
)
type Item struct {
Key, Val string
}
// byKeys is a comparison function that compares item keys and returns true
// when a is less than b.
func byKeys(a, b interface{}) bool {
i1, i2 := a.(*Item), b.(*Item)
return i1.Key < i2.Key
}
// byVals is a comparison function that compares item values and returns true
// when a is less than b.
func byVals(a, b interface{}) bool {
i1, i2 := a.(*Item), b.(*Item)
if i1.Val < i2.Val {
return true
}
if i1.Val > i2.Val {
return false
}
// Both vals are equal so we should fall though
// and let the key comparison take over.
return byKeys(a, b)
}
func main() {
// Create a tree for keys and a tree for values.
// The "keys" tree will be sorted on the Keys field.
// The "values" tree will be sorted on the Values field.
keys := btree.New(byKeys)
vals := btree.New(byVals)
// Create some items.
users := []*Item{
&Item{Key: "user:1", Val: "Jane"},
&Item{Key: "user:2", Val: "Andy"},
&Item{Key: "user:3", Val: "Steve"},
&Item{Key: "user:4", Val: "Andrea"},
&Item{Key: "user:5", Val: "Janet"},
&Item{Key: "user:6", Val: "Andy"},
}
// Insert each user into both trees
for _, user := range users {
keys.Set(user)
vals.Set(user)
}
// Iterate over each user in the key tree
keys.Ascend(nil, func(item interface{}) bool {
kvi := item.(*Item)
fmt.Printf("%s %s\n", kvi.Key, kvi.Val)
return true
})
fmt.Printf("\n")
// Iterate over each user in the val tree
vals.Ascend(nil, func(item interface{}) bool {
kvi := item.(*Item)
fmt.Printf("%s %s\n", kvi.Key, kvi.Val)
return true
})
// Output:
// user:1 Jane
// user:2 Andy
// user:3 Steve
// user:4 Andrea
// user:5 Janet
// user:6 Andy
//
// user:4 Andrea
// user:2 Andy
// user:6 Andy
// user:1 Jane
// user:5 Janet
// user:3 Steve
}
Performance
See tidwall/btree-benchmark for benchmark numbers.
Contact
Josh Baker @tidwall
License
Source code is available under the MIT License.