LLVMFuzzerTestOneInput:
    8|  1.94k|{
    9|       |   // use a vector with null termination instead of a std::string to avoid
   10|       |   // small string optimization to hide bounds problems
   11|  1.94k|   std::vector<char> buffer{Data, Data + Size};
   12|       |
   13|       |   // non-null terminated
   14|  1.94k|   {
   15|  1.94k|      const auto& input = buffer;
   16|  1.94k|      [[maybe_unused]] auto beautiful = glz::prettify_json(input);
   17|  1.94k|   }
   18|       |
   19|       |   // null terminated
   20|  1.94k|   {
   21|  1.94k|      buffer.push_back('\0');
   22|  1.94k|      const auto& input = buffer;
   23|  1.94k|      [[maybe_unused]] auto beautiful = glz::prettify_json(input);
   24|  1.94k|   }
   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.94k|   {
   31|  1.94k|      const std::vector<char> jsonc{Data, Data + Size};
   32|  1.94k|      [[maybe_unused]] auto beautiful = glz::prettify_jsonc(jsonc);
   33|  1.94k|   }
   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.94k|   {
   38|  1.94k|      const std::string jsonc{Data, Data + Size};
   39|  1.94k|      [[maybe_unused]] auto beautiful = glz::prettify_jsonc(jsonc);
   40|  1.94k|   }
   41|       |
   42|  1.94k|   return 0;
   43|  1.94k|}

_ZN3glz11grow_bufferINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEEvRT_m:
  143|  19.8k|   {
  144|  19.8k|      using traits = buffer_traits<std::remove_cvref_t<B>>;
  145|  19.8k|      if constexpr (requires { traits::grow(b, required); }) {
  146|  19.8k|         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|  19.8k|   }
_ZN3glz13buffer_traitsINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEE4growERS7_mQL_ZNS_13buffer_traits12is_resizableEE:
  118|  19.8k|      {
  119|  19.8k|         resize_unfilled(b, 2 * required);
  120|  19.8k|      }
_ZN3glz15resize_unfilledINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEEvRT_m:
   63|  19.8k|   {
   64|  19.8k|      if constexpr (requires { b.resize_and_overwrite(n, [](auto*, size_t written) { return written; }); }) {
   65|  19.8k|         b.resize_and_overwrite(n, [](auto*, size_t written) noexcept { return written; });
   66|       |      }
   67|       |      else {
   68|       |         b.resize(n);
   69|       |      }
   70|  19.8k|   }
_ZZN3glz15resize_unfilledINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEEvRT_mENKUlPS8_mE_clIcEEDaSA_m:
   65|  19.8k|         b.resize_and_overwrite(n, [](auto*, size_t written) noexcept { return written; });

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

_ZN3glz6detail16read_json_stringITkNS_10is_contextERNS_7contextERPKcS5_EENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEOT_OT0_T1_:
  156|   338k|   {
  157|   338k|      auto start = it;
  158|   338k|      ++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|   338k|      const auto* const chunk_limit = (end - it >= 8) ? end - 8 : it - 1;
  ------------------
  |  Branch (162:39): [True: 337k, False: 716]
  ------------------
  163|  2.41M|      while (it <= chunk_limit) {
  ------------------
  |  Branch (163:14): [True: 2.41M, False: 867]
  ------------------
  164|  2.41M|         uint64_t chunk;
  165|  2.41M|         std::memcpy(&chunk, it, 8);
  166|       |         if constexpr (std::endian::native == std::endian::big) {
  167|       |            chunk = std::byteswap(chunk);
  168|       |         }
  169|  2.41M|         const uint64_t quote = has_quote(chunk);
  170|  2.41M|         if (quote) {
  ------------------
  |  Branch (170:14): [True: 337k, False: 2.07M]
  ------------------
  171|   337k|            it += (countr_zero(quote) >> 3);
  172|       |
  173|   337k|            auto* prev = it - 1;
  174|   338k|            while (*prev == '\\') {
  ------------------
  |  Branch (174:20): [True: 1.04k, False: 337k]
  ------------------
  175|  1.04k|               --prev;
  176|  1.04k|            }
  177|   337k|            if (size_t(it - prev) % 2) {
  ------------------
  |  Branch (177:17): [True: 337k, False: 671]
  ------------------
  178|   337k|               ++it; // add quote
  179|   337k|               return {start, size_t(it - start)};
  180|   337k|            }
  181|    671|            ++it; // skip escaped quote and continue
  182|    671|         }
  183|  2.07M|         else {
  184|  2.07M|            it += 8;
  185|  2.07M|         }
  186|  2.41M|      }
  187|       |
  188|  1.76k|      while (it < end) {
  ------------------
  |  Branch (188:14): [True: 1.51k, False: 252]
  ------------------
  189|  1.51k|         if (*it == '"') {
  ------------------
  |  Branch (189:14): [True: 686, False: 827]
  ------------------
  190|    686|            auto* prev = it - 1;
  191|  1.63k|            while (*prev == '\\') {
  ------------------
  |  Branch (191:20): [True: 949, False: 686]
  ------------------
  192|    949|               --prev;
  193|    949|            }
  194|    686|            if (size_t(it - prev) % 2) {
  ------------------
  |  Branch (194:17): [True: 615, False: 71]
  ------------------
  195|    615|               ++it; // add quote
  196|    615|               return {start, size_t(it - start)};
  197|    615|            }
  198|    686|         }
  199|    898|         ++it;
  200|    898|      }
  201|       |
  202|    252|      ctx.error = error_code::unexpected_end;
  203|    252|      return {};
  204|    867|   }
_ZN3glz6detail10emit_bytesILb1ENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEETkNS_10is_contextENS_7contextENS2_17basic_string_viewIcS5_EEEEbRT1_RT0_RmRKT2_:
   91|   486k|   {
   92|   486k|      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|   486k|      else {
  102|   486k|         const sv s = [&] {
  103|   486k|            if constexpr (std::is_bounded_array_v<T>) {
  104|   486k|               return sv{x, std::extent_v<T> - 1}; // a string literal, without its terminator
  105|   486k|            }
  106|   486k|            else {
  107|   486k|               return sv{x};
  108|   486k|            }
  109|   486k|         }();
  110|       |         if constexpr (has_bounded_capacity<B>) {
  111|       |            if (not ensure_space(ctx, b, ix + s.size())) [[unlikely]] {
  112|       |               return false;
  113|       |            }
  114|       |         }
  115|   486k|         dump<Checked>(s, b, ix);
  116|   486k|      }
  117|   486k|      return true;
  118|   486k|   }
_ZZN3glz6detail10emit_bytesILb1ENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEETkNS_10is_contextENS_7contextENS2_17basic_string_viewIcS5_EEEEbRT1_RT0_RmRKT2_ENKUlvE_clEv:
  102|   486k|         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|   486k|            else {
  107|   486k|               return sv{x};
  108|   486k|            }
  109|   486k|         }();
_ZN3glz6detail10emit_bytesILb1ENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEETkNS_10is_contextENS_7contextEcEEbRT1_RT0_RmRKT2_:
   91|   126M|   {
   92|   126M|      using T = std::remove_cvref_t<decltype(x)>;
   93|   126M|      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|   126M|         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|   126M|      return true;
  118|   126M|   }
_ZN3glz6detail15append_new_lineILb0ELh3ERNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEERmEEvOT1_OT2_l:
   63|   126M|   {
   64|   126M|      dump('\n', b, ix);
   65|       |      if constexpr (use_tabs) {
   66|       |         dumpn('\t', indent, b, ix);
   67|       |      }
   68|   126M|      else {
   69|   126M|         dumpn(' ', indent * indentation_width, b, ix);
   70|   126M|      }
   71|   126M|   };
_ZN3glz6detail16read_json_numberILb0ERPKcS3_EENSt3__117basic_string_viewIcNS5_11char_traitsIcEEEEOT0_T1_:
  304|  56.2k|   {
  305|  56.2k|      auto start = it;
  306|       |      if constexpr (null_terminated) {
  307|       |         while (numeric_table[uint8_t(*it)]) {
  308|       |            ++it;
  309|       |         }
  310|       |      }
  311|  56.2k|      else {
  312|  2.80M|         while ((it < end) && numeric_table[uint8_t(*it)]) {
  ------------------
  |  Branch (312:17): [True: 2.80M, False: 147]
  |  Branch (312:31): [True: 2.74M, False: 56.0k]
  ------------------
  313|  2.74M|            ++it;
  314|  2.74M|         }
  315|  56.2k|      }
  316|  56.2k|      return {start, size_t(it - start)};
  317|  56.2k|   }
_ZN3glz6detail13match_literalITnNS_14string_literalEXtlNS2_ILm5EEEtlA5_cLc110ELc117ELc108ELc108EEEETkNS_10is_contextERNS_7contextERPKcS8_EEbOT0_OT1_T2_:
  130|  6.67k|   {
  131|  6.67k|      static constexpr auto s = literal.sv();
  132|  6.67k|      if (end - it < std::ptrdiff_t(s.size())) [[unlikely]] {
  ------------------
  |  Branch (132:11): [True: 65, False: 6.60k]
  ------------------
  133|     65|         ctx.error = error_code::unexpected_end;
  134|     65|         return false;
  135|     65|      }
  136|  6.60k|      if (not comparitor<s>(it)) [[unlikely]] {
  ------------------
  |  Branch (136:11): [True: 337, False: 6.27k]
  ------------------
  137|    337|         ctx.error = error_code::syntax_error;
  138|    337|         return false;
  139|    337|      }
  140|  6.27k|      it += s.size();
  141|  6.27k|      return true;
  142|  6.60k|   }
_ZN3glz6detail10emit_bytesILb1ENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEETkNS_10is_contextENS_7contextEA5_cEEbRT1_RT0_RmRKT2_:
   91|  17.7k|   {
   92|  17.7k|      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|  17.7k|      else {
  102|  17.7k|         const sv s = [&] {
  103|  17.7k|            if constexpr (std::is_bounded_array_v<T>) {
  104|  17.7k|               return sv{x, std::extent_v<T> - 1}; // a string literal, without its terminator
  105|  17.7k|            }
  106|  17.7k|            else {
  107|  17.7k|               return sv{x};
  108|  17.7k|            }
  109|  17.7k|         }();
  110|       |         if constexpr (has_bounded_capacity<B>) {
  111|       |            if (not ensure_space(ctx, b, ix + s.size())) [[unlikely]] {
  112|       |               return false;
  113|       |            }
  114|       |         }
  115|  17.7k|         dump<Checked>(s, b, ix);
  116|  17.7k|      }
  117|  17.7k|      return true;
  118|  17.7k|   }
_ZZN3glz6detail10emit_bytesILb1ENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEETkNS_10is_contextENS_7contextEA5_cEEbRT1_RT0_RmRKT2_ENKUlvE_clEv:
  102|  17.7k|         const sv s = [&] {
  103|  17.7k|            if constexpr (std::is_bounded_array_v<T>) {
  104|  17.7k|               return sv{x, std::extent_v<T> - 1}; // a string literal, without its terminator
  105|       |            }
  106|       |            else {
  107|       |               return sv{x};
  108|       |            }
  109|  17.7k|         }();
_ZN3glz6detail13match_literalITnNS_14string_literalEXtlNS2_ILm5EEEtlA5_cLc116ELc114ELc117ELc101EEEETkNS_10is_contextERNS_7contextERPKcS8_EEbOT0_OT1_T2_:
  130|  11.9k|   {
  131|  11.9k|      static constexpr auto s = literal.sv();
  132|  11.9k|      if (end - it < std::ptrdiff_t(s.size())) [[unlikely]] {
  ------------------
  |  Branch (132:11): [True: 79, False: 11.8k]
  ------------------
  133|     79|         ctx.error = error_code::unexpected_end;
  134|     79|         return false;
  135|     79|      }
  136|  11.8k|      if (not comparitor<s>(it)) [[unlikely]] {
  ------------------
  |  Branch (136:11): [True: 305, False: 11.5k]
  ------------------
  137|    305|         ctx.error = error_code::syntax_error;
  138|    305|         return false;
  139|    305|      }
  140|  11.5k|      it += s.size();
  141|  11.5k|      return true;
  142|  11.8k|   }
_ZN3glz6detail13match_literalITnNS_14string_literalEXtlNS2_ILm6EEEtlA6_cLc102ELc97ELc108ELc115ELc101EEEETkNS_10is_contextERNS_7contextERPKcS8_EEbOT0_OT1_T2_:
  130|  4.97k|   {
  131|  4.97k|      static constexpr auto s = literal.sv();
  132|  4.97k|      if (end - it < std::ptrdiff_t(s.size())) [[unlikely]] {
  ------------------
  |  Branch (132:11): [True: 132, False: 4.84k]
  ------------------
  133|    132|         ctx.error = error_code::unexpected_end;
  134|    132|         return false;
  135|    132|      }
  136|  4.84k|      if (not comparitor<s>(it)) [[unlikely]] {
  ------------------
  |  Branch (136:11): [True: 430, False: 4.41k]
  ------------------
  137|    430|         ctx.error = error_code::syntax_error;
  138|    430|         return false;
  139|    430|      }
  140|  4.41k|      it += s.size();
  141|  4.41k|      return true;
  142|  4.84k|   }
_ZN3glz6detail10emit_bytesILb1ENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEETkNS_10is_contextENS_7contextEA6_cEEbRT1_RT0_RmRKT2_:
   91|  4.41k|   {
   92|  4.41k|      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.41k|      else {
  102|  4.41k|         const sv s = [&] {
  103|  4.41k|            if constexpr (std::is_bounded_array_v<T>) {
  104|  4.41k|               return sv{x, std::extent_v<T> - 1}; // a string literal, without its terminator
  105|  4.41k|            }
  106|  4.41k|            else {
  107|  4.41k|               return sv{x};
  108|  4.41k|            }
  109|  4.41k|         }();
  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.41k|         dump<Checked>(s, b, ix);
  116|  4.41k|      }
  117|  4.41k|      return true;
  118|  4.41k|   }
_ZZN3glz6detail10emit_bytesILb1ENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEETkNS_10is_contextENS_7contextEA6_cEEbRT1_RT0_RmRKT2_ENKUlvE_clEv:
  102|  4.41k|         const sv s = [&] {
  103|  4.41k|            if constexpr (std::is_bounded_array_v<T>) {
  104|  4.41k|               return sv{x, std::extent_v<T> - 1}; // a string literal, without its terminator
  105|       |            }
  106|       |            else {
  107|       |               return sv{x};
  108|       |            }
  109|  4.41k|         }();
_ZN3glz6detail18read_jsonc_commentITkNS_10is_contextERNS_7contextERPKcS5_EENS0_13jsonc_commentEOT_OT0_T1_:
  227|  15.5k|   {
  228|  15.5k|      const auto start = it;
  229|  15.5k|      ++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|  15.5k|      if (it == end) [[unlikely]] {
  ------------------
  |  Branch (234:11): [True: 10, False: 15.4k]
  ------------------
  235|     10|         ctx.error = error_code::unexpected_end;
  236|     10|         return {};
  237|     10|      }
  238|       |
  239|  15.4k|      if (*it == '/') {
  ------------------
  |  Branch (239:11): [True: 13.9k, False: 1.58k]
  ------------------
  240|  13.9k|         ++it; // past the second '/'
  241|  3.45M|         while (it != end && *it != '\n' && *it != '\r') {
  ------------------
  |  Branch (241:17): [True: 3.45M, False: 150]
  |  Branch (241:30): [True: 3.45M, False: 2.30k]
  |  Branch (241:45): [True: 3.44M, False: 11.4k]
  ------------------
  242|  3.44M|            ++it;
  243|  3.44M|         }
  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|  13.9k|         return {sv{start, size_t(it - start)}, true};
  249|  13.9k|      }
  250|       |
  251|  1.58k|      if (*it != '*') [[unlikely]] {
  ------------------
  |  Branch (251:11): [True: 80, False: 1.50k]
  ------------------
  252|     80|         ctx.error = error_code::expected_end_comment;
  253|     80|         return {};
  254|     80|      }
  255|  1.50k|      ++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.50k|      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.50k|      const auto* const chunk_limit = (end - it >= 8) ? end - 8 : it - 1;
  ------------------
  |  Branch (266:39): [True: 1.40k, False: 98]
  ------------------
  267|   894k|      while (it <= chunk_limit) {
  ------------------
  |  Branch (267:14): [True: 894k, False: 270]
  ------------------
  268|   894k|         uint64_t chunk;
  269|   894k|         std::memcpy(&chunk, it, 8);
  270|       |         if constexpr (std::endian::native == std::endian::big) {
  271|       |            chunk = std::byteswap(chunk);
  272|       |         }
  273|   894k|         const uint64_t slash = has_char<'/'>(chunk);
  274|   894k|         if (slash) {
  ------------------
  |  Branch (274:14): [True: 180k, False: 714k]
  ------------------
  275|   180k|            it += (countr_zero(slash) >> 3);
  276|       |
  277|   180k|            if (it > content && it[-1] == '*') {
  ------------------
  |  Branch (277:17): [True: 179k, False: 706]
  |  Branch (277:33): [True: 1.23k, False: 178k]
  ------------------
  278|  1.23k|               ++it; // add slash
  279|  1.23k|               return {sv{start, size_t(it - start)}, false};
  280|  1.23k|            }
  281|       |            // skip slash and continue
  282|   179k|            ++it;
  283|   179k|         }
  284|   714k|         else {
  285|   714k|            it += 8;
  286|   714k|         }
  287|   894k|      }
  288|       |
  289|       |      // Tail end of buffer. Should be rare we even get here
  290|  1.19k|      while (it < end) {
  ------------------
  |  Branch (290:14): [True: 958, False: 238]
  ------------------
  291|    958|         if (it > content && it[-1] == '*' && *it == '/') {
  ------------------
  |  Branch (291:14): [True: 864, False: 94]
  |  Branch (291:30): [True: 110, False: 754]
  |  Branch (291:47): [True: 32, False: 78]
  ------------------
  292|     32|            ++it; // add slash
  293|     32|            return {sv{start, size_t(it - start)}, false};
  294|     32|         }
  295|    926|         ++it;
  296|    926|      }
  297|       |
  298|    238|      ctx.error = error_code::expected_end_comment;
  299|    238|      return {};
  300|    270|   }
_ZN3glz6detail16read_json_numberILb1ERPKcS3_EENSt3__117basic_string_viewIcNS5_11char_traitsIcEEEEOT0_T1_:
  304|  25.8k|   {
  305|  25.8k|      auto start = it;
  306|  25.8k|      if constexpr (null_terminated) {
  307|   950k|         while (numeric_table[uint8_t(*it)]) {
  ------------------
  |  Branch (307:17): [True: 924k, False: 25.8k]
  ------------------
  308|   924k|            ++it;
  309|   924k|         }
  310|       |      }
  311|       |      else {
  312|       |         while ((it < end) && numeric_table[uint8_t(*it)]) {
  313|       |            ++it;
  314|       |         }
  315|       |      }
  316|  25.8k|      return {start, size_t(it - start)};
  317|  25.8k|   }

_ZN3glz13prettify_jsonITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1EEENSt3__16vectorIcNS2_9allocatorIcEEEEEENS2_12basic_stringIcNS2_11char_traitsIcEES5_EERKT0_:
  350|  3.88k|   {
  351|  3.88k|      context ctx{};
  352|  3.88k|      std::string out{};
  353|  3.88k|      detail::prettify_json<Opts>(ctx, in, out);
  354|  3.88k|      if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (354:11): [True: 3.04k, False: 837]
  ------------------
  355|  3.04k|         return {}; // an incomplete result is not a document; see above
  356|  3.04k|      }
  357|    837|      return out;
  358|  3.88k|   }
_ZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1EEETkNS_10contiguousERKNSt3__16vectorIcNS3_9allocatorIcEEEETkNS_13output_bufferERNS3_12basic_stringIcNS3_11char_traitsIcEES6_EETkNS_10is_contextERNS_7contextEEEmOT2_OT0_OT1_:
  294|  3.88k|      {
  295|  3.88k|         if constexpr (resizable<Out>) {
  296|  3.88k|            if (in.size() == 0) {
  ------------------
  |  Branch (296:17): [True: 0, False: 3.88k]
  ------------------
  297|      0|               out.resize(0); // resize is what `resizable` promises; clear() is not
  298|      0|               return 0;
  299|      0|            }
  300|  3.88k|            out.resize(in.size() * 2);
  301|  3.88k|         }
  302|      0|         size_t ix = 0;
  303|  3.88k|         auto [it, end] = read_iterators<Opts>(in);
  304|  3.88k|         if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (304:14): [True: 0, False: 3.88k]
  ------------------
  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.88k|         else {
  312|  3.88k|            prettify_json<opt_false<Opts, &opts::null_terminated>>(ctx, it, end, out, ix);
  313|  3.88k|         }
  314|       |
  315|  3.88k|         if constexpr (resizable<Out>) {
  316|  3.88k|            out.resize(ix);
  317|  3.88k|         }
  318|  3.88k|         return ix;
  319|  3.88k|      }
_ZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_:
   17|  3.88k|      {
   18|  3.88k|         constexpr bool use_tabs = check_indentation_char(Opts) == '\t';
   19|  3.88k|         constexpr auto indent_width = check_indentation_width(Opts);
   20|       |
   21|  3.88k|         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.88k|         std::array<json_type, max_recursive_depth_limit + 1> state{};
   26|  3.88k|         int64_t indent{};
   27|       |
   28|       |         // Enters one level of nesting, failing past the readers' limit.
   29|  3.88k|         const auto open_level = [&](const json_type type) {
   30|  3.88k|            if (size_t(indent) >= max_recursive_depth_limit) [[unlikely]] {
   31|  3.88k|               ctx.error = error_code::exceeded_max_recursive_depth;
   32|  3.88k|               return false;
   33|  3.88k|            }
   34|  3.88k|            state[++indent] = type;
   35|  3.88k|            return true;
   36|  3.88k|         };
   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.88k|         [[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.88k|         const auto new_line = [&] {
   48|  3.88k|            if constexpr (has_bounded_capacity<decltype(b)>) {
   49|  3.88k|               const size_t n = use_tabs ? size_t(indent) : size_t(indent) * indent_width;
   50|  3.88k|               if (not ensure_space(ctx, b, ix + 1 + n)) [[unlikely]] {
   51|  3.88k|                  return false;
   52|  3.88k|               }
   53|  3.88k|            }
   54|  3.88k|            append_new_line<use_tabs, indent_width>(b, ix, indent);
   55|  3.88k|            if constexpr (Opts.comments) {
   56|  3.88k|               line_comment_open = false;
   57|  3.88k|            }
   58|  3.88k|            return true;
   59|  3.88k|         };
   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.88k|         const auto put = [&](const auto& x) {
   74|  3.88k|            if constexpr (Opts.comments) {
   75|  3.88k|               if (line_comment_open) [[unlikely]] {
   76|  3.88k|                  if (not new_line()) [[unlikely]] {
   77|  3.88k|                     return false;
   78|  3.88k|                  }
   79|  3.88k|               }
   80|  3.88k|            }
   81|  3.88k|            return emit_bytes<true>(ctx, b, ix, x);
   82|  3.88k|         };
   83|       |
   84|  45.8M|         while (it < end) {
  ------------------
  |  Branch (84:17): [True: 45.8M, False: 837]
  ------------------
   85|  45.8M|            switch (json_types[uint8_t(*it)]) {
   86|   123k|            case String: {
  ------------------
  |  Branch (86:13): [True: 123k, False: 45.7M]
  ------------------
   87|   123k|               const auto value = read_json_string(ctx, it, end);
   88|   123k|               if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (88:20): [True: 120, False: 123k]
  ------------------
   89|    120|                  return;
   90|    120|               }
   91|       |               // non-empty: the scanner reports an empty view as an error
   92|   123k|               if (not put(value)) [[unlikely]] {
  ------------------
  |  Branch (92:20): [True: 0, False: 123k]
  ------------------
   93|      0|                  return;
   94|      0|               }
   95|   123k|               break;
   96|   123k|            }
   97|  45.4M|            case Comma: {
  ------------------
  |  Branch (97:13): [True: 45.4M, False: 438k]
  ------------------
   98|  45.4M|               if (not put(',')) [[unlikely]] {
  ------------------
  |  Branch (98:20): [True: 0, False: 45.4M]
  ------------------
   99|      0|                  return;
  100|      0|               }
  101|  45.4M|               ++it;
  102|  45.4M|               if constexpr (check_new_lines_in_arrays(Opts)) {
  103|  45.4M|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (103:23): [True: 0, False: 45.4M]
  ------------------
  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|  45.4M|               break;
  118|  45.4M|            }
  119|  45.4M|            case Number: {
  ------------------
  |  Branch (119:13): [True: 30.4k, False: 45.8M]
  ------------------
  120|  30.4k|               const auto value = read_json_number<Opts.null_terminated>(it, end);
  121|       |               // non-empty: a Number match is one valid character
  122|  30.4k|               if (not put(value)) [[unlikely]] {
  ------------------
  |  Branch (122:20): [True: 0, False: 30.4k]
  ------------------
  123|      0|                  return;
  124|      0|               }
  125|  30.4k|               break;
  126|  30.4k|            }
  127|  30.4k|            case Colon: {
  ------------------
  |  Branch (127:13): [True: 20.4k, False: 45.8M]
  ------------------
  128|  20.4k|               static constexpr sv colon = use_tabs ? sv{":\t"} : sv{": "};
  ------------------
  |  Branch (128:44): [Folded, False: 20.4k]
  ------------------
  129|  20.4k|               if (not put(colon)) [[unlikely]] {
  ------------------
  |  Branch (129:20): [True: 0, False: 20.4k]
  ------------------
  130|      0|                  return;
  131|      0|               }
  132|  20.4k|               ++it;
  133|  20.4k|               break;
  134|  20.4k|            }
  135|   103k|            case Array_Start: {
  ------------------
  |  Branch (135:13): [True: 103k, False: 45.7M]
  ------------------
  136|   103k|               if (not put('[')) [[unlikely]] {
  ------------------
  |  Branch (136:20): [True: 0, False: 103k]
  ------------------
  137|      0|                  return;
  138|      0|               }
  139|   103k|               ++it;
  140|   103k|               if (not open_level(Array_Start)) [[unlikely]] {
  ------------------
  |  Branch (140:20): [True: 26, False: 103k]
  ------------------
  141|     26|                  return;
  142|     26|               }
  143|   103k|               if constexpr (check_new_lines_in_arrays(Opts)) {
  144|   103k|                  if constexpr (not Opts.null_terminated) {
  145|   103k|                     if (it != end && *it != ']') {
  ------------------
  |  Branch (145:26): [True: 103k, False: 117]
  |  Branch (145:39): [True: 101k, False: 1.24k]
  ------------------
  146|   101k|                        if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (146:29): [True: 0, False: 101k]
  ------------------
  147|      0|                           return;
  148|      0|                        }
  149|   101k|                     }
  150|       |                  }
  151|       |                  else {
  152|       |                     if (*it != ']') {
  153|       |                        if (not new_line()) [[unlikely]] {
  154|       |                           return;
  155|       |                        }
  156|       |                     }
  157|       |                  }
  158|   103k|               }
  159|   103k|               break;
  160|   103k|            }
  161|   103k|            case Array_End: {
  ------------------
  |  Branch (161:13): [True: 22.3k, False: 45.8M]
  ------------------
  162|  22.3k|               --indent;
  163|  22.3k|               if (indent < 0) {
  ------------------
  |  Branch (163:20): [True: 4, False: 22.3k]
  ------------------
  164|      4|                  ctx.error = error_code::syntax_error;
  165|      4|                  return;
  166|      4|               }
  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|  22.3k|               if constexpr (check_new_lines_in_arrays(Opts)) {
  170|  22.3k|                  if (it[-1] != '[') {
  ------------------
  |  Branch (170:23): [True: 21.0k, False: 1.24k]
  ------------------
  171|  21.0k|                     if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (171:26): [True: 0, False: 21.0k]
  ------------------
  172|      0|                        return;
  173|      0|                     }
  174|  21.0k|                  }
  175|  22.3k|               }
  176|  22.3k|               if (not put(']')) [[unlikely]] {
  ------------------
  |  Branch (176:20): [True: 0, False: 22.3k]
  ------------------
  177|      0|                  return;
  178|      0|               }
  179|  22.3k|               ++it;
  180|  22.3k|               break;
  181|  22.3k|            }
  182|  2.86k|            case Null: {
  ------------------
  |  Branch (182:13): [True: 2.86k, False: 45.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|  2.86k|               if (not match_literal<"null">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (185:20): [True: 196, False: 2.66k]
  ------------------
  186|    196|                  return;
  187|    196|               }
  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.32k|            case Bool: {
  ------------------
  |  Branch (193:13): [True: 4.32k, False: 45.8M]
  ------------------
  194|  4.32k|               if (*it == 't') {
  ------------------
  |  Branch (194:20): [True: 2.26k, False: 2.06k]
  ------------------
  195|  2.26k|                  if (not match_literal<"true">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (195:23): [True: 190, False: 2.07k]
  ------------------
  196|    190|                     return;
  197|    190|                  }
  198|  2.07k|                  if (not put("true")) [[unlikely]] {
  ------------------
  |  Branch (198:23): [True: 0, False: 2.07k]
  ------------------
  199|      0|                     return;
  200|      0|                  }
  201|  2.07k|                  break;
  202|  2.07k|               }
  203|  2.06k|               else {
  204|  2.06k|                  if (not match_literal<"false">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (204:23): [True: 272, False: 1.79k]
  ------------------
  205|    272|                     return;
  206|    272|                  }
  207|  1.79k|                  if (not put("false")) [[unlikely]] {
  ------------------
  |  Branch (207:23): [True: 0, False: 1.79k]
  ------------------
  208|      0|                     return;
  209|      0|                  }
  210|  1.79k|                  break;
  211|  1.79k|               }
  212|  4.32k|            }
  213|   107k|            case Object_Start: {
  ------------------
  |  Branch (213:13): [True: 107k, False: 45.7M]
  ------------------
  214|   107k|               if (not put('{')) [[unlikely]] {
  ------------------
  |  Branch (214:20): [True: 0, False: 107k]
  ------------------
  215|      0|                  return;
  216|      0|               }
  217|   107k|               ++it;
  218|   107k|               if (not open_level(Object_Start)) [[unlikely]] {
  ------------------
  |  Branch (218:20): [True: 20, False: 107k]
  ------------------
  219|     20|                  return;
  220|     20|               }
  221|   107k|               if constexpr (not Opts.null_terminated) {
  222|   107k|                  if (it != end && *it != '}') {
  ------------------
  |  Branch (222:23): [True: 107k, False: 111]
  |  Branch (222:36): [True: 105k, False: 2.57k]
  ------------------
  223|   105k|                     if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (223:26): [True: 0, False: 105k]
  ------------------
  224|      0|                        return;
  225|      0|                     }
  226|   105k|                  }
  227|       |               }
  228|       |               else {
  229|       |                  if (*it != '}') {
  230|       |                     if (not new_line()) [[unlikely]] {
  231|       |                        return;
  232|       |                     }
  233|       |                  }
  234|       |               }
  235|   107k|               break;
  236|   107k|            }
  237|   107k|            case Object_End: {
  ------------------
  |  Branch (237:13): [True: 20.3k, False: 45.8M]
  ------------------
  238|  20.3k|               --indent;
  239|  20.3k|               if (indent < 0) {
  ------------------
  |  Branch (239:20): [True: 8, False: 20.3k]
  ------------------
  240|      8|                  ctx.error = error_code::syntax_error;
  241|      8|                  return;
  242|      8|               }
  243|       |               // As in Array_End, this break doubles as the close of an open line comment.
  244|  20.3k|               if (it[-1] != '{') {
  ------------------
  |  Branch (244:20): [True: 17.7k, False: 2.57k]
  ------------------
  245|  17.7k|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (245:23): [True: 0, False: 17.7k]
  ------------------
  246|      0|                     return;
  247|      0|                  }
  248|  17.7k|               }
  249|  20.3k|               if (not put('}')) [[unlikely]] {
  ------------------
  |  Branch (249:20): [True: 0, False: 20.3k]
  ------------------
  250|      0|                  return;
  251|      0|               }
  252|  20.3k|               ++it;
  253|  20.3k|               break;
  254|  20.3k|            }
  255|    884|            case Comment: {
  ------------------
  |  Branch (255:13): [True: 884, False: 45.8M]
  ------------------
  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|    884|               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|    884|                  ctx.error = error_code::syntax_error;
  274|    884|                  return;
  275|    884|               }
  276|    884|            }
  277|  2.54k|            case Whitespace: {
  ------------------
  |  Branch (277:13): [True: 1.66k, False: 45.8M]
  ------------------
  278|       |               // Skip whitespace characters that are part of raw JSON content
  279|  2.54k|               ++it;
  280|  2.54k|               break;
  281|    884|            }
  282|  1.32k|            [[unlikely]] default: {
  ------------------
  |  Branch (282:26): [True: 1.32k, False: 45.8M]
  ------------------
  283|  1.32k|               ctx.error = error_code::syntax_error;
  284|  1.32k|               return;
  285|      0|            }
  286|  45.8M|            }
  287|  45.8M|         }
  288|  3.88k|      }
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clINS8_17basic_string_viewIcSB_EEEEDaSS_:
   73|   173k|         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|   173k|            return emit_bytes<true>(ctx, b, ix, x);
   82|   173k|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIcEEDaSS_:
   73|  45.6M|         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|  45.6M|            return emit_bytes<true>(ctx, b, ix, x);
   82|  45.6M|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlvE_clEv:
   47|  45.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|  45.6M|            append_new_line<use_tabs, indent_width>(b, ix, indent);
   55|       |            if constexpr (Opts.comments) {
   56|       |               line_comment_open = false;
   57|       |            }
   58|  45.6M|            return true;
   59|  45.6M|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlNS0_9json_typeEE_clESQ_:
   29|   211k|         const auto open_level = [&](const json_type type) {
   30|   211k|            if (size_t(indent) >= max_recursive_depth_limit) [[unlikely]] {
  ------------------
  |  Branch (30:17): [True: 46, False: 210k]
  ------------------
   31|     46|               ctx.error = error_code::exceeded_max_recursive_depth;
   32|     46|               return false;
   33|     46|            }
   34|   210k|            state[++indent] = type;
   35|   210k|            return true;
   36|   211k|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIA5_cEEDaSS_:
   73|  4.73k|         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.73k|            return emit_bytes<true>(ctx, b, ix, x);
   82|  4.73k|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIA6_cEEDaSS_:
   73|  1.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|  1.79k|            return emit_bytes<true>(ctx, b, ix, x);
   82|  1.79k|         };
