22// (c) Daniel Lemire and Geoff Langdale
33
44using System ;
5- using System . Diagnostics ;
65using System . Runtime . CompilerServices ;
7- using System . Runtime . InteropServices ;
86using System . Runtime . Intrinsics . X86 ;
97
108#region stdint types and friends
11- // if you change something here please change it in other files too
129using size_t = System . UInt64 ;
1310using uint8_t = System . Byte ;
1411using uint64_t = System . UInt64 ;
1512using uint32_t = System . UInt32 ;
1613using int64_t = System . Int64 ;
17- using bytechar = System . SByte ;
18- using unsigned_bytechar = System . Byte ;
19- using uintptr_t = System . UIntPtr ;
14+ using char1 = System . SByte ;
2015using static SimdJsonSharp . Utils ;
2116#endregion
2217
2318namespace SimdJsonSharp
2419{
2520 public unsafe class ParsedJson : IDisposable
2621 {
27- public size_t bytecapacity ; // indicates how many bits are meant to be supported
28- public size_t depthcapacity ; // how deep we can go
29- public size_t tapecapacity ;
30- public size_t stringcapacity ;
31- public uint32_t current_loc ;
32- public uint32_t n_structural_indexes ;
33- public uint32_t * structural_indexes ;
34- public uint64_t * tape ;
35- public uint32_t * containing_scope_offset ;
36- public bytechar * ret_address ;
37- public uint8_t * string_buf ; // should be at least bytecapacity
38- public uint8_t * current_string_buf_loc ;
39- public bool isvalid ;
22+ internal size_t bytecapacity ; // indicates how many bits are meant to be supported
23+ internal size_t depthcapacity ; // how deep we can go
24+ internal size_t tapecapacity ;
25+ internal size_t stringcapacity ;
26+ internal uint32_t current_loc ;
27+ internal uint32_t n_structural_indexes ;
28+ internal uint32_t * structural_indexes ;
29+ internal uint64_t * tape ;
30+ internal uint32_t * containing_scope_offset ;
31+ internal char1 * ret_address ;
32+ internal uint8_t * string_buf ; // should be at least bytecapacity
33+ internal uint8_t * current_string_buf_loc ;
34+ internal bool isvalid ;
35+ internal bool isDisposed ;
36+
37+ public JsonParseError ErrorCode { get ; internal set ; }
4038
4139 public ParsedJson ( )
4240 {
43- if ( ! Avx2 . IsSupported )
44- throw new NotSupportedException ( "AVX2 is required form SimdJson " ) ;
41+ if ( ! Sse42 . IsSupported || IntPtr . Size == 4 )
42+ throw new NotSupportedException ( "SimdJson requires AVX2 or SSE42 and x64 " ) ;
4543 }
4644
4745 // if needed, allocate memory so that the object is able to process JSON
@@ -50,32 +48,48 @@ public bool AllocateCapacity(size_t len, size_t maxdepth = DEFAULTMAXDEPTH)
5048 {
5149 if ( ( maxdepth == 0 ) || ( len == 0 ) )
5250 {
53- Debug . WriteLine ( "capacities must be non-zero " ) ;
5451 return false ;
5552 }
56-
53+ if ( len > SIMDJSON_MAXSIZE_BYTES )
54+ {
55+ return false ;
56+ }
5757 if ( ( len <= bytecapacity ) && ( depthcapacity < maxdepth ) )
58+ {
5859 return true ;
60+ }
5961 Deallocate ( ) ;
60-
6162 isvalid = false ;
6263 bytecapacity = 0 ; // will only set it to len after allocations are a success
6364 n_structural_indexes = 0 ;
64- uint32_t max_structures = ( uint32_t ) ROUNDUP_N ( len , 64 ) + 2 + 7 ;
65- structural_indexes = Utils . allocate < uint32_t > ( max_structures ) ;
66- size_t localtapecapacity = ROUNDUP_N ( len , 64 ) ;
67- size_t localstringcapacity = ROUNDUP_N ( len , 64 ) ;
68- string_buf = Utils . allocate < uint8_t > ( localstringcapacity ) ;
69- tape = Utils . allocate < uint64_t > ( localtapecapacity ) ;
70- containing_scope_offset = Utils . allocate < uint32_t > ( maxdepth ) ;
71- ret_address = Utils . allocate < bytechar > ( maxdepth ) ;
65+ uint32_t max_structures = ( uint32_t ) ( ROUNDUP_N ( len , 64 ) + 2 + 7 ) ;
66+ structural_indexes = allocate < uint32_t > ( max_structures ) ;
67+ // a pathological input like "[[[[..." would generate len tape elements, so need a capacity of len + 1
68+ size_t localtapecapacity = ROUNDUP_N ( len + 1 , 64 ) ;
69+ // a document with only zero-length strings... could have len/3 string
70+ // and we would need len/3 * 5 bytes on the string buffer
71+ size_t localstringcapacity = ROUNDUP_N ( 5 * len / 3 + 32 , 64 ) ;
72+ string_buf = allocate < uint8_t > ( localstringcapacity ) ;
73+ tape = allocate < uint64_t > ( localtapecapacity ) ;
74+ containing_scope_offset = allocate < uint32_t > ( maxdepth ) ;
75+ ret_address = allocate < char1 > ( maxdepth ) ;
7276 if ( ( string_buf == null ) || ( tape == null ) ||
7377 ( containing_scope_offset == null ) || ( ret_address == null ) || ( structural_indexes == null ) )
7478 {
75- Deallocate ( ) ;
79+ delete ( ret_address ) ;
80+ delete ( containing_scope_offset ) ;
81+ delete ( tape ) ;
82+ delete ( string_buf ) ;
83+ delete ( structural_indexes ) ;
7684 return false ;
7785 }
78-
86+ /*
87+ // We do not need to initialize this content for parsing, though we could
88+ // need to initialize it for safety.
89+ memset(string_buf, 0 , localstringcapacity);
90+ memset(structural_indexes, 0, max_structures * sizeof(uint32_t));
91+ memset(tape, 0, localtapecapacity * sizeof(uint64_t));
92+ */
7993 bytecapacity = len ;
8094 depthcapacity = maxdepth ;
8195 tapecapacity = localtapecapacity ;
@@ -85,48 +99,35 @@ public bool AllocateCapacity(size_t len, size_t maxdepth = DEFAULTMAXDEPTH)
8599
86100 private void Deallocate ( )
87101 {
88- isvalid = false ;
89102 bytecapacity = 0 ;
90103 depthcapacity = 0 ;
91104 tapecapacity = 0 ;
92105 stringcapacity = 0 ;
106+ delete ( ret_address ) ;
107+ delete ( containing_scope_offset ) ;
108+ delete ( tape ) ;
109+ delete ( string_buf ) ;
110+ delete ( structural_indexes ) ;
111+ isvalid = false ;
112+ }
93113
94- if ( ret_address != null )
95- {
96- delete ( ret_address ) ;
97- ret_address = null ;
98- }
99-
100- if ( containing_scope_offset != null )
101- {
102- delete ( containing_scope_offset ) ;
103- containing_scope_offset = null ;
104- }
114+ public void Dispose ( ) => Dispose ( true ) ;
105115
106- if ( tape != null )
107- {
108- delete ( tape ) ;
109- tape = null ;
110- }
111-
112- if ( string_buf != null )
113- {
114- delete ( string_buf ) ;
115- string_buf = null ;
116- }
116+ private void Dispose ( bool disposing )
117+ {
118+ if ( disposing )
119+ GC . SuppressFinalize ( this ) ;
117120
118- if ( structural_indexes != null )
121+ if ( ! isDisposed )
119122 {
120- delete ( structural_indexes ) ;
121- structural_indexes = null ;
123+ isDisposed = true ;
124+ Deallocate ( ) ;
122125 }
123126 }
124127
125- public void Dispose ( ) => Deallocate ( ) ;
126-
127128 ~ ParsedJson ( )
128129 {
129- Dispose ( ) ;
130+ Dispose ( false ) ;
130131 }
131132
132133 public bool IsValid => isvalid ;
0 commit comments