LLVMFuzzerTestOneInput:
    9|  3.47k|{
   10|       |   // use a vector with null termination instead of a std::string to avoid
   11|       |   // small string optimization to hide bounds problems
   12|  3.47k|   std::vector<char> buffer{Data, Data + Size};
   13|       |
   14|       |   // non-null terminated
   15|  3.47k|   {
   16|  3.47k|      [[maybe_unused]] auto maybe_smaller = glz::minify_json(buffer);
   17|  3.47k|   }
   18|       |
   19|       |   // null terminated
   20|  3.47k|   {
   21|  3.47k|      buffer.push_back('\0');
   22|  3.47k|      [[maybe_unused]] auto maybe_smaller = glz::minify_json(buffer);
   23|  3.47k|   }
   24|       |
   25|       |   // The comment enabled path is a different scan: read_jsonc_comment only runs here, and it is
   26|       |   // the scanner that has to report an unterminated comment rather than swallow the buffer. Fuzzed
   27|       |   // as its own input because a document rejected by the plain path may be accepted by this one.
   28|  3.47k|   {
   29|  3.47k|      std::vector<char> jsonc{Data, Data + Size};
   30|  3.47k|      [[maybe_unused]] auto maybe_smaller = glz::minify_jsonc(jsonc);
   31|  3.47k|   }
   32|       |
   33|       |   // Only a self-terminating buffer selects the null terminated scan, whose run ends on the
   34|       |   // sentinel rather than on a bound in its loop condition. A vector carrying a trailing NUL does
   35|       |   // not: that NUL is just a byte inside the document.
   36|  3.47k|   {
   37|  3.47k|      std::string jsonc{Data, Data + Size};
   38|  3.47k|      [[maybe_unused]] auto maybe_smaller = glz::minify_jsonc(jsonc);
   39|  3.47k|   }
   40|       |
   41|       |   // Minifying only ever removes bytes, so a bounded output large enough for the input is large
   42|       |   // enough for the result -- and one that is not has to say so rather than be written past.
   43|  3.47k|   {
   44|  3.47k|      std::vector<char> jsonc{Data, Data + Size};
   45|  3.47k|      std::array<char, 64> bounded{};
   46|  3.47k|      [[maybe_unused]] const auto ec = glz::minify_jsonc(jsonc, bounded);
   47|  3.47k|   }
   48|       |
   49|  3.47k|   return 0;
   50|  3.47k|}

_ZN3glz12ensure_spaceINSt3__15arrayIcLm64EEETkNS_10is_contextENS_7contextEEEbRT0_RT_m:
  265|  21.5k|   {
  266|  21.5k|      using Buffer = std::remove_cvref_t<B>;
  267|       |
  268|       |      if constexpr (vector_like<Buffer>) {
  269|       |         if (required > b.size()) [[unlikely]] {
  270|       |            grow_buffer(b, required);
  271|       |         }
  272|       |         return true;
  273|       |      }
  274|  21.5k|      else if constexpr (has_bounded_capacity<Buffer>) {
  275|  21.5k|         if (required > buffer_traits<Buffer>::capacity(b)) [[unlikely]] {
  ------------------
  |  Branch (275:14): [True: 286, False: 21.2k]
  ------------------
  276|    286|            ctx.error = error_code::buffer_overflow;
  277|    286|            return false;
  278|    286|         }
  279|  21.2k|         return true;
  280|       |      }
  281|       |      else {
  282|       |         return true; // Raw pointer or other - trust caller
  283|       |      }
  284|  21.5k|   }
_ZN3glz13buffer_traitsINSt3__15arrayIcLm64EEEE8capacityERKS3_:
  250|  21.5k|      GLZ_ALWAYS_INLINE static constexpr size_t capacity(const std::array<T, N>&) noexcept { return N; }

_ZN3glz14read_iteratorsITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1EEETkNS_10contiguousERNSt3__16vectorIcNS2_9allocatorIcEEEEEEDaOT0_:
   40|  6.95k|   {
   41|  6.95k|      static_assert(sizeof(decltype(*buffer.data())) == 1);
   42|       |
   43|  6.95k|      auto it = reinterpret_cast<const char*>(buffer.data());
   44|  6.95k|      auto end = it + buffer.size();
   45|       |
   46|  6.95k|      return std::pair{it, end};
   47|  6.95k|   }
_ZN3glz14read_iteratorsITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10contiguousERNSt3__16vectorIcNS2_9allocatorIcEEEEEEDaOT0_:
   40|  6.95k|   {
   41|  6.95k|      static_assert(sizeof(decltype(*buffer.data())) == 1);
   42|       |
   43|  6.95k|      auto it = reinterpret_cast<const char*>(buffer.data());
   44|  6.95k|      auto end = it + buffer.size();
   45|       |
   46|  6.95k|      return std::pair{it, end};
   47|  6.95k|   }
_ZN3glz14read_iteratorsITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10contiguousERNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEEDaOT0_:
   40|  3.47k|   {
   41|  3.47k|      static_assert(sizeof(decltype(*buffer.data())) == 1);
   42|       |
   43|  3.47k|      auto it = reinterpret_cast<const char*>(buffer.data());
   44|  3.47k|      auto end = it + buffer.size();
   45|       |
   46|  3.47k|      return std::pair{it, end};
   47|  3.47k|   }

_ZN3glz6detail16read_json_stringITkNS_10is_contextERNS_7contextERPKcS5_EENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEOT_OT0_T1_:
  156|  7.77k|   {
  157|  7.77k|      auto start = it;
  158|  7.77k|      ++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|  7.77k|      const auto* const chunk_limit = (end - it >= 8) ? end - 8 : it - 1;
  ------------------
  |  Branch (162:39): [True: 6.75k, False: 1.01k]
  ------------------
  163|  4.12M|      while (it <= chunk_limit) {
  ------------------
  |  Branch (163:14): [True: 4.12M, False: 1.44k]
  ------------------
  164|  4.12M|         uint64_t chunk;
  165|  4.12M|         std::memcpy(&chunk, it, 8);
  166|       |         if constexpr (std::endian::native == std::endian::big) {
  167|       |            chunk = std::byteswap(chunk);
  168|       |         }
  169|  4.12M|         const uint64_t quote = has_quote(chunk);
  170|  4.12M|         if (quote) {
  ------------------
  |  Branch (170:14): [True: 7.36k, False: 4.11M]
  ------------------
  171|  7.36k|            it += (countr_zero(quote) >> 3);
  172|       |
  173|  7.36k|            auto* prev = it - 1;
  174|  9.15k|            while (*prev == '\\') {
  ------------------
  |  Branch (174:20): [True: 1.78k, False: 7.36k]
  ------------------
  175|  1.78k|               --prev;
  176|  1.78k|            }
  177|  7.36k|            if (size_t(it - prev) % 2) {
  ------------------
  |  Branch (177:17): [True: 6.33k, False: 1.03k]
  ------------------
  178|  6.33k|               ++it; // add quote
  179|  6.33k|               return {start, size_t(it - start)};
  180|  6.33k|            }
  181|  1.03k|            ++it; // skip escaped quote and continue
  182|  1.03k|         }
  183|  4.11M|         else {
  184|  4.11M|            it += 8;
  185|  4.11M|         }
  186|  4.12M|      }
  187|       |
  188|  3.32k|      while (it < end) {
  ------------------
  |  Branch (188:14): [True: 2.68k, False: 638]
  ------------------
  189|  2.68k|         if (*it == '"') {
  ------------------
  |  Branch (189:14): [True: 907, False: 1.77k]
  ------------------
  190|    907|            auto* prev = it - 1;
  191|  2.40k|            while (*prev == '\\') {
  ------------------
  |  Branch (191:20): [True: 1.50k, False: 907]
  ------------------
  192|  1.50k|               --prev;
  193|  1.50k|            }
  194|    907|            if (size_t(it - prev) % 2) {
  ------------------
  |  Branch (194:17): [True: 802, False: 105]
  ------------------
  195|    802|               ++it; // add quote
  196|    802|               return {start, size_t(it - start)};
  197|    802|            }
  198|    907|         }
  199|  1.88k|         ++it;
  200|  1.88k|      }
  201|       |
  202|    638|      ctx.error = error_code::unexpected_end;
  203|    638|      return {};
  204|  1.44k|   }
_ZN3glz6detail10emit_bytesILb0ENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEETkNS_10is_contextENS_7contextENS2_17basic_string_viewIcS5_EEEEbRT1_RT0_RmRKT2_:
   91|  15.1k|   {
   92|  15.1k|      using T = std::remove_cvref_t<decltype(x)>;
   93|       |      if constexpr (byte_sized<T>) {
   94|       |         if constexpr (has_bounded_capacity<B>) {
   95|       |            if (not ensure_space(ctx, b, ix + 1)) [[unlikely]] {
   96|       |               return false;
   97|       |            }
   98|       |         }
   99|       |         dump<Checked>(x, b, ix);
  100|       |      }
  101|  15.1k|      else {
  102|  15.1k|         const sv s = [&] {
  103|  15.1k|            if constexpr (std::is_bounded_array_v<T>) {
  104|  15.1k|               return sv{x, std::extent_v<T> - 1}; // a string literal, without its terminator
  105|  15.1k|            }
  106|  15.1k|            else {
  107|  15.1k|               return sv{x};
  108|  15.1k|            }
  109|  15.1k|         }();
  110|       |         if constexpr (has_bounded_capacity<B>) {
  111|       |            if (not ensure_space(ctx, b, ix + s.size())) [[unlikely]] {
  112|       |               return false;
  113|       |            }
  114|       |         }
  115|  15.1k|         dump<Checked>(s, b, ix);
  116|  15.1k|      }
  117|  15.1k|      return true;
  118|  15.1k|   }
_ZZN3glz6detail10emit_bytesILb0ENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEETkNS_10is_contextENS_7contextENS2_17basic_string_viewIcS5_EEEEbRT1_RT0_RmRKT2_ENKUlvE_clEv:
  102|  15.1k|         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|  15.1k|            else {
  107|  15.1k|               return sv{x};
  108|  15.1k|            }
  109|  15.1k|         }();
_ZN3glz6detail10emit_bytesILb0ENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEETkNS_10is_contextENS_7contextEcEEbRT1_RT0_RmRKT2_:
   91|   105k|   {
   92|   105k|      using T = std::remove_cvref_t<decltype(x)>;
   93|   105k|      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|   105k|         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|   105k|      return true;
  118|   105k|   }
_ZN3glz6detail16read_json_numberILb0ERPKcS3_EENSt3__117basic_string_viewIcNS5_11char_traitsIcEEEEOT0_T1_:
  304|  5.13k|   {
  305|  5.13k|      auto start = it;
  306|       |      if constexpr (null_terminated) {
  307|       |         while (numeric_table[uint8_t(*it)]) {
  308|       |            ++it;
  309|       |         }
  310|       |      }
  311|  5.13k|      else {
  312|  9.74M|         while ((it < end) && numeric_table[uint8_t(*it)]) {
  ------------------
  |  Branch (312:17): [True: 9.74M, False: 148]
  |  Branch (312:31): [True: 9.74M, False: 4.98k]
  ------------------
  313|  9.74M|            ++it;
  314|  9.74M|         }
  315|  5.13k|      }
  316|  5.13k|      return {start, size_t(it - start)};
  317|  5.13k|   }
_ZN3glz6detail13match_literalITnNS_14string_literalEXtlNS2_ILm5EEEtlA5_cLc110ELc117ELc108ELc108EEEETkNS_10is_contextERNS_7contextERPKcS8_EEbOT0_OT1_T2_:
  130|  4.12k|   {
  131|  4.12k|      static constexpr auto s = literal.sv();
  132|  4.12k|      if (end - it < std::ptrdiff_t(s.size())) [[unlikely]] {
  ------------------
  |  Branch (132:11): [True: 118, False: 4.00k]
  ------------------
  133|    118|         ctx.error = error_code::unexpected_end;
  134|    118|         return false;
  135|    118|      }
  136|  4.00k|      if (not comparitor<s>(it)) [[unlikely]] {
  ------------------
  |  Branch (136:11): [True: 488, False: 3.51k]
  ------------------
  137|    488|         ctx.error = error_code::syntax_error;
  138|    488|         return false;
  139|    488|      }
  140|  3.51k|      it += s.size();
  141|  3.51k|      return true;
  142|  4.00k|   }
_ZN3glz6detail10emit_bytesILb0ENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEETkNS_10is_contextENS_7contextEA5_cEEbRT1_RT0_RmRKT2_:
   91|  6.34k|   {
   92|  6.34k|      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|  6.34k|      else {
  102|  6.34k|         const sv s = [&] {
  103|  6.34k|            if constexpr (std::is_bounded_array_v<T>) {
  104|  6.34k|               return sv{x, std::extent_v<T> - 1}; // a string literal, without its terminator
  105|  6.34k|            }
  106|  6.34k|            else {
  107|  6.34k|               return sv{x};
  108|  6.34k|            }
  109|  6.34k|         }();
  110|       |         if constexpr (has_bounded_capacity<B>) {
  111|       |            if (not ensure_space(ctx, b, ix + s.size())) [[unlikely]] {
  112|       |               return false;
  113|       |            }
  114|       |         }
  115|  6.34k|         dump<Checked>(s, b, ix);
  116|  6.34k|      }
  117|  6.34k|      return true;
  118|  6.34k|   }
