import (
"fmt"
+ "os"
"rand"
)
}
-// SetBytes interprets b as the bytes of a big-endian, unsigned integer and
-// sets z to that value.
-func (z *Int) SetBytes(b []byte) *Int {
- const s = _S
- z.abs = z.abs.make((len(b) + s - 1) / s)
-
- j := 0
- for len(b) >= s {
- var w Word
-
- for i := s; i > 0; i-- {
- w <<= 8
- w |= Word(b[len(b)-i])
- }
-
- z.abs[j] = w
- j++
- b = b[0 : len(b)-s]
- }
-
- if len(b) > 0 {
- var w Word
-
- for i := len(b); i > 0; i-- {
- w <<= 8
- w |= Word(b[len(b)-i])
- }
-
- z.abs[j] = w
- }
-
- z.abs = z.abs.norm()
+// SetBytes interprets buf as the bytes of a big-endian unsigned
+// integer, sets z to that value, and returns z.
+func (z *Int) SetBytes(buf []byte) *Int {
+ z.abs = z.abs.setBytes(buf)
z.neg = false
return z
}
-// Bytes returns the absolute value of x as a big-endian byte array.
+// Bytes returns the absolute value of z as a big-endian byte slice.
func (z *Int) Bytes() []byte {
- const s = _S
- b := make([]byte, len(z.abs)*s)
-
- for i, w := range z.abs {
- wordBytes := b[(len(z.abs)-i-1)*s : (len(z.abs)-i)*s]
- for j := s - 1; j >= 0; j-- {
- wordBytes[j] = byte(w)
- w >>= 8
- }
- }
-
- i := 0
- for i < len(b) && b[i] == 0 {
- i++
- }
-
- return b[i:]
+ buf := make([]byte, len(z.abs)*_S)
+ return buf[z.abs.bytes(buf):]
}
z.neg = true // z cannot be zero if x is positive
return z
}
+
+
+// Gob codec version. Permits backward-compatible changes to the encoding.
+const version byte = 1
+
+// GobEncode implements the gob.GobEncoder interface.
+func (z *Int) GobEncode() ([]byte, os.Error) {
+ buf := make([]byte, len(z.abs)*_S+1) // extra byte for version and sign bit
+ i := z.abs.bytes(buf) - 1 // i >= 0
+ b := version << 1 // make space for sign bit
+ if z.neg {
+ b |= 1
+ }
+ buf[i] = b
+ return buf[i:], nil
+}
+
+
+// GobDecode implements the gob.GobDecoder interface.
+func (z *Int) GobDecode(buf []byte) os.Error {
+ if len(buf) == 0 {
+ return os.NewError("Int.GobDecode: no data")
+ }
+ b := buf[0]
+ if b>>1 != version {
+ return os.NewError(fmt.Sprintf("Int.GobDecode: encoding version %d not supported", b>>1))
+ }
+ z.neg = b&1 != 0
+ z.abs = z.abs.setBytes(buf[1:])
+ return nil
+}
"bytes"
"encoding/hex"
"fmt"
+ "gob"
"testing"
"testing/quick"
)
}
}
}
+
+
+var gobEncodingTests = []string{
+ "0",
+ "1",
+ "2",
+ "10",
+ "42",
+ "1234567890",
+ "298472983472983471903246121093472394872319615612417471234712061",
+}
+
+func TestGobEncoding(t *testing.T) {
+ var medium bytes.Buffer
+ enc := gob.NewEncoder(&medium)
+ dec := gob.NewDecoder(&medium)
+ for i, test := range gobEncodingTests {
+ for j := 0; j < 2; j++ {
+ medium.Reset() // empty buffer for each test case (in case of failures)
+ stest := test
+ if j == 0 {
+ stest = "-" + test
+ }
+ var tx Int
+ tx.SetString(stest, 10)
+ if err := enc.Encode(&tx); err != nil {
+ t.Errorf("#%d%c: encoding failed: %s", i, 'a'+j, err)
+ }
+ var rx Int
+ if err := dec.Decode(&rx); err != nil {
+ t.Errorf("#%d%c: decoding failed: %s", i, 'a'+j, err)
+ }
+ if rx.Cmp(&tx) != 0 {
+ t.Errorf("#%d%c: transmission failed: got %s want %s", i, 'a'+j, &rx, &tx)
+ }
+ }
+ }
+}
return true
}
+
+
+// bytes writes the value of z into buf using big-endian encoding.
+// len(buf) must be >= len(z)*_S. The value of z is encoded in the
+// slice buf[i:]. The number i of unused bytes at the beginning of
+// buf is returned as result.
+func (z nat) bytes(buf []byte) (i int) {
+ i = len(buf)
+ for _, d := range z {
+ for j := 0; j < _S; j++ {
+ i--
+ buf[i] = byte(d)
+ d >>= 8
+ }
+ }
+
+ for i < len(buf) && buf[i] == 0 {
+ i++
+ }
+
+ return
+}
+
+
+// setBytes interprets buf as the bytes of a big-endian unsigned
+// integer, sets z to that value, and returns z.
+func (z nat) setBytes(buf []byte) nat {
+ z = z.make((len(buf) + _S - 1) / _S)
+
+ k := 0
+ s := uint(0)
+ var d Word
+ for i := len(buf); i > 0; i-- {
+ d |= Word(buf[i-1]) << s
+ if s += 8; s == _S*8 {
+ z[k] = d
+ k++
+ s = 0
+ d = 0
+ }
+ }
+ if k < len(z) {
+ z[k] = d
+ }
+
+ return z.norm()
+}