radixtree

package module
v0.4.1 Latest Latest
Warning

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

Go to latest
Published: May 1, 2026 License: MIT Imports: 2 Imported by: 6

README

radixtree

GoDoc Build Status Go Report Card codecov License

Package radixtree implements an Adaptive Radix Tree, also known as a compressed trie or compact prefix tree. Use it to look up values by key, find values whose keys share a common prefix, or find values whose keys lie along the path to a given key.

The tree uses a radix-256 structure where each key symbol is a byte, giving up to 256 branches per node. Nodes hold only as many children as needed, keeping memory proportional to the data stored.

Read operations (Get, Iter, IterAt, IterPath) allocate no heap memory and are safe to call concurrently. Write operations are not synchronized; callers that mix reads and writes must coordinate access themselves.

Features

  • Efficient: All operations are O(key-length). Reads allocate no heap memory.
  • Ordered: Iteration visits keys in lexical order, making output deterministic.
  • Nil-safe: Get distinguishes between a missing key and a key whose value is nil.
  • Compact: Keys with a common prefix share storage. Well-suited for timestamps, file paths, geohashes, and network addresses.
  • Iterators: Go 1.23 range iterators cover all key-value pairs (Iter), pairs with a given prefix (IterAt), or pairs along the path from root to a key (IterPath).
  • Stepper: Walk the tree one byte at a time for incremental lookup. Copy a Stepper to branch a search and use the copies concurrently.
  • Generics: Store any value type without interface conversions.

Install

$ go get github.com/gammazero/radixtree

Example

package main

import (
    "fmt"
    "github.com/gammazero/radixtree"
)

func main() {
    rt := radixtree.New[string]()
    rt.Put("tomato", "TOMATO")
    rt.Put("tom", "TOM")
    rt.Put("tommy", "TOMMY")
    rt.Put("tornado", "TORNADO")

    val, found := rt.Get("tom")
    if found {
        fmt.Println("Found", val)
    }
    // Output: Found TOM

    // Find all items whose keys start with "tom".
    for key, value := range rt.IterAt("tom") {
        fmt.Println(key, "=", value)
    }
    // Output:
    // tom = TOM
    // tomato = TOMATO
    // tommy = TOMMY

    // Find all items whose keys are a prefix of "tomato".
    for key, value := range rt.IterPath("tomato") {
        fmt.Println(key, "=", value)
    }
    // Output:
    // tom = TOM
    // tomato = TOMATO

    if rt.Delete("tom") {
        fmt.Println("Deleted tom")
    }
    // Output: Deleted tom

    _, found = rt.Get("tom")
    if !found {
        fmt.Println("not found")
    }
    // Output: not found
}

License

MIT License

Documentation

Overview

Package radixtree implements an Adaptive Radix Tree, also called a compressed trie or compact prefix tree. Use it to look up values by key, find values whose keys share a common prefix, or find values whose keys lie along the path to a given key.

The tree uses a radix-256 structure where each key symbol is a byte, giving up to 256 branches per node. Nodes hold only as many children as needed, keeping memory proportional to the data stored.

Read operations (Get, Iter, IterAt, IterPath) allocate no heap memory and are safe to call concurrently. Write operations are not synchronized; callers that mix reads and writes must coordinate access themselves.

The API accepts string keys. Because strings are immutable, the tree stores them directly without copying.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type InspectFunc

type InspectFunc[T any] func(link, prefix, key string, depth, children int, hasValue bool, value T) bool

InspectFunc is the type of the function called for each node visited by Inspect. The key argument contains the key at which the node is located, the depth is the distance from the root of the tree, and children is the number of children the node has.

If the function returns true Inspect stops immediately and returns.

type Item added in v0.3.2

type Item[T any] struct {
	// contains filtered or unexported fields
}

func (*Item[T]) Key added in v0.3.2

func (kv *Item[T]) Key() string

func (*Item[T]) Value added in v0.3.2

func (kv *Item[T]) Value() T

type Stepper added in v0.3.0

type Stepper[T any] struct {
	// contains filtered or unexported fields
}

Stepper traverses a Tree one byte at a time.

Any modification to the tree invalidates the Stepper.

func (*Stepper[T]) Copy added in v0.3.0

func (s *Stepper[T]) Copy() *Stepper[T]

Copy makes a copy of the current Stepper. This allows branching a Stepper into two that can take separate paths. These Steppers do not affect each other and can be used concurrently.

func (*Stepper[T]) Item added in v0.3.2

func (s *Stepper[T]) Item() *Item[T]

Item returns an Item containing the key and value at the current Stepper position, or returns nil if no value is present at the position.

func (*Stepper[T]) Next added in v0.3.0

func (s *Stepper[T]) Next(radix byte) bool

Next advances the Stepper from its current position, to the position of given key symbol in the tree, so long as the given symbol is next in a path in the tree. If the symbol allows the Stepper to advance, then true is returned. Otherwise false is returned.

When false is returned the Stepper is not modified. This allows different values to be used in subsequent calls to Next.

func (*Stepper[T]) Value added in v0.3.0