_ZZN3glz6detail10emit_bytesILb0ENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEETkNS_10is_contextENS_7contextEA5_cEEbRT1_RT0_RmRKT2_ENKUlvE_clEv:
  102|  6.34k|         const sv s = [&] {
  103|  6.34k|            if constexpr (std::is_bounded_array_v<T>) {
  104|  6.34k|               return sv{x, std::extent_v<T> - 1}; // a string literal, without its terminator
  105|       |            }
  106|       |            else {
  107|       |               return sv{x};
  108|       |            }
  109|  6.34k|         }();
_ZN3glz6detail13match_literalITnNS_14string_literalEXtlNS2_ILm5EEEtlA5_cLc116ELc114ELc117ELc101EEEETkNS_10is_contextERNS_7contextERPKcS8_EEbOT0_OT1_T2_:
  130|  4.03k|   {
  131|  4.03k|      static constexpr auto s = literal.sv();
  132|  4.03k|      if (end - it < std::ptrdiff_t(s.size())) [[unlikely]] {
  ------------------
  |  Branch (132:11): [True: 108, False: 3.92k]
  ------------------
  133|    108|         ctx.error = error_code::unexpected_end;
  134|    108|         return false;
  135|    108|      }
  136|  3.92k|      if (not comparitor<s>(it)) [[unlikely]] {
  ------------------
  |  Branch (136:11): [True: 457, False: 3.46k]
  ------------------
  137|    457|         ctx.error = error_code::syntax_error;
  138|    457|         return false;
  139|    457|      }
  140|  3.46k|      it += s.size();
  141|  3.46k|      return true;
  142|  3.92k|   }
_ZN3glz6detail13match_literalITnNS_14string_literalEXtlNS2_ILm6EEEtlA6_cLc102ELc97ELc108ELc115ELc101EEEETkNS_10is_contextERNS_7contextERPKcS8_EEbOT0_OT1_T2_:
  130|  3.11k|   {
  131|  3.11k|      static constexpr auto s = literal.sv();
  132|  3.11k|      if (end - it < std::ptrdiff_t(s.size())) [[unlikely]] {
  ------------------
  |  Branch (132:11): [True: 180, False: 2.93k]
  ------------------
  133|    180|         ctx.error = error_code::unexpected_end;
  134|    180|         return false;
  135|    180|      }
  136|  2.93k|      if (not comparitor<s>(it)) [[unlikely]] {
  ------------------
  |  Branch (136:11): [True: 499, False: 2.43k]
  ------------------
  137|    499|         ctx.error = error_code::syntax_error;
  138|    499|         return false;
  139|    499|      }
  140|  2.43k|      it += s.size();
  141|  2.43k|      return true;
  142|  2.93k|   }
_ZN3glz6detail10emit_bytesILb0ENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEETkNS_10is_contextENS_7contextEA6_cEEbRT1_RT0_RmRKT2_:
   91|  2.21k|   {
   92|  2.21k|      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|  2.21k|      else {
  102|  2.21k|         const sv s = [&] {
  103|  2.21k|            if constexpr (std::is_bounded_array_v<T>) {
  104|  2.21k|               return sv{x, std::extent_v<T> - 1}; // a string literal, without its terminator
  105|  2.21k|            }
  106|  2.21k|            else {
  107|  2.21k|               return sv{x};
  108|  2.21k|            }
  109|  2.21k|         }();
  110|       |         if constexpr (has_bounded_capacity<B>) {
  111|       |            if (not ensure_space(ctx, b, ix + s.size())) [[unlikely]] {
  112|       |               return false;
  113|       |            }
  114|       |         }
  115|  2.21k|         dump<Checked>(s, b, ix);
  116|  2.21k|      }
  117|  2.21k|      return true;
  118|  2.21k|   }
_ZZN3glz6detail10emit_bytesILb0ENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEETkNS_10is_contextENS_7contextEA6_cEEbRT1_RT0_RmRKT2_ENKUlvE_clEv:
  102|  2.21k|         const sv s = [&] {
  103|  2.21k|            if constexpr (std::is_bounded_array_v<T>) {
  104|  2.21k|               return sv{x, std::extent_v<T> - 1}; // a string literal, without its terminator
  105|       |            }
  106|       |            else {
  107|       |               return sv{x};
  108|       |            }
  109|  2.21k|         }();
_ZN3glz6detail18read_jsonc_commentITkNS_10is_contextERNS_7contextERPKcS5_EENS0_13jsonc_commentEOT_OT0_T1_:
  227|  6.30k|   {
  228|  6.30k|      const auto start = it;
  229|  6.30k|      ++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|  6.30k|      if (it == end) [[unlikely]] {
  ------------------
  |  Branch (234:11): [True: 22, False: 6.28k]
  ------------------
  235|     22|         ctx.error = error_code::unexpected_end;
  236|     22|         return {};
  237|     22|      }
  238|       |
  239|  6.28k|      if (*it == '/') {
  ------------------
  |  Branch (239:11): [True: 2.46k, False: 3.81k]
  ------------------
  240|  2.46k|         ++it; // past the second '/'
  241|  12.6k|         while (it != end && *it != '\n' && *it != '\r') {
  ------------------
  |  Branch (241:17): [True: 12.5k, False: 113]
  |  Branch (241:30): [True: 11.3k, False: 1.20k]
  |  Branch (241:45): [True: 10.1k, False: 1.14k]
  ------------------
  242|  10.1k|            ++it;
  243|  10.1k|         }
  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|  2.46k|         return {sv{start, size_t(it - start)}, true};
  249|  2.46k|      }
  250|       |
  251|  3.81k|      if (*it != '*') [[unlikely]] {
  ------------------
  |  Branch (251:11): [True: 74, False: 3.74k]
  ------------------
  252|     74|         ctx.error = error_code::expected_end_comment;
  253|     74|         return {};
  254|     74|      }
  255|  3.74k|      ++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|  3.74k|      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|  3.74k|      const auto* const chunk_limit = (end - it >= 8) ? end - 8 : it - 1;
  ------------------
  |  Branch (266:39): [True: 3.52k, False: 219]
  ------------------
  267|  3.12M|      while (it <= chunk_limit) {
  ------------------
  |  Branch (267:14): [True: 3.12M, False: 499]
  ------------------
  268|  3.12M|         uint64_t chunk;
  269|  3.12M|         std::memcpy(&chunk, it, 8);
  270|       |         if constexpr (std::endian::native == std::endian::big) {
  271|       |            chunk = std::byteswap(chunk);
  272|       |         }
  273|  3.12M|         const uint64_t slash = has_char<'/'>(chunk);
  274|  3.12M|         if (slash) {
  ------------------
  |  Branch (274:14): [True: 26.6k, False: 3.09M]
  ------------------
  275|  26.6k|            it += (countr_zero(slash) >> 3);
  276|       |
  277|  26.6k|            if (it > content && it[-1] == '*') {
  ------------------
  |  Branch (277:17): [True: 25.2k, False: 1.42k]
  |  Branch (277:33): [True: 3.24k, False: 22.0k]
  ------------------
  278|  3.24k|               ++it; // add slash
  279|  3.24k|               return {sv{start, size_t(it - start)}, false};
  280|  3.24k|            }
  281|       |            // skip slash and continue
  282|  23.4k|            ++it;
  283|  23.4k|         }
  284|  3.09M|         else {
  285|  3.09M|            it += 8;
  286|  3.09M|         }
  287|  3.12M|      }
  288|       |
  289|       |      // Tail end of buffer. Should be rare we even get here
  290|  1.91k|      while (it < end) {
  ------------------
  |  Branch (290:14): [True: 1.61k, False: 301]
  ------------------
  291|  1.61k|         if (it > content && it[-1] == '*' && *it == '/') {
  ------------------
  |  Branch (291:14): [True: 1.40k, False: 210]
  |  Branch (291:30): [True: 320, False: 1.08k]
  |  Branch (291:47): [True: 198, False: 122]
  ------------------
  292|    198|            ++it; // add slash
  293|    198|            return {sv{start, size_t(it - start)}, false};
  294|    198|         }
  295|  1.42k|         ++it;
  296|  1.42k|      }
  297|       |
  298|    301|      ctx.error = error_code::expected_end_comment;
  299|    301|      return {};
  300|    499|   }
_ZN3glz6detail16read_json_numberILb1ERPKcS3_EENSt3__117basic_string_viewIcNS5_11char_traitsIcEEEEOT0_T1_:
  304|  1.46k|   {
  305|  1.46k|      auto start = it;
  306|  1.46k|      if constexpr (null_terminated) {
  307|  2.43M|         while (numeric_table[uint8_t(*it)]) {
  ------------------
  |  Branch (307:17): [True: 2.43M, False: 1.46k]
  ------------------
  308|  2.43M|            ++it;
  309|  2.43M|         }
  310|       |      }
  311|       |      else {
  312|       |         while ((it < end) && numeric_table[uint8_t(*it)]) {
  313|       |            ++it;
  314|       |         }
  315|       |      }
  316|  1.46k|      return {start, size_t(it - start)};
  317|  1.46k|   }
_ZN3glz6detail10emit_bytesILb0ENSt3__15arrayIcLm64EEETkNS_10is_contextENS_7contextENS2_17basic_string_viewIcNS2_11char_traitsIcEEEEEEbRT1_RT0_RmRKT2_:
   91|  1.98k|   {
   92|  1.98k|      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|  1.98k|      else {
  102|  1.98k|         const sv s = [&] {
  103|  1.98k|            if constexpr (std::is_bounded_array_v<T>) {
  104|  1.98k|               return sv{x, std::extent_v<T> - 1}; // a string literal, without its terminator
  105|  1.98k|            }
  106|  1.98k|            else {
  107|  1.98k|               return sv{x};
  108|  1.98k|            }
  109|  1.98k|         }();
  110|  1.98k|         if constexpr (has_bounded_capacity<B>) {
  111|  1.98k|            if (not ensure_space(ctx, b, ix + s.size())) [[unlikely]] {
  ------------------
  |  Branch (111:17): [True: 134, False: 1.85k]
  ------------------
  112|    134|               return false;
  113|    134|            }
  114|  1.98k|         }
  115|  1.85k|         dump<Checked>(s, b, ix);
  116|  1.98k|      }
  117|      0|      return true;
  118|  1.98k|   }
_ZZN3glz6detail10emit_bytesILb0ENSt3__15arrayIcLm64EEETkNS_10is_contextENS_7contextENS2_17basic_string_viewIcNS2_11char_traitsIcEEEEEEbRT1_RT0_RmRKT2_ENKUlvE_clEv:
  102|  1.98k|         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|  1.98k|            else {
  107|  1.98k|               return sv{x};
  108|  1.98k|            }
  109|  1.98k|         }();
