From 487c5cc294d4c0506e50a026737be7f4cc94436f Mon Sep 17 00:00:00 2001
From: obscuren <geffobscura@gmail.com>
Date: Wed, 18 Feb 2015 17:18:07 +0100
Subject: Added WIP number package

---
 ethutil/number/int.go       | 181 ++++++++++++++++++++++++++++++++++++++++++++
 ethutil/number/uint_test.go |  92 ++++++++++++++++++++++
 2 files changed, 273 insertions(+)
 create mode 100644 ethutil/number/int.go
 create mode 100644 ethutil/number/uint_test.go

(limited to 'ethutil/number')

diff --git a/ethutil/number/int.go b/ethutil/number/int.go
new file mode 100644
index 000000000..9a41fe3e5
--- /dev/null
+++ b/ethutil/number/int.go
@@ -0,0 +1,181 @@
+package number
+
+import (
+	"math/big"
+
+	"github.com/ethereum/go-ethereum/ethutil"
+)
+
+var tt256 = new(big.Int).Lsh(big.NewInt(1), 256)
+var tt256m1 = new(big.Int).Sub(new(big.Int).Lsh(big.NewInt(1), 256), big.NewInt(1))
+var tt255 = new(big.Int).Lsh(big.NewInt(1), 255)
+
+func limitUnsigned256(x *Number) *Number {
+	x.num.And(x.num, tt256m1)
+	return x
+}
+
+func limitSigned256(x *Number) *Number {
+	if x.num.Cmp(tt255) < 0 {
+		return x
+	} else {
+		x.num.Sub(x.num, tt256)
+		return x
+	}
+}
+
+// Number function
+type Initialiser func(n int64) *Number
+
+// A Number represents a generic integer with a bounding function limiter. Limit is called after each operations
+// to give "fake" bounded integers. New types of Number can be created through NewInitialiser returning a lambda
+// with the new Initialiser.
+type Number struct {
+	num   *big.Int
+	limit func(n *Number) *Number
+}
+
+// Returns a new initialiser for a new *Number without having to expose certain fields
+func NewInitialiser(limiter func(*Number) *Number) Initialiser {
+	return func(n int64) *Number {
+		return &Number{big.NewInt(n), limiter}
+	}
+}
+
+// Return a Number with a UNSIGNED limiter up to 256 bits
+func Uint256(n int64) *Number {
+	return &Number{big.NewInt(n), limitUnsigned256}
+}
+
+// Return a Number with a SIGNED limiter up to 256 bits
+func Int256(n int64) *Number {
+	return &Number{big.NewInt(n), limitSigned256}
+}
+
+// Returns a Number with a SIGNED unlimited size
+func Big(n int64) *Number {
+	return &Number{big.NewInt(n), func(x *Number) *Number { return x }}
+}
+
+// Sets i to sum of x+y
+func (i *Number) Add(x, y *Number) *Number {
+	i.num.Add(x.num, y.num)
+	return i.limit(i)
+}
+
+// Sets i to difference of x-y
+func (i *Number) Sub(x, y *Number) *Number {
+	i.num.Sub(x.num, y.num)
+	return i.limit(i)
+}
+
+// Sets i to product of x*y
+func (i *Number) Mul(x, y *Number) *Number {
+	i.num.Mul(x.num, y.num)
+	return i.limit(i)
+}
+
+// Sets i to the quotient prodject of x/y
+func (i *Number) Div(x, y *Number) *Number {
+	i.num.Div(x.num, y.num)
+	return i.limit(i)
+}
+
+// Sets i to x % y
+func (i *Number) Mod(x, y *Number) *Number {
+	i.num.Mod(x.num, y.num)
+	return i.limit(i)
+}
+
+// Sets i to x << s
+func (i *Number) Lsh(x *Number, s uint) *Number {
+	i.num.Lsh(x.num, s)
+	return i.limit(i)
+}
+
+// Sets i to x^y
+func (i *Number) Pow(x, y *Number) *Number {
+	i.num.Exp(x.num, y.num, big.NewInt(0))
+	return i.limit(i)
+}
+
+// Setters
+
+// Set x to i
+func (i *Number) Set(x *Number) *Number {
+	i.num.Set(x.num)
+	return i.limit(i)
+}
+
+// Set x bytes to i
+func (i *Number) SetBytes(x []byte) *Number {
+	i.num.SetBytes(x)
+	return i.limit(i)
+}
+
+// Cmp compares x and y and returns:
+//
+//     -1 if x <  y
+//     0 if x == y
+//     +1 if x >  y
+func (i *Number) Cmp(x *Number) int {
+	return i.num.Cmp(x.num)
+}
+
+// Getters
+
+// Returns the string representation of i
+func (i *Number) String() string {
+	return i.num.String()
+}
+
+// Returns the byte representation of i
+func (i *Number) Bytes() []byte {
+	return i.num.Bytes()
+}
+
+// Uint64 returns the Uint64 representation of x. If x cannot be represented in an int64, the result is undefined.
+func (i *Number) Uint64() uint64 {
+	return i.num.Uint64()
+}
+
+// Int64 returns the int64 representation of x. If x cannot be represented in an int64, the result is undefined.
+func (i *Number) Int64() int64 {
+	return i.num.Int64()
+}
+
+// Returns the signed version of i
+func (i *Number) Int256() *Number {
+	return Int(0).Set(i)
+}
+
+// Returns the unsigned version of i
+func (i *Number) Uint256() *Number {
+	return Uint(0).Set(i)
+}
+
+// Returns the index of the first bit that's set to 1
+func (i *Number) FirstBitSet() int {
+	for j := 0; j < i.num.BitLen(); j++ {
+		if i.num.Bit(j) > 0 {
+			return j
+		}
+	}
+
+	return i.num.BitLen()
+}
+
+// Variables
+
+var (
+	Zero       = Uint(0)
+	One        = Uint(1)
+	Two        = Uint(2)
+	MaxUint256 = Uint(0).SetBytes(ethutil.Hex2Bytes("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))
+
+	MinOne = Int(-1)
+
+	// "typedefs"
+	Uint = Uint256
+	Int  = Int256
+)
diff --git a/ethutil/number/uint_test.go b/ethutil/number/uint_test.go
new file mode 100644
index 000000000..c42989465
--- /dev/null
+++ b/ethutil/number/uint_test.go
@@ -0,0 +1,92 @@
+package number
+
+import (
+	"math/big"
+	"testing"
+
+	"github.com/ethereum/go-ethereum/ethutil"
+)
+
+func TestSet(t *testing.T) {
+	a := Uint(0)
+	b := Uint(10)
+	a.Set(b)
+	if a.num.Cmp(b.num) != 0 {
+		t.Error("didn't compare", a, b)
+	}
+
+	c := Uint(0).SetBytes(ethutil.Hex2Bytes("0a"))
+	if c.num.Cmp(big.NewInt(10)) != 0 {
+		t.Error("c set bytes failed.")
+	}
+}
+
+func TestInitialiser(t *testing.T) {
+	check := false
+	init := NewInitialiser(func(x *Number) *Number {
+		check = true
+		return x
+	})
+	a := init(0).Add(init(1), init(2))
+	if a.Cmp(init(3)) != 0 {
+		t.Error("expected 3. got", a)
+	}
+	if !check {
+		t.Error("expected limiter to be called")
+	}
+}
+
+func TestGet(t *testing.T) {
+	a := Uint(10)
+	if a.Uint64() != 10 {
+		t.Error("expected to get 10. got", a.Uint64())
+	}
+
+	a = Uint(10)
+	if a.Int64() != 10 {
+		t.Error("expected to get 10. got", a.Int64())
+	}
+}
+
+func TestCmp(t *testing.T) {
+	a := Uint(10)
+	b := Uint(10)
+	c := Uint(11)
+
+	if a.Cmp(b) != 0 {
+		t.Error("a b == 0 failed", a, b)
+	}
+
+	if a.Cmp(c) >= 0 {
+		t.Error("a c < 0 failed", a, c)
+	}
+
+	if c.Cmp(b) <= 0 {
+		t.Error("c b > 0 failed", c, b)
+	}
+}
+
+func TestMaxArith(t *testing.T) {
+	a := Uint(0).Add(MaxUint256, One)
+	if a.Cmp(Zero) != 0 {
+		t.Error("expected max256 + 1 = 0 got", a)
+	}
+
+	a = Uint(0).Sub(Uint(0), One)
+	if a.Cmp(MaxUint256) != 0 {
+		t.Error("expected 0 - 1 = max256 got", a)
+	}
+
+	a = Int(0).Sub(Int(0), One)
+	if a.Cmp(MinOne) != 0 {
+		t.Error("expected 0 - 1 = -1 got", a)
+	}
+}
+
+func TestConversion(t *testing.T) {
+	a := Int(-1)
+	b := a.Uint256()
+	if b.Cmp(MaxUint256) != 0 {
+		t.Error("expected -1 => unsigned to return max. got", b)
+	}
+}
-- 
cgit v1.2.3