From 8d50f5104debef584d494c52b8c8d5e7a61875a8 Mon Sep 17 00:00:00 2001 From: Long Hoang Date: Sun, 26 Feb 2017 17:32:35 +0800 Subject: [PATCH] Introduce build tags to disable unsafe package usage Package `unsafe` is used in jlexer to prevent copying when casting from []byte to string, speeding up the marshalling process to a large extent. However, `unsafe` is not allowed in environments such as Google Appengine. Therefore two build tags are introduced, which either of them can disable the use of unsafe package, falling back to conventional copy-based []byte to string conversion. The build tags are `easyjson_nounsafe` and `appengine` (which is set when building for Google Appengine) --- benchmark/data_codec.go | 5 ++++- jlexer/bytestostr.go | 20 ++++++++++++++++++++ jlexer/bytestostr_nounsafe.go | 10 ++++++++++ jlexer/lexer.go | 13 ------------- 4 files changed, 34 insertions(+), 14 deletions(-) create mode 100644 jlexer/bytestostr.go create mode 100644 jlexer/bytestostr_nounsafe.go diff --git a/benchmark/data_codec.go b/benchmark/data_codec.go index 0bb8c4c..d2d83fa 100644 --- a/benchmark/data_codec.go +++ b/benchmark/data_codec.go @@ -1,4 +1,6 @@ //+build use_codec +//+build !easyjson_nounsafe +//+build !appengine // ************************************************************ // DO NOT EDIT. @@ -10,10 +12,11 @@ package benchmark import ( "errors" "fmt" - codec1978 "github.com/ugorji/go/codec" "reflect" "runtime" "unsafe" + + codec1978 "github.com/ugorji/go/codec" ) const ( diff --git a/jlexer/bytestostr.go b/jlexer/bytestostr.go new file mode 100644 index 0000000..516b193 --- /dev/null +++ b/jlexer/bytestostr.go @@ -0,0 +1,20 @@ +//+build !easyjson_nounsafe +//+build !appengine + +package jlexer + +import ( + "reflect" + "unsafe" +) + +// bytesToStr creates a string pointing at the slice to avoid copying. +// +// Warning: the string returned by the function should be used with care, as the whole input data +// chunk may be either blocked from being freed by GC because of a single string or the buffer.Data +// may be garbage-collected even when the string exists. +func bytesToStr(data []byte) string { + h := (*reflect.SliceHeader)(unsafe.Pointer(&data)) + shdr := reflect.StringHeader{h.Data, h.Len} + return *(*string)(unsafe.Pointer(&shdr)) +} diff --git a/jlexer/bytestostr_nounsafe.go b/jlexer/bytestostr_nounsafe.go new file mode 100644 index 0000000..f6d6ef3 --- /dev/null +++ b/jlexer/bytestostr_nounsafe.go @@ -0,0 +1,10 @@ +//+build easyjson_nounsafe appengine + +package jlexer + +// bytesToStr creates a string normally from []byte +// +// Note that this method is roughly 1.5x slower than using the 'unsafe' method. +func bytesToStr(data []byte) string { + return string(data) +} diff --git a/jlexer/lexer.go b/jlexer/lexer.go index c8a5d07..ae8344e 100644 --- a/jlexer/lexer.go +++ b/jlexer/lexer.go @@ -9,12 +9,10 @@ import ( "errors" "fmt" "io" - "reflect" "strconv" "unicode" "unicode/utf16" "unicode/utf8" - "unsafe" ) // tokenKind determines type of a token. @@ -205,17 +203,6 @@ func (r *Lexer) fetchFalse() { } } -// bytesToStr creates a string pointing at the slice to avoid copying. -// -// Warning: the string returned by the function should be used with care, as the whole input data -// chunk may be either blocked from being freed by GC because of a single string or the buffer.Data -// may be garbage-collected even when the string exists. -func bytesToStr(data []byte) string { - h := (*reflect.SliceHeader)(unsafe.Pointer(&data)) - shdr := reflect.StringHeader{h.Data, h.Len} - return *(*string)(unsafe.Pointer(&shdr)) -} - // fetchNumber scans a number literal token. func (r *Lexer) fetchNumber() { hasE := false