index

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Mar 11, 2026 License: AGPL-3.0 Imports: 12 Imported by: 0

Documentation

Overview

Package index provides in-memory indexing for code symbols.

The index package contains SymbolIndex, a concurrent-safe data structure for fast O(1) lookups of symbols by ID, name, file path, and kind.

Ownership Model

The index stores pointers to symbols but does NOT own them:

  • Symbols MUST NOT be mutated after being added to the index
  • To update symbols: call RemoveByFile() then AddBatch() with new symbols
  • The index does NOT copy symbols (for memory efficiency)

Thread Safety

SymbolIndex is safe for concurrent use. Multiple goroutines can call any combination of methods simultaneously. Write operations (Add, AddBatch, RemoveByFile, Clear) use exclusive locks; read operations (GetBy*, Search, Stats) use shared locks.

Index

Constants

View Source
const (
	// DefaultMaxSymbols is the default maximum number of symbols the index can hold.
	DefaultMaxSymbols = 1_000_000
)

Default configuration values.

Variables

View Source
var (
	// ErrDuplicateSymbol is returned when adding a symbol with an ID
	// that already exists in the index.
	ErrDuplicateSymbol = errors.New("duplicate symbol ID")

	// ErrMaxSymbolsExceeded is returned when the index has reached
	// its configured maximum capacity.
	ErrMaxSymbolsExceeded = errors.New("maximum symbol count exceeded")

	// ErrInvalidSymbol is returned when a symbol fails validation.
	// The underlying error from Symbol.Validate() is wrapped.
	ErrInvalidSymbol = errors.New("invalid symbol")
)

Sentinel errors for symbol index operations.

Functions

This section is empty.

Types

type BatchError

type BatchError struct {
	// Errors contains all individual errors encountered during the batch operation.
	// Each error includes the index position (e.g., "symbol[0]: duplicate ID").
	Errors []error
}

BatchError aggregates multiple errors from batch operations.

When AddBatch encounters validation errors or duplicates, it collects all errors and returns them together rather than failing on the first error. This allows callers to see all problems at once.

BatchError implements the standard errors.Unwrap() interface for Go 1.20+ multi-error unwrapping.

func (*BatchError) Error

func (e *BatchError) Error() string

Error returns a human-readable summary of the batch errors.

Format depends on error count:

  • 1 error: returns that error's message directly
  • 2+ errors: returns count and first error with "and N more" suffix

func (*BatchError) ErrorList

func (e *BatchError) ErrorList() string

ErrorList returns a formatted string with all errors, one per line.

This is useful for logging or displaying the full list of problems to a user who needs to fix them all.

func (*BatchError) Unwrap

func (e *BatchError) Unwrap() []error

Unwrap returns the underlying errors for use with errors.Is and errors.As.

This implements the Go 1.20+ multi-error unwrapping interface.

type IndexStats

type IndexStats struct {
	// TotalSymbols is the total number of symbols in the index.
	TotalSymbols int

	// ByKind maps each SymbolKind to the count of symbols of that kind.
	ByKind map[ast.SymbolKind]int

	// FileCount is the number of unique files with symbols in the index.
	FileCount int

	// MaxSymbols is the configured maximum capacity.
	MaxSymbols int
}

IndexStats contains statistics about the symbol index.

type SymbolIndex

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

SymbolIndex provides fast O(1) lookups of symbols by various keys.

The index maintains multiple maps for efficient access patterns:

  • byID: Primary index for unique symbol lookup
  • byName: Secondary index for name-based queries (multiple symbols can share a name)
  • byFile: Secondary index for file-based queries
  • byKind: Secondary index for kind-based queries

Thread Safety:

SymbolIndex is safe for concurrent use. Multiple goroutines can call
any combination of methods simultaneously.

Ownership:

The index stores pointers to symbols but does NOT own them.
Symbols MUST NOT be mutated after being added to the index.

func NewSymbolIndex

func NewSymbolIndex(opts ...SymbolIndexOption) *SymbolIndex

NewSymbolIndex creates a new empty symbol index with the given options.

Description:

Creates a concurrent-safe index for storing and querying code symbols.
The index is empty upon creation.

Example:

// Default options (1M max symbols)
idx := NewSymbolIndex()

// Custom options
idx := NewSymbolIndex(WithMaxSymbols(100_000))

func (*SymbolIndex) Add

func (idx *SymbolIndex) Add(symbol *ast.Symbol) error

Add adds a single symbol to the index.

Description:

Validates the symbol, checks for duplicates and capacity, then adds
the symbol to all indexes atomically.

Inputs:

symbol - The symbol to add. Must pass Symbol.Validate().

Outputs:

error - Non-nil if validation fails, symbol ID already exists, or
        index is at capacity.

Errors:

ErrInvalidSymbol - Symbol failed validation
ErrDuplicateSymbol - Symbol with same ID already exists
ErrMaxSymbolsExceeded - Index is at capacity

Thread Safety:

This method is safe for concurrent use.

func (*SymbolIndex) AddBatch

func (idx *SymbolIndex) AddBatch(symbols []*ast.Symbol) error

AddBatch adds multiple symbols to the index atomically.

Description:

Validates all symbols, checks for duplicates (both within the batch
and against existing symbols), then adds all symbols atomically.
If any validation fails, NO symbols are added.

Inputs:

symbols - The symbols to add. All must pass validation.

Outputs:

error - Non-nil if any validation fails, any duplicates exist, or
        adding would exceed capacity.

Errors:

*BatchError - Contains all validation/duplicate errors found
ErrMaxSymbolsExceeded - Adding batch would exceed capacity

Thread Safety:

This method is safe for concurrent use.

func (*SymbolIndex) Clear

func (idx *SymbolIndex) Clear()

