@@ -96,7 +96,7 @@ never_inline bool find_structural_bits(const u8 * buf, size_t len, ParsedJson &
9696 // persistent state across loop
9797 u64 prev_iter_ends_odd_backslash = 0ULL ; // either 0 or 1, but a 64-bit value
9898 u64 prev_iter_inside_quote = 0ULL ; // either all zeros or all ones
99- u64 prev_iter_pseudo_structural_carry = 0ULL ;
99+ u64 prev_iter_ends_pseudo_pred = 0ULL ;
100100
101101 for (size_t idx = 0 ; idx < len; idx+=64 ) {
102102#ifdef DEBUG
@@ -228,39 +228,27 @@ never_inline bool find_structural_bits(const u8 * buf, size_t len, ParsedJson &
228228 // mask off anything inside quotes
229229 structurals &= ~quote_mask;
230230
231- // whitespace inside our quotes also doesn't count; otherwise " foo" would generate a spurious
232- // pseudo-structural-character at 'foo'
233- whitespace &= ~quote_mask;
234-
235231 // add the real quote bits back into our bitmask as well, so we can
236232 // quickly traverse the strings we've spent all this trouble gathering
237233 structurals |= quote_bits;
238234
239- // Now, establish "pseudo-structural characters". These are characters that follow a structural
240- // character followed by zero or more whitespace
241- // this allows us to discover true/false/null and numbers in any location where they might legally
242- // occur; it will also create another 'checkpoint' where if a non-quoted region of our input
243- // has whitespace after a structural character fullowed by a syntax error, we can detect this
244- // and get an error in a later stage (i.e. the state machine)
245-
246- // Slightly more painful than it would seem. It's possible that either structurals or whitespace are
247- // all 1s (e.g. {{{{{{{....{{{{x64, or a really long whitespace). As such there is no safe place
248- // to add a '1' from the previous iteration without *that* triggering the carry we are looking
249- // out for, so we must check both carries for overflow
250-
251- u64 tmp = structurals | whitespace;
252- u64 tmp2;
253- bool ps_carry = __builtin_uaddll_overflow (tmp, structurals, &tmp2);
254- dumpbits (tmp2, " pseudo_structural add calculation first part" );
255- u64 tmp3;
256- ps_carry = ps_carry | __builtin_uaddll_overflow (tmp2, prev_iter_pseudo_structural_carry, &tmp3);
257- prev_iter_pseudo_structural_carry = ps_carry ? 0x1ULL : 0x0ULL ;
258- dumpbits (tmp3, " pseudo_structural add calculation after adding carry" );
259- tmp3 &= ~quote_mask;
260- tmp3 &= ~whitespace;
261- dumpbits (tmp3, " pseudo_structural add calculation without quotes and whitespace" );
262- dumpbits (structurals, " final structurals without quotes" );
263- structurals |= tmp3;
235+ // Now, establish "pseudo-structural characters". These are non-whitespace characters
236+ // that are (a) outside quotes and (b) have a predecessor that's either whitespace or a structural
237+ // character. This means that subsequent passes will get a chance to encounter the first character
238+ // of every string of non-whitespace and, if we're parsing an atom like true/false/null or a number
239+ // we can stop at the first whitespace or structural character following it.
240+
241+ // a qualified predecessor is something that can happen 1 position before an
242+ // psuedo-structural character
243+ u64 pseudo_pred = structurals | whitespace;
244+ dumpbits (pseudo_pred, " pseudo_pred" );
245+ u64 shifted_pseudo_pred = (pseudo_pred << 1 ) | prev_iter_ends_pseudo_pred;
246+ dumpbits (shifted_pseudo_pred, " shifted_pseudo_pred" );
247+ prev_iter_ends_pseudo_pred = pseudo_pred >> 63 ;
248+ u64 pseudo_structurals = shifted_pseudo_pred & (~whitespace) & (~quote_mask);
249+ dumpbits (pseudo_structurals, " pseudo_structurals" );
250+ dumpbits (structurals, " final structurals without pseudos" );
251+ structurals |= pseudo_structurals;
264252 dumpbits (structurals, " final structurals and pseudo structurals" );
265253
266254 *(u64 *)(pj.structurals + idx/8 ) = structurals;
@@ -596,28 +584,28 @@ int main(int argc, char * argv[]) {
596584 // as well as a dummy structure and a root structure
597585 // we also potentially write up to 7 iterations beyond
598586 // in our 'cheesy flatten', so make some worst-case
599- // sapce for that too
587+ // space for that too
600588 u32 max_structures = ROUNDUP_N (p.second , 64 ) + 2 + 7 ;
601589 pj.structural_indexes = new u32 [max_structures];
602590 pj.nodes = new JsonNode[max_structures];
603591
604- #if defined(DEBUG) || defined(DEBUG_FSM)
592+ #if defined(DEBUG)
605593 const u32 iterations = 1 ;
606594#else
607595 const u32 iterations = 1000 ;
608596#endif
609597 vector<double > res;
610598 res.resize (iterations);
611599 for (u32 i = 0 ; i < iterations; i++) {
600+ auto start = std::chrono::steady_clock::now ();
612601 find_structural_bits (p.first , p.second , pj);
613602 flatten_indexes (p.second , pj);
614- auto start = std::chrono::steady_clock::now ();
615603 ape_machine (p.first , p.second , pj);
616604 auto end = std::chrono::steady_clock::now ();
617605 std::chrono::duration<double > secs = end - start;
618606 res[i] = secs.count ();
619607 }
620- colorfuldisplay (pj, p.first );
608+ // colorfuldisplay(pj, p.first);
621609 double min_result = *min_element (res.begin (), res.end ());
622610 cout << " Min: " << min_result << " bytes read: " << p.second << " Gigabytes/second: " << (p.second ) / (min_result * 1000000000.0 ) << " \n " ;
623611 return 0 ;
0 commit comments