Skip to content
Snippets Groups Projects
Unverified Commit 25aa4e1d authored by Wolfgang Welz's avatar Wolfgang Welz Committed by GitHub
Browse files

Merge pull request #69 from iotaledger/chore/conv

Improved []byte<->string conversion
parents a996497e 2f20bca2
No related branches found
No related tags found
No related merge requests found
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
}
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
}
package typeutils
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)
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment