- Kind
- Pure package
- Name
- v1
- Namespace
- gnoswap / gnsmath
- Exported functions
- n/a — not supported for pure packages by the node (vm/qfuncs)
- Module
- gno.land/p/gnoswap/gnsmath/v1
- gno
- 0.9
safe_math.gnogno
1package gnsmath23import (4 "math"56 ufmt "gno.land/p/nt/ufmt/v0"78
not supported for pure packages by the node (vm/qfuncs)
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
i256
"gno.land/p/gnoswap/int256/v1"
9 u256 "gno.land/p/gnoswap/uint256/v1"
10)
11
12// Range bounds used by the safe conversion helpers.
13const (
14 maxInt64Decimal = "9223372036854775807" // 2^63 - 1
15 maxInt128Decimal = "170141183460469231731687303715884105727" // 2^127 - 1
16)
17
18// MaxInt128 returns the largest positive value representable by a signed 128-bit integer.
19//
20// Returns:
21// - maxInt128: A fresh *i256.Int containing 2^127 - 1, used as the upper bound
22// for conversions that must fit in the signed int128 range.
23func MaxInt128() *i256.Int {
24 return i256.MustFromDecimal(maxInt128Decimal)
25}
26
27// SafeAddInt64 returns the exact sum of two signed 64-bit integers.
28//
29// Parameters:
30// - a: First signed int64 operand.
31// - b: Second signed int64 operand.
32//
33// Returns:
34// - sum: a + b when the mathematical result is within [math.MinInt64, math.MaxInt64].
35//
36// Panics if the signed int64 sum overflows or underflows.
37func SafeAddInt64(a, b int64) int64 {
38 if a > 0 && b > math.MaxInt64-a {
39 panic("int64 addition overflow")
40 }
41 if a < 0 && b < math.MinInt64-a {
42 panic("int64 addition underflow")
43 }
44 return a + b
45}
46
47// SafeSubInt64 returns the exact difference of two signed 64-bit integers.
48//
49// Parameters:
50// - a: Signed int64 minuend.
51// - b: Signed int64 subtrahend.
52//
53// Returns:
54// - difference: a - b when the mathematical result is within [math.MinInt64, math.MaxInt64].
55//
56// Panics if the signed int64 difference overflows or underflows.
57func SafeSubInt64(a, b int64) int64 {
58 if b > 0 && a < math.MinInt64+b {
59 panic("int64 subtraction underflow")
60 }
61 if b < 0 && a > math.MaxInt64+b {
62 panic("int64 subtraction overflow")
63 }
64 return a - b
65}
66
67// SafeMulInt64 returns the exact product of two signed 64-bit integers.
68//
69// Parameters:
70// - a: First signed int64 factor.
71// - b: Second signed int64 factor.
72//
73// Returns:
74// - product: a * b when the mathematical result is within [math.MinInt64, math.MaxInt64].
75//
76// Panics if the signed int64 product overflows or underflows.
77func SafeMulInt64(a, b int64) int64 {
78 if a == 0 || b == 0 {
79 return 0
80 }
81
82 if a > 0 && b > 0 {
83 if a > math.MaxInt64/b {
84 panic("int64 multiplication overflow")
85 }
86 } else if a < 0 && b < 0 {
87 if a < math.MaxInt64/b {
88 panic("int64 multiplication overflow")
89 }
90 } else if a > 0 && b < 0 {
91 if b < math.MinInt64/a {
92 panic("int64 multiplication underflow")
93 }
94 } else { // a < 0 && b > 0
95 if a < math.MinInt64/b {
96 panic("int64 multiplication underflow")
97 }
98 }
99
100 return a * b
101}
102
103// SafeMulDivInt64 returns the truncated quotient (a * b) / c.
104//
105// The product is formed in signed 256-bit arithmetic before division, so an
106// intermediate product may exceed int64 while the final quotient must still fit.
107//
108// Parameters:
109// - a: First signed int64 factor.
110// - b: Second signed int64 factor.
111// - c: Non-zero signed int64 divisor.
112//
113// Returns:
114// - quotient: The signed integer quotient after dividing a * b by c.
115//
116// Panics if the 256-bit product overflows, c is zero, or the quotient is outside
117// the representable int64 range.
118func SafeMulDivInt64(a, b, c int64) int64 {
119 if a == 0 || b == 0 {
120 return 0
121 }
122
123 result, overflow := i256.Zero().MulOverflow(i256.NewInt(a), i256.NewInt(b))
124 if overflow {
125 panic(errSafeMathOverflow)
126 }
127
128 result = i256.Zero().Div(result, i256.NewInt(c))
129 if !result.IsInt64() {
130 panic(errSafeMathOverflow)
131 }
132
133 return result.Int64()
134}
135
136// SafeAbsInt64 returns the non-negative absolute value of a.
137//
138// Parameters:
139// - a: Signed int64 value whose magnitude is requested.
140//
141// Returns:
142// - magnitude: |a| as int64.
143//
144// Panics when a is math.MinInt64 because its positive magnitude cannot be
145// represented by int64.
146func SafeAbsInt64(a int64) int64 {
147 if a == math.MinInt64 {
148 panic(errSafeMathOverflow)
149 }
150 if a < 0 {
151 return -a
152 }
153 return a
154}
155
156// SafeAddUint64 returns the exact sum of two unsigned 64-bit integers.
157//
158// Parameters:
159// - a: First uint64 operand.
160// - b: Second uint64 operand.
161//
162// Returns:
163// - sum: a + b when the mathematical result is at most math.MaxUint64.
164//
165// Panics if the uint64 sum overflows.
166func SafeAddUint64(a, b uint64) uint64 {
167 if a > math.MaxUint64-b {
168 panic("uint64 addition overflow")
169 }
170 return a + b
171}
172
173// SafeSubUint64 returns the exact difference of two unsigned 64-bit integers.
174//
175// Parameters:
176// - a: Unsigned uint64 minuend.
177// - b: Unsigned uint64 subtrahend; it must not exceed a.
178//
179// Returns:
180// - difference: a - b.
181//
182// Panics if b is greater than a and the subtraction would underflow uint64.
183func SafeSubUint64(a, b uint64) uint64 {
184 if a < b {
185 panic("uint64 subtraction underflow")
186 }
187 return a - b
188}
189
190// SafeUint64ToInt64 converts a uint64 to a signed int64 without changing its value.
191//
192// Parameters:
193// - value: Unsigned value to convert; it must be no greater than 2^63 - 1.
194//
195// Returns:
196// - converted: value represented as int64.
197//
198// Panics when value exceeds math.MaxInt64.
199func SafeUint64ToInt64(value uint64) int64 {
200 if value > uint64(math.MaxInt64) {
201 panic(ufmt.Sprintf(
202 "amount(%d) overflows int64 range (max: %s)",
203 value, maxInt64Decimal,
204 ))
205 }
206 return int64(value)
207}
208
209// SafeConvertToInt64 converts a non-negative 256-bit integer to int64.
210//
211// Parameters:
212// - value: Unsigned 256-bit value to convert; nil is invalid.
213//
214// Returns:
215// - converted: value represented as int64 when it is at most math.MaxInt64.
216//
217// Panics when value is nil or outside the int64 range.
218func SafeConvertToInt64(value *u256.Uint) int64 {
219 if value == nil {
220 panic("SafeConvertToInt64: value is nil")
221 }
222 res, overflow := value.Uint64WithOverflow()
223 if overflow || res > uint64(math.MaxInt64) {
224 panic(ufmt.Sprintf(
225 "amount(%s) overflows int64 range (max: %s)",
226 value.ToString(), maxInt64Decimal,
227 ))
228 }
229 return int64(res)
230}
231
232// SafeConvertToInt128 converts a non-negative 256-bit integer to signed int128.
233//
234// Parameters:
235// - value: Unsigned 256-bit value to convert; nil is invalid.
236//
237// Returns:
238// - converted: A new *i256.Int representing value when it is at most 2^127 - 1.
239//
240// Panics when value is nil or exceeds the largest positive signed int128 value.
241func SafeConvertToInt128(value *u256.Uint) *i256.Int {
242 if value == nil {
243 panic("SafeConvertToInt128: value is nil")
244 }
245 converted := i256.FromUint256(value)
246 if converted.Gt(MaxInt128()) {
247 panic(ufmt.Sprintf(
248 "amount(%s) overflows int128 range",
249 value.ToString(),
250 ))
251 }
252 return converted
253}
254