@@ -19,22 +19,64 @@ package fieldpath
19
19
import (
20
20
"bytes"
21
21
"io"
22
+ "unsafe"
22
23
23
24
jsoniter "github.com/json-iterator/go"
24
25
)
25
26
26
27
func (s * Set ) ToJSON () ([]byte , error ) {
27
28
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
29
41
30
42
stream .WriteObjectStart ()
31
- s .emitContents_v1 (false , stream )
43
+ err := s .emitContents_v1 (false , stream , & r )
44
+ if err != nil {
45
+ return err
46
+ }
32
47
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
35
63
}
36
64
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 {
38
80
mi , ci := 0 , 0
39
81
first := true
40
82
preWrite := func () {
@@ -51,24 +93,34 @@ func (s *Set) emitContents_v1(includeSelf bool, stream *jsoniter.Stream) {
51
93
52
94
if mpe .Less (cpe ) {
53
95
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 ())
56
100
stream .WriteEmptyObject ()
57
101
mi ++
58
102
} else if cpe .Less (mpe ) {
59
103
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 ())
62
108
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
+ }
64
112
stream .WriteObjectEnd ()
65
113
ci ++
66
114
} else {
67
115
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 ())
70
120
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
+ }
72
124
stream .WriteObjectEnd ()
73
125
mi ++
74
126
ci ++
@@ -79,8 +131,10 @@ func (s *Set) emitContents_v1(includeSelf bool, stream *jsoniter.Stream) {
79
131
mpe := s .Members .members [mi ]
80
132
81
133
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 ())
84
138
stream .WriteEmptyObject ()
85
139
mi ++
86
140
}
@@ -89,10 +143,14 @@ func (s *Set) emitContents_v1(includeSelf bool, stream *jsoniter.Stream) {
89
143
cpe := s .Children .members [ci ].pathElement
90
144
91
145
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 ())
94
150
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
+ }
96
154
stream .WriteObjectEnd ()
97
155
ci ++
98
156
}
@@ -102,10 +160,12 @@ func (s *Set) emitContents_v1(includeSelf bool, stream *jsoniter.Stream) {
102
160
stream .WriteObjectField ("." )
103
161
stream .WriteEmptyObject ()
104
162
}
163
+ return manageMemory (stream )
105
164
}
106
165
107
166
// FromJSON clears s and reads a JSON formatted set structure.
108
167
func (s * Set ) FromJSON (r io.Reader ) error {
168
+ // The iterator pool is completely useless for memory management, grrr.
109
169
iter := jsoniter .Parse (jsoniter .ConfigCompatibleWithStandardLibrary , r , 4096 )
110
170
111
171
found , _ := readIter_v1 (iter )
0 commit comments