sparse

package
v0.0.0-...-2f994d5 Latest Latest
Warning

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

Go to latest
Published: May 15, 2026 License: MIT Imports: 0 Imported by: 0

Documentation

Overview

Package sparse provides a sparse set data structure for efficient state tracking.

A sparse set achieves O(1) insertion, membership testing, and clearing by exploiting the "uninitialized memory trick" described by Briggs & Torczon (1993) and popularized by Russ Cox for regex engines (https://research.swtch.com/sparse).

This is the preferred data structure for NFA state tracking because:

  • O(1) clear: just reset the size counter, no memory zeroing needed
  • O(1) membership test: cross-validation between sparse and dense arrays
  • Insertion order preserved: enables deterministic NFA simulation
  • Cache-friendly iteration: sequential access to dense array

Trade-off: Uses 8 bytes per potential element (4 bytes sparse + 4 bytes dense) vs 1 bit for bitsets. But the O(1) clear makes this worthwhile for regex engines where clear is called per-position during NFA simulation.

Reference implementations:

  • Rust regex-automata: regex-automata/src/util/sparse_set.rs
  • RE2: re2/sparse_set.h
  • Go regexp: uses bitsets (different trade-off for small patterns)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type SparseSet

type SparseSet struct {
	// contains filtered or unexported fields
}

SparseSet is a set of uint32 values with O(1) membership, insertion, and clear.

The data structure maintains two arrays:

  • sparse[value] = index in dense where value is stored
  • dense[index] = the actual value

Membership test: sparse[v] < size AND dense[sparse[v]] == v The cross-validation handles garbage values in uninitialized sparse slots.

Example layout for set {2, 5, 1}:

sparse[]                        dense[]
+---+---+---+---+---+---+       +---+---+---+---+
| ? | 2 | 0 | ? | ? | 1 |       | 2 | 5 | 1 | ? |
+---+---+---+---+---+---+       +---+---+---+---+
  0   1   2   3   4   5           0   1   2
                                        ^ size=3

Clear() simply sets size=0, making all elements "unreachable" in O(1).

func NewSparseSet

func NewSparseSet(capacity uint32) *SparseSet

NewSparseSet creates a new sparse set with the given capacity. Capacity must be at least max(values)+1 that will be stored. For NFA state tracking, use nfa.States() as capacity.

func (*SparseSet) Capacity

func (s *SparseSet) Capacity() uint32

Capacity returns the maximum value that can be stored + 1.

func (*SparseSet) Clear

func (s *SparseSet) Clear()

Clear removes all elements in O(1) time. This is the magic of sparse sets - no memory zeroing needed. All previous elements become "unreachable" because idx >= size.

func (*SparseSet) Clone

func (s *SparseSet) Clone() *SparseSet

Clone creates a deep copy of the sparse set.

func (*SparseSet) Contains

func (s *SparseSet) Contains(value uint32) bool

Contains returns true if the value is in the set. This is the key operation - O(1) with cross-validation to handle garbage.

func (*SparseSet) Insert

func (s *SparseSet) Insert(value uint32) bool

Insert adds a value to the set. Returns true if the value was newly added. If the value is already present, returns false (no-op). Panics if value >= capacity.

func (*SparseSet) IsEmpty

func (s *SparseSet) IsEmpty() bool

IsEmpty returns true if the set contains no elements.

func (*SparseSet) Iter

func (s *SparseSet) Iter(f func(uint32))

Iter calls the given function for each value in the set. Values are iterated in insertion order.

func (*SparseSet) Len

func (s *SparseSet) Len() int

Len returns the number of elements in the set.

func (*SparseSet) MemoryUsage

func (s *SparseSet) MemoryUsage() int

MemoryUsage returns the approximate memory usage in bytes. Formula: 2 * capacity * 4 bytes (for sparse and dense arrays)

func (*SparseSet) Remove

func (s *SparseSet) Remove(value uint32)

Remove removes a value from the set. If the value is not present, this is a no-op.

func (*SparseSet) Resize

func (s *SparseSet) Resize(newCapacity uint32)

Resize changes the capacity of the set. If newCapacity < current capacity, the set is cleared. If newCapacity > current capacity, arrays are reallocated.

func (*SparseSet) Size

func (s *SparseSet) Size() int

Size returns the number of elements in the set. Alias for Len() for compatibility.

func (*SparseSet) Values

func (s *SparseSet) Values() []uint32

Values returns a slice of all values in the set. The returned slice is valid until the next mutation. Values are in insertion order (first inserted = first in slice).

type SparseSets

type SparseSets struct {
	Set1 *SparseSet // Current generation
	Set2 *SparseSet // Next generation
}

SparseSets holds a pair of sparse sets for double-buffering. This is the Rust regex-automata pattern for NFA simulation:

  • Set1 holds current generation states
  • Set2 accumulates next generation states
  • After each byte: Swap() and Clear(Set2)

func NewSparseSets

func NewSparseSets(capacity uint32) *SparseSets

NewSparseSets creates a pair of sparse sets with given capacity.

func (*SparseSets) Clear

func (ss *SparseSets) Clear()

Clear clears both sets.

func (*SparseSets) MemoryUsage

func (ss *SparseSets) MemoryUsage() int

MemoryUsage returns total memory usage of both sets.

func (*SparseSets) Resize

func (ss *SparseSets) Resize(newCapacity uint32)

Resize resizes both sets to the new capacity.

func (*SparseSets) Swap

func (ss *SparseSets) Swap()

Swap exchanges Set1 and Set2 in O(1) time (pointer swap).

Jump to

Keyboard shortcuts

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