Skip to content

Commit

Permalink
Remove string to byte slice conversions at runtime
Browse files Browse the repository at this point in the history
All those were constants anyways.
  • Loading branch information
kaiburjack committed Feb 14, 2022
1 parent ede6482 commit ac5ed41
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 26 deletions.
10 changes: 8 additions & 2 deletions decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ type decoder struct {
lastStartElement bool
}

var (
bsxml = []byte("xml")
bsspace = []byte("space")
bspreserve = []byte("preserve")
)

// NewDecoder creates a new Decoder.
func NewDecoder(r io.Reader) Decoder {
return &decoder{
Expand Down Expand Up @@ -477,8 +483,8 @@ func (thiz *decoder) decodeAttribute(attr *Attr) error {
return err
}
// xml:space?
if bytes.Equal(name.Prefix, bs("xml")) && bytes.Equal(name.Local, bs("space")) {
thiz.preserveWhitespaces[thiz.top] = bytes.Equal(value, bs("preserve"))
if bytes.Equal(name.Prefix, bsxml) && bytes.Equal(name.Local, bsspace) {
thiz.preserveWhitespaces[thiz.top] = bytes.Equal(value, bspreserve)
}
attr.Name = name
attr.SingleQuote = singleQuote
Expand Down
26 changes: 8 additions & 18 deletions encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,18 @@ package gosaxml
import (
"errors"
"io"
"reflect"
"unsafe"
)

const (
// all characters used to build new namespace aliases
namespaceAliases = "abcdefghijklmnopqrstuvwxyz"
)

// pre-allocate all constant byte slices that we write
var (
slashAngleClose = bs("/>")
angleOpenSlash = bs("</")
angleOpenQuest = bs("<?")
questAngleClose = bs("?>")
// all characters used to build new namespace aliases
namespaceAliases = []byte("abcdefghijklmnopqrstuvwxyz")

// constant strings needed here and there
slashAngleClose = []byte("/>")
angleOpenSlash = []byte("</")
angleOpenQuest = []byte("<?")
questAngleClose = []byte("?>")
)

// EncoderMiddleware allows to pre-process a Token before
Expand Down Expand Up @@ -331,10 +328,3 @@ func (thiz *Encoder) encodeProcInst(t *Token) error {
err = thiz.writeBytes(questAngleClose)
return err
}

// https://stackoverflow.com/questions/59209493/how-to-use-unsafe-get-a-byte-slice-from-a-string-without-memory-copy#answer-59210739
func bs(s string) []byte {
return (*[0x7fff0000]byte)(unsafe.Pointer(
(*reflect.StringHeader)(unsafe.Pointer(&s)).Data),
)[:len(s):len(s)]
}
15 changes: 9 additions & 6 deletions namespaceModifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ type NamespaceModifier struct {
PreserveOriginalPrefixes bool
}

var (
bsxmlns = []byte("xmlns")
)

// NewNamespaceModifier creates a new NamespaceModifier and returns a pointer to it.
func NewNamespaceModifier() *NamespaceModifier {
return &NamespaceModifier{
Expand Down Expand Up @@ -154,7 +158,7 @@ func (thiz *NamespaceModifier) processNamespaces(t *Token) {
for i := 0; i < len(t.Attr); i++ {
attr := &t.Attr[i]
// check for advertized namespaces in attributes
if bytes.Equal(attr.Name.Prefix, bs("xmlns")) { // <- xmlns:prefix
if bytes.Equal(attr.Name.Prefix, bsxmlns) { // <- xmlns:prefix
// this element introduces a new namespace that binds to a prefix
// check if we already know this namespace by this or another prefix
prefix := thiz.findPrefixForNamespace(attr.Value)
Expand All @@ -171,14 +175,13 @@ func (thiz *NamespaceModifier) processNamespaces(t *Token) {
// wo don't know the prefix, but we want to rewrite it
nextPrefixAlias := len(thiz.prefixAliases) / 2
c := namespaceAliases[nextPrefixAlias : nextPrefixAlias+1]
bsc := bs(c)
thiz.addPrefixRewrite(attr.Name.Local, bsc)
thiz.addNamespaceBinding(bsc, attr.Value)
attr.Name.Local = bsc
thiz.addPrefixRewrite(attr.Name.Local, c)
thiz.addNamespaceBinding(c, attr.Value)
attr.Name.Local = c
} else {
thiz.addNamespaceBinding(attr.Name.Local, attr.Value)
}
} else if attr.Name.Prefix == nil && bytes.Equal(attr.Name.Local, bs("xmlns")) {
} else if attr.Name.Prefix == nil && bytes.Equal(attr.Name.Local, bsxmlns) {
// check if the element is already in that namespace, in which case
// we can simply omit the namespace.
currentNamespace := thiz.findNamespaceForPrefix(nil)
Expand Down

0 comments on commit ac5ed41

Please sign in to comment.