LLVMFuzzerTestOneInput:
    8|  1.92k|{
    9|       |   // use a vector with null termination instead of a std::string to avoid
   10|       |   // small string optimization to hide bounds problems
   11|  1.92k|   std::vector<char> buffer{Data, Data + Size};
   12|       |
   13|       |   // non-null terminated
   14|  1.92k|   {
   15|  1.92k|      const auto& input = buffer;
   16|  1.92k|      [[maybe_unused]] auto beautiful = glz::prettify_json(input);
   17|  1.92k|   }
   18|       |
   19|       |   // null terminated
   20|  1.92k|   {
   21|  1.92k|      buffer.push_back('\0');
   22|  1.92k|      const auto& input = buffer;
   23|  1.92k|      [[maybe_unused]] auto beautiful = glz::prettify_json(input);
   24|  1.92k|   }
   25|       |
   26|       |   // The comment enabled path is a different scan: read_jsonc_comment only runs here, and it is
   27|       |   // the scanner that has to report an unterminated comment rather than hand an empty view to a
   28|       |   // memcpy. Fuzzed as its own input because a document rejected by the plain path may be accepted
   29|       |   // by this one.
   30|  1.92k|   {
   31|  1.92k|      const std::vector<char> jsonc{Data, Data + Size};
   32|  1.92k|      [[maybe_unused]] auto beautiful = glz::prettify_jsonc(jsonc);
   33|  1.92k|   }
   34|       |
   35|       |   // Only a self-terminating buffer selects the null terminated scan. A vector carrying a
   36|       |   // trailing NUL does not: that NUL is just a byte inside the document.
   37|  1.92k|   {
   38|  1.92k|      const std::string jsonc{Data, Data + Size};
   39|  1.92k|      [[maybe_unused]] auto beautiful = glz::prettify_jsonc(jsonc);
   40|  1.92k|   }
   41|       |
   42|  1.92k|   return 0;
   43|  1.92k|}

_ZN3glz11grow_bufferINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEEvRT_m:
  143|  20.4k|   {
  144|  20.4k|      using traits = buffer_traits<std::remove_cvref_t<B>>;
  145|  20.4k|      if constexpr (requires { traits::grow(b, required); }) {
  146|  20.4k|         traits::grow(b, required);
  147|       |      }
  148|       |      else {
  149|       |         // A user specialization written before `grow` existed: keep the growth it used to get.
  150|       |         resize_unfilled(b, 2 * required);
  151|       |      }
  152|  20.4k|   }
_ZN3glz13buffer_traitsINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEE4growERS7_mQL_ZNS_13buffer_traits12is_resizableEE:
  118|  20.4k|      {
  119|  20.4k|         resize_unfilled(b, 2 * required);
  120|  20.4k|      }
_ZN3glz15resize_unfilledINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEEvRT_m:
   63|  20.4k|   {
   64|  20.4k|      if constexpr (requires { b.resize_and_overwrite(n, [](auto*, size_t written) { return written; }); }) {
   65|  20.4k|         b.resize_and_overwrite(n, [](auto*, size_t written) noexcept { return written; });
   66|       |      }
   67|       |      else {
   68|       |         b.resize(n);
   69|       |      }
   70|  20.4k|   }
_ZZN3glz15resize_unfilledINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEEvRT_mENKUlPS8_mE_clIcEEDaSA_m:
   65|  20.4k|         b.resize_and_overwrite(n, [](auto*, size_t written) noexcept { return written; });

_ZN3glz14read_iteratorsITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1EEETkNS_10contiguousERKNSt3__16vectorIcNS2_9allocatorIcEEEEEEDaOT0_:
   40|  3.85k|   {
   41|  3.85k|      static_assert(sizeof(decltype(*buffer.data())) == 1);
   42|       |
   43|  3.85k|      auto it = reinterpret_cast<const char*>(buffer.data());
   44|  3.85k|      auto end = it + buffer.size();
   45|       |
   46|  3.85k|      return std::pair{it, end};
   47|  3.85k|   }
_ZN3glz14read_iteratorsITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10contiguousERKNSt3__16vectorIcNS2_9allocatorIcEEEEEEDaOT0_:
   40|  1.92k|   {
   41|  1.92k|      static_assert(sizeof(decltype(*buffer.data())) == 1);
   42|       |
   43|  1.92k|      auto it = reinterpret_cast<const char*>(buffer.data());
   44|  1.92k|      auto end = it + buffer.size();
   45|       |
   46|  1.92k|      return std::pair{it, end};
   47|  1.92k|   }
_ZN3glz14read_iteratorsITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10contiguousERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEEDaOT0_:
   40|  1.92k|   {
   41|  1.92k|      static_assert(sizeof(decltype(*buffer.data())) == 1);
   42|       |
   43|  1.92k|      auto it = reinterpret_cast<const char*>(buffer.data());
   44|  1.92k|      auto end = it + buffer.size();
   45|       |
   46|  1.92k|      return std::pair{it, end};
   47|  1.92k|   }

_ZN3glz6detail16read_json_stringITkNS_10is_contextERNS_7contextERPKcS5_EENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEOT_OT0_T1_:
  156|   229k|   {
  157|   229k|      auto start = it;
  158|   229k|      ++it; // skip quote
  159|       |      // The bound as a pointer, so each chunk costs one compare. Where eight bytes are not left,
  160|       |      // the fallback is the opening quote, which sits before `it` and fails the test on the first
  161|       |      // look; never `it` itself, which would pass and read a chunk past `end`.
  162|   229k|      const auto* const chunk_limit = (end - it >= 8) ? end - 8 : it - 1;
  ------------------
  |  Branch (162:39): [True: 229k, False: 716]
  ------------------
  163|  2.22M|      while (it <= chunk_limit) {
  ------------------
  |  Branch (163:14): [True: 2.22M, False: 886]
  ------------------
  164|  2.22M|         uint64_t chunk;
  165|  2.22M|         std::memcpy(&chunk, it, 8);
  166|       |         if constexpr (std::endian::native == std::endian::big) {
  167|       |            chunk = std::byteswap(chunk);
  168|       |         }
  169|  2.22M|         const uint64_t quote = has_quote(chunk);
  170|  2.22M|         if (quote) {
  ------------------
  |  Branch (170:14): [True: 229k, False: 1.99M]
  ------------------
  171|   229k|            it += (countr_zero(quote) >> 3);
  172|       |
  173|   229k|            auto* prev = it - 1;
  174|   230k|            while (*prev == '\\') {
  ------------------
  |  Branch (174:20): [True: 1.16k, False: 229k]
  ------------------
  175|  1.16k|               --prev;
  176|  1.16k|            }
  177|   229k|            if (size_t(it - prev) % 2) {
  ------------------
  |  Branch (177:17): [True: 228k, False: 710]
  ------------------
  178|   228k|               ++it; // add quote
  179|   228k|               return {start, size_t(it - start)};
  180|   228k|            }
  181|    710|            ++it; // skip escaped quote and continue
  182|    710|         }
  183|  1.99M|         else {
  184|  1.99M|            it += 8;
  185|  1.99M|         }
  186|  2.22M|      }
  187|       |
  188|  1.78k|      while (it < end) {
  ------------------
  |  Branch (188:14): [True: 1.51k, False: 276]
  ------------------
  189|  1.51k|         if (*it == '"') {
  ------------------
  |  Branch (189:14): [True: 664, False: 849]
  ------------------
  190|    664|            auto* prev = it - 1;
  191|  1.52k|            while (*prev == '\\') {
  ------------------
  |  Branch (191:20): [True: 858, False: 664]
  ------------------
  192|    858|               --prev;
  193|    858|            }
  194|    664|            if (size_t(it - prev) % 2) {
  ------------------
  |  Branch (194:17): [True: 610, False: 54]
  ------------------
  195|    610|               ++it; // add quote
  196|    610|               return {start, size_t(it - start)};
  197|    610|            }
  198|    664|         }
  199|    903|         ++it;
  200|    903|      }
  201|       |
  202|    276|      ctx.error = error_code::unexpected_end;
  203|    276|      return {};
  204|    886|   }
_ZN3glz6detail10emit_bytesILb1ENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEETkNS_10is_contextENS_7contextENS2_17basic_string_viewIcS5_EEEEbRT1_RT0_RmRKT2_:
   91|   371k|   {
   92|   371k|      using T = std::remove_cvref_t<decltype(x)>;
   93|       |      if constexpr (byte_sized<T>) {
   94|       |         if constexpr (has_bounded_capacity<B>) {
   95|       |            if (not ensure_space(ctx, b, ix + 1)) [[unlikely]] {
   96|       |               return false;
   97|       |            }
   98|       |         }
   99|       |         dump<Checked>(x, b, ix);
  100|       |      }
  101|   371k|      else {
  102|   371k|         const sv s = [&] {
  103|   371k|            if constexpr (std::is_bounded_array_v<T>) {
  104|   371k|               return sv{x, std::extent_v<T> - 1}; // a string literal, without its terminator
  105|   371k|            }
  106|   371k|            else {
  107|   371k|               return sv{x};
  108|   371k|            }
  109|   371k|         }();
  110|       |         if constexpr (has_bounded_capacity<B>) {
  111|       |            if (not ensure_space(ctx, b, ix + s.size())) [[unlikely]] {
  112|       |               return false;
  113|       |            }
  114|       |         }
  115|   371k|         dump<Checked>(s, b, ix);
  116|   371k|      }
  117|   371k|      return true;
  118|   371k|   }
_ZZN3glz6detail10emit_bytesILb1ENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEETkNS_10is_contextENS_7contextENS2_17basic_string_viewIcS5_EEEEbRT1_RT0_RmRKT2_ENKUlvE_clEv:
  102|   371k|         const sv s = [&] {
  103|       |            if constexpr (std::is_bounded_array_v<T>) {
  104|       |               return sv{x, std::extent_v<T> - 1}; // a string literal, without its terminator
  105|       |            }
  106|   371k|            else {
  107|   371k|               return sv{x};
  108|   371k|            }
  109|   371k|         }();
_ZN3glz6detail10emit_bytesILb1ENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEETkNS_10is_contextENS_7contextEcEEbRT1_RT0_RmRKT2_:
   91|   121M|   {
   92|   121M|      using T = std::remove_cvref_t<decltype(x)>;
   93|   121M|      if constexpr (byte_sized<T>) {
   94|       |         if constexpr (has_bounded_capacity<B>) {
   95|       |            if (not ensure_space(ctx, b, ix + 1)) [[unlikely]] {
   96|       |               return false;
   97|       |            }
   98|       |         }
   99|   121M|         dump<Checked>(x, b, ix);
  100|       |      }
  101|       |      else {
  102|       |         const sv s = [&] {
  103|       |            if constexpr (std::is_bounded_array_v<T>) {
  104|       |               return sv{x, std::extent_v<T> - 1}; // a string literal, without its terminator
  105|       |            }
  106|       |            else {
  107|       |               return sv{x};
  108|       |            }
  109|       |         }();
  110|       |         if constexpr (has_bounded_capacity<B>) {
  111|       |            if (not ensure_space(ctx, b, ix + s.size())) [[unlikely]] {
  112|       |               return false;
  113|       |            }
  114|       |         }
  115|       |         dump<Checked>(s, b, ix);
  116|       |      }
  117|   121M|      return true;
  118|   121M|   }
_ZN3glz6detail15append_new_lineILb0ELh3ERNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERmEEvOT1_OT2_l:
   63|   121M|   {
   64|   121M|      dump('\n', b, ix);
   65|       |      if constexpr (use_tabs) {
   66|       |         dumpn('\t', indent, b, ix);
   67|       |      }
   68|   121M|      else {
   69|   121M|         dumpn(' ', indent * indentation_width, b, ix);
   70|   121M|      }
   71|   121M|   };
_ZN3glz6detail16read_json_numberILb0ERPKcS3_EENSt3__117basic_string_viewIcNS5_11char_traitsIcEEEEOT0_T1_:
  304|  54.3k|   {
  305|  54.3k|      auto start = it;
  306|       |      if constexpr (null_terminated) {
  307|       |         while (numeric_table[uint8_t(*it)]) {
  308|       |            ++it;
  309|       |         }
  310|       |      }
  311|  54.3k|      else {
  312|  2.68M|         while ((it < end) && numeric_table[uint8_t(*it)]) {
  ------------------
  |  Branch (312:17): [True: 2.68M, False: 154]
  |  Branch (312:31): [True: 2.62M, False: 54.1k]
  ------------------
  313|  2.62M|            ++it;
  314|  2.62M|         }
  315|  54.3k|      }
  316|  54.3k|      return {start, size_t(it - start)};
  317|  54.3k|   }
_ZN3glz6detail13match_literalITnNS_14string_literalEXtlNS2_ILm5EEEtlA5_cLc110ELc117ELc108ELc108EEEETkNS_10is_contextERNS_7contextERPKcS8_EEbOT0_OT1_T2_:
  130|  6.24k|   {
  131|  6.24k|      static constexpr auto s = literal.sv();
  132|  6.24k|      if (end - it < std::ptrdiff_t(s.size())) [[unlikely]] {
  ------------------
  |  Branch (132:11): [True: 63, False: 6.17k]
  ------------------
  133|     63|         ctx.error = error_code::unexpected_end;
  134|     63|         return false;
  135|     63|      }
  136|  6.17k|      if (not comparitor<s>(it)) [[unlikely]] {
  ------------------
  |  Branch (136:11): [True: 321, False: 5.85k]
  ------------------
  137|    321|         ctx.error = error_code::syntax_error;
  138|    321|         return false;
  139|    321|      }
  140|  5.85k|      it += s.size();
  141|  5.85k|      return true;
  142|  6.17k|   }
