From 6b71eb1ef78f2af56092ef3a29930d0c9d6fb2cb Mon Sep 17 00:00:00 2001
From: Wolfgang Welz <welzwo@gmail.com>
Date: Thu, 1 Aug 2019 19:09:14 +0200
Subject: [PATCH] Use optimized version to convert bytes and string

---
 packages/typeutils/typeutils.go | 14 +-------------
 packages/typeutils/unsafe.go    | 30 ++++++++++++++++++++++++++++++
 2 files changed, 31 insertions(+), 13 deletions(-)
 create mode 100644 packages/typeutils/unsafe.go

diff --git a/packages/typeutils/typeutils.go b/packages/typeutils/typeutils.go
index eed90cf9..6bd97c88 100644
--- a/packages/typeutils/typeutils.go
+++ b/packages/typeutils/typeutils.go
@@ -1,22 +1,10 @@
 package typeutils
 
 import (
-	"reflect"
 	"unsafe"
 )
 
-func BytesToString(b []byte) string {
-	bh := (*reflect.SliceHeader)(unsafe.Pointer(&b))
-
-	return *(*string)(unsafe.Pointer(&reflect.StringHeader{Data: bh.Data, Len: bh.Len}))
-}
-
-func StringToBytes(str string) []byte {
-	hdr := (*reflect.StringHeader)(unsafe.Pointer(&str))
-
-	return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{Data: hdr.Data, Len: hdr.Len, Cap: hdr.Len}))
-}
-
+// Checks whether an interface is nil or has the value nil.
 func IsInterfaceNil(param interface{}) bool {
 	return param == nil || (*[2]uintptr)(unsafe.Pointer(&param))[1] == 0
 }
diff --git a/packages/typeutils/unsafe.go b/packages/typeutils/unsafe.go
new file mode 100644
index 00000000..56e8a996
--- /dev/null
+++ b/packages/typeutils/unsafe.go
@@ -0,0 +1,30 @@
+package typeutils
+
+import (
+	"reflect"
+	"runtime"
+	"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(b []byte) string {
+	return *(*string)(unsafe.Pointer(&b))
+}
+
+// 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 {
+	sh := (*reflect.StringHeader)(unsafe.Pointer(&s))
+	b := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
+		Data: sh.Data,
+		Len:  sh.Len,
+		Cap:  sh.Len,
+	}))
+	// ensure the underlying string doesn't get GC'ed before the assignment happens
+	runtime.KeepAlive(&s)
+
+	return b
+}
-- 
GitLab