_ZN3glz14prettify_jsoncITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1EEENSt3__16vectorIcNS2_9allocatorIcEEEEEENS2_12basic_stringIcNS2_11char_traitsIcEES5_EERKT0_:
  373|  1.94k|   {
  374|  1.94k|      context ctx{};
  375|  1.94k|      std::string out{};
  376|  1.94k|      detail::prettify_json<opt_true<Opts, &opts::comments>>(ctx, in, out);
  377|  1.94k|      if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (377:11): [True: 914, False: 1.02k]
  ------------------
  378|    914|         return {}; // an incomplete result is not a document; see above
  379|    914|      }
  380|  1.02k|      return out;
  381|  1.94k|   }
_ZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10contiguousERKNSt3__16vectorIcNS3_9allocatorIcEEEETkNS_13output_bufferERNS3_12basic_stringIcNS3_11char_traitsIcEES6_EETkNS_10is_contextERNS_7contextEEEmOT2_OT0_OT1_:
  294|  1.94k|      {
  295|  1.94k|         if constexpr (resizable<Out>) {
  296|  1.94k|            if (in.size() == 0) {
  ------------------
  |  Branch (296:17): [True: 0, False: 1.94k]
  ------------------
  297|      0|               out.resize(0); // resize is what `resizable` promises; clear() is not
  298|      0|               return 0;
  299|      0|            }
  300|  1.94k|            out.resize(in.size() * 2);
  301|  1.94k|         }
  302|      0|         size_t ix = 0;
  303|  1.94k|         auto [it, end] = read_iterators<Opts>(in);
  304|  1.94k|         if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (304:14): [True: 0, False: 1.94k]
  ------------------
  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.94k|         else {
  312|  1.94k|            prettify_json<opt_false<Opts, &opts::null_terminated>>(ctx, it, end, out, ix);
  313|  1.94k|         }
  314|       |
  315|  1.94k|         if constexpr (resizable<Out>) {
  316|  1.94k|            out.resize(ix);
  317|  1.94k|         }
  318|  1.94k|         return ix;
  319|  1.94k|      }
_ZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_:
   17|  1.94k|      {
   18|  1.94k|         constexpr bool use_tabs = check_indentation_char(Opts) == '\t';
   19|  1.94k|         constexpr auto indent_width = check_indentation_width(Opts);
   20|       |
   21|  1.94k|         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.94k|         std::array<json_type, max_recursive_depth_limit + 1> state{};
   26|  1.94k|         int64_t indent{};
   27|       |
   28|       |         // Enters one level of nesting, failing past the readers' limit.
   29|  1.94k|         const auto open_level = [&](const json_type type) {
   30|  1.94k|            if (size_t(indent) >= max_recursive_depth_limit) [[unlikely]] {
   31|  1.94k|               ctx.error = error_code::exceeded_max_recursive_depth;
   32|  1.94k|               return false;
   33|  1.94k|            }
   34|  1.94k|            state[++indent] = type;
   35|  1.94k|            return true;
   36|  1.94k|         };
   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.94k|         [[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.94k|         const auto new_line = [&] {
   48|  1.94k|            if constexpr (has_bounded_capacity<decltype(b)>) {
   49|  1.94k|               const size_t n = use_tabs ? size_t(indent) : size_t(indent) * indent_width;
   50|  1.94k|               if (not ensure_space(ctx, b, ix + 1 + n)) [[unlikely]] {
   51|  1.94k|                  return false;
   52|  1.94k|               }
   53|  1.94k|            }
   54|  1.94k|            append_new_line<use_tabs, indent_width>(b, ix, indent);
   55|  1.94k|            if constexpr (Opts.comments) {
   56|  1.94k|               line_comment_open = false;
   57|  1.94k|            }
   58|  1.94k|            return true;
   59|  1.94k|         };
   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.94k|         const auto put = [&](const auto& x) {
   74|  1.94k|            if constexpr (Opts.comments) {
   75|  1.94k|               if (line_comment_open) [[unlikely]] {
   76|  1.94k|                  if (not new_line()) [[unlikely]] {
   77|  1.94k|                     return false;
   78|  1.94k|                  }
   79|  1.94k|               }
   80|  1.94k|            }
   81|  1.94k|            return emit_bytes<true>(ctx, b, ix, x);
   82|  1.94k|         };
   83|       |
   84|  40.5M|         while (it < end) {
  ------------------
  |  Branch (84:17): [True: 40.5M, False: 1.02k]
  ------------------
   85|  40.5M|            switch (json_types[uint8_t(*it)]) {
   86|   107k|            case String: {
  ------------------
  |  Branch (86:13): [True: 107k, False: 40.4M]
  ------------------
   87|   107k|               const auto value = read_json_string(ctx, it, end);
   88|   107k|               if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (88:20): [True: 66, False: 107k]
  ------------------
   89|     66|                  return;
   90|     66|               }
   91|       |               // non-empty: the scanner reports an empty view as an error
   92|   107k|               if (not put(value)) [[unlikely]] {
  ------------------
  |  Branch (92:20): [True: 0, False: 107k]
  ------------------
   93|      0|                  return;
   94|      0|               }
   95|   107k|               break;
   96|   107k|            }
   97|  40.2M|            case Comma: {
  ------------------
  |  Branch (97:13): [True: 40.2M, False: 313k]
  ------------------
   98|  40.2M|               if (not put(',')) [[unlikely]] {
  ------------------
  |  Branch (98:20): [True: 0, False: 40.2M]
  ------------------
   99|      0|                  return;
  100|      0|               }
  101|  40.2M|               ++it;
  102|  40.2M|               if constexpr (check_new_lines_in_arrays(Opts)) {
  103|  40.2M|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (103:23): [True: 0, False: 40.2M]
  ------------------
  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|  40.2M|               break;
  118|  40.2M|            }
  119|  40.2M|            case Number: {
  ------------------
  |  Branch (119:13): [True: 25.8k, False: 40.5M]
  ------------------
  120|  25.8k|               const auto value = read_json_number<Opts.null_terminated>(it, end);
  121|       |               // non-empty: a Number match is one valid character
  122|  25.8k|               if (not put(value)) [[unlikely]] {
  ------------------
  |  Branch (122:20): [True: 0, False: 25.8k]
  ------------------
  123|      0|                  return;
  124|      0|               }
  125|  25.8k|               break;
  126|  25.8k|            }
  127|  25.8k|            case Colon: {
  ------------------
  |  Branch (127:13): [True: 15.2k, False: 40.5M]
  ------------------
  128|  15.2k|               static constexpr sv colon = use_tabs ? sv{":\t"} : sv{": "};
  ------------------
  |  Branch (128:44): [Folded, False: 15.2k]
  ------------------
  129|  15.2k|               if (not put(colon)) [[unlikely]] {
  ------------------
  |  Branch (129:20): [True: 0, False: 15.2k]
  ------------------
  130|      0|                  return;
  131|      0|               }
  132|  15.2k|               ++it;
  133|  15.2k|               break;
  134|  15.2k|            }
  135|  56.1k|            case Array_Start: {
  ------------------
  |  Branch (135:13): [True: 56.1k, False: 40.5M]
  ------------------
  136|  56.1k|               if (not put('[')) [[unlikely]] {
  ------------------
  |  Branch (136:20): [True: 0, False: 56.1k]
  ------------------
  137|      0|                  return;
  138|      0|               }
  139|  56.1k|               ++it;
  140|  56.1k|               if (not open_level(Array_Start)) [[unlikely]] {
  ------------------
  |  Branch (140:20): [True: 16, False: 56.1k]
  ------------------
  141|     16|                  return;
  142|     16|               }
  143|  56.1k|               if constexpr (check_new_lines_in_arrays(Opts)) {
  144|  56.1k|                  if constexpr (not Opts.null_terminated) {
  145|  56.1k|                     if (it != end && *it != ']') {
  ------------------
  |  Branch (145:26): [True: 56.0k, False: 132]
  |  Branch (145:39): [True: 55.1k, False: 837]
  ------------------
  146|  55.1k|                        if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (146:29): [True: 0, False: 55.1k]
  ------------------
  147|      0|                           return;
  148|      0|                        }
  149|  55.1k|                     }
  150|       |                  }
  151|       |                  else {
  152|       |                     if (*it != ']') {
  153|       |                        if (not new_line()) [[unlikely]] {
  154|       |                           return;
  155|       |                        }
  156|       |                     }
  157|       |                  }
  158|  56.1k|               }
  159|  56.1k|               break;
  160|  56.1k|            }
  161|  56.1k|            case Array_End: {
  ------------------
  |  Branch (161:13): [True: 11.8k, False: 40.5M]
  ------------------
  162|  11.8k|               --indent;
  163|  11.8k|               if (indent < 0) {
  ------------------
  |  Branch (163:20): [True: 3, False: 11.7k]
  ------------------
  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|  11.7k|               if constexpr (check_new_lines_in_arrays(Opts)) {
  170|  11.7k|                  if (it[-1] != '[') {
  ------------------
  |  Branch (170:23): [True: 10.9k, False: 837]
  ------------------
  171|  10.9k|                     if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (171:26): [True: 0, False: 10.9k]
  ------------------
  172|      0|                        return;
  173|      0|                     }
  174|  10.9k|                  }
  175|  11.7k|               }
  176|  11.7k|               if (not put(']')) [[unlikely]] {
  ------------------
  |  Branch (176:20): [True: 0, False: 11.7k]
  ------------------
  177|      0|                  return;
  178|      0|               }
  179|  11.7k|               ++it;
  180|  11.7k|               break;
  181|  11.7k|            }
  182|  1.90k|            case Null: {
  ------------------
  |  Branch (182:13): [True: 1.90k, False: 40.5M]
  ------------------
  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.90k|               if (not match_literal<"null">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (185:20): [True: 103, False: 1.80k]
  ------------------
  186|    103|                  return;
  187|    103|               }
  188|  1.80k|               if (not put("null")) [[unlikely]] {
  ------------------
  |  Branch (188:20): [True: 0, False: 1.80k]
  ------------------
  189|      0|                  return;
  190|      0|               }
  191|  1.80k|               break;
  192|  1.80k|            }
  193|  6.27k|            case Bool: {
  ------------------
  |  Branch (193:13): [True: 6.27k, False: 40.5M]
  ------------------
  194|  6.27k|               if (*it == 't') {
  ------------------
  |  Branch (194:20): [True: 4.82k, False: 1.45k]
  ------------------
  195|  4.82k|                  if (not match_literal<"true">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (195:23): [True: 97, False: 4.72k]
  ------------------
  196|     97|                     return;
  197|     97|                  }
  198|  4.72k|                  if (not put("true")) [[unlikely]] {
  ------------------
  |  Branch (198:23): [True: 0, False: 4.72k]
  ------------------
  199|      0|                     return;
  200|      0|                  }
  201|  4.72k|                  break;
  202|  4.72k|               }
  203|  1.45k|               else {
  204|  1.45k|                  if (not match_literal<"false">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (204:23): [True: 145, False: 1.31k]
  ------------------
  205|    145|                     return;
  206|    145|                  }
  207|  1.31k|                  if (not put("false")) [[unlikely]] {
  ------------------
  |  Branch (207:23): [True: 0, False: 1.31k]
  ------------------
  208|      0|                     return;
  209|      0|                  }
  210|  1.31k|                  break;
  211|  1.31k|               }
  212|  6.27k|            }
  213|  58.2k|            case Object_Start: {
  ------------------
  |  Branch (213:13): [True: 58.2k, False: 40.5M]
  ------------------
  214|  58.2k|               if (not put('{')) [[unlikely]] {
  ------------------
  |  Branch (214:20): [True: 0, False: 58.2k]
  ------------------
  215|      0|                  return;
  216|      0|               }
  217|  58.2k|               ++it;
  218|  58.2k|               if (not open_level(Object_Start)) [[unlikely]] {
  ------------------
  |  Branch (218:20): [True: 11, False: 58.2k]
  ------------------
  219|     11|                  return;
  220|     11|               }
  221|  58.2k|               if constexpr (not Opts.null_terminated) {
  222|  58.2k|                  if (it != end && *it != '}') {
  ------------------
  |  Branch (222:23): [True: 58.0k, False: 129]
  |  Branch (222:36): [True: 56.6k, False: 1.38k]
  ------------------
  223|  56.6k|                     if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (223:26): [True: 0, False: 56.6k]
  ------------------
  224|      0|                        return;
  225|      0|                     }
  226|  56.6k|                  }
  227|       |               }
  228|       |               else {
  229|       |                  if (*it != '}') {
  230|       |                     if (not new_line()) [[unlikely]] {
  231|       |                        return;
  232|       |                     }
  233|       |                  }
  234|       |               }
  235|  58.2k|               break;
  236|  58.2k|            }
  237|  58.2k|            case Object_End: {
  ------------------
  |  Branch (237:13): [True: 13.1k, False: 40.5M]
  ------------------
  238|  13.1k|               --indent;
  239|  13.1k|               if (indent < 0) {
  ------------------
  |  Branch (239:20): [True: 4, False: 13.1k]
  ------------------
  240|      4|                  ctx.error = error_code::syntax_error;
  241|      4|                  return;
  242|      4|               }
  243|       |               // As in Array_End, this break doubles as the close of an open line comment.
  244|  13.1k|               if (it[-1] != '{') {
  ------------------
  |  Branch (244:20): [True: 11.7k, False: 1.38k]
  ------------------
  245|  11.7k|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (245:23): [True: 0, False: 11.7k]
  ------------------
  246|      0|                     return;
  247|      0|                  }
  248|  11.7k|               }
  249|  13.1k|               if (not put('}')) [[unlikely]] {
  ------------------
  |  Branch (249:20): [True: 0, False: 13.1k]
  ------------------
  250|      0|                  return;
  251|      0|               }
  252|  13.1k|               ++it;
  253|  13.1k|               break;
  254|  13.1k|            }
  255|  7.75k|            case Comment: {
  ------------------
  |  Branch (255:13): [True: 7.75k, False: 40.5M]
  ------------------
  256|  7.75k|               if constexpr (Opts.comments) {
  257|  7.75k|                  const auto comment = read_jsonc_comment(ctx, it, end);
  258|  7.75k|                  if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (258:23): [True: 164, False: 7.59k]
  ------------------
  259|    164|                     return;
  260|    164|                  }
  261|       |                  // non-empty: an empty view comes with an error
  262|  7.59k|                  if (not put(comment.text)) [[unlikely]] {
  ------------------
  |  Branch (262:23): [True: 0, False: 7.59k]
  ------------------
  263|      0|                     return;
  264|      0|                  }
  265|  7.59k|                  line_comment_open = comment.line;
  266|  7.59k|                  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.75k|            }
  277|  17.2k|            case Whitespace: {
  ------------------
  |  Branch (277:13): [True: 9.53k, False: 40.5M]
  ------------------
  278|       |               // Skip whitespace characters that are part of raw JSON content
  279|  17.2k|               ++it;
  280|  17.2k|               break;
  281|  7.75k|            }
  282|    305|            [[unlikely]] default: {
  ------------------
  |  Branch (282:26): [True: 305, False: 40.5M]
  ------------------
  283|    305|               ctx.error = error_code::syntax_error;
  284|    305|               return;
  285|      0|            }
  286|  40.5M|            }
  287|  40.5M|         }
  288|  1.94k|      }
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clINS8_17basic_string_viewIcSB_EEEEDaSS_:
   73|   156k|         const auto put = [&](const auto& x) {
   74|   156k|            if constexpr (Opts.comments) {
   75|   156k|               if (line_comment_open) [[unlikely]] {
  ------------------
  |  Branch (75:20): [True: 1.69k, False: 154k]
  ------------------
   76|  1.69k|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (76:23): [True: 0, False: 1.69k]
  ------------------
   77|      0|                     return false;
   78|      0|                  }
   79|  1.69k|               }
   80|   156k|            }
   81|   156k|            return emit_bytes<true>(ctx, b, ix, x);
   82|   156k|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIcEEDaSS_:
   73|  40.3M|         const auto put = [&](const auto& x) {
   74|  40.3M|            if constexpr (Opts.comments) {
   75|  40.3M|               if (line_comment_open) [[unlikely]] {
  ------------------
  |  Branch (75:20): [True: 929, False: 40.3M]
  ------------------
   76|    929|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (76:23): [True: 0, False: 929]
  ------------------
   77|      0|                     return false;
   78|      0|                  }
   79|    929|               }
   80|  40.3M|            }
   81|  40.3M|            return emit_bytes<true>(ctx, b, ix, x);
   82|  40.3M|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlvE_clEv:
   47|  40.3M|         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|  40.3M|            append_new_line<use_tabs, indent_width>(b, ix, indent);
   55|  40.3M|            if constexpr (Opts.comments) {
   56|  40.3M|               line_comment_open = false;
   57|  40.3M|            }
   58|  40.3M|            return true;
   59|  40.3M|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlNS0_9json_typeEE_clESQ_:
   29|   114k|         const auto open_level = [&](const json_type type) {
   30|   114k|            if (size_t(indent) >= max_recursive_depth_limit) [[unlikely]] {
  ------------------
  |  Branch (30:17): [True: 27, False: 114k]
  ------------------
   31|     27|               ctx.error = error_code::exceeded_max_recursive_depth;
   32|     27|               return false;
   33|     27|            }
   34|   114k|            state[++indent] = type;
   35|   114k|            return true;
   36|   114k|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIA5_cEEDaSS_:
   73|  6.52k|         const auto put = [&](const auto& x) {
   74|  6.52k|            if constexpr (Opts.comments) {
   75|  6.52k|               if (line_comment_open) [[unlikely]] {
  ------------------
  |  Branch (75:20): [True: 4.01k, False: 2.51k]
  ------------------
   76|  4.01k|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (76:23): [True: 0, False: 4.01k]
  ------------------
   77|      0|                     return false;
   78|      0|                  }
   79|  4.01k|               }
   80|  6.52k|            }
   81|  6.52k|            return emit_bytes<true>(ctx, b, ix, x);
   82|  6.52k|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIA6_cEEDaSS_:
   73|  1.31k|         const auto put = [&](const auto& x) {
   74|  1.31k|            if constexpr (Opts.comments) {
   75|  1.31k|               if (line_comment_open) [[unlikely]] {
  ------------------
  |  Branch (75:20): [True: 220, False: 1.09k]
  ------------------
   76|    220|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (76:23): [True: 0, False: 220]
  ------------------
   77|      0|                     return false;
   78|      0|                  }
   79|    220|               }
   80|  1.31k|            }
   81|  1.31k|            return emit_bytes<true>(ctx, b, ix, x);
   82|  1.31k|         };
