From 6214286757a98b398792b8c4d88c732b45aca302 Mon Sep 17 00:00:00 2001 From: tdakkota Date: Mon, 3 Jan 2022 02:08:24 +0300 Subject: [PATCH 1/2] test(json): add UUID decode/encode benchmark --- json/uuid_test.go | 56 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 json/uuid_test.go diff --git a/json/uuid_test.go b/json/uuid_test.go new file mode 100644 index 000000000..583ecdac4 --- /dev/null +++ b/json/uuid_test.go @@ -0,0 +1,56 @@ +package json + +import ( + "testing" + + "github.com/go-faster/jx" + "github.com/google/uuid" +) + +func BenchmarkDecodeUUID(b *testing.B) { + e := jx.GetEncoder() + defer jx.PutEncoder(e) + + u, err := uuid.NewUUID() + if err != nil { + b.Fatal(err) + } + EncodeUUID(e, u) + data := e.Bytes() + + d := jx.GetDecoder() + defer jx.PutDecoder(d) + + b.ReportAllocs() + b.SetBytes(int64(len(data))) + b.ResetTimer() + + for i := 0; i < b.N; i++ { + d.ResetBytes(data) + if _, err := DecodeUUID(d); err != nil { + b.Fatal(err) + } + } +} + +func BenchmarkEncodeUUID(b *testing.B) { + e := jx.GetEncoder() + defer jx.PutEncoder(e) + + u, err := uuid.NewUUID() + if err != nil { + b.Fatal(err) + } + + EncodeUUID(e, u) + data := e.Bytes() + + b.ReportAllocs() + b.SetBytes(int64(len(data))) + b.ResetTimer() + + for i := 0; i < b.N; i++ { + e.Reset() + EncodeUUID(e, u) + } +} From 8904bc2040b61c2ed2d2129e42dabd0ac1e43d01 Mon Sep 17 00:00:00 2001 From: tdakkota Date: Mon, 3 Jan 2022 02:37:29 +0300 Subject: [PATCH 2/2] feat(json): optimize UUID encode/decode --- json/uuid.go | 51 ++++++++++++++++++++++++++++++++++++++++++++--- json/uuid_test.go | 12 +++++++++++ 2 files changed, 60 insertions(+), 3 deletions(-) diff --git a/json/uuid.go b/json/uuid.go index 9690a4c25..9db569066 100644 --- a/json/uuid.go +++ b/json/uuid.go @@ -7,14 +7,59 @@ import ( // DecodeUUID decodes UUID from json. func DecodeUUID(i *jx.Decoder) (v uuid.UUID, err error) { - s, err := i.Str() + s, err := i.StrBytes() if err != nil { return v, err } - return uuid.Parse(s) + return uuid.ParseBytes(s) } // EncodeUUID encodes UUID to json. func EncodeUUID(s *jx.Encoder, v uuid.UUID) { - s.Str(v.String()) + const ( + // Hexed length (16 * 2) + 4 hyphens + length = len(v)*2 + 4 + quotedLength = length + 2 + ) + var dst = [quotedLength]byte{ + 0: '"', + quotedLength - 1: '"', + } + hexEncode((*[length]byte)(dst[1:length+1]), v) + s.Raw(dst[:]) +} + +func hexEncode(dst *[36]byte, v uuid.UUID) { + const hextable = "0123456789abcdef" + + { + dst[0], dst[1] = hextable[v[0]>>4], hextable[v[0]&0x0f] + dst[2], dst[3] = hextable[v[1]>>4], hextable[v[1]&0x0f] + dst[4], dst[5] = hextable[v[2]>>4], hextable[v[2]&0x0f] + dst[6], dst[7] = hextable[v[3]>>4], hextable[v[3]&0x0f] + } + dst[8] = '-' + { + dst[9+0], dst[9+1] = hextable[v[4+0]>>4], hextable[v[4+0]&0x0f] + dst[9+2], dst[9+3] = hextable[v[4+1]>>4], hextable[v[4+1]&0x0f] + } + dst[13] = '-' + { + dst[14+0], dst[14+1] = hextable[v[6+0]>>4], hextable[v[6+0]&0x0f] + dst[14+2], dst[14+3] = hextable[v[6+1]>>4], hextable[v[6+1]&0x0f] + } + dst[18] = '-' + { + dst[19+0], dst[19+1] = hextable[v[8+0]>>4], hextable[v[8+0]&0x0f] + dst[19+2], dst[19+3] = hextable[v[8+1]>>4], hextable[v[8+1]&0x0f] + } + dst[23] = '-' + { + dst[24+0], dst[24+1] = hextable[v[10+0]>>4], hextable[v[10+0]&0x0f] + dst[24+2], dst[24+3] = hextable[v[10+1]>>4], hextable[v[10+1]&0x0f] + dst[24+4], dst[24+5] = hextable[v[10+2]>>4], hextable[v[10+2]&0x0f] + dst[24+6], dst[24+7] = hextable[v[10+3]>>4], hextable[v[10+3]&0x0f] + dst[24+8], dst[24+9] = hextable[v[10+4]>>4], hextable[v[10+4]&0x0f] + dst[24+10], dst[24+11] = hextable[v[10+5]>>4], hextable[v[10+5]&0x0f] + } } diff --git a/json/uuid_test.go b/json/uuid_test.go index 583ecdac4..0f13591c7 100644 --- a/json/uuid_test.go +++ b/json/uuid_test.go @@ -5,6 +5,7 @@ import ( "github.com/go-faster/jx" "github.com/google/uuid" + "github.com/stretchr/testify/require" ) func BenchmarkDecodeUUID(b *testing.B) { @@ -54,3 +55,14 @@ func BenchmarkEncodeUUID(b *testing.B) { EncodeUUID(e, u) } } + +func Test_hexEncode(t *testing.T) { + a := require.New(t) + + u, err := uuid.NewUUID() + a.NoError(err) + + var dst [36]byte + hexEncode(&dst, u) + a.Equal(u.String(), string(dst[:])) +}