Clear removes all symbols from the index.

Description:

Resets the index to empty state. All counters are reset to zero.

Thread Safety:

This method is safe for concurrent use.

func (*SymbolIndex) Clone

func (idx *SymbolIndex) Clone() *SymbolIndex

Clone creates a deep copy of the symbol index.

Description:

Creates an independent copy of the index that can be modified without
affecting the original. Used for copy-on-write incremental updates.

Outputs:

*SymbolIndex - A deep copy of the index.

Behavior:

  • All maps are deep copied
  • Symbol pointers are shared (symbols are immutable after add)
  • Counters are copied
  • Options are copied

Thread Safety:

The returned index is independent and can be modified without synchronization.
This method is safe to call concurrently on the source index.

func (*SymbolIndex) GetByFile

func (idx *SymbolIndex) GetByFile(filePath string) []*ast.Symbol

GetByFile retrieves all symbols in the given file.

Description:

Performs O(1) lookup, returns defensive copy of the result slice.

Inputs:

filePath - The file path (relative to project root)

Outputs:

[]*ast.Symbol - Defensive copy of symbols in that file, nil if none found

Thread Safety:

This method is safe for concurrent use. The returned slice is a copy
and can be safely modified by the caller.

func (*SymbolIndex) GetByID

func (idx *SymbolIndex) GetByID(id string) (*ast.Symbol, bool)

GetByID retrieves a symbol by its unique ID.

Description:

Performs O(1) lookup in the primary index.

Inputs:

id - The symbol ID (format: "file_path:line:name")

Outputs:

*ast.Symbol - The symbol if found, nil otherwise
bool - True if symbol was found

Thread Safety:

This method is safe for concurrent use.

func (*SymbolIndex) GetByKind

func (idx *SymbolIndex) GetByKind(kind ast.SymbolKind) []*ast.Symbol

GetByKind retrieves all symbols of the given kind.

Description:

Performs O(1) lookup, returns defensive copy of the result slice.

Inputs:

kind - The symbol kind (e.g., SymbolKindFunction)

Outputs:

[]*ast.Symbol - Defensive copy of symbols of that kind, nil if none found

Thread Safety:

This method is safe for concurrent use. The returned slice is a copy
and can be safely modified by the caller.

func (*SymbolIndex) GetByName

func (idx *SymbolIndex) GetByName(name string) []*ast.Symbol

GetByName retrieves all symbols with the given name.

Description:

Performs O(1) lookup, returns defensive copy of the result slice.
Multiple symbols can share the same name (e.g., "Handler" in different packages).

Inputs:

name - The symbol name to search for

Outputs:

[]*ast.Symbol - Defensive copy of matching symbols, nil if none found

Thread Safety:

This method is safe for concurrent use. The returned slice is a copy
and can be safely modified by the caller.

func (*SymbolIndex) GetUniqueFilePaths

func (idx *SymbolIndex) GetUniqueFilePaths() []string

GetUniqueFilePaths returns a list of unique file paths that have symbols in the index.

Description:

CRS-26n: Used by computeGraphContentHash to include file identity in
the content hash. This prevents hash collisions when two different
projects have the same node+edge count.

Outputs:

[]string - Unique file paths (unsorted). Caller should sort if deterministic
           ordering is needed.

Thread Safety:

This method is safe for concurrent use.

func (*SymbolIndex) RemoveByFile

func (idx *SymbolIndex) RemoveByFile(filePath string) int

RemoveByFile removes all symbols from the given file.

Description:

Removes symbols from all indexes atomically. Use this before
AddBatch when updating symbols for a file.

Inputs:

filePath - The file path whose symbols should be removed

Outputs:

int - Number of symbols removed

Thread Safety:

This method is safe for concurrent use.

func (*SymbolIndex) Search

func (idx *SymbolIndex) Search(ctx context.Context, query string, limit int) ([]*ast.Symbol, error)

Search finds symbols matching the query string.

Description:

Performs fuzzy search across all symbol names. Results are sorted by
relevance: exact matches first, then prefix matches, then substring
matches, then fuzzy matches (Levenshtein distance < 3).

Performance:

O(n) where n is total symbols. For indexes > 50k symbols, consider
using GetByName() for exact matches first. The context is checked
periodically during search to allow cancellation.

Inputs:

ctx - Context for cancellation
query - Search string (case-insensitive)
limit - Maximum number of results to return (0 = no limit)

Outputs:

[]*ast.Symbol - Matching symbols sorted by relevance
error - Non-nil if context was cancelled

Thread Safety:

This method is safe for concurrent use.

func (*SymbolIndex) Stats

func (idx *SymbolIndex) Stats() IndexStats

Stats returns statistics about the index.

Description:

Returns counts using O(1) maintained counters, not map traversal.

Outputs:

IndexStats - Current index statistics

Thread Safety:

This method is safe for concurrent use.

type SymbolIndexOption

type SymbolIndexOption func(*SymbolIndexOptions)

SymbolIndexOption is a functional option for configuring SymbolIndex.

func WithMaxSymbols

func WithMaxSymbols(max int) SymbolIndexOption

WithMaxSymbols sets the maximum number of symbols the index can hold.

type SymbolIndexOptions

type SymbolIndexOptions struct {
	// MaxSymbols is the maximum number of symbols the index can hold.
	// Attempting to add more symbols returns ErrMaxSymbolsExceeded.
	// Default: 1,000,000
	MaxSymbols int
}

SymbolIndexOptions configures SymbolIndex behavior and limits.

func DefaultSymbolIndexOptions

func DefaultSymbolIndexOptions() SymbolIndexOptions

DefaultSymbolIndexOptions returns the default options.

Jump to

Keyboard shortcuts

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