aboutsummaryrefslogtreecommitdiff
path: root/immutable.go
diff options
context:
space:
mode:
Diffstat (limited to 'immutable.go')
-rw-r--r--immutable.go2459
1 files changed, 0 insertions, 2459 deletions
diff --git a/immutable.go b/immutable.go
deleted file mode 100644
index 1642de3..0000000
--- a/immutable.go
+++ /dev/null
@@ -1,2459 +0,0 @@
-// Package immutable provides immutable collection types.
-//
-// # Introduction
-//
-// Immutable collections provide an efficient, safe way to share collections
-// of data while minimizing locks. The collections in this package provide
-// List, Map, and SortedMap implementations. These act similarly to slices
-// and maps, respectively, except that altering a collection returns a new
-// copy of the collection with that change.
-//
-// Because collections are unable to change, they are safe for multiple
-// goroutines to read from at the same time without a mutex. However, these
-// types of collections come with increased CPU & memory usage as compared
-// with Go's built-in collection types so please evaluate for your specific
-// use.
-//
-// # Collection Types
-//
-// The List type provides an API similar to Go slices. They allow appending,
-// prepending, and updating of elements. Elements can also be fetched by index
-// or iterated over using a ListIterator.
-//
-// The Map & SortedMap types provide an API similar to Go maps. They allow
-// values to be assigned to unique keys and allow for the deletion of keys.
-// Values can be fetched by key and key/value pairs can be iterated over using
-// the appropriate iterator type. Both map types provide the same API. The
-// SortedMap, however, provides iteration over sorted keys while the Map
-// provides iteration over unsorted keys. Maps improved performance and memory
-// usage as compared to SortedMaps.
-//
-// # Hashing and Sorting
-//
-// Map types require the use of a Hasher implementation to calculate hashes for
-// their keys and check for key equality. SortedMaps require the use of a
-// Comparer implementation to sort keys in the map.
-//
-// These collection types automatically provide built-in hasher and comparers
-// for int, string, and byte slice keys. If you are using one of these key types
-// then simply pass a nil into the constructor. Otherwise you will need to
-// implement a custom Hasher or Comparer type. Please see the provided
-// implementations for reference.
-package immutable
-
-import (
- "fmt"
- "math/bits"
- "reflect"
- "sort"
- "strings"
-
- "golang.org/x/exp/constraints"
-)
-
-// List is a dense, ordered, indexed collections. They are analogous to slices
-// in Go. They can be updated by appending to the end of the list, prepending
-// values to the beginning of the list, or updating existing indexes in the
-// list.
-type List[T any] struct {
- root listNode[T] // root node
- origin int // offset to zero index element
- size int // total number of elements in use
-}
-
-// NewList returns a new empty instance of List.
-func NewList[T any](values ...T) *List[T] {
- l := &List[T]{
- root: &listLeafNode[T]{},
- }
- for _, value := range values {
- l.append(value, true)
- }
- return l
-}
-
-// clone returns a copy of the list.
-func (l *List[T]) clone() *List[T] {
- other := *l
- return &other
-}
-
-// Len returns the number of elements in the list.
-func (l *List[T]) Len() int {
- return l.size
-}
-
-// cap returns the total number of possible elements for the current depth.
-func (l *List[T]) cap() int {
- return 1 << (l.root.depth() * listNodeBits)
-}
-
-// Get returns the value at the given index. Similar to slices, this method will
-// panic if index is below zero or is greater than or equal to the list size.
-func (l *List[T]) Get(index int) T {
- if index < 0 || index >= l.size {
- panic(fmt.Sprintf("immutable.List.Get: index %d out of bounds", index))
- }
- return l.root.get(l.origin + index)
-}
-
-// Set returns a new list with value set at index. Similar to slices, this
-// method will panic if index is below zero or if the index is greater than
-// or equal to the list size.
-func (l *List[T]) Set(index int, value T) *List[T] {
- return l.set(index, value, false)
-}
-
-func (l *List[T]) set(index int, value T, mutable bool) *List[T] {
- if index < 0 || index >= l.size {
- panic(fmt.Sprintf("immutable.List.Set: index %d out of bounds", index))
- }
- other := l
- if !mutable {
- other = l.clone()
- }
- other.root = other.root.set(l.origin+index, value, mutable)
- return other
-}
-
-// Append returns a new list with value added to the end of the list.
-func (l *List[T]) Append(value T) *List[T] {
- return l.append(value, false)
-}
-
-func (l *List[T]) append(value T, mutable bool) *List[T] {
- other := l
- if !mutable {
- other = l.clone()
- }
-
- // Expand list to the right if no slots remain.
- if other.size+other.origin >= l.cap() {
- newRoot := &listBranchNode[T]{d: other.root.depth() + 1}
- newRoot.children[0] = other.root
- other.root = newRoot
- }
-
- // Increase size and set the last element to the new value.
- other.size++
- other.root = other.root.set(other.origin+other.size-1, value, mutable)
- return other
-}
-
-// Prepend returns a new list with value(s) added to the beginning of the list.
-func (l *List[T]) Prepend(value T) *List[T] {
- return l.prepend(value, false)
-}
-
-func (l *List[T]) prepend(value T, mutable bool) *List[T] {
- other := l
- if !mutable {
- other = l.clone()
- }
-
- // Expand list to the left if no slots remain.
- if other.origin == 0 {
- newRoot := &listBranchNode[T]{d: other.root.depth() + 1}
- newRoot.children[listNodeSize-1] = other.root
- other.root = newRoot
- other.origin += (listNodeSize - 1) << (other.root.depth() * listNodeBits)
- }
-
- // Increase size and move origin back. Update first element to value.
- other.size++
- other.origin--
- other.root = other.root.set(other.origin, value, mutable)
- return other
-}
-
-// Slice returns a new list of elements between start index and end index.
-// Similar to slices, this method will panic if start or end are below zero or
-// greater than the list size. A panic will also occur if start is greater than
-// end.
-//
-// Unlike Go slices, references to inaccessible elements will be automatically
-// removed so they can be garbage collected.
-func (l *List[T]) Slice(start, end int) *List[T] {
- return l.slice(start, end, false)
-}
-
-func (l *List[T]) slice(start, end int, mutable bool) *List[T] {
- // Panics similar to Go slices.
- if start < 0 || start > l.size {
- panic(fmt.Sprintf("immutable.List.Slice: start index %d out of bounds", start))
- } else if end < 0 || end > l.size {
- panic(fmt.Sprintf("immutable.List.Slice: end index %d out of bounds", end))
- } else if start > end {
- panic(fmt.Sprintf("immutable.List.Slice: invalid slice index: [%d:%d]", start, end))
- }
-
- // Return the same list if the start and end are the entire range.
- if start == 0 && end == l.size {
- return l
- }
-
- // Create copy, if immutable.
- other := l
- if !mutable {
- other = l.clone()
- }
-
- // Update origin/size.
- other.origin = l.origin + start
- other.size = end - start
-
- // Contract tree while the start & end are in the same child node.
- for other.root.depth() > 1 {
- i := (other.origin >> (other.root.depth() * listNodeBits)) & listNodeMask
- j := ((other.origin + other.size - 1) >> (other.root.depth() * listNodeBits)) & listNodeMask
- if i != j {
- break // branch contains at least two nodes, exit
- }
-
- // Replace the current root with the single child & update origin offset.
- other.origin -= i << (other.root.depth() * listNodeBits)
- other.root = other.root.(*listBranchNode[T]).children[i]
- }
-
- // Ensure all references are removed before start & after end.
- other.root = other.root.deleteBefore(other.origin, mutable)
- other.root = other.root.deleteAfter(other.origin+other.size-1, mutable)
-
- return other
-}
-
-// Iterator returns a new iterator for this list positioned at the first index.
-func (l *List[T]) Iterator() *ListIterator[T] {
- itr := &ListIterator[T]{list: l}
- itr.First()
- return itr
-}
-
-// ListBuilder represents an efficient builder for creating new Lists.
-type ListBuilder[T any] struct {
- list *List[T] // current state
-}
-
-// NewListBuilder returns a new instance of ListBuilder.
-func NewListBuilder[T any]() *ListBuilder[T] {
- return &ListBuilder[T]{list: NewList[T]()}
-}
-
-// List returns the current copy of the list.
-// The builder should not be used again after the list after this call.
-func (b *ListBuilder[T]) List() *List[T] {
- assert(b.list != nil, "immutable.ListBuilder.List(): duplicate call to fetch list")
- list := b.list
- b.list = nil
- return list
-}
-
-// Len returns the number of elements in the underlying list.
-func (b *ListBuilder[T]) Len() int {
- assert(b.list != nil, "immutable.ListBuilder: builder invalid after List() invocation")
- return b.list.Len()
-}
-
-// Get returns the value at the given index. Similar to slices, this method will
-// panic if index is below zero or is greater than or equal to the list size.
-func (b *ListBuilder[T]) Get(index int) T {
- assert(b.list != nil, "immutable.ListBuilder: builder invalid after List() invocation")
- return b.list.Get(index)
-}
-
-// Set updates the value at the given index. Similar to slices, this method will
-// panic if index is below zero or if the index is greater than or equal to the
-// list size.
-func (b *ListBuilder[T]) Set(index int, value T) {
- assert(b.list != nil, "immutable.ListBuilder: builder invalid after List() invocation")
- b.list = b.list.set(index, value, true)
-}
-
-// Append adds value to the end of the list.
-func (b *ListBuilder[T]) Append(value T) {
- assert(b.list != nil, "immutable.ListBuilder: builder invalid after List() invocation")
- b.list = b.list.append(value, true)
-}
-
-// Prepend adds value to the beginning of the list.
-func (b *ListBuilder[T]) Prepend(value T) {
- assert(b.list != nil, "immutable.ListBuilder: builder invalid after List() invocation")
- b.list = b.list.prepend(value, true)
-}
-
-// Slice updates the list with a sublist of elements between start and end index.
-// See List.Slice() for more details.
-func (b *ListBuilder[T]) Slice(start, end int) {
- assert(b.list != nil, "immutable.ListBuilder: builder invalid after List() invocation")
- b.list = b.list.slice(start, end, true)
-}
-
-// Iterator returns a new iterator for the underlying list.
-func (b *ListBuilder[T]) Iterator() *ListIterator[T] {
- assert(b.list != nil, "immutable.ListBuilder: builder invalid after List() invocation")
- return b.list.Iterator()
-}
-
-// Constants for bit shifts used for levels in the List trie.
-const (
- listNodeBits = 5
- listNodeSize = 1 << listNodeBits
- listNodeMask = listNodeSize - 1
-)
-
-// listNode represents either a branch or leaf node in a List.
-type listNode[T any] interface {
- depth() uint
- get(index int) T
- set(index int, v T, mutable bool) listNode[T]
-
- containsBefore(index int) bool
- containsAfter(index int) bool
-
- deleteBefore(index int, mutable bool) listNode[T]
- deleteAfter(index int, mutable bool) listNode[T]
-}
-
-// newListNode returns a leaf node for depth zero, otherwise returns a branch node.
-func newListNode[T any](depth uint) listNode[T] {
- if depth == 0 {
- return &listLeafNode[T]{}
- }
- return &listBranchNode[T]{d: depth}
-}
-
-// listBranchNode represents a branch of a List tree at a given depth.
-type listBranchNode[T any] struct {
- d uint // depth
- children [listNodeSize]listNode[T]
-}
-
-// depth returns the depth of this branch node from the leaf.
-func (n *listBranchNode[T]) depth() uint { return n.d }
-
-// get returns the child node at the segment of the index for this depth.
-func (n *listBranchNode[T]) get(index int) T {
- idx := (index >> (n.d * listNodeBits)) & listNodeMask
- return n.children[idx].get(index)
-}
-
-// set recursively updates the value at index for each lower depth from the node.
-func (n *listBranchNode[T]) set(index int, v T, mutable bool) listNode[T] {
- idx := (index >> (n.d * listNodeBits)) & listNodeMask
-
- // Find child for the given value in the branch. Create new if it doesn't exist.
- child := n.children[idx]
- if child == nil {
- child = newListNode[T](n.depth() - 1)
- }
-
- // Return a copy of this branch with the new child.
- var other *listBranchNode[T]
- if mutable {
- other = n
- } else {
- tmp := *n
- other = &tmp
- }
- other.children[idx] = child.set(index, v, mutable)
- return other
-}
-
-// containsBefore returns true if non-nil values exists between [0,index).
-func (n *listBranchNode[T]) containsBefore(index int) bool {
- idx := (index >> (n.d * listNodeBits)) & listNodeMask
-
- // Quickly check if any direct children exist before this segment of the index.
- for i := 0; i < idx; i++ {
- if n.children[i] != nil {
- return true
- }
- }
-
- // Recursively check for children directly at the given index at this segment.
- if n.children[idx] != nil && n.children[idx].containsBefore(index) {
- return true
- }
- return false
-}
-
-// containsAfter returns true if non-nil values exists between (index,listNodeSize).
-func (n *listBranchNode[T]) containsAfter(index int) bool {
- idx := (index >> (n.d * listNodeBits)) & listNodeMask
-
- // Quickly check if any direct children exist after this segment of the index.
- for i := idx + 1; i < len(n.children); i++ {
- if n.children[i] != nil {
- return true
- }
- }
-
- // Recursively check for children directly at the given index at this segment.
- if n.children[idx] != nil && n.children[idx].containsAfter(index) {
- return true
- }
- return false
-}
-
-// deleteBefore returns a new node with all elements before index removed.
-func (n *listBranchNode[T]) deleteBefore(index int, mutable bool) listNode[T] {
- // Ignore if no nodes exist before the given index.
- if !n.containsBefore(index) {
- return n
- }
-
- // Return a copy with any nodes prior to the index removed.
- idx := (index >> (n.d * listNodeBits)) & listNodeMask
-
- var other *listBranchNode[T]
- if mutable {
- other = n
- for i := 0; i < idx; i++ {
- n.children[i] = nil
- }
- } else {
- other = &listBranchNode[T]{d: n.d}
- copy(other.children[idx:][:], n.children[idx:][:])
- }
-
- if other.children[idx] != nil {
- other.children[idx] = other.children[idx].deleteBefore(index, mutable)
- }
- return other
-}
-
-// deleteBefore returns a new node with all elements before index removed.
-func (n *listBranchNode[T]) deleteAfter(index int, mutable bool) listNode[T] {
- // Ignore if no nodes exist after the given index.
- if !n.containsAfter(index) {
- return n
- }
-
- // Return a copy with any nodes after the index removed.
- idx := (index >> (n.d * listNodeBits)) & listNodeMask
-
- var other *listBranchNode[T]
- if mutable {
- other = n
- for i := idx + 1; i < len(n.children); i++ {
- n.children[i] = nil
- }
- } else {
- other = &listBranchNode[T]{d: n.d}
- copy(other.children[:idx+1], n.children[:idx+1])
- }
-
- if other.children[idx] != nil {
- other.children[idx] = other.children[idx].deleteAfter(index, mutable)
- }
- return other
-}
-
-// listLeafNode represents a leaf node in a List.
-type listLeafNode[T any] struct {
- children [listNodeSize]T
- // bitset with ones at occupied positions, position 0 is the LSB
- occupied uint32
-}
-
-// depth always returns 0 for leaf nodes.
-func (n *listLeafNode[T]) depth() uint { return 0 }
-
-// get returns the value at the given index.
-func (n *listLeafNode[T]) get(index int) T {
- return n.children[index&listNodeMask]
-}
-
-// set returns a copy of the node with the value at the index updated to v.
-func (n *listLeafNode[T]) set(index int, v T, mutable bool) listNode[T] {
- idx := index & listNodeMask
- var other *listLeafNode[T]
- if mutable {
- other = n
- } else {
- tmp := *n
- other = &tmp
- }
- other.children[idx] = v
- other.occupied |= 1 << idx
- return other
-}
-
-// containsBefore returns true if non-nil values exists between [0,index).
-func (n *listLeafNode[T]) containsBefore(index int) bool {
- idx := index & listNodeMask
- return bits.TrailingZeros32(n.occupied) < idx
-}
-
-// containsAfter returns true if non-nil values exists between (index,listNodeSize).
-func (n *listLeafNode[T]) containsAfter(index int) bool {
- idx := index & listNodeMask
- lastSetPos := 31 - bits.LeadingZeros32(n.occupied)
- return lastSetPos > idx
-}
-
-// deleteBefore returns a new node with all elements before index removed.
-func (n *listLeafNode[T]) deleteBefore(index int, mutable bool) listNode[T] {
- if !n.containsBefore(index) {
- return n
- }
-
- idx := index & listNodeMask
- var other *listLeafNode[T]
- if mutable {
- other = n
- var empty T
- for i := 0; i < idx; i++ {
- other.children[i] = empty
- }
- } else {
- other = &listLeafNode[T]{occupied: n.occupied}
- copy(other.children[idx:][:], n.children[idx:][:])
- }
- // Set the first idx bits to 0.
- other.occupied &= ^((1 << idx) - 1)
- return other
-}
-
-// deleteAfter returns a new node with all elements after index removed.
-func (n *listLeafNode[T]) deleteAfter(index int, mutable bool) listNode[T] {
- if !n.containsAfter(index) {
- return n
- }
-
- idx := index & listNodeMask
- var other *listLeafNode[T]
- if mutable {
- other = n
- var empty T
- for i := idx + 1; i < len(n.children); i++ {
- other.children[i] = empty
- }
- } else {
- other = &listLeafNode[T]{occupied: n.occupied}
- copy(other.children[:idx+1][:], n.children[:idx+1][:])
- }
- // Set bits after idx to 0. idx < 31 because n.containsAfter(index) == true.
- other.occupied &= (1 << (idx + 1)) - 1
- return other
-}
-
-// ListIterator represents an ordered iterator over a list.
-type ListIterator[T any] struct {
- list *List[T] // source list
- index int // current index position
-
- stack [32]listIteratorElem[T] // search stack
- depth int // stack depth
-}
-
-// Done returns true if no more elements remain in the iterator.
-func (itr *ListIterator[T]) Done() bool {
- return itr.index < 0 || itr.index >= itr.list.Len()
-}
-
-// First positions the iterator on the first index.
-// If source list is empty then no change is made.
-func (itr *ListIterator[T]) First() {
- if itr.list.Len() != 0 {
- itr.Seek(0)
- }
-}
-
-// Last positions the iterator on the last index.
-// If source list is empty then no change is made.
-func (itr *ListIterator[T]) Last() {
- if n := itr.list.Len(); n != 0 {
- itr.Seek(n - 1)
- }
-}
-
-// Seek moves the iterator position to the given index in the list.
-// Similar to Go slices, this method will panic if index is below zero or if
-// the index is greater than or equal to the list size.
-func (itr *ListIterator[T]) Seek(index int) {
- // Panic similar to Go slices.
- if index < 0 || index >= itr.list.Len() {
- panic(fmt.Sprintf("immutable.ListIterator.Seek: index %d out of bounds", index))
- }
- itr.index = index
-
- // Reset to the bottom of the stack at seek to the correct position.
- itr.stack[0] = listIteratorElem[T]{node: itr.list.root}
- itr.depth = 0
- itr.seek(index)
-}
-
-// Next returns the current index and its value & moves the iterator forward.
-// Returns an index of -1 if the there are no more elements to return.
-func (itr *ListIterator[T]) Next() (index int, value T) {
- // Exit immediately if there are no elements remaining.
- var empty T
- if itr.Done() {
- return -1, empty
- }
-
- // Retrieve current index & value.
- elem := &itr.stack[itr.depth]
- index, value = itr.index, elem.node.(*listLeafNode[T]).children[elem.index]
-
- // Increase index. If index is at the end then return immediately.
- itr.index++
- if itr.Done() {
- return index, value
- }
-
- // Move up stack until we find a node that has remaining position ahead.
- for ; itr.depth > 0 && itr.stack[itr.depth].index >= listNodeSize-1; itr.depth-- {
- }
-
- // Seek to correct position from current depth.
- itr.seek(itr.index)
-
- return index, value
-}
-
-// Prev returns the current index and value and moves the iterator backward.
-// Returns an index of -1 if the there are no more elements to return.
-func (itr *ListIterator[T]) Prev() (index int, value T) {
- // Exit immediately if there are no elements remaining.
- var empty T
- if itr.Done() {
- return -1, empty
- }
-
- // Retrieve current index & value.
- elem := &itr.stack[itr.depth]
- index, value = itr.index, elem.node.(*listLeafNode[T]).children[elem.index]
-
- // Decrease index. If index is past the beginning then return immediately.
- itr.index--
- if itr.Done() {
- return index, value
- }
-
- // Move up stack until we find a node that has remaining position behind.
- for ; itr.depth > 0 && itr.stack[itr.depth].index == 0; itr.depth-- {
- }
-
- // Seek to correct position from current depth.
- itr.seek(itr.index)
-
- return index, value
-}
-
-// seek positions the stack to the given index from the current depth.
-// Elements and indexes below the current depth are assumed to be correct.
-func (itr *ListIterator[T]) seek(index int) {
- // Iterate over each level until we reach a leaf node.
- for {
- elem := &itr.stack[itr.depth]
- elem.index = ((itr.list.origin + index) >> (elem.node.depth() * listNodeBits)) & listNodeMask
-
- switch node := elem.node.(type) {
- case *listBranchNode[T]:
- child := node.children[elem.index]
- itr.stack[itr.depth+1] = listIteratorElem[T]{node: child}
- itr.depth++
- case *listLeafNode[T]:
- return
- }
- }
-}
-
-// listIteratorElem represents the node and it's child index within the stack.
-type listIteratorElem[T any] struct {
- node listNode[T]
- index int
-}
-
-// Size thresholds for each type of branch node.
-const (
- maxArrayMapSize = 8
- maxBitmapIndexedSize = 16
-)
-
-// Segment bit shifts within the map tree.
-const (
- mapNodeBits = 5
- mapNodeSize = 1 << mapNodeBits
- mapNodeMask = mapNodeSize - 1
-)
-
-// Map represents an immutable hash map implementation. The map uses a Hasher
-// to generate hashes and check for equality of key values.
-//
-// It is implemented as an Hash Array Mapped Trie.
-type Map[K, V any] struct {
- size int // total number of key/value pairs
- root mapNode[K, V] // root node of trie
- hasher Hasher[K] // hasher implementation
-}
-
-// NewMap returns a new instance of Map. If hasher is nil, a default hasher
-// implementation will automatically be chosen based on the first key added.
-// Default hasher implementations only exist for int, string, and byte slice types.
-func NewMap[K, V any](hasher Hasher[K]) *Map[K, V] {
- return &Map[K, V]{
- hasher: hasher,
- }
-}
-
-// NewMapOf returns a new instance of Map, containing a map of provided entries.
-//
-// If hasher is nil, a default hasher implementation will automatically be chosen based on the first key added.
-// Default hasher implementations only exist for int, string, and byte slice types.
-func NewMapOf[K comparable, V any](hasher Hasher[K], entries map[K]V) *Map[K, V] {
- m := &Map[K, V]{
- hasher: hasher,
- }
- for k, v := range entries {
- m.set(k, v, true)
- }
- return m
-}
-
-// Len returns the number of elements in the map.
-func (m *Map[K, V]) Len() int {
- return m.size
-}
-
-// clone returns a shallow copy of m.
-func (m *Map[K, V]) clone() *Map[K, V] {
- other := *m
- return &other
-}
-
-// Get returns the value for a given key and a flag indicating whether the
-// key exists. This flag distinguishes a nil value set on a key versus a
-// non-existent key in the map.
-func (m *Map[K, V]) Get(key K) (value V, ok bool) {
- var empty V
- if m.root == nil {
- return empty, false
- }
- keyHash := m.hasher.Hash(key)
- return m.root.get(key, 0, keyHash, m.hasher)
-}
-
-// Set returns a map with the key set to the new value. A nil value is allowed.
-//
-// This function will return a new map even if the updated value is the same as
-// the existing value because Map does not track value equality.
-func (m *Map[K, V]) Set(key K, value V) *Map[K, V] {
- return m.set(key, value, false)
-}
-
-func (m *Map[K, V]) set(key K, value V, mutable bool) *Map[K, V] {
- // Set a hasher on the first value if one does not already exist.
- hasher := m.hasher
- if hasher == nil {
- hasher = NewHasher(key)
- }
-
- // Generate copy if necessary.
- other := m
- if !mutable {
- other = m.clone()
- }
- other.hasher = hasher
-
- // If the map is empty, initialize with a simple array node.
- if m.root == nil {
- other.size = 1
- other.root = &mapArrayNode[K, V]{entries: []mapEntry[K, V]{{key: key, value: value}}}
- return other
- }
-
- // Otherwise copy the map and delegate insertion to the root.
- // Resized will return true if the key does not currently exist.
- var resized bool
- other.root = m.root.set(key, value, 0, hasher.Hash(key), hasher, mutable, &resized)
- if resized {
- other.size++
- }
- return other
-}
-
-// Delete returns a map with the given key removed.
-// Removing a non-existent key will cause this method to return the same map.
-func (m *Map[K, V]) Delete(key K) *Map[K, V] {
- return m.delete(key, false)
-}
-
-func (m *Map[K, V]) delete(key K, mutable bool) *Map[K, V] {
- // Return original map if no keys exist.
- if m.root == nil {
- return m
- }
-
- // If the delete did not change the node then return the original map.
- var resized bool
- newRoot := m.root.delete(key, 0, m.hasher.Hash(key), m.hasher, mutable, &resized)
- if !resized {
- return m
- }
-
- // Generate copy if necessary.
- other := m
- if !mutable {
- other = m.clone()
- }
-
- // Return copy of map with new root and decreased size.
- other.size = m.size - 1
- other.root = newRoot
- return other
-}
-
-// Iterator returns a new iterator for the map.
-func (m *Map[K, V]) Iterator() *MapIterator[K, V] {
- itr := &MapIterator[K, V]{m: m}
- itr.First()
- return itr
-}
-
-// MapBuilder represents an efficient builder for creating Maps.
-type MapBuilder[K, V any] struct {
- m *Map[K, V] // current state
-}
-
-// NewMapBuilder returns a new instance of MapBuilder.
-func NewMapBuilder[K, V any](hasher Hasher[K]) *MapBuilder[K, V] {
- return &MapBuilder[K, V]{m: NewMap[K, V](hasher)}
-}
-
-// Map returns the underlying map. Only call once.
-// Builder is invalid after call. Will panic on second invocation.
-func (b *MapBuilder[K, V]) Map() *Map[K, V] {
- assert(b.m != nil, "immutable.SortedMapBuilder.Map(): duplicate call to fetch map")
- m := b.m
- b.m = nil
- return m
-}
-
-// Len returns the number of elements in the underlying map.
-func (b *MapBuilder[K, V]) Len() int {
- assert(b.m != nil, "immutable.MapBuilder: builder invalid after Map() invocation")
- return b.m.Len()
-}
-
-// Get returns the value for the given key.
-func (b *MapBuilder[K, V]) Get(key K) (value V, ok bool) {
- assert(b.m != nil, "immutable.MapBuilder: builder invalid after Map() invocation")
- return b.m.Get(key)
-}
-
-// Set sets the value of the given key. See Map.Set() for additional details.
-func (b *MapBuilder[K, V]) Set(key K, value V) {
- assert(b.m != nil, "immutable.MapBuilder: builder invalid after Map() invocation")
- b.m = b.m.set(key, value, true)
-}
-
-// Delete removes the given key. See Map.Delete() for additional details.
-func (b *MapBuilder[K, V]) Delete(key K) {
- assert(b.m != nil, "immutable.MapBuilder: builder invalid after Map() invocation")
- b.m = b.m.delete(key, true)
-}
-
-// Iterator returns a new iterator for the underlying map.
-func (b *MapBuilder[K, V]) Iterator() *MapIterator[K, V] {
- assert(b.m != nil, "immutable.MapBuilder: builder invalid after Map() invocation")
- return b.m.Iterator()
-}
-
-// mapNode represents any node in the map tree.
-type mapNode[K, V any] interface {
- get(key K, shift uint, keyHash uint32, h Hasher[K]) (value V, ok bool)
- set(key K, value V, shift uint, keyHash uint32, h Hasher[K], mutable bool, resized *bool) mapNode[K, V]
- delete(key K, shift uint, keyHash uint32, h Hasher[K], mutable bool, resized *bool) mapNode[K, V]
-}
-
-var _ mapNode[string, any] = (*mapArrayNode[string, any])(nil)
-var _ mapNode[string, any] = (*mapBitmapIndexedNode[string, any])(nil)
-var _ mapNode[string, any] = (*mapHashArrayNode[string, any])(nil)
-var _ mapNode[string, any] = (*mapValueNode[string, any])(nil)
-var _ mapNode[string, any] = (*mapHashCollisionNode[string, any])(nil)
-
-// mapLeafNode represents a node that stores a single key hash at the leaf of the map tree.
-type mapLeafNode[K, V any] interface {
- mapNode[K, V]
- keyHashValue() uint32
-}
-
-var _ mapLeafNode[string, any] = (*mapValueNode[string, any])(nil)
-var _ mapLeafNode[string, any] = (*mapHashCollisionNode[string, any])(nil)
-
-// mapArrayNode is a map node that stores key/value pairs in a slice.
-// Entries are stored in insertion order. An array node expands into a bitmap
-// indexed node once a given threshold size is crossed.
-type mapArrayNode[K, V any] struct {
- entries []mapEntry[K, V]
-}
-
-// indexOf returns the entry index of the given key. Returns -1 if key not found.
-func (n *mapArrayNode[K, V]) indexOf(key K, h Hasher[K]) int {
- for i := range n.entries {
- if h.Equal(n.entries[i].key, key) {
- return i
- }
- }
- return -1
-}
-
-// get returns the value for the given key.
-func (n *mapArrayNode[K, V]) get(key K, shift uint, keyHash uint32, h Hasher[K]) (value V, ok bool) {
- i := n.indexOf(key, h)
- if i == -1 {
- return value, false
- }
- return n.entries[i].value, true
-}
-
-// set inserts or updates the value for a given key. If the key is inserted and
-// the new size crosses the max size threshold, a bitmap indexed node is returned.
-func (n *mapArrayNode[K, V]) set(key K, value V, shift uint, keyHash uint32, h Hasher[K], mutable bool, resized *bool) mapNode[K, V] {
- idx := n.indexOf(key, h)
-
- // Mark as resized if the key doesn't exist.
- if idx == -1 {
- *resized = true
- }
-
- // If we are adding and it crosses the max size threshold, expand the node.
- // We do this by continually setting the entries to a value node and expanding.
- if idx == -1 && len(n.entries) >= maxArrayMapSize {
- var node mapNode[K, V] = newMapValueNode(h.Hash(key), key, value)
- for _, entry := range n.entries {
- node = node.set(entry.key, entry.value, 0, h.Hash(entry.key), h, false, resized)
- }
- return node
- }
-
- // Update in-place if mutable.
- if mutable {
- if idx != -1 {
- n.entries[idx] = mapEntry[K, V]{key, value}
- } else {
- n.entries = append(n.entries, mapEntry[K, V]{key, value})
- }
- return n
- }
-
- // Update existing entry if a match is found.
- // Otherwise append to the end of the element list if it doesn't exist.
- var other mapArrayNode[K, V]
- if idx != -1 {
- other.entries = make([]mapEntry[K, V], len(n.entries))
- copy(other.entries, n.entries)
- other.entries[idx] = mapEntry[K, V]{key, value}
- } else {
- other.entries = make([]mapEntry[K, V], len(n.entries)+1)
- copy(other.entries, n.entries)
- other.entries[len(other.entries)-1] = mapEntry[K, V]{key, value}
- }
- return &other
-}
-
-// delete removes the given key from the node. Returns the same node if key does
-// not exist. Returns a nil node when removing the last entry.
-func (n *mapArrayNode[K, V]) delete(key K, shift uint, keyHash uint32, h Hasher[K], mutable bool, resized *bool) mapNode[K, V] {
- idx := n.indexOf(key, h)
-
- // Return original node if key does not exist.
- if idx == -1 {
- return n
- }
- *resized = true
-
- // Return nil if this node will contain no nodes.
- if len(n.entries) == 1 {
- return nil
- }
-
- // Update in-place, if mutable.
- if mutable {
- copy(n.entries[idx:], n.entries[idx+1:])
- n.entries[len(n.entries)-1] = mapEntry[K, V]{}
- n.entries = n.entries[:len(n.entries)-1]
- return n
- }
-
- // Otherwise create a copy with the given entry removed.
- other := &mapArrayNode[K, V]{entries: make([]mapEntry[K, V], len(n.entries)-1)}
- copy(other.entries[:idx], n.entries[:idx])
- copy(other.entries[idx:], n.entries[idx+1:])
- return other
-}
-
-// mapBitmapIndexedNode represents a map branch node with a variable number of
-// node slots and indexed using a bitmap. Indexes for the node slots are
-// calculated by counting the number of set bits before the target bit using popcount.
-type mapBitmapIndexedNode[K, V any] struct {
- bitmap uint32
- nodes []mapNode[K, V]
-}
-
-// get returns the value for the given key.
-func (n *mapBitmapIndexedNode[K, V]) get(key K, shift uint, keyHash uint32, h Hasher[K]) (value V, ok bool) {
- bit := uint32(1) << ((keyHash >> shift) & mapNodeMask)
- if (n.bitmap & bit) == 0 {
- return value, false
- }
- child := n.nodes[bits.OnesCount32(n.bitmap&(bit-1))]
- return child.get(key, shift+mapNodeBits, keyHash, h)
-}
-
-// set inserts or updates the value for the given key. If a new key is inserted
-// and the size crosses the max size threshold then a hash array node is returned.
-func (n *mapBitmapIndexedNode[K, V]) set(key K, value V, shift uint, keyHash uint32, h Hasher[K], mutable bool, resized *bool) mapNode[K, V] {
- // Extract the index for the bit segment of the key hash.
- keyHashFrag := (keyHash >> shift) & mapNodeMask
-
- // Determine the bit based on the hash index.
- bit := uint32(1) << keyHashFrag
- exists := (n.bitmap & bit) != 0
-
- // Mark as resized if the key doesn't exist.
- if !exists {
- *resized = true
- }
-
- // Find index of node based on popcount of bits before it.
- idx := bits.OnesCount32(n.bitmap & (bit - 1))
-
- // If the node already exists, delegate set operation to it.
- // If the node doesn't exist then create a simple value leaf node.
- var newNode mapNode[K, V]
- if exists {
- newNode = n.nodes[idx].set(key, value, shift+mapNodeBits, keyHash, h, mutable, resized)
- } else {
- newNode = newMapValueNode(keyHash, key, value)
- }
-
- // Convert to a hash-array node once we exceed the max bitmap size.
- // Copy each node based on their bit position within the bitmap.
- if !exists && len(n.nodes) > maxBitmapIndexedSize {
- var other mapHashArrayNode[K, V]
- for i := uint(0); i < uint(len(other.nodes)); i++ {
- if n.bitmap&(uint32(1)<<i) != 0 {
- other.nodes[i] = n.nodes[other.count]
- other.count++
- }
- }
- other.nodes[keyHashFrag] = newNode
- other.count++
- return &other
- }
-
- // Update in-place if mutable.
- if mutable {
- if exists {
- n.nodes[idx] = newNode
- } else {
- n.bitmap |= bit
- n.nodes = append(n.nodes, nil)
- copy(n.nodes[idx+1:], n.nodes[idx:])
- n.nodes[idx] = newNode
- }
- return n
- }
-
- // If node exists at given slot then overwrite it with new node.
- // Otherwise expand the node list and insert new node into appropriate position.
- other := &mapBitmapIndexedNode[K, V]{bitmap: n.bitmap | bit}
- if exists {
- other.nodes = make([]mapNode[K, V], len(n.nodes))
- copy(other.nodes, n.nodes)
- other.nodes[idx] = newNode
- } else {
- other.nodes = make([]mapNode[K, V], len(n.nodes)+1)
- copy(other.nodes, n.nodes[:idx])
- other.nodes[idx] = newNode
- copy(other.nodes[idx+1:], n.nodes[idx:])
- }
- return other
-}
-
-// delete removes the key from the tree. If the key does not exist then the
-// original node is returned. If removing the last child node then a nil is
-// returned. Note that shrinking the node will not convert it to an array node.
-func (n *mapBitmapIndexedNode[K, V]) delete(key K, shift uint, keyHash uint32, h Hasher[K], mutable bool, resized *bool) mapNode[K, V] {
- bit := uint32(1) << ((keyHash >> shift) & mapNodeMask)
-
- // Return original node if key does not exist.
- if (n.bitmap & bit) == 0 {
- return n
- }
-
- // Find index of node based on popcount of bits before it.
- idx := bits.OnesCount32(n.bitmap & (bit - 1))
-
- // Delegate delete to child node.
- child := n.nodes[idx]
- newChild := child.delete(key, shift+mapNodeBits, keyHash, h, mutable, resized)
-
- // Return original node if key doesn't exist in child.
- if !*resized {
- return n
- }
-
- // Remove if returned child has been deleted.
- if newChild == nil {
- // If we won't have any children then return nil.
- if len(n.nodes) == 1 {
- return nil
- }
-
- // Update in-place if mutable.
- if mutable {
- n.bitmap ^= bit
- copy(n.nodes[idx:], n.nodes[idx+1:])
- n.nodes[len(n.nodes)-1] = nil
- n.nodes = n.nodes[:len(n.nodes)-1]
- return n
- }
-
- // Return copy with bit removed from bitmap and node removed from node list.
- other := &mapBitmapIndexedNode[K, V]{bitmap: n.bitmap ^ bit, nodes: make([]mapNode[K, V], len(n.nodes)-1)}
- copy(other.nodes[:idx], n.nodes[:idx])
- copy(other.nodes[idx:], n.nodes[idx+1:])
- return other
- }
-
- // Generate copy, if necessary.
- other := n
- if !mutable {
- other = &mapBitmapIndexedNode[K, V]{bitmap: n.bitmap, nodes: make([]mapNode[K, V], len(n.nodes))}
- copy(other.nodes, n.nodes)
- }
-
- // Update child.
- other.nodes[idx] = newChild
- return other
-}
-
-// mapHashArrayNode is a map branch node that stores nodes in a fixed length
-// array. Child nodes are indexed by their index bit segment for the current depth.
-type mapHashArrayNode[K, V any] struct {
- count uint // number of set nodes
- nodes [mapNodeSize]mapNode[K, V] // child node slots, may contain empties
-}
-
-// clone returns a shallow copy of n.
-func (n *mapHashArrayNode[K, V]) clone() *mapHashArrayNode[K, V] {
- other := *n
- return &other
-}
-
-// get returns the value for the given key.
-func (n *mapHashArrayNode[K, V]) get(key K, shift uint, keyHash uint32, h Hasher[K]) (value V, ok bool) {
- node := n.nodes[(keyHash>>shift)&mapNodeMask]
- if node == nil {
- return value, false
- }
- return node.get(key, shift+mapNodeBits, keyHash, h)
-}
-
-// set returns a node with the value set for the given key.
-func (n *mapHashArrayNode[K, V]) set(key K, value V, shift uint, keyHash uint32, h Hasher[K], mutable bool, resized *bool) mapNode[K, V] {
- idx := (keyHash >> shift) & mapNodeMask
- node := n.nodes[idx]
-
- // If node at index doesn't exist, create a simple value leaf node.
- // Otherwise delegate set to child node.
- var newNode mapNode[K, V]
- if node == nil {
- *resized = true
- newNode = newMapValueNode(keyHash, key, value)
- } else {
- newNode = node.set(key, value, shift+mapNodeBits, keyHash, h, mutable, resized)
- }
-
- // Generate copy, if necessary.
- other := n
- if !mutable {
- other = n.clone()
- }
-
- // Update child node (and update size, if new).
- if node == nil {
- other.count++
- }
- other.nodes[idx] = newNode
- return other
-}
-
-// delete returns a node with the given key removed. Returns the same node if
-// the key does not exist. If node shrinks to within bitmap-indexed size then
-// converts to a bitmap-indexed node.
-func (n *mapHashArrayNode[K, V]) delete(key K, shift uint, keyHash uint32, h Hasher[K], mutable bool, resized *bool) mapNode[K, V] {
- idx := (keyHash >> shift) & mapNodeMask
- node := n.nodes[idx]
-
- // Return original node if child is not found.
- if node == nil {
- return n
- }
-
- // Return original node if child is unchanged.
- newNode := node.delete(key, shift+mapNodeBits, keyHash, h, mutable, resized)
- if !*resized {
- return n
- }
-
- // If we remove a node and drop below a threshold, convert back to bitmap indexed node.
- if newNode == nil && n.count <= maxBitmapIndexedSize {
- other := &mapBitmapIndexedNode[K, V]{nodes: make([]mapNode[K, V], 0, n.count-1)}
- for i, child := range n.nodes {
- if child != nil && uint32(i) != idx {
- other.bitmap |= 1 << uint(i)
- other.nodes = append(other.nodes, child)
- }
- }
- return other
- }
-
- // Generate copy, if necessary.
- other := n
- if !mutable {
- other = n.clone()
- }
-
- // Return copy of node with child updated.
- other.nodes[idx] = newNode
- if newNode == nil {
- other.count--
- }
- return other
-}
-
-// mapValueNode represents a leaf node with a single key/value pair.
-// A value node can be converted to a hash collision leaf node if a different
-// key with the same keyHash is inserted.
-type mapValueNode[K, V any] struct {
- keyHash uint32
- key K
- value V
-}
-
-// newMapValueNode returns a new instance of mapValueNode.
-func newMapValueNode[K, V any](keyHash uint32, key K, value V) *mapValueNode[K, V] {
- return &mapValueNode[K, V]{
- keyHash: keyHash,
- key: key,
- value: value,
- }
-}
-
-// keyHashValue returns the key hash for this node.
-func (n *mapValueNode[K, V]) keyHashValue() uint32 {
- return n.keyHash
-}
-
-// get returns the value for the given key.
-func (n *mapValueNode[K, V]) get(key K, shift uint, keyHash uint32, h Hasher[K]) (value V, ok bool) {
- if !h.Equal(n.key, key) {
- return value, false
- }
- return n.value, true
-}
-
-// set returns a new node with the new value set for the key. If the key equals
-// the node's key then a new value node is returned. If key is not equal to the
-// node's key but has the same hash then a hash collision node is returned.
-// Otherwise the nodes are merged into a branch node.
-func (n *mapValueNode[K, V]) set(key K, value V, shift uint, keyHash uint32, h Hasher[K], mutable bool, resized *bool) mapNode[K, V] {
- // If the keys match then return a new value node overwriting the value.
- if h.Equal(n.key, key) {
- // Update in-place if mutable.
- if mutable {
- n.value = value
- return n
- }
- // Otherwise return a new copy.
- return newMapValueNode(n.keyHash, key, value)
- }
-
- *resized = true
-
- // Recursively merge nodes together if key hashes are different.
- if n.keyHash != keyHash {
- return mergeIntoNode[K, V](n, shift, keyHash, key, value)
- }
-
- // Merge into collision node if hash matches.
- return &mapHashCollisionNode[K, V]{keyHash: keyHash, entries: []mapEntry[K, V]{
- {key: n.key, value: n.value},
- {key: key, value: value},
- }}
-}
-
-// delete returns nil if the key matches the node's key. Otherwise returns the original node.
-func (n *mapValueNode[K, V]) delete(key K, shift uint, keyHash uint32, h Hasher[K], mutable bool, resized *bool) mapNode[K, V] {
- // Return original node if the keys do not match.
- if !h.Equal(n.key, key) {
- return n
- }
-
- // Otherwise remove the node if keys do match.
- *resized = true
- return nil
-}
-
-// mapHashCollisionNode represents a leaf node that contains two or more key/value
-// pairs with the same key hash. Single pairs for a hash are stored as value nodes.
-type mapHashCollisionNode[K, V any] struct {
- keyHash uint32 // key hash for all entries
- entries []mapEntry[K, V]
-}
-
-// keyHashValue returns the key hash for all entries on the node.
-func (n *mapHashCollisionNode[K, V]) keyHashValue() uint32 {
- return n.keyHash
-}
-
-// indexOf returns the index of the entry for the given key.
-// Returns -1 if the key does not exist in the node.
-func (n *mapHashCollisionNode[K, V]) indexOf(key K, h Hasher[K]) int {
- for i := range n.entries {
- if h.Equal(n.entries[i].key, key) {
- return i
- }
- }
- return -1
-}
-
-// get returns the value for the given key.
-func (n *mapHashCollisionNode[K, V]) get(key K, shift uint, keyHash uint32, h Hasher[K]) (value V, ok bool) {
- for i := range n.entries {
- if h.Equal(n.entries[i].key, key) {
- return n.entries[i].value, true
- }
- }
- return value, false
-}
-
-// set returns a copy of the node with key set to the given value.
-func (n *mapHashCollisionNode[K, V]) set(key K, value V, shift uint, keyHash uint32, h Hasher[K], mutable bool, resized *bool) mapNode[K, V] {
- // Merge node with key/value pair if this is not a hash collision.
- if n.keyHash != keyHash {
- *resized = true
- return mergeIntoNode[K, V](n, shift, keyHash, key, value)
- }
-
- // Update in-place if mutable.
- if mutable {
- if idx := n.indexOf(key, h); idx == -1 {
- *resized = true
- n.entries = append(n.entries, mapEntry[K, V]{key, value})
- } else {
- n.entries[idx] = mapEntry[K, V]{key, value}
- }
- return n
- }
-
- // Append to end of node if key doesn't exist & mark resized.
- // Otherwise copy nodes and overwrite at matching key index.
- other := &mapHashCollisionNode[K, V]{keyHash: n.keyHash}
- if idx := n.indexOf(key, h); idx == -1 {
- *resized = true
- other.entries = make([]mapEntry[K, V], len(n.entries)+1)
- copy(other.entries, n.entries)
- other.entries[len(other.entries)-1] = mapEntry[K, V]{key, value}
- } else {
- other.entries = make([]mapEntry[K, V], len(n.entries))
- copy(other.entries, n.entries)
- other.entries[idx] = mapEntry[K, V]{key, value}
- }
- return other
-}
-
-// delete returns a node with the given key deleted. Returns the same node if
-// the key does not exist. If removing the key would shrink the node to a single
-// entry then a value node is returned.
-func (n *mapHashCollisionNode[K, V]) delete(key K, shift uint, keyHash uint32, h Hasher[K], mutable bool, resized *bool) mapNode[K, V] {
- idx := n.indexOf(key, h)
-
- // Return original node if key is not found.
- if idx == -1 {
- return n
- }
-
- // Mark as resized if key exists.
- *resized = true
-
- // Convert to value node if we move to one entry.
- if len(n.entries) == 2 {
- return &mapValueNode[K, V]{
- keyHash: n.keyHash,
- key: n.entries[idx^1].key,
- value: n.entries[idx^1].value,
- }
- }
-
- // Remove entry in-place if mutable.
- if mutable {
- copy(n.entries[idx:], n.entries[idx+1:])
- n.entries[len(n.entries)-1] = mapEntry[K, V]{}
- n.entries = n.entries[:len(n.entries)-1]
- return n
- }
-
- // Return copy without entry if immutable.
- other := &mapHashCollisionNode[K, V]{keyHash: n.keyHash, entries: make([]mapEntry[K, V], len(n.entries)-1)}
- copy(other.entries[:idx], n.entries[:idx])
- copy(other.entries[idx:], n.entries[idx+1:])
- return other
-}
-
-// mergeIntoNode merges a key/value pair into an existing node.
-// Caller must verify that node's keyHash is not equal to keyHash.
-func mergeIntoNode[K, V any](node mapLeafNode[K, V], shift uint, keyHash uint32, key K, value V) mapNode[K, V] {
- idx1 := (node.keyHashValue() >> shift) & mapNodeMask
- idx2 := (keyHash >> shift) & mapNodeMask
-
- // Recursively build branch nodes to combine the node and its key.
- other := &mapBitmapIndexedNode[K, V]{bitmap: (1 << idx1) | (1 << idx2)}
- if idx1 == idx2 {
- other.nodes = []mapNode[K, V]{mergeIntoNode(node, shift+mapNodeBits, keyHash, key, value)}
- } else {
- if newNode := newMapValueNode(keyHash, key, value); idx1 < idx2 {
- other.nodes = []mapNode[K, V]{node, newNode}
- } else {
- other.nodes = []mapNode[K, V]{newNode, node}
- }
- }
- return other
-}
-
-// mapEntry represents a single key/value pair.
-type mapEntry[K, V any] struct {
- key K
- value V
-}
-
-// MapIterator represents an iterator over a map's key/value pairs. Although
-// map keys are not sorted, the iterator's order is deterministic.
-type MapIterator[K, V any] struct {
- m *Map[K, V] // source map
-
- stack [32]mapIteratorElem[K, V] // search stack
- depth int // stack depth
-}
-
-// Done returns true if no more elements remain in the iterator.
-func (itr *MapIterator[K, V]) Done() bool {
- return itr.depth == -1
-}
-
-// First resets the iterator to the first key/value pair.
-func (itr *MapIterator[K, V]) First() {
- // Exit immediately if the map is empty.
- if itr.m.root == nil {
- itr.depth = -1
- return
- }
-
- // Initialize the stack to the left most element.
- itr.stack[0] = mapIteratorElem[K, V]{node: itr.m.root}
- itr.depth = 0
- itr.first()
-}
-
-// Next returns the next key/value pair. Returns a nil key when no elements remain.
-func (itr *MapIterator[K, V]) Next() (key K, value V, ok bool) {
- // Return nil key if iteration is done.
- if itr.Done() {
- return key, value, false
- }
-
- // Retrieve current index & value. Current node is always a leaf.
- elem := &itr.stack[itr.depth]
- switch node := elem.node.(type) {
- case *mapArrayNode[K, V]:
- entry := &node.entries[elem.index]
- key, value = entry.key, entry.value
- case *mapValueNode[K, V]:
- key, value = node.key, node.value
- case *mapHashCollisionNode[K, V]:
- entry := &node.entries[elem.index]
- key, value = entry.key, entry.value
- }
-
- // Move up stack until we find a node that has remaining position ahead
- // and move that element forward by one.
- itr.next()
- return key, value, true
-}
-
-// next moves to the next available key.
-func (itr *MapIterator[K, V]) next() {
- for ; itr.depth >= 0; itr.depth-- {
- elem := &itr.stack[itr.depth]
-
- switch node := elem.node.(type) {
- case *mapArrayNode[K, V]:
- if elem.index < len(node.entries)-1 {
- elem.index++
- return
- }
-
- case *mapBitmapIndexedNode[K, V]:
- if elem.index < len(node.nodes)-1 {
- elem.index++
- itr.stack[itr.depth+1].node = node.nodes[elem.index]
- itr.depth++
- itr.first()
- return
- }
-
- case *mapHashArrayNode[K, V]:
- for i := elem.index + 1; i < len(node.nodes); i++ {
- if node.nodes[i] != nil {
- elem.index = i
- itr.stack[itr.depth+1].node = node.nodes[elem.index]
- itr.depth++
- itr.first()
- return
- }
- }
-
- case *mapValueNode[K, V]:
- continue // always the last value, traverse up
-
- case *mapHashCollisionNode[K, V]:
- if elem.index < len(node.entries)-1 {
- elem.index++
- return
- }
- }
- }
-}
-
-// first positions the stack left most index.
-// Elements and indexes at and below the current depth are assumed to be correct.
-func (itr *MapIterator[K, V]) first() {
- for ; ; itr.depth++ {
- elem := &itr.stack[itr.depth]
-
- switch node := elem.node.(type) {
- case *mapBitmapIndexedNode[K, V]:
- elem.index = 0
- itr.stack[itr.depth+1].node = node.nodes[0]
-
- case *mapHashArrayNode[K, V]:
- for i := 0; i < len(node.nodes); i++ {
- if node.nodes[i] != nil { // find first node
- elem.index = i
- itr.stack[itr.depth+1].node = node.nodes[i]
- break
- }
- }
-
- default: // *mapArrayNode, mapLeafNode
- elem.index = 0
- return
- }
- }
-}
-
-// mapIteratorElem represents a node/index pair in the MapIterator stack.
-type mapIteratorElem[K, V any] struct {
- node mapNode[K, V]
- index int
-}
-
-// Sorted map child node limit size.
-const (
- sortedMapNodeSize = 32
-)
-
-// SortedMap represents a map of key/value pairs sorted by key. The sort order
-// is determined by the Comparer used by the map.
-//
-// This map is implemented as a B+tree.
-type SortedMap[K, V any] struct {
- size int // total number of key/value pairs
- root sortedMapNode[K, V] // root of b+tree
- comparer Comparer[K]
-}
-
-// NewSortedMap returns a new instance of SortedMap. If comparer is nil then
-// a default comparer is set after the first key is inserted. Default comparers
-// exist for int, string, and byte slice keys.
-func NewSortedMap[K, V any](comparer Comparer[K]) *SortedMap[K, V] {
- return &SortedMap[K, V]{
- comparer: comparer,
- }
-}
-
-// NewSortedMapOf returns a new instance of SortedMap, containing a map of provided entries.
-//
-// If comparer is nil then a default comparer is set after the first key is inserted. Default comparers
-// exist for int, string, and byte slice keys.
-func NewSortedMapOf[K comparable, V any](comparer Comparer[K], entries map[K]V) *SortedMap[K, V] {
- m := &SortedMap[K, V]{
- comparer: comparer,
- }
- for k, v := range entries {
- m.set(k, v, true)
- }
- return m
-}
-
-// Len returns the number of elements in the sorted map.
-func (m *SortedMap[K, V]) Len() int {
- return m.size
-}
-
-// Get returns the value for a given key and a flag indicating if the key is set.
-// The flag can be used to distinguish between a nil-set key versus an unset key.
-func (m *SortedMap[K, V]) Get(key K) (V, bool) {
- if m.root == nil {
- var v V
- return v, false
- }
- return m.root.get(key, m.comparer)
-}
-
-// Set returns a copy of the map with the key set to the given value.
-func (m *SortedMap[K, V]) Set(key K, value V) *SortedMap[K, V] {
- return m.set(key, value, false)
-}
-
-func (m *SortedMap[K, V]) set(key K, value V, mutable bool) *SortedMap[K, V] {
- // Set a comparer on the first value if one does not already exist.
- comparer := m.comparer
- if comparer == nil {
- comparer = NewComparer(key)
- }
-
- // Create copy, if necessary.
- other := m
- if !mutable {
- other = m.clone()
- }
- other.comparer = comparer
-
- // If no values are set then initialize with a leaf node.
- if m.root == nil {
- other.size = 1
- other.root = &sortedMapLeafNode[K, V]{entries: []mapEntry[K, V]{{key: key, value: value}}}
- return other
- }
-
- // Otherwise delegate to root node.
- // If a split occurs then grow the tree from the root.
- var resized bool
- newRoot, splitNode := m.root.set(key, value, comparer, mutable, &resized)
- if splitNode != nil {
- newRoot = newSortedMapBranchNode(newRoot, splitNode)
- }
-
- // Update root and size (if resized).
- other.size = m.size
- other.root = newRoot
- if resized {
- other.size++
- }
- return other
-}
-
-// Delete returns a copy of the map with the key removed.
-// Returns the original map if key does not exist.
-func (m *SortedMap[K, V]) Delete(key K) *SortedMap[K, V] {
- return m.delete(key, false)
-}
-
-func (m *SortedMap[K, V]) delete(key K, mutable bool) *SortedMap[K, V] {
- // Return original map if no keys exist.
- if m.root == nil {
- return m
- }
-
- // If the delete did not change the node then return the original map.
- var resized bool
- newRoot := m.root.delete(key, m.comparer, mutable, &resized)
- if !resized {
- return m
- }
-
- // Create copy, if necessary.
- other := m
- if !mutable {
- other = m.clone()
- }
-
- // Update root and size.
- other.size = m.size - 1
- other.root = newRoot
- return other
-}
-
-// clone returns a shallow copy of m.
-func (m *SortedMap[K, V]) clone() *SortedMap[K, V] {
- other := *m
- return &other
-}
-
-// Iterator returns a new iterator for this map positioned at the first key.
-func (m *SortedMap[K, V]) Iterator() *SortedMapIterator[K, V] {
- itr := &SortedMapIterator[K, V]{m: m}
- itr.First()
- return itr
-}
-
-// SortedMapBuilder represents an efficient builder for creating sorted maps.
-type SortedMapBuilder[K, V any] struct {
- m *SortedMap[K, V] // current state
-}
-
-// NewSortedMapBuilder returns a new instance of SortedMapBuilder.
-func NewSortedMapBuilder[K, V any](comparer Comparer[K]) *SortedMapBuilder[K, V] {
- return &SortedMapBuilder[K, V]{m: NewSortedMap[K, V](comparer)}
-}
-
-// SortedMap returns the current copy of the map.
-// The returned map is safe to use even if after the builder continues to be used.
-func (b *SortedMapBuilder[K, V]) Map() *SortedMap[K, V] {
- assert(b.m != nil, "immutable.SortedMapBuilder.Map(): duplicate call to fetch map")
- m := b.m
- b.m = nil
- return m
-}
-
-// Len returns the number of elements in the underlying map.
-func (b *SortedMapBuilder[K, V]) Len() int {
- assert(b.m != nil, "immutable.SortedMapBuilder: builder invalid after Map() invocation")
- return b.m.Len()
-}
-
-// Get returns the value for the given key.
-func (b *SortedMapBuilder[K, V]) Get(key K) (value V, ok bool) {
- assert(b.m != nil, "immutable.SortedMapBuilder: builder invalid after Map() invocation")
- return b.m.Get(key)
-}
-
-// Set sets the value of the given key. See SortedMap.Set() for additional details.
-func (b *SortedMapBuilder[K, V]) Set(key K, value V) {
- assert(b.m != nil, "immutable.SortedMapBuilder: builder invalid after Map() invocation")
- b.m = b.m.set(key, value, true)
-}
-
-// Delete removes the given key. See SortedMap.Delete() for additional details.
-func (b *SortedMapBuilder[K, V]) Delete(key K) {
- assert(b.m != nil, "immutable.SortedMapBuilder: builder invalid after Map() invocation")
- b.m = b.m.delete(key, true)
-}
-
-// Iterator returns a new iterator for the underlying map positioned at the first key.
-func (b *SortedMapBuilder[K, V]) Iterator() *SortedMapIterator[K, V] {
- assert(b.m != nil, "immutable.SortedMapBuilder: builder invalid after Map() invocation")
- return b.m.Iterator()
-}
-
-// sortedMapNode represents a branch or leaf node in the sorted map.
-type sortedMapNode[K, V any] interface {
- minKey() K
- indexOf(key K, c Comparer[K]) int
- get(key K, c Comparer[K]) (value V, ok bool)
- set(key K, value V, c Comparer[K], mutable bool, resized *bool) (sortedMapNode[K, V], sortedMapNode[K, V])
- delete(key K, c Comparer[K], mutable bool, resized *bool) sortedMapNode[K, V]
-}
-
-var _ sortedMapNode[string, any] = (*sortedMapBranchNode[string, any])(nil)
-var _ sortedMapNode[string, any] = (*sortedMapLeafNode[string, any])(nil)
-
-// sortedMapBranchNode represents a branch in the sorted map.
-type sortedMapBranchNode[K, V any] struct {
- elems []sortedMapBranchElem[K, V]
-}
-
-// newSortedMapBranchNode returns a new branch node with the given child nodes.
-func newSortedMapBranchNode[K, V any](children ...sortedMapNode[K, V]) *sortedMapBranchNode[K, V] {
- // Fetch min keys for every child.
- elems := make([]sortedMapBranchElem[K, V], len(children))
- for i, child := range children {
- elems[i] = sortedMapBranchElem[K, V]{
- key: child.minKey(),
- node: child,
- }
- }
-
- return &sortedMapBranchNode[K, V]{elems: elems}
-}
-
-// minKey returns the lowest key stored in this node's tree.
-func (n *sortedMapBranchNode[K, V]) minKey() K {
- return n.elems[0].node.minKey()
-}
-
-// indexOf returns the index of the key within the child nodes.
-func (n *sortedMapBranchNode[K, V]) indexOf(key K, c Comparer[K]) int {
- if idx := sort.Search(len(n.elems), func(i int) bool { return c.Compare(n.elems[i].key, key) == 1 }); idx > 0 {
- return idx - 1
- }
- return 0
-}
-
-// get returns the value for the given key.
-func (n *sortedMapBranchNode[K, V]) get(key K, c Comparer[K]) (value V, ok bool) {
- idx := n.indexOf(key, c)
- return n.elems[idx].node.get(key, c)
-}
-
-// set returns a copy of the node with the key set to the given value.
-func (n *sortedMapBranchNode[K, V]) set(key K, value V, c Comparer[K], mutable bool, resized *bool) (sortedMapNode[K, V], sortedMapNode[K, V]) {
- idx := n.indexOf(key, c)
-
- // Delegate insert to child node.
- newNode, splitNode := n.elems[idx].node.set(key, value, c, mutable, resized)
-
- // Update in-place, if mutable.
- if mutable {
- n.elems[idx] = sortedMapBranchElem[K, V]{key: newNode.minKey(), node: newNode}
- if splitNode != nil {
- n.elems = append(n.elems, sortedMapBranchElem[K, V]{})
- copy(n.elems[idx+1:], n.elems[idx:])
- n.elems[idx+1] = sortedMapBranchElem[K, V]{key: splitNode.minKey(), node: splitNode}
- }
-
- // If the child splits and we have no more room then we split too.
- if len(n.elems) > sortedMapNodeSize {
- splitIdx := len(n.elems) / 2
- newNode := &sortedMapBranchNode[K, V]{elems: n.elems[:splitIdx:splitIdx]}
- splitNode := &sortedMapBranchNode[K, V]{elems: n.elems[splitIdx:]}
- return newNode, splitNode
- }
- return n, nil
- }
-
- // If no split occurs, copy branch and update keys.
- // If the child splits, insert new key/child into copy of branch.
- var other sortedMapBranchNode[K, V]
- if splitNode == nil {
- other.elems = make([]sortedMapBranchElem[K, V], len(n.elems))
- copy(other.elems, n.elems)
- other.elems[idx] = sortedMapBranchElem[K, V]{
- key: newNode.minKey(),
- node: newNode,
- }
- } else {
- other.elems = make([]sortedMapBranchElem[K, V], len(n.elems)+1)
- copy(other.elems[:idx], n.elems[:idx])
- copy(other.elems[idx+1:], n.elems[idx:])
- other.elems[idx] = sortedMapBranchElem[K, V]{
- key: newNode.minKey(),
- node: newNode,
- }
- other.elems[idx+1] = sortedMapBranchElem[K, V]{
- key: splitNode.minKey(),
- node: splitNode,
- }
- }
-
- // If the child splits and we have no more room then we split too.
- if len(other.elems) > sortedMapNodeSize {
- splitIdx := len(other.elems) / 2
- newNode := &sortedMapBranchNode[K, V]{elems: other.elems[:splitIdx:splitIdx]}
- splitNode := &sortedMapBranchNode[K, V]{elems: other.elems[splitIdx:]}
- return newNode, splitNode
- }
-
- // Otherwise return the new branch node with the updated entry.
- return &other, nil
-}
-
-// delete returns a node with the key removed. Returns the same node if the key
-// does not exist. Returns nil if all child nodes are removed.
-func (n *sortedMapBranchNode[K, V]) delete(key K, c Comparer[K], mutable bool, resized *bool) sortedMapNode[K, V] {
- idx := n.indexOf(key, c)
-
- // Return original node if child has not changed.
- newNode := n.elems[idx].node.delete(key, c, mutable, resized)
- if !*resized {
- return n
- }
-
- // Remove child if it is now nil.
- if newNode == nil {
- // If this node will become empty then simply return nil.
- if len(n.elems) == 1 {
- return nil
- }
-
- // If mutable, update in-place.
- if mutable {
- copy(n.elems[idx:], n.elems[idx+1:])
- n.elems[len(n.elems)-1] = sortedMapBranchElem[K, V]{}
- n.elems = n.elems[:len(n.elems)-1]
- return n
- }
-
- // Return a copy without the given node.
- other := &sortedMapBranchNode[K, V]{elems: make([]sortedMapBranchElem[K, V], len(n.elems)-1)}
- copy(other.elems[:idx], n.elems[:idx])
- copy(other.elems[idx:], n.elems[idx+1:])
- return other
- }
-
- // If mutable, update in-place.
- if mutable {
- n.elems[idx] = sortedMapBranchElem[K, V]{key: newNode.minKey(), node: newNode}
- return n
- }
-
- // Return a copy with the updated node.
- other := &sortedMapBranchNode[K, V]{elems: make([]sortedMapBranchElem[K, V], len(n.elems))}
- copy(other.elems, n.elems)
- other.elems[idx] = sortedMapBranchElem[K, V]{
- key: newNode.minKey(),
- node: newNode,
- }
- return other
-}
-
-type sortedMapBranchElem[K, V any] struct {
- key K
- node sortedMapNode[K, V]
-}
-
-// sortedMapLeafNode represents a leaf node in the sorted map.
-type sortedMapLeafNode[K, V any] struct {
- entries []mapEntry[K, V]
-}
-
-// minKey returns the first key stored in this node.
-func (n *sortedMapLeafNode[K, V]) minKey() K {
- return n.entries[0].key
-}
-
-// indexOf returns the index of the given key.
-func (n *sortedMapLeafNode[K, V]) indexOf(key K, c Comparer[K]) int {
- return sort.Search(len(n.entries), func(i int) bool {
- return c.Compare(n.entries[i].key, key) != -1 // GTE
- })
-}
-
-// get returns the value of the given key.
-func (n *sortedMapLeafNode[K, V]) get(key K, c Comparer[K]) (value V, ok bool) {
- idx := n.indexOf(key, c)
-
- // If the index is beyond the entry count or the key is not equal then return 'not found'.
- if idx == len(n.entries) || c.Compare(n.entries[idx].key, key) != 0 {
- return value, false
- }
-
- // If the key matches then return its value.
- return n.entries[idx].value, true
-}
-
-// set returns a copy of node with the key set to the given value. If the update
-// causes the node to grow beyond the maximum size then it is split in two.
-func (n *sortedMapLeafNode[K, V]) set(key K, value V, c Comparer[K], mutable bool, resized *bool) (sortedMapNode[K, V], sortedMapNode[K, V]) {
- // Find the insertion index for the key.
- idx := n.indexOf(key, c)
- exists := idx < len(n.entries) && c.Compare(n.entries[idx].key, key) == 0
-
- // Update in-place, if mutable.
- if mutable {
- if !exists {
- *resized = true
- n.entries = append(n.entries, mapEntry[K, V]{})
- copy(n.entries[idx+1:], n.entries[idx:])
- }
- n.entries[idx] = mapEntry[K, V]{key: key, value: value}
-
- // If the key doesn't exist and we exceed our max allowed values then split.
- if len(n.entries) > sortedMapNodeSize {
- splitIdx := len(n.entries) / 2
- newNode := &sortedMapLeafNode[K, V]{entries: n.entries[:splitIdx:splitIdx]}
- splitNode := &sortedMapLeafNode[K, V]{entries: n.entries[splitIdx:]}
- return newNode, splitNode
- }
- return n, nil
- }
-
- // If the key matches then simply return a copy with the entry overridden.
- // If there is no match then insert new entry and mark as resized.
- var newEntries []mapEntry[K, V]
- if exists {
- newEntries = make([]mapEntry[K, V], len(n.entries))
- copy(newEntries, n.entries)
- newEntries[idx] = mapEntry[K, V]{key: key, value: value}
- } else {
- *resized = true
- newEntries = make([]mapEntry[K, V], len(n.entries)+1)
- copy(newEntries[:idx], n.entries[:idx])
- newEntries[idx] = mapEntry[K, V]{key: key, value: value}
- copy(newEntries[idx+1:], n.entries[idx:])
- }
-
- // If the key doesn't exist and we exceed our max allowed values then split.
- if len(newEntries) > sortedMapNodeSize {
- splitIdx := len(newEntries) / 2
- newNode := &sortedMapLeafNode[K, V]{entries: newEntries[:splitIdx:splitIdx]}
- splitNode := &sortedMapLeafNode[K, V]{entries: newEntries[splitIdx:]}
- return newNode, splitNode
- }
-
- // Otherwise return the new leaf node with the updated entry.
- return &sortedMapLeafNode[K, V]{entries: newEntries}, nil
-}
-
-// delete returns a copy of node with key removed. Returns the original node if
-// the key does not exist. Returns nil if the removed key is the last remaining key.
-func (n *sortedMapLeafNode[K, V]) delete(key K, c Comparer[K], mutable bool, resized *bool) sortedMapNode[K, V] {
- idx := n.indexOf(key, c)
-
- // Return original node if key is not found.
- if idx >= len(n.entries) || c.Compare(n.entries[idx].key, key) != 0 {
- return n
- }
- *resized = true
-
- // If this is the last entry then return nil.
- if len(n.entries) == 1 {
- return nil
- }
-
- // Update in-place, if mutable.
- if mutable {
- copy(n.entries[idx:], n.entries[idx+1:])
- n.entries[len(n.entries)-1] = mapEntry[K, V]{}
- n.entries = n.entries[:len(n.entries)-1]
- return n
- }
-
- // Return copy of node with entry removed.
- other := &sortedMapLeafNode[K, V]{entries: make([]mapEntry[K, V], len(n.entries)-1)}
- copy(other.entries[:idx], n.entries[:idx])
- copy(other.entries[idx:], n.entries[idx+1:])
- return other
-}
-
-// SortedMapIterator represents an iterator over a sorted map.
-// Iteration can occur in natural or reverse order based on use of Next() or Prev().
-type SortedMapIterator[K, V any] struct {
- m *SortedMap[K, V] // source map
-
- stack [32]sortedMapIteratorElem[K, V] // search stack
- depth int // stack depth
-}
-
-// Done returns true if no more key/value pairs remain in the iterator.
-func (itr *SortedMapIterator[K, V]) Done() bool {
- return itr.depth == -1
-}
-
-// First moves the iterator to the first key/value pair.
-func (itr *SortedMapIterator[K, V]) First() {
- if itr.m.root == nil {
- itr.depth = -1
- return
- }
- itr.stack[0] = sortedMapIteratorElem[K, V]{node: itr.m.root}
- itr.depth = 0
- itr.first()
-}
-
-// Last moves the iterator to the last key/value pair.
-func (itr *SortedMapIterator[K, V]) Last() {
- if itr.m.root == nil {
- itr.depth = -1
- return
- }
- itr.stack[0] = sortedMapIteratorElem[K, V]{node: itr.m.root}
- itr.depth = 0
- itr.last()
-}
-
-// Seek moves the iterator position to the given key in the map.
-// If the key does not exist then the next key is used. If no more keys exist
-// then the iteartor is marked as done.
-func (itr *SortedMapIterator[K, V]) Seek(key K) {
- if itr.m.root == nil {
- itr.depth = -1
- return
- }
- itr.stack[0] = sortedMapIteratorElem[K, V]{node: itr.m.root}
- itr.depth = 0
- itr.seek(key)
-}
-
-// Next returns the current key/value pair and moves the iterator forward.
-// Returns a nil key if the there are no more elements to return.
-func (itr *SortedMapIterator[K, V]) Next() (key K, value V, ok bool) {
- // Return nil key if iteration is complete.
- if itr.Done() {
- return key, value, false
- }
-
- // Retrieve current key/value pair.
- leafElem := &itr.stack[itr.depth]
- leafNode := leafElem.node.(*sortedMapLeafNode[K, V])
- leafEntry := &leafNode.entries[leafElem.index]
- key, value = leafEntry.key, leafEntry.value
-
- // Move to the next available key/value pair.
- itr.next()
-
- // Only occurs when iterator is done.
- return key, value, true
-}
-
-// next moves to the next key. If no keys are after then depth is set to -1.
-func (itr *SortedMapIterator[K, V]) next() {
- for ; itr.depth >= 0; itr.depth-- {
- elem := &itr.stack[itr.depth]
-
- switch node := elem.node.(type) {
- case *sortedMapLeafNode[K, V]:
- if elem.index < len(node.entries)-1 {
- elem.index++
- return
- }
- case *sortedMapBranchNode[K, V]:
- if elem.index < len(node.elems)-1 {
- elem.index++
- itr.stack[itr.depth+1].node = node.elems[elem.index].node
- itr.depth++
- itr.first()
- return
- }
- }
- }
-}
-
-// Prev returns the current key/value pair and moves the iterator backward.
-// Returns a nil key if the there are no more elements to return.
-func (itr *SortedMapIterator[K, V]) Prev() (key K, value V, ok bool) {
- // Return nil key if iteration is complete.
- if itr.Done() {
- return key, value, false
- }
-
- // Retrieve current key/value pair.
- leafElem := &itr.stack[itr.depth]
- leafNode := leafElem.node.(*sortedMapLeafNode[K, V])
- leafEntry := &leafNode.entries[leafElem.index]
- key, value = leafEntry.key, leafEntry.value
-
- itr.prev()
- return key, value, true
-}
-
-// prev moves to the previous key. If no keys are before then depth is set to -1.
-func (itr *SortedMapIterator[K, V]) prev() {
- for ; itr.depth >= 0; itr.depth-- {
- elem := &itr.stack[itr.depth]
-
- switch node := elem.node.(type) {
- case *sortedMapLeafNode[K, V]:
- if elem.index > 0 {
- elem.index--
- return
- }
- case *sortedMapBranchNode[K, V]:
- if elem.index > 0 {
- elem.index--
- itr.stack[itr.depth+1].node = node.elems[elem.index].node
- itr.depth++
- itr.last()
- return
- }
- }
- }
-}
-
-// first positions the stack to the leftmost key from the current depth.
-// Elements and indexes below the current depth are assumed to be correct.
-func (itr *SortedMapIterator[K, V]) first() {
- for {
- elem := &itr.stack[itr.depth]
- elem.index = 0
-
- switch node := elem.node.(type) {
- case *sortedMapBranchNode[K, V]:
- itr.stack[itr.depth+1] = sortedMapIteratorElem[K, V]{node: node.elems[elem.index].node}
- itr.depth++
- case *sortedMapLeafNode[K, V]:
- return
- }
- }
-}
-
-// last positions the stack to the rightmost key from the current depth.
-// Elements and indexes below the current depth are assumed to be correct.
-func (itr *SortedMapIterator[K, V]) last() {
- for {
- elem := &itr.stack[itr.depth]
-
- switch node := elem.node.(type) {
- case *sortedMapBranchNode[K, V]:
- elem.index = len(node.elems) - 1
- itr.stack[itr.depth+1] = sortedMapIteratorElem[K, V]{node: node.elems[elem.index].node}
- itr.depth++
- case *sortedMapLeafNode[K, V]:
- elem.index = len(node.entries) - 1
- return
- }
- }
-}
-
-// seek positions the stack to the given key from the current depth.
-// Elements and indexes below the current depth are assumed to be correct.
-func (itr *SortedMapIterator[K, V]) seek(key K) {
- for {
- elem := &itr.stack[itr.depth]
- elem.index = elem.node.indexOf(key, itr.m.comparer)
-
- switch node := elem.node.(type) {
- case *sortedMapBranchNode[K, V]:
- itr.stack[itr.depth+1] = sortedMapIteratorElem[K, V]{node: node.elems[elem.index].node}
- itr.depth++
- case *sortedMapLeafNode[K, V]:
- if elem.index == len(node.entries) {
- itr.next()
- }
- return
- }
- }
-}
-
-// sortedMapIteratorElem represents node/index pair in the SortedMapIterator stack.
-type sortedMapIteratorElem[K, V any] struct {
- node sortedMapNode[K, V]
- index int
-}
-
-// Hasher hashes keys and checks them for equality.
-type Hasher[K any] interface {
- // Computes a hash for key.
- Hash(key K) uint32
-
- // Returns true if a and b are equal.
- Equal(a, b K) bool
-}
-
-// NewHasher returns the built-in hasher for a given key type.
-func NewHasher[K any](key K) Hasher[K] {
- // Attempt to use non-reflection based hasher first.
- switch (any(key)).(type) {
- case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr, string:
- return &defaultHasher[K]{}
- }
-
- // Fallback to reflection-based hasher otherwise.
- // This is used when caller wraps a type around a primitive type.
- switch reflect.TypeOf(key).Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.String:
- return &reflectHasher[K]{}
- }
-
- // If no hashers match then panic.
- // This is a compile time issue so it should not return an error.
- panic(fmt.Sprintf("immutable.NewHasher: must set hasher for %T type", key))
-}
-
-// Hash returns a hash for value.
-func hashString(value string) uint32 {
- var hash uint32
- for i, value := 0, value; i < len(value); i++ {
- hash = 31*hash + uint32(value[i])
- }
- return hash
-}
-
-// reflectIntHasher implements a reflection-based Hasher for keys.
-type reflectHasher[K any] struct{}
-
-// Hash returns a hash for key.
-func (h *reflectHasher[K]) Hash(key K) uint32 {
- switch reflect.TypeOf(key).Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return hashUint64(uint64(reflect.ValueOf(key).Int()))
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- return hashUint64(reflect.ValueOf(key).Uint())
- case reflect.String:
- var hash uint32
- s := reflect.ValueOf(key).String()
- for i := 0; i < len(s); i++ {
- hash = 31*hash + uint32(s[i])
- }
- return hash
- }
- panic(fmt.Sprintf("immutable.reflectHasher.Hash: reflectHasher does not support %T type", key))
-}
-
-// Equal returns true if a is equal to b. Otherwise returns false.
-// Panics if a and b are not int-ish or string-ish.
-func (h *reflectHasher[K]) Equal(a, b K) bool {
- switch reflect.TypeOf(a).Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- return reflect.ValueOf(a).Int() == reflect.ValueOf(b).Int()
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- return reflect.ValueOf(a).Uint() == reflect.ValueOf(b).Uint()
- case reflect.String:
- return reflect.ValueOf(a).String() == reflect.ValueOf(b).String()
- }
- panic(fmt.Sprintf("immutable.reflectHasher.Equal: reflectHasher does not support %T type", a))
-
-}
-
-// hashUint64 returns a 32-bit hash for a 64-bit value.
-func hashUint64(value uint64) uint32 {
- hash := value
- for value > 0xffffffff {
- value /= 0xffffffff
- hash ^= value
- }
- return uint32(hash)
-}
-
-// defaultHasher implements Hasher.
-type defaultHasher[K any] struct{}
-
-// Hash returns a hash for key.
-func (h *defaultHasher[K]) Hash(key K) uint32 {
- switch x := (any(key)).(type) {
- case int:
- return hashUint64(uint64(x))
- case int8:
- return hashUint64(uint64(x))
- case int16:
- return hashUint64(uint64(x))
- case int32:
- return hashUint64(uint64(x))
- case int64:
- return hashUint64(uint64(x))
- case uint:
- return hashUint64(uint64(x))
- case uint8:
- return hashUint64(uint64(x))
- case uint16:
- return hashUint64(uint64(x))
- case uint32:
- return hashUint64(uint64(x))
- case uint64:
- return hashUint64(uint64(x))
- case uintptr:
- return hashUint64(uint64(x))
- case string:
- return hashString(x)
- }
- panic(fmt.Sprintf("immutable.defaultHasher.Hash: must set comparer for %T type", key))
-}
-
-// Equal returns true if a is equal to b. Otherwise returns false.
-// Panics if a and b are not comparable.
-func (h *defaultHasher[K]) Equal(a, b K) bool {
- return any(a) == any(b)
-}
-
-// Comparer allows the comparison of two keys for the purpose of sorting.
-type Comparer[K any] interface {
- // Returns -1 if a is less than b, returns 1 if a is greater than b,
- // and returns 0 if a is equal to b.
- Compare(a, b K) int
-}
-
-// NewComparer returns the built-in comparer for a given key type.
-// Note that only int-ish and string-ish types are supported, despite the 'comparable' constraint.
-// Attempts to use other types will result in a panic - users should define their own Comparers for these cases.
-func NewComparer[K any](key K) Comparer[K] {
- // Attempt to use non-reflection based comparer first.
- switch (any(key)).(type) {
- case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr, string:
- return &defaultComparer[K]{}
- }
- // Fallback to reflection-based comparer otherwise.
- // This is used when caller wraps a type around a primitive type.
- switch reflect.TypeOf(key).Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.String:
- return &reflectComparer[K]{}
- }
- // If no comparers match then panic.
- // This is a compile time issue so it should not return an error.
- panic(fmt.Sprintf("immutable.NewComparer: must set comparer for %T type", key))
-}
-
-// defaultComparer compares two values (int-ish and string-ish types are supported). Implements Comparer.
-type defaultComparer[K any] struct{}
-
-// Compare returns -1 if a is less than b, returns 1 if a is greater than b, and
-// returns 0 if a is equal to b. Panic if a or b is not a string or int* type
-func (c *defaultComparer[K]) Compare(i K, j K) int {
- switch x := (any(i)).(type) {
- case int:
- return defaultCompare(x, (any(j)).(int))
- case int8:
- return defaultCompare(x, (any(j)).(int8))
- case int16:
- return defaultCompare(x, (any(j)).(int16))
- case int32:
- return defaultCompare(x, (any(j)).(int32))
- case int64:
- return defaultCompare(x, (any(j)).(int64))
- case uint:
- return defaultCompare(x, (any(j)).(uint))
- case uint8:
- return defaultCompare(x, (any(j)).(uint8))
- case uint16:
- return defaultCompare(x, (any(j)).(uint16))
- case uint32:
- return defaultCompare(x, (any(j)).(uint32))
- case uint64:
- return defaultCompare(x, (any(j)).(uint64))
- case uintptr:
- return defaultCompare(x, (any(j)).(uintptr))
- case string:
- return defaultCompare(x, (any(j)).(string))
- }
- panic(fmt.Sprintf("immutable.defaultComparer: must set comparer for %T type", i))
-}
-
-// defaultCompare only operates on constraints.Ordered.
-// For other types, users should bring their own comparers
-func defaultCompare[K constraints.Ordered](i, j K) int {
- if i < j {
- return -1
- } else if i > j {
- return 1
- }
- return 0
-}
-
-// reflectIntComparer compares two values using reflection. Implements Comparer.
-type reflectComparer[K any] struct{}
-
-// Compare returns -1 if a is less than b, returns 1 if a is greater than b, and
-// returns 0 if a is equal to b. Panic if a or b is not an int-ish or string-ish type.
-func (c *reflectComparer[K]) Compare(a, b K) int {
- switch reflect.TypeOf(a).Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- if i, j := reflect.ValueOf(a).Int(), reflect.ValueOf(b).Int(); i < j {
- return -1
- } else if i > j {
- return 1
- }
- return 0
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- if i, j := reflect.ValueOf(a).Uint(), reflect.ValueOf(b).Uint(); i < j {
- return -1
- } else if i > j {
- return 1
- }
- return 0
- case reflect.String:
- return strings.Compare(reflect.ValueOf(a).String(), reflect.ValueOf(b).String())
- }
- panic(fmt.Sprintf("immutable.reflectComparer.Compare: must set comparer for %T type", a))
-}
-
-func assert(condition bool, message string) {
- if !condition {
- panic(message)
- }
-}