func (s *Stepper[T]) Value() (T, bool)

Value returns the value at the current Stepper position, and true or false to indicate if a value is present at the position.

type Tree added in v0.3.0

type Tree[T any] struct {
	// contains filtered or unexported fields
}

Tree is a radix tree of bytes keys and any values.

func New added in v0.2.0

func New[T any]() *Tree[T]

New creates a new bytes-based radix tree

func (*Tree[T]) Delete added in v0.3.0

func (t *Tree[T]) Delete(key string) bool

Delete removes the value associated with the given key. Returns true if there was a value stored for the key. If the node or any of its ancestors becomes childless as a result, they are removed from the tree.

func (*Tree[T]) DeletePrefix added in v0.3.1

func (t *Tree[T]) DeletePrefix(prefix string) bool

DeletePrefix removes all values whose key is prefixed by the given prefix. Returns true if any values were removed.

func (*Tree[T]) Get added in v0.3.0

func (t *Tree[T]) Get(key string) (T, bool)

Get returns the value stored at the given key. Returns false if there is no value present for the key.

func (*Tree[T]) Inspect added in v0.3.0

func (t *Tree[T]) Inspect(inspectFn InspectFunc[T])

Inspect walks every node of the tree, whether or not it holds a value, calling inspectFn with information about each node. This allows the structure of the tree to be examined and detailed statistics to be collected.

If inspectFn returns false, the traversal is stopped and Inspect returns.

The tree is traversed in lexical order, making the output deterministic.

func (*Tree[T]) Iter added in v0.4.0

func (t *Tree[T]) Iter() iter.Seq2[string, T]

Iter visits all nodes in the tree, yielding the key and value of each.

The tree is traversed in lexical order, making the output deterministic.

Example
package main

import (
	"fmt"

	"github.com/gammazero/radixtree"
)

func main() {
	rt := radixtree.New[int]()
	rt.Put("mercury", 1)
	rt.Put("venus", 2)
	rt.Put("earth", 3)
	rt.Put("mars", 4)

	// Find all items that that have a key that is a prefix of "tomato".
	for key, value := range rt.Iter() {
		fmt.Println(key, "=", value)
	}
}
Output:
earth = 3
mars = 4
mercury = 1
venus = 2

func (*Tree[T]) IterAt added in v0.4.0

func (t *Tree[T]) IterAt(key string) iter.Seq2[string, T]

IterAt visits all nodes whose keys match or are prefixed by the specified key, yielding the key and value of each. An empty key "" to visits all nodes, and is the same as calling Iter.

The tree is traversed in lexical order, making the output deterministic.

Example
package main

import (
	"fmt"

	"github.com/gammazero/radixtree"
)

func main() {
	rt := radixtree.New[string]()
	rt.Put("tomato", "TOMATO")
	rt.Put("tom", "TOM")
	rt.Put("tommy", "TOMMY")
	rt.Put("tornado", "TORNADO")

	// Find all items whose keys start with "tom".
	for _, value := range rt.IterAt("tom") {
		fmt.Println(value)
	}
}
Output:
TOM
TOMATO
TOMMY

func (*Tree[T]) IterPath added in v0.4.0

func (t *Tree[T]) IterPath(key string) iter.Seq2[string, T]

IterPath returns an iterator that visits each node along the path from the root to the node at the given key. yielding the key and value of each.

The tree is traversed in lexical order, making the output deterministic.

Example
package main

import (
	"fmt"

	"github.com/gammazero/radixtree"
)

func main() {
	rt := radixtree.New[string]()
	rt.Put("tomato", "TOMATO")
	rt.Put("tom", "TOM")
	rt.Put("tommy", "TOMMY")
	rt.Put("tornado", "TORNADO")

	// Find all items that that have a key that is a prefix of "tomato".
	for key, value := range rt.IterPath("tomato") {
		fmt.Println(key, "=", value)
	}
}
Output:
tom = TOM
tomato = TOMATO

func (*Tree[T]) Len added in v0.3.0

func (t *Tree[T]) Len() int

Len returns the number of values stored in the tree.

func (*Tree[T]) NewStepper added in v0.3.0

func (t *Tree[T]) NewStepper() *Stepper[T]

NewStepper returns a new Stepper instance that begins at the root of the tree.

Example
package main

import (
	"fmt"

	"github.com/gammazero/radixtree"
)

func main() {
	rt := radixtree.New[string]()
	rt.Put("tomato", "TOMATO")
	rt.Put("tom", "TOM")
	rt.Put("tommy", "TOMMY")
	rt.Put("tornado", "TORNADO")

	stepper := rt.NewStepper()
	word := "tomato"
	for i := range word {
		if !stepper.Next(word[i]) {
			break
		}
		if val, ok := stepper.Value(); ok {
			fmt.Println(val)
		}
	}
}
Output:
TOM
TOMATO

func (*Tree[T]) Put added in v0.3.0

func (t *Tree[T]) Put(key string, value T) bool

Put inserts the value into the tree at the given key, replacing any existing items. It returns true if it adds a new value, false if it replaces an existing value.

Jump to

Keyboard shortcuts

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