Skip to content

Commit

Permalink
feat(pointer): better performance through directly managed pointers
Browse files Browse the repository at this point in the history
  • Loading branch information
Arqu committed May 7, 2020
1 parent 43be820 commit 2ed0ba9
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 2 deletions.
35 changes: 35 additions & 0 deletions pointer.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import (
"strings"
)

const defaultPointerAllocationSize = 32

// Parse parses str into a Pointer structure.
// str may be a pointer or a url string.
// If a url string, Parse will use the URL's fragment component
Expand All @@ -35,6 +37,25 @@ func Parse(str string) (Pointer, error) {
return parse(u.Fragment)
}

// IsEmpty is a utility function to check if the Pointer
// is empty / nil equivalent
func (p Pointer) IsEmpty() bool {
return len(p) == 0
}

// Head returns the root of the Pointer
func (p Pointer) Head() *string {
if len(p) == 0 {
return nil
}
return &p[0]
}

// Tail returns everything after the Pointer head
func (p Pointer) Tail() Pointer {
return Pointer(p[1:])
}

// The ABNF syntax of a JSON Pointer is:
// json-pointer = *( "/" reference-token )
// reference-token = *( unescaped / escaped )
Expand Down Expand Up @@ -62,6 +83,12 @@ func parse(str string) (Pointer, error) {
// Pointer represents a parsed JSON pointer
type Pointer []string

// NewPointer creates a Pointer with a pre-allocated block of memory
// to avoid repeated slice expansions
func NewPointer() Pointer {
return make([]string, 0, defaultPointerAllocationSize)
}

// String implements the stringer interface for Pointer,
// giving the escaped string
func (p Pointer) String() (str string) {
Expand Down Expand Up @@ -104,6 +131,14 @@ func (p Pointer) Descendant(path string) (Pointer, error) {
return append(p, dpath...), nil
}

// RawDescendant extends the pointer with 1 or more path tokens
// The function itself is unsafe as it doesnt fully parse the input
// and assumes the user is directly managing the pointer
// This allows for much faster pointer management
func (p Pointer) RawDescendant(path ...string) Pointer {
return append(p, path...)
}

// Evaluation of each reference token begins by decoding any escaped
// character sequence. This is performed by first transforming any
// occurrence of the sequence '~1' to '/', and then transforming any
Expand Down
5 changes: 3 additions & 2 deletions pointer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/json"
"fmt"
"reflect"
"strings"
"testing"
)

Expand Down Expand Up @@ -60,15 +61,15 @@ func TestParse(t *testing.T) {
{"#/foo", "/foo", ""},
{"#/foo/", "/foo/", ""},

{"://", "", "parse ://: missing protocol scheme"},
{"://", "", "missing protocol scheme"},
{"#7", "", "non-empty references must begin with a '/' character"},
{"", "", ""},
{"https://example.com#", "", ""},
}

for i, c := range cases {
got, err := Parse(c.raw)
if !(err == nil && c.err == "" || err != nil && err.Error() == c.err) {
if !(err == nil && c.err == "" || err != nil && strings.Contains(err.Error(), c.err)) {
t.Errorf("case %d error mismatch. expected: '%s', got: '%s'", i, c.err, err)
continue
}
Expand Down

0 comments on commit 2ed0ba9

Please sign in to comment.