Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

tree.gno

6.77 Kb · 196 lines
  1package staker
  2
  3import (
  4	"gno.land/p/gnoswap/gnsmath/v1"
  5	"gno.land/p/gnoswap/utils/v1"
  6	rotree "gno.land/p/nt/bptree/rotree/v0"
  7	bptree "gno.land/p/nt/bptree/v0"
  8	ufmt "gno.land/p/nt/ufmt/v0"
  9)
 10
 11// UintTree wraps a B+ tree with nonnegative int64 timestamp keys, encoded as
 12// fixed-width 8-byte big-endian strings to preserve numeric ordering.
 13//
 14// Methods:
 15// - Get: Retrieves a value associated with an int64 key.
 16// - Set: Stores a value with an int64 key.
 17// - Has: Checks if an int64 key exists in the tree.
 18// - Remove: Removes an int64 key and its associated value.
 19// - Iterate: Iterates over keys and values in a range.
 20// - ReverseIterate: Iterates in reverse order over keys and values in a range.
 21type UintTree struct {
 22	tree   *bptree.BPTree // blockTimestamp -> any
 23	fanout int
 24}
 25
 26// NewBPTreeN allocates a raw BP-tree under /r/gnoswap/staker's realm
 27// context (the realm that declares Pool/Deposit/ExternalIncentive). The tree's
 28// PkgID is therefore /r/gnoswap/staker, matching the domain values it stores,
 29// so tree.Set leaf-slot writes clear the readonly-taint gate regardless of
 30// which realm (staker/v1, mock) calls Set (borrow rule #2 borrows m.Realm to
 31// the tree's owning realm). Implementations and mocks must allocate trees that
 32// hold /r/gnoswap/staker-declared values through here rather than calling
 33// bptree.NewBPTreeN directly in their own realm.
 34//
 35// Parameters:
 36//   - fanout: Number of child pointers per B+ tree node; controls the tree's branching factor.
 37//
 38// Returns:
 39//   - tree: Mutable raw B+ tree allocated in the staker realm context.
 40func NewBPTreeN(fanout int) *bptree.BPTree {
 41	return bptree.NewBPTreeN(fanout)
 42}
 43
 44// NewUintTree creates a new UintTree instance with default fanout 64.
 45//
 46// Returns:
 47//   - tree: Empty UintTree using the default fanout of 64.
 48func NewUintTree() *UintTree {
 49	return NewUintTreeN(64)
 50}
 51
 52// NewUintTreeN creates a new UintTree instance with the specified fanout.
 53//
 54// Parameters:
 55//   - fanout: Number of child pointers per B+ tree node used by the wrapped tree.
 56//
 57// Returns:
 58//   - tree: Empty UintTree configured with the requested fanout.
 59func NewUintTreeN(fanout int) *UintTree {
 60	return &UintTree{
 61		tree:   bptree.NewBPTreeN(fanout),
 62		fanout: fanout,
 63	}
 64}
 65
 66// Get looks up a value by its nonnegative int64 key.
 67//
 68// Parameters:
 69//   - key: Nonnegative timestamp-like key encoded into the tree's ordered key format.
 70//
 71// Returns:
 72//   - value: Stored value when the key maps to a non-nil entry; nil when absent.
 73//   - found: True when a non-nil value exists for key, and false otherwise.
 74func (self *UintTree) Get(key int64) (any, bool) {
 75	v := self.tree.Get(encodeInt64(key))
 76	if v == nil {
 77		return nil, false
 78	}
 79	return v, true
 80}
 81
 82// Set stores a value under a nonnegative int64 key.
 83//
 84// Parameters:
 85//   - key: Nonnegative timestamp-like key used as the ordered tree key; negative values panic.
 86//   - value: Value to associate with key.
 87func (self *UintTree) Set(key int64, value any) {
 88	self.tree.Set(encodeInt64(key), value)
 89}
 90
 91// Has reports whether an encoded key is present in the underlying tree.
 92//
 93// Parameters:
 94//   - key: Nonnegative timestamp-like key to test; negative values panic during encoding.
 95//
 96// Returns:
 97//   - present: True when the underlying tree contains key, including entries whose value may be nil according to the B+ tree.
 98func (self *UintTree) Has(key int64) bool {
 99	return self.tree.Has(encodeInt64(key))
100}
101
102// Remove deletes the value stored under a key, if any.
103//
104// Parameters:
105//   - key: Nonnegative timestamp-like key to remove; negative values panic during encoding.
106func (self *UintTree) Remove(key int64) {
107	self.tree.Remove(encodeInt64(key))
108}
109
110// Iterate visits entries in ascending key order over the underlying tree range.
111//
112// Parameters:
113//   - start: Nonnegative lower bound for the encoded key range.
114//   - end: Nonnegative upper bound for the encoded key range.
115//   - fn: Callback receiving each decoded key and value; returning true requests that iteration stop.
116func (self *UintTree) Iterate(start, end int64, fn func(key int64, value any) bool) {
117	self.tree.Iterate(encodeInt64(start), encodeInt64(end), func(key string, value any) bool {
118		return fn(decodeInt64(key), value)
119	})
120}
121
122// ReverseIterate visits entries in descending key order over the underlying tree range.
123//
124// Parameters:
125//   - start: Nonnegative lower bound for the encoded key range.
126//   - end: Nonnegative upper bound for the encoded key range.
127//   - fn: Callback receiving each decoded key and value; returning true requests that iteration stop.
128func (self *UintTree) ReverseIterate(start, end int64, fn func(key int64, value any) bool) {
129	self.tree.ReverseIterate(encodeInt64(start), encodeInt64(end), func(key string, value any) bool {
130		return fn(decodeInt64(key), value)
131	})
132}
133
134// Size returns the number of entries currently stored in the tree.
135//
136// Returns:
137//   - size: Number of key/value entries in the underlying B+ tree.
138func (self *UintTree) Size() int {
139	return self.tree.Size()
140}
141
142// IterateByOffset visits a page of entries beginning at an offset.
143//
144// Parameters:
145//   - offset: Zero-based number of entries to skip before invoking fn.
146//   - count: Maximum number of entries to visit.
147//   - fn: Callback receiving each decoded key and value; returning true requests that iteration stop.
148func (self *UintTree) IterateByOffset(offset, count int, fn func(key int64, value any) bool) {
149	self.tree.IterateByOffset(offset, count, func(key string, value any) bool {
150		return fn(decodeInt64(key), value)
151	})
152}
153
154// ReadOnly returns a read-only view of the underlying tree, so callers can
155// paginate it without gaining a handle on the mutable tree.
156//
157// Keys use utils.EncodeUint64's fixed-width binary encoding, not the int64
158// keys this type takes; utils.DecodeUint64 recovers the nonnegative value.
159//
160// Parameters:
161//   - makeEntrySafeFn: Callback that converts each stored value into the representation exposed through the read-only view.
162//
163// Returns:
164//   - tree: Read-only wrapper over the underlying tree for safe pagination.
165func (self *UintTree) ReadOnly(makeEntrySafeFn func(any) any) *rotree.ReadOnlyTree {
166	return rotree.Wrap(self.tree, makeEntrySafeFn)
167}
168
169// Clone returns a new UintTree with the same encoded keys and stored value references.
170//
171// Returns:
172//   - tree: New UintTree preserving this tree's fanout and entries; pointed-to values are not deep-cloned.
173func (self *UintTree) Clone() *UintTree {
174	if self == nil {
175		return nil
176	}
177
178	cloned := NewUintTreeN(self.fanout)
179	self.tree.Iterate("", "", func(key string, value any) bool {
180		cloned.tree.Set(key, value)
181		return false
182	})
183
184	return cloned
185}
186
187func encodeInt64(num int64) string {
188	if num < 0 {
189		panic(ufmt.Sprintf("negative value not supported: %d", num))
190	}
191	return utils.EncodeUint64(uint64(num))
192}
193
194func decodeInt64(s string) int64 {
195	return gnsmath.SafeUint64ToInt64(utils.DecodeUint64(s))
196}