diff --git a/cmd/noms/noms_show_test.go b/cmd/noms/noms_show_test.go index 759f2bd7b8..aa0adc555c 100644 --- a/cmd/noms/noms_show_test.go +++ b/cmd/noms/noms_show_test.go @@ -25,9 +25,9 @@ type nomsShowTestSuite struct { const ( res1 = "struct Commit {\n parents: Set>>,\n value: Value,\n}({\n parents: {},\n value: sha1-0ddf89c44a4ce4075714a4fc51d31a76e38f84ce,\n})\n" res2 = "\"test string\"\n" - res3 = "struct Commit {\n parents: Set>>,\n value: Value,\n}({\n parents: {\n sha1-46506c93810ce363c04c4bcf945797e4843a2a50,\n },\n value: sha1-dc6f386ab57b4ca62f54f7b63e5fe21a787f761e,\n})\n" + res3 = "struct Commit {\n parents: Set>>,\n value: Value,\n}({\n parents: {\n sha1-46506c93810ce363c04c4bcf945797e4843a2a50,\n },\n value: sha1-46f553ffca109477301aca47b2576ac5d2a8ec9b,\n})\n" res4 = "List([\n \"elem1\",\n 2,\n \"elem3\",\n])\n" - res5 = "struct Commit {\n parents: Set>>,\n value: Value,\n}({\n parents: {\n sha1-88ccdecaa410c101bfac396ed6a451aa14b5043b,\n },\n value: sha1-0ddf89c44a4ce4075714a4fc51d31a76e38f84ce,\n})\n" + res5 = "struct Commit {\n parents: Set>>,\n value: Value,\n}({\n parents: {\n sha1-024d53e8f0adc94f1a8a81d265255fb2a5c8233b,\n },\n value: sha1-0ddf89c44a4ce4075714a4fc51d31a76e38f84ce,\n})\n" ) func writeTestData(str string, value types.Value) types.Ref { diff --git a/go/constants/version.go b/go/constants/version.go index dd73334c2d..b808f39b3b 100644 --- a/go/constants/version.go +++ b/go/constants/version.go @@ -5,6 +5,6 @@ package constants // TODO: generate this from some central thing with go generate, so that JS and Go can be easily kept in sync -const NomsVersion = "2" +const NomsVersion = "3" var NomsGitSHA = "" diff --git a/go/types/blob_test.go b/go/types/blob_test.go index 723ec536d7..3d5a7a96ab 100644 --- a/go/types/blob_test.go +++ b/go/types/blob_test.go @@ -96,26 +96,26 @@ func newBlobTestSuite(size uint, expectRefStr string, expectChunkCount int, expe } func TestBlobSuite1K(t *testing.T) { - suite.Run(t, newBlobTestSuite(10, "sha1-ccf0161935f285d1d80cbcab8fd4c092fbf1f63b", 3, 2, 2)) + suite.Run(t, newBlobTestSuite(10, "sha1-225cb62f282db9950802a8a0dce55b577af16e86", 3, 2, 2)) } func TestBlobSuite4K(t *testing.T) { - suite.Run(t, newBlobTestSuite(12, "sha1-fc4c95f8f9db7c60d17bfc3366373e44168b6903", 9, 2, 2)) + suite.Run(t, newBlobTestSuite(12, "sha1-5171d9ff4c8b7420a22cdec5c1282b6fbcafa0d5", 9, 2, 2)) } func TestBlobSuite16K(t *testing.T) { - suite.Run(t, newBlobTestSuite(14, "sha1-43cc3d646647cb63dfe3c13ea6e352fecc597379", 2, 2, 2)) + suite.Run(t, newBlobTestSuite(14, "sha1-8741539c258f9c464b08d099cb2521f19138eae7", 2, 2, 2)) } func TestBlobSuite64K(t *testing.T) { - suite.Run(t, newBlobTestSuite(16, "sha1-5af76c7ea2a964ff7355418c3ec38504ee6cbd9e", 3, 2, 2)) + suite.Run(t, newBlobTestSuite(16, "sha1-f2563df4e20835fb3402837272a24f58e9e48bd8", 3, 2, 2)) } func TestBlobSuite256K(t *testing.T) { if testing.Short() { t.Skip("Skipping test in short mode.") } - suite.Run(t, newBlobTestSuite(18, "sha1-2fe75543395ab5f54d0586b88f79d44ebc41490d", 8, 2, 2)) + suite.Run(t, newBlobTestSuite(18, "sha1-f97d8d77fb1e3ef21f2ccccbde810151b4e8c4e9", 8, 2, 2)) } // Checks the first 1/2 of the bytes, then 1/2 of the remainder, then 1/2 of the remainder, etc... diff --git a/go/types/codec.go b/go/types/codec.go index 9acd700e38..356e33a6fc 100644 --- a/go/types/codec.go +++ b/go/types/codec.go @@ -6,7 +6,7 @@ package types import ( "crypto/sha1" - "math" + "encoding/binary" "github.com/attic-labs/noms/go/chunks" "github.com/attic-labs/noms/go/d" @@ -54,7 +54,7 @@ type nomsReader interface { readUint8() uint8 readUint32() uint32 readUint64() uint64 - readFloat64() float64 + readNumber() Number readBool() bool readString() string readIdent(tc *TypeCache) uint32 @@ -66,7 +66,7 @@ type nomsWriter interface { writeUint8(v uint8) writeUint32(v uint32) writeUint64(v uint64) - writeFloat64(v float64) + writeNumber(v Number) writeBool(b bool) writeString(v string) writeHash(h hash.Hash) @@ -123,8 +123,13 @@ func (b *binaryNomsReader) readUint64() uint64 { return v } -func (b *binaryNomsReader) readFloat64() float64 { - return math.Float64frombits(b.readUint64()) +func (b *binaryNomsReader) readNumber() Number { + // b.assertCanRead(binary.MaxVarintLen64 * 2) + i, count := binary.Varint(b.buff[b.offset:]) + b.offset += uint32(count) + exp, count2 := binary.Varint(b.buff[b.offset:]) + b.offset += uint32(count2) + return Number(intExpToFloat64(i, int(exp))) } func (b *binaryNomsReader) readBool() bool { @@ -212,7 +217,6 @@ func (b *binaryNomsWriter) writeUint32(v uint32) { func (b *binaryNomsWriter) writeUint64(v uint64) { b.ensureCapacity(8) - // Little-Endian: TODO: Need Big b.buff[b.offset] = byte(v) b.buff[b.offset+1] = byte(v >> 8) @@ -225,8 +229,13 @@ func (b *binaryNomsWriter) writeUint64(v uint64) { b.offset += 8 } -func (b *binaryNomsWriter) writeFloat64(v float64) { - b.writeUint64(math.Float64bits(v)) +func (b *binaryNomsWriter) writeNumber(v Number) { + b.ensureCapacity(binary.MaxVarintLen64 * 2) + i, exp := float64ToIntExp(float64(v)) + count := binary.PutVarint(b.buff[b.offset:], i) + b.offset += uint32(count) + count = binary.PutVarint(b.buff[b.offset:], int64(exp)) + b.offset += uint32(count) } func (b *binaryNomsWriter) writeBool(v bool) { diff --git a/go/types/encode_human_readable_test.go b/go/types/encode_human_readable_test.go index 69ee9276e4..94905280c8 100644 --- a/go/types/encode_human_readable_test.go +++ b/go/types/encode_human_readable_test.go @@ -63,8 +63,8 @@ func TestWriteHumanReadableRef(t *testing.T) { x := Number(42) rv := vs.WriteValue(x) - assertWriteHRSEqual(t, "sha1-c47f695d492ba4a218281aa7c0269d304af48b9e", rv) - assertWriteTaggedHRSEqual(t, "Ref(sha1-c47f695d492ba4a218281aa7c0269d304af48b9e)", rv) + assertWriteHRSEqual(t, "sha1-f76a38165c9408b5cafa7e67006ba7e697756072", rv) + assertWriteTaggedHRSEqual(t, "Ref(sha1-f76a38165c9408b5cafa7e67006ba7e697756072)", rv) } func TestWriteHumanReadableCollections(t *testing.T) { diff --git a/go/types/encoding_test.go b/go/types/encoding_test.go index cd392772c8..a12a44da42 100644 --- a/go/types/encoding_test.go +++ b/go/types/encoding_test.go @@ -6,6 +6,7 @@ package types import ( "bytes" + "math" "strconv" "strings" "testing" @@ -67,8 +68,8 @@ func (r *nomsTestReader) readUint64() uint64 { return r.read().(uint64) } -func (r *nomsTestReader) readFloat64() float64 { - return r.read().(float64) +func (r *nomsTestReader) readNumber() Number { + return r.read().(Number) } func (r *nomsTestReader) readBytes() []byte { @@ -107,7 +108,7 @@ func (w *nomsTestWriter) writeUint64(v uint64) { w.write(v) } -func (w *nomsTestWriter) writeFloat64(v float64) { +func (w *nomsTestWriter) writeNumber(v Number) { w.write(v) } @@ -148,10 +149,33 @@ func TestRoundTrips(t *testing.T) { assertRoundTrips(Bool(false)) assertRoundTrips(Bool(true)) - assertRoundTrips(Number(1)) - assertRoundTrips(Number(-0)) assertRoundTrips(Number(0)) - assertRoundTrips(Number(1)) + assertRoundTrips(Number(-0)) + assertRoundTrips(Number(math.Copysign(0, -1))) + + intTest := []int64{1, 2, 3, 7, 15, 16, 17, + 127, 128, 129, + 254, 255, 256, 257, + 1023, 1024, 1025, + 2048, 4096, 8192, 32767, 32768, 65535, 65536, + 4294967295, 4294967296, + 9223372036854779, + 92233720368547760, + } + for _, v := range intTest { + f := float64(v) + assertRoundTrips(Number(f)) + f = math.Copysign(f, -1) + assertRoundTrips(Number(f)) + } + floatTest := []float64{1.01, 1.001, 1.0001, 1.00001, 1.000001, 100.01, 1000.000001} + for _, f := range floatTest { + assertRoundTrips(Number(f)) + f = math.Copysign(f, -1) + assertRoundTrips(Number(f)) + } + assertRoundTrips(Number(math.MaxFloat64)) + assertRoundTrips(Number(math.Nextafter(1, 2) - 1)) assertRoundTrips(String("")) assertRoundTrips(String("foo")) @@ -184,25 +208,25 @@ func TestWritePrimitives(t *testing.T) { assertEncoding(t, []interface{}{ - uint8(NumberKind), float64(0), + uint8(NumberKind), Number(0), }, Number(0)) assertEncoding(t, []interface{}{ - uint8(NumberKind), float64(1000000000000000000), + uint8(NumberKind), Number(1000000000000000000), }, Number(1e18)) assertEncoding(t, []interface{}{ - uint8(NumberKind), float64(10000000000000000000), + uint8(NumberKind), Number(10000000000000000000), }, Number(1e19)) assertEncoding(t, []interface{}{ - uint8(NumberKind), float64(1e+20), + uint8(NumberKind), Number(1e+20), }, Number(1e20)) @@ -225,7 +249,7 @@ func TestWriteSimpleBlob(t *testing.T) { func TestWriteList(t *testing.T) { assertEncoding(t, []interface{}{ - uint8(ListKind), uint8(NumberKind), false, uint32(4) /* len */, uint8(NumberKind), float64(0), uint8(NumberKind), float64(1), uint8(NumberKind), float64(2), uint8(NumberKind), float64(3), + uint8(ListKind), uint8(NumberKind), false, uint32(4) /* len */, uint8(NumberKind), Number(0), uint8(NumberKind), Number(1), uint8(NumberKind), Number(2), uint8(NumberKind), Number(3), }, NewList(Number(0), Number(1), Number(2), Number(3)), ) @@ -236,8 +260,8 @@ func TestWriteListOfList(t *testing.T) { []interface{}{ uint8(ListKind), uint8(ListKind), uint8(NumberKind), false, uint32(2), // len - uint8(ListKind), uint8(NumberKind), false, uint32(1) /* len */, uint8(NumberKind), float64(0), - uint8(ListKind), uint8(NumberKind), false, uint32(3) /* len */, uint8(NumberKind), float64(1), uint8(NumberKind), float64(2), uint8(NumberKind), float64(3), + uint8(ListKind), uint8(NumberKind), false, uint32(1) /* len */, uint8(NumberKind), Number(0), + uint8(ListKind), uint8(NumberKind), false, uint32(3) /* len */, uint8(NumberKind), Number(1), uint8(NumberKind), Number(2), uint8(NumberKind), Number(3), }, NewList(NewList(Number(0)), NewList(Number(1), Number(2), Number(3))), ) @@ -246,7 +270,7 @@ func TestWriteListOfList(t *testing.T) { func TestWriteSet(t *testing.T) { assertEncoding(t, []interface{}{ - uint8(SetKind), uint8(NumberKind), false, uint32(4) /* len */, uint8(NumberKind), float64(0), uint8(NumberKind), float64(1), uint8(NumberKind), float64(2), uint8(NumberKind), float64(3), + uint8(SetKind), uint8(NumberKind), false, uint32(4) /* len */, uint8(NumberKind), Number(0), uint8(NumberKind), Number(1), uint8(NumberKind), Number(2), uint8(NumberKind), Number(3), }, NewSet(Number(3), Number(1), Number(2), Number(0)), ) @@ -257,8 +281,8 @@ func TestWriteSetOfSet(t *testing.T) { []interface{}{ uint8(SetKind), uint8(SetKind), uint8(NumberKind), false, uint32(2), // len - uint8(SetKind), uint8(NumberKind), false, uint32(1) /* len */, uint8(NumberKind), float64(0), - uint8(SetKind), uint8(NumberKind), false, uint32(3) /* len */, uint8(NumberKind), float64(1), uint8(NumberKind), float64(2), uint8(NumberKind), float64(3), + uint8(SetKind), uint8(NumberKind), false, uint32(1) /* len */, uint8(NumberKind), Number(0), + uint8(SetKind), uint8(NumberKind), false, uint32(3) /* len */, uint8(NumberKind), Number(1), uint8(NumberKind), Number(2), uint8(NumberKind), Number(3), }, NewSet(NewSet(Number(0)), NewSet(Number(1), Number(2), Number(3))), ) @@ -278,7 +302,7 @@ func TestWriteMapOfMap(t *testing.T) { []interface{}{ uint8(MapKind), uint8(MapKind), uint8(StringKind), uint8(NumberKind), uint8(SetKind), uint8(BoolKind), false, uint32(1), // len - uint8(MapKind), uint8(StringKind), uint8(NumberKind), false, uint32(1) /* len */, uint8(StringKind), "a", uint8(NumberKind), float64(0), + uint8(MapKind), uint8(StringKind), uint8(NumberKind), false, uint32(1) /* len */, uint8(StringKind), "a", uint8(NumberKind), Number(0), uint8(SetKind), uint8(BoolKind), false, uint32(1) /* len */, uint8(BoolKind), true, }, NewMap(NewMap(String("a"), Number(0)), NewSet(Bool(true))), @@ -294,9 +318,9 @@ func TestWriteCompoundBlob(t *testing.T) { []interface{}{ uint8(BlobKind), true, uint32(3), // len - uint8(RefKind), uint8(BlobKind), r1.String(), uint64(11), uint8(NumberKind), float64(20), uint64(20), - uint8(RefKind), uint8(BlobKind), r2.String(), uint64(22), uint8(NumberKind), float64(40), uint64(40), - uint8(RefKind), uint8(BlobKind), r3.String(), uint64(33), uint8(NumberKind), float64(60), uint64(60), + uint8(RefKind), uint8(BlobKind), r1.String(), uint64(11), uint8(NumberKind), Number(20), uint64(20), + uint8(RefKind), uint8(BlobKind), r2.String(), uint64(22), uint8(NumberKind), Number(40), uint64(40), + uint8(RefKind), uint8(BlobKind), r3.String(), uint64(33), uint8(NumberKind), Number(60), uint64(60), }, newBlob(newBlobMetaSequence([]metaTuple{ newMetaTuple(constructRef(MakeRefType(BlobType), r1, 11), orderedKeyFromInt(20), 20, nil), @@ -319,7 +343,7 @@ func TestWriteStruct(t *testing.T) { assertEncoding(t, []interface{}{ uint8(StructKind), "S", uint32(2) /* len */, "b", uint8(BoolKind), "x", uint8(NumberKind), - uint8(BoolKind), true, uint8(NumberKind), float64(42), + uint8(BoolKind), true, uint8(NumberKind), Number(42), }, NewStruct("S", structData{"x": Number(42), "b": Bool(true)}), ) @@ -358,7 +382,7 @@ func TestWriteStructWithStruct(t *testing.T) { uint32(1), // len "s", uint8(StructKind), "S2", uint32(1) /* len */, "x", uint8(NumberKind), uint8(StructKind), "S2", uint32(1) /* len */, "x", uint8(NumberKind), - uint8(NumberKind), float64(42), + uint8(NumberKind), Number(42), }, // {s: {x: 42}} NewStruct("S", structData{"s": NewStruct("S2", structData{"x": Number(42)})}), @@ -381,8 +405,8 @@ func TestWriteCompoundList(t *testing.T) { []interface{}{ uint8(ListKind), uint8(NumberKind), true, uint32(2), // len, - uint8(RefKind), uint8(ListKind), uint8(NumberKind), list1.Hash().String(), uint64(1), uint8(NumberKind), float64(1), uint64(1), - uint8(RefKind), uint8(ListKind), uint8(NumberKind), list2.Hash().String(), uint64(1), uint8(NumberKind), float64(3), uint64(3), + uint8(RefKind), uint8(ListKind), uint8(NumberKind), list1.Hash().String(), uint64(1), uint8(NumberKind), Number(1), uint64(1), + uint8(RefKind), uint8(ListKind), uint8(NumberKind), list2.Hash().String(), uint64(1), uint8(NumberKind), Number(3), uint64(3), }, newList(newListMetaSequence([]metaTuple{ newMetaTuple(NewRef(list1), orderedKeyFromInt(1), 1, list1), @@ -399,8 +423,8 @@ func TestWriteCompoundSet(t *testing.T) { []interface{}{ uint8(SetKind), uint8(NumberKind), true, uint32(2), // len, - uint8(RefKind), uint8(SetKind), uint8(NumberKind), set1.Hash().String(), uint64(1), uint8(NumberKind), float64(1), uint64(2), - uint8(RefKind), uint8(SetKind), uint8(NumberKind), set2.Hash().String(), uint64(1), uint8(NumberKind), float64(4), uint64(3), + uint8(RefKind), uint8(SetKind), uint8(NumberKind), set1.Hash().String(), uint64(1), uint8(NumberKind), Number(1), uint64(2), + uint8(RefKind), uint8(SetKind), uint8(NumberKind), set2.Hash().String(), uint64(1), uint8(NumberKind), Number(4), uint64(3), }, newSet(newSetMetaSequence([]metaTuple{ newMetaTuple(NewRef(set1), orderedKeyFromInt(1), 2, set1), @@ -443,7 +467,7 @@ func TestWriteListOfUnion(t *testing.T) { assertEncoding(t, []interface{}{ uint8(ListKind), uint8(UnionKind), uint32(3) /* len */, uint8(BoolKind), uint8(StringKind), uint8(NumberKind), false, - uint32(4) /* len */, uint8(StringKind), "0", uint8(NumberKind), float64(1), uint8(StringKind), "2", uint8(BoolKind), true, + uint32(4) /* len */, uint8(StringKind), "0", uint8(NumberKind), Number(1), uint8(StringKind), "2", uint8(BoolKind), true, }, NewList( String("0"), @@ -458,7 +482,7 @@ func TestWriteListOfStruct(t *testing.T) { assertEncoding(t, []interface{}{ uint8(ListKind), uint8(StructKind), "S", uint32(1) /* len */, "x", uint8(NumberKind), false, - uint32(1) /* len */, uint8(StructKind), "S", uint32(1) /* len */, "x", uint8(NumberKind), uint8(NumberKind), float64(42), + uint32(1) /* len */, uint8(StructKind), "S", uint32(1) /* len */, "x", uint8(NumberKind), uint8(NumberKind), Number(42), }, NewList(NewStruct("S", structData{"x": Number(42)})), ) @@ -519,7 +543,7 @@ func nomsTestWriteRecursiveStruct(t *testing.T) { []interface{}{ uint8(StructKind), "A6", uint32(2) /* len */, "cs", uint8(ListKind), uint8(CycleKind), uint32(0), "v", uint8(NumberKind), uint8(ListKind), uint8(UnionKind), uint32(0) /* len */, false, uint32(0), /* len */ - uint8(NumberKind), float64(42), + uint8(NumberKind), Number(42), }, // {v: 42, cs: [{v: 555, cs: []}]} NewStructWithType(structType, ValueSlice{NewList(), Number(42)}), @@ -530,9 +554,12 @@ func TestWriteUnionList(t *testing.T) { assertEncoding(t, []interface{}{ uint8(ListKind), uint8(UnionKind), uint32(2) /* len */, uint8(StringKind), uint8(NumberKind), - false, uint32(2) /* len */, uint8(StringKind), "hi", uint8(NumberKind), float64(42), + false, uint32(3), /* len */ + uint8(NumberKind), Number(23), + uint8(StringKind), "hi", + uint8(NumberKind), Number(42), }, - NewList(String("hi"), Number(42)), + NewList(Number(23), String("hi"), Number(42)), ) } diff --git a/go/types/list_test.go b/go/types/list_test.go index b097fa1154..1e2b039b6e 100644 --- a/go/types/list_test.go +++ b/go/types/list_test.go @@ -153,11 +153,11 @@ func (suite *listTestSuite) TestMap() { } func TestListSuite1K(t *testing.T) { - suite.Run(t, newListTestSuite(10, "sha1-99a9e8aa75f9363b561d4576c99630b1103c9083", 2, 2, 2)) + suite.Run(t, newListTestSuite(10, "sha1-d797568943812c45ec530c80d3a2654a77649890", 17, 5, 1)) } func TestListSuite4K(t *testing.T) { - suite.Run(t, newListTestSuite(12, "sha1-3e4d4c123dceea5b45fcddb207a40b7e0f69a4f2", 4, 2, 2)) + suite.Run(t, newListTestSuite(12, "sha1-be2dbb48eaee147211a3f57da879feefd3e44269", 2, 2, 2)) } func TestListInsert(t *testing.T) { @@ -595,7 +595,7 @@ func TestListFirstNNumbers(t *testing.T) { nums := generateNumbersAsValues(testListSize) s := NewList(nums...) - assert.Equal("sha1-241e54086d50c131db3c2f3f5f17e68f42fd98ac", s.Hash().String()) + assert.Equal("sha1-cb53c5de1ccef77930f19fce6c425998a763b231", s.Hash().String()) } func TestListRefOfStructFirstNNumbers(t *testing.T) { @@ -606,7 +606,7 @@ func TestListRefOfStructFirstNNumbers(t *testing.T) { nums := generateNumbersAsRefOfStructs(testListSize) s := NewList(nums...) - assert.Equal("sha1-ac7830942e248613be6643a2667048667e9c22d1", s.Hash().String()) + assert.Equal("sha1-6a02619eb8074f89ee2f0453837140f6e796609f", s.Hash().String()) } func TestListModifyAfterRead(t *testing.T) { @@ -880,9 +880,9 @@ func TestListDiffLargeWithSameMiddle(t *testing.T) { assert.Equal(diff1, diff2) // should only read/write a "small & reasonably sized portion of the total" - assert.Equal(95, cs1.Writes) - assert.Equal(16, cs1.Reads) - assert.Equal(85, cs2.Writes) + assert.Equal(79, cs1.Writes) + assert.Equal(13, cs1.Reads) + assert.Equal(72, cs2.Writes) assert.Equal(6, cs2.Reads) } diff --git a/go/types/map_test.go b/go/types/map_test.go index 10aac04022..2df905f9d6 100644 --- a/go/types/map_test.go +++ b/go/types/map_test.go @@ -230,18 +230,19 @@ func (suite *mapTestSuite) TestStreamingMap() { } func TestMapSuite1K(t *testing.T) { - suite.Run(t, newMapTestSuite(10, "sha1-b4dfda98cac31acfb42c42bbe7692d576855e520", 2, 2, 2, newNumber)) + suite.Run(t, newMapTestSuite(10, "sha1-ccda04ba3961a70124e029c2e9af7b0537e726db", 16, 1, 2, newNumber)) } func TestMapSuite4K(t *testing.T) { - suite.Run(t, newMapTestSuite(12, "sha1-7d650134fa9c0424a4c5ff93f377b8e8d54dbd0f", 4, 2, 2, newNumber)) + suite.Run(t, newMapTestSuite(12, "sha1-80e91e9538aeaabe75793c6c29d03954ac81d221", 2, 2, 2, newNumber)) } + func TestMapSuite1KStructs(t *testing.T) { - suite.Run(t, newMapTestSuite(10, "sha1-73ab90e854ea52001e59ea4b097c9f3b40565d8c", 18, 2, 2, newNumberStruct)) + suite.Run(t, newMapTestSuite(10, "sha1-17a96ed265da91aa992be70dba34cd9c3b9000df", 2, 2, 2, newNumberStruct)) } func TestMapSuite4KStructs(t *testing.T) { - suite.Run(t, newMapTestSuite(12, "sha1-b48765e4423ec48eb5925276794b2864a4b48928", 76, 2, 2, newNumberStruct)) + suite.Run(t, newMapTestSuite(12, "sha1-ed658ef24dbc4fa2fecefa1e215bc06887199935", 2, 2, 2, newNumberStruct)) } func newNumber(i int) Value { @@ -948,7 +949,7 @@ func TestMapFirstNNumbers(t *testing.T) { } m := NewMap(kvs...) - assert.Equal("sha1-9fce950ce2606ced8681a695b608384c642ffb53", m.Hash().String()) + assert.Equal("sha1-0ce27caa55f6fec82da76e1bc84fe459b7387791", m.Hash().String()) assert.Equal(deriveCollectionHeight(m), getRefHeightOfCollection(m)) } @@ -969,7 +970,7 @@ func TestMapRefOfStructFirstNNumbers(t *testing.T) { } m := NewMap(kvs...) - assert.Equal("sha1-c43b17db2fa433aa1842b8b0b25acfd10e035be3", m.Hash().String()) + assert.Equal("sha1-5c36c25f8d62e72b3d02089febab440049236631", m.Hash().String()) // height + 1 because the leaves are Ref values (with height 1). assert.Equal(deriveCollectionHeight(m)+1, getRefHeightOfCollection(m)) } diff --git a/go/types/number_util.go b/go/types/number_util.go new file mode 100644 index 0000000000..51b2a5ed9f --- /dev/null +++ b/go/types/number_util.go @@ -0,0 +1,53 @@ +// Copyright 2016 Attic Labs, Inc. All rights reserved. +// Licensed under the Apache License, version 2.0: +// http://www.apache.org/licenses/LICENSE-2.0 + +package types + +import ( + "math" +) + +func float64IsInt(f, machineEpsilon float64) bool { + _, frac := math.Modf(math.Abs(f)) + if frac < machineEpsilon || frac > 1.0-machineEpsilon { + return true + } + return false +} + +// convert float64 to int64 where f == i / 2^exp +func float64ToIntExp(f float64) (i int64, exp int) { + if f == 0 { + return 0, 0 + } + + isNegative := math.Signbit(f) + f = math.Abs(f) + + machineEpsilon := math.Nextafter(1, 2) - 1 + exp = 0 + // really large float, bring down to within MaxInt64 + for f > float64(math.MaxInt64) { + f /= 2 + exp-- + } + + for !float64IsInt(f, machineEpsilon) { + f *= 2 + exp++ + } + if isNegative { + f *= -1 + } + return int64(f), exp +} + +// returns float value == i / 2^exp +func intExpToFloat64(i int64, exp int) float64 { + if exp == 0 { + return float64(i) + } else { + return float64(i) / math.Pow(2, float64(exp)) + } +} diff --git a/go/types/opcache_compare.go b/go/types/opcache_compare.go index 8094a04bc2..6bc04b0bf3 100644 --- a/go/types/opcache_compare.go +++ b/go/types/opcache_compare.go @@ -35,9 +35,9 @@ func (opCacheComparer) Compare(a, b []byte) int { return res } reader := binaryNomsReader{a[1:], 0} - aNum := reader.readFloat64() + aNum := reader.readNumber() reader.buff, reader.offset = b[1:], 0 - bNum := reader.readFloat64() + bNum := reader.readNumber() if aNum == bNum { return 0 } diff --git a/go/types/set_test.go b/go/types/set_test.go index 964c21e1aa..18b3debb0e 100644 --- a/go/types/set_test.go +++ b/go/types/set_test.go @@ -157,19 +157,19 @@ func newSetTestSuite(size uint, expectRefStr string, expectChunkCount int, expec } func TestSetSuite1K(t *testing.T) { - suite.Run(t, newSetTestSuite(10, "sha1-5e5eda1a8813f19d0e5e68e6725cb6b3d9b63daa", 14, 2, 2, newNumber)) + suite.Run(t, newSetTestSuite(10, "sha1-1520836622fd7cd2964c3d49c3076a270422e255", 16, 1, 2, newNumber)) } func TestSetSuite4K(t *testing.T) { - suite.Run(t, newSetTestSuite(12, "sha1-d32df81dba427a00d949f3dbca477a5d2d8057a9", 2, 2, 2, newNumber)) + suite.Run(t, newSetTestSuite(12, "sha1-874d250b19dab05ddc63feb301ba95bdafcf8a7d", 2, 2, 2, newNumber)) } func TestSetSuite1KStructs(t *testing.T) { - suite.Run(t, newSetTestSuite(10, "sha1-9d904bcb2b06b0361a73f9ccbdfeca53f081030f", 18, 2, 2, newNumberStruct)) + suite.Run(t, newSetTestSuite(10, "sha1-217eba8e53962c0efea24f4c22e6a525bb1663dd", 14, 1, 2, newNumberStruct)) } func TestSetSuite4KStructs(t *testing.T) { - suite.Run(t, newSetTestSuite(12, "sha1-a8f3b3362cde66638e6e1fb8359ad5675b7b5292", 2, 2, 2, newNumberStruct)) + suite.Run(t, newSetTestSuite(12, "sha1-3ac7ebc9123028d1ade619f539ad4d488a3ab6ea", 2, 2, 2, newNumberStruct)) } func getTestNativeOrderSet(scale int) testSet { @@ -785,7 +785,7 @@ func TestSetFirstNNumbers(t *testing.T) { nums := generateNumbersAsValues(testSetSize) s := NewSet(nums...) - assert.Equal("sha1-1fc97c4e369770b643e013569c68687765601514", s.Hash().String()) + assert.Equal("sha1-ae7716c21164c7095686610371fd8e4af7b4e7c2", s.Hash().String()) assert.Equal(deriveCollectionHeight(s), getRefHeightOfCollection(s)) } @@ -797,7 +797,7 @@ func TestSetRefOfStructFirstNNumbers(t *testing.T) { nums := generateNumbersAsRefOfStructs(testSetSize) s := NewSet(nums...) - assert.Equal("sha1-084c21ccfb81d18d1b6da8bae6b5de1f52d1bd00", s.Hash().String()) + assert.Equal("sha1-73ceda53a24ffc2d76d17a34b772468cfe84576f", s.Hash().String()) // height + 1 because the leaves are Ref values (with height 1). assert.Equal(deriveCollectionHeight(s)+1, getRefHeightOfCollection(s)) } diff --git a/go/types/value_decoder.go b/go/types/value_decoder.go index 121ec4c900..0adfa9c7f8 100644 --- a/go/types/value_decoder.go +++ b/go/types/value_decoder.go @@ -141,7 +141,7 @@ func (r *valueDecoder) readValue() Value { case BoolKind: return Bool(r.readBool()) case NumberKind: - return Number(r.readFloat64()) + return r.readNumber() case StringKind: return String(r.readString()) case ListKind: diff --git a/go/types/value_encoder.go b/go/types/value_encoder.go index 9b0101f663..40fc4396e6 100644 --- a/go/types/value_encoder.go +++ b/go/types/value_encoder.go @@ -129,7 +129,7 @@ func (w *valueEncoder) writeValue(v Value) { case BoolKind: w.writeBool(bool(v.(Bool))) case NumberKind: - w.writeFloat64(float64(v.(Number))) + w.writeNumber(v.(Number)) case ListKind: seq := v.(List).sequence() if w.maybeWriteMetaSequence(seq) { diff --git a/go/types/xp_test.go b/go/types/xp_test.go index 0e16ac2a94..bd319f01d9 100644 --- a/go/types/xp_test.go +++ b/go/types/xp_test.go @@ -26,9 +26,9 @@ func newTestSuite() *testSuite { testValues := []*testValue{ &testValue{Bool(true), "sha1-3f29546453678b855931c174a97d6c0894b8f546", "bool - true"}, &testValue{Bool(false), "sha1-1489f923c4dca729178b3e3233458550d8dddf29", "bool - false"}, - &testValue{Number(-1), "sha1-cd243416f913f4a81d020a866266316b30200e34", "num - -1"}, - &testValue{Number(0), "sha1-80e331473af6cb0cd7ae6f75793070cfbc4d642b", "num - 0"}, - &testValue{Number(1), "sha1-9f34f68652a49c4b7cc5e25951311e92c61d46d0", "num - 1"}, + &testValue{Number(-1), "sha1-47ec8d98366433dc002e7721c9e37d5067547937", "num - -1"}, + &testValue{Number(0), "sha1-9508e90548b0440a4a61e5743b76c1e309b23b7f", "num - 0"}, + &testValue{Number(1), "sha1-9f36f27018671b24dcdf70c9eb857d5ea2a064c8", "num - 1"}, &testValue{String(""), "sha1-e1bc1dae59f116abb43f9dafbb2acc9b141aa6b0", "str - empty"}, &testValue{String("0"), "sha1-a1c90c71d1ffdb51138677c578e6f2e8a011070d", "str - 0"}, &testValue{String("false"), "sha1-e15d53dc6c9d3aa6eca4eea28382c9c45ba8fd9e", "str - false"}, diff --git a/js/package.json b/js/package.json index 41b1dad789..d389530408 100644 --- a/js/package.json +++ b/js/package.json @@ -1,7 +1,7 @@ { "name": "@attic/noms", "license": "Apache-2.0", - "version": "49.2.0", + "version": "50.0.0", "description": "Noms JS SDK", "repository": "https://github.com/attic-labs/noms", "main": "dist/commonjs/noms.js", @@ -14,7 +14,8 @@ "babel-runtime": "^6.9.2", "rusha": "^0.8.3", "text-encoding-utf-8": "^1.0.1", - "tingodb": "^0.4.2" + "tingodb": "^0.4.2", + "signed-varint": "2.0.0" }, "devDependencies": { "@attic/eslintrc": "^3.1.0", diff --git a/js/src/blob-test.js b/js/src/blob-test.js index c047bdfd12..0023568991 100644 --- a/js/src/blob-test.js +++ b/js/src/blob-test.js @@ -158,19 +158,19 @@ suite('Blob', () => { } test('Blob 1K', () => - blobTestSuite(10, 'sha1-ccf0161935f285d1d80cbcab8fd4c092fbf1f63b', 3, 2, 2)); + blobTestSuite(10, 'sha1-225cb62f282db9950802a8a0dce55b577af16e86', 3, 2, 2)); test('LONG: Blob 4K', () => - blobTestSuite(12, 'sha1-fc4c95f8f9db7c60d17bfc3366373e44168b6903', 9, 2, 2)); + blobTestSuite(12, 'sha1-5171d9ff4c8b7420a22cdec5c1282b6fbcafa0d5', 9, 2, 2)); test('LONG: Blob 16K', () => - blobTestSuite(14, 'sha1-43cc3d646647cb63dfe3c13ea6e352fecc597379', 2, 2, 2)); + blobTestSuite(14, 'sha1-8741539c258f9c464b08d099cb2521f19138eae7', 2, 2, 2)); test('LONG: Blob 64K', () => - blobTestSuite(16, 'sha1-5af76c7ea2a964ff7355418c3ec38504ee6cbd9e', 3, 2, 2)); + blobTestSuite(16, 'sha1-f2563df4e20835fb3402837272a24f58e9e48bd8', 3, 2, 2)); test('LONG: Blob 256K', () => - blobTestSuite(18, 'sha1-2fe75543395ab5f54d0586b88f79d44ebc41490d', 8, 2, 2)); + blobTestSuite(18, 'sha1-f97d8d77fb1e3ef21f2ccccbde810151b4e8c4e9', 8, 2, 2)); suite('BlobWriter', () => { let db; diff --git a/js/src/codec.js b/js/src/codec.js index e923a8a704..2ced2a4bab 100644 --- a/js/src/codec.js +++ b/js/src/codec.js @@ -14,6 +14,8 @@ import {setHash, ValueBase} from './value.js'; import type Value from './value.js'; import type {ValueReader, ValueWriter} from './value-store.js'; import * as Bytes from './bytes.js'; +import {floatToIntExp, intExpToFloat} from './number-util.js'; +import svarint from 'signed-varint'; export function encodeValue(v: Value, vw: ?ValueWriter): Chunk { const w = new BinaryNomsWriter(); @@ -50,7 +52,7 @@ export interface NomsReader { readUint8(): number; readUint32(): number; readUint64(): number; - readFloat64(): number; + readNumber(): number; readBool(): boolean; readString(): string; readHash(): Hash; @@ -61,7 +63,7 @@ export interface NomsWriter { writeUint8(v: number): void; writeUint32(v: number): void; writeUint64(v: number): void; - writeFloat64(v: number): void; + writeNumber(v: number): void; writeBool(v:boolean): void; writeString(v: string): void; writeHash(h: Hash): void; @@ -106,10 +108,12 @@ export class BinaryNomsReader { return v; } - readFloat64(): number { - const v = this.dv.getFloat64(this.offset, littleEndian); - this.offset += 8; - return v; + readNumber(): number { + const intVal = svarint.decode(this.buff, this.offset); + this.offset += svarint.decode.bytes; + const expVal = svarint.decode(this.buff, this.offset); + this.offset += svarint.decode.bytes; + return intExpToFloat(intVal, expVal); } readBool(): boolean { @@ -194,10 +198,16 @@ export class BinaryNomsWriter { this.writeUint32(v2); } - writeFloat64(v: number): void { - this.ensureCapacity(8); - this.dv.setFloat64(this.offset, v, littleEndian); - this.offset += 8; + writeNumber(v: number): void { + const [intVal, expVal] = floatToIntExp(v); + const intLen = svarint.encodingLength(intVal); + const expLen = svarint.encodingLength(expVal); + this.ensureCapacity(intLen + expLen); + + svarint.encode(intVal, this.buff, this.offset); + this.offset += intLen; + svarint.encode(expVal, this.buff, this.offset); + this.offset += expLen; } writeBool(v:boolean): void { diff --git a/js/src/compare-test.js b/js/src/compare-test.js index 8f803ceebf..db752f1035 100644 --- a/js/src/compare-test.js +++ b/js/src/compare-test.js @@ -41,8 +41,8 @@ suite('compare.js', () => { assert.equal(compare(listA, listA), 0); assert.equal(compare(listA, listB), 0); // These two are ordered by hash - assert.isAbove(compare(listC, listA), 0); - assert.isBelow(compare(listA, listC), 0); + assert.isAbove(compare(listA, listC), 0); + assert.isBelow(compare(listC, listA), 0); }); test('union', () => { diff --git a/js/src/encoding-test.js b/js/src/encoding-test.js index 483f4ce478..c3f7a84f3a 100644 --- a/js/src/encoding-test.js +++ b/js/src/encoding-test.js @@ -154,7 +154,7 @@ suite('Encoding', () => { return tagged.value; } - readFloat64(): number { + readNumber(): number { const tagged = this.read(); invariant(tagged.type === 'float64'); return tagged.value; @@ -205,7 +205,7 @@ suite('Encoding', () => { this.write(uint64(v)); } - writeFloat64(v: number): void { + writeNumber(v: number): void { this.write(float64(v)); } diff --git a/js/src/list-test.js b/js/src/list-test.js index 779a47591c..05779501c4 100644 --- a/js/src/list-test.js +++ b/js/src/list-test.js @@ -36,7 +36,7 @@ import {TestDatabase} from './test-util.js'; import {IndexedMetaSequence} from './meta-sequence.js'; const testListSize = 5000; -const listOfNRef = 'sha1-241e54086d50c131db3c2f3f5f17e68f42fd98ac'; +const listOfNRef = 'sha1-cb53c5de1ccef77930f19fce6c425998a763b231'; async function assertToJS(list: List, nums: Array, start: number = 0, end: number = nums.length): Promise { @@ -148,18 +148,18 @@ suite('List', () => { } test('List 1K', async () => { - await listTestSuite(10, 'sha1-99a9e8aa75f9363b561d4576c99630b1103c9083', 2, 2, 2); + await listTestSuite(10, 'sha1-d797568943812c45ec530c80d3a2654a77649890', 17, 5, 1); }); test('LONG: List 4K', async () => { - await listTestSuite(12, 'sha1-3e4d4c123dceea5b45fcddb207a40b7e0f69a4f2', 4, 2, 2); + await listTestSuite(12, 'sha1-be2dbb48eaee147211a3f57da879feefd3e44269', 2, 2, 2); }); test('LONG: list of ref, set of n numbers, length', async () => { const nums = intSequence(testListSize); const refs = nums.map(n => new Ref(newStruct('num', {n}))); const s = new List(refs); - assert.strictEqual('sha1-ac7830942e248613be6643a2667048667e9c22d1', s.hash.toString()); + assert.strictEqual('sha1-6a02619eb8074f89ee2f0453837140f6e796609f', s.hash.toString()); assert.strictEqual(testListSize, s.length); const height = deriveCollectionHeight(s); @@ -635,6 +635,7 @@ suite('ListWriter', () => { w.write(values[i]); } + writes++; writes++; assert.equal(db.writeCount, writes); diff --git a/js/src/map-test.js b/js/src/map-test.js index 3b51bb1282..13f0faed70 100644 --- a/js/src/map-test.js +++ b/js/src/map-test.js @@ -40,7 +40,7 @@ import { } from './type.js'; const testMapSize = 1000; -const mapOfNRef = 'sha1-9fce950ce2606ced8681a695b608384c642ffb53'; +const mapOfNRef = 'sha1-0ce27caa55f6fec82da76e1bc84fe459b7387791'; const smallRandomMapSize = 50; const randomMapSize = 500; @@ -85,21 +85,21 @@ suite('BuildMap', () => { } test('Map 1K', async () => { - await mapTestSuite(10, 'sha1-b4dfda98cac31acfb42c42bbe7692d576855e520', 2, i => i); + await mapTestSuite(10, 'sha1-ccda04ba3961a70124e029c2e9af7b0537e726db', 16, i => i); }); test('LONG: Map 4K', async () => { - await mapTestSuite(12, 'sha1-7d650134fa9c0424a4c5ff93f377b8e8d54dbd0f', 4, i => i); + await mapTestSuite(12, 'sha1-80e91e9538aeaabe75793c6c29d03954ac81d221', 2, i => i); }); const newNumberStruct = i => newStruct('', {n: i}); test('Map 1K structs', async () => { - await mapTestSuite(10, 'sha1-73ab90e854ea52001e59ea4b097c9f3b40565d8c', 18, newNumberStruct); + await mapTestSuite(10, 'sha1-17a96ed265da91aa992be70dba34cd9c3b9000df', 2, newNumberStruct); }); test('LONG: Map 4K structs', async () => { - await mapTestSuite(12, 'sha1-b48765e4423ec48eb5925276794b2864a4b48928', 76, newNumberStruct); + await mapTestSuite(12, 'sha1-ed658ef24dbc4fa2fecefa1e215bc06887199935', 2, newNumberStruct); }); test('unique keys - strings', async () => { @@ -154,7 +154,7 @@ suite('BuildMap', () => { const kvRefs = kvs.map(entry => entry.map(n => new Ref(newStruct('num', {n})))); const m = new Map(kvRefs); - assert.strictEqual(m.hash.toString(), 'sha1-c43b17db2fa433aa1842b8b0b25acfd10e035be3'); + assert.strictEqual(m.hash.toString(), 'sha1-5c36c25f8d62e72b3d02089febab440049236631'); const height = deriveCollectionHeight(m); assert.isTrue(height > 0); // height + 1 because the leaves are Ref values (with height 1). @@ -268,7 +268,7 @@ suite('BuildMap', () => { const sortedKeys = numbers.concat(strings, structs); const m = new Map(kvs); - assert.strictEqual(m.hash.toString(), 'sha1-96504f677dae417f0714af77b3e313ca1c3764e6'); + assert.strictEqual(m.hash.toString(), 'sha1-4e3eb68ff102c74aa7305753ee2ebcc4ebdebf62'); const height = deriveCollectionHeight(m); assert.isTrue(height > 0); assert.strictEqual(height, m.sequence.items[0].ref.height); diff --git a/js/src/number-util.js b/js/src/number-util.js new file mode 100644 index 0000000000..3e877ad1bf --- /dev/null +++ b/js/src/number-util.js @@ -0,0 +1,26 @@ +// @flow + +// Copyright 2016 Attic Labs, Inc. All rights reserved. +// Licensed under the Apache License, version 2.0: +// http://www.apache.org/licenses/LICENSE-2.0 + +// convert float to [int, exp] where f = i / 2^exp +export function floatToIntExp(f: number): [number, number] { + if (f === 0) { + return [0, 0]; + } + let exp = 0; + while (!Number.isInteger(f)) { + f *= 2; + exp++; + } + return [f, exp]; +} + +// returns float value of i / 2^exp +export function intExpToFloat(i: number, exp: number): number { + if (exp === 0) { + return i; + } + return i / Math.pow(2, exp); +} diff --git a/js/src/set-test.js b/js/src/set-test.js index 87a4e20ceb..c96eaf18ee 100644 --- a/js/src/set-test.js +++ b/js/src/set-test.js @@ -37,7 +37,7 @@ import { } from './type.js'; const testSetSize = 5000; -const setOfNRef = 'sha1-1fc97c4e369770b643e013569c68687765601514'; +const setOfNRef = 'sha1-ae7716c21164c7095686610371fd8e4af7b4e7c2'; const smallRandomSetSize = 200; const randomSetSize = 2000; @@ -72,21 +72,21 @@ suite('BuildSet', () => { } test('Set 1K', async () => { - await setTestSuite(10, 'sha1-5e5eda1a8813f19d0e5e68e6725cb6b3d9b63daa', 14, i => i); + await setTestSuite(10, 'sha1-1520836622fd7cd2964c3d49c3076a270422e255', 16, i => i); }); test('LONG: Set 4K', async () => { - await setTestSuite(12, 'sha1-d32df81dba427a00d949f3dbca477a5d2d8057a9', 2, i => i); + await setTestSuite(12, 'sha1-874d250b19dab05ddc63feb301ba95bdafcf8a7d', 2, i => i); }); const newNumberStruct = i => newStruct('', {n: i}); test('Set 1K structs', async () => { - await setTestSuite(10, 'sha1-9d904bcb2b06b0361a73f9ccbdfeca53f081030f', 18, newNumberStruct); + await setTestSuite(10, 'sha1-217eba8e53962c0efea24f4c22e6a525bb1663dd', 14, newNumberStruct); }); test('LONG: Set 4K structs', async () => { - await setTestSuite(12, 'sha1-a8f3b3362cde66638e6e1fb8359ad5675b7b5292', 2, newNumberStruct); + await setTestSuite(12, 'sha1-3ac7ebc9123028d1ade619f539ad4d488a3ab6ea', 2, newNumberStruct); }); test('unique keys - strings', async () => { @@ -124,7 +124,7 @@ suite('BuildSet', () => { const nums = intSequence(testSetSize); const structs = nums.map(n => newStruct('num', {n})); const s = new Set(structs); - assert.strictEqual('sha1-4f207ac30b7922b5c2181769ce827d9a3cbc8b9b', s.hash.toString()); + assert.strictEqual('sha1-dd51e00ce152fbcab72d625ec2c2895f9264ec8f', s.hash.toString()); const height = deriveCollectionHeight(s); assert.isTrue(height > 0); assert.strictEqual(height, s.sequence.items[0].ref.height); @@ -139,7 +139,7 @@ suite('BuildSet', () => { const nums = intSequence(testSetSize); const refs = nums.map(n => new Ref(newStruct('num', {n}))); const s = new Set(refs); - assert.strictEqual('sha1-084c21ccfb81d18d1b6da8bae6b5de1f52d1bd00', s.hash.toString()); + assert.strictEqual('sha1-73ceda53a24ffc2d76d17a34b772468cfe84576f', s.hash.toString()); const height = deriveCollectionHeight(s); assert.isTrue(height > 0); // height + 1 because the leaves are Ref values (with height 1). @@ -231,7 +231,7 @@ suite('BuildSet', () => { vals.sort(compare); const s = new Set(vals); - assert.strictEqual('sha1-b40b9337b0a87c1c0233a415e28bd5294cab6abb', s.hash.toString()); + assert.strictEqual('sha1-7b6b734e9cb67af9a93dd82ae82a60a2d4ae8ad5', s.hash.toString()); const height = deriveCollectionHeight(s); assert.isTrue(height > 0); assert.strictEqual(height, s.sequence.items[0].ref.height); diff --git a/js/src/value-decoder.js b/js/src/value-decoder.js index 3d1a5025a2..1c66636fe6 100644 --- a/js/src/value-decoder.js +++ b/js/src/value-decoder.js @@ -156,7 +156,7 @@ export default class ValueDecoder { case Kind.Bool: return this._r.readBool(); case Kind.Number: - return this._r.readFloat64(); + return this._r.readNumber(); case Kind.String: return this._r.readString(); case Kind.List: { diff --git a/js/src/value-encoder.js b/js/src/value-encoder.js index 91bfd8137f..0d6b17a3f2 100644 --- a/js/src/value-encoder.js +++ b/js/src/value-encoder.js @@ -153,7 +153,7 @@ export default class ValueEncoder { case Kind.Number: invariant(typeof v === 'number', () => `Failed to write Number. Invalid type: ${describeTypeOfValue(v)}`); - this._w.writeFloat64(v); + this._w.writeNumber(v); break; case Kind.List: { invariant(v instanceof List, diff --git a/js/src/version.js b/js/src/version.js index f9df8d05f1..39198510dd 100644 --- a/js/src/version.js +++ b/js/src/version.js @@ -4,4 +4,4 @@ // Licensed under the Apache License, version 2.0: // http://www.apache.org/licenses/LICENSE-2.0 -export default '2'; +export default '3'; diff --git a/js/src/xp-test.js b/js/src/xp-test.js index 3299ed38cb..f31d8dedea 100644 --- a/js/src/xp-test.js +++ b/js/src/xp-test.js @@ -46,9 +46,9 @@ suite('cross platform test', () => { const testValues = [ new TestValue(true, 'sha1-3f29546453678b855931c174a97d6c0894b8f546', 'bool - true'), new TestValue(false, 'sha1-1489f923c4dca729178b3e3233458550d8dddf29', 'bool - false'), - new TestValue(-1, 'sha1-cd243416f913f4a81d020a866266316b30200e34', 'num - -1'), - new TestValue(0, 'sha1-80e331473af6cb0cd7ae6f75793070cfbc4d642b', 'num - 0'), - new TestValue(1, 'sha1-9f34f68652a49c4b7cc5e25951311e92c61d46d0', 'num - 1'), + new TestValue(-1, 'sha1-47ec8d98366433dc002e7721c9e37d5067547937', 'num - -1'), + new TestValue(0, 'sha1-9508e90548b0440a4a61e5743b76c1e309b23b7f', 'num - 0'), + new TestValue(1, 'sha1-9f36f27018671b24dcdf70c9eb857d5ea2a064c8', 'num - 1'), new TestValue('', 'sha1-e1bc1dae59f116abb43f9dafbb2acc9b141aa6b0', 'str - empty'), new TestValue('0', 'sha1-a1c90c71d1ffdb51138677c578e6f2e8a011070d', 'str - 0'), new TestValue('false', 'sha1-e15d53dc6c9d3aa6eca4eea28382c9c45ba8fd9e', 'str - false'), diff --git a/samples/go/hr/.gitignore b/samples/go/hr/.gitignore new file mode 100644 index 0000000000..fcb5e9c654 --- /dev/null +++ b/samples/go/hr/.gitignore @@ -0,0 +1 @@ +hr diff --git a/samples/go/hr/build_test_data.sh b/samples/go/hr/build_test_data.sh new file mode 100755 index 0000000000..bd404b8254 --- /dev/null +++ b/samples/go/hr/build_test_data.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +if [ -d test-data ]; then + mv test-data test-data.bak +fi + +./hr -ds test-data::hr add-person 7 "Aaron Boodman" "Chief Evangelism Officer" +./hr -ds test-data::hr add-person 13 "Samuel Boodman" "VP, Culture" + diff --git a/samples/go/hr/test-data/000002.ldb b/samples/go/hr/test-data/000002.ldb index e7676e9dd1..e472a47892 100644 Binary files a/samples/go/hr/test-data/000002.ldb and b/samples/go/hr/test-data/000002.ldb differ diff --git a/samples/go/hr/test-data/000003.log b/samples/go/hr/test-data/000003.log index ade720a3e4..4cc84dd5a1 100644 Binary files a/samples/go/hr/test-data/000003.log and b/samples/go/hr/test-data/000003.log differ diff --git a/samples/go/hr/test-data/LOG b/samples/go/hr/test-data/LOG index 6ec3ce961e..a05f1ac73a 100644 --- a/samples/go/hr/test-data/LOG +++ b/samples/go/hr/test-data/LOG @@ -1,10 +1,10 @@ -=============== Jun 23, 2016 (PDT) =============== -15:35:19.958917 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed -15:35:19.959337 db@open opening -15:35:19.959481 journal@recovery F·1 -15:35:19.960200 journal@recovery recovering @1 -15:35:19.961638 memdb@flush created L0@2 N·4 S·563B "/ch..\xbdO\xe1,v2":"/vers,v1" -15:35:19.963310 db@janitor F·3 G·0 -15:35:19.963335 db@open done T·3.979371ms -15:35:19.964056 db@close closing -15:35:19.964188 db@close done T·108.38µs +=============== Jul 11, 2016 (PDT) =============== +10:20:40.754716 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed +10:20:40.755153 db@open opening +10:20:40.755212 journal@recovery F·1 +10:20:40.755854 journal@recovery recovering @1 +10:20:40.758518 memdb@flush created L0@2 N·4 S·558B "/ch..\xe7\x0f8,v3":"/vers,v1" +10:20:40.759925 db@janitor F·3 G·0 +10:20:40.759947 db@open done T·4.782632ms +10:20:40.760616 db@close closing +10:20:40.760702 db@close done T·84.005µs diff --git a/samples/go/hr/test-data/LOG.old b/samples/go/hr/test-data/LOG.old index 99b8622aee..b896c593b1 100644 --- a/samples/go/hr/test-data/LOG.old +++ b/samples/go/hr/test-data/LOG.old @@ -1,7 +1,7 @@ -=============== Jun 23, 2016 (PDT) =============== -15:35:14.753756 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed -15:35:14.754345 db@open opening -15:35:14.755509 db@janitor F·2 G·0 -15:35:14.755562 db@open done T·1.197988ms -15:35:14.756433 db@close closing -15:35:14.756504 db@close done T·62.056µs +=============== Jul 11, 2016 (PDT) =============== +10:20:40.741086 log@legend F·NumFile S·FileSize N·Entry C·BadEntry B·BadBlock Ke·KeyError D·DroppedEntry L·Level Q·SeqNum T·TimeElapsed +10:20:40.741928 db@open opening +10:20:40.743679 db@janitor F·2 G·0 +10:20:40.743711 db@open done T·1.755791ms +10:20:40.744305 db@close closing +10:20:40.744376 db@close done T·64.884µs diff --git a/samples/go/hr/test-data/MANIFEST-000004 b/samples/go/hr/test-data/MANIFEST-000004 index e531dee8e7..d413083093 100644 Binary files a/samples/go/hr/test-data/MANIFEST-000004 and b/samples/go/hr/test-data/MANIFEST-000004 differ