_ZN3glz6detail10emit_bytesILb0ENSt3__15arrayIcLm64EEETkNS_10is_contextENS_7contextEcEEbRT1_RT0_RmRKT2_:
   91|  18.7k|   {
   92|  18.7k|      using T = std::remove_cvref_t<decltype(x)>;
   93|  18.7k|      if constexpr (byte_sized<T>) {
   94|  18.7k|         if constexpr (has_bounded_capacity<B>) {
   95|  18.7k|            if (not ensure_space(ctx, b, ix + 1)) [[unlikely]] {
  ------------------
  |  Branch (95:17): [True: 119, False: 18.6k]
  ------------------
   96|    119|               return false;
   97|    119|            }
   98|  18.7k|         }
   99|  18.6k|         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|      0|      return true;
  118|  18.7k|   }
_ZN3glz6detail10emit_bytesILb0ENSt3__15arrayIcLm64EEETkNS_10is_contextENS_7contextEA5_cEEbRT1_RT0_RmRKT2_:
   91|    635|   {
   92|    635|      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|    635|      else {
  102|    635|         const sv s = [&] {
  103|    635|            if constexpr (std::is_bounded_array_v<T>) {
  104|    635|               return sv{x, std::extent_v<T> - 1}; // a string literal, without its terminator
  105|    635|            }
  106|    635|            else {
  107|    635|               return sv{x};
  108|    635|            }
  109|    635|         }();
  110|    635|         if constexpr (has_bounded_capacity<B>) {
  111|    635|            if (not ensure_space(ctx, b, ix + s.size())) [[unlikely]] {
  ------------------
  |  Branch (111:17): [True: 24, False: 611]
  ------------------
  112|     24|               return false;
  113|     24|            }
  114|    635|         }
  115|    611|         dump<Checked>(s, b, ix);
  116|    635|      }
  117|      0|      return true;
  118|    635|   }
_ZZN3glz6detail10emit_bytesILb0ENSt3__15arrayIcLm64EEETkNS_10is_contextENS_7contextEA5_cEEbRT1_RT0_RmRKT2_ENKUlvE_clEv:
  102|    635|         const sv s = [&] {
  103|    635|            if constexpr (std::is_bounded_array_v<T>) {
  104|    635|               return sv{x, std::extent_v<T> - 1}; // a string literal, without its terminator
  105|       |            }
  106|       |            else {
  107|       |               return sv{x};
  108|       |            }
  109|    635|         }();
_ZN3glz6detail10emit_bytesILb0ENSt3__15arrayIcLm64EEETkNS_10is_contextENS_7contextEA6_cEEbRT1_RT0_RmRKT2_:
   91|    221|   {
   92|    221|      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|    221|      else {
  102|    221|         const sv s = [&] {
  103|    221|            if constexpr (std::is_bounded_array_v<T>) {
  104|    221|               return sv{x, std::extent_v<T> - 1}; // a string literal, without its terminator
  105|    221|            }
  106|    221|            else {
  107|    221|               return sv{x};
  108|    221|            }
  109|    221|         }();
  110|    221|         if constexpr (has_bounded_capacity<B>) {
  111|    221|            if (not ensure_space(ctx, b, ix + s.size())) [[unlikely]] {
  ------------------
  |  Branch (111:17): [True: 9, False: 212]
  ------------------
  112|      9|               return false;
  113|      9|            }
  114|    221|         }
  115|    212|         dump<Checked>(s, b, ix);
  116|    221|      }
  117|      0|      return true;
  118|    221|   }
_ZZN3glz6detail10emit_bytesILb0ENSt3__15arrayIcLm64EEETkNS_10is_contextENS_7contextEA6_cEEbRT1_RT0_RmRKT2_ENKUlvE_clEv:
  102|    221|         const sv s = [&] {
  103|    221|            if constexpr (std::is_bounded_array_v<T>) {
  104|    221|               return sv{x, std::extent_v<T> - 1}; // a string literal, without its terminator
  105|       |            }
  106|       |            else {
  107|       |               return sv{x};
  108|       |            }
  109|    221|         }();

_ZN3glz11minify_jsonITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1EEETkNS_9resizableENSt3__16vectorIcNS2_9allocatorIcEEEEEENS2_12basic_stringIcNS2_11char_traitsIcEES5_EERT0_:
  288|  6.95k|   {
  289|  6.95k|      context ctx{};
  290|  6.95k|      std::string out{};
  291|  6.95k|      detail::minify_json<Opts>(ctx, in, out);
  292|  6.95k|      if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (292:11): [True: 5.91k, False: 1.04k]
  ------------------
  293|  5.91k|         return {}; // an incomplete result is not a document; see above
  294|  5.91k|      }
  295|  1.04k|      return out;
  296|  6.95k|   }
_ZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1EEERNSt3__16vectorIcNS3_9allocatorIcEEEETkNS_13output_bufferERNS3_12basic_stringIcNS3_11char_traitsIcEES6_EETkNS_10is_contextERNS_7contextEQaa10contiguousIT0_E9resizableISG_EEEmOT2_OSG_OT1_:
  230|  6.95k|      {
  231|  6.95k|         if (in.size() == 0) {
  ------------------
  |  Branch (231:14): [True: 0, False: 6.95k]
  ------------------
  232|      0|            return 0;
  233|      0|         }
  234|       |
  235|  6.95k|         if constexpr (resizable<Out>) {
  236|       |            // Minifying only ever removes bytes, so this is room enough for whatever comes out.
  237|       |            // A bounded output is checked per write instead; see the scan above for why.
  238|  6.95k|            out.resize(in.size() + 2 * padding_bytes);
  239|  6.95k|         }
  240|  6.95k|         size_t ix = 0;
  241|  6.95k|         auto [it, end] = read_iterators<Opts>(in);
  242|  6.95k|         if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (242:14): [True: 0, False: 6.95k]
  ------------------
  243|      0|            return 0;
  244|      0|         }
  245|       |
  246|       |         // The input is no longer grown and shrunk around this: everything the scan below reads
  247|       |         // through -- read_json_string, read_json_number, skip_matching_ws -- bounds its own loads
  248|       |         // against `end`, so there is nothing left for the padding to protect.
  249|       |         if constexpr (self_terminating<In>) {
  250|       |            minify_json<opt_true<Opts, &opts::null_terminated>>(ctx, it, end, out, ix);
  251|       |         }
  252|  6.95k|         else {
  253|  6.95k|            minify_json<opt_false<Opts, &opts::null_terminated>>(ctx, it, end, out, ix);
  254|  6.95k|         }
  255|       |
  256|  6.95k|         if constexpr (resizable<Out>) {
  257|  6.95k|            out.resize(ix);
  258|  6.95k|         }
  259|  6.95k|         return ix;
  260|  6.95k|      }
_ZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_:
   18|  6.95k|      {
   19|  6.95k|         using enum json_type;
   20|       |
   21|       |         // Every write below goes through this, and the dump it makes is unchecked: the caller's
   22|       |         // one-shot sizing covers a resizable destination, because minifying only ever removes
   23|       |         // bytes, so the input's length is room enough.
   24|       |         //
   25|       |         // A bounded destination cannot be grown, and asking it for the input's length up front
   26|       |         // refuses a buffer that fits the result -- sizing the output to the minified length is the
   27|       |         // obvious thing to do, and `{ "a" : 1 }` into a 7 byte buffer has to work. So each write
   28|       |         // asks for exactly what it stores instead; see emit_bytes for where that count comes from.
   29|       |         // None of it survives for a resizable destination, which keeps the unchecked dumps and
   30|       |         // nothing more.
   31|  6.95k|         const auto put = [&](const auto& x) { return emit_bytes<false>(ctx, b, ix, x); };
   32|       |
   33|  6.95k|         auto ws_start = it;
   34|  6.95k|         uint64_t ws_size{};
   35|       |
   36|  6.95k|         auto skip_expected_whitespace = [&] {
   37|  6.95k|            auto new_ws_start = it;
   38|  6.95k|            if (ws_size && std::ptrdiff_t(ws_size) < end - it) [[likely]] {
   39|  6.95k|               skip_matching_ws(ws_start, it, ws_size);
   40|  6.95k|            }
   41|       |
   42|  6.95k|            if constexpr (Opts.null_terminated) {
   43|  6.95k|               while (whitespace_table[uint8_t(*it)]) {
   44|  6.95k|                  ++it;
   45|  6.95k|               }
   46|  6.95k|            }
   47|  6.95k|            else {
   48|  6.95k|               while ((it < end) && whitespace_table[uint8_t(*it)]) {
   49|  6.95k|                  ++it;
   50|  6.95k|               }
   51|  6.95k|            }
   52|  6.95k|            ws_start = new_ws_start;
   53|  6.95k|            ws_size = size_t(it - new_ws_start);
   54|  6.95k|         };
   55|       |
   56|  6.95k|         auto skip_whitespace = [&] {
   57|  6.95k|            if constexpr (Opts.null_terminated) {
   58|  6.95k|               while (whitespace_table[uint8_t(*it)]) {
   59|  6.95k|                  ++it;
   60|  6.95k|               }
   61|  6.95k|            }
   62|  6.95k|            else {
   63|  6.95k|               while ((it < end) && whitespace_table[uint8_t(*it)]) {
   64|  6.95k|                  ++it;
   65|  6.95k|               }
   66|  6.95k|            }
   67|  6.95k|         };
   68|       |
   69|  6.95k|         skip_whitespace();
   70|       |
   71|  69.3k|         while ([&]() -> bool {
  ------------------
  |  Branch (71:17): [True: 68.3k, False: 1.04k]
  ------------------
   72|  69.3k|            if constexpr (Opts.null_terminated) {
   73|  69.3k|               return true;
   74|  69.3k|            }
   75|  69.3k|            else {
   76|  69.3k|               return it < end;
   77|  69.3k|            }
   78|  69.3k|         }()) {
   79|  68.3k|            switch (json_types[uint8_t(*it)]) {
   80|  3.23k|            case String: {
  ------------------
  |  Branch (80:13): [True: 3.23k, False: 65.1k]
  ------------------
   81|  3.23k|               const auto value = read_json_string(ctx, it, end);
   82|  3.23k|               if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (82:20): [True: 244, False: 2.98k]
  ------------------
   83|    244|                  return;
   84|    244|               }
   85|       |               // non-empty: the scanner reports an empty view as an error
   86|  2.98k|               if (not put(value)) [[unlikely]] {
  ------------------
  |  Branch (86:20): [True: 0, False: 2.98k]
  ------------------
   87|      0|                  return;
   88|      0|               }
   89|  2.98k|               skip_whitespace();
   90|  2.98k|               break;
   91|  2.98k|            }
   92|  15.6k|            case Comma: {
  ------------------
  |  Branch (92:13): [True: 15.6k, False: 52.6k]
  ------------------
   93|  15.6k|               if (not put(',')) [[unlikely]] {
  ------------------
  |  Branch (93:20): [True: 0, False: 15.6k]
  ------------------
   94|      0|                  return;
   95|      0|               }
   96|  15.6k|               ++it;
   97|  15.6k|               skip_expected_whitespace();
   98|  15.6k|               break;
   99|  15.6k|            }
  100|  2.86k|            case Number: {
  ------------------
  |  Branch (100:13): [True: 2.86k, False: 65.4k]
  ------------------
  101|  2.86k|               const auto value = read_json_number<Opts.null_terminated>(it, end);
  102|       |               // non-empty: a Number match is one valid character
  103|  2.86k|               if (not put(value)) [[unlikely]] {
  ------------------
  |  Branch (103:20): [True: 0, False: 2.86k]
  ------------------
  104|      0|                  return;
  105|      0|               }
  106|  2.86k|               skip_whitespace();
  107|  2.86k|               break;
  108|  2.86k|            }
  109|  2.92k|            case Colon: {
  ------------------
  |  Branch (109:13): [True: 2.92k, False: 65.4k]
  ------------------
  110|  2.92k|               if (not put(':')) [[unlikely]] {
  ------------------
  |  Branch (110:20): [True: 0, False: 2.92k]
  ------------------
  111|      0|                  return;
  112|      0|               }
  113|  2.92k|               ++it;
  114|  2.92k|               skip_whitespace();
  115|  2.92k|               break;
  116|  2.92k|            }
  117|  12.2k|            case Array_Start: {
  ------------------
  |  Branch (117:13): [True: 12.2k, False: 56.0k]
  ------------------
  118|  12.2k|               if (not put('[')) [[unlikely]] {
  ------------------
  |  Branch (118:20): [True: 0, False: 12.2k]
  ------------------
  119|      0|                  return;
  120|      0|               }
  121|  12.2k|               ++it;
  122|  12.2k|               skip_expected_whitespace();
  123|  12.2k|               break;
  124|  12.2k|            }
  125|  2.54k|            case Array_End: {
  ------------------
  |  Branch (125:13): [True: 2.54k, False: 65.7k]
  ------------------
  126|  2.54k|               if (not put(']')) [[unlikely]] {
  ------------------
  |  Branch (126:20): [True: 0, False: 2.54k]
  ------------------
  127|      0|                  return;
  128|      0|               }
  129|  2.54k|               ++it;
  130|  2.54k|               skip_whitespace();
  131|  2.54k|               break;
  132|  2.54k|            }
  133|  1.84k|            case Null: {
  ------------------
  |  Branch (133:13): [True: 1.84k, False: 66.4k]
  ------------------
  134|       |               // The type table matched on the first byte alone; see match_literal for why writing
  135|       |               // the literal from the writer's own spelling needs the rest of it checked. Stepping
  136|       |               // over it unchecked also puts `it` past `end`, and from there the loop goes on
  137|       |               // minifying whatever follows the document into an output sized for the document.
  138|  1.84k|               if (not match_literal<"null">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (138:20): [True: 246, False: 1.59k]
  ------------------
  139|    246|                  return;
  140|    246|               }
  141|  1.59k|               if (not put("null")) [[unlikely]] {
  ------------------
  |  Branch (141:20): [True: 0, False: 1.59k]
  ------------------
  142|      0|                  return;
  143|      0|               }
  144|  1.59k|               skip_whitespace();
  145|  1.59k|               break;
  146|  1.59k|            }
  147|  3.18k|            case Bool: {
  ------------------
  |  Branch (147:13): [True: 3.18k, False: 65.1k]
  ------------------
  148|  3.18k|               if (*it == 't') {
  ------------------
  |  Branch (148:20): [True: 1.80k, False: 1.37k]
  ------------------
  149|  1.80k|                  if (not match_literal<"true">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (149:23): [True: 232, False: 1.57k]
  ------------------
  150|    232|                     return;
  151|    232|                  }
  152|  1.57k|                  if (not put("true")) [[unlikely]] {
  ------------------
  |  Branch (152:23): [True: 0, False: 1.57k]
  ------------------
  153|      0|                     return;
  154|      0|                  }
  155|  1.57k|                  skip_whitespace();
  156|  1.57k|                  break;
  157|  1.57k|               }
  158|  1.37k|               else {
  159|  1.37k|                  if (not match_literal<"false">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (159:23): [True: 274, False: 1.10k]
  ------------------
  160|    274|                     return;
  161|    274|                  }
  162|  1.10k|                  if (not put("false")) [[unlikely]] {
  ------------------
  |  Branch (162:23): [True: 0, False: 1.10k]
  ------------------
  163|      0|                     return;
  164|      0|                  }
  165|  1.10k|                  skip_whitespace();
  166|  1.10k|                  break;
  167|  1.10k|               }
  168|  3.18k|            }
  169|  15.7k|            case Object_Start: {
  ------------------
  |  Branch (169:13): [True: 15.7k, False: 52.5k]
  ------------------
  170|  15.7k|               if (not put('{')) [[unlikely]] {
  ------------------
  |  Branch (170:20): [True: 0, False: 15.7k]
  ------------------
  171|      0|                  return;
  172|      0|               }
  173|  15.7k|               ++it;
  174|  15.7k|               skip_expected_whitespace();
  175|  15.7k|               break;
  176|  15.7k|            }
  177|  3.07k|            case Object_End: {
  ------------------
  |  Branch (177:13): [True: 3.07k, False: 65.2k]
  ------------------
  178|  3.07k|               if (not put('}')) [[unlikely]] {
  ------------------
  |  Branch (178:20): [True: 0, False: 3.07k]
  ------------------
  179|      0|                  return;
  180|      0|               }
  181|  3.07k|               ++it;
  182|  3.07k|               skip_whitespace();
  183|  3.07k|               break;
  184|  3.07k|            }
  185|    566|            case Comment: {
  ------------------
  |  Branch (185:13): [True: 566, False: 67.7k]
  ------------------
  186|       |               if constexpr (Opts.comments) {
  187|       |                  const auto comment = read_jsonc_comment(ctx, it, end);
  188|       |                  if (bool(ctx.error)) [[unlikely]] {
  189|       |                     return;
  190|       |                  }
  191|       |                  // A line comment is dropped rather than written out. Minifying is what removes
  192|       |                  // the newline that ends it, and a line comment with no line break behind it
  193|       |                  // comments out the whole rest of the output.
  194|       |                  if (not comment.line) {
  195|       |                     // non-empty: an empty view comes with an error
  196|       |                     if (not put(comment.text)) [[unlikely]] {
  197|       |                        return;
  198|       |                     }
  199|       |                  }
  200|       |                  skip_whitespace();
  201|       |                  break;
  202|       |               }
  203|    566|               else {
  204|    566|                  [[fallthrough]];
  205|    566|               }
  206|    566|            }
  207|  4.91k|            [[unlikely]] default: {
  ------------------
  |  Branch (207:26): [True: 4.35k, False: 63.9k]
  ------------------
  208|       |               // A null terminated run carries no bound in its loop condition, so it ends here, on
  209|       |               // the terminator, which is not a JSON token. Reaching it is the end of the document
  210|       |               // rather than an error -- unclassified is how the type table reports both, and
  211|       |               // without this the minifier left syntax_error behind on every input it was ever
  212|       |               // given, valid or not, which is what made its error not worth returning.
  213|       |               if constexpr (Opts.null_terminated) {
  214|       |                  if (it >= end) {
  215|       |                     return;
  216|       |                  }
  217|       |               }
  218|  4.91k|               ctx.error = error_code::syntax_error;
  219|  4.91k|               return;
  220|    566|            }
  221|  68.3k|            }
  222|  68.3k|         }
  223|  6.95k|      }
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlvE0_clEv:
   56|  25.6k|         auto skip_whitespace = [&] {
   57|       |            if constexpr (Opts.null_terminated) {
   58|       |               while (whitespace_table[uint8_t(*it)]) {
   59|       |                  ++it;
   60|       |               }
   61|       |            }
   62|  25.6k|            else {
   63|   260k|               while ((it < end) && whitespace_table[uint8_t(*it)]) {
  ------------------
  |  Branch (63:23): [True: 259k, False: 430]
  |  Branch (63:37): [True: 234k, False: 25.1k]
  ------------------
   64|   234k|                  ++it;
   65|   234k|               }
   66|  25.6k|            }
   67|  25.6k|         };
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlvE1_clEv:
   71|  69.3k|         while ([&]() -> bool {
   72|       |            if constexpr (Opts.null_terminated) {
   73|       |               return true;
   74|       |            }
   75|  69.3k|            else {
   76|  69.3k|               return it < end;
   77|  69.3k|            }
   78|  69.3k|         }()) {
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clINS8_17basic_string_viewIcSB_EEEEDaSS_:
   31|  5.85k|         const auto put = [&](const auto& x) { return emit_bytes<false>(ctx, b, ix, x); };
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIcEEDaSS_:
   31|  52.2k|         const auto put = [&](const auto& x) { return emit_bytes<false>(ctx, b, ix, x); };
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlvE_clEv:
   36|  43.7k|         auto skip_expected_whitespace = [&] {
   37|  43.7k|            auto new_ws_start = it;
   38|  43.7k|            if (ws_size && std::ptrdiff_t(ws_size) < end - it) [[likely]] {
  ------------------
  |  Branch (38:17): [True: 32.0k, False: 11.7k]
  |  Branch (38:28): [True: 30.4k, False: 1.57k]
  ------------------
   39|  30.4k|               skip_matching_ws(ws_start, it, ws_size);
   40|  30.4k|            }
   41|       |
   42|       |            if constexpr (Opts.null_terminated) {
   43|       |               while (whitespace_table[uint8_t(*it)]) {
   44|       |                  ++it;
   45|       |               }
   46|       |            }
   47|  43.7k|            else {
   48|  38.6M|               while ((it < end) && whitespace_table[uint8_t(*it)]) {
  ------------------
  |  Branch (48:23): [True: 38.6M, False: 612]
  |  Branch (48:37): [True: 38.5M, False: 43.1k]
  ------------------
   49|  38.5M|                  ++it;
   50|  38.5M|               }
   51|  43.7k|            }
   52|  43.7k|            ws_start = new_ws_start;
   53|  43.7k|            ws_size = size_t(it - new_ws_start);
   54|  43.7k|         };
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIA5_cEEDaSS_:
   31|  3.16k|         const auto put = [&](const auto& x) { return emit_bytes<false>(ctx, b, ix, x); };
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb0ELb0ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIA6_cEEDaSS_:
   31|  1.10k|         const auto put = [&](const auto& x) { return emit_bytes<false>(ctx, b, ix, x); };
_ZN3glz12minify_jsoncITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1EEETkNS_9resizableENSt3__16vectorIcNS2_9allocatorIcEEEEEENS2_12basic_stringIcNS2_11char_traitsIcEES5_EERT0_:
  308|  3.47k|   {
  309|  3.47k|      context ctx{};
  310|  3.47k|      std::string out{};
  311|  3.47k|      detail::minify_json<opt_true<Opts, &opts::comments>>(ctx, in, out);
  312|  3.47k|      if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (312:11): [True: 2.33k, False: 1.14k]
  ------------------
  313|  2.33k|         return {}; // an incomplete result is not a document; see above
  314|  2.33k|      }
  315|  1.14k|      return out;
  316|  3.47k|   }
_ZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEERNSt3__16vectorIcNS3_9allocatorIcEEEETkNS_13output_bufferERNS3_12basic_stringIcNS3_11char_traitsIcEES6_EETkNS_10is_contextERNS_7contextEQaa10contiguousIT0_E9resizableISG_EEEmOT2_OSG_OT1_:
  230|  3.47k|      {
  231|  3.47k|         if (in.size() == 0) {
  ------------------
  |  Branch (231:14): [True: 0, False: 3.47k]
  ------------------
  232|      0|            return 0;
  233|      0|         }
  234|       |
  235|  3.47k|         if constexpr (resizable<Out>) {
  236|       |            // Minifying only ever removes bytes, so this is room enough for whatever comes out.
  237|       |            // A bounded output is checked per write instead; see the scan above for why.
  238|  3.47k|            out.resize(in.size() + 2 * padding_bytes);
  239|  3.47k|         }
  240|  3.47k|         size_t ix = 0;
  241|  3.47k|         auto [it, end] = read_iterators<Opts>(in);
  242|  3.47k|         if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (242:14): [True: 0, False: 3.47k]
  ------------------
  243|      0|            return 0;
  244|      0|         }
  245|       |
  246|       |         // The input is no longer grown and shrunk around this: everything the scan below reads
  247|       |         // through -- read_json_string, read_json_number, skip_matching_ws -- bounds its own loads
  248|       |         // against `end`, so there is nothing left for the padding to protect.
  249|       |         if constexpr (self_terminating<In>) {
  250|       |            minify_json<opt_true<Opts, &opts::null_terminated>>(ctx, it, end, out, ix);
  251|       |         }
  252|  3.47k|         else {
  253|  3.47k|            minify_json<opt_false<Opts, &opts::null_terminated>>(ctx, it, end, out, ix);
  254|  3.47k|         }
  255|       |
  256|  3.47k|         if constexpr (resizable<Out>) {
  257|  3.47k|            out.resize(ix);
  258|  3.47k|         }
  259|  3.47k|         return ix;
  260|  3.47k|      }
_ZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_:
   18|  3.47k|      {
   19|  3.47k|         using enum json_type;
   20|       |
   21|       |         // Every write below goes through this, and the dump it makes is unchecked: the caller's
   22|       |         // one-shot sizing covers a resizable destination, because minifying only ever removes
   23|       |         // bytes, so the input's length is room enough.
   24|       |         //
   25|       |         // A bounded destination cannot be grown, and asking it for the input's length up front
   26|       |         // refuses a buffer that fits the result -- sizing the output to the minified length is the
   27|       |         // obvious thing to do, and `{ "a" : 1 }` into a 7 byte buffer has to work. So each write
   28|       |         // asks for exactly what it stores instead; see emit_bytes for where that count comes from.
   29|       |         // None of it survives for a resizable destination, which keeps the unchecked dumps and
   30|       |         // nothing more.
   31|  3.47k|         const auto put = [&](const auto& x) { return emit_bytes<false>(ctx, b, ix, x); };
   32|       |
   33|  3.47k|         auto ws_start = it;
   34|  3.47k|         uint64_t ws_size{};
   35|       |
   36|  3.47k|         auto skip_expected_whitespace = [&] {
   37|  3.47k|            auto new_ws_start = it;
   38|  3.47k|            if (ws_size && std::ptrdiff_t(ws_size) < end - it) [[likely]] {
   39|  3.47k|               skip_matching_ws(ws_start, it, ws_size);
   40|  3.47k|            }
   41|       |
   42|  3.47k|            if constexpr (Opts.null_terminated) {
   43|  3.47k|               while (whitespace_table[uint8_t(*it)]) {
   44|  3.47k|                  ++it;
   45|  3.47k|               }
   46|  3.47k|            }
   47|  3.47k|            else {
   48|  3.47k|               while ((it < end) && whitespace_table[uint8_t(*it)]) {
   49|  3.47k|                  ++it;
   50|  3.47k|               }
   51|  3.47k|            }
   52|  3.47k|            ws_start = new_ws_start;
   53|  3.47k|            ws_size = size_t(it - new_ws_start);
   54|  3.47k|         };
   55|       |
   56|  3.47k|         auto skip_whitespace = [&] {
   57|  3.47k|            if constexpr (Opts.null_terminated) {
   58|  3.47k|               while (whitespace_table[uint8_t(*it)]) {
   59|  3.47k|                  ++it;
   60|  3.47k|               }
   61|  3.47k|            }
   62|  3.47k|            else {
   63|  3.47k|               while ((it < end) && whitespace_table[uint8_t(*it)]) {
   64|  3.47k|                  ++it;
   65|  3.47k|               }
   66|  3.47k|            }
   67|  3.47k|         };
   68|       |
   69|  3.47k|         skip_whitespace();
   70|       |
   71|  37.8k|         while ([&]() -> bool {
  ------------------
  |  Branch (71:17): [True: 36.6k, False: 1.14k]
  ------------------
   72|  37.8k|            if constexpr (Opts.null_terminated) {
   73|  37.8k|               return true;
   74|  37.8k|            }
   75|  37.8k|            else {
   76|  37.8k|               return it < end;
   77|  37.8k|            }
   78|  37.8k|         }()) {
   79|  36.6k|            switch (json_types[uint8_t(*it)]) {
   80|  1.81k|            case String: {
  ------------------
  |  Branch (80:13): [True: 1.81k, False: 34.8k]
  ------------------
   81|  1.81k|               const auto value = read_json_string(ctx, it, end);
   82|  1.81k|               if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (82:20): [True: 135, False: 1.68k]
  ------------------
   83|    135|                  return;
   84|    135|               }
   85|       |               // non-empty: the scanner reports an empty view as an error
   86|  1.68k|               if (not put(value)) [[unlikely]] {
  ------------------
  |  Branch (86:20): [True: 0, False: 1.68k]
  ------------------
   87|      0|                  return;
   88|      0|               }
   89|  1.68k|               skip_whitespace();
   90|  1.68k|               break;
   91|  1.68k|            }
   92|  7.92k|            case Comma: {
  ------------------
  |  Branch (92:13): [True: 7.92k, False: 28.7k]
  ------------------
   93|  7.92k|               if (not put(',')) [[unlikely]] {
  ------------------
  |  Branch (93:20): [True: 0, False: 7.92k]
  ------------------
   94|      0|                  return;
   95|      0|               }
   96|  7.92k|               ++it;
   97|  7.92k|               skip_expected_whitespace();
   98|  7.92k|               break;
   99|  7.92k|            }
  100|  1.46k|            case Number: {
  ------------------
  |  Branch (100:13): [True: 1.46k, False: 35.2k]
  ------------------
  101|  1.46k|               const auto value = read_json_number<Opts.null_terminated>(it, end);
  102|       |               // non-empty: a Number match is one valid character
  103|  1.46k|               if (not put(value)) [[unlikely]] {
  ------------------
  |  Branch (103:20): [True: 0, False: 1.46k]
  ------------------
  104|      0|                  return;
  105|      0|               }
  106|  1.46k|               skip_whitespace();
  107|  1.46k|               break;
  108|  1.46k|            }
  109|  1.51k|            case Colon: {
  ------------------
  |  Branch (109:13): [True: 1.51k, False: 35.1k]
  ------------------
  110|  1.51k|               if (not put(':')) [[unlikely]] {
  ------------------
  |  Branch (110:20): [True: 0, False: 1.51k]
  ------------------
  111|      0|                  return;
  112|      0|               }
  113|  1.51k|               ++it;
  114|  1.51k|               skip_whitespace();
  115|  1.51k|               break;
  116|  1.51k|            }
  117|  6.37k|            case Array_Start: {
  ------------------
  |  Branch (117:13): [True: 6.37k, False: 30.3k]
  ------------------
  118|  6.37k|               if (not put('[')) [[unlikely]] {
  ------------------
  |  Branch (118:20): [True: 0, False: 6.37k]
  ------------------
  119|      0|                  return;
  120|      0|               }
  121|  6.37k|               ++it;
  122|  6.37k|               skip_expected_whitespace();
  123|  6.37k|               break;
  124|  6.37k|            }
  125|  1.28k|            case Array_End: {
  ------------------
  |  Branch (125:13): [True: 1.28k, False: 35.4k]
  ------------------
  126|  1.28k|               if (not put(']')) [[unlikely]] {
  ------------------
  |  Branch (126:20): [True: 0, False: 1.28k]
  ------------------
  127|      0|                  return;
  128|      0|               }
  129|  1.28k|               ++it;
  130|  1.28k|               skip_whitespace();
  131|  1.28k|               break;
  132|  1.28k|            }
  133|    921|            case Null: {
  ------------------
  |  Branch (133:13): [True: 921, False: 35.7k]
  ------------------
  134|       |               // The type table matched on the first byte alone; see match_literal for why writing
  135|       |               // the literal from the writer's own spelling needs the rest of it checked. Stepping
  136|       |               // over it unchecked also puts `it` past `end`, and from there the loop goes on
  137|       |               // minifying whatever follows the document into an output sized for the document.
  138|    921|               if (not match_literal<"null">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (138:20): [True: 123, False: 798]
  ------------------
  139|    123|                  return;
  140|    123|               }
  141|    798|               if (not put("null")) [[unlikely]] {
  ------------------
  |  Branch (141:20): [True: 0, False: 798]
  ------------------
  142|      0|                  return;
  143|      0|               }
  144|    798|               skip_whitespace();
  145|    798|               break;
  146|    798|            }
  147|  1.59k|            case Bool: {
  ------------------
  |  Branch (147:13): [True: 1.59k, False: 35.0k]
  ------------------
  148|  1.59k|               if (*it == 't') {
  ------------------
  |  Branch (148:20): [True: 907, False: 692]
  ------------------
  149|    907|                  if (not match_literal<"true">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (149:23): [True: 116, False: 791]
  ------------------
  150|    116|                     return;
  151|    116|                  }
  152|    791|                  if (not put("true")) [[unlikely]] {
  ------------------
  |  Branch (152:23): [True: 0, False: 791]
  ------------------
  153|      0|                     return;
  154|      0|                  }
  155|    791|                  skip_whitespace();
  156|    791|                  break;
  157|    791|               }
  158|    692|               else {
  159|    692|                  if (not match_literal<"false">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (159:23): [True: 138, False: 554]
  ------------------
  160|    138|                     return;
  161|    138|                  }
  162|    554|                  if (not put("false")) [[unlikely]] {
  ------------------
  |  Branch (162:23): [True: 0, False: 554]
  ------------------
  163|      0|                     return;
  164|      0|                  }
  165|    554|                  skip_whitespace();
  166|    554|                  break;
  167|    554|               }
  168|  1.59k|            }
  169|  7.93k|            case Object_Start: {
  ------------------
  |  Branch (169:13): [True: 7.93k, False: 28.7k]
  ------------------
  170|  7.93k|               if (not put('{')) [[unlikely]] {
  ------------------
  |  Branch (170:20): [True: 0, False: 7.93k]
  ------------------
  171|      0|                  return;
  172|      0|               }
  173|  7.93k|               ++it;
  174|  7.93k|               skip_expected_whitespace();
  175|  7.93k|               break;
  176|  7.93k|            }
  177|  1.56k|            case Object_End: {
  ------------------
  |  Branch (177:13): [True: 1.56k, False: 35.1k]
  ------------------
  178|  1.56k|               if (not put('}')) [[unlikely]] {
  ------------------
  |  Branch (178:20): [True: 0, False: 1.56k]
  ------------------
  179|      0|                  return;
  180|      0|               }
  181|  1.56k|               ++it;
  182|  1.56k|               skip_whitespace();
  183|  1.56k|               break;
  184|  1.56k|            }
  185|  2.61k|            case Comment: {
  ------------------
  |  Branch (185:13): [True: 2.61k, False: 34.0k]
  ------------------
  186|  2.61k|               if constexpr (Opts.comments) {
  187|  2.61k|                  const auto comment = read_jsonc_comment(ctx, it, end);
  188|  2.61k|                  if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (188:23): [True: 137, False: 2.47k]
  ------------------
  189|    137|                     return;
  190|    137|                  }
  191|       |                  // A line comment is dropped rather than written out. Minifying is what removes
  192|       |                  // the newline that ends it, and a line comment with no line break behind it
  193|       |                  // comments out the whole rest of the output.
  194|  2.47k|                  if (not comment.line) {
  ------------------
  |  Branch (194:23): [True: 1.52k, False: 949]
  ------------------
  195|       |                     // non-empty: an empty view comes with an error
  196|  1.52k|                     if (not put(comment.text)) [[unlikely]] {
  ------------------
  |  Branch (196:26): [True: 0, False: 1.52k]
  ------------------
  197|      0|                        return;
  198|      0|                     }
  199|  1.52k|                  }
  200|  2.47k|                  skip_whitespace();
  201|  2.47k|                  break;
  202|       |               }
  203|       |               else {
  204|       |                  [[fallthrough]];
  205|       |               }
  206|  2.61k|            }
  207|  4.29k|            [[unlikely]] default: {
  ------------------
  |  Branch (207:26): [True: 1.68k, False: 35.0k]
  ------------------
  208|       |               // A null terminated run carries no bound in its loop condition, so it ends here, on
  209|       |               // the terminator, which is not a JSON token. Reaching it is the end of the document
  210|       |               // rather than an error -- unclassified is how the type table reports both, and
  211|       |               // without this the minifier left syntax_error behind on every input it was ever
  212|       |               // given, valid or not, which is what made its error not worth returning.
  213|       |               if constexpr (Opts.null_terminated) {
  214|       |                  if (it >= end) {
  215|       |                     return;
  216|       |                  }
  217|       |               }
  218|  4.29k|               ctx.error = error_code::syntax_error;
  219|  4.29k|               return;
  220|  2.61k|            }
  221|  36.6k|            }
  222|  36.6k|         }
  223|  3.47k|      }
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlvE0_clEv:
   56|  15.6k|         auto skip_whitespace = [&] {
   57|       |            if constexpr (Opts.null_terminated) {
   58|       |               while (whitespace_table[uint8_t(*it)]) {
   59|       |                  ++it;
   60|       |               }
   61|       |            }
   62|  15.6k|            else {
   63|   135k|               while ((it < end) && whitespace_table[uint8_t(*it)]) {
  ------------------
  |  Branch (63:23): [True: 135k, False: 533]
  |  Branch (63:37): [True: 120k, False: 15.0k]
  ------------------
   64|   120k|                  ++it;
   65|   120k|               }
   66|  15.6k|            }
   67|  15.6k|         };
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlvE1_clEv:
   71|  37.8k|         while ([&]() -> bool {
   72|       |            if constexpr (Opts.null_terminated) {
   73|       |               return true;
   74|       |            }
   75|  37.8k|            else {
   76|  37.8k|               return it < end;
   77|  37.8k|            }
   78|  37.8k|         }()) {
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clINS8_17basic_string_viewIcSB_EEEEDaSS_:
   31|  4.66k|         const auto put = [&](const auto& x) { return emit_bytes<false>(ctx, b, ix, x); };
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIcEEDaSS_:
   31|  26.6k|         const auto put = [&](const auto& x) { return emit_bytes<false>(ctx, b, ix, x); };
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlvE_clEv:
   36|  22.2k|         auto skip_expected_whitespace = [&] {
   37|  22.2k|            auto new_ws_start = it;
   38|  22.2k|            if (ws_size && std::ptrdiff_t(ws_size) < end - it) [[likely]] {
  ------------------
  |  Branch (38:17): [True: 16.0k, False: 6.14k]
  |  Branch (38:28): [True: 14.8k, False: 1.25k]
  ------------------
   39|  14.8k|               skip_matching_ws(ws_start, it, ws_size);
   40|  14.8k|            }
   41|       |
   42|       |            if constexpr (Opts.null_terminated) {
   43|       |               while (whitespace_table[uint8_t(*it)]) {
   44|       |                  ++it;
   45|       |               }
   46|       |            }
   47|  22.2k|            else {
   48|  19.3M|               while ((it < end) && whitespace_table[uint8_t(*it)]) {
  ------------------
  |  Branch (48:23): [True: 19.3M, False: 614]
  |  Branch (48:37): [True: 19.2M, False: 21.6k]
  ------------------
   49|  19.2M|                  ++it;
   50|  19.2M|               }
   51|  22.2k|            }
   52|  22.2k|            ws_start = new_ws_start;
   53|  22.2k|            ws_size = size_t(it - new_ws_start);
   54|  22.2k|         };
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIA5_cEEDaSS_:
   31|  1.58k|         const auto put = [&](const auto& x) { return emit_bytes<false>(ctx, b, ix, x); };
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIA6_cEEDaSS_:
   31|    554|         const auto put = [&](const auto& x) { return emit_bytes<false>(ctx, b, ix, x); };
_ZN3glz12minify_jsoncITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1EEETkNS_9resizableENSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEEES8_RT0_:
  308|  3.47k|   {
  309|  3.47k|      context ctx{};
  310|  3.47k|      std::string out{};
  311|  3.47k|      detail::minify_json<opt_true<Opts, &opts::comments>>(ctx, in, out);
  312|  3.47k|      if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (312:11): [True: 2.33k, False: 1.14k]
  ------------------
  313|  2.33k|         return {}; // an incomplete result is not a document; see above
  314|  2.33k|      }
  315|  1.14k|      return out;
  316|  3.47k|   }
_ZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEERNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEETkNS_13output_bufferESA_TkNS_10is_contextERNS_7contextEQaa10contiguousIT0_E9resizableISD_EEEmOT2_OSD_OT1_:
  230|  3.47k|      {
  231|  3.47k|         if (in.size() == 0) {
  ------------------
  |  Branch (231:14): [True: 0, False: 3.47k]
  ------------------
  232|      0|            return 0;
  233|      0|         }
  234|       |
  235|  3.47k|         if constexpr (resizable<Out>) {
  236|       |            // Minifying only ever removes bytes, so this is room enough for whatever comes out.
  237|       |            // A bounded output is checked per write instead; see the scan above for why.
  238|  3.47k|            out.resize(in.size() + 2 * padding_bytes);
  239|  3.47k|         }
  240|  3.47k|         size_t ix = 0;
  241|  3.47k|         auto [it, end] = read_iterators<Opts>(in);
  242|  3.47k|         if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (242:14): [True: 0, False: 3.47k]
  ------------------
  243|      0|            return 0;
  244|      0|         }
  245|       |
  246|       |         // The input is no longer grown and shrunk around this: everything the scan below reads
  247|       |         // through -- read_json_string, read_json_number, skip_matching_ws -- bounds its own loads
  248|       |         // against `end`, so there is nothing left for the padding to protect.
  249|  3.47k|         if constexpr (self_terminating<In>) {
  250|  3.47k|            minify_json<opt_true<Opts, &opts::null_terminated>>(ctx, it, end, out, ix);
  251|       |         }
  252|       |         else {
  253|       |            minify_json<opt_false<Opts, &opts::null_terminated>>(ctx, it, end, out, ix);
  254|       |         }
  255|       |
  256|  3.47k|         if constexpr (resizable<Out>) {
  257|  3.47k|            out.resize(ix);
  258|  3.47k|         }
  259|  3.47k|         return ix;
  260|  3.47k|      }
_ZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_:
   18|  3.47k|      {
   19|  3.47k|         using enum json_type;
   20|       |
   21|       |         // Every write below goes through this, and the dump it makes is unchecked: the caller's
   22|       |         // one-shot sizing covers a resizable destination, because minifying only ever removes
   23|       |         // bytes, so the input's length is room enough.
   24|       |         //
   25|       |         // A bounded destination cannot be grown, and asking it for the input's length up front
   26|       |         // refuses a buffer that fits the result -- sizing the output to the minified length is the
   27|       |         // obvious thing to do, and `{ "a" : 1 }` into a 7 byte buffer has to work. So each write
   28|       |         // asks for exactly what it stores instead; see emit_bytes for where that count comes from.
   29|       |         // None of it survives for a resizable destination, which keeps the unchecked dumps and
   30|       |         // nothing more.
   31|  3.47k|         const auto put = [&](const auto& x) { return emit_bytes<false>(ctx, b, ix, x); };
   32|       |
   33|  3.47k|         auto ws_start = it;
   34|  3.47k|         uint64_t ws_size{};
   35|       |
   36|  3.47k|         auto skip_expected_whitespace = [&] {
   37|  3.47k|            auto new_ws_start = it;
   38|  3.47k|            if (ws_size && std::ptrdiff_t(ws_size) < end - it) [[likely]] {
   39|  3.47k|               skip_matching_ws(ws_start, it, ws_size);
   40|  3.47k|            }
   41|       |
   42|  3.47k|            if constexpr (Opts.null_terminated) {
   43|  3.47k|               while (whitespace_table[uint8_t(*it)]) {
   44|  3.47k|                  ++it;
   45|  3.47k|               }
   46|  3.47k|            }
   47|  3.47k|            else {
   48|  3.47k|               while ((it < end) && whitespace_table[uint8_t(*it)]) {
   49|  3.47k|                  ++it;
   50|  3.47k|               }
   51|  3.47k|            }
   52|  3.47k|            ws_start = new_ws_start;
   53|  3.47k|            ws_size = size_t(it - new_ws_start);
   54|  3.47k|         };
   55|       |
   56|  3.47k|         auto skip_whitespace = [&] {
   57|  3.47k|            if constexpr (Opts.null_terminated) {
   58|  3.47k|               while (whitespace_table[uint8_t(*it)]) {
   59|  3.47k|                  ++it;
   60|  3.47k|               }
   61|  3.47k|            }
   62|  3.47k|            else {
   63|  3.47k|               while ((it < end) && whitespace_table[uint8_t(*it)]) {
   64|  3.47k|                  ++it;
   65|  3.47k|               }
   66|  3.47k|            }
   67|  3.47k|         };
   68|       |
   69|  3.47k|         skip_whitespace();
   70|       |
   71|  37.8k|         while ([&]() -> bool {
  ------------------
  |  Branch (71:17): [True: 37.8k, Folded]
  ------------------
   72|  37.8k|            if constexpr (Opts.null_terminated) {
   73|  37.8k|               return true;
   74|  37.8k|            }
   75|  37.8k|            else {
   76|  37.8k|               return it < end;
   77|  37.8k|            }
   78|  37.8k|         }()) {
   79|  37.8k|            switch (json_types[uint8_t(*it)]) {
   80|  1.81k|            case String: {
  ------------------
  |  Branch (80:13): [True: 1.81k, False: 36.0k]
  ------------------
   81|  1.81k|               const auto value = read_json_string(ctx, it, end);
   82|  1.81k|               if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (82:20): [True: 135, False: 1.68k]
  ------------------
   83|    135|                  return;
   84|    135|               }
   85|       |               // non-empty: the scanner reports an empty view as an error
   86|  1.68k|               if (not put(value)) [[unlikely]] {
  ------------------
  |  Branch (86:20): [True: 0, False: 1.68k]
  ------------------
   87|      0|                  return;
   88|      0|               }
   89|  1.68k|               skip_whitespace();
   90|  1.68k|               break;
   91|  1.68k|            }
   92|  7.92k|            case Comma: {
  ------------------
  |  Branch (92:13): [True: 7.92k, False: 29.9k]
  ------------------
   93|  7.92k|               if (not put(',')) [[unlikely]] {
  ------------------
  |  Branch (93:20): [True: 0, False: 7.92k]
  ------------------
   94|      0|                  return;
   95|      0|               }
   96|  7.92k|               ++it;
   97|  7.92k|               skip_expected_whitespace();
   98|  7.92k|               break;
   99|  7.92k|            }
  100|  1.46k|            case Number: {
  ------------------
  |  Branch (100:13): [True: 1.46k, False: 36.3k]
  ------------------
  101|  1.46k|               const auto value = read_json_number<Opts.null_terminated>(it, end);
  102|       |               // non-empty: a Number match is one valid character
  103|  1.46k|               if (not put(value)) [[unlikely]] {
  ------------------
  |  Branch (103:20): [True: 0, False: 1.46k]
  ------------------
  104|      0|                  return;
  105|      0|               }
  106|  1.46k|               skip_whitespace();
  107|  1.46k|               break;
  108|  1.46k|            }
  109|  1.51k|            case Colon: {
  ------------------
  |  Branch (109:13): [True: 1.51k, False: 36.3k]
  ------------------
  110|  1.51k|               if (not put(':')) [[unlikely]] {
  ------------------
  |  Branch (110:20): [True: 0, False: 1.51k]
  ------------------
  111|      0|                  return;
  112|      0|               }
  113|  1.51k|               ++it;
  114|  1.51k|               skip_whitespace();
  115|  1.51k|               break;
  116|  1.51k|            }
  117|  6.37k|            case Array_Start: {
  ------------------
  |  Branch (117:13): [True: 6.37k, False: 31.4k]
  ------------------
  118|  6.37k|               if (not put('[')) [[unlikely]] {
  ------------------
  |  Branch (118:20): [True: 0, False: 6.37k]
  ------------------
  119|      0|                  return;
  120|      0|               }
  121|  6.37k|               ++it;
  122|  6.37k|               skip_expected_whitespace();
  123|  6.37k|               break;
  124|  6.37k|            }
  125|  1.28k|            case Array_End: {
  ------------------
  |  Branch (125:13): [True: 1.28k, False: 36.5k]
  ------------------
  126|  1.28k|               if (not put(']')) [[unlikely]] {
  ------------------
  |  Branch (126:20): [True: 0, False: 1.28k]
  ------------------
  127|      0|                  return;
  128|      0|               }
  129|  1.28k|               ++it;
  130|  1.28k|               skip_whitespace();
  131|  1.28k|               break;
  132|  1.28k|            }
  133|    921|            case Null: {
  ------------------
  |  Branch (133:13): [True: 921, False: 36.9k]
  ------------------
  134|       |               // The type table matched on the first byte alone; see match_literal for why writing
  135|       |               // the literal from the writer's own spelling needs the rest of it checked. Stepping
  136|       |               // over it unchecked also puts `it` past `end`, and from there the loop goes on
  137|       |               // minifying whatever follows the document into an output sized for the document.
  138|    921|               if (not match_literal<"null">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (138:20): [True: 123, False: 798]
  ------------------
  139|    123|                  return;
  140|    123|               }
  141|    798|               if (not put("null")) [[unlikely]] {
  ------------------
  |  Branch (141:20): [True: 0, False: 798]
  ------------------
  142|      0|                  return;
  143|      0|               }
  144|    798|               skip_whitespace();
  145|    798|               break;
  146|    798|            }
  147|  1.59k|            case Bool: {
  ------------------
  |  Branch (147:13): [True: 1.59k, False: 36.2k]
  ------------------
  148|  1.59k|               if (*it == 't') {
  ------------------
  |  Branch (148:20): [True: 907, False: 692]
  ------------------
  149|    907|                  if (not match_literal<"true">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (149:23): [True: 116, False: 791]
  ------------------
  150|    116|                     return;
  151|    116|                  }
  152|    791|                  if (not put("true")) [[unlikely]] {
  ------------------
  |  Branch (152:23): [True: 0, False: 791]
  ------------------
  153|      0|                     return;
  154|      0|                  }
  155|    791|                  skip_whitespace();
  156|    791|                  break;
  157|    791|               }
  158|    692|               else {
  159|    692|                  if (not match_literal<"false">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (159:23): [True: 138, False: 554]
  ------------------
  160|    138|                     return;
  161|    138|                  }
  162|    554|                  if (not put("false")) [[unlikely]] {
  ------------------
  |  Branch (162:23): [True: 0, False: 554]
  ------------------
  163|      0|                     return;
  164|      0|                  }
  165|    554|                  skip_whitespace();
  166|    554|                  break;
  167|    554|               }
  168|  1.59k|            }
  169|  7.93k|            case Object_Start: {
  ------------------
  |  Branch (169:13): [True: 7.93k, False: 29.9k]
  ------------------
  170|  7.93k|               if (not put('{')) [[unlikely]] {
  ------------------
  |  Branch (170:20): [True: 0, False: 7.93k]
  ------------------
  171|      0|                  return;
  172|      0|               }
  173|  7.93k|               ++it;
  174|  7.93k|               skip_expected_whitespace();
  175|  7.93k|               break;
  176|  7.93k|            }
  177|  1.56k|            case Object_End: {
  ------------------
  |  Branch (177:13): [True: 1.56k, False: 36.2k]
  ------------------
  178|  1.56k|               if (not put('}')) [[unlikely]] {
  ------------------
  |  Branch (178:20): [True: 0, False: 1.56k]
  ------------------
  179|      0|                  return;
  180|      0|               }
  181|  1.56k|               ++it;
  182|  1.56k|               skip_whitespace();
  183|  1.56k|               break;
  184|  1.56k|            }
  185|  2.61k|            case Comment: {
  ------------------
  |  Branch (185:13): [True: 2.61k, False: 35.2k]
  ------------------
  186|  2.61k|               if constexpr (Opts.comments) {
  187|  2.61k|                  const auto comment = read_jsonc_comment(ctx, it, end);
  188|  2.61k|                  if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (188:23): [True: 137, False: 2.47k]
  ------------------
  189|    137|                     return;
  190|    137|                  }
  191|       |                  // A line comment is dropped rather than written out. Minifying is what removes
  192|       |                  // the newline that ends it, and a line comment with no line break behind it
  193|       |                  // comments out the whole rest of the output.
  194|  2.47k|                  if (not comment.line) {
  ------------------
  |  Branch (194:23): [True: 1.52k, False: 949]
  ------------------
  195|       |                     // non-empty: an empty view comes with an error
  196|  1.52k|                     if (not put(comment.text)) [[unlikely]] {
  ------------------
  |  Branch (196:26): [True: 0, False: 1.52k]
  ------------------
  197|      0|                        return;
  198|      0|                     }
  199|  1.52k|                  }
  200|  2.47k|                  skip_whitespace();
  201|  2.47k|                  break;
  202|       |               }
  203|       |               else {
  204|       |                  [[fallthrough]];
  205|       |               }
  206|  2.61k|            }
  207|  5.43k|            [[unlikely]] default: {
  ------------------
  |  Branch (207:26): [True: 2.82k, False: 35.0k]
  ------------------
  208|       |               // A null terminated run carries no bound in its loop condition, so it ends here, on
  209|       |               // the terminator, which is not a JSON token. Reaching it is the end of the document
  210|       |               // rather than an error -- unclassified is how the type table reports both, and
  211|       |               // without this the minifier left syntax_error behind on every input it was ever
  212|       |               // given, valid or not, which is what made its error not worth returning.
  213|  5.43k|               if constexpr (Opts.null_terminated) {
  214|  5.43k|                  if (it >= end) {
  ------------------
  |  Branch (214:23): [True: 1.14k, False: 4.29k]
  ------------------
  215|  1.14k|                     return;
  216|  1.14k|                  }
  217|  5.43k|               }
  218|  4.29k|               ctx.error = error_code::syntax_error;
  219|  5.43k|               return;
  220|  2.61k|            }
  221|  37.8k|            }
  222|  37.8k|         }
  223|  3.47k|      }
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlvE0_clEv:
   56|  15.6k|         auto skip_whitespace = [&] {
   57|  15.6k|            if constexpr (Opts.null_terminated) {
   58|   135k|               while (whitespace_table[uint8_t(*it)]) {
  ------------------
  |  Branch (58:23): [True: 120k, False: 15.6k]
  ------------------
   59|   120k|                  ++it;
   60|   120k|               }
   61|       |            }
   62|       |            else {
   63|       |               while ((it < end) && whitespace_table[uint8_t(*it)]) {
   64|       |                  ++it;
   65|       |               }
   66|       |            }
   67|  15.6k|         };
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlvE1_clEv:
   71|  37.8k|         while ([&]() -> bool {
   72|  37.8k|            if constexpr (Opts.null_terminated) {
   73|  37.8k|               return true;
   74|       |            }
   75|       |            else {
   76|       |               return it < end;
   77|       |            }
   78|  37.8k|         }()) {
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clINS8_17basic_string_viewIcSB_EEEEDaSS_:
   31|  4.66k|         const auto put = [&](const auto& x) { return emit_bytes<false>(ctx, b, ix, x); };
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIcEEDaSS_:
   31|  26.6k|         const auto put = [&](const auto& x) { return emit_bytes<false>(ctx, b, ix, x); };
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlvE_clEv:
   36|  22.2k|         auto skip_expected_whitespace = [&] {
   37|  22.2k|            auto new_ws_start = it;
   38|  22.2k|            if (ws_size && std::ptrdiff_t(ws_size) < end - it) [[likely]] {
  ------------------
  |  Branch (38:17): [True: 16.0k, False: 6.14k]
  |  Branch (38:28): [True: 14.8k, False: 1.25k]
  ------------------
   39|  14.8k|               skip_matching_ws(ws_start, it, ws_size);
   40|  14.8k|            }
   41|       |
   42|  22.2k|            if constexpr (Opts.null_terminated) {
   43|  19.3M|               while (whitespace_table[uint8_t(*it)]) {
  ------------------
  |  Branch (43:23): [True: 19.2M, False: 22.2k]
  ------------------
   44|  19.2M|                  ++it;
   45|  19.2M|               }
   46|       |            }
   47|       |            else {
   48|       |               while ((it < end) && whitespace_table[uint8_t(*it)]) {
   49|       |                  ++it;
   50|       |               }
   51|       |            }
   52|  22.2k|            ws_start = new_ws_start;
   53|  22.2k|            ws_size = size_t(it - new_ws_start);
   54|  22.2k|         };
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIA5_cEEDaSS_:
   31|  1.58k|         const auto put = [&](const auto& x) { return emit_bytes<false>(ctx, b, ix, x); };
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__112basic_stringIcNS8_11char_traitsIcEENS8_9allocatorIcEEEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIA6_cEEDaSS_:
   31|    554|         const auto put = [&](const auto& x) { return emit_bytes<false>(ctx, b, ix, x); };
_ZN3glz12minify_jsoncITnDaXtlNS_4optsELj10ELb1ELb0ELb1ELb1EEETkNS_9resizableENSt3__16vectorIcNS2_9allocatorIcEEEENS2_5arrayIcLm64EEEEENS_9error_ctxERT0_RT1_:
  300|  3.47k|   {
  301|  3.47k|      context ctx{};
  302|  3.47k|      const auto n = detail::minify_json<opt_true<Opts, &opts::comments>>(ctx, in, out);
  303|  3.47k|      return {n, ctx.error, ctx.custom_error_message};
  304|  3.47k|   }
_ZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb1ELb1ELb1ELb1EEERNSt3__16vectorIcNS3_9allocatorIcEEEETkNS_13output_bufferERNS3_5arrayIcLm64EEETkNS_10is_contextERNS_7contextEQaa10contiguousIT0_E9resizableISE_EEEmOT2_OSE_OT1_:
  230|  3.47k|      {
  231|  3.47k|         if (in.size() == 0) {
  ------------------
  |  Branch (231:14): [True: 0, False: 3.47k]
  ------------------
  232|      0|            return 0;
  233|      0|         }
  234|       |
  235|       |         if constexpr (resizable<Out>) {
  236|       |            // Minifying only ever removes bytes, so this is room enough for whatever comes out.
  237|       |            // A bounded output is checked per write instead; see the scan above for why.
  238|       |            out.resize(in.size() + 2 * padding_bytes);
  239|       |         }
  240|  3.47k|         size_t ix = 0;
  241|  3.47k|         auto [it, end] = read_iterators<Opts>(in);
  242|  3.47k|         if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (242:14): [True: 0, False: 3.47k]
  ------------------
  243|      0|            return 0;
  244|      0|         }
  245|       |
  246|       |         // The input is no longer grown and shrunk around this: everything the scan below reads
  247|       |         // through -- read_json_string, read_json_number, skip_matching_ws -- bounds its own loads
  248|       |         // against `end`, so there is nothing left for the padding to protect.
  249|       |         if constexpr (self_terminating<In>) {
  250|       |            minify_json<opt_true<Opts, &opts::null_terminated>>(ctx, it, end, out, ix);
  251|       |         }
  252|  3.47k|         else {
  253|  3.47k|            minify_json<opt_false<Opts, &opts::null_terminated>>(ctx, it, end, out, ix);
  254|  3.47k|         }
  255|       |
  256|       |         if constexpr (resizable<Out>) {
  257|       |            out.resize(ix);
  258|       |         }
  259|  3.47k|         return ix;
  260|  3.47k|      }
_ZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__15arrayIcLm64EEEmEEvOT0_OT1_OT2_OT3_RT4_:
   18|  3.47k|      {
   19|  3.47k|         using enum json_type;
   20|       |
   21|       |         // Every write below goes through this, and the dump it makes is unchecked: the caller's
   22|       |         // one-shot sizing covers a resizable destination, because minifying only ever removes
   23|       |         // bytes, so the input's length is room enough.
   24|       |         //
   25|       |         // A bounded destination cannot be grown, and asking it for the input's length up front
   26|       |         // refuses a buffer that fits the result -- sizing the output to the minified length is the
   27|       |         // obvious thing to do, and `{ "a" : 1 }` into a 7 byte buffer has to work. So each write
   28|       |         // asks for exactly what it stores instead; see emit_bytes for where that count comes from.
   29|       |         // None of it survives for a resizable destination, which keeps the unchecked dumps and
   30|       |         // nothing more.
   31|  3.47k|         const auto put = [&](const auto& x) { return emit_bytes<false>(ctx, b, ix, x); };
   32|       |
   33|  3.47k|         auto ws_start = it;
   34|  3.47k|         uint64_t ws_size{};
   35|       |
   36|  3.47k|         auto skip_expected_whitespace = [&] {
   37|  3.47k|            auto new_ws_start = it;
   38|  3.47k|            if (ws_size && std::ptrdiff_t(ws_size) < end - it) [[likely]] {
   39|  3.47k|               skip_matching_ws(ws_start, it, ws_size);
   40|  3.47k|            }
   41|       |
   42|  3.47k|            if constexpr (Opts.null_terminated) {
   43|  3.47k|               while (whitespace_table[uint8_t(*it)]) {
   44|  3.47k|                  ++it;
   45|  3.47k|               }
   46|  3.47k|            }
   47|  3.47k|            else {
   48|  3.47k|               while ((it < end) && whitespace_table[uint8_t(*it)]) {
   49|  3.47k|                  ++it;
   50|  3.47k|               }
   51|  3.47k|            }
   52|  3.47k|            ws_start = new_ws_start;
   53|  3.47k|            ws_size = size_t(it - new_ws_start);
   54|  3.47k|         };
   55|       |
   56|  3.47k|         auto skip_whitespace = [&] {
   57|  3.47k|            if constexpr (Opts.null_terminated) {
   58|  3.47k|               while (whitespace_table[uint8_t(*it)]) {
   59|  3.47k|                  ++it;
   60|  3.47k|               }
   61|  3.47k|            }
   62|  3.47k|            else {
   63|  3.47k|               while ((it < end) && whitespace_table[uint8_t(*it)]) {
   64|  3.47k|                  ++it;
   65|  3.47k|               }
   66|  3.47k|            }
   67|  3.47k|         };
   68|       |
   69|  3.47k|         skip_whitespace();
   70|       |
   71|  25.3k|         while ([&]() -> bool {
  ------------------
  |  Branch (71:17): [True: 24.3k, False: 996]
  ------------------
   72|  25.3k|            if constexpr (Opts.null_terminated) {
   73|  25.3k|               return true;
   74|  25.3k|            }
   75|  25.3k|            else {
   76|  25.3k|               return it < end;
   77|  25.3k|            }
   78|  25.3k|         }()) {
   79|  24.3k|            switch (json_types[uint8_t(*it)]) {
   80|    909|            case String: {
  ------------------
  |  Branch (80:13): [True: 909, False: 23.4k]
  ------------------
   81|    909|               const auto value = read_json_string(ctx, it, end);
   82|    909|               if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (82:20): [True: 124, False: 785]
  ------------------
   83|    124|                  return;
   84|    124|               }
   85|       |               // non-empty: the scanner reports an empty view as an error
   86|    785|               if (not put(value)) [[unlikely]] {
  ------------------
  |  Branch (86:20): [True: 60, False: 725]
  ------------------
   87|     60|                  return;
   88|     60|               }
   89|    725|               skip_whitespace();
   90|    725|               break;
   91|    785|            }
   92|  5.63k|            case Comma: {
  ------------------
  |  Branch (92:13): [True: 5.63k, False: 18.6k]
  ------------------
   93|  5.63k|               if (not put(',')) [[unlikely]] {
  ------------------
  |  Branch (93:20): [True: 35, False: 5.60k]
  ------------------
   94|     35|                  return;
   95|     35|               }
   96|  5.60k|               ++it;
   97|  5.60k|               skip_expected_whitespace();
   98|  5.60k|               break;
   99|  5.63k|            }
  100|    809|            case Number: {
  ------------------
  |  Branch (100:13): [True: 809, False: 23.5k]
  ------------------
  101|    809|               const auto value = read_json_number<Opts.null_terminated>(it, end);
  102|       |               // non-empty: a Number match is one valid character
  103|    809|               if (not put(value)) [[unlikely]] {
  ------------------
  |  Branch (103:20): [True: 29, False: 780]
  ------------------
  104|     29|                  return;
  105|     29|               }
  106|    780|               skip_whitespace();
  107|    780|               break;
  108|    809|            }
  109|  1.23k|            case Colon: {
  ------------------
  |  Branch (109:13): [True: 1.23k, False: 23.1k]
  ------------------
  110|  1.23k|               if (not put(':')) [[unlikely]] {
  ------------------
  |  Branch (110:20): [True: 6, False: 1.22k]
  ------------------
  111|      6|                  return;
  112|      6|               }
  113|  1.22k|               ++it;
  114|  1.22k|               skip_whitespace();
  115|  1.22k|               break;
  116|  1.23k|            }
  117|  4.64k|            case Array_Start: {
  ------------------
  |  Branch (117:13): [True: 4.64k, False: 19.6k]
  ------------------
  118|  4.64k|               if (not put('[')) [[unlikely]] {
  ------------------
  |  Branch (118:20): [True: 28, False: 4.62k]
  ------------------
  119|     28|                  return;
  120|     28|               }
  121|  4.62k|               ++it;
  122|  4.62k|               skip_expected_whitespace();
  123|  4.62k|               break;
  124|  4.64k|            }
  125|    788|            case Array_End: {
  ------------------
  |  Branch (125:13): [True: 788, False: 23.5k]
  ------------------
  126|    788|               if (not put(']')) [[unlikely]] {
  ------------------
  |  Branch (126:20): [True: 8, False: 780]
  ------------------
  127|      8|                  return;
  128|      8|               }
  129|    780|               ++it;
  130|    780|               skip_whitespace();
  131|    780|               break;
  132|    788|            }
  133|    440|            case Null: {
  ------------------
  |  Branch (133:13): [True: 440, False: 23.8k]
  ------------------
  134|       |               // The type table matched on the first byte alone; see match_literal for why writing
  135|       |               // the literal from the writer's own spelling needs the rest of it checked. Stepping
  136|       |               // over it unchecked also puts `it` past `end`, and from there the loop goes on
  137|       |               // minifying whatever follows the document into an output sized for the document.
  138|    440|               if (not match_literal<"null">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (138:20): [True: 114, False: 326]
  ------------------
  139|    114|                  return;
  140|    114|               }
  141|    326|               if (not put("null")) [[unlikely]] {
  ------------------
  |  Branch (141:20): [True: 12, False: 314]
  ------------------
  142|     12|                  return;
  143|     12|               }
  144|    314|               skip_whitespace();
  145|    314|               break;
  146|    326|            }
  147|    760|            case Bool: {
  ------------------
  |  Branch (147:13): [True: 760, False: 23.5k]
  ------------------
  148|    760|               if (*it == 't') {
  ------------------
  |  Branch (148:20): [True: 410, False: 350]
  ------------------
  149|    410|                  if (not match_literal<"true">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (149:23): [True: 101, False: 309]
  ------------------
  150|    101|                     return;
  151|    101|                  }
  152|    309|                  if (not put("true")) [[unlikely]] {
  ------------------
  |  Branch (152:23): [True: 12, False: 297]
  ------------------
  153|     12|                     return;
  154|     12|                  }
  155|    297|                  skip_whitespace();
  156|    297|                  break;
  157|    309|               }
  158|    350|               else {
  159|    350|                  if (not match_literal<"false">(ctx, it, end)) [[unlikely]] {
  ------------------
  |  Branch (159:23): [True: 129, False: 221]
  ------------------
  160|    129|                     return;
  161|    129|                  }
  162|    221|                  if (not put("false")) [[unlikely]] {
  ------------------
  |  Branch (162:23): [True: 9, False: 212]
  ------------------
  163|      9|                     return;
  164|      9|                  }
  165|    212|                  skip_whitespace();
  166|    212|                  break;
  167|    221|               }
  168|    760|            }
  169|  5.35k|            case Object_Start: {
  ------------------
  |  Branch (169:13): [True: 5.35k, False: 18.9k]
  ------------------
  170|  5.35k|               if (not put('{')) [[unlikely]] {
  ------------------
  |  Branch (170:20): [True: 36, False: 5.32k]
  ------------------
  171|     36|                  return;
  172|     36|               }
  173|  5.32k|               ++it;
  174|  5.32k|               skip_expected_whitespace();
  175|  5.32k|               break;
  176|  5.35k|            }
  177|  1.06k|            case Object_End: {
  ------------------
  |  Branch (177:13): [True: 1.06k, False: 23.2k]
  ------------------
  178|  1.06k|               if (not put('}')) [[unlikely]] {
  ------------------
  |  Branch (178:20): [True: 6, False: 1.05k]
  ------------------
  179|      6|                  return;
  180|      6|               }
  181|  1.05k|               ++it;
  182|  1.05k|               skip_whitespace();
  183|  1.05k|               break;
  184|  1.06k|            }
  185|  1.08k|            case Comment: {
  ------------------
  |  Branch (185:13): [True: 1.08k, False: 23.2k]
  ------------------
  186|  1.08k|               if constexpr (Opts.comments) {
  187|  1.08k|                  const auto comment = read_jsonc_comment(ctx, it, end);
  188|  1.08k|                  if (bool(ctx.error)) [[unlikely]] {
  ------------------
  |  Branch (188:23): [True: 123, False: 963]
  ------------------
  189|    123|                     return;
  190|    123|                  }
  191|       |                  // A line comment is dropped rather than written out. Minifying is what removes
  192|       |                  // the newline that ends it, and a line comment with no line break behind it
  193|       |                  // comments out the whole rest of the output.
  194|    963|                  if (not comment.line) {
  ------------------
  |  Branch (194:23): [True: 392, False: 571]
  ------------------
  195|       |                     // non-empty: an empty view comes with an error
  196|    392|                     if (not put(comment.text)) [[unlikely]] {
  ------------------
  |  Branch (196:26): [True: 45, False: 347]
  ------------------
  197|     45|                        return;
  198|     45|                     }
  199|    392|                  }
  200|    918|                  skip_whitespace();
  201|    918|                  break;
  202|       |               }
  203|       |               else {
  204|       |                  [[fallthrough]];
  205|       |               }
  206|  1.08k|            }
  207|  2.69k|            [[unlikely]] default: {
  ------------------
  |  Branch (207:26): [True: 1.60k, False: 22.7k]
  ------------------
  208|       |               // A null terminated run carries no bound in its loop condition, so it ends here, on
  209|       |               // the terminator, which is not a JSON token. Reaching it is the end of the document
  210|       |               // rather than an error -- unclassified is how the type table reports both, and
  211|       |               // without this the minifier left syntax_error behind on every input it was ever
  212|       |               // given, valid or not, which is what made its error not worth returning.
  213|       |               if constexpr (Opts.null_terminated) {
  214|       |                  if (it >= end) {
  215|       |                     return;
  216|       |                  }
  217|       |               }
  218|  2.69k|               ctx.error = error_code::syntax_error;
  219|  2.69k|               return;
  220|  1.08k|            }
  221|  24.3k|            }
  222|  24.3k|         }
  223|  3.47k|      }
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__15arrayIcLm64EEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlvE0_clEv:
   56|  9.78k|         auto skip_whitespace = [&] {
   57|       |            if constexpr (Opts.null_terminated) {
   58|       |               while (whitespace_table[uint8_t(*it)]) {
   59|       |                  ++it;
   60|       |               }
   61|       |            }
   62|  9.78k|            else {
   63|  99.0k|               while ((it < end) && whitespace_table[uint8_t(*it)]) {
  ------------------
  |  Branch (63:23): [True: 98.6k, False: 441]
  |  Branch (63:37): [True: 89.2k, False: 9.34k]
  ------------------
   64|  89.2k|                  ++it;
   65|  89.2k|               }
   66|  9.78k|            }
   67|  9.78k|         };
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__15arrayIcLm64EEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlvE1_clEv:
   71|  25.3k|         while ([&]() -> bool {
   72|       |            if constexpr (Opts.null_terminated) {
   73|       |               return true;
   74|       |            }
   75|  25.3k|            else {
   76|  25.3k|               return it < end;
   77|  25.3k|            }
   78|  25.3k|         }()) {
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__15arrayIcLm64EEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clINS8_17basic_string_viewIcNS8_11char_traitsIcEEEEEEDaSO_:
   31|  1.98k|         const auto put = [&](const auto& x) { return emit_bytes<false>(ctx, b, ix, x); };
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__15arrayIcLm64EEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIcEEDaSO_:
   31|  18.7k|         const auto put = [&](const auto& x) { return emit_bytes<false>(ctx, b, ix, x); };
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__15arrayIcLm64EEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlvE_clEv:
   36|  15.5k|         auto skip_expected_whitespace = [&] {
   37|  15.5k|            auto new_ws_start = it;
   38|  15.5k|            if (ws_size && std::ptrdiff_t(ws_size) < end - it) [[likely]] {
  ------------------
  |  Branch (38:17): [True: 10.7k, False: 4.80k]
  |  Branch (38:28): [True: 9.51k, False: 1.22k]
  ------------------
   39|  9.51k|               skip_matching_ws(ws_start, it, ws_size);
   40|  9.51k|            }
   41|       |
   42|       |            if constexpr (Opts.null_terminated) {
   43|       |               while (whitespace_table[uint8_t(*it)]) {
   44|       |                  ++it;
   45|       |               }
   46|       |            }
   47|  15.5k|            else {
   48|  19.2M|               while ((it < end) && whitespace_table[uint8_t(*it)]) {
  ------------------
  |  Branch (48:23): [True: 19.2M, False: 555]
  |  Branch (48:37): [True: 19.2M, False: 14.9k]
  ------------------
   49|  19.2M|                  ++it;
   50|  19.2M|               }
   51|  15.5k|            }
   52|  15.5k|            ws_start = new_ws_start;
   53|  15.5k|            ws_size = size_t(it - new_ws_start);
   54|  15.5k|         };
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__15arrayIcLm64EEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIA5_cEEDaSO_:
   31|    635|         const auto put = [&](const auto& x) { return emit_bytes<false>(ctx, b, ix, x); };
_ZZN3glz6detail11minify_jsonITnDaXtlNS_4optsELj10ELb0ELb1ELb1ELb1EEETkNS_10is_contextERNS_7contextERPKcS7_RNSt3__15arrayIcLm64EEEmEEvOT0_OT1_OT2_OT3_RT4_ENKUlRKT_E_clIA6_cEEDaSO_:
   31|    221|         const auto put = [&](const auto& x) { return emit_bytes<false>(ctx, b, ix, x); };

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

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

_ZN3glz4dumpILb0ENSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEEvNS1_17basic_string_viewIcS4_EERT0_Rm:
  192|  23.7k|   {
  193|  23.7k|      const auto n = str.size();
  194|  23.7k|      if constexpr (vector_like<B>) {
  195|       |         if constexpr (Checked) {
  196|       |            const auto k = ix + n;
  197|       |            if (ix + n > b.size()) [[unlikely]] {
  198|       |               grow_buffer(b, k);
  199|       |            }
  200|       |         }
  201|  23.7k|      }
  202|  23.7k|      std::memcpy(&b[ix], str.data(), n);
  203|  23.7k|      ix += n;
  204|  23.7k|   }
_ZN3glz4dumpILb0ENSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEETkNS_10byte_sizedEcEEvT1_RT0_Rm:
  150|   105k|   {
  151|       |      if constexpr (Checked && vector_like<B>) {
  152|       |         if (ix == b.size()) [[unlikely]] {
  153|       |            grow_buffer(b, b.size() == 0 ? 64 : ix + 1);
  154|       |         }
  155|       |      }
  156|   105k|      assign_maybe_cast(c, b, ix);
  157|   105k|      ++ix;
  158|   105k|   }
_ZN3glz17assign_maybe_castITkNS_10byte_sizedEcNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEEvT_RT0_Rm:
   95|   105k|   {
   96|   105k|      using V = std::decay_t<decltype(b[0])>;
   97|   105k|      using C = std::decay_t<decltype(c)>;
   98|   105k|      if constexpr (std::same_as<V, C>) {
   99|   105k|         b[ix] = c;
  100|       |      }
  101|       |      else {
  102|       |         b[ix] = static_cast<V>(c);
  103|       |      }
  104|   105k|   }
_ZN3glz4dumpILb0ENSt3__15arrayIcLm64EEEEEvNS1_17basic_string_viewIcNS1_11char_traitsIcEEEERT0_Rm:
  192|  2.67k|   {
  193|  2.67k|      const auto n = str.size();
  194|       |      if constexpr (vector_like<B>) {
  195|       |         if constexpr (Checked) {
  196|       |            const auto k = ix + n;
  197|       |            if (ix + n > b.size()) [[unlikely]] {
  198|       |               grow_buffer(b, k);
  199|       |            }
  200|       |         }
  201|       |      }
  202|  2.67k|      std::memcpy(&b[ix], str.data(), n);
  203|  2.67k|      ix += n;
  204|  2.67k|   }
_ZN3glz4dumpILb0ENSt3__15arrayIcLm64EEETkNS_10byte_sizedEcEEvT1_RT0_Rm:
  150|  18.6k|   {
  151|       |      if constexpr (Checked && vector_like<B>) {
  152|       |         if (ix == b.size()) [[unlikely]] {
  153|       |            grow_buffer(b, b.size() == 0 ? 64 : ix + 1);
  154|       |         }
  155|       |      }
  156|  18.6k|      assign_maybe_cast(c, b, ix);
  157|  18.6k|      ++ix;
  158|  18.6k|   }
_ZN3glz17assign_maybe_castITkNS_10byte_sizedEcNSt3__15arrayIcLm64EEEEEvT_RT0_Rm:
   95|  18.6k|   {
   96|  18.6k|      using V = std::decay_t<decltype(b[0])>;
   97|  18.6k|      using C = std::decay_t<decltype(c)>;
   98|  18.6k|      if constexpr (std::same_as<V, C>) {
   99|  18.6k|         b[ix] = c;
  100|       |      }
  101|       |      else {
  102|       |         b[ix] = static_cast<V>(c);
  103|       |      }
  104|  18.6k|   }

_ZN3glz16skip_matching_wsIcRPKcEEvPKT_OT0_m:
  730|  69.6k|   {
  731|  69.6k|      if (length > 7) {
  ------------------
  |  Branch (731:11): [True: 32.8k, False: 36.8k]
  ------------------
  732|  32.8k|         uint64_t v[2];
  733|  60.6k|         while (length > 8) {
  ------------------
  |  Branch (733:17): [True: 41.2k, False: 19.4k]
  ------------------
  734|  41.2k|            std::memcpy(v, ws, 8);
  735|  41.2k|            std::memcpy(v + 1, it, 8);
  736|  41.2k|            if (v[0] != v[1]) {
  ------------------
  |  Branch (736:17): [True: 13.4k, False: 27.8k]
  ------------------
  737|  13.4k|               return;
  738|  13.4k|            }
  739|  27.8k|            length -= 8;
  740|  27.8k|            ws += 8;
  741|  27.8k|            it += 8;
  742|  27.8k|         }
  743|       |
  744|  19.4k|         const auto shift = 8 - length;
  745|  19.4k|         ws -= shift;
  746|  19.4k|         it -= shift;
  747|       |
  748|  19.4k|         std::memcpy(v, ws, 8);
  749|  19.4k|         std::memcpy(v + 1, it, 8);
  750|  19.4k|         if (v[0] != v[1]) {
  ------------------
  |  Branch (750:14): [True: 8.69k, False: 10.7k]
  ------------------
  751|  8.69k|            return;
  752|  8.69k|         }
  753|  10.7k|         it += 8;
  754|  10.7k|         return;
  755|  19.4k|      }
  756|  36.8k|      {
  757|  36.8k|         constexpr uint64_t n{sizeof(uint32_t)};
  758|  36.8k|         if (length >= n) {
  ------------------
  |  Branch (758:14): [True: 15.3k, False: 21.4k]
  ------------------
  759|  15.3k|            uint32_t v[2];
  760|  15.3k|            std::memcpy(v, ws, n);
  761|  15.3k|            std::memcpy(v + 1, it, n);
  762|  15.3k|            if (v[0] != v[1]) {
  ------------------
  |  Branch (762:17): [True: 9.25k, False: 6.09k]
  ------------------
  763|  9.25k|               return;
  764|  9.25k|            }
  765|  6.09k|            length -= n;
  766|  6.09k|            ws += n;
  767|  6.09k|            it += n;
  768|  6.09k|         }
  769|  36.8k|      }
  770|  27.5k|      {
  771|  27.5k|         constexpr uint64_t n{sizeof(uint16_t)};
  772|  27.5k|         if (length >= n) {
  ------------------
  |  Branch (772:14): [True: 14.3k, False: 13.2k]
  ------------------
  773|  14.3k|            uint16_t v[2];
  774|  14.3k|            std::memcpy(v, ws, n);
  775|  14.3k|            std::memcpy(v + 1, it, n);
  776|  14.3k|            if (v[0] != v[1]) {
  ------------------
  |  Branch (776:17): [True: 8.32k, False: 6.02k]
  ------------------
  777|  8.32k|               return;
  778|  8.32k|            }
  779|       |            // length -= n;
  780|       |            // ws += n;
  781|  6.02k|            it += n;
  782|  6.02k|         }
  783|  27.5k|      }
  784|       |      // We have to call a whitespace check after this function
  785|       |      // in case the whitespace is mismatching.
  786|       |      // So, we forgo this check as to not duplicate.
  787|       |      /*if (length && *ws == *it) {
  788|       |         ++it;
  789|       |      }*/
  790|  27.5k|   }

