]> Cypherpunks repositories - gostls13.git/commitdiff
big: gobs for big rats
authorRobert Griesemer <gri@golang.org>
Wed, 8 Jun 2011 16:10:01 +0000 (09:10 -0700)
committerRobert Griesemer <gri@golang.org>
Wed, 8 Jun 2011 16:10:01 +0000 (09:10 -0700)
Fixes #1926.

R=r
CC=golang-dev
https://golang.org/cl/4550122

src/pkg/big/int.go
src/pkg/big/int_test.go
src/pkg/big/rat.go
src/pkg/big/rat_test.go

index e66c34a8362f96caddaa45f9617d19c9684eb6e1..22bdf8d2f8f34983559dfefe0011897e5ff5169d 100755 (executable)
@@ -816,13 +816,13 @@ func (z *Int) Not(x *Int) *Int {
 
 
 // Gob codec version. Permits backward-compatible changes to the encoding.
-const version byte = 1
+const intGobVersion 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
+       buf := make([]byte, 1+len(z.abs)*_S) // extra byte for version and sign bit
        i := z.abs.bytes(buf) - 1            // i >= 0
-       b := version << 1                    // make space for sign bit
+       b := intGobVersion << 1              // make space for sign bit
        if z.neg {
                b |= 1
        }
@@ -837,7 +837,7 @@ func (z *Int) GobDecode(buf []byte) os.Error {
                return os.ErrorString("Int.GobDecode: no data")
        }
        b := buf[0]
-       if b>>1 != version {
+       if b>>1 != intGobVersion {
                return os.ErrorString(fmt.Sprintf("Int.GobDecode: encoding version %d not supported", b>>1))
        }
        z.neg = b&1 != 0
index 1a492925b858945a1bd7041372226c68617e48a5..58a55030d5345b1ecc449a72f3046edf9a133820 100755 (executable)
@@ -1303,6 +1303,7 @@ func TestModInverse(t *testing.T) {
 }
 
 
+// used by TestIntGobEncoding and TestRatGobEncoding
 var gobEncodingTests = []string{
        "0",
        "1",
@@ -1313,7 +1314,7 @@ var gobEncodingTests = []string{
        "298472983472983471903246121093472394872319615612417471234712061",
 }
 
-func TestGobEncoding(t *testing.T) {
+func TestIntGobEncoding(t *testing.T) {
        var medium bytes.Buffer
        enc := gob.NewEncoder(&medium)
        dec := gob.NewDecoder(&medium)
@@ -1321,7 +1322,8 @@ func TestGobEncoding(t *testing.T) {
                for j := 0; j < 2; j++ {
                        medium.Reset() // empty buffer for each test case (in case of failures)
                        stest := test
-                       if j == 0 {
+                       if j != 0 {
+                               // negative numbers
                                stest = "-" + test
                        }
                        var tx Int
index b2e93f2a450c29ab6a52a5868c97ba4b08551432..1fbf8c4596c1d2f5454286552a6233e37d043f27 100644 (file)
@@ -7,6 +7,7 @@
 package big
 
 import (
+       "encoding/binary"
        "fmt"
        "os"
        "strings"
@@ -354,3 +355,45 @@ func (z *Rat) FloatString(prec int) string {
 
        return s
 }
+
+
+// Gob codec version. Permits backward-compatible changes to the encoding.
+const ratGobVersion byte = 1
+
+// GobEncode implements the gob.GobEncoder interface.
+func (z *Rat) GobEncode() ([]byte, os.Error) {
+       buf := make([]byte, 1+4+(len(z.a.abs)+len(z.b))*_S) // extra bytes for version and sign bit (1), and numerator length (4)
+       i := z.b.bytes(buf)
+       j := z.a.abs.bytes(buf[0:i])
+       n := i - j
+       if int(uint32(n)) != n {
+               // this should never happen
+               return nil, os.ErrorString("Rat.GobEncode: numerator too large")
+       }
+       binary.BigEndian.PutUint32(buf[j-4:j], uint32(n))
+       j -= 1 + 4
+       b := ratGobVersion << 1 // make space for sign bit
+       if z.a.neg {
+               b |= 1
+       }
+       buf[j] = b
+       return buf[j:], nil
+}
+
+
+// GobDecode implements the gob.GobDecoder interface.
+func (z *Rat) GobDecode(buf []byte) os.Error {
+       if len(buf) == 0 {
+               return os.ErrorString("Rat.GobDecode: no data")
+       }
+       b := buf[0]
+       if b>>1 != ratGobVersion {
+               return os.ErrorString(fmt.Sprintf("Rat.GobDecode: encoding version %d not supported", b>>1))
+       }
+       const j = 1 + 4
+       i := j + binary.BigEndian.Uint32(buf[j-4:j])
+       z.a.neg = b&1 != 0
+       z.a.abs = z.a.abs.setBytes(buf[j:i])
+       z.b = z.b.setBytes(buf[i:])
+       return nil
+}
index 4effbf8eac3f683493c0c0a4c7cde6495dc9b8dd..e64505ea3c6408ba4553b4dcdf6bf8745be827f7 100644 (file)
@@ -7,6 +7,7 @@ package big
 import (
        "bytes"
        "fmt"
+       "gob"
        "testing"
 )
 
@@ -308,3 +309,36 @@ func TestRatSetFrac64Rat(t *testing.T) {
                }
        }
 }
+
+
+func TestRatGobEncoding(t *testing.T) {
+       var medium bytes.Buffer
+       enc := gob.NewEncoder(&medium)
+       dec := gob.NewDecoder(&medium)
+       for i, test := range gobEncodingTests {
+               for j := 0; j < 4; j++ {
+                       medium.Reset() // empty buffer for each test case (in case of failures)
+                       stest := test
+                       if j&1 != 0 {
+                               // negative numbers
+                               stest = "-" + test
+                       }
+                       if j%2 != 0 {
+                               // fractions
+                               stest = stest + "." + test
+                       }
+                       var tx Rat
+                       tx.SetString(stest)
+                       if err := enc.Encode(&tx); err != nil {
+                               t.Errorf("#%d%c: encoding failed: %s", i, 'a'+j, err)
+                       }
+                       var rx Rat
+                       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)
+                       }
+               }
+       }
+}