xref: /aosp_15_r20/external/starlark-go/starlark/int.go (revision 4947cdc739c985f6d86941e22894f5cefe7c9e9a)
1*4947cdc7SCole Faust// Copyright 2017 The Bazel Authors. All rights reserved.
2*4947cdc7SCole Faust// Use of this source code is governed by a BSD-style
3*4947cdc7SCole Faust// license that can be found in the LICENSE file.
4*4947cdc7SCole Faust
5*4947cdc7SCole Faustpackage starlark
6*4947cdc7SCole Faust
7*4947cdc7SCole Faustimport (
8*4947cdc7SCole Faust	"fmt"
9*4947cdc7SCole Faust	"math"
10*4947cdc7SCole Faust	"math/big"
11*4947cdc7SCole Faust	"reflect"
12*4947cdc7SCole Faust	"strconv"
13*4947cdc7SCole Faust
14*4947cdc7SCole Faust	"go.starlark.net/syntax"
15*4947cdc7SCole Faust)
16*4947cdc7SCole Faust
17*4947cdc7SCole Faust// Int is the type of a Starlark int.
18*4947cdc7SCole Faust//
19*4947cdc7SCole Faust// The zero value is not a legal value; use MakeInt(0).
20*4947cdc7SCole Fausttype Int struct{ impl intImpl }
21*4947cdc7SCole Faust
22*4947cdc7SCole Faust// --- high-level accessors ---
23*4947cdc7SCole Faust
24*4947cdc7SCole Faust// MakeInt returns a Starlark int for the specified signed integer.
25*4947cdc7SCole Faustfunc MakeInt(x int) Int { return MakeInt64(int64(x)) }
26*4947cdc7SCole Faust
27*4947cdc7SCole Faust// MakeInt64 returns a Starlark int for the specified int64.
28*4947cdc7SCole Faustfunc MakeInt64(x int64) Int {
29*4947cdc7SCole Faust	if math.MinInt32 <= x && x <= math.MaxInt32 {
30*4947cdc7SCole Faust		return makeSmallInt(x)
31*4947cdc7SCole Faust	}
32*4947cdc7SCole Faust	return makeBigInt(big.NewInt(x))
33*4947cdc7SCole Faust}
34*4947cdc7SCole Faust
35*4947cdc7SCole Faust// MakeUint returns a Starlark int for the specified unsigned integer.
36*4947cdc7SCole Faustfunc MakeUint(x uint) Int { return MakeUint64(uint64(x)) }
37*4947cdc7SCole Faust
38*4947cdc7SCole Faust// MakeUint64 returns a Starlark int for the specified uint64.
39*4947cdc7SCole Faustfunc MakeUint64(x uint64) Int {
40*4947cdc7SCole Faust	if x <= math.MaxInt32 {
41*4947cdc7SCole Faust		return makeSmallInt(int64(x))
42*4947cdc7SCole Faust	}
43*4947cdc7SCole Faust	return makeBigInt(new(big.Int).SetUint64(x))
44*4947cdc7SCole Faust}
45*4947cdc7SCole Faust
46*4947cdc7SCole Faust// MakeBigInt returns a Starlark int for the specified big.Int.
47*4947cdc7SCole Faust// The new Int value will contain a copy of x. The caller is safe to modify x.
48*4947cdc7SCole Faustfunc MakeBigInt(x *big.Int) Int {
49*4947cdc7SCole Faust	if n := x.BitLen(); n < 32 || n == 32 && x.Int64() == math.MinInt32 {
50*4947cdc7SCole Faust		return makeSmallInt(x.Int64())
51*4947cdc7SCole Faust	}
52*4947cdc7SCole Faust	z := new(big.Int).Set(x)
53*4947cdc7SCole Faust	return makeBigInt(z)
54*4947cdc7SCole Faust}
55*4947cdc7SCole Faust
56*4947cdc7SCole Faustvar (
57*4947cdc7SCole Faust	zero, one = makeSmallInt(0), makeSmallInt(1)
58*4947cdc7SCole Faust	oneBig    = big.NewInt(1)
59*4947cdc7SCole Faust
60*4947cdc7SCole Faust	_ HasUnary = Int{}
61*4947cdc7SCole Faust)
62*4947cdc7SCole Faust
63*4947cdc7SCole Faust// Unary implements the operations +int, -int, and ~int.
64*4947cdc7SCole Faustfunc (i Int) Unary(op syntax.Token) (Value, error) {
65*4947cdc7SCole Faust	switch op {
66*4947cdc7SCole Faust	case syntax.MINUS:
67*4947cdc7SCole Faust		return zero.Sub(i), nil
68*4947cdc7SCole Faust	case syntax.PLUS:
69*4947cdc7SCole Faust		return i, nil
70*4947cdc7SCole Faust	case syntax.TILDE:
71*4947cdc7SCole Faust		return i.Not(), nil
72*4947cdc7SCole Faust	}
73*4947cdc7SCole Faust	return nil, nil
74*4947cdc7SCole Faust}
75*4947cdc7SCole Faust
76*4947cdc7SCole Faust// Int64 returns the value as an int64.
77*4947cdc7SCole Faust// If it is not exactly representable the result is undefined and ok is false.
78*4947cdc7SCole Faustfunc (i Int) Int64() (_ int64, ok bool) {
79*4947cdc7SCole Faust	iSmall, iBig := i.get()
80*4947cdc7SCole Faust	if iBig != nil {
81*4947cdc7SCole Faust		x, acc := bigintToInt64(iBig)
82*4947cdc7SCole Faust		if acc != big.Exact {
83*4947cdc7SCole Faust			return // inexact
84*4947cdc7SCole Faust		}
85*4947cdc7SCole Faust		return x, true
86*4947cdc7SCole Faust	}
87*4947cdc7SCole Faust	return iSmall, true
88*4947cdc7SCole Faust}
89*4947cdc7SCole Faust
90*4947cdc7SCole Faust// BigInt returns a new big.Int with the same value as the Int.
91*4947cdc7SCole Faustfunc (i Int) BigInt() *big.Int {
92*4947cdc7SCole Faust	iSmall, iBig := i.get()
93*4947cdc7SCole Faust	if iBig != nil {
94*4947cdc7SCole Faust		return new(big.Int).Set(iBig)
95*4947cdc7SCole Faust	}
96*4947cdc7SCole Faust	return big.NewInt(iSmall)
97*4947cdc7SCole Faust}
98*4947cdc7SCole Faust
99*4947cdc7SCole Faust// bigInt returns the value as a big.Int.
100*4947cdc7SCole Faust// It differs from BigInt in that this method returns the actual
101*4947cdc7SCole Faust// reference and any modification will change the state of i.
102*4947cdc7SCole Faustfunc (i Int) bigInt() *big.Int {
103*4947cdc7SCole Faust	iSmall, iBig := i.get()
104*4947cdc7SCole Faust	if iBig != nil {
105*4947cdc7SCole Faust		return iBig
106*4947cdc7SCole Faust	}
107*4947cdc7SCole Faust	return big.NewInt(iSmall)
108*4947cdc7SCole Faust}
109*4947cdc7SCole Faust
110*4947cdc7SCole Faust// Uint64 returns the value as a uint64.
111*4947cdc7SCole Faust// If it is not exactly representable the result is undefined and ok is false.
112*4947cdc7SCole Faustfunc (i Int) Uint64() (_ uint64, ok bool) {
113*4947cdc7SCole Faust	iSmall, iBig := i.get()
114*4947cdc7SCole Faust	if iBig != nil {
115*4947cdc7SCole Faust		x, acc := bigintToUint64(iBig)
116*4947cdc7SCole Faust		if acc != big.Exact {
117*4947cdc7SCole Faust			return // inexact
118*4947cdc7SCole Faust		}
119*4947cdc7SCole Faust		return x, true
120*4947cdc7SCole Faust	}
121*4947cdc7SCole Faust	if iSmall < 0 {
122*4947cdc7SCole Faust		return // inexact
123*4947cdc7SCole Faust	}
124*4947cdc7SCole Faust	return uint64(iSmall), true
125*4947cdc7SCole Faust}
126*4947cdc7SCole Faust
127*4947cdc7SCole Faust// The math/big API should provide this function.
128*4947cdc7SCole Faustfunc bigintToInt64(i *big.Int) (int64, big.Accuracy) {
129*4947cdc7SCole Faust	sign := i.Sign()
130*4947cdc7SCole Faust	if sign > 0 {
131*4947cdc7SCole Faust		if i.Cmp(maxint64) > 0 {
132*4947cdc7SCole Faust			return math.MaxInt64, big.Below
133*4947cdc7SCole Faust		}
134*4947cdc7SCole Faust	} else if sign < 0 {
135*4947cdc7SCole Faust		if i.Cmp(minint64) < 0 {
136*4947cdc7SCole Faust			return math.MinInt64, big.Above
137*4947cdc7SCole Faust		}
138*4947cdc7SCole Faust	}
139*4947cdc7SCole Faust	return i.Int64(), big.Exact
140*4947cdc7SCole Faust}
141*4947cdc7SCole Faust
142*4947cdc7SCole Faust// The math/big API should provide this function.
143*4947cdc7SCole Faustfunc bigintToUint64(i *big.Int) (uint64, big.Accuracy) {
144*4947cdc7SCole Faust	sign := i.Sign()
145*4947cdc7SCole Faust	if sign > 0 {
146*4947cdc7SCole Faust		if i.BitLen() > 64 {
147*4947cdc7SCole Faust			return math.MaxUint64, big.Below
148*4947cdc7SCole Faust		}
149*4947cdc7SCole Faust	} else if sign < 0 {
150*4947cdc7SCole Faust		return 0, big.Above
151*4947cdc7SCole Faust	}
152*4947cdc7SCole Faust	return i.Uint64(), big.Exact
153*4947cdc7SCole Faust}
154*4947cdc7SCole Faust
155*4947cdc7SCole Faustvar (
156*4947cdc7SCole Faust	minint64 = new(big.Int).SetInt64(math.MinInt64)
157*4947cdc7SCole Faust	maxint64 = new(big.Int).SetInt64(math.MaxInt64)
158*4947cdc7SCole Faust)
159*4947cdc7SCole Faust
160*4947cdc7SCole Faustfunc (i Int) Format(s fmt.State, ch rune) {
161*4947cdc7SCole Faust	iSmall, iBig := i.get()
162*4947cdc7SCole Faust	if iBig != nil {
163*4947cdc7SCole Faust		iBig.Format(s, ch)
164*4947cdc7SCole Faust		return
165*4947cdc7SCole Faust	}
166*4947cdc7SCole Faust	big.NewInt(iSmall).Format(s, ch)
167*4947cdc7SCole Faust}
168*4947cdc7SCole Faustfunc (i Int) String() string {
169*4947cdc7SCole Faust	iSmall, iBig := i.get()
170*4947cdc7SCole Faust	if iBig != nil {
171*4947cdc7SCole Faust		return iBig.Text(10)
172*4947cdc7SCole Faust	}
173*4947cdc7SCole Faust	return strconv.FormatInt(iSmall, 10)
174*4947cdc7SCole Faust}
175*4947cdc7SCole Faustfunc (i Int) Type() string { return "int" }
176*4947cdc7SCole Faustfunc (i Int) Freeze()      {} // immutable
177*4947cdc7SCole Faustfunc (i Int) Truth() Bool  { return i.Sign() != 0 }
178*4947cdc7SCole Faustfunc (i Int) Hash() (uint32, error) {
179*4947cdc7SCole Faust	iSmall, iBig := i.get()
180*4947cdc7SCole Faust	var lo big.Word
181*4947cdc7SCole Faust	if iBig != nil {
182*4947cdc7SCole Faust		lo = iBig.Bits()[0]
183*4947cdc7SCole Faust	} else {
184*4947cdc7SCole Faust		lo = big.Word(iSmall)
185*4947cdc7SCole Faust	}
186*4947cdc7SCole Faust	return 12582917 * uint32(lo+3), nil
187*4947cdc7SCole Faust}
188*4947cdc7SCole Faustfunc (x Int) CompareSameType(op syntax.Token, v Value, depth int) (bool, error) {
189*4947cdc7SCole Faust	y := v.(Int)
190*4947cdc7SCole Faust	xSmall, xBig := x.get()
191*4947cdc7SCole Faust	ySmall, yBig := y.get()
192*4947cdc7SCole Faust	if xBig != nil || yBig != nil {
193*4947cdc7SCole Faust		return threeway(op, x.bigInt().Cmp(y.bigInt())), nil
194*4947cdc7SCole Faust	}
195*4947cdc7SCole Faust	return threeway(op, signum64(xSmall-ySmall)), nil
196*4947cdc7SCole Faust}
197*4947cdc7SCole Faust
198*4947cdc7SCole Faust// Float returns the float value nearest i.
199*4947cdc7SCole Faustfunc (i Int) Float() Float {
200*4947cdc7SCole Faust	iSmall, iBig := i.get()
201*4947cdc7SCole Faust	if iBig != nil {
202*4947cdc7SCole Faust		f, _ := new(big.Float).SetInt(iBig).Float64()
203*4947cdc7SCole Faust		return Float(f)
204*4947cdc7SCole Faust	}
205*4947cdc7SCole Faust	return Float(iSmall)
206*4947cdc7SCole Faust}
207*4947cdc7SCole Faust
208*4947cdc7SCole Faust// finiteFloat returns the finite float value nearest i,
209*4947cdc7SCole Faust// or an error if the magnitude is too large.
210*4947cdc7SCole Faustfunc (i Int) finiteFloat() (Float, error) {
211*4947cdc7SCole Faust	f := i.Float()
212*4947cdc7SCole Faust	if math.IsInf(float64(f), 0) {
213*4947cdc7SCole Faust		return 0, fmt.Errorf("int too large to convert to float")
214*4947cdc7SCole Faust	}
215*4947cdc7SCole Faust	return f, nil
216*4947cdc7SCole Faust}
217*4947cdc7SCole Faust
218*4947cdc7SCole Faustfunc (x Int) Sign() int {
219*4947cdc7SCole Faust	xSmall, xBig := x.get()
220*4947cdc7SCole Faust	if xBig != nil {
221*4947cdc7SCole Faust		return xBig.Sign()
222*4947cdc7SCole Faust	}
223*4947cdc7SCole Faust	return signum64(xSmall)
224*4947cdc7SCole Faust}
225*4947cdc7SCole Faust
226*4947cdc7SCole Faustfunc (x Int) Add(y Int) Int {
227*4947cdc7SCole Faust	xSmall, xBig := x.get()
228*4947cdc7SCole Faust	ySmall, yBig := y.get()
229*4947cdc7SCole Faust	if xBig != nil || yBig != nil {
230*4947cdc7SCole Faust		return MakeBigInt(new(big.Int).Add(x.bigInt(), y.bigInt()))
231*4947cdc7SCole Faust	}
232*4947cdc7SCole Faust	return MakeInt64(xSmall + ySmall)
233*4947cdc7SCole Faust}
234*4947cdc7SCole Faustfunc (x Int) Sub(y Int) Int {
235*4947cdc7SCole Faust	xSmall, xBig := x.get()
236*4947cdc7SCole Faust	ySmall, yBig := y.get()
237*4947cdc7SCole Faust	if xBig != nil || yBig != nil {
238*4947cdc7SCole Faust		return MakeBigInt(new(big.Int).Sub(x.bigInt(), y.bigInt()))
239*4947cdc7SCole Faust	}
240*4947cdc7SCole Faust	return MakeInt64(xSmall - ySmall)
241*4947cdc7SCole Faust}
242*4947cdc7SCole Faustfunc (x Int) Mul(y Int) Int {
243*4947cdc7SCole Faust	xSmall, xBig := x.get()
244*4947cdc7SCole Faust	ySmall, yBig := y.get()
245*4947cdc7SCole Faust	if xBig != nil || yBig != nil {
246*4947cdc7SCole Faust		return MakeBigInt(new(big.Int).Mul(x.bigInt(), y.bigInt()))
247*4947cdc7SCole Faust	}
248*4947cdc7SCole Faust	return MakeInt64(xSmall * ySmall)
249*4947cdc7SCole Faust}
250*4947cdc7SCole Faustfunc (x Int) Or(y Int) Int {
251*4947cdc7SCole Faust	xSmall, xBig := x.get()
252*4947cdc7SCole Faust	ySmall, yBig := y.get()
253*4947cdc7SCole Faust	if xBig != nil || yBig != nil {
254*4947cdc7SCole Faust		return MakeBigInt(new(big.Int).Or(x.bigInt(), y.bigInt()))
255*4947cdc7SCole Faust	}
256*4947cdc7SCole Faust	return makeSmallInt(xSmall | ySmall)
257*4947cdc7SCole Faust}
258*4947cdc7SCole Faustfunc (x Int) And(y Int) Int {
259*4947cdc7SCole Faust	xSmall, xBig := x.get()
260*4947cdc7SCole Faust	ySmall, yBig := y.get()
261*4947cdc7SCole Faust	if xBig != nil || yBig != nil {
262*4947cdc7SCole Faust		return MakeBigInt(new(big.Int).And(x.bigInt(), y.bigInt()))
263*4947cdc7SCole Faust	}
264*4947cdc7SCole Faust	return makeSmallInt(xSmall & ySmall)
265*4947cdc7SCole Faust}
266*4947cdc7SCole Faustfunc (x Int) Xor(y Int) Int {
267*4947cdc7SCole Faust	xSmall, xBig := x.get()
268*4947cdc7SCole Faust	ySmall, yBig := y.get()
269*4947cdc7SCole Faust	if xBig != nil || yBig != nil {
270*4947cdc7SCole Faust		return MakeBigInt(new(big.Int).Xor(x.bigInt(), y.bigInt()))
271*4947cdc7SCole Faust	}
272*4947cdc7SCole Faust	return makeSmallInt(xSmall ^ ySmall)
273*4947cdc7SCole Faust}
274*4947cdc7SCole Faustfunc (x Int) Not() Int {
275*4947cdc7SCole Faust	xSmall, xBig := x.get()
276*4947cdc7SCole Faust	if xBig != nil {
277*4947cdc7SCole Faust		return MakeBigInt(new(big.Int).Not(xBig))
278*4947cdc7SCole Faust	}
279*4947cdc7SCole Faust	return makeSmallInt(^xSmall)
280*4947cdc7SCole Faust}
281*4947cdc7SCole Faustfunc (x Int) Lsh(y uint) Int { return MakeBigInt(new(big.Int).Lsh(x.bigInt(), y)) }
282*4947cdc7SCole Faustfunc (x Int) Rsh(y uint) Int { return MakeBigInt(new(big.Int).Rsh(x.bigInt(), y)) }
283*4947cdc7SCole Faust
284*4947cdc7SCole Faust// Precondition: y is nonzero.
285*4947cdc7SCole Faustfunc (x Int) Div(y Int) Int {
286*4947cdc7SCole Faust	xSmall, xBig := x.get()
287*4947cdc7SCole Faust	ySmall, yBig := y.get()
288*4947cdc7SCole Faust	// http://python-history.blogspot.com/2010/08/why-pythons-integer-division-floors.html
289*4947cdc7SCole Faust	if xBig != nil || yBig != nil {
290*4947cdc7SCole Faust		xb, yb := x.bigInt(), y.bigInt()
291*4947cdc7SCole Faust
292*4947cdc7SCole Faust		var quo, rem big.Int
293*4947cdc7SCole Faust		quo.QuoRem(xb, yb, &rem)
294*4947cdc7SCole Faust		if (xb.Sign() < 0) != (yb.Sign() < 0) && rem.Sign() != 0 {
295*4947cdc7SCole Faust			quo.Sub(&quo, oneBig)
296*4947cdc7SCole Faust		}
297*4947cdc7SCole Faust		return MakeBigInt(&quo)
298*4947cdc7SCole Faust	}
299*4947cdc7SCole Faust	quo := xSmall / ySmall
300*4947cdc7SCole Faust	rem := xSmall % ySmall
301*4947cdc7SCole Faust	if (xSmall < 0) != (ySmall < 0) && rem != 0 {
302*4947cdc7SCole Faust		quo -= 1
303*4947cdc7SCole Faust	}
304*4947cdc7SCole Faust	return MakeInt64(quo)
305*4947cdc7SCole Faust}
306*4947cdc7SCole Faust
307*4947cdc7SCole Faust// Precondition: y is nonzero.
308*4947cdc7SCole Faustfunc (x Int) Mod(y Int) Int {
309*4947cdc7SCole Faust	xSmall, xBig := x.get()
310*4947cdc7SCole Faust	ySmall, yBig := y.get()
311*4947cdc7SCole Faust	if xBig != nil || yBig != nil {
312*4947cdc7SCole Faust		xb, yb := x.bigInt(), y.bigInt()
313*4947cdc7SCole Faust
314*4947cdc7SCole Faust		var quo, rem big.Int
315*4947cdc7SCole Faust		quo.QuoRem(xb, yb, &rem)
316*4947cdc7SCole Faust		if (xb.Sign() < 0) != (yb.Sign() < 0) && rem.Sign() != 0 {
317*4947cdc7SCole Faust			rem.Add(&rem, yb)
318*4947cdc7SCole Faust		}
319*4947cdc7SCole Faust		return MakeBigInt(&rem)
320*4947cdc7SCole Faust	}
321*4947cdc7SCole Faust	rem := xSmall % ySmall
322*4947cdc7SCole Faust	if (xSmall < 0) != (ySmall < 0) && rem != 0 {
323*4947cdc7SCole Faust		rem += ySmall
324*4947cdc7SCole Faust	}
325*4947cdc7SCole Faust	return makeSmallInt(rem)
326*4947cdc7SCole Faust}
327*4947cdc7SCole Faust
328*4947cdc7SCole Faustfunc (i Int) rational() *big.Rat {
329*4947cdc7SCole Faust	iSmall, iBig := i.get()
330*4947cdc7SCole Faust	if iBig != nil {
331*4947cdc7SCole Faust		return new(big.Rat).SetInt(iBig)
332*4947cdc7SCole Faust	}
333*4947cdc7SCole Faust	return new(big.Rat).SetInt64(iSmall)
334*4947cdc7SCole Faust}
335*4947cdc7SCole Faust
336*4947cdc7SCole Faust// AsInt32 returns the value of x if is representable as an int32.
337*4947cdc7SCole Faustfunc AsInt32(x Value) (int, error) {
338*4947cdc7SCole Faust	i, ok := x.(Int)
339*4947cdc7SCole Faust	if !ok {
340*4947cdc7SCole Faust		return 0, fmt.Errorf("got %s, want int", x.Type())
341*4947cdc7SCole Faust	}
342*4947cdc7SCole Faust	iSmall, iBig := i.get()
343*4947cdc7SCole Faust	if iBig != nil {
344*4947cdc7SCole Faust		return 0, fmt.Errorf("%s out of range", i)
345*4947cdc7SCole Faust	}
346*4947cdc7SCole Faust	return int(iSmall), nil
347*4947cdc7SCole Faust}
348*4947cdc7SCole Faust
349*4947cdc7SCole Faust// AsInt sets *ptr to the value of Starlark int x, if it is exactly representable,
350*4947cdc7SCole Faust// otherwise it returns an error.
351*4947cdc7SCole Faust// The type of ptr must be one of the pointer types *int, *int8, *int16, *int32, or *int64,
352*4947cdc7SCole Faust// or one of their unsigned counterparts including *uintptr.
353*4947cdc7SCole Faustfunc AsInt(x Value, ptr interface{}) error {
354*4947cdc7SCole Faust	xint, ok := x.(Int)
355*4947cdc7SCole Faust	if !ok {
356*4947cdc7SCole Faust		return fmt.Errorf("got %s, want int", x.Type())
357*4947cdc7SCole Faust	}
358*4947cdc7SCole Faust
359*4947cdc7SCole Faust	bits := reflect.TypeOf(ptr).Elem().Size() * 8
360*4947cdc7SCole Faust	switch ptr.(type) {
361*4947cdc7SCole Faust	case *int, *int8, *int16, *int32, *int64:
362*4947cdc7SCole Faust		i, ok := xint.Int64()
363*4947cdc7SCole Faust		if !ok || bits < 64 && !(-1<<(bits-1) <= i && i < 1<<(bits-1)) {
364*4947cdc7SCole Faust			return fmt.Errorf("%s out of range (want value in signed %d-bit range)", xint, bits)
365*4947cdc7SCole Faust		}
366*4947cdc7SCole Faust		switch ptr := ptr.(type) {
367*4947cdc7SCole Faust		case *int:
368*4947cdc7SCole Faust			*ptr = int(i)
369*4947cdc7SCole Faust		case *int8:
370*4947cdc7SCole Faust			*ptr = int8(i)
371*4947cdc7SCole Faust		case *int16:
372*4947cdc7SCole Faust			*ptr = int16(i)
373*4947cdc7SCole Faust		case *int32:
374*4947cdc7SCole Faust			*ptr = int32(i)
375*4947cdc7SCole Faust		case *int64:
376*4947cdc7SCole Faust			*ptr = int64(i)
377*4947cdc7SCole Faust		}
378*4947cdc7SCole Faust
379*4947cdc7SCole Faust	case *uint, *uint8, *uint16, *uint32, *uint64, *uintptr:
380*4947cdc7SCole Faust		i, ok := xint.Uint64()
381*4947cdc7SCole Faust		if !ok || bits < 64 && i >= 1<<bits {
382*4947cdc7SCole Faust			return fmt.Errorf("%s out of range (want value in unsigned %d-bit range)", xint, bits)
383*4947cdc7SCole Faust		}
384*4947cdc7SCole Faust		switch ptr := ptr.(type) {
385*4947cdc7SCole Faust		case *uint:
386*4947cdc7SCole Faust			*ptr = uint(i)
387*4947cdc7SCole Faust		case *uint8:
388*4947cdc7SCole Faust			*ptr = uint8(i)
389*4947cdc7SCole Faust		case *uint16:
390*4947cdc7SCole Faust			*ptr = uint16(i)
391*4947cdc7SCole Faust		case *uint32:
392*4947cdc7SCole Faust			*ptr = uint32(i)
393*4947cdc7SCole Faust		case *uint64:
394*4947cdc7SCole Faust			*ptr = uint64(i)
395*4947cdc7SCole Faust		case *uintptr:
396*4947cdc7SCole Faust			*ptr = uintptr(i)
397*4947cdc7SCole Faust		}
398*4947cdc7SCole Faust	default:
399*4947cdc7SCole Faust		panic(fmt.Sprintf("invalid argument type: %T", ptr))
400*4947cdc7SCole Faust	}
401*4947cdc7SCole Faust	return nil
402*4947cdc7SCole Faust}
403*4947cdc7SCole Faust
404*4947cdc7SCole Faust// NumberToInt converts a number x to an integer value.
405*4947cdc7SCole Faust// An int is returned unchanged, a float is truncated towards zero.
406*4947cdc7SCole Faust// NumberToInt reports an error for all other values.
407*4947cdc7SCole Faustfunc NumberToInt(x Value) (Int, error) {
408*4947cdc7SCole Faust	switch x := x.(type) {
409*4947cdc7SCole Faust	case Int:
410*4947cdc7SCole Faust		return x, nil
411*4947cdc7SCole Faust	case Float:
412*4947cdc7SCole Faust		f := float64(x)
413*4947cdc7SCole Faust		if math.IsInf(f, 0) {
414*4947cdc7SCole Faust			return zero, fmt.Errorf("cannot convert float infinity to integer")
415*4947cdc7SCole Faust		} else if math.IsNaN(f) {
416*4947cdc7SCole Faust			return zero, fmt.Errorf("cannot convert float NaN to integer")
417*4947cdc7SCole Faust		}
418*4947cdc7SCole Faust		return finiteFloatToInt(x), nil
419*4947cdc7SCole Faust
420*4947cdc7SCole Faust	}
421*4947cdc7SCole Faust	return zero, fmt.Errorf("cannot convert %s to int", x.Type())
422*4947cdc7SCole Faust}
423*4947cdc7SCole Faust
424*4947cdc7SCole Faust// finiteFloatToInt converts f to an Int, truncating towards zero.
425*4947cdc7SCole Faust// f must be finite.
426*4947cdc7SCole Faustfunc finiteFloatToInt(f Float) Int {
427*4947cdc7SCole Faust	if math.MinInt64 <= f && f <= math.MaxInt64 {
428*4947cdc7SCole Faust		// small values
429*4947cdc7SCole Faust		return MakeInt64(int64(f))
430*4947cdc7SCole Faust	}
431*4947cdc7SCole Faust	rat := f.rational()
432*4947cdc7SCole Faust	if rat == nil {
433*4947cdc7SCole Faust		panic(f) // non-finite
434*4947cdc7SCole Faust	}
435*4947cdc7SCole Faust	return MakeBigInt(new(big.Int).Div(rat.Num(), rat.Denom()))
436*4947cdc7SCole Faust}
437