1
0
mirror of https://github.com/golang/go synced 2024-11-21 23:24:41 -07:00

big: gobs for big rats

Fixes #1926.

R=r
CC=golang-dev
https://golang.org/cl/4550122
This commit is contained in:
Robert Griesemer 2011-06-08 09:10:01 -07:00
parent 6c746328f7
commit 21032ebebd
4 changed files with 85 additions and 6 deletions

View File

@ -816,13 +816,13 @@ func (z *Int) Not(x *Int) *Int {
// Gob codec version. Permits backward-compatible changes to the encoding. // Gob codec version. Permits backward-compatible changes to the encoding.
const version byte = 1 const intGobVersion byte = 1
// GobEncode implements the gob.GobEncoder interface. // GobEncode implements the gob.GobEncoder interface.
func (z *Int) GobEncode() ([]byte, os.Error) { 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 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 { if z.neg {
b |= 1 b |= 1
} }
@ -837,7 +837,7 @@ func (z *Int) GobDecode(buf []byte) os.Error {
return os.ErrorString("Int.GobDecode: no data") return os.ErrorString("Int.GobDecode: no data")
} }
b := buf[0] 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)) return os.ErrorString(fmt.Sprintf("Int.GobDecode: encoding version %d not supported", b>>1))
} }
z.neg = b&1 != 0 z.neg = b&1 != 0

View File

@ -1303,6 +1303,7 @@ func TestModInverse(t *testing.T) {
} }
// used by TestIntGobEncoding and TestRatGobEncoding
var gobEncodingTests = []string{ var gobEncodingTests = []string{
"0", "0",
"1", "1",
@ -1313,7 +1314,7 @@ var gobEncodingTests = []string{
"298472983472983471903246121093472394872319615612417471234712061", "298472983472983471903246121093472394872319615612417471234712061",
} }
func TestGobEncoding(t *testing.T) { func TestIntGobEncoding(t *testing.T) {
var medium bytes.Buffer var medium bytes.Buffer
enc := gob.NewEncoder(&medium) enc := gob.NewEncoder(&medium)
dec := gob.NewDecoder(&medium) dec := gob.NewDecoder(&medium)
@ -1321,7 +1322,8 @@ func TestGobEncoding(t *testing.T) {
for j := 0; j < 2; j++ { for j := 0; j < 2; j++ {
medium.Reset() // empty buffer for each test case (in case of failures) medium.Reset() // empty buffer for each test case (in case of failures)
stest := test stest := test
if j == 0 { if j != 0 {
// negative numbers
stest = "-" + test stest = "-" + test
} }
var tx Int var tx Int

View File

@ -7,6 +7,7 @@
package big package big
import ( import (
"encoding/binary"
"fmt" "fmt"
"os" "os"
"strings" "strings"
@ -354,3 +355,45 @@ func (z *Rat) FloatString(prec int) string {
return s 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
}

View File

@ -7,6 +7,7 @@ package big
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"gob"
"testing" "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)
}
}
}
}