From 9e45d490d92e835cba4ef5b9c1e1ea16c2027841 Mon Sep 17 00:00:00 2001 From: Wolfgang Welz <welzwo@gmail.com> Date: Fri, 5 Jul 2019 17:43:23 +0200 Subject: [PATCH] Add unsafe []byte-string conversion --- packages/unsafeconvert/unsafeconvert.go | 19 ++++ packages/unsafeconvert/unsafeconvert_test.go | 92 ++++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 packages/unsafeconvert/unsafeconvert.go create mode 100644 packages/unsafeconvert/unsafeconvert_test.go diff --git a/packages/unsafeconvert/unsafeconvert.go b/packages/unsafeconvert/unsafeconvert.go new file mode 100644 index 00000000..eb43bb70 --- /dev/null +++ b/packages/unsafeconvert/unsafeconvert.go @@ -0,0 +1,19 @@ +package unsafeconvert + +import ( + "unsafe" +) + +// Converts a slice of bytes into a string without performing a copy. +// NOTE: This is an unsafe operation and may lead to problems if the bytes +// passed as argument are changed while the string is used. No checking whether +// bytes are valid UTF-8 data is performed. +func BytesToString(bs []byte) string { + return *(*string)(unsafe.Pointer(&bs)) +} + +// Converts a string into a slice of bytes without performing a copy. +// NOTE: This is an unsafe operation and may lead to problems if the bytes are changed. +func StringToBytes(s string) []byte { + return *(*[]byte)(unsafe.Pointer(&s)) +} diff --git a/packages/unsafeconvert/unsafeconvert_test.go b/packages/unsafeconvert/unsafeconvert_test.go new file mode 100644 index 00000000..b6c343fd --- /dev/null +++ b/packages/unsafeconvert/unsafeconvert_test.go @@ -0,0 +1,92 @@ +package unsafeconvert + +import ( + "bytes" + "strings" + "testing" +) + +var testStrings = []string{ + "", + " ", + "test", + "ã“ã‚“ã«ã¡ã¯ã€ 世界", + strings.Repeat(" ", 10), + strings.Repeat(" ", 100), + strings.Repeat(" ", 10000), + strings.Repeat(" ", 1000000), +} + +func TestBytesToString(t *testing.T) { + for _, expected := range testStrings { + arg := []byte(expected) + actual := BytesToString(arg) + if actual != expected { + t.Errorf("BytesToString(%q) = %q but expected %q", arg, actual, expected) + } + } +} + +func TestStringToBytes(t *testing.T) { + for _, arg := range testStrings { + expected := []byte(arg) + actual := StringToBytes(arg) + if !bytes.Equal(actual, expected) { + t.Errorf("Bytes(%q) = %q but expected %q", arg, actual, expected) + } + } +} + +func TestNil(t *testing.T) { + actual := BytesToString(nil) + expected := "" + if actual != expected { + t.Errorf("String(nil) = %q but expected %q", actual, expected) + } +} + +func createTestBytes() [][]byte { + result := make([][]byte, len(testStrings)) + for i, str := range testStrings { + result[i] = []byte(str) + } + return result +} + +func BenchmarkNativeBytesToString(b *testing.B) { + testBytes := createTestBytes() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + for _, bs := range testBytes { + _ = string(bs) + } + } +} + +func BenchmarkUnsafeBytesToString(b *testing.B) { + testBytes := createTestBytes() + b.ResetTimer() + + for i := 0; i < b.N; i++ { + for _, bs := range testBytes { + _ = BytesToString(bs) + } + } +} + +func BenchmarkNativeStringToBytes(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, str := range testStrings { + _ = []byte(str) + } + } +} + +func BenchmarkUnsafeStringToBytes(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, str := range testStrings { + _ = StringToBytes(str) + } + } +} -- GitLab