Search Apps Documentation Source Content File Folder Download Copy Actions Download

tree.gno

5.07 Kb · 192 lines
  1package staker
  2
  3import (
  4	"strconv"
  5	"strings"
  6
  7	bptree "gno.land/p/nt/bptree/v0"
  8	ufmt "gno.land/p/nt/ufmt/v0"
  9)
 10
 11// UintTree is a wrapper around a B+ tree for storing block timestamps as strings.
 12// Since block timestamps are defined as int64, we take int64 and convert it to uint64 for the tree.
 13//
 14// Methods:
 15// - Get: Retrieves a value associated with a uint64 key.
 16// - Set: Stores a value with a uint64 key.
 17// - Has: Checks if a uint64 key exists in the tree.
 18// - Remove: Removes a uint64 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.
 34func NewBPTreeN(fanout int) *bptree.BPTree {
 35	return bptree.NewBPTreeN(fanout)
 36}
 37
 38// NewUintTree creates a new UintTree instance with default fanout 64.
 39func NewUintTree() *UintTree {
 40	return NewUintTreeN(64)
 41}
 42
 43// NewUintTreeN creates a new UintTree instance with the specified fanout.
 44func NewUintTreeN(fanout int) *UintTree {
 45	return &UintTree{
 46		tree:   bptree.NewBPTreeN(fanout),
 47		fanout: fanout,
 48	}
 49}
 50
 51func (self *UintTree) Get(key int64) (any, bool) {
 52	v, ok := self.tree.Get(EncodeInt64(key))
 53	if !ok {
 54		return nil, false
 55	}
 56	return v, true
 57}
 58
 59func (self *UintTree) Set(key int64, value any) {
 60	self.tree.Set(EncodeInt64(key), value)
 61}
 62
 63func (self *UintTree) Has(key int64) bool {
 64	return self.tree.Has(EncodeInt64(key))
 65}
 66
 67func (self *UintTree) Remove(key int64) {
 68	self.tree.Remove(EncodeInt64(key))
 69}
 70
 71func (self *UintTree) Iterate(start, end int64, fn func(key int64, value any) bool) {
 72	self.tree.Iterate(EncodeInt64(start), EncodeInt64(end), func(key string, value any) bool {
 73		return fn(DecodeInt64(key), value)
 74	})
 75}
 76
 77func (self *UintTree) ReverseIterate(start, end int64, fn func(key int64, value any) bool) {
 78	self.tree.ReverseIterate(EncodeInt64(start), EncodeInt64(end), func(key string, value any) bool {
 79		return fn(DecodeInt64(key), value)
 80	})
 81}
 82
 83func (self *UintTree) Size() int {
 84	return self.tree.Size()
 85}
 86
 87func (self *UintTree) IterateByOffset(offset, count int, fn func(key int64, value any) bool) {
 88	self.tree.IterateByOffset(offset, count, func(key string, value any) bool {
 89		return fn(DecodeInt64(key), value)
 90	})
 91}
 92
 93func (self *UintTree) Clone() *UintTree {
 94	if self == nil {
 95		return nil
 96	}
 97
 98	cloned := NewUintTreeN(self.fanout)
 99	self.tree.Iterate("", "", func(key string, value any) bool {
100		cloned.tree.Set(key, value)
101		return false
102	})
103
104	return cloned
105}
106
107// EncodeUint converts a uint64 number into a zero-padded 20-character string.
108//
109// Parameters:
110// - num (uint64): The number to encode.
111//
112// Returns:
113// - string: A zero-padded string representation of the number.
114//
115// Example:
116// Input: 12345
117// Output: "00000000000000012345"
118func EncodeUint(num uint64) string {
119	// Convert the value to a decimal string.
120	s := strconv.FormatUint(num, 10)
121
122	// Zero-pad to a total length of 20 characters.
123	zerosNeeded := 20 - len(s)
124	return strings.Repeat("0", zerosNeeded) + s
125}
126
127func EncodeInt64(num int64) string {
128	if num < 0 {
129		panic(ufmt.Sprintf("negative value not supported: %d", num))
130	}
131	return EncodeUint(uint64(num))
132}
133
134// DecodeUint converts a zero-padded string back into a uint64 number.
135//
136// Parameters:
137// - s (string): The zero-padded string.
138//
139// Returns:
140// - uint64: The decoded number.
141//
142// Panics:
143// - If the string cannot be parsed into a uint64.
144//
145// Example:
146// Input: "00000000000000012345"
147// Output: 12345
148func DecodeUint(s string) uint64 {
149	num, err := strconv.ParseUint(s, 10, 64)
150	if err != nil {
151		panic(err)
152	}
153	return num
154}
155
156func DecodeInt64(s string) int64 {
157	num, err := strconv.ParseInt(s, 10, 64)
158	if err != nil {
159		panic(err)
160	}
161	return num
162}
163
164// EncodeInt takes an int32 and returns a zero-padded decimal string
165// with up to 10 digits for the absolute value.
166// If the number is negative, the '-' sign comes first, followed by zeros, then digits.
167func EncodeInt(num int32) string {
168	// Convert the absolute value to a decimal string.
169	absValue := int64(num)
170	isNegative := false
171	if num < 0 {
172		isNegative = true
173		absValue = -absValue // Safely negate into int64 to avoid overflow.
174	}
175
176	s := strconv.FormatInt(absValue, 10)
177
178	// Zero-pad to a total of 10 digits for the absolute value.
179	// (The '-' sign will be added later if needed.)
180	zerosNeeded := 10 - len(s)
181	if zerosNeeded < 0 {
182		zerosNeeded = 0
183	}
184
185	padded := strings.Repeat("0", zerosNeeded) + s
186
187	// If the original number was negative, prepend '-'.
188	if isNegative {
189		return "-" + padded
190	}
191	return padded
192}