@@ -43,6 +43,8 @@ const (
43
43
type Type int
44
44
45
45
var (
46
+ StartNodePoolSize = 16
47
+
46
48
decoderPool = make ([]* decoder , 0 , 16 )
47
49
decoderPoolIndex = - 1
48
50
decoderPoolMu = & sync.Mutex {}
63
65
ErrExpectedComma = errors .New ("expected comma" )
64
66
65
67
// api errors
68
+ ErrRootIsNil = errors .New ("root is nil" )
66
69
ErrNotFound = errors .New ("node isn't found" )
67
70
ErrNotObject = errors .New ("node isn't an object" )
68
71
ErrNotArray = errors .New ("node isn't an array" )
@@ -125,6 +128,33 @@ type decoder struct {
125
128
nodes int
126
129
}
127
130
131
+ // ReleaseMem sends node pool and internal buffer to GC
132
+ // useful to reduce memory usage after decoding big JSON
133
+ func (r * Root ) ReleaseMem () {
134
+ r .ReleasePoolMem ()
135
+ r .ReleaseBufMem ()
136
+ }
137
+
138
+ // ReleasePoolMem sends node pool to GC
139
+ func (r * Root ) ReleasePoolMem () {
140
+ r .data .decoder .initPool ()
141
+ }
142
+
143
+ // ReleasePoolMem sends internal buffer to GC
144
+ func (r * Root ) ReleaseBufMem () {
145
+ r .data .decoder .json = make ([]byte , 0 , 0 )
146
+ }
147
+
148
+ // BuffCap returns current size of internal buffer
149
+ func (r * Root ) BuffCap () int {
150
+ return cap (r .data .decoder .json )
151
+ }
152
+
153
+ // PullSize returns current size of node pool
154
+ func (r * Root ) PullSize () int {
155
+ return len (r .data .decoder .nodePool )
156
+ }
157
+
128
158
// ******************** //
129
159
// MAIN SHIT //
130
160
// ******************** //
@@ -497,18 +527,25 @@ func (d *decoder) decodeHeadless(json string, isPooled bool) (*Root, error) {
497
527
return & d .root , nil
498
528
}
499
529
500
- // EncodeNoAlloc legendary insane encode function
501
- // allocates new byte buffer on every call
502
- // use EncodeNoAlloc to reuse already created buffer and gain more performance
503
- func (n * Node ) Encode () []byte {
504
- return n .EncodeNoAlloc ([]byte {})
530
+ // EncodeToByte legendary insane encode function
531
+ // slow because it allocates new byte buffer on every call
532
+ // use Encode to reuse already created buffer and gain more performance
533
+ func (n * Node ) EncodeToByte () []byte {
534
+ return n .Encode ([]byte {})
535
+ }
536
+
537
+ // EncodeToString legendary insane encode function
538
+ // slow because it allocates new string on every call
539
+ // use Encode to reuse already created buffer and gain more performance
540
+ func (n * Node ) EncodeToString () string {
541
+ return toString (n .Encode ([]byte {}))
505
542
}
506
543
507
- // EncodeNoAlloc legendary insane encode function
544
+ // Encode legendary insane encode function
508
545
// uses already created byte buffer to place json data so
509
546
// mem allocations may occur only if buffer isn't long enough
510
547
// use it for performance
511
- func (n * Node ) EncodeNoAlloc (out []byte ) []byte {
548
+ func (n * Node ) Encode (out []byte ) []byte {
512
549
out = out [:0 ]
513
550
s := 0
514
551
curNode := n
@@ -1008,47 +1045,75 @@ func (n *Node) findSelf() int {
1008
1045
// MUTATIONS //
1009
1046
// ******************** //
1010
1047
1011
- func (n * Node ) MutateToJSON ( json string ) * Node {
1012
- if n == nil {
1048
+ func (n * Node ) MergeWith ( node * Node ) * Node {
1049
+ if n == nil || node == nil {
1013
1050
return n
1014
1051
}
1015
- owner := n .parent
1016
- if owner == nil {
1052
+ if ! n .IsObject () || ! node .IsObject () {
1017
1053
return n
1018
1054
}
1019
1055
1020
- root , err := n .data .decoder .decode (json , false )
1021
- if err != nil {
1056
+ for _ , child := range node .data .values {
1057
+ child .unescapeField ()
1058
+ childField := child .AsString ()
1059
+ x := n .AddField (childField )
1060
+ x .MutateToNode (child .next )
1061
+ }
1062
+
1063
+ return n
1064
+ }
1065
+
1066
+ // MutateToNode it isn't safe function, if you create node cycle, encode() may freeze
1067
+ func (n * Node ) MutateToNode (node * Node ) * Node {
1068
+ if n == nil || node == nil {
1022
1069
return n
1023
1070
}
1024
- end := root .data .end
1025
- n .tryDropLinks ()
1026
1071
1027
- index := n . actualizeIndex ()
1072
+ n . tryDropLinks ()
1028
1073
1029
- end .parent = n
1030
- if index != len (owner .data .values )- 1 {
1031
- end .next = owner .data .values [index + 1 ]
1032
- } else {
1033
- end .next = owner .data .end
1074
+ curNext := n .next
1075
+ if n .Type == Object || n .Type == Array {
1076
+ curNext = n .data .end .next
1034
1077
}
1035
1078
1036
- n .Type = root .Type
1037
- n .next = root .next
1038
- n .value = root .value
1039
- n .data .end = root .data .end
1040
- n .data .flags = root .data .flags
1041
- n .data .values = append (n .data .values [:0 ], root .data .values ... )
1042
- for _ , node := range root .data .values {
1043
- node .parent = n
1044
- if root .Type == Object {
1045
- node .next .parent = n
1079
+ if node .Type == Object || node .Type == Array {
1080
+ node .data .end .next = curNext
1081
+ } else {
1082
+ node .next = curNext
1083
+ }
1084
+
1085
+ n .Type = node .Type
1086
+ n .value = node .value
1087
+ if node .Type == Object || node .Type == Array {
1088
+ n .next = node .next
1089
+ n .data .end = node .data .end
1090
+ n .data .end .parent = n .parent
1091
+ n .data .flags &= ^ FlagFieldMap // reset field mapping
1092
+ n .data .values = append (n .data .values [:0 ], node .data .values ... )
1093
+ for _ , child := range node .data .values {
1094
+ child .parent = n
1095
+ if node .Type == Object {
1096
+ child .next .parent = n
1097
+ }
1046
1098
}
1047
1099
}
1048
1100
1049
1101
return n
1050
1102
}
1051
1103
1104
+ func (n * Node ) MutateToJSON (json string ) * Node {
1105
+ if n == nil {
1106
+ return n
1107
+ }
1108
+
1109
+ node , err := n .data .decoder .decode (json , false )
1110
+ if err != nil {
1111
+ return n
1112
+ }
1113
+
1114
+ return n .MutateToNode (node )
1115
+ }
1116
+
1052
1117
func (n * Node ) MutateToField (value string ) * Node {
1053
1118
if n .Type != Field {
1054
1119
return n
@@ -1255,6 +1320,10 @@ func (n *Node) unescapeStr() {
1255
1320
}
1256
1321
1257
1322
func (n * Node ) unescapeField () {
1323
+ if n .Type == Field {
1324
+ return
1325
+ }
1326
+
1258
1327
value := n .value
1259
1328
i := strings .LastIndexByte (value , '"' )
1260
1329
n .value = unescapeStr (value [1 :i ])
@@ -1289,6 +1358,19 @@ func (n *Node) AsString() string {
1289
1358
}
1290
1359
}
1291
1360
1361
+ func (n * Node ) AsBytes () []byte {
1362
+ return toByte (n .AsString ())
1363
+ }
1364
+
1365
+ func (n * StrictNode ) AsBytes () ([]byte , error ) {
1366
+ s , err := n .AsString ()
1367
+ if err != nil {
1368
+ return nil , err
1369
+ }
1370
+
1371
+ return toByte (s ), nil
1372
+ }
1373
+
1292
1374
func (n * StrictNode ) AsString () (string , error ) {
1293
1375
if n .Type == escapedField {
1294
1376
panic ("insane json really goes outta its mind" )
@@ -1501,9 +1583,8 @@ func (n *Node) InStrictMode() *StrictNode {
1501
1583
// ******************** //
1502
1584
1503
1585
func (d * decoder ) initPool () {
1504
- l := 1024
1505
- d .nodePool = make ([]* Node , l , l )
1506
- for i := 0 ; i < l ; i ++ {
1586
+ d .nodePool = make ([]* Node , StartNodePoolSize , StartNodePoolSize )
1587
+ for i := 0 ; i < StartNodePoolSize ; i ++ {
1507
1588
d .nodePool [i ] = & Node {data : & data {decoder : d }}
1508
1589
}
1509
1590
}
@@ -1557,18 +1638,46 @@ func DecodeString(json string) (*Root, error) {
1557
1638
return Spawn ().data .decoder .decodeHeadless (json , true )
1558
1639
}
1559
1640
1560
- func DecodeBytesReusing (root * Root , jsonBytes []byte ) error {
1561
- _ , err := root .data .decoder .decodeHeadless (toString (jsonBytes ), false )
1641
+ // DecodeBytes clear root and decode new JSON
1642
+ // useful for reusing root to decode multiple times and reduce allocations
1643
+ func (r * Root ) DecodeBytes (jsonBytes []byte ) error {
1644
+ if r == nil {
1645
+ return ErrRootIsNil
1646
+ }
1647
+ _ , err := r .data .decoder .decodeHeadless (toString (jsonBytes ), false )
1562
1648
1563
1649
return err
1564
1650
}
1565
1651
1566
- func DecodeStringReusing (root * Root , json string ) error {
1567
- _ , err := root .data .decoder .decodeHeadless (json , false )
1652
+ // DecodeString clear root and decode new JSON
1653
+ // useful for reusing root to decode multiple times and reduce allocations
1654
+ func (r * Root ) DecodeString (json string ) error {
1655
+ if r == nil {
1656
+ return ErrRootIsNil
1657
+ }
1658
+ _ , err := r .data .decoder .decodeHeadless (json , false )
1568
1659
1569
1660
return err
1570
1661
}
1571
1662
1663
+ // DecodeBytesAdditional doesn't clean root, uses root's node pool to decode JSON
1664
+ func (r * Root ) DecodeBytesAdditional (jsonBytes []byte ) (* Node , error ) {
1665
+ if r == nil {
1666
+ return nil , ErrRootIsNil
1667
+ }
1668
+
1669
+ return r .data .decoder .decode (toString (jsonBytes ), false )
1670
+ }
1671
+
1672
+ // DecodeStringAdditional doesn't clean root, uses root's node pool to decode JSON
1673
+ func (r * Root ) DecodeStringAdditional (json string ) (* Node , error ) {
1674
+ if r == nil {
1675
+ return nil , ErrRootIsNil
1676
+ }
1677
+
1678
+ return r .data .decoder .decode (json , false )
1679
+ }
1680
+
1572
1681
func Release (root * Root ) {
1573
1682
if root == nil {
1574
1683
return
@@ -1930,7 +2039,7 @@ var out = make([]byte, 0, 0)
1930
2039
var root = Spawn ()
1931
2040
1932
2041
func Fuzz (data []byte ) int {
1933
- err := DecodeBytesReusing ( root , data )
2042
+ err := root . DecodeBytes ( data )
1934
2043
if err != nil {
1935
2044
return - 1
1936
2045
}
@@ -2009,7 +2118,7 @@ func Fuzz(data []byte) int {
2009
2118
}
2010
2119
}
2011
2120
2012
- root .EncodeNoAlloc (out )
2121
+ root .Encode (out )
2013
2122
2014
2123
return 1
2015
2124
}
0 commit comments