_ZN3glz14prettify_jsoncITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1EEENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEES8_RKT0_:
  373|  1.94k|   {
  374|  1.94k|      context ctx{};
  375|  1.94k|      std::string out{};
  376|  1.94k|      detail::prettify_json<opt_true<Opts, &opts::comments>>(ctx, in, out);
  377|  1.94k|      if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (377:11): [True: 914, False: 1.02k]
  ------------------
  378|    914|         return {}; // an incomplete result is not a document; see above
  379|    914|      }
  380|  1.02k|      return out;
  381|  1.94k|   }
_ZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10contiguousERKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEETkNS_13output_bufferERS9_TkNS_10is_contextERNS_7contextEEEmOT2_OT0_OT1_:
  294|  1.94k|      {
  295|  1.94k|         if constexpr (resizable<Out>) {
  296|  1.94k|            if (in.size() == 0) {
  ------------------
  |  Branch (296:17): [True: 0, False: 1.94k]
  ------------------
  297|      0|               out.resize(0); // resize is what `resizable` promises; clear() is not
  298|      0|               return 0;
  299|      0|            }
  300|  1.94k|            out.resize(in.size() * 2);
  301|  1.94k|         }
  302|      0|         size_t ix = 0;
  303|  1.94k|         auto [it, end] = read_iterators<Opts>(in);
  304|  1.94k|         if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (304:14): [True: 0, False: 1.94k]
  ------------------
  305|      0|            return 0;
  306|      0|         }
  307|       |
  308|  1.94k|         if constexpr (self_terminating<In>) {
  309|  1.94k|            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.94k|         if constexpr (resizable<Out>) {
  316|  1.94k|            out.resize(ix);
  317|  1.94k|         }
  318|  1.94k|         return ix;
  319|  1.94k|      }
_ZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_:
   17|  1.94k|      {
   18|  1.94k|         constexpr bool use_tabs = check_indentation_char(Opts) == '\t';
   19|  1.94k|         constexpr auto indent_width = check_indentation_width(Opts);
   20|       |
   21|  1.94k|         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.94k|         std::array<json_type, max_recursive_depth_limit + 1> state{};
   26|  1.94k|         int64_t indent{};
   27|       |
   28|       |         // Enters one level of nesting, failing past the readers' limit.
   29|  1.94k|         const auto open_level = [&](const json_type type) {
   30|  1.94k|            if (size_t(indent) >= max_recursive_depth_limit) [[unlikely]] {
   31|  1.94k|               ctx.error = error_code::exceeded_max_recursive_depth;
   32|  1.94k|               return false;
   33|  1.94k|            }
   34|  1.94k|            state[++indent] = type;
   35|  1.94k|            return true;
   36|  1.94k|         };
   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.94k|         [[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.94k|         const auto new_line = [&] {
   48|  1.94k|            if constexpr (has_bounded_capacity<decltype(b)>) {
   49|  1.94k|               const size_t n = use_tabs ? size_t(indent) : size_t(indent) * indent_width;
   50|  1.94k|               if (not ensure_space(ctx, b, ix + 1 + n)) [[unlikely]] {
   51|  1.94k|                  return false;
   52|  1.94k|               }
   53|  1.94k|            }
   54|  1.94k|            append_new_line<use_tabs, indent_width>(b, ix, indent);
   55|  1.94k|            if constexpr (Opts.comments) {
   56|  1.94k|               line_comment_open = false;
   57|  1.94k|            }
   58|  1.94k|            return true;
   59|  1.94k|         };
   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.94k|         const auto put = [&](const auto& x) {
   74|  1.94k|            if constexpr (Opts.comments) {
   75|  1.94k|               if (line_comment_open) [[unlikely]] {
   76|  1.94k|                  if (not new_line()) [[unlikely]] {
   77|  1.94k|                     return false;
   78|  1.94k|                  }
   79|  1.94k|               }
   80|  1.94k|            }
   81|  1.94k|            return emit_bytes<true>(ctx, b, ix, x);
   82|  1.94k|         };
   83|       |
   84|  40.5M|         while (it < end) {
  ------------------
  |  Branch (84:17): [True: 40.5M, False: 1.02k]
  ------------------
   85|  40.5M|            switch (json_types[uint8_t(*it)]) {
   86|   107k|            case String: {
  ------------------
  |  Branch (86:13): [True: 107k, False: 40.4M]
  ------------------
   87|   107k|               const auto value = read_json_string(ctx, it, end);
   88|   107k|               if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (88:20): [True: 66, False: 107k]
  ------------------
   89|     66|                  return;
   90|     66|               }
   91|       |               // non-empty: the scanner reports an empty view as an error
   92|   107k|               if (not put(value)) [[unlikely]] {
  ------------------
  |  Branch (92:20): [True: 0, False: 107k]
  ------------------
   93|      0|                  return;
   94|      0|               }
   95|   107k|               break;
   96|   107k|            }
   97|  40.2M|            case Comma: {
  ------------------
  |  Branch (97:13): [True: 40.2M, False: 313k]
  ------------------
   98|  40.2M|               if (not put(',')) [[unlikely]] {
  ------------------
  |  Branch (98:20): [True: 0, False: 40.2M]
  ------------------
   99|      0|                  return;
  100|      0|               }
  101|  40.2M|               ++it;
  102|  40.2M|               if constexpr (check_new_lines_in_arrays(Opts)) {
  103|  40.2M|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (103:23): [True: 0, False: 40.2M]
  ------------------
  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|  40.2M|               break;
  118|  40.2M|            }
  119|  40.2M|            case Number: {
  ------------------
  |  Branch (119:13): [True: 25.8k, False: 40.5M]
  ------------------
  120|  25.8k|               const auto value = read_json_number<Opts.null_terminated>(it, end);
  121|       |               // non-empty: a Number match is one valid character
  122|  25.8k|               if (not put(value)) [[unlikely]] {
  ------------------
  |  Branch (122:20): [True: 0, False: 25.8k]
  ------------------
  123|      0|                  return;
  124|      0|               }
  125|  25.8k|               break;
  126|  25.8k|            }
  127|  25.8k|            case Colon: {
  ------------------
  |  Branch (127:13): [True: 15.2k, False: 40.5M]
  ------------------
  128|  15.2k|               static constexpr sv colon = use_tabs ? sv{":\t"} : sv{": "};
  ------------------
  |  Branch (128:44): [Folded, False: 15.2k]
  ------------------
  129|  15.2k|               if (not put(colon)) [[unlikely]] {
  ------------------
  |  Branch (129:20): [True: 0, False: 15.2k]
  ------------------
  130|      0|                  return;
  131|      0|               }
  132|  15.2k|               ++it;
  133|  15.2k|               break;
  134|  15.2k|            }
  135|  56.1k|            case Array_Start: {
  ------------------
  |  Branch (135:13): [True: 56.1k, False: 40.5M]
  ------------------
  136|  56.1k|               if (not put('[')) [[unlikely]] {
  ------------------
  |  Branch (136:20): [True: 0, False: 56.1k]
  ------------------
  137|      0|                  return;
  138|      0|               }
  139|  56.1k|               ++it;
  140|  56.1k|               if (not open_level(Array_Start)) [[unlikely]] {
  ------------------
  |  Branch (140:20): [True: 16, False: 56.1k]
  ------------------
  141|     16|                  return;
  142|     16|               }
  143|  56.1k|               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|  56.1k|                  else {
  152|  56.1k|                     if (*it != ']') {
  ------------------
  |  Branch (152:26): [True: 55.2k, False: 837]
  ------------------
  153|  55.2k|                        if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (153:29): [True: 0, False: 55.2k]
  ------------------
  154|      0|                           return;
  155|      0|                        }
  156|  55.2k|                     }
  157|  56.1k|                  }
  158|  56.1k|               }
  159|  56.1k|               break;
  160|  56.1k|            }
  161|  56.1k|            case Array_End: {
  ------------------
  |  Branch (161:13): [True: 11.8k, False: 40.5M]
  ------------------
  162|  11.8k|               --indent;
  163|  11.8k|               if (indent < 0) {
  ------------------
  |  Branch (163:20): [True: 3, False: 11.7k]
  ------------------
  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|  11.7k|               if constexpr (check_new_lines_in_arrays(Opts)) {
  170|  11.7k|                  if (it[-1] != '[') {
  ------------------
  |  Branch (170:23): [True: 10.9k, False: 837]
  ------------------
  171|  10.9k|                     if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (171:26): [True: 0, False: 10.9k]
  ------------------
  172|      0|                        return;
  173|      0|                     }
  174|  10.9k|                  }
  175|  11.7k|               }
  176|  11.7k|               if (not put(']')) [[unlikely]] {
  ------------------
  |  Branch (176:20): [True: 0, False: 11.7k]
  ------------------
  177|      0|                  return;
  178|      0|               }
  179|  11.7k|               ++it;
  180|  11.7k|               break;
  181|  11.7k|            }
  182|  1.90k|            case Null: {
  ------------------
  |  Branch (182:13): [True: 1.90k, False: 40.5M]
  ------------------
  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.90k|               if (not match_literal<"null">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (185:20): [True: 103, False: 1.80k]
  ------------------
  186|    103|                  return;
  187|    103|               }
  188|  1.80k|               if (not put("null")) [[unlikely]] {
  ------------------
  |  Branch (188:20): [True: 0, False: 1.80k]
  ------------------
  189|      0|                  return;
  190|      0|               }
  191|  1.80k|               break;
  192|  1.80k|            }
  193|  6.27k|            case Bool: {
  ------------------
  |  Branch (193:13): [True: 6.27k, False: 40.5M]
  ------------------
  194|  6.27k|               if (*it == 't') {
  ------------------
  |  Branch (194:20): [True: 4.82k, False: 1.45k]
  ------------------
  195|  4.82k|                  if (not match_literal<"true">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (195:23): [True: 97, False: 4.72k]
  ------------------
  196|     97|                     return;
  197|     97|                  }
  198|  4.72k|                  if (not put("true")) [[unlikely]] {
  ------------------
  |  Branch (198:23): [True: 0, False: 4.72k]
  ------------------
  199|      0|                     return;
  200|      0|                  }
  201|  4.72k|                  break;
  202|  4.72k|               }
  203|  1.45k|               else {
  204|  1.45k|                  if (not match_literal<"false">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (204:23): [True: 145, False: 1.31k]
  ------------------
  205|    145|                     return;
  206|    145|                  }
  207|  1.31k|                  if (not put("false")) [[unlikely]] {
  ------------------
  |  Branch (207:23): [True: 0, False: 1.31k]
  ------------------
  208|      0|                     return;
  209|      0|                  }
  210|  1.31k|                  break;
  211|  1.31k|               }
  212|  6.27k|            }
  213|  58.2k|            case Object_Start: {
  ------------------
  |  Branch (213:13): [True: 58.2k, False: 40.5M]
  ------------------
  214|  58.2k|               if (not put('{')) [[unlikely]] {
  ------------------
  |  Branch (214:20): [True: 0, False: 58.2k]
  ------------------
  215|      0|                  return;
  216|      0|               }
  217|  58.2k|               ++it;
  218|  58.2k|               if (not open_level(Object_Start)) [[unlikely]] {
  ------------------
  |  Branch (218:20): [True: 11, False: 58.2k]
  ------------------
  219|     11|                  return;
  220|     11|               }
  221|       |               if constexpr (not Opts.null_terminated) {
  222|       |                  if (it != end && *it != '}') {
  223|       |                     if (not new_line()) [[unlikely]] {
  224|       |                        return;
  225|       |                     }
  226|       |                  }
  227|       |               }
  228|  58.2k|               else {
  229|  58.2k|                  if (*it != '}') {
  ------------------
  |  Branch (229:23): [True: 56.8k, False: 1.38k]
  ------------------
  230|  56.8k|                     if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (230:26): [True: 0, False: 56.8k]
  ------------------
  231|      0|                        return;
  232|      0|                     }
  233|  56.8k|                  }
  234|  58.2k|               }
  235|  58.2k|               break;
  236|  58.2k|            }
  237|  58.2k|            case Object_End: {
  ------------------
  |  Branch (237:13): [True: 13.1k, False: 40.5M]
  ------------------
  238|  13.1k|               --indent;
  239|  13.1k|               if (indent < 0) {
  ------------------
  |  Branch (239:20): [True: 4, False: 13.1k]
  ------------------
  240|      4|                  ctx.error = error_code::syntax_error;
  241|      4|                  return;
  242|      4|               }
  243|       |               // As in Array_End, this break doubles as the close of an open line comment.
  244|  13.1k|               if (it[-1] != '{') {
  ------------------
  |  Branch (244:20): [True: 11.7k, False: 1.38k]
  ------------------
  245|  11.7k|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (245:23): [True: 0, False: 11.7k]
  ------------------
  246|      0|                     return;
  247|      0|                  }
  248|  11.7k|               }
  249|  13.1k|               if (not put('}')) [[unlikely]] {
  ------------------
  |  Branch (249:20): [True: 0, False: 13.1k]
  ------------------
  250|      0|                  return;
  251|      0|               }
  252|  13.1k|               ++it;
  253|  13.1k|               break;
  254|  13.1k|            }
  255|  7.75k|            case Comment: {
  ------------------
  |  Branch (255:13): [True: 7.75k, False: 40.5M]
  ------------------
  256|  7.75k|               if constexpr (Opts.comments) {
  257|  7.75k|                  const auto comment = read_jsonc_comment(ctx, it, end);
  258|  7.75k|                  if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (258:23): [True: 164, False: 7.59k]
  ------------------
  259|    164|                     return;
  260|    164|                  }
  261|       |                  // non-empty: an empty view comes with an error
  262|  7.59k|                  if (not put(comment.text)) [[unlikely]] {
  ------------------
  |  Branch (262:23): [True: 0, False: 7.59k]
  ------------------
  263|      0|                     return;
  264|      0|                  }
  265|  7.59k|                  line_comment_open = comment.line;
  266|  7.59k|                  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.75k|            }
  277|  17.2k|            case Whitespace: {
  ------------------
  |  Branch (277:13): [True: 9.53k, False: 40.5M]
  ------------------
  278|       |               // Skip whitespace characters that are part of raw JSON content
  279|  17.2k|               ++it;
  280|  17.2k|               break;
  281|  7.75k|            }
  282|    305|            [[unlikely]] default: {
  ------------------
  |  Branch (282:26): [True: 305, False: 40.5M]
  ------------------
  283|    305|               ctx.error = error_code::syntax_error;
  284|    305|               return;
  285|      0|            }
  286|  40.5M|            }
  287|  40.5M|         }
  288|  1.94k|      }
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clINS8_17basic_string_viewIcSB_EEEEDaSS_:
   73|   156k|         const auto put = [&](const auto& x) {
   74|   156k|            if constexpr (Opts.comments) {
   75|   156k|               if (line_comment_open) [[unlikely]] {
  ------------------
  |  Branch (75:20): [True: 1.69k, False: 154k]
  ------------------
   76|  1.69k|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (76:23): [True: 0, False: 1.69k]
  ------------------
   77|      0|                     return false;
   78|      0|                  }
   79|  1.69k|               }
   80|   156k|            }
   81|   156k|            return emit_bytes<true>(ctx, b, ix, x);
   82|   156k|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIcEEDaSS_:
   73|  40.3M|         const auto put = [&](const auto& x) {
   74|  40.3M|            if constexpr (Opts.comments) {
   75|  40.3M|               if (line_comment_open) [[unlikely]] {
  ------------------
  |  Branch (75:20): [True: 929, False: 40.3M]
  ------------------
   76|    929|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (76:23): [True: 0, False: 929]
  ------------------
   77|      0|                     return false;
   78|      0|                  }
   79|    929|               }
   80|  40.3M|            }
   81|  40.3M|            return emit_bytes<true>(ctx, b, ix, x);
   82|  40.3M|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlvE_clEv:
   47|  40.3M|         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|  40.3M|            append_new_line<use_tabs, indent_width>(b, ix, indent);
   55|  40.3M|            if constexpr (Opts.comments) {
   56|  40.3M|               line_comment_open = false;
   57|  40.3M|            }
   58|  40.3M|            return true;
   59|  40.3M|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlNS0_9json_typeEE_clESQ_:
   29|   114k|         const auto open_level = [&](const json_type type) {
   30|   114k|            if (size_t(indent) >= max_recursive_depth_limit) [[unlikely]] {
  ------------------
  |  Branch (30:17): [True: 27, False: 114k]
  ------------------
   31|     27|               ctx.error = error_code::exceeded_max_recursive_depth;
   32|     27|               return false;
   33|     27|            }
   34|   114k|            state[++indent] = type;
   35|   114k|            return true;
   36|   114k|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIA5_cEEDaSS_:
   73|  6.52k|         const auto put = [&](const auto& x) {
   74|  6.52k|            if constexpr (Opts.comments) {
   75|  6.52k|               if (line_comment_open) [[unlikely]] {
  ------------------
  |  Branch (75:20): [True: 4.01k, False: 2.51k]
  ------------------
   76|  4.01k|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (76:23): [True: 0, False: 4.01k]
  ------------------
   77|      0|                     return false;
   78|      0|                  }
   79|  4.01k|               }
   80|  6.52k|            }
   81|  6.52k|            return emit_bytes<true>(ctx, b, ix, x);
   82|  6.52k|         };
