diff --git a/vegz/README.md b/vegz/README.md new file mode 100644 index 0000000..a23f8d5 --- /dev/null +++ b/vegz/README.md @@ -0,0 +1,3 @@ +## vegz [runtime] + +В этой задаче нужно победить бенчмарк, переписав функцию сериализации в `gzip`. diff --git a/vegz/encode.go b/vegz/encode.go new file mode 100644 index 0000000..37b8cd0 --- /dev/null +++ b/vegz/encode.go @@ -0,0 +1,17 @@ +//go:build !solution + +package vegz + +import ( + "compress/gzip" + "io" +) + +func Encode(data []byte, w io.Writer) error { + ww := gzip.NewWriter(w) + defer func() { _ = ww.Close() }() + if _, err := ww.Write(data); err != nil { + return err + } + return ww.Flush() +} diff --git a/vegz/encode_test.go b/vegz/encode_test.go new file mode 100644 index 0000000..6bd1e58 --- /dev/null +++ b/vegz/encode_test.go @@ -0,0 +1,63 @@ +package vegz + +import ( + "bytes" + "compress/gzip" + "io" + "testing" + + "github.com/stretchr/testify/require" + "gitlab.com/slon/shad-go/tools/testtool" +) + +func BenchmarkEncode(b *testing.B) { + data := []byte( + "New function should generally only return pointer types, " + + "since a pointer can be put into the return interface " + + "value without an allocation. " + + testtool.RandomName(), + ) + + b.ResetTimer() + b.ReportAllocs() + for n := 0; n < b.N; n++ { + require.NoError(b, Encode(data, io.Discard)) + } +} + +func TestRoundTrip(t *testing.T) { + testCases := []struct { + name string + in string + }{ + {name: "empty", in: ""}, + {name: "simple", in: "A long time ago in a galaxy far, far away..."}, + {name: "random", in: testtool.RandomName()}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + buf := new(bytes.Buffer) + require.NoError(t, Encode([]byte(tc.in), buf)) + + out, err := decode(buf.Bytes()) + require.NoError(t, err, tc.in) + require.Equal(t, tc.in, string(out)) + }) + + } +} + +func decode(data []byte) ([]byte, error) { + r, err := gzip.NewReader(bytes.NewReader(data)) + if err != nil { + return nil, err + } + + buf := &bytes.Buffer{} + if _, err := io.Copy(buf, r); err != nil { + return nil, err + } + + return buf.Bytes(), nil +} diff --git a/vegz/solution.go b/vegz/solution.go new file mode 100644 index 0000000..2f6eb2c --- /dev/null +++ b/vegz/solution.go @@ -0,0 +1,31 @@ +//go:build solution + +package vegz + +import ( + "compress/gzip" + "io" + "sync" +) + +var writerPool = sync.Pool{ + New: func() interface{} { + return new(gzip.Writer) + }, +} + +func Encode(data []byte, w io.Writer) error { + ww := writerPool.Get().(*gzip.Writer) + defer func() { + _ = ww.Close() + writerPool.Put(ww) + }() + + ww.Reset(w) + + if _, err := ww.Write(data); err != nil { + return err + } + + return ww.Close() +}