// Copyright 2022 The Cockroach Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or // implied. See the License for the specific language governing // permissions and limitations under the License. package apd import ( "fmt" "math/big" "math/bits" "math/rand" "strconv" "unsafe" ) // The inlineWords capacity is set to accommodate any value that would fit in a // 128-bit integer (i.e. values with an absolute value up to 2^128 - 1). const inlineWords = 128 / bits.UintSize // BigInt is a wrapper around big.Int. It minimizes memory allocation by using // an inline array to back the big.Int's variable-length "nat" slice when the // integer's value is sufficiently small. // The zero value is ready to use. type BigInt struct { // A wrapped big.Int. Only set to the BigInt's value when the value exceeds // what is representable in the _inline array. // // When the BigInt's value is still small enough to use the _inline array, // this field doubles as integer's negative flag. See negSentinel. // // Methods should access this field through inner. _inner *big.Int // The inlined backing array use for short-lived, stack-allocated big.Int // structs during arithmetic when the value is small. // // Each BigInt maintains (through big.Int) an internal reference to a // variable-length integer value, which is represented by a []big.Word. The // _inline field and the inner and updateInner methods combine to allow // BigInt to inline this variable-length integer array within the BigInt // struct when its value is sufficiently small. In the inner method, we // point a temporary big.Int's nat slice at this _inline array. big.Int will // avoid re-allocating this array until it is provided with a value that // exceeds the initial capacity. Later in updateInner, we detect whether the // array has been re-allocated. If so, we switch to using the _inner. If // not, we continue to use this array. _inline [inlineWords]big.Word } // NewBigInt allocates and returns a new BigInt set to x. // // NOTE: BigInt jumps through hoops to avoid escaping to the heap. As such, most // users of BigInt should not need this function. They should instead declare a // zero-valued BigInt directly on the stack and interact with references to this // stack-allocated value. Recall that the zero-valued BigInt is ready to use. func NewBigInt(x int64) *BigInt { return new(BigInt).SetInt64(x) } // Set as the value of BigInt._inner as a "sentinel" flag to indicate that a // BigInt is negative ((big.Int).Sign() < 0) but the absolute value is still // small enough to represent in the _inline array. var negSentinel = new(big.Int) // isInline returns whether the BigInt stores its value in its _inline array. //gcassert:inline func (z *BigInt) isInline() bool { return z._inner == nil || z._inner == negSentinel } // The memory representation of big.Int. Used for unsafe modification below. type intStruct struct { neg bool abs []big.Word } // noescape hides a pointer from escape analysis. noescape is the identity // function but escape analysis doesn't think the output depends on the input. // noescape is inlined and currently compiles down to zero instructions. // // USE CAREFULLY! // // This was copied from strings.Builder, which has identical code which was // itself copied from the runtime. // For more, see issues #23382 and #7921 in github.com/golang/go. //go:nosplit //go:nocheckptr func noescape(p unsafe.Pointer) unsafe.Pointer { x := uintptr(p) //lint:ignore SA4016 intentional no-op to hide pointer from escape analysis. return unsafe.Pointer(x ^ 0) } // inner returns the BigInt's current value as a *big.Int. // // NOTE: this was carefully written to permit function inlining. Modify with // care. //gcassert:inline func (z *BigInt) inner(tmp *big.Int) *big.Int { // Point the big.Int at the inline array. When doing so, use noescape to // avoid forcing the BigInt to escape to the heap. Go's escape analysis // struggles with self-referential pointers, and it can't prove that we // only assign _inner to a heap-allocated object (which must not contain // pointers that reference the stack or the GC explodes) if the big.Int's // backing array has been re-allocated onto the heap first. // // NOTE: SetBits sets the neg field to false, so this must come before the // negSentinel handling. tmp.SetBits((*[inlineWords]big.Word)(noescape(unsafe.Pointer(&z._inline[0])))[:]) if z._inner != nil { if z._inner != negSentinel { // The variable-length big.Int reference is set. return z._inner } // This is the negative sentinel, which indicates that the integer is // negative but still stored inline. Update the big.Int accordingly. We // use unsafe because (*big.Int).Neg is too complex and prevents this // method from being inlined. (*intStruct)(unsafe.Pointer(tmp)).neg = true } return tmp } // innerOrNil is like inner, but returns a nil *big.Int if the receiver is nil. // NOTE: this is not inlined. func (z *BigInt) innerOrNil(tmp *big.Int) *big.Int { if z == nil { return nil } return z.inner(tmp) } // innerOrAlias is like inner, but returns the provided *big.Int if the receiver // and the other *BigInt argument reference the same object. // NOTE: this is not inlined. func (z *BigInt) innerOrAlias(tmp *big.Int, a *BigInt, ai *big.Int) *big.Int { if a == z { return ai } return z.inner(tmp) } // innerOrNilOrAlias is like inner, but with the added semantics specified for // both innerOrNil and innerOrAlias. // NOTE: this is not inlined. func (z *BigInt) innerOrNilOrAlias(tmp *big.Int, a *BigInt, ai *big.Int) *big.Int { if z == nil { return nil } else if z == a { return ai } return z.inner(tmp) } // updateInner updates the BigInt's current value with the provided *big.Int. // // NOTE: this was carefully written to permit function inlining. Modify with // care. //gcassert:inline func (z *BigInt) updateInner(src *big.Int) { if z._inner == src { return } bits := src.Bits() bitsLen := len(bits) if bitsLen > 0 && &z._inline[0] != &bits[0] { // The big.Int re-allocated its backing array during arithmetic because // the value grew beyond what could fit in the _inline array. Switch to // a heap-allocated, variable-length big.Int and store that in _inner. // From now on, all arithmetic will use this big.Int directly. // // Allocate a new big.Int and perform a shallow-copy of the argument to // prevent it from escaping off the stack. z._inner = new(big.Int) *z._inner = *src } else { // Zero out all words beyond the end of the big.Int's current Word // slice. big.Int arithmetic can sometimes leave these words "dirty". // They would cause issues when the _inline array is injected into the // next big.Int if not cleared. for bitsLen < len(z._inline) { z._inline[bitsLen] = 0 bitsLen++ } // Set or unset the negative sentinel, according to the argument's sign. // We use unsafe because (*big.Int).Sign is too complex and prevents // this method from being inlined. if (*intStruct)(unsafe.Pointer(src)).neg { z._inner = negSentinel } else { z._inner = nil } } } const wordsInUint64 = 64 / bits.UintSize func init() { if inlineWords < wordsInUint64 { panic("inline array must be at least 64 bits large") } } // innerAsUint64 returns the BigInt's current absolute value as a uint64 and a // flag indicating whether the value is negative. If the value is not stored // inline or if it can not fit in a uint64, false is returned. // // NOTE: this was carefully written to permit function inlining. Modify with // care. //gcassert:inline func (z *BigInt) innerAsUint64() (val uint64, neg bool, ok bool) { if !z.isInline() { // The value is not stored inline. return 0, false, false } if wordsInUint64 == 1 && inlineWords == 2 { // Manually unrolled loop for current inlineWords setting. if z._inline[1] != 0 { // The value can not fit in a uint64. return 0, false, false } } else { // Fallback for other values of inlineWords. for i := wordsInUint64; i < len(z._inline); i++ { if z._inline[i] != 0 { // The value can not fit in a uint64. return 0, false, false } } } val = uint64(z._inline[0]) if wordsInUint64 == 2 { // From big.low64. val = uint64(z._inline[1])<<32 | val } neg = z._inner == negSentinel return val, neg, true } // updateInnerFromUint64 updates the BigInt's current value with the provided // absolute value and sign. // // NOTE: this was carefully written to permit function inlining. Modify with // care. //gcassert:inline func (z *BigInt) updateInnerFromUint64(val uint64, neg bool) { // Set the inline value. z._inline[0] = big.Word(val) if wordsInUint64 == 2 { // From (big.nat).setUint64. z._inline[1] = big.Word(val >> 32) } // Clear out all other words in the inline array. if wordsInUint64 == 1 && inlineWords == 2 { // Manually unrolled loop for current inlineWords setting. z._inline[1] = 0 } else { // Fallback for other values of inlineWords. for i := wordsInUint64; i < len(z._inline); i++ { z._inline[i] = 0 } } // Set or unset the negative sentinel. if neg { z._inner = negSentinel } else { z._inner = nil } } const ( bigIntSize = unsafe.Sizeof(BigInt{}) mathBigIntSize = unsafe.Sizeof(big.Int{}) mathWordSize = unsafe.Sizeof(big.Word(0)) ) // Size returns the total memory footprint of z in bytes. func (z *BigInt) Size() uintptr { if z.isInline() { return bigIntSize } return bigIntSize + mathBigIntSize + uintptr(cap(z._inner.Bits()))*mathWordSize } /////////////////////////////////////////////////////////////////////////////// // inline arithmetic for small values // /////////////////////////////////////////////////////////////////////////////// //gcassert:inline func addInline(xVal, yVal uint64, xNeg, yNeg bool) (zVal uint64, zNeg, ok bool) { if xNeg == yNeg { sum, carry := bits.Add64(xVal, yVal, 0) overflow := carry != 0 return sum, xNeg, !overflow } diff, borrow := bits.Sub64(xVal, yVal, 0) if borrow != 0 { // underflow xNeg = !xNeg diff = yVal - xVal } if diff == 0 { xNeg = false } return diff, xNeg, true } //gcassert:inline func mulInline(xVal, yVal uint64, xNeg, yNeg bool) (zVal uint64, zNeg, ok bool) { hi, lo := bits.Mul64(xVal, yVal) neg := xNeg != yNeg && lo != 0 overflow := hi != 0 return lo, neg, !overflow } //gcassert:inline func quoInline(xVal, yVal uint64, xNeg, yNeg bool) (quoVal uint64, quoNeg, ok bool) { if yVal == 0 { // divide by 0 return 0, false, false } quo := xVal / yVal neg := xNeg != yNeg && quo != 0 return quo, neg, true } //gcassert:inline func remInline(xVal, yVal uint64, xNeg, yNeg bool) (remVal uint64, remNeg, ok bool) { if yVal == 0 { // divide by 0 return 0, false, false } rem := xVal % yVal return rem, xNeg && rem != 0, true } /////////////////////////////////////////////////////////////////////////////// // big.Int API wrapper methods // /////////////////////////////////////////////////////////////////////////////// // Abs calls (big.Int).Abs. func (z *BigInt) Abs(x *BigInt) *BigInt { if x.isInline() { z._inline = x._inline z._inner = nil // !negSentinel return z } var tmp1, tmp2 big.Int //gcassert:noescape zi := z.inner(&tmp1) zi.Abs(x.inner(&tmp2)) z.updateInner(zi) return z } // Add calls (big.Int).Add. func (z *BigInt) Add(x, y *BigInt) *BigInt { if xVal, xNeg, ok := x.innerAsUint64(); ok { if yVal, yNeg, ok := y.innerAsUint64(); ok { if zVal, zNeg, ok := addInline(xVal, yVal, xNeg, yNeg); ok { z.updateInnerFromUint64(zVal, zNeg) return z } } } var tmp1, tmp2, tmp3 big.Int //gcassert:noescape zi := z.inner(&tmp1) zi.Add(x.inner(&tmp2), y.inner(&tmp3)) z.updateInner(zi) return z } // And calls (big.Int).And. func (z *BigInt) And(x, y *BigInt) *BigInt { var tmp1, tmp2, tmp3 big.Int //gcassert:noescape zi := z.inner(&tmp1) zi.And(x.inner(&tmp2), y.inner(&tmp3)) z.updateInner(zi) return z } // AndNot calls (big.Int).AndNot. func (z *BigInt) AndNot(x, y *BigInt) *BigInt { var tmp1, tmp2, tmp3 big.Int //gcassert:noescape zi := z.inner(&tmp1) zi.AndNot(x.inner(&tmp2), y.inner(&tmp3)) z.updateInner(zi) return z } // Append calls (big.Int).Append. func (z *BigInt) Append(buf []byte, base int) []byte { if z == nil { // Fast-path that avoids innerOrNil, allowing inner to be inlined. return append(buf, ""...) } if zVal, zNeg, ok := z.innerAsUint64(); ok { // Check if the base is supported by strconv.AppendUint. if base >= 2 && base <= 36 { if zNeg { buf = append(buf, '-') } return strconv.AppendUint(buf, zVal, base) } } var tmp1 big.Int //gcassert:noescape return z.inner(&tmp1).Append(buf, base) } // Binomial calls (big.Int).Binomial. func (z *BigInt) Binomial(n, k int64) *BigInt { var tmp1 big.Int //gcassert:noescape zi := z.inner(&tmp1) zi.Binomial(n, k) z.updateInner(zi) return z } // Bit calls (big.Int).Bit. func (z *BigInt) Bit(i int) uint { if i == 0 && z.isInline() { // Optimization for common case: odd/even test of z. return uint(z._inline[0] & 1) } var tmp1 big.Int //gcassert:noescape return z.inner(&tmp1).Bit(i) } // BitLen calls (big.Int).BitLen. func (z *BigInt) BitLen() int { if z.isInline() { // Find largest non-zero inline word. for i := len(z._inline) - 1; i >= 0; i-- { if z._inline[i] != 0 { return i*bits.UintSize + bits.Len(uint(z._inline[i])) } } return 0 } var tmp1 big.Int //gcassert:noescape return z.inner(&tmp1).BitLen() } // Bits calls (big.Int).Bits. func (z *BigInt) Bits() []big.Word { var tmp1 big.Int //gcassert:noescape return z.inner(&tmp1).Bits() } // Bytes calls (big.Int).Bytes. func (z *BigInt) Bytes() []byte { var tmp1 big.Int //gcassert:noescape return z.inner(&tmp1).Bytes() } // Cmp calls (big.Int).Cmp. func (z *BigInt) Cmp(y *BigInt) (r int) { if zVal, zNeg, ok := z.innerAsUint64(); ok { if yVal, yNeg, ok := y.innerAsUint64(); ok { switch { case zNeg == yNeg: switch { case zVal < yVal: r = -1 case zVal > yVal: r = 1 } if zNeg { r = -r } case zNeg: r = -1 default: r = 1 } return r } } var tmp1, tmp2 big.Int //gcassert:noescape return z.inner(&tmp1).Cmp(y.inner(&tmp2)) } // CmpAbs calls (big.Int).CmpAbs. func (z *BigInt) CmpAbs(y *BigInt) (r int) { if zVal, _, ok := z.innerAsUint64(); ok { if yVal, _, ok := y.innerAsUint64(); ok { switch { case zVal < yVal: r = -1 case zVal > yVal: r = 1 } return r } } var tmp1, tmp2 big.Int //gcassert:noescape return z.inner(&tmp1).CmpAbs(y.inner(&tmp2)) } // Div calls (big.Int).Div. func (z *BigInt) Div(x, y *BigInt) *BigInt { var tmp1, tmp2, tmp3 big.Int //gcassert:noescape zi := z.inner(&tmp1) zi.Div(x.inner(&tmp2), y.inner(&tmp3)) z.updateInner(zi) return z } // DivMod calls (big.Int).DivMod. func (z *BigInt) DivMod(x, y, m *BigInt) (*BigInt, *BigInt) { var tmp1, tmp2, tmp3, tmp4 big.Int //gcassert:noescape zi := z.inner(&tmp1) mi := m.inner(&tmp2) // NOTE: innerOrAlias for the y param because (big.Int).DivMod needs to // detect when y is aliased to the receiver. zi.DivMod(x.inner(&tmp3), y.innerOrAlias(&tmp4, z, zi), mi) z.updateInner(zi) m.updateInner(mi) return z, m } // Exp calls (big.Int).Exp. func (z *BigInt) Exp(x, y, m *BigInt) *BigInt { var tmp1, tmp2, tmp3, tmp4 big.Int //gcassert:noescape zi := z.inner(&tmp1) if zi.Exp(x.inner(&tmp2), y.inner(&tmp3), m.innerOrNil(&tmp4)) == nil { return nil } z.updateInner(zi) return z } // Format calls (big.Int).Format. func (z *BigInt) Format(s fmt.State, ch rune) { var tmp1 big.Int //gcassert:noescape z.innerOrNil(&tmp1).Format(s, ch) } // GCD calls (big.Int).GCD. func (z *BigInt) GCD(x, y, a, b *BigInt) *BigInt { var tmp1, tmp2, tmp3, tmp4, tmp5 big.Int //gcassert:noescape zi := z.inner(&tmp1) ai := a.inner(&tmp2) bi := b.inner(&tmp3) xi := x.innerOrNil(&tmp4) // NOTE: innerOrNilOrAlias for the y param because (big.Int).GCD needs to // detect when y is aliased to b. See "avoid aliasing b" in lehmerGCD. yi := y.innerOrNilOrAlias(&tmp5, b, bi) zi.GCD(xi, yi, ai, bi) z.updateInner(zi) if xi != nil { x.updateInner(xi) } if yi != nil { y.updateInner(yi) } return z } // GobEncode calls (big.Int).GobEncode. func (z *BigInt) GobEncode() ([]byte, error) { var tmp1 big.Int //gcassert:noescape return z.innerOrNil(&tmp1).GobEncode() } // GobDecode calls (big.Int).GobDecode. func (z *BigInt) GobDecode(buf []byte) error { var tmp1 big.Int //gcassert:noescape zi := z.inner(&tmp1) if err := zi.GobDecode(buf); err != nil { return err } z.updateInner(zi) return nil } // Int64 calls (big.Int).Int64. func (z *BigInt) Int64() int64 { if zVal, zNeg, ok := z.innerAsUint64(); ok { // The unchecked cast from uint64 to int64 looks unsafe, but it is // allowed and is identical to the logic in (big.Int).Int64. Per the // method's contract: // > If z cannot be represented in an int64, the result is undefined. zi := int64(zVal) if zNeg { zi = -zi } return zi } var tmp1 big.Int //gcassert:noescape return z.inner(&tmp1).Int64() } // IsInt64 calls (big.Int).IsInt64. func (z *BigInt) IsInt64() bool { if zVal, zNeg, ok := z.innerAsUint64(); ok { // From (big.Int).IsInt64. zi := int64(zVal) return zi >= 0 || zNeg && zi == -zi } var tmp1 big.Int //gcassert:noescape return z.inner(&tmp1).IsInt64() } // IsUint64 calls (big.Int).IsUint64. func (z *BigInt) IsUint64() bool { if _, zNeg, ok := z.innerAsUint64(); ok { return !zNeg } var tmp1 big.Int //gcassert:noescape return z.inner(&tmp1).IsUint64() } // Lsh calls (big.Int).Lsh. func (z *BigInt) Lsh(x *BigInt, n uint) *BigInt { var tmp1, tmp2 big.Int //gcassert:noescape zi := z.inner(&tmp1) zi.Lsh(x.inner(&tmp2), n) z.updateInner(zi) return z } // MarshalJSON calls (big.Int).MarshalJSON. func (z *BigInt) MarshalJSON() ([]byte, error) { var tmp1 big.Int //gcassert:noescape return z.innerOrNil(&tmp1).MarshalJSON() } // MarshalText calls (big.Int).MarshalText. func (z *BigInt) MarshalText() (text []byte, err error) { var tmp1 big.Int //gcassert:noescape return z.innerOrNil(&tmp1).MarshalText() } // Mod calls (big.Int).Mod. func (z *BigInt) Mod(x, y *BigInt) *BigInt { var tmp1, tmp2, tmp3 big.Int //gcassert:noescape zi := z.inner(&tmp1) // NOTE: innerOrAlias for the y param because (big.Int).Mod needs to detect // when y is aliased to the receiver. zi.Mod(x.inner(&tmp2), y.innerOrAlias(&tmp3, z, zi)) z.updateInner(zi) return z } // ModInverse calls (big.Int).ModInverse. func (z *BigInt) ModInverse(g, n *BigInt) *BigInt { var tmp1, tmp2, tmp3 big.Int //gcassert:noescape zi := z.inner(&tmp1) if zi.ModInverse(g.inner(&tmp2), n.inner(&tmp3)) == nil { return nil } z.updateInner(zi) return z } // ModSqrt calls (big.Int).ModSqrt. func (z *BigInt) ModSqrt(x, p *BigInt) *BigInt { var tmp1, tmp2 big.Int //gcassert:noescape var tmp3 big.Int // escapes because of https://github.com/golang/go/pull/50527. zi := z.inner(&tmp1) if zi.ModSqrt(x.inner(&tmp2), p.inner(&tmp3)) == nil { return nil } z.updateInner(zi) return z } // Mul calls (big.Int).Mul. func (z *BigInt) Mul(x, y *BigInt) *BigInt { if xVal, xNeg, ok := x.innerAsUint64(); ok { if yVal, yNeg, ok := y.innerAsUint64(); ok { if zVal, zNeg, ok := mulInline(xVal, yVal, xNeg, yNeg); ok { z.updateInnerFromUint64(zVal, zNeg) return z } } } var tmp1, tmp2, tmp3 big.Int //gcassert:noescape zi := z.inner(&tmp1) zi.Mul(x.inner(&tmp2), y.inner(&tmp3)) z.updateInner(zi) return z } // MulRange calls (big.Int).MulRange. func (z *BigInt) MulRange(x, y int64) *BigInt { var tmp1 big.Int //gcassert:noescape zi := z.inner(&tmp1) zi.MulRange(x, y) z.updateInner(zi) return z } // Neg calls (big.Int).Neg. func (z *BigInt) Neg(x *BigInt) *BigInt { if x.isInline() { z._inline = x._inline if x._inner == negSentinel { z._inner = nil } else { z._inner = negSentinel } return z } var tmp1, tmp2 big.Int //gcassert:noescape zi := z.inner(&tmp1) zi.Neg(x.inner(&tmp2)) z.updateInner(zi) return z } // Not calls (big.Int).Not. func (z *BigInt) Not(x *BigInt) *BigInt { var tmp1, tmp2 big.Int //gcassert:noescape zi := z.inner(&tmp1) zi.Not(x.inner(&tmp2)) z.updateInner(zi) return z } // Or calls (big.Int).Or. func (z *BigInt) Or(x, y *BigInt) *BigInt { var tmp1, tmp2, tmp3 big.Int //gcassert:noescape zi := z.inner(&tmp1) zi.Or(x.inner(&tmp2), y.inner(&tmp3)) z.updateInner(zi) return z } // ProbablyPrime calls (big.Int).ProbablyPrime. func (z *BigInt) ProbablyPrime(n int) bool { var tmp1 big.Int //gcassert:noescape return z.inner(&tmp1).ProbablyPrime(n) } // Quo calls (big.Int).Quo. func (z *BigInt) Quo(x, y *BigInt) *BigInt { if xVal, xNeg, ok := x.innerAsUint64(); ok { if yVal, yNeg, ok := y.innerAsUint64(); ok { if quoVal, quoNeg, ok := quoInline(xVal, yVal, xNeg, yNeg); ok { z.updateInnerFromUint64(quoVal, quoNeg) return z } } } var tmp1, tmp2, tmp3 big.Int //gcassert:noescape zi := z.inner(&tmp1) zi.Quo(x.inner(&tmp2), y.inner(&tmp3)) z.updateInner(zi) return z } // QuoRem calls (big.Int).QuoRem. func (z *BigInt) QuoRem(x, y, r *BigInt) (*BigInt, *BigInt) { if xVal, xNeg, ok := x.innerAsUint64(); ok { if yVal, yNeg, ok := y.innerAsUint64(); ok { if quoVal, quoNeg, ok := quoInline(xVal, yVal, xNeg, yNeg); ok { if remVal, remNeg, ok := remInline(xVal, yVal, xNeg, yNeg); ok { z.updateInnerFromUint64(quoVal, quoNeg) r.updateInnerFromUint64(remVal, remNeg) return z, r } } } } var tmp1, tmp2, tmp3, tmp4 big.Int //gcassert:noescape zi := z.inner(&tmp1) ri := r.inner(&tmp2) zi.QuoRem(x.inner(&tmp3), y.inner(&tmp4), ri) z.updateInner(zi) r.updateInner(ri) return z, r } // Rand calls (big.Int).Rand. func (z *BigInt) Rand(rnd *rand.Rand, n *BigInt) *BigInt { var tmp1, tmp2 big.Int //gcassert:noescape zi := z.inner(&tmp1) zi.Rand(rnd, n.inner(&tmp2)) z.updateInner(zi) return z } // Rem calls (big.Int).Rem. func (z *BigInt) Rem(x, y *BigInt) *BigInt { if xVal, xNeg, ok := x.innerAsUint64(); ok { if yVal, yNeg, ok := y.innerAsUint64(); ok { if remVal, remNeg, ok := remInline(xVal, yVal, xNeg, yNeg); ok { z.updateInnerFromUint64(remVal, remNeg) return z } } } var tmp1, tmp2, tmp3 big.Int //gcassert:noescape zi := z.inner(&tmp1) zi.Rem(x.inner(&tmp2), y.inner(&tmp3)) z.updateInner(zi) return z } // Rsh calls (big.Int).Rsh. func (z *BigInt) Rsh(x *BigInt, n uint) *BigInt { var tmp1, tmp2 big.Int //gcassert:noescape zi := z.inner(&tmp1) zi.Rsh(x.inner(&tmp2), n) z.updateInner(zi) return z } // Scan calls (big.Int).Scan. func (z *BigInt) Scan(s fmt.ScanState, ch rune) error { var tmp1 big.Int //gcassert:noescape zi := z.inner(&tmp1) if err := zi.Scan(s, ch); err != nil { return err } z.updateInner(zi) return nil } // Set calls (big.Int).Set. func (z *BigInt) Set(x *BigInt) *BigInt { if x.isInline() { *z = *x return z } var tmp1, tmp2 big.Int //gcassert:noescape zi := z.inner(&tmp1) zi.Set(x.inner(&tmp2)) z.updateInner(zi) return z } // SetBit calls (big.Int).SetBit. func (z *BigInt) SetBit(x *BigInt, i int, b uint) *BigInt { var tmp1, tmp2 big.Int //gcassert:noescape zi := z.inner(&tmp1) zi.SetBit(x.inner(&tmp2), i, b) z.updateInner(zi) return z } // SetBits calls (big.Int).SetBits. func (z *BigInt) SetBits(abs []big.Word) *BigInt { var tmp1 big.Int //gcassert:noescape zi := z.inner(&tmp1) zi.SetBits(abs) z.updateInner(zi) return z } // SetBytes calls (big.Int).SetBytes. func (z *BigInt) SetBytes(buf []byte) *BigInt { var tmp1 big.Int //gcassert:noescape zi := z.inner(&tmp1) zi.SetBytes(buf) z.updateInner(zi) return z } // SetInt64 calls (big.Int).SetInt64. func (z *BigInt) SetInt64(x int64) *BigInt { neg := false if x < 0 { neg = true x = -x } z.updateInnerFromUint64(uint64(x), neg) return z } // SetString calls (big.Int).SetString. func (z *BigInt) SetString(s string, base int) (*BigInt, bool) { if i, err := strconv.ParseInt(s, base, 64); err == nil { z.SetInt64(i) return z, true } var tmp1 big.Int //gcassert:noescape zi := z.inner(&tmp1) if _, ok := zi.SetString(s, base); !ok { return nil, false } z.updateInner(zi) return z, true } // SetUint64 calls (big.Int).SetUint64. func (z *BigInt) SetUint64(x uint64) *BigInt { z.updateInnerFromUint64(x, false) return z } // Sign calls (big.Int).Sign. func (z *BigInt) Sign() int { if z._inner == nil { if z._inline == [inlineWords]big.Word{} { return 0 } return 1 } else if z._inner == negSentinel { return -1 } return z._inner.Sign() } // Sqrt calls (big.Int).Sqrt. func (z *BigInt) Sqrt(x *BigInt) *BigInt { var tmp1, tmp2 big.Int //gcassert:noescape zi := z.inner(&tmp1) zi.Sqrt(x.inner(&tmp2)) z.updateInner(zi) return z } // String calls (big.Int).String. func (z *BigInt) String() string { if z == nil { // Fast-path that avoids innerOrNil, allowing inner to be inlined. return "" } var tmp1 big.Int //gcassert:noescape return z.inner(&tmp1).String() } // Sub calls (big.Int).Sub. func (z *BigInt) Sub(x, y *BigInt) *BigInt { if xVal, xNeg, ok := x.innerAsUint64(); ok { if yVal, yNeg, ok := y.innerAsUint64(); ok { if zVal, zNeg, ok := addInline(xVal, yVal, xNeg, !yNeg); ok { z.updateInnerFromUint64(zVal, zNeg) return z } } } var tmp1, tmp2, tmp3 big.Int //gcassert:noescape zi := z.inner(&tmp1) zi.Sub(x.inner(&tmp2), y.inner(&tmp3)) z.updateInner(zi) return z } // Text calls (big.Int).Text. func (z *BigInt) Text(base int) string { if z == nil { // Fast-path that avoids innerOrNil, allowing inner to be inlined. return "" } var tmp1 big.Int //gcassert:noescape return z.inner(&tmp1).Text(base) } // TrailingZeroBits calls (big.Int).TrailingZeroBits. func (z *BigInt) TrailingZeroBits() uint { var tmp1 big.Int //gcassert:noescape return z.inner(&tmp1).TrailingZeroBits() } // Uint64 calls (big.Int).Uint64. func (z *BigInt) Uint64() uint64 { if zVal, _, ok := z.innerAsUint64(); ok { return zVal } var tmp1 big.Int //gcassert:noescape return z.inner(&tmp1).Uint64() } // UnmarshalJSON calls (big.Int).UnmarshalJSON. func (z *BigInt) UnmarshalJSON(text []byte) error { var tmp1 big.Int //gcassert:noescape zi := z.inner(&tmp1) if err := zi.UnmarshalJSON(text); err != nil { return err } z.updateInner(zi) return nil } // UnmarshalText calls (big.Int).UnmarshalText. func (z *BigInt) UnmarshalText(text []byte) error { var tmp1 big.Int //gcassert:noescape zi := z.inner(&tmp1) if err := zi.UnmarshalText(text); err != nil { return err } z.updateInner(zi) return nil } // Xor calls (big.Int).Xor. func (z *BigInt) Xor(x, y *BigInt) *BigInt { var tmp1, tmp2, tmp3 big.Int //gcassert:noescape zi := z.inner(&tmp1) zi.Xor(x.inner(&tmp2), y.inner(&tmp3)) z.updateInner(zi) return z } /////////////////////////////////////////////////////////////////////////////// // apd.BigInt / math/big.Int interop // /////////////////////////////////////////////////////////////////////////////// // MathBigInt returns the math/big.Int representation of z. func (z *BigInt) MathBigInt() *big.Int { var tmp1 big.Int //gcassert:noescape zi := z.inner(&tmp1) // NOTE: We can't return zi directly, because it may be pointing into z's // _inline array. We have disabled escape analysis for such aliasing, so // this would be unsafe as it would not force the receiver to escape and // could leave the return value pointing into stack memory. return new(big.Int).Set(zi) } // SetMathBigInt sets z to x and returns z. func (z *BigInt) SetMathBigInt(x *big.Int) *BigInt { var tmp1 big.Int //gcassert:noescape zi := z.inner(&tmp1) zi.Set(x) z.updateInner(zi) return z }