@@ -19,22 +19,64 @@ package fieldpath
1919import (
2020 "bytes"
2121 "io"
22+ "unsafe"
2223
2324 jsoniter "github.com/json-iterator/go"
2425)
2526
2627func (s * Set ) ToJSON () ([]byte , error ) {
2728 buf := bytes.Buffer {}
28- stream := jsoniter .NewStream (jsoniter .ConfigCompatibleWithStandardLibrary , & buf , 4096 )
29+ err := s .ToJSONStream (& buf )
30+ if err != nil {
31+ return nil , err
32+ }
33+ return buf .Bytes (), nil
34+ }
35+
36+ func (s * Set ) ToJSONStream (w io.Writer ) error {
37+ stream := writePool .BorrowStream (w )
38+ defer writePool .ReturnStream (stream )
39+
40+ var r reusableBuilder
2941
3042 stream .WriteObjectStart ()
31- s .emitContents_v1 (false , stream )
43+ err := s .emitContents_v1 (false , stream , & r )
44+ if err != nil {
45+ return err
46+ }
3247 stream .WriteObjectEnd ()
33- err := stream .Flush ()
34- return buf .Bytes (), err
48+ return stream .Flush ()
49+ }
50+
51+ func manageMemory (stream * jsoniter.Stream ) error {
52+ // Help jsoniter manage its buffers--without this, it does a bunch of
53+ // alloctaions that are not necessary. They were probably optimizing
54+ // for folks using the buffer directly.
55+ b := stream .Buffer ()
56+ if len (b ) > 4096 || cap (b )- len (b ) < 2048 {
57+ if err := stream .Flush (); err != nil {
58+ return err
59+ }
60+ stream .SetBuffer (b [:0 ])
61+ }
62+ return nil
3563}
3664
37- func (s * Set ) emitContents_v1 (includeSelf bool , stream * jsoniter.Stream ) {
65+ type reusableBuilder struct {
66+ bytes.Buffer
67+ }
68+
69+ func (r * reusableBuilder ) unsafeString () string {
70+ b := r .Bytes ()
71+ return * (* string )(unsafe .Pointer (& b ))
72+ }
73+
74+ func (r * reusableBuilder ) reset () * bytes.Buffer {
75+ r .Reset ()
76+ return & r .Buffer
77+ }
78+
79+ func (s * Set ) emitContents_v1 (includeSelf bool , stream * jsoniter.Stream , r * reusableBuilder ) error {
3880 mi , ci := 0 , 0
3981 first := true
4082 preWrite := func () {
@@ -51,24 +93,34 @@ func (s *Set) emitContents_v1(includeSelf bool, stream *jsoniter.Stream) {
5193
5294 if mpe .Less (cpe ) {
5395 preWrite ()
54- str , _ := SerializePathElement (mpe )
55- stream .WriteObjectField (str )
96+ if err := serializePathElementToWriter (r .reset (), mpe ); err != nil {
97+ return err
98+ }
99+ stream .WriteObjectField (r .unsafeString ())
56100 stream .WriteEmptyObject ()
57101 mi ++
58102 } else if cpe .Less (mpe ) {
59103 preWrite ()
60- str , _ := SerializePathElement (cpe )
61- stream .WriteObjectField (str )
104+ if err := serializePathElementToWriter (r .reset (), cpe ); err != nil {
105+ return err
106+ }
107+ stream .WriteObjectField (r .unsafeString ())
62108 stream .WriteObjectStart ()
63- s .Children .members [ci ].set .emitContents_v1 (false , stream )
109+ if err := s .Children .members [ci ].set .emitContents_v1 (false , stream , r ); err != nil {
110+ return err
111+ }
64112 stream .WriteObjectEnd ()
65113 ci ++
66114 } else {
67115 preWrite ()
68- str , _ := SerializePathElement (cpe )
69- stream .WriteObjectField (str )
116+ if err := serializePathElementToWriter (r .reset (), cpe ); err != nil {
117+ return err
118+ }
119+ stream .WriteObjectField (r .unsafeString ())
70120 stream .WriteObjectStart ()
71- s .Children .members [ci ].set .emitContents_v1 (true , stream )
121+ if err := s .Children .members [ci ].set .emitContents_v1 (true , stream , r ); err != nil {
122+ return err
123+ }
72124 stream .WriteObjectEnd ()
73125 mi ++
74126 ci ++
@@ -79,8 +131,10 @@ func (s *Set) emitContents_v1(includeSelf bool, stream *jsoniter.Stream) {
79131 mpe := s .Members .members [mi ]
80132
81133 preWrite ()
82- str , _ := SerializePathElement (mpe )
83- stream .WriteObjectField (str )
134+ if err := serializePathElementToWriter (r .reset (), mpe ); err != nil {
135+ return err
136+ }
137+ stream .WriteObjectField (r .unsafeString ())
84138 stream .WriteEmptyObject ()
85139 mi ++
86140 }
@@ -89,10 +143,14 @@ func (s *Set) emitContents_v1(includeSelf bool, stream *jsoniter.Stream) {
89143 cpe := s .Children .members [ci ].pathElement
90144
91145 preWrite ()
92- str , _ := SerializePathElement (cpe )
93- stream .WriteObjectField (str )
146+ if err := serializePathElementToWriter (r .reset (), cpe ); err != nil {
147+ return err
148+ }
149+ stream .WriteObjectField (r .unsafeString ())
94150 stream .WriteObjectStart ()
95- s .Children .members [ci ].set .emitContents_v1 (false , stream )
151+ if err := s .Children .members [ci ].set .emitContents_v1 (false , stream , r ); err != nil {
152+ return err
153+ }
96154 stream .WriteObjectEnd ()
97155 ci ++
98156 }
@@ -102,10 +160,12 @@ func (s *Set) emitContents_v1(includeSelf bool, stream *jsoniter.Stream) {
102160 stream .WriteObjectField ("." )
103161 stream .WriteEmptyObject ()
104162 }
163+ return manageMemory (stream )
105164}
106165
107166// FromJSON clears s and reads a JSON formatted set structure.
108167func (s * Set ) FromJSON (r io.Reader ) error {
168+ // The iterator pool is completely useless for memory management, grrr.
109169 iter := jsoniter .Parse (jsoniter .ConfigCompatibleWithStandardLibrary , r , 4096 )
110170
111171 found , _ := readIter_v1 (iter )
0 commit comments