_ZN3glz6detail10emit_bytesILb1ENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEETkNS_10is_contextENS_7contextEA5_cEEbRT1_RT0_RmRKT2_:
   91|  15.5k|   {
   92|  15.5k|      using T = std::remove_cvref_t<decltype(x)>;
   93|       |      if constexpr (byte_sized<T>) {
   94|       |         if constexpr (has_bounded_capacity<B>) {
   95|       |            if (not ensure_space(ctx, b, ix + 1)) [[unlikely]] {
   96|       |               return false;
   97|       |            }
   98|       |         }
   99|       |         dump<Checked>(x, b, ix);
  100|       |      }
  101|  15.5k|      else {
  102|  15.5k|         const sv s = [&] {
  103|  15.5k|            if constexpr (std::is_bounded_array_v<T>) {
  104|  15.5k|               return sv{x, std::extent_v<T> - 1}; // a string literal, without its terminator
  105|  15.5k|            }
  106|  15.5k|            else {
  107|  15.5k|               return sv{x};
  108|  15.5k|            }
  109|  15.5k|         }();
  110|       |         if constexpr (has_bounded_capacity<B>) {
  111|       |            if (not ensure_space(ctx, b, ix + s.size())) [[unlikely]] {
  112|       |               return false;
  113|       |            }
  114|       |         }
  115|  15.5k|         dump<Checked>(s, b, ix);
  116|  15.5k|      }
  117|  15.5k|      return true;
  118|  15.5k|   }
_ZZN3glz6detail10emit_bytesILb1ENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEETkNS_10is_contextENS_7contextEA5_cEEbRT1_RT0_RmRKT2_ENKUlvE_clEv:
  102|  15.5k|         const sv s = [&] {
  103|  15.5k|            if constexpr (std::is_bounded_array_v<T>) {
  104|  15.5k|               return sv{x, std::extent_v<T> - 1}; // a string literal, without its terminator
  105|       |            }
  106|       |            else {
  107|       |               return sv{x};
  108|       |            }
  109|  15.5k|         }();
_ZN3glz6detail13match_literalITnNS_14string_literalEXtlNS2_ILm5EEEtlA5_cLc116ELc114ELc117ELc101EEEETkNS_10is_contextERNS_7contextERPKcS8_EEbOT0_OT1_T2_:
  130|  10.0k|   {
  131|  10.0k|      static constexpr auto s = literal.sv();
  132|  10.0k|      if (end - it < std::ptrdiff_t(s.size())) [[unlikely]] {
  ------------------
  |  Branch (132:11): [True: 88, False: 9.98k]
  ------------------
  133|     88|         ctx.error = error_code::unexpected_end;
  134|     88|         return false;
  135|     88|      }
  136|  9.98k|      if (not comparitor<s>(it)) [[unlikely]] {
  ------------------
  |  Branch (136:11): [True: 292, False: 9.69k]
  ------------------
  137|    292|         ctx.error = error_code::syntax_error;
  138|    292|         return false;
  139|    292|      }
  140|  9.69k|      it += s.size();
  141|  9.69k|      return true;
  142|  9.98k|   }
_ZN3glz6detail13match_literalITnNS_14string_literalEXtlNS2_ILm6EEEtlA6_cLc102ELc97ELc108ELc115ELc101EEEETkNS_10is_contextERNS_7contextERPKcS8_EEbOT0_OT1_T2_:
  130|  4.84k|   {
  131|  4.84k|      static constexpr auto s = literal.sv();
  132|  4.84k|      if (end - it < std::ptrdiff_t(s.size())) [[unlikely]] {
  ------------------
  |  Branch (132:11): [True: 125, False: 4.71k]
  ------------------
  133|    125|         ctx.error = error_code::unexpected_end;
  134|    125|         return false;
  135|    125|      }
  136|  4.71k|      if (not comparitor<s>(it)) [[unlikely]] {
  ------------------
  |  Branch (136:11): [True: 429, False: 4.28k]
  ------------------
  137|    429|         ctx.error = error_code::syntax_error;
  138|    429|         return false;
  139|    429|      }
  140|  4.28k|      it += s.size();
  141|  4.28k|      return true;
  142|  4.71k|   }
_ZN3glz6detail10emit_bytesILb1ENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEETkNS_10is_contextENS_7contextEA6_cEEbRT1_RT0_RmRKT2_:
   91|  4.28k|   {
   92|  4.28k|      using T = std::remove_cvref_t<decltype(x)>;
   93|       |      if constexpr (byte_sized<T>) {
   94|       |         if constexpr (has_bounded_capacity<B>) {
   95|       |            if (not ensure_space(ctx, b, ix + 1)) [[unlikely]] {
   96|       |               return false;
   97|       |            }
   98|       |         }
   99|       |         dump<Checked>(x, b, ix);
  100|       |      }
  101|  4.28k|      else {
  102|  4.28k|         const sv s = [&] {
  103|  4.28k|            if constexpr (std::is_bounded_array_v<T>) {
  104|  4.28k|               return sv{x, std::extent_v<T> - 1}; // a string literal, without its terminator
  105|  4.28k|            }
  106|  4.28k|            else {
  107|  4.28k|               return sv{x};
  108|  4.28k|            }
  109|  4.28k|         }();
  110|       |         if constexpr (has_bounded_capacity<B>) {
  111|       |            if (not ensure_space(ctx, b, ix + s.size())) [[unlikely]] {
  112|       |               return false;
  113|       |            }
  114|       |         }
  115|  4.28k|         dump<Checked>(s, b, ix);
  116|  4.28k|      }
  117|  4.28k|      return true;
  118|  4.28k|   }
_ZZN3glz6detail10emit_bytesILb1ENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEETkNS_10is_contextENS_7contextEA6_cEEbRT1_RT0_RmRKT2_ENKUlvE_clEv:
  102|  4.28k|         const sv s = [&] {
  103|  4.28k|            if constexpr (std::is_bounded_array_v<T>) {
  104|  4.28k|               return sv{x, std::extent_v<T> - 1}; // a string literal, without its terminator
  105|       |            }
  106|       |            else {
  107|       |               return sv{x};
  108|       |            }
  109|  4.28k|         }();
_ZN3glz6detail18read_jsonc_commentITkNS_10is_contextERNS_7contextERPKcS5_EENS0_13jsonc_commentEOT_OT0_T1_:
  227|  14.0k|   {
  228|  14.0k|      const auto start = it;
  229|  14.0k|      ++it; // past the opening '/'
  230|       |
  231|       |      // The caller matched one '/'; that says nothing about a second byte being there at all.
  232|       |      // Stepping over both regardless leaves `it` past `end`, and every scan the caller runs after
  233|       |      // this one starts from there.
  234|  14.0k|      if (it == end) [[unlikely]] {
  ------------------
  |  Branch (234:11): [True: 8, False: 14.0k]
  ------------------
  235|      8|         ctx.error = error_code::unexpected_end;
  236|      8|         return {};
  237|      8|      }
  238|       |
  239|  14.0k|      if (*it == '/') {
  ------------------
  |  Branch (239:11): [True: 12.3k, False: 1.67k]
  ------------------
  240|  12.3k|         ++it; // past the second '/'
  241|  1.62M|         while (it != end && *it != '\n' && *it != '\r') {
  ------------------
  |  Branch (241:17): [True: 1.62M, False: 150]
  |  Branch (241:30): [True: 1.62M, False: 2.37k]
  |  Branch (241:45): [True: 1.61M, False: 9.81k]
  ------------------
  242|  1.61M|            ++it;
  243|  1.61M|         }
  244|       |         // The terminator is left where it is: minify drops it along with the rest of the
  245|       |         // whitespace and prettify emits its own break. A carriage return ends the comment on its
  246|       |         // own, so a file with CR line endings is not swallowed by its first comment; a line feed
  247|       |         // behind it is then ordinary whitespace.
  248|  12.3k|         return {sv{start, size_t(it - start)}, true};
  249|  12.3k|      }
  250|       |
  251|  1.67k|      if (*it != '*') [[unlikely]] {
  ------------------
  |  Branch (251:11): [True: 70, False: 1.60k]
  ------------------
  252|     70|         ctx.error = error_code::expected_end_comment;
  253|     70|         return {};
  254|     70|      }
  255|  1.60k|      ++it; // past the '*' of the opener
  256|       |
  257|       |      // Only a '*' after the opening delimiter can close the comment, which is what the `content`
  258|       |      // guards below are for: without them the '*' of the opener closes the comment it opened, so
  259|       |      // "/*/" reads as complete and swallows whatever follows it.
  260|  1.60k|      const auto content = it;
  261|       |
  262|       |      // The bound as a pointer, so each chunk costs one compare. `end - 8` only points into the
  263|       |      // buffer once that much of it is left; where it is not, the fallback is the byte before the
  264|       |      // cursor, which is inside the opener and so fails the test on the first look. Never `it`
  265|       |      // itself -- that passes, and the chunk behind it would read past the end of the buffer.
  266|  1.60k|      const auto* const chunk_limit = (end - it >= 8) ? end - 8 : it - 1;
  ------------------
  |  Branch (266:39): [True: 1.50k, False: 104]
  ------------------
  267|  1.06M|      while (it <= chunk_limit) {
  ------------------
  |  Branch (267:14): [True: 1.06M, False: 268]
  ------------------
  268|  1.06M|         uint64_t chunk;
  269|  1.06M|         std::memcpy(&chunk, it, 8);
  270|       |         if constexpr (std::endian::native == std::endian::big) {
  271|       |            chunk = std::byteswap(chunk);
  272|       |         }
  273|  1.06M|         const uint64_t slash = has_char<'/'>(chunk);
  274|  1.06M|         if (slash) {
  ------------------
  |  Branch (274:14): [True: 236k, False: 832k]
  ------------------
  275|   236k|            it += (countr_zero(slash) >> 3);
  276|       |
  277|   236k|            if (it > content && it[-1] == '*') {
  ------------------
  |  Branch (277:17): [True: 235k, False: 826]
  |  Branch (277:33): [True: 1.34k, False: 234k]
  ------------------
  278|  1.34k|               ++it; // add slash
  279|  1.34k|               return {sv{start, size_t(it - start)}, false};
  280|  1.34k|            }
  281|       |            // skip slash and continue
  282|   235k|            ++it;
  283|   235k|         }
  284|   832k|         else {
  285|   832k|            it += 8;
  286|   832k|         }
  287|  1.06M|      }
  288|       |
  289|       |      // Tail end of buffer. Should be rare we even get here
  290|  1.02k|      while (it < end) {
  ------------------
  |  Branch (290:14): [True: 802, False: 226]
  ------------------
  291|    802|         if (it > content && it[-1] == '*' && *it == '/') {
  ------------------
  |  Branch (291:14): [True: 704, False: 98]
  |  Branch (291:30): [True: 118, False: 586]
  |  Branch (291:47): [True: 42, False: 76]
  ------------------
  292|     42|            ++it; // add slash
  293|     42|            return {sv{start, size_t(it - start)}, false};
  294|     42|         }
  295|    760|         ++it;
  296|    760|      }
  297|       |
  298|    226|      ctx.error = error_code::expected_end_comment;
  299|    226|      return {};
  300|    268|   }
_ZN3glz6detail16read_json_numberILb1ERPKcS3_EENSt3__117basic_string_viewIcNS5_11char_traitsIcEEEEOT0_T1_:
  304|  23.0k|   {
  305|  23.0k|      auto start = it;
  306|  23.0k|      if constexpr (null_terminated) {
  307|   903k|         while (numeric_table[uint8_t(*it)]) {
  ------------------
  |  Branch (307:17): [True: 880k, False: 23.0k]
  ------------------
  308|   880k|            ++it;
  309|   880k|         }
  310|       |      }
  311|       |      else {
  312|       |         while ((it < end) && numeric_table[uint8_t(*it)]) {
  313|       |            ++it;
  314|       |         }
  315|       |      }
  316|  23.0k|      return {start, size_t(it - start)};
  317|  23.0k|   }

_ZN3glz13prettify_jsonITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1EEENSt3__16vectorIcNS2_9allocatorIcEEEEEENS2_12basic_stringIcNS2_11char_traitsIcEES5_EERKT0_:
  350|  3.85k|   {
  351|  3.85k|      context ctx{};
  352|  3.85k|      std::string out{};
  353|  3.85k|      detail::prettify_json<Opts>(ctx, in, out);
  354|  3.85k|      if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (354:11): [True: 3.01k, False: 837]
  ------------------
  355|  3.01k|         return {}; // an incomplete result is not a document; see above
  356|  3.01k|      }
  357|    837|      return out;
  358|  3.85k|   }
_ZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1EEETkNS_10contiguousERKNSt3__16vectorIcNS3_9allocatorIcEEEETkNS_13output_bufferERNS3_12basic_stringIcNS3_11char_traitsIcEES6_EETkNS_10is_contextERNS_7contextEEEmOT2_OT0_OT1_:
  294|  3.85k|      {
  295|  3.85k|         if constexpr (resizable<Out>) {
  296|  3.85k|            if (in.size() == 0) {
  ------------------
  |  Branch (296:17): [True: 0, False: 3.85k]
  ------------------
  297|      0|               out.resize(0); // resize is what `resizable` promises; clear() is not
  298|      0|               return 0;
  299|      0|            }
  300|  3.85k|            out.resize(in.size() * 2);
  301|  3.85k|         }
  302|      0|         size_t ix = 0;
  303|  3.85k|         auto [it, end] = read_iterators<Opts>(in);
  304|  3.85k|         if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (304:14): [True: 0, False: 3.85k]
  ------------------
  305|      0|            return 0;
  306|      0|         }
  307|       |
  308|       |         if constexpr (self_terminating<In>) {
  309|       |            prettify_json<opt_true<Opts, &opts::null_terminated>>(ctx, it, end, out, ix);
  310|       |         }
  311|  3.85k|         else {
  312|  3.85k|            prettify_json<opt_false<Opts, &opts::null_terminated>>(ctx, it, end, out, ix);
  313|  3.85k|         }
  314|       |
  315|  3.85k|         if constexpr (resizable<Out>) {
  316|  3.85k|            out.resize(ix);
  317|  3.85k|         }
  318|  3.85k|         return ix;
  319|  3.85k|      }
_ZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_:
   17|  3.85k|      {
   18|  3.85k|         constexpr bool use_tabs = check_indentation_char(Opts) == '\t';
   19|  3.85k|         constexpr auto indent_width = check_indentation_width(Opts);
   20|       |
   21|  3.85k|         using enum json_type;
   22|       |
   23|       |         // Indexed by nesting level, with level 0 the top. Sized for the depth the readers accept (see
   24|       |         // enter_depth), so that every document glz::validate_jsonc passes can be prettified.
   25|  3.85k|         std::array<json_type, max_recursive_depth_limit + 1> state{};
   26|  3.85k|         int64_t indent{};
   27|       |
   28|       |         // Enters one level of nesting, failing past the readers' limit.
   29|  3.85k|         const auto open_level = [&](const json_type type) {
   30|  3.85k|            if (size_t(indent) >= max_recursive_depth_limit) [[unlikely]] {
   31|  3.85k|               ctx.error = error_code::exceeded_max_recursive_depth;
   32|  3.85k|               return false;
   33|  3.85k|            }
   34|  3.85k|            state[++indent] = type;
   35|  3.85k|            return true;
   36|  3.85k|         };
   37|       |
   38|       |         // Set while the output cursor sits on a line that a `//` comment has commented out. Only
   39|       |         // the comment-enabled path can set it, so the plain JSON writer keeps the code it had.
   40|  3.85k|         [[maybe_unused]] bool line_comment_open = false;
   41|       |
   42|       |         // Every line break the writer emits goes through this, because a break is also what ends a
   43|       |         // line comment: doing it in one place is what keeps the two from doubling up. The newline
   44|       |         // and the indentation behind it are also what make the output unbounded -- there is no
   45|       |         // bound on prettified output that a single reservation up front could use -- so this is
   46|       |         // the write a bounded destination is likeliest to run out on.
   47|  3.85k|         const auto new_line = [&] {
   48|  3.85k|            if constexpr (has_bounded_capacity<decltype(b)>) {
   49|  3.85k|               const size_t n = use_tabs ? size_t(indent) : size_t(indent) * indent_width;
   50|  3.85k|               if (not ensure_space(ctx, b, ix + 1 + n)) [[unlikely]] {
   51|  3.85k|                  return false;
   52|  3.85k|               }
   53|  3.85k|            }
   54|  3.85k|            append_new_line<use_tabs, indent_width>(b, ix, indent);
   55|  3.85k|            if constexpr (Opts.comments) {
   56|  3.85k|               line_comment_open = false;
   57|  3.85k|            }
   58|  3.85k|            return true;
   59|  3.85k|         };
   60|       |
   61|       |         // Every write below goes through this, which is what fixes their order in one place: an
   62|       |         // open line comment is closed first, because anything written into one is commented out,
   63|       |         // and emit_bytes then takes the reservation from the argument rather than from a byte
   64|       |         // count spelled out beside the write.
   65|       |         //
   66|       |         // Deferring that break to the next write rather than emitting it with the comment is what
   67|       |         // keeps a comment at the end of the input from leaving a trailing newline behind, and lets
   68|       |         // a break the writer was going to emit anyway serve as this one.
   69|       |         //
   70|       |         // A break that fails is reported rather than swallowed: on a bounded destination that ran
   71|       |         // out, carrying on would leave `line_comment_open` set and put this write *inside* the
   72|       |         // comment, which is not a truncated document but a wrong one.
   73|  3.85k|         const auto put = [&](const auto& x) {
   74|  3.85k|            if constexpr (Opts.comments) {
   75|  3.85k|               if (line_comment_open) [[unlikely]] {
   76|  3.85k|                  if (not new_line()) [[unlikely]] {
   77|  3.85k|                     return false;
   78|  3.85k|                  }
   79|  3.85k|               }
   80|  3.85k|            }
   81|  3.85k|            return emit_bytes<true>(ctx, b, ix, x);
   82|  3.85k|         };
   83|       |
   84|  48.4M|         while (it < end) {
  ------------------
  |  Branch (84:17): [True: 48.4M, False: 837]
  ------------------
   85|  48.4M|            switch (json_types[uint8_t(*it)]) {
   86|  91.5k|            case String: {
  ------------------
  |  Branch (86:13): [True: 91.5k, False: 48.3M]
  ------------------
   87|  91.5k|               const auto value = read_json_string(ctx, it, end);
   88|  91.5k|               if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (88:20): [True: 134, False: 91.4k]
  ------------------
   89|    134|                  return;
   90|    134|               }
   91|       |               // non-empty: the scanner reports an empty view as an error
   92|  91.4k|               if (not put(value)) [[unlikely]] {
  ------------------
  |  Branch (92:20): [True: 0, False: 91.4k]
  ------------------
   93|      0|                  return;
   94|      0|               }
   95|  91.4k|               break;
   96|  91.4k|            }
   97|  47.5M|            case Comma: {
  ------------------
  |  Branch (97:13): [True: 47.5M, False: 830k]
  ------------------
   98|  47.5M|               if (not put(',')) [[unlikely]] {
  ------------------
  |  Branch (98:20): [True: 0, False: 47.5M]
  ------------------
   99|      0|                  return;
  100|      0|               }
  101|  47.5M|               ++it;
  102|  47.5M|               if constexpr (check_new_lines_in_arrays(Opts)) {
  103|  47.5M|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (103:23): [True: 0, False: 47.5M]
  ------------------
  104|      0|                     return;
  105|      0|                  }
  106|       |               }
  107|       |               else {
  108|       |                  if (state[indent] == Object_Start) {
  109|       |                     if (not new_line()) [[unlikely]] {
  110|       |                        return;
  111|       |                     }
  112|       |                  }
  113|       |                  else if (not put(use_tabs ? '\t' : ' ')) [[unlikely]] {
  114|       |                     return;
  115|       |                  }
  116|       |               }
  117|  47.5M|               break;
  118|  47.5M|            }
  119|  47.5M|            case Number: {
  ------------------
  |  Branch (119:13): [True: 31.2k, False: 48.3M]
  ------------------
  120|  31.2k|               const auto value = read_json_number<Opts.null_terminated>(it, end);
  121|       |               // non-empty: a Number match is one valid character
  122|  31.2k|               if (not put(value)) [[unlikely]] {
  ------------------
  |  Branch (122:20): [True: 0, False: 31.2k]
  ------------------
  123|      0|                  return;
  124|      0|               }
  125|  31.2k|               break;
  126|  31.2k|            }
  127|  31.2k|            case Colon: {
  ------------------
  |  Branch (127:13): [True: 21.5k, False: 48.3M]
  ------------------
  128|  21.5k|               static constexpr sv colon = use_tabs ? sv{":\t"} : sv{": "};
  ------------------
  |  Branch (128:44): [Folded, False: 21.5k]
  ------------------
  129|  21.5k|               if (not put(colon)) [[unlikely]] {
  ------------------
  |  Branch (129:20): [True: 0, False: 21.5k]
  ------------------
  130|      0|                  return;
  131|      0|               }
  132|  21.5k|               ++it;
  133|  21.5k|               break;
  134|  21.5k|            }
  135|   275k|            case Array_Start: {
  ------------------
  |  Branch (135:13): [True: 275k, False: 48.1M]
  ------------------
  136|   275k|               if (not put('[')) [[unlikely]] {
  ------------------
  |  Branch (136:20): [True: 0, False: 275k]
  ------------------
  137|      0|                  return;
  138|      0|               }
  139|   275k|               ++it;
  140|   275k|               if (not open_level(Array_Start)) [[unlikely]] {
  ------------------
  |  Branch (140:20): [True: 28, False: 275k]
  ------------------
  141|     28|                  return;
  142|     28|               }
  143|   275k|               if constexpr (check_new_lines_in_arrays(Opts)) {
  144|   275k|                  if constexpr (not Opts.null_terminated) {
  145|   275k|                     if (it != end && *it != ']') {
  ------------------
  |  Branch (145:26): [True: 275k, False: 118]
  |  Branch (145:39): [True: 274k, False: 1.30k]
  ------------------
  146|   274k|                        if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (146:29): [True: 0, False: 274k]
  ------------------
  147|      0|                           return;
  148|      0|                        }
  149|   274k|                     }
  150|       |                  }
  151|       |                  else {
  152|       |                     if (*it != ']') {
  153|       |                        if (not new_line()) [[unlikely]] {
  154|       |                           return;
  155|       |                        }
  156|       |                     }
  157|       |                  }
  158|   275k|               }
  159|   275k|               break;
  160|   275k|            }
  161|   275k|            case Array_End: {
  ------------------
  |  Branch (161:13): [True: 36.4k, False: 48.3M]
  ------------------
  162|  36.4k|               --indent;
  163|  36.4k|               if (indent < 0) {
  ------------------
  |  Branch (163:20): [True: 6, False: 36.4k]
  ------------------
  164|      6|                  ctx.error = error_code::syntax_error;
  165|      6|                  return;
  166|      6|               }
  167|       |               // This break is the one the bracket wanted anyway, and it closes an open line
  168|       |               // comment on its way, leaving the put below nothing to close.
  169|  36.4k|               if constexpr (check_new_lines_in_arrays(Opts)) {
  170|  36.4k|                  if (it[-1] != '[') {
  ------------------
  |  Branch (170:23): [True: 35.1k, False: 1.30k]
  ------------------
  171|  35.1k|                     if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (171:26): [True: 0, False: 35.1k]
  ------------------
  172|      0|                        return;
  173|      0|                     }
  174|  35.1k|                  }
  175|  36.4k|               }
  176|  36.4k|               if (not put(']')) [[unlikely]] {
  ------------------
  |  Branch (176:20): [True: 0, False: 36.4k]
  ------------------
  177|      0|                  return;
  178|      0|               }
  179|  36.4k|               ++it;
  180|  36.4k|               break;
  181|  36.4k|            }
  182|  2.85k|            case Null: {
  ------------------
  |  Branch (182:13): [True: 2.85k, False: 48.4M]
  ------------------
  183|       |               // The type table matched on the first byte alone; see match_literal for why writing
  184|       |               // the literal from the writer's own spelling needs the rest of it checked.
  185|  2.85k|               if (not match_literal<"null">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (185:20): [True: 190, False: 2.66k]
  ------------------
  186|    190|                  return;
  187|    190|               }
  188|  2.66k|               if (not put("null")) [[unlikely]] {
  ------------------
  |  Branch (188:20): [True: 0, False: 2.66k]
  ------------------
  189|      0|                  return;
  190|      0|               }
  191|  2.66k|               break;
  192|  2.66k|            }
  193|  4.39k|            case Bool: {
  ------------------
  |  Branch (193:13): [True: 4.39k, False: 48.4M]
  ------------------
  194|  4.39k|               if (*it == 't') {
  ------------------
  |  Branch (194:20): [True: 2.31k, False: 2.08k]
  ------------------
  195|  2.31k|                  if (not match_literal<"true">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (195:23): [True: 186, False: 2.12k]
  ------------------
  196|    186|                     return;
  197|    186|                  }
  198|  2.12k|                  if (not put("true")) [[unlikely]] {
  ------------------
  |  Branch (198:23): [True: 0, False: 2.12k]
  ------------------
  199|      0|                     return;
  200|      0|                  }
  201|  2.12k|                  break;
  202|  2.12k|               }
  203|  2.08k|               else {
  204|  2.08k|                  if (not match_literal<"false">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (204:23): [True: 270, False: 1.81k]
  ------------------
  205|    270|                     return;
  206|    270|                  }
  207|  1.81k|                  if (not put("false")) [[unlikely]] {
  ------------------
  |  Branch (207:23): [True: 0, False: 1.81k]
  ------------------
  208|      0|                     return;
  209|      0|                  }
  210|  1.81k|                  break;
  211|  1.81k|               }
  212|  4.39k|            }
  213|   152k|            case Object_Start: {
  ------------------
  |  Branch (213:13): [True: 152k, False: 48.2M]
  ------------------
  214|   152k|               if (not put('{')) [[unlikely]] {
  ------------------
  |  Branch (214:20): [True: 0, False: 152k]
  ------------------
  215|      0|                  return;
  216|      0|               }
  217|   152k|               ++it;
  218|   152k|               if (not open_level(Object_Start)) [[unlikely]] {
  ------------------
  |  Branch (218:20): [True: 22, False: 152k]
  ------------------
  219|     22|                  return;
  220|     22|               }
  221|   152k|               if constexpr (not Opts.null_terminated) {
  222|   152k|                  if (it != end && *it != '}') {
  ------------------
  |  Branch (222:23): [True: 151k, False: 104]
  |  Branch (222:36): [True: 148k, False: 3.06k]
  ------------------
  223|   148k|                     if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (223:26): [True: 0, False: 148k]
  ------------------
  224|      0|                        return;
  225|      0|                     }
  226|   148k|                  }
  227|       |               }
  228|       |               else {
  229|       |                  if (*it != '}') {
  230|       |                     if (not new_line()) [[unlikely]] {
  231|       |                        return;
  232|       |                     }
  233|       |                  }
  234|       |               }
  235|   152k|               break;
  236|   152k|            }
  237|   211k|            case Object_End: {
  ------------------
  |  Branch (237:13): [True: 211k, False: 48.2M]
  ------------------
  238|   211k|               --indent;
  239|   211k|               if (indent < 0) {
  ------------------
  |  Branch (239:20): [True: 6, False: 211k]
  ------------------
  240|      6|                  ctx.error = error_code::syntax_error;
  241|      6|                  return;
  242|      6|               }
  243|       |               // As in Array_End, this break doubles as the close of an open line comment.
  244|   211k|               if (it[-1] != '{') {
  ------------------
  |  Branch (244:20): [True: 208k, False: 3.06k]
  ------------------
  245|   208k|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (245:23): [True: 0, False: 208k]
  ------------------
  246|      0|                     return;
  247|      0|                  }
  248|   208k|               }
  249|   211k|               if (not put('}')) [[unlikely]] {
  ------------------
  |  Branch (249:20): [True: 0, False: 211k]
  ------------------
  250|      0|                  return;
  251|      0|               }
  252|   211k|               ++it;
  253|   211k|               break;
  254|   211k|            }
  255|    812|            case Comment: {
  ------------------
  |  Branch (255:13): [True: 812, False: 48.4M]
  ------------------
  256|       |               if constexpr (Opts.comments) {
  257|       |                  const auto comment = read_jsonc_comment(ctx, it, end);
  258|       |                  if (bool(ctx.error)) [[unlikely]] {
  259|       |                     return;
  260|       |                  }
  261|       |                  // non-empty: an empty view comes with an error
  262|       |                  if (not put(comment.text)) [[unlikely]] {
  263|       |                     return;
  264|       |                  }
  265|       |                  line_comment_open = comment.line;
  266|       |                  break;
  267|       |               }
  268|    812|               else {
  269|       |                  // A '/' opens a comment, and plain JSON has none. Skipping it as though it were
  270|       |                  // whitespace silently rewrote the document: "{\"a\":1} // tail" came out as
  271|       |                  // "{...}true", the 't' of "tail" taken for a literal. minify_json has always
  272|       |                  // reported this, and the two had no business disagreeing.
  273|    812|                  ctx.error = error_code::syntax_error;
  274|    812|                  return;
  275|    812|               }
  276|    812|            }
  277|  2.58k|            case Whitespace: {
  ------------------
  |  Branch (277:13): [True: 1.77k, False: 48.4M]
  ------------------
  278|       |               // Skip whitespace characters that are part of raw JSON content
  279|  2.58k|               ++it;
  280|  2.58k|               break;
  281|    812|            }
  282|  1.36k|            [[unlikely]] default: {
  ------------------
  |  Branch (282:26): [True: 1.36k, False: 48.4M]
  ------------------
  283|  1.36k|               ctx.error = error_code::syntax_error;
  284|  1.36k|               return;
  285|      0|            }
  286|  48.4M|            }
  287|  48.4M|         }
  288|  3.85k|      }
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clINS8_17basic_string_viewIcSB_EEEEDaSS_:
   73|   144k|         const auto put = [&](const auto& x) {
   74|       |            if constexpr (Opts.comments) {
   75|       |               if (line_comment_open) [[unlikely]] {
   76|       |                  if (not new_line()) [[unlikely]] {
   77|       |                     return false;
   78|       |                  }
   79|       |               }
   80|       |            }
   81|   144k|            return emit_bytes<true>(ctx, b, ix, x);
   82|   144k|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIcEEDaSS_:
   73|  48.2M|         const auto put = [&](const auto& x) {
   74|       |            if constexpr (Opts.comments) {
   75|       |               if (line_comment_open) [[unlikely]] {
   76|       |                  if (not new_line()) [[unlikely]] {
   77|       |                     return false;
   78|       |                  }
   79|       |               }
   80|       |            }
   81|  48.2M|            return emit_bytes<true>(ctx, b, ix, x);
   82|  48.2M|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlvE_clEv:
   47|  48.2M|         const auto new_line = [&] {
   48|       |            if constexpr (has_bounded_capacity<decltype(b)>) {
   49|       |               const size_t n = use_tabs ? size_t(indent) : size_t(indent) * indent_width;
   50|       |               if (not ensure_space(ctx, b, ix + 1 + n)) [[unlikely]] {
   51|       |                  return false;
   52|       |               }
   53|       |            }
   54|  48.2M|            append_new_line<use_tabs, indent_width>(b, ix, indent);
   55|       |            if constexpr (Opts.comments) {
   56|       |               line_comment_open = false;
   57|       |            }
   58|  48.2M|            return true;
   59|  48.2M|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlNS0_9json_typeEE_clESQ_:
   29|   427k|         const auto open_level = [&](const json_type type) {
   30|   427k|            if (size_t(indent) >= max_recursive_depth_limit) [[unlikely]] {
  ------------------
  |  Branch (30:17): [True: 50, False: 427k]
  ------------------
   31|     50|               ctx.error = error_code::exceeded_max_recursive_depth;
   32|     50|               return false;
   33|     50|            }
   34|   427k|            state[++indent] = type;
   35|   427k|            return true;
   36|   427k|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIA5_cEEDaSS_:
   73|  4.79k|         const auto put = [&](const auto& x) {
   74|       |            if constexpr (Opts.comments) {
   75|       |               if (line_comment_open) [[unlikely]] {
   76|       |                  if (not new_line()) [[unlikely]] {
   77|       |                     return false;
   78|       |                  }
   79|       |               }
   80|       |            }
   81|  4.79k|            return emit_bytes<true>(ctx, b, ix, x);
   82|  4.79k|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIA6_cEEDaSS_:
   73|  1.81k|         const auto put = [&](const auto& x) {
   74|       |            if constexpr (Opts.comments) {
   75|       |               if (line_comment_open) [[unlikely]] {
   76|       |                  if (not new_line()) [[unlikely]] {
   77|       |                     return false;
   78|       |                  }
   79|       |               }
   80|       |            }
   81|  1.81k|            return emit_bytes<true>(ctx, b, ix, x);
   82|  1.81k|         };
_ZN3glz14prettify_jsoncITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1EEENSt3__16vectorIcNS2_9allocatorIcEEEEEENS2_12basic_stringIcNS2_11char_traitsIcEES5_EERKT0_:
  373|  1.92k|   {
  374|  1.92k|      context ctx{};
  375|  1.92k|      std::string out{};
  376|  1.92k|      detail::prettify_json<opt_true<Opts, &opts::comments>>(ctx, in, out);
  377|  1.92k|      if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (377:11): [True: 902, False: 1.02k]
  ------------------
  378|    902|         return {}; // an incomplete result is not a document; see above
  379|    902|      }
  380|  1.02k|      return out;
  381|  1.92k|   }
_ZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10contiguousERKNSt3__16vectorIcNS3_9allocatorIcEEEETkNS_13output_bufferERNS3_12basic_stringIcNS3_11char_traitsIcEES6_EETkNS_10is_contextERNS_7contextEEEmOT2_OT0_OT1_:
  294|  1.92k|      {
  295|  1.92k|         if constexpr (resizable<Out>) {
  296|  1.92k|            if (in.size() == 0) {
  ------------------
  |  Branch (296:17): [True: 0, False: 1.92k]
  ------------------
  297|      0|               out.resize(0); // resize is what `resizable` promises; clear() is not
  298|      0|               return 0;
  299|      0|            }
  300|  1.92k|            out.resize(in.size() * 2);
  301|  1.92k|         }
  302|      0|         size_t ix = 0;
  303|  1.92k|         auto [it, end] = read_iterators<Opts>(in);
  304|  1.92k|         if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (304:14): [True: 0, False: 1.92k]
  ------------------
  305|      0|            return 0;
  306|      0|         }
  307|       |
  308|       |         if constexpr (self_terminating<In>) {
  309|       |            prettify_json<opt_true<Opts, &opts::null_terminated>>(ctx, it, end, out, ix);
  310|       |         }
  311|  1.92k|         else {
  312|  1.92k|            prettify_json<opt_false<Opts, &opts::null_terminated>>(ctx, it, end, out, ix);
  313|  1.92k|         }
  314|       |
  315|  1.92k|         if constexpr (resizable<Out>) {
  316|  1.92k|            out.resize(ix);
  317|  1.92k|         }
  318|  1.92k|         return ix;
  319|  1.92k|      }
_ZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_:
   17|  1.92k|      {
   18|  1.92k|         constexpr bool use_tabs = check_indentation_char(Opts) == '\t';
   19|  1.92k|         constexpr auto indent_width = check_indentation_width(Opts);
   20|       |
   21|  1.92k|         using enum json_type;
   22|       |
   23|       |         // Indexed by nesting level, with level 0 the top. Sized for the depth the readers accept (see
   24|       |         // enter_depth), so that every document glz::validate_jsonc passes can be prettified.
   25|  1.92k|         std::array<json_type, max_recursive_depth_limit + 1> state{};
   26|  1.92k|         int64_t indent{};
   27|       |
   28|       |         // Enters one level of nesting, failing past the readers' limit.
   29|  1.92k|         const auto open_level = [&](const json_type type) {
   30|  1.92k|            if (size_t(indent) >= max_recursive_depth_limit) [[unlikely]] {
   31|  1.92k|               ctx.error = error_code::exceeded_max_recursive_depth;
   32|  1.92k|               return false;
   33|  1.92k|            }
   34|  1.92k|            state[++indent] = type;
   35|  1.92k|            return true;
   36|  1.92k|         };
   37|       |
   38|       |         // Set while the output cursor sits on a line that a `//` comment has commented out. Only
   39|       |         // the comment-enabled path can set it, so the plain JSON writer keeps the code it had.
   40|  1.92k|         [[maybe_unused]] bool line_comment_open = false;
   41|       |
   42|       |         // Every line break the writer emits goes through this, because a break is also what ends a
   43|       |         // line comment: doing it in one place is what keeps the two from doubling up. The newline
   44|       |         // and the indentation behind it are also what make the output unbounded -- there is no
   45|       |         // bound on prettified output that a single reservation up front could use -- so this is
   46|       |         // the write a bounded destination is likeliest to run out on.
   47|  1.92k|         const auto new_line = [&] {
   48|  1.92k|            if constexpr (has_bounded_capacity<decltype(b)>) {
   49|  1.92k|               const size_t n = use_tabs ? size_t(indent) : size_t(indent) * indent_width;
   50|  1.92k|               if (not ensure_space(ctx, b, ix + 1 + n)) [[unlikely]] {
   51|  1.92k|                  return false;
   52|  1.92k|               }
   53|  1.92k|            }
   54|  1.92k|            append_new_line<use_tabs, indent_width>(b, ix, indent);
   55|  1.92k|            if constexpr (Opts.comments) {
   56|  1.92k|               line_comment_open = false;
   57|  1.92k|            }
   58|  1.92k|            return true;
   59|  1.92k|         };
   60|       |
   61|       |         // Every write below goes through this, which is what fixes their order in one place: an
   62|       |         // open line comment is closed first, because anything written into one is commented out,
   63|       |         // and emit_bytes then takes the reservation from the argument rather than from a byte
   64|       |         // count spelled out beside the write.
   65|       |         //
   66|       |         // Deferring that break to the next write rather than emitting it with the comment is what
   67|       |         // keeps a comment at the end of the input from leaving a trailing newline behind, and lets
   68|       |         // a break the writer was going to emit anyway serve as this one.
   69|       |         //
   70|       |         // A break that fails is reported rather than swallowed: on a bounded destination that ran
   71|       |         // out, carrying on would leave `line_comment_open` set and put this write *inside* the
   72|       |         // comment, which is not a truncated document but a wrong one.
   73|  1.92k|         const auto put = [&](const auto& x) {
   74|  1.92k|            if constexpr (Opts.comments) {
   75|  1.92k|               if (line_comment_open) [[unlikely]] {
   76|  1.92k|                  if (not new_line()) [[unlikely]] {
   77|  1.92k|                     return false;
   78|  1.92k|                  }
   79|  1.92k|               }
   80|  1.92k|            }
   81|  1.92k|            return emit_bytes<true>(ctx, b, ix, x);
   82|  1.92k|         };
   83|       |
   84|  36.8M|         while (it < end) {
  ------------------
  |  Branch (84:17): [True: 36.8M, False: 1.02k]
  ------------------
   85|  36.8M|            switch (json_types[uint8_t(*it)]) {
   86|  69.0k|            case String: {
  ------------------
  |  Branch (86:13): [True: 69.0k, False: 36.7M]
  ------------------
   87|  69.0k|               const auto value = read_json_string(ctx, it, end);
   88|  69.0k|               if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (88:20): [True: 71, False: 68.9k]
  ------------------
   89|     71|                  return;
   90|     71|               }
   91|       |               // non-empty: the scanner reports an empty view as an error
   92|  68.9k|               if (not put(value)) [[unlikely]] {
  ------------------
  |  Branch (92:20): [True: 0, False: 68.9k]
  ------------------
   93|      0|                  return;
   94|      0|               }
   95|  68.9k|               break;
   96|  68.9k|            }
   97|  36.3M|            case Comma: {
  ------------------
  |  Branch (97:13): [True: 36.3M, False: 473k]
  ------------------
   98|  36.3M|               if (not put(',')) [[unlikely]] {
  ------------------
  |  Branch (98:20): [True: 0, False: 36.3M]
  ------------------
   99|      0|                  return;
  100|      0|               }
  101|  36.3M|               ++it;
  102|  36.3M|               if constexpr (check_new_lines_in_arrays(Opts)) {
  103|  36.3M|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (103:23): [True: 0, False: 36.3M]
  ------------------
  104|      0|                     return;
  105|      0|                  }
  106|       |               }
  107|       |               else {
  108|       |                  if (state[indent] == Object_Start) {
  109|       |                     if (not new_line()) [[unlikely]] {
  110|       |                        return;
  111|       |                     }
  112|       |                  }
  113|       |                  else if (not put(use_tabs ? '\t' : ' ')) [[unlikely]] {
  114|       |                     return;
  115|       |                  }
  116|       |               }
  117|  36.3M|               break;
  118|  36.3M|            }
  119|  36.3M|            case Number: {
  ------------------
  |  Branch (119:13): [True: 23.0k, False: 36.7M]
  ------------------
  120|  23.0k|               const auto value = read_json_number<Opts.null_terminated>(it, end);
  121|       |               // non-empty: a Number match is one valid character
  122|  23.0k|               if (not put(value)) [[unlikely]] {
  ------------------
  |  Branch (122:20): [True: 0, False: 23.0k]
  ------------------
  123|      0|                  return;
  124|      0|               }
  125|  23.0k|               break;
  126|  23.0k|            }
  127|  23.0k|            case Colon: {
  ------------------
  |  Branch (127:13): [True: 14.5k, False: 36.7M]
  ------------------
  128|  14.5k|               static constexpr sv colon = use_tabs ? sv{":\t"} : sv{": "};
  ------------------
  |  Branch (128:44): [Folded, False: 14.5k]
  ------------------
  129|  14.5k|               if (not put(colon)) [[unlikely]] {
  ------------------
  |  Branch (129:20): [True: 0, False: 14.5k]
  ------------------
  130|      0|                  return;
  131|      0|               }
  132|  14.5k|               ++it;
  133|  14.5k|               break;
  134|  14.5k|            }
  135|   140k|            case Array_Start: {
  ------------------
  |  Branch (135:13): [True: 140k, False: 36.6M]
  ------------------
  136|   140k|               if (not put('[')) [[unlikely]] {
  ------------------
  |  Branch (136:20): [True: 0, False: 140k]
  ------------------
  137|      0|                  return;
  138|      0|               }
  139|   140k|               ++it;
  140|   140k|               if (not open_level(Array_Start)) [[unlikely]] {
  ------------------
  |  Branch (140:20): [True: 16, False: 140k]
  ------------------
  141|     16|                  return;
  142|     16|               }
  143|   140k|               if constexpr (check_new_lines_in_arrays(Opts)) {
  144|   140k|                  if constexpr (not Opts.null_terminated) {
  145|   140k|                     if (it != end && *it != ']') {
  ------------------
  |  Branch (145:26): [True: 140k, False: 129]
  |  Branch (145:39): [True: 139k, False: 846]
  ------------------
  146|   139k|                        if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (146:29): [True: 0, False: 139k]
  ------------------
  147|      0|                           return;
  148|      0|                        }
  149|   139k|                     }
  150|       |                  }
  151|       |                  else {
  152|       |                     if (*it != ']') {
  153|       |                        if (not new_line()) [[unlikely]] {
  154|       |                           return;
  155|       |                        }
  156|       |                     }
  157|       |                  }
  158|   140k|               }
  159|   140k|               break;
  160|   140k|            }
  161|   140k|            case Array_End: {
  ------------------
  |  Branch (161:13): [True: 18.8k, False: 36.7M]
  ------------------
  162|  18.8k|               --indent;
  163|  18.8k|               if (indent < 0) {
  ------------------
  |  Branch (163:20): [True: 3, False: 18.8k]
  ------------------
  164|      3|                  ctx.error = error_code::syntax_error;
  165|      3|                  return;
  166|      3|               }
  167|       |               // This break is the one the bracket wanted anyway, and it closes an open line
  168|       |               // comment on its way, leaving the put below nothing to close.
  169|  18.8k|               if constexpr (check_new_lines_in_arrays(Opts)) {
  170|  18.8k|                  if (it[-1] != '[') {
  ------------------
  |  Branch (170:23): [True: 17.9k, False: 846]
  ------------------
  171|  17.9k|                     if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (171:26): [True: 0, False: 17.9k]
  ------------------
  172|      0|                        return;
  173|      0|                     }
  174|  17.9k|                  }
  175|  18.8k|               }
  176|  18.8k|               if (not put(']')) [[unlikely]] {
  ------------------
  |  Branch (176:20): [True: 0, False: 18.8k]
  ------------------
  177|      0|                  return;
  178|      0|               }
  179|  18.8k|               ++it;
  180|  18.8k|               break;
  181|  18.8k|            }
  182|  1.69k|            case Null: {
  ------------------
  |  Branch (182:13): [True: 1.69k, False: 36.8M]
  ------------------
  183|       |               // The type table matched on the first byte alone; see match_literal for why writing
  184|       |               // the literal from the writer's own spelling needs the rest of it checked.
  185|  1.69k|               if (not match_literal<"null">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (185:20): [True: 97, False: 1.59k]
  ------------------
  186|     97|                  return;
  187|     97|               }
  188|  1.59k|               if (not put("null")) [[unlikely]] {
  ------------------
  |  Branch (188:20): [True: 0, False: 1.59k]
  ------------------
  189|      0|                  return;
  190|      0|               }
  191|  1.59k|               break;
  192|  1.59k|            }
  193|  5.25k|            case Bool: {
  ------------------
  |  Branch (193:13): [True: 5.25k, False: 36.8M]
  ------------------
  194|  5.25k|               if (*it == 't') {
  ------------------
  |  Branch (194:20): [True: 3.87k, False: 1.38k]
  ------------------
  195|  3.87k|                  if (not match_literal<"true">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (195:23): [True: 97, False: 3.78k]
  ------------------
  196|     97|                     return;
  197|     97|                  }
  198|  3.78k|                  if (not put("true")) [[unlikely]] {
  ------------------
  |  Branch (198:23): [True: 0, False: 3.78k]
  ------------------
  199|      0|                     return;
  200|      0|                  }
  201|  3.78k|                  break;
  202|  3.78k|               }
  203|  1.38k|               else {
  204|  1.38k|                  if (not match_literal<"false">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (204:23): [True: 142, False: 1.23k]
  ------------------
  205|    142|                     return;
  206|    142|                  }
  207|  1.23k|                  if (not put("false")) [[unlikely]] {
  ------------------
  |  Branch (207:23): [True: 0, False: 1.23k]
  ------------------
  208|      0|                     return;
  209|      0|                  }
  210|  1.23k|                  break;
  211|  1.23k|               }
  212|  5.25k|            }
  213|  78.3k|            case Object_Start: {
  ------------------
  |  Branch (213:13): [True: 78.3k, False: 36.7M]
  ------------------
  214|  78.3k|               if (not put('{')) [[unlikely]] {
  ------------------
  |  Branch (214:20): [True: 0, False: 78.3k]
  ------------------
  215|      0|                  return;
  216|      0|               }
  217|  78.3k|               ++it;
  218|  78.3k|               if (not open_level(Object_Start)) [[unlikely]] {
  ------------------
  |  Branch (218:20): [True: 12, False: 78.3k]
  ------------------
  219|     12|                  return;
  220|     12|               }
  221|  78.3k|               if constexpr (not Opts.null_terminated) {
  222|  78.3k|                  if (it != end && *it != '}') {
  ------------------
  |  Branch (222:23): [True: 78.2k, False: 125]
  |  Branch (222:36): [True: 76.6k, False: 1.57k]
  ------------------
  223|  76.6k|                     if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (223:26): [True: 0, False: 76.6k]
  ------------------
  224|      0|                        return;
  225|      0|                     }
  226|  76.6k|                  }
  227|       |               }
  228|       |               else {
  229|       |                  if (*it != '}') {
  230|       |                     if (not new_line()) [[unlikely]] {
  231|       |                        return;
  232|       |                     }
  233|       |                  }
  234|       |               }
  235|  78.3k|               break;
  236|  78.3k|            }
  237|   106k|            case Object_End: {
  ------------------
  |  Branch (237:13): [True: 106k, False: 36.7M]
  ------------------
  238|   106k|               --indent;
  239|   106k|               if (indent < 0) {
  ------------------
  |  Branch (239:20): [True: 3, False: 106k]
  ------------------
  240|      3|                  ctx.error = error_code::syntax_error;
  241|      3|                  return;
  242|      3|               }
  243|       |               // As in Array_End, this break doubles as the close of an open line comment.
  244|   106k|               if (it[-1] != '{') {
  ------------------
  |  Branch (244:20): [True: 105k, False: 1.57k]
  ------------------
  245|   105k|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (245:23): [True: 0, False: 105k]
  ------------------
  246|      0|                     return;
  247|      0|                  }
  248|   105k|               }
  249|   106k|               if (not put('}')) [[unlikely]] {
  ------------------
  |  Branch (249:20): [True: 0, False: 106k]
  ------------------
  250|      0|                  return;
  251|      0|               }
  252|   106k|               ++it;
  253|   106k|               break;
  254|   106k|            }
  255|  7.01k|            case Comment: {
  ------------------
  |  Branch (255:13): [True: 7.01k, False: 36.8M]
  ------------------
  256|  7.01k|               if constexpr (Opts.comments) {
  257|  7.01k|                  const auto comment = read_jsonc_comment(ctx, it, end);
  258|  7.01k|                  if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (258:23): [True: 152, False: 6.86k]
  ------------------
  259|    152|                     return;
  260|    152|                  }
  261|       |                  // non-empty: an empty view comes with an error
  262|  6.86k|                  if (not put(comment.text)) [[unlikely]] {
  ------------------
  |  Branch (262:23): [True: 0, False: 6.86k]
  ------------------
  263|      0|                     return;
  264|      0|                  }
  265|  6.86k|                  line_comment_open = comment.line;
  266|  6.86k|                  break;
  267|       |               }
  268|       |               else {
  269|       |                  // A '/' opens a comment, and plain JSON has none. Skipping it as though it were
  270|       |                  // whitespace silently rewrote the document: "{\"a\":1} // tail" came out as
  271|       |                  // "{...}true", the 't' of "tail" taken for a literal. minify_json has always
  272|       |                  // reported this, and the two had no business disagreeing.
  273|       |                  ctx.error = error_code::syntax_error;
  274|       |                  return;
  275|       |               }
  276|  7.01k|            }
  277|  14.9k|            case Whitespace: {
  ------------------
  |  Branch (277:13): [True: 7.91k, False: 36.8M]
  ------------------
  278|       |               // Skip whitespace characters that are part of raw JSON content
  279|  14.9k|               ++it;
  280|  14.9k|               break;
  281|  7.01k|            }
  282|    309|            [[unlikely]] default: {
  ------------------
  |  Branch (282:26): [True: 309, False: 36.8M]
  ------------------
  283|    309|               ctx.error = error_code::syntax_error;
  284|    309|               return;
  285|      0|            }
  286|  36.8M|            }
  287|  36.8M|         }
  288|  1.92k|      }
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clINS8_17basic_string_viewIcSB_EEEEDaSS_:
   73|   113k|         const auto put = [&](const auto& x) {
   74|   113k|            if constexpr (Opts.comments) {
   75|   113k|               if (line_comment_open) [[unlikely]] {
  ------------------
  |  Branch (75:20): [True: 1.64k, False: 111k]
  ------------------
   76|  1.64k|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (76:23): [True: 0, False: 1.64k]
  ------------------
   77|      0|                     return false;
   78|      0|                  }
   79|  1.64k|               }
   80|   113k|            }
   81|   113k|            return emit_bytes<true>(ctx, b, ix, x);
   82|   113k|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIcEEDaSS_:
   73|  36.6M|         const auto put = [&](const auto& x) {
   74|  36.6M|            if constexpr (Opts.comments) {
   75|  36.6M|               if (line_comment_open) [[unlikely]] {
  ------------------
  |  Branch (75:20): [True: 1.26k, False: 36.6M]
  ------------------
   76|  1.26k|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (76:23): [True: 0, False: 1.26k]
  ------------------
   77|      0|                     return false;
   78|      0|                  }
   79|  1.26k|               }
   80|  36.6M|            }
   81|  36.6M|            return emit_bytes<true>(ctx, b, ix, x);
   82|  36.6M|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlvE_clEv:
   47|  36.6M|         const auto new_line = [&] {
   48|       |            if constexpr (has_bounded_capacity<decltype(b)>) {
   49|       |               const size_t n = use_tabs ? size_t(indent) : size_t(indent) * indent_width;
   50|       |               if (not ensure_space(ctx, b, ix + 1 + n)) [[unlikely]] {
   51|       |                  return false;
   52|       |               }
   53|       |            }
   54|  36.6M|            append_new_line<use_tabs, indent_width>(b, ix, indent);
   55|  36.6M|            if constexpr (Opts.comments) {
   56|  36.6M|               line_comment_open = false;
   57|  36.6M|            }
   58|  36.6M|            return true;
   59|  36.6M|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlNS0_9json_typeEE_clESQ_:
   29|   219k|         const auto open_level = [&](const json_type type) {
   30|   219k|            if (size_t(indent) >= max_recursive_depth_limit) [[unlikely]] {
  ------------------
  |  Branch (30:17): [True: 28, False: 219k]
  ------------------
   31|     28|               ctx.error = error_code::exceeded_max_recursive_depth;
   32|     28|               return false;
   33|     28|            }
   34|   219k|            state[++indent] = type;
   35|   219k|            return true;
   36|   219k|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIA5_cEEDaSS_:
   73|  5.37k|         const auto put = [&](const auto& x) {
   74|  5.37k|            if constexpr (Opts.comments) {
   75|  5.37k|               if (line_comment_open) [[unlikely]] {
  ------------------
  |  Branch (75:20): [True: 2.92k, False: 2.45k]
  ------------------
   76|  2.92k|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (76:23): [True: 0, False: 2.92k]
  ------------------
   77|      0|                     return false;
   78|      0|                  }
   79|  2.92k|               }
   80|  5.37k|            }
   81|  5.37k|            return emit_bytes<true>(ctx, b, ix, x);
   82|  5.37k|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIA6_cEEDaSS_:
   73|  1.23k|         const auto put = [&](const auto& x) {
   74|  1.23k|            if constexpr (Opts.comments) {
   75|  1.23k|               if (line_comment_open) [[unlikely]] {
  ------------------
  |  Branch (75:20): [True: 239, False: 999]
  ------------------
   76|    239|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (76:23): [True: 0, False: 239]
  ------------------
   77|      0|                     return false;
   78|      0|                  }
   79|    239|               }
   80|  1.23k|            }
   81|  1.23k|            return emit_bytes<true>(ctx, b, ix, x);
   82|  1.23k|         };
_ZN3glz14prettify_jsoncITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1EEENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEES8_RKT0_:
  373|  1.92k|   {
  374|  1.92k|      context ctx{};
  375|  1.92k|      std::string out{};
  376|  1.92k|      detail::prettify_json<opt_true<Opts, &opts::comments>>(ctx, in, out);
  377|  1.92k|      if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (377:11): [True: 902, False: 1.02k]
  ------------------
  378|    902|         return {}; // an incomplete result is not a document; see above
  379|    902|      }
  380|  1.02k|      return out;
  381|  1.92k|   }
_ZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10contiguousERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEETkNS_13output_bufferERS9_TkNS_10is_contextERNS_7contextEEEmOT2_OT0_OT1_:
  294|  1.92k|      {
  295|  1.92k|         if constexpr (resizable<Out>) {
  296|  1.92k|            if (in.size() == 0) {
  ------------------
  |  Branch (296:17): [True: 0, False: 1.92k]
  ------------------
  297|      0|               out.resize(0); // resize is what `resizable` promises; clear() is not
  298|      0|               return 0;
  299|      0|            }
  300|  1.92k|            out.resize(in.size() * 2);
  301|  1.92k|         }
  302|      0|         size_t ix = 0;
  303|  1.92k|         auto [it, end] = read_iterators<Opts>(in);
  304|  1.92k|         if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (304:14): [True: 0, False: 1.92k]
  ------------------
  305|      0|            return 0;
  306|      0|         }
  307|       |
  308|  1.92k|         if constexpr (self_terminating<In>) {
  309|  1.92k|            prettify_json<opt_true<Opts, &opts::null_terminated>>(ctx, it, end, out, ix);
  310|       |         }
  311|       |         else {
  312|       |            prettify_json<opt_false<Opts, &opts::null_terminated>>(ctx, it, end, out, ix);
  313|       |         }
  314|       |
  315|  1.92k|         if constexpr (resizable<Out>) {
  316|  1.92k|            out.resize(ix);
  317|  1.92k|         }
  318|  1.92k|         return ix;
  319|  1.92k|      }
_ZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_:
   17|  1.92k|      {
   18|  1.92k|         constexpr bool use_tabs = check_indentation_char(Opts) == '\t';
   19|  1.92k|         constexpr auto indent_width = check_indentation_width(Opts);
   20|       |
   21|  1.92k|         using enum json_type;
   22|       |
   23|       |         // Indexed by nesting level, with level 0 the top. Sized for the depth the readers accept (see
   24|       |         // enter_depth), so that every document glz::validate_jsonc passes can be prettified.
   25|  1.92k|         std::array<json_type, max_recursive_depth_limit + 1> state{};
   26|  1.92k|         int64_t indent{};
   27|       |
   28|       |         // Enters one level of nesting, failing past the readers' limit.
   29|  1.92k|         const auto open_level = [&](const json_type type) {
   30|  1.92k|            if (size_t(indent) >= max_recursive_depth_limit) [[unlikely]] {
   31|  1.92k|               ctx.error = error_code::exceeded_max_recursive_depth;
   32|  1.92k|               return false;
   33|  1.92k|            }
   34|  1.92k|            state[++indent] = type;
   35|  1.92k|            return true;
   36|  1.92k|         };
   37|       |
   38|       |         // Set while the output cursor sits on a line that a `//` comment has commented out. Only
   39|       |         // the comment-enabled path can set it, so the plain JSON writer keeps the code it had.
   40|  1.92k|         [[maybe_unused]] bool line_comment_open = false;
   41|       |
   42|       |         // Every line break the writer emits goes through this, because a break is also what ends a
   43|       |         // line comment: doing it in one place is what keeps the two from doubling up. The newline
   44|       |         // and the indentation behind it are also what make the output unbounded -- there is no
   45|       |         // bound on prettified output that a single reservation up front could use -- so this is
   46|       |         // the write a bounded destination is likeliest to run out on.
   47|  1.92k|         const auto new_line = [&] {
   48|  1.92k|            if constexpr (has_bounded_capacity<decltype(b)>) {
   49|  1.92k|               const size_t n = use_tabs ? size_t(indent) : size_t(indent) * indent_width;
   50|  1.92k|               if (not ensure_space(ctx, b, ix + 1 + n)) [[unlikely]] {
   51|  1.92k|                  return false;
   52|  1.92k|               }
   53|  1.92k|            }
   54|  1.92k|            append_new_line<use_tabs, indent_width>(b, ix, indent);
   55|  1.92k|            if constexpr (Opts.comments) {
   56|  1.92k|               line_comment_open = false;
   57|  1.92k|            }
   58|  1.92k|            return true;
   59|  1.92k|         };
   60|       |
   61|       |         // Every write below goes through this, which is what fixes their order in one place: an
   62|       |         // open line comment is closed first, because anything written into one is commented out,
   63|       |         // and emit_bytes then takes the reservation from the argument rather than from a byte
   64|       |         // count spelled out beside the write.
   65|       |         //
   66|       |         // Deferring that break to the next write rather than emitting it with the comment is what
   67|       |         // keeps a comment at the end of the input from leaving a trailing newline behind, and lets
   68|       |         // a break the writer was going to emit anyway serve as this one.
   69|       |         //
   70|       |         // A break that fails is reported rather than swallowed: on a bounded destination that ran
   71|       |         // out, carrying on would leave `line_comment_open` set and put this write *inside* the
   72|       |         // comment, which is not a truncated document but a wrong one.
   73|  1.92k|         const auto put = [&](const auto& x) {
   74|  1.92k|            if constexpr (Opts.comments) {
   75|  1.92k|               if (line_comment_open) [[unlikely]] {
   76|  1.92k|                  if (not new_line()) [[unlikely]] {
   77|  1.92k|                     return false;
   78|  1.92k|                  }
   79|  1.92k|               }
   80|  1.92k|            }
   81|  1.92k|            return emit_bytes<true>(ctx, b, ix, x);
   82|  1.92k|         };
   83|       |
   84|  36.8M|         while (it < end) {
  ------------------
  |  Branch (84:17): [True: 36.8M, False: 1.02k]
  ------------------
   85|  36.8M|            switch (json_types[uint8_t(*it)]) {
   86|  69.0k|            case String: {
  ------------------
  |  Branch (86:13): [True: 69.0k, False: 36.7M]
  ------------------
   87|  69.0k|               const auto value = read_json_string(ctx, it, end);
   88|  69.0k|               if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (88:20): [True: 71, False: 68.9k]
  ------------------
   89|     71|                  return;
   90|     71|               }
   91|       |               // non-empty: the scanner reports an empty view as an error
   92|  68.9k|               if (not put(value)) [[unlikely]] {
  ------------------
  |  Branch (92:20): [True: 0, False: 68.9k]
  ------------------
   93|      0|                  return;
   94|      0|               }
   95|  68.9k|               break;
   96|  68.9k|            }
   97|  36.3M|            case Comma: {
  ------------------
  |  Branch (97:13): [True: 36.3M, False: 473k]
  ------------------
   98|  36.3M|               if (not put(',')) [[unlikely]] {
  ------------------
  |  Branch (98:20): [True: 0, False: 36.3M]
  ------------------
   99|      0|                  return;
  100|      0|               }
  101|  36.3M|               ++it;
  102|  36.3M|               if constexpr (check_new_lines_in_arrays(Opts)) {
  103|  36.3M|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (103:23): [True: 0, False: 36.3M]
  ------------------
  104|      0|                     return;
  105|      0|                  }
  106|       |               }
  107|       |               else {
  108|       |                  if (state[indent] == Object_Start) {
  109|       |                     if (not new_line()) [[unlikely]] {
  110|       |                        return;
  111|       |                     }
  112|       |                  }
  113|       |                  else if (not put(use_tabs ? '\t' : ' ')) [[unlikely]] {
  114|       |                     return;
  115|       |                  }
  116|       |               }
  117|  36.3M|               break;
  118|  36.3M|            }
  119|  36.3M|            case Number: {
  ------------------
  |  Branch (119:13): [True: 23.0k, False: 36.7M]
  ------------------
  120|  23.0k|               const auto value = read_json_number<Opts.null_terminated>(it, end);
  121|       |               // non-empty: a Number match is one valid character
  122|  23.0k|               if (not put(value)) [[unlikely]] {
  ------------------
  |  Branch (122:20): [True: 0, False: 23.0k]
  ------------------
  123|      0|                  return;
  124|      0|               }
  125|  23.0k|               break;
  126|  23.0k|            }
  127|  23.0k|            case Colon: {
  ------------------
  |  Branch (127:13): [True: 14.5k, False: 36.7M]
  ------------------
  128|  14.5k|               static constexpr sv colon = use_tabs ? sv{":\t"} : sv{": "};
  ------------------
  |  Branch (128:44): [Folded, False: 14.5k]
  ------------------
  129|  14.5k|               if (not put(colon)) [[unlikely]] {
  ------------------
  |  Branch (129:20): [True: 0, False: 14.5k]
  ------------------
  130|      0|                  return;
  131|      0|               }
  132|  14.5k|               ++it;
  133|  14.5k|               break;
  134|  14.5k|            }
  135|   140k|            case Array_Start: {
  ------------------
  |  Branch (135:13): [True: 140k, False: 36.6M]
  ------------------
  136|   140k|               if (not put('[')) [[unlikely]] {
  ------------------
  |  Branch (136:20): [True: 0, False: 140k]
  ------------------
  137|      0|                  return;
  138|      0|               }
  139|   140k|               ++it;
  140|   140k|               if (not open_level(Array_Start)) [[unlikely]] {
  ------------------
  |  Branch (140:20): [True: 16, False: 140k]
  ------------------
  141|     16|                  return;
  142|     16|               }
  143|   140k|               if constexpr (check_new_lines_in_arrays(Opts)) {
  144|       |                  if constexpr (not Opts.null_terminated) {
  145|       |                     if (it != end && *it != ']') {
  146|       |                        if (not new_line()) [[unlikely]] {
  147|       |                           return;
  148|       |                        }
  149|       |                     }
  150|       |                  }
  151|   140k|                  else {
  152|   140k|                     if (*it != ']') {
  ------------------
  |  Branch (152:26): [True: 139k, False: 846]
  ------------------
  153|   139k|                        if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (153:29): [True: 0, False: 139k]
  ------------------
  154|      0|                           return;
  155|      0|                        }
  156|   139k|                     }
  157|   140k|                  }
  158|   140k|               }
  159|   140k|               break;
  160|   140k|            }
  161|   140k|            case Array_End: {
  ------------------
  |  Branch (161:13): [True: 18.8k, False: 36.7M]
  ------------------
  162|  18.8k|               --indent;
  163|  18.8k|               if (indent < 0) {
  ------------------
  |  Branch (163:20): [True: 3, False: 18.8k]
  ------------------
  164|      3|                  ctx.error = error_code::syntax_error;
  165|      3|                  return;
  166|      3|               }
  167|       |               // This break is the one the bracket wanted anyway, and it closes an open line
  168|       |               // comment on its way, leaving the put below nothing to close.
  169|  18.8k|               if constexpr (check_new_lines_in_arrays(Opts)) {
  170|  18.8k|                  if (it[-1] != '[') {
  ------------------
  |  Branch (170:23): [True: 17.9k, False: 846]
  ------------------
  171|  17.9k|                     if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (171:26): [True: 0, False: 17.9k]
  ------------------
  172|      0|                        return;
  173|      0|                     }
  174|  17.9k|                  }
  175|  18.8k|               }
  176|  18.8k|               if (not put(']')) [[unlikely]] {
  ------------------
  |  Branch (176:20): [True: 0, False: 18.8k]
  ------------------
  177|      0|                  return;
  178|      0|               }
  179|  18.8k|               ++it;
  180|  18.8k|               break;
  181|  18.8k|            }
  182|  1.69k|            case Null: {
  ------------------
  |  Branch (182:13): [True: 1.69k, False: 36.8M]
  ------------------
  183|       |               // The type table matched on the first byte alone; see match_literal for why writing
  184|       |               // the literal from the writer's own spelling needs the rest of it checked.
  185|  1.69k|               if (not match_literal<"null">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (185:20): [True: 97, False: 1.59k]
  ------------------
  186|     97|                  return;
  187|     97|               }
  188|  1.59k|               if (not put("null")) [[unlikely]] {
  ------------------
  |  Branch (188:20): [True: 0, False: 1.59k]
  ------------------
  189|      0|                  return;
  190|      0|               }
  191|  1.59k|               break;
  192|  1.59k|            }
  193|  5.25k|            case Bool: {
  ------------------
  |  Branch (193:13): [True: 5.25k, False: 36.8M]
  ------------------
  194|  5.25k|               if (*it == 't') {
  ------------------
  |  Branch (194:20): [True: 3.87k, False: 1.38k]
  ------------------
  195|  3.87k|                  if (not match_literal<"true">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (195:23): [True: 97, False: 3.78k]
  ------------------
  196|     97|                     return;
  197|     97|                  }
  198|  3.78k|                  if (not put("true")) [[unlikely]] {
  ------------------
  |  Branch (198:23): [True: 0, False: 3.78k]
  ------------------
  199|      0|                     return;
  200|      0|                  }
  201|  3.78k|                  break;
  202|  3.78k|               }
  203|  1.38k|               else {
  204|  1.38k|                  if (not match_literal<"false">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (204:23): [True: 142, False: 1.23k]
  ------------------
  205|    142|                     return;
  206|    142|                  }
  207|  1.23k|                  if (not put("false")) [[unlikely]] {
  ------------------
  |  Branch (207:23): [True: 0, False: 1.23k]
  ------------------
  208|      0|                     return;
  209|      0|                  }
  210|  1.23k|                  break;
  211|  1.23k|               }
  212|  5.25k|            }
  213|  78.3k|            case Object_Start: {
  ------------------
  |  Branch (213:13): [True: 78.3k, False: 36.7M]
  ------------------
  214|  78.3k|               if (not put('{')) [[unlikely]] {
  ------------------
  |  Branch (214:20): [True: 0, False: 78.3k]
  ------------------
  215|      0|                  return;
  216|      0|               }
  217|  78.3k|               ++it;
  218|  78.3k|               if (not open_level(Object_Start)) [[unlikely]] {
  ------------------
  |  Branch (218:20): [True: 12, False: 78.3k]
  ------------------
  219|     12|                  return;
  220|     12|               }
  221|       |               if constexpr (not Opts.null_terminated) {
  222|       |                  if (it != end && *it != '}') {
  223|       |                     if (not new_line()) [[unlikely]] {
  224|       |                        return;
  225|       |                     }
  226|       |                  }
  227|       |               }
  228|  78.3k|               else {
  229|  78.3k|                  if (*it != '}') {
  ------------------
  |  Branch (229:23): [True: 76.7k, False: 1.57k]
  ------------------
  230|  76.7k|                     if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (230:26): [True: 0, False: 76.7k]
  ------------------
  231|      0|                        return;
  232|      0|                     }
  233|  76.7k|                  }
  234|  78.3k|               }
  235|  78.3k|               break;
  236|  78.3k|            }
  237|   106k|            case Object_End: {
  ------------------
  |  Branch (237:13): [True: 106k, False: 36.7M]
  ------------------
  238|   106k|               --indent;
  239|   106k|               if (indent < 0) {
  ------------------
  |  Branch (239:20): [True: 3, False: 106k]
  ------------------
  240|      3|                  ctx.error = error_code::syntax_error;
  241|      3|                  return;
  242|      3|               }
  243|       |               // As in Array_End, this break doubles as the close of an open line comment.
  244|   106k|               if (it[-1] != '{') {
  ------------------
  |  Branch (244:20): [True: 105k, False: 1.57k]
  ------------------
  245|   105k|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (245:23): [True: 0, False: 105k]
  ------------------
  246|      0|                     return;
  247|      0|                  }
  248|   105k|               }
  249|   106k|               if (not put('}')) [[unlikely]] {
  ------------------
  |  Branch (249:20): [True: 0, False: 106k]
  ------------------
  250|      0|                  return;
  251|      0|               }
  252|   106k|               ++it;
  253|   106k|               break;
  254|   106k|            }
  255|  7.01k|            case Comment: {
  ------------------
  |  Branch (255:13): [True: 7.01k, False: 36.8M]
  ------------------
  256|  7.01k|               if constexpr (Opts.comments) {
  257|  7.01k|                  const auto comment = read_jsonc_comment(ctx, it, end);
  258|  7.01k|                  if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (258:23): [True: 152, False: 6.86k]
  ------------------
  259|    152|                     return;
  260|    152|                  }
  261|       |                  // non-empty: an empty view comes with an error
  262|  6.86k|                  if (not put(comment.text)) [[unlikely]] {
  ------------------
  |  Branch (262:23): [True: 0, False: 6.86k]
  ------------------
  263|      0|                     return;
  264|      0|                  }
  265|  6.86k|                  line_comment_open = comment.line;
  266|  6.86k|                  break;
  267|       |               }
  268|       |               else {
  269|       |                  // A '/' opens a comment, and plain JSON has none. Skipping it as though it were
  270|       |                  // whitespace silently rewrote the document: "{\"a\":1} // tail" came out as
  271|       |                  // "{...}true", the 't' of "tail" taken for a literal. minify_json has always
  272|       |                  // reported this, and the two had no business disagreeing.
  273|       |                  ctx.error = error_code::syntax_error;
  274|       |                  return;
  275|       |               }
  276|  7.01k|            }
  277|  14.9k|            case Whitespace: {
  ------------------
  |  Branch (277:13): [True: 7.91k, False: 36.8M]
  ------------------
  278|       |               // Skip whitespace characters that are part of raw JSON content
  279|  14.9k|               ++it;
  280|  14.9k|               break;
  281|  7.01k|            }
  282|    309|            [[unlikely]] default: {
  ------------------
  |  Branch (282:26): [True: 309, False: 36.8M]
  ------------------
  283|    309|               ctx.error = error_code::syntax_error;
  284|    309|               return;
  285|      0|            }
  286|  36.8M|            }
  287|  36.8M|         }
  288|  1.92k|      }
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clINS8_17basic_string_viewIcSB_EEEEDaSS_:
   73|   113k|         const auto put = [&](const auto& x) {
   74|   113k|            if constexpr (Opts.comments) {
   75|   113k|               if (line_comment_open) [[unlikely]] {
  ------------------
  |  Branch (75:20): [True: 1.64k, False: 111k]
  ------------------
   76|  1.64k|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (76:23): [True: 0, False: 1.64k]
  ------------------
   77|      0|                     return false;
   78|      0|                  }
   79|  1.64k|               }
   80|   113k|            }
   81|   113k|            return emit_bytes<true>(ctx, b, ix, x);
   82|   113k|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIcEEDaSS_:
   73|  36.6M|         const auto put = [&](const auto& x) {
   74|  36.6M|            if constexpr (Opts.comments) {
   75|  36.6M|               if (line_comment_open) [[unlikely]] {
  ------------------
  |  Branch (75:20): [True: 1.26k, False: 36.6M]
  ------------------
   76|  1.26k|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (76:23): [True: 0, False: 1.26k]
  ------------------
   77|      0|                     return false;
   78|      0|                  }
   79|  1.26k|               }
   80|  36.6M|            }
   81|  36.6M|            return emit_bytes<true>(ctx, b, ix, x);
   82|  36.6M|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlvE_clEv:
   47|  36.6M|         const auto new_line = [&] {
   48|       |            if constexpr (has_bounded_capacity<decltype(b)>) {
   49|       |               const size_t n = use_tabs ? size_t(indent) : size_t(indent) * indent_width;
   50|       |               if (not ensure_space(ctx, b, ix + 1 + n)) [[unlikely]] {
   51|       |                  return false;
   52|       |               }
   53|       |            }
   54|  36.6M|            append_new_line<use_tabs, indent_width>(b, ix, indent);
   55|  36.6M|            if constexpr (Opts.comments) {
   56|  36.6M|               line_comment_open = false;
   57|  36.6M|            }
   58|  36.6M|            return true;
   59|  36.6M|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlNS0_9json_typeEE_clESQ_:
   29|   219k|         const auto open_level = [&](const json_type type) {
   30|   219k|            if (size_t(indent) >= max_recursive_depth_limit) [[unlikely]] {
  ------------------
  |  Branch (30:17): [True: 28, False: 219k]
  ------------------
   31|     28|               ctx.error = error_code::exceeded_max_recursive_depth;
   32|     28|               return false;
   33|     28|            }
   34|   219k|            state[++indent] = type;
   35|   219k|            return true;
   36|   219k|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIA5_cEEDaSS_:
   73|  5.37k|         const auto put = [&](const auto& x) {
   74|  5.37k|            if constexpr (Opts.comments) {
   75|  5.37k|               if (line_comment_open) [[unlikely]] {
  ------------------
  |  Branch (75:20): [True: 2.92k, False: 2.45k]
  ------------------
   76|  2.92k|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (76:23): [True: 0, False: 2.92k]
  ------------------
   77|      0|                     return false;
   78|      0|                  }
   79|  2.92k|               }
   80|  5.37k|            }
   81|  5.37k|            return emit_bytes<true>(ctx, b, ix, x);
   82|  5.37k|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIA6_cEEDaSS_:
   73|  1.23k|         const auto put = [&](const auto& x) {
   74|  1.23k|            if constexpr (Opts.comments) {
   75|  1.23k|               if (line_comment_open) [[unlikely]] {
  ------------------
  |  Branch (75:20): [True: 239, False: 999]
  ------------------
   76|    239|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (76:23): [True: 0, False: 239]
  ------------------
   77|      0|                     return false;
   78|      0|                  }
   79|    239|               }
   80|  1.23k|            }
   81|  1.23k|            return emit_bytes<true>(ctx, b, ix, x);
   82|  1.23k|         };

_ZN3glz9has_quoteEm:
   86|  2.22M|   {
   87|  2.22M|      return has_zero(chunk ^ repeat_byte8('"'));
   88|  2.22M|   }
_ZN3glz8has_zeroEm:
   81|  3.29M|   {
   82|  3.29M|      return (((chunk - 0x0101010101010101ull) & ~chunk) & 0x8080808080808080ull);
   83|  3.29M|   }
_ZN3glz11countr_zeroEm:
   29|   466k|   {
   30|       |#ifdef _MSC_VER
   31|       |      return std::countr_zero(x);
   32|       |#else
   33|   466k|#if __has_builtin(__builtin_ctzll)
   34|   466k|      return __builtin_ctzll(x);
   35|       |#else
   36|       |      return std::countr_zero(x);
   37|       |#endif
   38|   466k|#endif
   39|   466k|   }
_ZN3glz8has_charILc47EEEmm:
  102|  1.06M|   {
  103|  1.06M|      return has_zero(chunk ^ repeat_byte8(Char));
  104|  1.06M|   }

_ZN3glz10comparitorIL_ZZNS_6detail13match_literalITnNS_14string_literalEXtlNS3_ILm5EEEtlA5_cLc110ELc117ELc108ELc108EEEETkNS_10is_contextERNS_7contextERPKcS9_EEbOT0_OT1_T2_E1sELm4EcEEbPKSD_:
  245|  6.17k|   {
  246|       |      // pack() builds values in little-endian order (byte 0 in LSB position).
  247|       |      // On big-endian systems, memcpy produces native (big-endian) values,
  248|       |      // so we need to byteswap to match the packed representation.
  249|       |      if constexpr (N == 8) {
  250|       |         static constexpr auto packed = pack<Str, 8>();
  251|       |         uint64_t in;
  252|       |         std::memcpy(&in, other, 8);
  253|       |         if constexpr (std::endian::native == std::endian::big) {
  254|       |            in = std::byteswap(in);
  255|       |         }
  256|       |         return (in == packed);
  257|       |      }
  258|       |      else if constexpr (N == 7) {
  259|       |         static constexpr auto packed = pack_buffered<Str, 8>();
  260|       |         uint64_t in{};
  261|       |         std::memcpy(&in, other, 7);
  262|       |         if constexpr (std::endian::native == std::endian::big) {
  263|       |            in = std::byteswap(in);
  264|       |         }
  265|       |         return (in == packed);
  266|       |      }
  267|       |      else if constexpr (N == 6) {
  268|       |         static constexpr auto packed = pack_buffered<Str, 8>();
  269|       |         uint64_t in{};
  270|       |         std::memcpy(&in, other, 6);
  271|       |         if constexpr (std::endian::native == std::endian::big) {
  272|       |            in = std::byteswap(in);
  273|       |         }
  274|       |         return (in == packed);
  275|       |      }
  276|       |      else if constexpr (N == 5) {
  277|       |         static constexpr auto packed = pack<Str, 4>();
  278|       |         uint32_t in;
  279|       |         std::memcpy(&in, other, 4);
  280|       |         if constexpr (std::endian::native == std::endian::big) {
  281|       |            in = std::byteswap(in);
  282|       |         }
  283|       |         return (in == packed) & (Str[4] == other[4]);
  284|       |      }
  285|  6.17k|      else if constexpr (N == 4) {
  286|  6.17k|         static constexpr auto packed = pack<Str, 4>();
  287|  6.17k|         uint32_t in;
  288|  6.17k|         std::memcpy(&in, other, 4);
  289|       |         if constexpr (std::endian::native == std::endian::big) {
  290|       |            in = std::byteswap(in);
  291|       |         }
  292|  6.17k|         return (in == packed);
  293|       |      }
  294|       |      else if constexpr (N == 3) {
  295|       |         static constexpr auto packed = pack<Str, 2>();
  296|       |         uint16_t in;
  297|       |         std::memcpy(&in, other, 2);
  298|       |         if constexpr (std::endian::native == std::endian::big) {
  299|       |            in = std::byteswap(in);
  300|       |         }
  301|       |         return (in == packed) & (Str[2] == other[2]);
  302|       |      }
  303|       |      else if constexpr (N == 2) {
  304|       |         static constexpr auto packed = pack<Str, 2>();
  305|       |         uint16_t in;
  306|       |         std::memcpy(&in, other, 2);
  307|       |         if constexpr (std::endian::native == std::endian::big) {
  308|       |            in = std::byteswap(in);
  309|       |         }
  310|       |         return (in == packed);
  311|       |      }
  312|       |      else if constexpr (N == 1) {
  313|       |         return Str[0] == other[0];
  314|       |      }
  315|       |      else if constexpr (N == 0) {
  316|       |         return true;
  317|       |      }
  318|       |      else {
  319|       |         // Clang and GCC optimize this extremely well for constexpr std::string_view
  320|       |         // Packing data can create more binary on GCC
  321|       |         // The other cases probably aren't needed as compiler explorer shows them optimized equally well as memcmp
  322|       |         return 0 == std::memcmp(Str.data(), other, N);
  323|       |      }
  324|  6.17k|   }
_ZN3glz10comparitorIL_ZZNS_6detail13match_literalITnNS_14string_literalEXtlNS3_ILm5EEEtlA5_cLc116ELc114ELc117ELc101EEEETkNS_10is_contextERNS_7contextERPKcS9_EEbOT0_OT1_T2_E1sELm4EcEEbPKSD_:
  245|  9.98k|   {
  246|       |      // pack() builds values in little-endian order (byte 0 in LSB position).
  247|       |      // On big-endian systems, memcpy produces native (big-endian) values,
  248|       |      // so we need to byteswap to match the packed representation.
  249|       |      if constexpr (N == 8) {
  250|       |         static constexpr auto packed = pack<Str, 8>();
  251|       |         uint64_t in;
  252|       |         std::memcpy(&in, other, 8);
  253|       |         if constexpr (std::endian::native == std::endian::big) {
  254|       |            in = std::byteswap(in);
  255|       |         }
  256|       |         return (in == packed);
  257|       |      }
  258|       |      else if constexpr (N == 7) {
  259|       |         static constexpr auto packed = pack_buffered<Str, 8>();
  260|       |         uint64_t in{};
  261|       |         std::memcpy(&in, other, 7);
  262|       |         if constexpr (std::endian::native == std::endian::big) {
  263|       |            in = std::byteswap(in);
  264|       |         }
  265|       |         return (in == packed);
  266|       |      }
  267|       |      else if constexpr (N == 6) {
  268|       |         static constexpr auto packed = pack_buffered<Str, 8>();
  269|       |         uint64_t in{};
  270|       |         std::memcpy(&in, other, 6);
  271|       |         if constexpr (std::endian::native == std::endian::big) {
  272|       |            in = std::byteswap(in);
  273|       |         }
  274|       |         return (in == packed);
  275|       |      }
  276|       |      else if constexpr (N == 5) {
  277|       |         static constexpr auto packed = pack<Str, 4>();
  278|       |         uint32_t in;
  279|       |         std::memcpy(&in, other, 4);
  280|       |         if constexpr (std::endian::native == std::endian::big) {
  281|       |            in = std::byteswap(in);
  282|       |         }
  283|       |         return (in == packed) & (Str[4] == other[4]);
  284|       |      }
  285|  9.98k|      else if constexpr (N == 4) {
  286|  9.98k|         static constexpr auto packed = pack<Str, 4>();
  287|  9.98k|         uint32_t in;
  288|  9.98k|         std::memcpy(&in, other, 4);
  289|       |         if constexpr (std::endian::native == std::endian::big) {
  290|       |            in = std::byteswap(in);
  291|       |         }
  292|  9.98k|         return (in == packed);
  293|       |      }
  294|       |      else if constexpr (N == 3) {
  295|       |         static constexpr auto packed = pack<Str, 2>();
  296|       |         uint16_t in;
  297|       |         std::memcpy(&in, other, 2);
  298|       |         if constexpr (std::endian::native == std::endian::big) {
  299|       |            in = std::byteswap(in);
  300|       |         }
  301|       |         return (in == packed) & (Str[2] == other[2]);
  302|       |      }
  303|       |      else if constexpr (N == 2) {
  304|       |         static constexpr auto packed = pack<Str, 2>();
  305|       |         uint16_t in;
  306|       |         std::memcpy(&in, other, 2);
  307|       |         if constexpr (std::endian::native == std::endian::big) {
  308|       |            in = std::byteswap(in);
  309|       |         }
  310|       |         return (in == packed);
  311|       |      }
  312|       |      else if constexpr (N == 1) {
  313|       |         return Str[0] == other[0];
  314|       |      }
  315|       |      else if constexpr (N == 0) {
  316|       |         return true;
  317|       |      }
  318|       |      else {
  319|       |         // Clang and GCC optimize this extremely well for constexpr std::string_view
  320|       |         // Packing data can create more binary on GCC
  321|       |         // The other cases probably aren't needed as compiler explorer shows them optimized equally well as memcmp
  322|       |         return 0 == std::memcmp(Str.data(), other, N);
  323|       |      }
  324|  9.98k|   }
_ZN3glz10comparitorIL_ZZNS_6detail13match_literalITnNS_14string_literalEXtlNS3_ILm6EEEtlA6_cLc102ELc97ELc108ELc115ELc101EEEETkNS_10is_contextERNS_7contextERPKcS9_EEbOT0_OT1_T2_E1sELm5EcEEbPKSD_:
  245|  4.71k|   {
  246|       |      // pack() builds values in little-endian order (byte 0 in LSB position).
  247|       |      // On big-endian systems, memcpy produces native (big-endian) values,
  248|       |      // so we need to byteswap to match the packed representation.
  249|       |      if constexpr (N == 8) {
  250|       |         static constexpr auto packed = pack<Str, 8>();
  251|       |         uint64_t in;
  252|       |         std::memcpy(&in, other, 8);
  253|       |         if constexpr (std::endian::native == std::endian::big) {
  254|       |            in = std::byteswap(in);
  255|       |         }
  256|       |         return (in == packed);
  257|       |      }
  258|       |      else if constexpr (N == 7) {
  259|       |         static constexpr auto packed = pack_buffered<Str, 8>();
  260|       |         uint64_t in{};
  261|       |         std::memcpy(&in, other, 7);
  262|       |         if constexpr (std::endian::native == std::endian::big) {
  263|       |            in = std::byteswap(in);
  264|       |         }
  265|       |         return (in == packed);
  266|       |      }
  267|       |      else if constexpr (N == 6) {
  268|       |         static constexpr auto packed = pack_buffered<Str, 8>();
  269|       |         uint64_t in{};
  270|       |         std::memcpy(&in, other, 6);
  271|       |         if constexpr (std::endian::native == std::endian::big) {
  272|       |            in = std::byteswap(in);
  273|       |         }
  274|       |         return (in == packed);
  275|       |      }
  276|  4.71k|      else if constexpr (N == 5) {
  277|  4.71k|         static constexpr auto packed = pack<Str, 4>();
  278|  4.71k|         uint32_t in;
  279|  4.71k|         std::memcpy(&in, other, 4);
  280|       |         if constexpr (std::endian::native == std::endian::big) {
  281|       |            in = std::byteswap(in);
  282|       |         }
  283|  4.71k|         return (in == packed) & (Str[4] == other[4]);
  284|       |      }
  285|       |      else if constexpr (N == 4) {
  286|       |         static constexpr auto packed = pack<Str, 4>();
  287|       |         uint32_t in;
  288|       |         std::memcpy(&in, other, 4);
  289|       |         if constexpr (std::endian::native == std::endian::big) {
  290|       |            in = std::byteswap(in);
  291|       |         }
  292|       |         return (in == packed);
  293|       |      }
  294|       |      else if constexpr (N == 3) {
  295|       |         static constexpr auto packed = pack<Str, 2>();
  296|       |         uint16_t in;
  297|       |         std::memcpy(&in, other, 2);
  298|       |         if constexpr (std::endian::native == std::endian::big) {
  299|       |            in = std::byteswap(in);
  300|       |         }
  301|       |         return (in == packed) & (Str[2] == other[2]);
  302|       |      }
  303|       |      else if constexpr (N == 2) {
  304|       |         static constexpr auto packed = pack<Str, 2>();
  305|       |         uint16_t in;
  306|       |         std::memcpy(&in, other, 2);
  307|       |         if constexpr (std::endian::native == std::endian::big) {
  308|       |            in = std::byteswap(in);
  309|       |         }
  310|       |         return (in == packed);
  311|       |      }
  312|       |      else if constexpr (N == 1) {
  313|       |         return Str[0] == other[0];
  314|       |      }
  315|       |      else if constexpr (N == 0) {
  316|       |         return true;
  317|       |      }
  318|       |      else {
  319|       |         // Clang and GCC optimize this extremely well for constexpr std::string_view
  320|       |         // Packing data can create more binary on GCC
  321|       |         // The other cases probably aren't needed as compiler explorer shows them optimized equally well as memcmp
  322|       |         return 0 == std::memcmp(Str.data(), other, N);
  323|       |      }
  324|  4.71k|   }

_ZN3glz4dumpILb1ENSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEEvNS1_17basic_string_viewIcS4_EERT0_Rm:
  192|   391k|   {
  193|   391k|      const auto n = str.size();
  194|   391k|      if constexpr (vector_like<B>) {
  195|   391k|         if constexpr (Checked) {
  196|   391k|            const auto k = ix + n;
  197|   391k|            if (ix + n > b.size()) [[unlikely]] {
  ------------------
  |  Branch (197:17): [True: 685, False: 390k]
  ------------------
  198|    685|               grow_buffer(b, k);
  199|    685|            }
  200|   391k|         }
  201|   391k|      }
  202|   391k|      std::memcpy(&b[ix], str.data(), n);
  203|   391k|      ix += n;
  204|   391k|   }
_ZN3glz4dumpILb1ENSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEETkNS_10byte_sizedEcEEvT1_RT0_Rm:
  150|   243M|   {
  151|   243M|      if constexpr (Checked && vector_like<B>) {
  152|   243M|         if (ix == b.size()) [[unlikely]] {
  ------------------
  |  Branch (152:14): [True: 2.17k, False: 243M]
  ------------------
  153|  2.17k|            grow_buffer(b, b.size() == 0 ? 64 : ix + 1);
  ------------------
  |  Branch (153:28): [True: 0, False: 2.17k]
  ------------------
  154|  2.17k|         }
  155|   243M|      }
  156|   243M|      assign_maybe_cast(c, b, ix);
  157|   243M|      ++ix;
  158|   243M|   }
_ZN3glz17assign_maybe_castITkNS_10byte_sizedEcNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEEvT_RT0_Rm:
   95|   243M|   {
   96|   243M|      using V = std::decay_t<decltype(b[0])>;
   97|   243M|      using C = std::decay_t<decltype(c)>;
   98|   243M|      if constexpr (std::same_as<V, C>) {
   99|   243M|         b[ix] = c;
  100|       |      }
  101|       |      else {
  102|       |         b[ix] = static_cast<V>(c);
  103|       |      }
  104|   243M|   }
_ZN3glz5dumpnINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEETkNS_10byte_sizedEcEEvT0_mRT_Rm:
  222|   121M|   {
  223|   121M|      if constexpr (vector_like<B>) {
  224|   121M|         const auto k = ix + n;
  225|   121M|         if (k > b.size()) [[unlikely]] {
  ------------------
  |  Branch (225:14): [True: 17.5k, False: 121M]
  ------------------
  226|  17.5k|            grow_buffer(b, k);
  227|  17.5k|         }
  228|   121M|      }
  229|   121M|      fill_bytes(data_at(b, ix), c, n);
  230|   121M|      ix += n;
  231|   121M|   }
_ZN3glz10fill_bytesIcEEvPT_cm:
   54|   121M|   {
   55|   121M|      auto* p = reinterpret_cast<char*>(dst);
   56|   121M|      if (n >= 64) [[unlikely]] {
  ------------------
  |  Branch (56:11): [True: 121M, False: 528k]
  ------------------
   57|   121M|         std::memset(p, c, n);
   58|   121M|         return;
   59|   121M|      }
   60|   528k|      const uint64_t v = 0x0101010101010101ull * uint8_t(c);
   61|   528k|      if (n >= 8) {
  ------------------
  |  Branch (61:11): [True: 151k, False: 376k]
  ------------------
   62|   151k|         size_t i = 0;
   63|   751k|         for (; i + 8 <= n; i += 8) {
  ------------------
  |  Branch (63:17): [True: 600k, False: 151k]
  ------------------
   64|   600k|            std::memcpy(p + i, &v, 8);
   65|   600k|         }
   66|   151k|         if (i < n) {
  ------------------
  |  Branch (66:14): [True: 134k, False: 17.1k]
  ------------------
   67|   134k|            std::memcpy(p + n - 8, &v, 8); // overlaps what is already written, stays within n
   68|   134k|         }
   69|   151k|      }
   70|   376k|      else if (n >= 4) {
  ------------------
  |  Branch (70:16): [True: 10.3k, False: 366k]
  ------------------
   71|  10.3k|         std::memcpy(p, &v, 4);
   72|  10.3k|         std::memcpy(p + n - 4, &v, 4);
   73|  10.3k|      }
   74|   366k|      else if (n) {
  ------------------
  |  Branch (74:16): [True: 28.0k, False: 338k]
  ------------------
   75|  28.0k|         std::memcpy(p, &v, 1);
   76|  28.0k|         std::memcpy(p + (n >> 1), &v, 1);
   77|  28.0k|         std::memcpy(p + n - 1, &v, 1);
   78|  28.0k|      }
   79|   528k|   }
_ZN3glz7data_atINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEEDaRT_m:
  117|   121M|   {
  118|       |      if constexpr (std::is_pointer_v<std::remove_cvref_t<B>>) {
  119|       |         return b + ix;
  120|       |      }
  121|   121M|      else {
  122|   121M|         static_assert(has_data<std::remove_cvref_t<B>>,
  123|   121M|                       "an output buffer must be contiguous: dump writes through memset and memcpy");
  124|       |         if constexpr (has_data_offset<std::remove_cvref_t<B>>) {
  125|       |            assert(ix >= b.data_offset() && "Index before flush offset");
  126|       |            return b.data() + (ix - b.data_offset());
  127|       |         }
  128|   121M|         else {
  129|   121M|            return b.data() + ix;
  130|   121M|         }
  131|   121M|      }
  132|   121M|   }