_ZZN3glz6detail13prettify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIA6_cEEDaSS_:
   73|  1.31k|         const auto put = [&](const auto& x) {
   74|  1.31k|            if constexpr (Opts.comments) {
   75|  1.31k|               if (line_comment_open) [[unlikely]] {
  ------------------
  |  Branch (75:20): [True: 220, False: 1.09k]
  ------------------
   76|    220|                  if (not new_line()) [[unlikely]] {
  ------------------
  |  Branch (76:23): [True: 0, False: 220]
  ------------------
   77|      0|                     return false;
   78|      0|                  }
   79|    220|               }
   80|  1.31k|            }
   81|  1.31k|            return emit_bytes<true>(ctx, b, ix, x);
   82|  1.31k|         };

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

_ZN3glz10comparitorIL_ZZNS_6detail13match_literalITnNS_14string_literalEXtlNS3_ILm5EEEtlA5_cLc110ELc117ELc108ELc108EEEETkNS_10is_contextERNS_7contextERPKcS9_EEbOT0_OT1_T2_E1sELm4EcEEbPKSD_:
  245|  6.60k|   {
  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.60k|      else if constexpr (N == 4) {
  286|  6.60k|         static constexpr auto packed = pack<Str, 4>();
  287|  6.60k|         uint32_t in;
  288|  6.60k|         std::memcpy(&in, other, 4);
  289|       |         if constexpr (std::endian::native == std::endian::big) {
  290|       |            in = std::byteswap(in);
  291|       |         }
  292|  6.60k|         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.60k|   }
_ZN3glz10comparitorIL_ZZNS_6detail13match_literalITnNS_14string_literalEXtlNS3_ILm5EEEtlA5_cLc116ELc114ELc117ELc101EEEETkNS_10is_contextERNS_7contextERPKcS9_EEbOT0_OT1_T2_E1sELm4EcEEbPKSD_:
  245|  11.8k|   {
  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|  11.8k|      else if constexpr (N == 4) {
  286|  11.8k|         static constexpr auto packed = pack<Str, 4>();
  287|  11.8k|         uint32_t in;
  288|  11.8k|         std::memcpy(&in, other, 4);
  289|       |         if constexpr (std::endian::native == std::endian::big) {
  290|       |            in = std::byteswap(in);
  291|       |         }
  292|  11.8k|         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|  11.8k|   }
_ZN3glz10comparitorIL_ZZNS_6detail13match_literalITnNS_14string_literalEXtlNS3_ILm6EEEtlA6_cLc102ELc97ELc108ELc115ELc101EEEETkNS_10is_contextERNS_7contextERPKcS9_EEbOT0_OT1_T2_E1sELm5EcEEbPKSD_:
  245|  4.84k|   {
  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.84k|      else if constexpr (N == 5) {
  277|  4.84k|         static constexpr auto packed = pack<Str, 4>();
  278|  4.84k|         uint32_t in;
  279|  4.84k|         std::memcpy(&in, other, 4);
  280|       |         if constexpr (std::endian::native == std::endian::big) {
  281|       |            in = std::byteswap(in);
  282|       |         }
  283|  4.84k|         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.84k|   }

_ZN3glz4dumpILb1ENSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEEvNS1_17basic_string_viewIcS4_EERT0_Rm:
  192|   508k|   {
  193|   508k|      const auto n = str.size();
  194|   508k|      if constexpr (vector_like<B>) {
  195|   508k|         if constexpr (Checked) {
  196|   508k|            const auto k = ix + n;
  197|   508k|            if (ix + n > b.size()) [[unlikely]] {
  ------------------
  |  Branch (197:17): [True: 675, False: 507k]
  ------------------
  198|    675|               grow_buffer(b, k);
  199|    675|            }
  200|   508k|         }
  201|   508k|      }
  202|   508k|      std::memcpy(&b[ix], str.data(), n);
  203|   508k|      ix += n;
  204|   508k|   }
_ZN3glz4dumpILb1ENSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEETkNS_10byte_sizedEcEEvT1_RT0_Rm:
  150|   252M|   {
  151|   252M|      if constexpr (Checked && vector_like<B>) {
  152|   252M|         if (ix == b.size()) [[unlikely]] {
  ------------------
  |  Branch (152:14): [True: 2.14k, False: 252M]
  ------------------
  153|  2.14k|            grow_buffer(b, b.size() == 0 ? 64 : ix + 1);
  ------------------
  |  Branch (153:28): [True: 0, False: 2.14k]
  ------------------
  154|  2.14k|         }
  155|   252M|      }
  156|   252M|      assign_maybe_cast(c, b, ix);
  157|   252M|      ++ix;
  158|   252M|   }
_ZN3glz17assign_maybe_castITkNS_10byte_sizedEcNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEEvT_RT0_Rm:
   95|   252M|   {
   96|   252M|      using V = std::decay_t<decltype(b[0])>;
   97|   252M|      using C = std::decay_t<decltype(c)>;
   98|   252M|      if constexpr (std::same_as<V, C>) {
   99|   252M|         b[ix] = c;
  100|       |      }
  101|       |      else {
  102|       |         b[ix] = static_cast<V>(c);
  103|       |      }
  104|   252M|   }
_ZN3glz5dumpnINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEETkNS_10byte_sizedEcEEvT0_mRT_Rm:
  222|   126M|   {
  223|   126M|      if constexpr (vector_like<B>) {
  224|   126M|         const auto k = ix + n;
  225|   126M|         if (k > b.size()) [[unlikely]] {
  ------------------
  |  Branch (225:14): [True: 17.0k, False: 126M]
  ------------------
  226|  17.0k|            grow_buffer(b, k);
  227|  17.0k|         }
  228|   126M|      }
  229|   126M|      fill_bytes(data_at(b, ix), c, n);
  230|   126M|      ix += n;
  231|   126M|   }
_ZN3glz10fill_bytesIcEEvPT_cm:
   54|   126M|   {
   55|   126M|      auto* p = reinterpret_cast<char*>(dst);
   56|   126M|      if (n >= 64) [[unlikely]] {
  ------------------
  |  Branch (56:11): [True: 125M, False: 1.28M]
  ------------------
   57|   125M|         std::memset(p, c, n);
   58|   125M|         return;
   59|   125M|      }
   60|  1.28M|      const uint64_t v = 0x0101010101010101ull * uint8_t(c);
   61|  1.28M|      if (n >= 8) {
  ------------------
  |  Branch (61:11): [True: 90.7k, False: 1.19M]
  ------------------
   62|  90.7k|         size_t i = 0;
   63|   444k|         for (; i + 8 <= n; i += 8) {
  ------------------
  |  Branch (63:17): [True: 353k, False: 90.7k]
  ------------------
   64|   353k|            std::memcpy(p + i, &v, 8);
   65|   353k|         }
   66|  90.7k|         if (i < n) {
  ------------------
  |  Branch (66:14): [True: 79.1k, False: 11.5k]
  ------------------
   67|  79.1k|            std::memcpy(p + n - 8, &v, 8); // overlaps what is already written, stays within n
   68|  79.1k|         }
   69|  90.7k|      }
   70|  1.19M|      else if (n >= 4) {
  ------------------
  |  Branch (70:16): [True: 8.37k, False: 1.18M]
  ------------------
   71|  8.37k|         std::memcpy(p, &v, 4);
   72|  8.37k|         std::memcpy(p + n - 4, &v, 4);
   73|  8.37k|      }
   74|  1.18M|      else if (n) {
  ------------------
  |  Branch (74:16): [True: 46.4k, False: 1.13M]
  ------------------
   75|  46.4k|         std::memcpy(p, &v, 1);
   76|  46.4k|         std::memcpy(p + (n >> 1), &v, 1);
   77|  46.4k|         std::memcpy(p + n - 1, &v, 1);
   78|  46.4k|      }
   79|  1.28M|   }
_ZN3glz7data_atINSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEEDaRT_m:
  117|   126M|   {
  118|       |      if constexpr (std::is_pointer_v<std::remove_cvref_t<B>>) {
  119|       |         return b + ix;
  120|       |      }
  121|   126M|      else {
  122|   126M|         static_assert(has_data<std::remove_cvref_t<B>>,
  123|   126M|                       "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|   126M|         else {
  129|   126M|            return b.data() + ix;
  130|   126M|         }
  131|   126M|      }
  132|   126M|   }

