_ZN3ada7unicode14percent_encodeILb1EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKhRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEE:
 7349|  3.30k|                    std::string& out) {
 7350|  3.30k|  ada_log("percent_encode ", input, " to output string while ",
 7351|  3.30k|          append ? "appending" : "overwriting");
 7352|  3.30k|  auto pointer = std::ranges::find_if(input, [character_set](const char c) {
 7353|  3.30k|    return character_sets::bit_at(character_set, c);
 7354|  3.30k|  });
 7355|  3.30k|  ada_log("percent_encode done checking, moved to ",
 7356|  3.30k|          std::distance(input.begin(), pointer));
 7357|       |
 7358|       |  // Optimization: Don't iterate if percent encode is not required
 7359|  3.30k|  if (pointer == input.end()) {
  ------------------
  |  Branch (7359:7): [True: 1.87k, False: 1.43k]
  ------------------
 7360|  1.87k|    ada_log("percent_encode encoding not needed.");
 7361|  1.87k|    return false;
 7362|  1.87k|  }
 7363|       |  if constexpr (!append) {
 7364|       |    out.clear();
 7365|       |  }
 7366|  1.43k|  ada_log("percent_encode appending ", std::distance(input.begin(), pointer),
 7367|  1.43k|          " bytes");
 7368|       |  // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage)
 7369|  1.43k|  out.append(input.data(), std::distance(input.begin(), pointer));
 7370|  1.43k|  ada_log("percent_encode processing ", std::distance(pointer, input.end()),
 7371|  1.43k|          " bytes");
 7372|  56.7k|  for (; pointer != input.end(); pointer++) {
  ------------------
  |  Branch (7372:10): [True: 55.3k, False: 1.43k]
  ------------------
 7373|  55.3k|    if (character_sets::bit_at(character_set, *pointer)) {
  ------------------
  |  Branch (7373:9): [True: 38.8k, False: 16.4k]
  ------------------
 7374|  38.8k|      out.append(character_sets::hex + uint8_t(*pointer) * 4, 3);
 7375|  38.8k|    } else {
 7376|  16.4k|      out += *pointer;
 7377|  16.4k|    }
 7378|  55.3k|  }
 7379|  1.43k|  return true;
 7380|  3.30k|}
_ZN3ada7unicode22form_urlencoded_decodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 7249|  55.4k|std::string form_urlencoded_decode(const std::string_view input) {
 7250|  55.4k|  const size_t len = input.size();
 7251|  55.4k|  if (len == 0) [[unlikely]] {
  ------------------
  |  Branch (7251:7): [True: 27.0k, False: 28.3k]
  ------------------
 7252|  27.0k|    return {};
 7253|  27.0k|  }
 7254|       |
 7255|       |  // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage)
 7256|  28.3k|  const char* const src = input.data();
 7257|  28.3k|  const char* const end = src + len;
 7258|  28.3k|  const char* p = src;
 7259|       |
 7260|       |  // Advance over the untransformed prefix.
 7261|   101k|  while (p < end && *p != '+' && *p != '%') {
  ------------------
  |  Branch (7261:10): [True: 90.6k, False: 10.3k]
  |  Branch (7261:21): [True: 89.0k, False: 1.64k]
  |  Branch (7261:34): [True: 72.7k, False: 16.3k]
  ------------------
 7262|  72.7k|    ++p;
 7263|  72.7k|  }
 7264|  28.3k|  if (p == end) {
  ------------------
  |  Branch (7264:7): [True: 10.3k, False: 17.9k]
  ------------------
 7265|  10.3k|    return std::string(input);
 7266|  10.3k|  }
 7267|       |
 7268|       |  // Output is always at most as long as the input: write into a single
 7269|       |  // pre-sized buffer, then shrink to the final length.
 7270|  17.9k|  std::string out(len, '\0');
 7271|  17.9k|  char* d = out.data();
 7272|  17.9k|  char* const d0 = d;
 7273|       |
 7274|  17.9k|  const size_t prefix = static_cast<size_t>(p - src);
 7275|  17.9k|  std::memcpy(d, src, prefix);
 7276|  17.9k|  d += prefix;
 7277|       |
 7278|  56.2k|  while (p < end) {
  ------------------
  |  Branch (7278:10): [True: 38.2k, False: 17.9k]
  ------------------
 7279|  38.2k|    const char c = *p;
 7280|  38.2k|    if (c == '+') {
  ------------------
  |  Branch (7280:9): [True: 6.39k, False: 31.8k]
  ------------------
 7281|  6.39k|      *d++ = ' ';
 7282|  6.39k|      ++p;
 7283|  31.8k|    } else if (c == '%') {
  ------------------
  |  Branch (7283:16): [True: 23.4k, False: 8.32k]
  ------------------
 7284|       |      // Decode runs of valid %XX tightly (common for nested URL query values).
 7285|   144k|      while (p + 2 < end && *p == '%') {
  ------------------
  |  Branch (7285:14): [True: 128k, False: 15.9k]
  |  Branch (7285:29): [True: 122k, False: 6.03k]
  ------------------
 7286|   122k|        const uint8_t hi = unhex_table[static_cast<uint8_t>(p[1])];
 7287|   122k|        const uint8_t lo = unhex_table[static_cast<uint8_t>(p[2])];
 7288|   122k|        if ((hi | lo) >= 16) {
  ------------------
  |  Branch (7288:13): [True: 1.52k, False: 121k]
  ------------------
 7289|  1.52k|          break;
 7290|  1.52k|        }
 7291|   121k|        *d++ = static_cast<char>((hi << 4) | lo);
 7292|   121k|        p += 3;
 7293|   121k|      }
 7294|  23.4k|      if (p < end && *p == '%') {
  ------------------
  |  Branch (7294:11): [True: 11.4k, False: 12.0k]
  |  Branch (7294:22): [True: 4.40k, False: 7.02k]
  ------------------
 7295|       |        // Invalid escape: copy '%' literally and continue.
 7296|  4.40k|        *d++ = *p++;
 7297|  4.40k|      }
 7298|  23.4k|    } else {
 7299|       |      // Copy a plain run until the next '+' or '%'.
 7300|  8.32k|      const char* start = p;
 7301|  8.32k|      ++p;
 7302|  37.4k|      while (p < end && *p != '+' && *p != '%') {
  ------------------
  |  Branch (7302:14): [True: 35.7k, False: 1.70k]
  |  Branch (7302:25): [True: 34.6k, False: 1.07k]
  |  Branch (7302:38): [True: 29.0k, False: 5.54k]
  ------------------
 7303|  29.0k|        ++p;
 7304|  29.0k|      }
 7305|  8.32k|      const size_t n = static_cast<size_t>(p - start);
 7306|  8.32k|      std::memcpy(d, start, n);
 7307|  8.32k|      d += n;
 7308|  8.32k|    }
 7309|  38.2k|  }
 7310|       |
 7311|  17.9k|  out.resize(static_cast<size_t>(d - d0));
 7312|  17.9k|  return out;
 7313|  28.3k|}
_ZN3ada7unicode14percent_encodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKh:
 7319|   118k|                           const uint8_t character_set[]) {
 7320|   118k|  auto pointer = std::ranges::find_if(input, [character_set](const char c) {
 7321|   118k|    return character_sets::bit_at(character_set, c);
 7322|   118k|  });
 7323|       |  // Optimization: Don't iterate if percent encode is not required
 7324|   118k|  if (pointer == input.end()) {
  ------------------
  |  Branch (7324:7): [True: 81.0k, False: 37.1k]
  ------------------
 7325|  81.0k|    return std::string(input);
 7326|  81.0k|  }
 7327|       |
 7328|  37.1k|  std::string result;
 7329|  37.1k|  result.reserve(input.length());  // in the worst case, percent encoding might
 7330|       |                                   // produce 3 characters.
 7331|  37.1k|  result.append(input.substr(0, std::distance(input.begin(), pointer)));
 7332|  37.1k|  if (static_cast<size_t>(input.end() - pointer) >= 48) {
  ------------------
  |  Branch (7332:7): [True: 3.35k, False: 33.8k]
  ------------------
 7333|  3.35k|    percent_encode_suffix(&*pointer, input.data() + input.size(), character_set,
 7334|  3.35k|                          result);
 7335|  33.8k|  } else {
 7336|   198k|    for (; pointer != input.end(); pointer++) {
  ------------------
  |  Branch (7336:12): [True: 164k, False: 33.8k]
  ------------------
 7337|   164k|      if (character_sets::bit_at(character_set, *pointer)) {
  ------------------
  |  Branch (7337:11): [True: 141k, False: 22.9k]
  ------------------
 7338|   141k|        result.append(character_sets::hex + uint8_t(*pointer) * 4, 3);
 7339|   141k|      } else {
 7340|  22.9k|        result += *pointer;
 7341|  22.9k|      }
 7342|   164k|    }
 7343|  33.8k|  }
 7344|  37.1k|  return result;
 7345|   118k|}
_ZN3ada7unicode21percent_encode_suffixEPKcS2_PKhRNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEE:
 7720|  3.35k|                           const uint8_t character_set[], std::string& out) {
 7721|  3.35k|#if ADA_UNICODE_SSSE3 || ADA_NEON || ADA_RVV
 7722|  3.35k|  if (static_cast<size_t>(end - p) >= kPercentEncodeSimdMin) {
  ------------------
  |  Branch (7722:7): [True: 3.35k, False: 0]
  ------------------
 7723|  3.35k|    percent_encode_to_wide(p, end, character_set, out);
 7724|  3.35k|    return;
 7725|  3.35k|  }
 7726|      0|#endif
 7727|      0|  percent_encode_to_scalar(p, end, character_set, out);
 7728|      0|}
_ZN3ada5parseINS_14url_aggregatorEEEN2tl8expectedIT_NS_6errorsEEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEPKS4_:
 8268|  3.05k|    std::string_view input, const result_type* base_url) {
 8269|  3.05k|  result_type u = ada::parser::parse_url_impl<result_type>(input, base_url);
 8270|  3.05k|  if (!u.is_valid) {
  ------------------
  |  Branch (8270:7): [True: 0, False: 3.05k]
  ------------------
 8271|      0|    return tl::unexpected(errors::type_error);
 8272|      0|  }
 8273|  3.05k|  return u;
 8274|  3.05k|}
_ZN3ada20get_max_input_lengthEv:
 7889|  11.0k|uint32_t get_max_input_length() {
 7890|  11.0k|  return max_input_length_.load(std::memory_order_relaxed);
 7891|  11.0k|}
_ZN3ada7helpers18trim_c0_whitespaceERNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9243|    500|void trim_c0_whitespace(std::string_view& input) noexcept {
 9244|    500|  while (!input.empty() &&
  ------------------
  |  Branch (9244:10): [True: 500, False: 0]
  ------------------
 9245|    500|         ada::unicode::is_c0_control_or_space(input.front())) {
  ------------------
  |  Branch (9245:10): [True: 0, False: 500]
  ------------------
 9246|      0|    input.remove_prefix(1);
 9247|      0|  }
 9248|  2.91k|  while (!input.empty() && ada::unicode::is_c0_control_or_space(input.back())) {
  ------------------
  |  Branch (9248:10): [True: 2.91k, False: 0]
  |  Branch (9248:28): [True: 2.41k, False: 500]
  ------------------
 9249|  2.41k|    input.remove_suffix(1);
 9250|  2.41k|  }
 9251|    500|}
_ZN3ada6parser25try_parse_simple_absoluteINS_14url_aggregatorEEEbNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEERT_:
11946|  3.05k|                                                result_type& out) {
11947|  3.05k|  constexpr bool is_ada_url = std::is_same_v<result_type, ada::url>;
11948|  3.05k|  constexpr bool is_aggregator =
11949|  3.05k|      std::is_same_v<result_type, ada::url_aggregator>;
11950|  3.05k|  static_assert(is_ada_url || is_aggregator);
11951|       |
11952|  3.05k|  const size_t len = input.size();
11953|       |  // Shortest accepted form is "ws://x" (6).
11954|  3.05k|  if (len < 6) [[unlikely]] {
  ------------------
  |  Branch (11954:7): [True: 0, False: 3.05k]
  ------------------
11955|      0|    return false;
11956|      0|  }
11957|  3.05k|  const auto* b = reinterpret_cast<const uint8_t*>(input.data());
11958|       |
11959|  3.05k|  size_t pos = 0;
11960|  3.05k|  ada::scheme::type scheme_type = ada::scheme::type::NOT_SPECIAL;
11961|  3.05k|  uint32_t protocol_end = 0;
11962|  3.05k|#if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \
11963|  3.05k|    defined(_M_X64) || defined(_M_IX86) || defined(_M_AMD64)
11964|       |  // One 8-byte load + integer compare is a single cmp/jcc on x86-64.
11965|       |  // Masked compares cover the shorter special schemes without extra loads.
11966|  3.05k|  if (len >= 8) {
  ------------------
  |  Branch (11966:7): [True: 3.05k, False: 0]
  ------------------
11967|  3.05k|    uint64_t first8 = 0;
11968|  3.05k|    std::memcpy(&first8, b, 8);
11969|  3.05k|    if (first8 == 0x2f2f3a7370747468ull) {  // "https://"
  ------------------
  |  Branch (11969:9): [True: 3.05k, False: 0]
  ------------------
11970|  3.05k|      pos = 8;
11971|  3.05k|      scheme_type = ada::scheme::type::HTTPS;
11972|  3.05k|      protocol_end = 6;
11973|  3.05k|    } else if ((first8 & 0x00ffffffffffffffull) ==
  ------------------
  |  Branch (11973:16): [True: 0, False: 0]
  ------------------
11974|      0|               0x002f2f3a70747468ull) {  // "http://"
11975|      0|      pos = 7;
11976|      0|      scheme_type = ada::scheme::type::HTTP;
11977|      0|      protocol_end = 5;
11978|      0|    } else if ((first8 & 0x0000ffffffffffffull) ==
  ------------------
  |  Branch (11978:16): [True: 0, False: 0]
  ------------------
11979|      0|               0x00002f2f3a737377ull) {  // "wss://"
11980|      0|      pos = 6;
11981|      0|      scheme_type = ada::scheme::type::WSS;
11982|      0|      protocol_end = 4;
11983|      0|    } else if ((first8 & 0x0000ffffffffffffull) ==
  ------------------
  |  Branch (11983:16): [True: 0, False: 0]
  ------------------
11984|      0|               0x00002f2f3a707466ull) {  // "ftp://"
11985|      0|      pos = 6;
11986|      0|      scheme_type = ada::scheme::type::FTP;
11987|      0|      protocol_end = 4;
11988|      0|    } else if ((first8 & 0x000000ffffffffffull) ==
  ------------------
  |  Branch (11988:16): [True: 0, False: 0]
  ------------------
11989|      0|               0x0000002f2f3a7377ull) {  // "ws://"
11990|      0|      pos = 5;
11991|      0|      scheme_type = ada::scheme::type::WS;
11992|      0|      protocol_end = 3;
11993|      0|    } else {
11994|      0|      return false;
11995|      0|    }
11996|  3.05k|  } else if (b[0] == 'w' && b[1] == 's') {
  ------------------
  |  Branch (11996:14): [True: 0, False: 0]
  |  Branch (11996:29): [True: 0, False: 0]
  ------------------
11997|      0|    if (b[2] == ':' && b[3] == '/' && b[4] == '/') {
  ------------------
  |  Branch (11997:9): [True: 0, False: 0]
  |  Branch (11997:24): [True: 0, False: 0]
  |  Branch (11997:39): [True: 0, False: 0]
  ------------------
11998|      0|      pos = 5;
11999|      0|      scheme_type = ada::scheme::type::WS;
12000|      0|      protocol_end = 3;
12001|      0|    } else if (b[2] == 's' && b[3] == ':' && b[4] == '/' && b[5] == '/') {
  ------------------
  |  Branch (12001:16): [True: 0, False: 0]
  |  Branch (12001:31): [True: 0, False: 0]
  |  Branch (12001:46): [True: 0, False: 0]
  |  Branch (12001:61): [True: 0, False: 0]
  ------------------
12002|      0|      pos = 6;
12003|      0|      scheme_type = ada::scheme::type::WSS;
12004|      0|      protocol_end = 4;
12005|      0|    } else {
12006|      0|      return false;
12007|      0|    }
12008|      0|  } else if (b[0] == 'f' && b[1] == 't' && b[2] == 'p' && b[3] == ':' &&
  ------------------
  |  Branch (12008:14): [True: 0, False: 0]
  |  Branch (12008:29): [True: 0, False: 0]
  |  Branch (12008:44): [True: 0, False: 0]
  |  Branch (12008:59): [True: 0, False: 0]
  ------------------
12009|      0|             b[4] == '/' && b[5] == '/') {
  ------------------
  |  Branch (12009:14): [True: 0, False: 0]
  |  Branch (12009:29): [True: 0, False: 0]
  ------------------
12010|      0|    pos = 6;
12011|      0|    scheme_type = ada::scheme::type::FTP;
12012|      0|    protocol_end = 4;
12013|      0|  } else if (len >= 7 && b[0] == 'h' && b[1] == 't' && b[2] == 't' &&
  ------------------
  |  Branch (12013:14): [True: 0, False: 0]
  |  Branch (12013:26): [True: 0, False: 0]
  |  Branch (12013:41): [True: 0, False: 0]
  |  Branch (12013:56): [True: 0, False: 0]
  ------------------
12014|      0|             b[3] == 'p' && b[4] == ':' && b[5] == '/' && b[6] == '/') {
  ------------------
  |  Branch (12014:14): [True: 0, False: 0]
  |  Branch (12014:29): [True: 0, False: 0]
  |  Branch (12014:44): [True: 0, False: 0]
  |  Branch (12014:59): [True: 0, False: 0]
  ------------------
12015|      0|    pos = 7;
12016|      0|    scheme_type = ada::scheme::type::HTTP;
12017|      0|    protocol_end = 5;
12018|      0|  } else {
12019|      0|    return false;
12020|      0|  }
12021|       |#else
12022|       |  // Big-endian / uncommon arches: byte-wise special-scheme match.
12023|       |  if (len >= 8 && b[0] == 'h' && b[1] == 't' && b[2] == 't' && b[3] == 'p' &&
12024|       |      b[4] == 's' && b[5] == ':' && b[6] == '/' && b[7] == '/') {
12025|       |    pos = 8;
12026|       |    scheme_type = ada::scheme::type::HTTPS;
12027|       |    protocol_end = 6;
12028|       |  } else if (len >= 7 && b[0] == 'h' && b[1] == 't' && b[2] == 't' &&
12029|       |             b[3] == 'p' && b[4] == ':' && b[5] == '/' && b[6] == '/') {
12030|       |    pos = 7;
12031|       |    scheme_type = ada::scheme::type::HTTP;
12032|       |    protocol_end = 5;
12033|       |  } else if (b[0] == 'w' && b[1] == 's') {
12034|       |    if (b[2] == ':' && b[3] == '/' && b[4] == '/') {
12035|       |      pos = 5;
12036|       |      scheme_type = ada::scheme::type::WS;
12037|       |      protocol_end = 3;
12038|       |    } else if (len >= 6 && b[2] == 's' && b[3] == ':' && b[4] == '/' &&
12039|       |               b[5] == '/') {
12040|       |      pos = 6;
12041|       |      scheme_type = ada::scheme::type::WSS;
12042|       |      protocol_end = 4;
12043|       |    } else {
12044|       |      return false;
12045|       |    }
12046|       |  } else if (b[0] == 'f' && b[1] == 't' && b[2] == 'p' && b[3] == ':' &&
12047|       |             b[4] == '/' && b[5] == '/') {
12048|       |    pos = 6;
12049|       |    scheme_type = ada::scheme::type::FTP;
12050|       |    protocol_end = 4;
12051|       |  } else {
12052|       |    return false;
12053|       |  }
12054|       |#endif
12055|  3.05k|  if (pos < len && (b[pos] == '/' || b[pos] == '\\')) [[unlikely]] {
  ------------------
  |  Branch (12055:7): [True: 3.05k, False: 0]
  |  Branch (12055:21): [True: 0, False: 3.05k]
  |  Branch (12055:38): [True: 0, False: 3.05k]
  ------------------
12056|      0|    return false;
12057|      0|  }
12058|       |
12059|       |  // Digit-led hosts are IPv4/numeric; '[' is IPv6. Skip before scanning.
12060|  3.05k|  if (pos < len && ((b[pos] >= '0' && b[pos] <= '9') || b[pos] == '[')) {
  ------------------
  |  Branch (12060:7): [True: 3.05k, False: 0]
  |  Branch (12060:22): [True: 3.05k, False: 0]
  |  Branch (12060:39): [True: 0, False: 3.05k]
  |  Branch (12060:57): [True: 0, False: 3.05k]
  ------------------
12061|      0|    return false;
12062|      0|  }
12063|       |
12064|  3.05k|  const size_t host_start = pos;
12065|  3.05k|  bool has_upper = false;
12066|  3.05k|  bool has_x = false;
12067|  3.05k|  size_t host_end = pos;
12068|  3.05k|  if (!scan_plain_host(b, pos, len, host_end, has_upper, has_x)) {
  ------------------
  |  Branch (12068:7): [True: 0, False: 3.05k]
  ------------------
12069|      0|    return false;
12070|      0|  }
12071|  3.05k|  if (host_start == host_end) [[unlikely]] {
  ------------------
  |  Branch (12071:7): [True: 0, False: 3.05k]
  ------------------
12072|      0|    return false;
12073|      0|  }
12074|  3.05k|  const size_t host_len = host_end - host_start;
12075|  3.05k|  if (host_len > 253) [[unlikely]] {
  ------------------
  |  Branch (12075:7): [True: 0, False: 3.05k]
  ------------------
12076|      0|    return false;
12077|      0|  }
12078|  3.05k|  {
12079|  3.05k|    std::string_view hv(input.data() + host_start, host_len);
12080|  3.05k|    char host_buf[256];
12081|  3.05k|    if (has_upper) [[unlikely]] {
  ------------------
  |  Branch (12081:9): [True: 0, False: 3.05k]
  ------------------
12082|      0|      std::memcpy(host_buf, input.data() + host_start, host_len);
12083|      0|      unicode::to_lower_ascii(host_buf, host_len);
12084|      0|      hv = std::string_view(host_buf, host_len);
12085|      0|    }
12086|  3.05k|    if (ada::checkers::last_label_may_be_a_number(hv)) [[unlikely]] {
  ------------------
  |  Branch (12086:9): [True: 0, False: 3.05k]
  ------------------
12087|      0|      return false;
12088|      0|    }
12089|       |    // Punycode is "xn--...". The host scan already notes a lowercase 'x';
12090|       |    // uppercase 'X' is covered by has_upper after the in-place lower.
12091|  3.05k|    static constexpr std::string_view xn{"xn-", 3};
12092|  3.05k|    if ((has_x || has_upper) && hv.find(xn) != std::string_view::npos)
  ------------------
  |  Branch (12092:10): [True: 3.05k, False: 0]
  |  Branch (12092:19): [True: 0, False: 0]
  |  Branch (12092:33): [True: 0, False: 3.05k]
  ------------------
12093|      0|        [[unlikely]] {
12094|      0|      return false;
12095|      0|    }
12096|  3.05k|  }
12097|       |
12098|  3.05k|  if (host_end < len && b[host_end] == ':') [[unlikely]] {
  ------------------
  |  Branch (12098:7): [True: 3.05k, False: 0]
  |  Branch (12098:25): [True: 0, False: 3.05k]
  ------------------
12099|      0|    return finish_simple_absolute_with_port(input, out, scheme_type,
12100|      0|                                            protocol_end, host_start, host_end,
12101|      0|                                            host_len, has_upper);
12102|      0|  }
12103|       |
12104|  3.05k|  size_t i = host_end;
12105|  3.05k|  size_t path_start = host_end;
12106|  3.05k|  size_t path_end = host_end;
12107|  3.05k|  size_t query_start = std::string_view::npos;
12108|  3.05k|  size_t hash_start = std::string_view::npos;
12109|  3.05k|  bool has_path = false;
12110|  3.05k|  bool maybe_dot_segment = false;
12111|  3.05k|  bool rest_simple = true;
12112|       |
12113|  3.05k|  if (i < len && b[i] == '/') {
  ------------------
  |  Branch (12113:7): [True: 3.05k, False: 0]
  |  Branch (12113:18): [True: 3.05k, False: 0]
  ------------------
12114|  3.05k|    has_path = true;
12115|  3.05k|    path_start = i;
12116|  3.05k|    ++i;
12117|  3.05k|    scan_path_run(b, i, len, maybe_dot_segment);
12118|  3.05k|    if (i < len) {
  ------------------
  |  Branch (12118:9): [True: 3.05k, False: 0]
  ------------------
12119|  3.05k|      const uint8_t cls = k_path[b[i]];
12120|  3.05k|      if (cls == 1) {
  ------------------
  |  Branch (12120:11): [True: 3.05k, False: 0]
  ------------------
12121|  3.05k|        path_end = i;
12122|  3.05k|        if (b[i] == '?') {
  ------------------
  |  Branch (12122:13): [True: 3.05k, False: 0]
  ------------------
12123|  3.05k|          query_start = i;
12124|  3.05k|          ++i;
12125|  3.05k|          goto scan_query;
12126|  3.05k|        }
12127|      0|        hash_start = i;
12128|      0|        ++i;
12129|      0|        goto scan_hash;
12130|  3.05k|      }
12131|      0|      rest_simple = false;
12132|      0|      for (; i < len; ++i) {
  ------------------
  |  Branch (12132:14): [True: 0, False: 0]
  ------------------
12133|      0|        if (b[i] == '?') {
  ------------------
  |  Branch (12133:13): [True: 0, False: 0]
  ------------------
12134|      0|          path_end = i;
12135|      0|          query_start = i;
12136|      0|          ++i;
12137|      0|          goto scan_query_boundary;
12138|      0|        }
12139|      0|        if (b[i] == '#') {
  ------------------
  |  Branch (12139:13): [True: 0, False: 0]
  ------------------
12140|      0|          path_end = i;
12141|      0|          hash_start = i;
12142|      0|          ++i;
12143|      0|          goto after_rest;
12144|      0|        }
12145|      0|      }
12146|      0|      path_end = i;
12147|      0|      goto after_rest;
12148|      0|    }
12149|      0|    path_end = i;
12150|      0|  } else if (i < len && b[i] == '?') {
  ------------------
  |  Branch (12150:14): [True: 0, False: 0]
  |  Branch (12150:25): [True: 0, False: 0]
  ------------------
12151|      0|    query_start = i;
12152|      0|    ++i;
12153|      0|    goto scan_query;
12154|      0|  } else if (i < len && b[i] == '#') {
  ------------------
  |  Branch (12154:14): [True: 0, False: 0]
  |  Branch (12154:25): [True: 0, False: 0]
  ------------------
12155|      0|    hash_start = i;
12156|      0|    ++i;
12157|      0|    goto scan_hash;
12158|      0|  }
12159|      0|  goto after_rest;
12160|       |
12161|  3.05k|scan_query:
12162|  3.05k|  scan_query_run(b, i, len);
12163|  3.05k|  if (i < len) {
  ------------------
  |  Branch (12163:7): [True: 1.66k, False: 1.39k]
  ------------------
12164|  1.66k|    if (b[i] == '#') {
  ------------------
  |  Branch (12164:9): [True: 307, False: 1.35k]
  ------------------
12165|    307|      hash_start = i;
12166|    307|      ++i;
12167|    307|      goto scan_hash;
12168|    307|    }
12169|  1.35k|    rest_simple = false;
12170|  1.35k|    goto scan_query_boundary;
12171|  1.66k|  }
12172|  1.39k|  goto after_rest;
12173|       |
12174|  1.39k|scan_query_boundary:
12175|  54.4k|  for (; i < len; ++i) {
  ------------------
  |  Branch (12175:10): [True: 53.2k, False: 1.17k]
  ------------------
12176|  53.2k|    if (b[i] == '#') {
  ------------------
  |  Branch (12176:9): [True: 185, False: 53.0k]
  ------------------
12177|    185|      hash_start = i;
12178|    185|      ++i;
12179|    185|      goto after_rest;
12180|    185|    }
12181|  53.2k|  }
12182|  1.17k|  goto after_rest;
12183|       |
12184|  1.17k|scan_hash:
12185|    307|  scan_hash_run(b, i, len);
12186|    307|  if (i < len) {
  ------------------
  |  Branch (12186:7): [True: 207, False: 100]
  ------------------
12187|    207|    rest_simple = false;
12188|    207|  }
12189|       |
12190|  3.05k|after_rest:
12191|  3.05k|  if (rest_simple && maybe_dot_segment) {
  ------------------
  |  Branch (12191:7): [True: 1.49k, False: 1.56k]
  |  Branch (12191:22): [True: 0, False: 1.49k]
  ------------------
12192|      0|    const std::string_view path_body(input.data() + path_start,
12193|      0|                                     path_end - path_start);
12194|      0|    if (path_has_dot_segment(path_body)) {
  ------------------
  |  Branch (12194:9): [True: 0, False: 0]
  ------------------
12195|      0|      rest_simple = false;
12196|      0|    }
12197|      0|  }
12198|       |
12199|       |  // The slow path removes ASCII tab/newline anywhere in the input and trims a
12200|       |  // trailing C0 control or space; this fast path does neither. A query or
12201|       |  // fragment reaching the helpers below would keep those bytes percent-encoded
12202|       |  // ("?a\nb" -> "?a%0Ab", "#f " -> "#f%20") instead of stripped, so hand such
12203|       |  // inputs back to the slow path.
12204|  3.05k|  if (!rest_simple && (unicode::is_c0_control_or_space(input.back()) ||
  ------------------
  |  Branch (12204:7): [True: 1.56k, False: 1.49k]
  |  Branch (12204:24): [True: 351, False: 1.21k]
  ------------------
12205|  1.21k|                       unicode::has_tabs_or_newline(input))) {
  ------------------
  |  Branch (12205:24): [True: 149, False: 1.06k]
  ------------------
12206|    500|    return false;
12207|    500|  }
12208|       |
12209|  2.55k|  out.type = scheme_type;
12210|  2.55k|  out.is_valid = true;
12211|  2.55k|  out.has_opaque_path = false;
12212|  2.55k|  out.host_type = DEFAULT;
12213|       |
12214|  2.55k|  if (!rest_simple) {
  ------------------
  |  Branch (12214:7): [True: 1.06k, False: 1.49k]
  ------------------
12215|       |    // Host is a plain domain. Finish path/query/hash with
12216|       |    // the regular helpers
12217|       |    // so percent-encoding and dot segments do not re-parse the authority.
12218|  1.06k|    const std::string_view path_view =
12219|  1.06k|        has_path
  ------------------
  |  Branch (12219:9): [True: 1.06k, False: 0]
  ------------------
12220|  1.06k|            ? std::string_view(input.data() + path_start, path_end - path_start)
12221|  1.06k|            : std::string_view{};
12222|  1.06k|    auto apply_query_and_hash = [&]() {
12223|  1.06k|      if (query_start != std::string_view::npos) {
12224|  1.06k|        const size_t q_end =
12225|  1.06k|            (hash_start != std::string_view::npos) ? hash_start : len;
12226|  1.06k|        out.update_base_search(std::string_view(input.data() + query_start + 1,
12227|  1.06k|                                                q_end - query_start - 1),
12228|  1.06k|                               character_sets::SPECIAL_QUERY_PERCENT_ENCODE);
12229|  1.06k|      }
12230|  1.06k|      if (hash_start != std::string_view::npos) {
12231|  1.06k|        out.update_unencoded_base_hash(std::string_view(
12232|  1.06k|            input.data() + hash_start + 1, len - hash_start - 1));
12233|  1.06k|      }
12234|  1.06k|    };
12235|  1.06k|    if constexpr (is_aggregator) {
12236|  1.06k|      out.buffer.assign(input.substr(0, host_end));
12237|  1.06k|      if (has_upper) {
  ------------------
  |  Branch (12237:11): [True: 0, False: 1.06k]
  ------------------
12238|      0|        unicode::to_lower_ascii(out.buffer.data() + host_start, host_len);
12239|      0|      }
12240|  1.06k|      out.components.protocol_end = protocol_end;
12241|  1.06k|      out.components.username_end = protocol_end + 2;
12242|  1.06k|      out.components.host_start = protocol_end + 2;
12243|  1.06k|      out.components.host_end = static_cast<uint32_t>(host_end);
12244|  1.06k|      out.components.port = url_components::omitted;
12245|  1.06k|      out.components.pathname_start = static_cast<uint32_t>(host_end);
12246|  1.06k|      out.components.search_start = url_components::omitted;
12247|  1.06k|      out.components.hash_start = url_components::omitted;
12248|  1.06k|      out.parse_path(path_view);
12249|  1.06k|      apply_query_and_hash();
12250|       |    } else {
12251|       |      std::string host_str(input.substr(host_start, host_len));
12252|       |      if (has_upper) {
12253|       |        unicode::to_lower_ascii(host_str.data(), host_str.size());
12254|       |      }
12255|       |      out.host = std::move(host_str);
12256|       |      out.parse_path(path_view);
12257|       |      apply_query_and_hash();
12258|       |    }
12259|  1.06k|    return true;
12260|  1.06k|  }
12261|       |
12262|  1.49k|  const bool need_slash = !has_path;
12263|  1.49k|  if constexpr (is_aggregator) {
12264|  1.49k|    if (!need_slash) {
  ------------------
  |  Branch (12264:9): [True: 1.49k, False: 0]
  ------------------
12265|       |      // assign copies once. resize()+memcpy would value-init then overwrite.
12266|  1.49k|      out.buffer.assign(input);
12267|  1.49k|      if (has_upper) {
  ------------------
  |  Branch (12267:11): [True: 0, False: 1.49k]
  ------------------
12268|      0|        unicode::to_lower_ascii(out.buffer.data() + host_start, host_len);
12269|      0|      }
12270|  1.49k|      out.components.protocol_end = protocol_end;
12271|  1.49k|      out.components.username_end = protocol_end + 2;
12272|  1.49k|      out.components.host_start = protocol_end + 2;
12273|  1.49k|      out.components.host_end = static_cast<uint32_t>(host_end);
12274|  1.49k|      out.components.port = url_components::omitted;
12275|  1.49k|      out.components.pathname_start = static_cast<uint32_t>(path_start);
12276|  1.49k|      out.components.search_start = (query_start != std::string_view::npos)
  ------------------
  |  Branch (12276:37): [True: 1.49k, False: 0]
  ------------------
12277|  1.49k|                                        ? static_cast<uint32_t>(query_start)
12278|  1.49k|                                        : url_components::omitted;
12279|  1.49k|      out.components.hash_start = (hash_start != std::string_view::npos)
  ------------------
  |  Branch (12279:35): [True: 100, False: 1.39k]
  ------------------
12280|  1.49k|                                      ? static_cast<uint32_t>(hash_start)
12281|  1.49k|                                      : url_components::omitted;
12282|  1.49k|    } else {
12283|      0|      out.buffer.clear();
12284|      0|      out.buffer.reserve(len + 1);
12285|      0|      out.buffer.append(input.substr(0, host_end));
12286|      0|      out.buffer.push_back('/');
12287|      0|      if (host_end < len) {
  ------------------
  |  Branch (12287:11): [True: 0, False: 0]
  ------------------
12288|      0|        out.buffer.append(input.substr(host_end));
12289|      0|      }
12290|      0|      if (has_upper) {
  ------------------
  |  Branch (12290:11): [True: 0, False: 0]
  ------------------
12291|      0|        unicode::to_lower_ascii(out.buffer.data() + host_start, host_len);
12292|      0|      }
12293|      0|      out.components.protocol_end = protocol_end;
12294|      0|      out.components.username_end = protocol_end + 2;
12295|      0|      out.components.host_start = protocol_end + 2;
12296|      0|      out.components.host_end = static_cast<uint32_t>(host_end);
12297|      0|      out.components.port = url_components::omitted;
12298|      0|      out.components.pathname_start = static_cast<uint32_t>(host_end);
12299|      0|      out.components.search_start = (query_start != std::string_view::npos)
  ------------------
  |  Branch (12299:37): [True: 0, False: 0]
  ------------------
12300|      0|                                        ? static_cast<uint32_t>(query_start + 1)
12301|      0|                                        : url_components::omitted;
12302|      0|      out.components.hash_start = (hash_start != std::string_view::npos)
  ------------------
  |  Branch (12302:35): [True: 0, False: 0]
  ------------------
12303|      0|                                      ? static_cast<uint32_t>(hash_start + 1)
12304|      0|                                      : url_components::omitted;
12305|      0|    }
12306|       |  } else {
12307|       |    std::string host_str(input.substr(host_start, host_len));
12308|       |    if (has_upper) {
12309|       |      unicode::to_lower_ascii(host_str.data(), host_str.size());
12310|       |    }
12311|       |    out.host = std::move(host_str);
12312|       |    if (need_slash) {
12313|       |      out.path = "/";
12314|       |    } else {
12315|       |      out.path.assign(input.data() + path_start, path_end - path_start);
12316|       |    }
12317|       |    if (query_start != std::string_view::npos) {
12318|       |      const size_t q_end =
12319|       |          (hash_start != std::string_view::npos) ? hash_start : len;
12320|       |      out.query.emplace(input.data() + query_start + 1,
12321|       |                        q_end - query_start - 1);
12322|       |    }
12323|       |    if (hash_start != std::string_view::npos) {
12324|       |      out.hash.emplace(input.data() + hash_start + 1, len - hash_start - 1);
12325|       |    }
12326|       |  }
12327|  1.49k|  return true;
12328|  2.55k|}
_ZN3ada6parser14parse_url_implINS_14url_aggregatorELb1EEET_NSt3__117basic_string_viewIcNS4_11char_traitsIcEEEEPKS3_:
12517|  3.05k|                           const result_type* base_url) {
12518|       |  // We can specialize the implementation per type.
12519|       |  // Important: result_type_is_ada_url is evaluated at *compile time*. This
12520|       |  // means that doing if constexpr(result_type_is_ada_url) { something } else {
12521|       |  // something else } is free (at runtime). This means that ada::url_aggregator
12522|       |  // and ada::url **do not have to support the exact same API**.
12523|  3.05k|  constexpr bool result_type_is_ada_url = std::is_same_v<url, result_type>;
12524|  3.05k|  constexpr bool result_type_is_ada_url_aggregator =
12525|  3.05k|      std::is_same_v<url_aggregator, result_type>;
12526|  3.05k|  static_assert(result_type_is_ada_url ||
12527|  3.05k|                result_type_is_ada_url_aggregator);  // We don't support
12528|       |                                                     // anything else for now.
12529|       |
12530|  3.05k|  ada_log("ada::parser::parse_url('", user_input, "' [", user_input.size(),
12531|  3.05k|          " bytes],", (base_url != nullptr ? base_url->to_string() : "null"),
12532|  3.05k|          ")");
12533|       |
12534|  3.05k|  result_type url{};
12535|       |
12536|  3.05k|  const uint32_t max_input_length = ada::get_max_input_length();
12537|       |
12538|       |  // Normalization (percent-encoding, IDNA) can push the serialized URL past
12539|       |  // max_input_length even when the input fit under it. The check at the end of
12540|       |  // the state machine covers URLs that run to completion, but several states
12541|       |  // return early after appending a query or fragment, so run the same check on
12542|       |  // those exits too. Without this, a query- or fragment-terminated URL such as
12543|       |  // file://x/?<...> or https://user@x/?<...> is accepted while the equivalent
12544|       |  // https://x/?<...> that takes the absolute fast path is rejected.
12545|  3.05k|  const auto enforce_max_input_length = [&]() {
12546|  3.05k|    if constexpr (store_values) {
12547|  3.05k|      if (url.is_valid) {
12548|  3.05k|        if constexpr (result_type_is_ada_url_aggregator) {
12549|  3.05k|          if (url.buffer.size() > max_input_length) [[unlikely]] {
12550|  3.05k|            url.is_valid = false;
12551|  3.05k|          }
12552|  3.05k|        } else {
12553|  3.05k|          if (url.get_href_size() > max_input_length) [[unlikely]] {
12554|  3.05k|            url.is_valid = false;
12555|  3.05k|          }
12556|  3.05k|        }
12557|  3.05k|      }
12558|  3.05k|    }
12559|  3.05k|  };
12560|       |
12561|       |  // We refuse to parse URL strings that exceed the maximum input length.
12562|       |  // By default, this is 4GB but can be configured via
12563|       |  // ada::set_max_input_length().
12564|  3.05k|  if (user_input.size() > max_input_length) [[unlikely]] {
  ------------------
  |  Branch (12564:7): [True: 0, False: 3.05k]
  ------------------
12565|      0|    url.is_valid = false;
12566|      0|  }
12567|       |  // Going forward, user_input.size() is in [0,
12568|       |  // std::numeric_limits<uint32_t>::max). If we are provided with an invalid
12569|       |  // base, or the optional_url was invalid, we must return.
12570|  3.05k|  if (base_url != nullptr) {
  ------------------
  |  Branch (12570:7): [True: 0, False: 3.05k]
  ------------------
12571|      0|    url.is_valid &= base_url->is_valid;
12572|      0|  }
12573|  3.05k|  if (!url.is_valid) {
  ------------------
  |  Branch (12573:7): [True: 0, False: 3.05k]
  ------------------
12574|      0|    return url;
12575|      0|  }
12576|       |
12577|       |  // Simple absolute / relative fast paths (before tabs/newline scan).
12578|  3.05k|  if constexpr (store_values) {
12579|  3.05k|    bool hit_fast_path = false;
12580|  3.05k|    if (base_url == nullptr) {
  ------------------
  |  Branch (12580:9): [True: 3.05k, False: 0]
  ------------------
12581|       |      // IPv4/IPv6 and userinfo miss the fast path. Skip the never_inline
12582|       |      // call so those URLs (including SetHref) do not pay for a miss.
12583|  3.05k|      const auto* p = reinterpret_cast<const uint8_t*>(user_input.data());
12584|  3.05k|      const size_t n = user_input.size();
12585|  3.05k|      size_t host_start = 0;
12586|  3.05k|      if (n >= 8 && p[4] == ':' && p[5] == '/' && p[6] == '/') {
  ------------------
  |  Branch (12586:11): [True: 3.05k, False: 0]
  |  Branch (12586:21): [True: 0, False: 3.05k]
  |  Branch (12586:36): [True: 0, False: 0]
  |  Branch (12586:51): [True: 0, False: 0]
  ------------------
12587|      0|        host_start = 7;
12588|  3.05k|      } else if (n >= 9 && p[5] == ':' && p[6] == '/' && p[7] == '/') {
  ------------------
  |  Branch (12588:18): [True: 3.05k, False: 0]
  |  Branch (12588:28): [True: 3.05k, False: 0]
  |  Branch (12588:43): [True: 3.05k, False: 0]
  |  Branch (12588:58): [True: 3.05k, False: 0]
  ------------------
12589|  3.05k|        host_start = 8;
12590|  3.05k|      }
12591|  3.05k|      const uint8_t host_first = host_start != 0 ? p[host_start] : 0;
  ------------------
  |  Branch (12591:34): [True: 3.05k, False: 0]
  ------------------
12592|  3.05k|      const bool skip_ip =
12593|  3.05k|          host_first == '[' || (host_first >= '0' && host_first <= '9');
  ------------------
  |  Branch (12593:11): [True: 0, False: 3.05k]
  |  Branch (12593:33): [True: 3.05k, False: 0]
  |  Branch (12593:54): [True: 0, False: 3.05k]
  ------------------
12594|  3.05k|      const bool skip_userinfo =
12595|  3.05k|          host_start != 0 && authority_has_at(p, host_start, n);
  ------------------
  |  Branch (12595:11): [True: 3.05k, False: 0]
  |  Branch (12595:30): [True: 0, False: 3.05k]
  ------------------
12596|  3.05k|      hit_fast_path = !skip_ip && !skip_userinfo &&
  ------------------
  |  Branch (12596:23): [True: 3.05k, False: 0]
  |  Branch (12596:35): [True: 3.05k, False: 0]
  ------------------
12597|  3.05k|                      try_parse_simple_absolute(user_input, url);
  ------------------
  |  Branch (12597:23): [True: 2.55k, False: 500]
  ------------------
12598|  3.05k|    } else {
12599|      0|      hit_fast_path = try_parse_simple_relative(user_input, *base_url, url);
12600|      0|    }
12601|  3.05k|    if (hit_fast_path) {
  ------------------
  |  Branch (12601:9): [True: 2.55k, False: 500]
  ------------------
12602|  2.55k|      if constexpr (result_type_is_ada_url_aggregator) {
12603|  2.55k|        if (url.buffer.size() > max_input_length) [[unlikely]] {
  ------------------
  |  Branch (12603:13): [True: 0, False: 2.55k]
  ------------------
12604|      0|          url.is_valid = false;
12605|      0|        }
12606|       |      } else {
12607|       |        // For a small absolute input, even worst-case normalization cannot
12608|       |        // exceed the limit: percent encoding expands at most 3x and IDNA at
12609|       |        // most 4.5x. Avoid traversing every stored component on the common
12610|       |        // default-limit path.
12611|       |        if ((base_url != nullptr ||
12612|       |             user_input.size() > static_cast<size_t>(max_input_length) / 5) &&
12613|       |            url.get_href_size() > max_input_length) [[unlikely]] {
12614|       |          url.is_valid = false;
12615|       |        }
12616|       |      }
12617|  2.55k|      return url;
12618|  2.55k|    }
12619|  3.05k|  }
12620|       |
12621|    500|  state state = state::SCHEME_START;
12622|       |
12623|  3.05k|  std::string tmp_buffer;
12624|  3.05k|  std::string_view url_data;
12625|  3.05k|  if (unicode::has_tabs_or_newline(user_input)) [[unlikely]] {
  ------------------
  |  Branch (12625:7): [True: 245, False: 2.80k]
  ------------------
12626|    245|    tmp_buffer = user_input;
12627|       |    // Optimization opportunity: Instead of copying and then pruning, we could
12628|       |    // just directly build the string from user_input.
12629|    245|    helpers::remove_ascii_tab_or_newline(tmp_buffer);
12630|    245|    url_data = tmp_buffer;
12631|  2.80k|  } else [[likely]] {
12632|  2.80k|    url_data = user_input;
12633|  2.80k|  }
12634|       |
12635|       |  // Leading and trailing control characters are uncommon and easy to deal with
12636|       |  // (no performance concern).
12637|  3.05k|  helpers::trim_c0_whitespace(url_data);
12638|       |
12639|  3.05k|  if constexpr (result_type_is_ada_url_aggregator && store_values) {
12640|       |    // Most of the time, we just need user_input.size().
12641|       |    // In some instances, we may need a bit more.
12642|       |    ///////////////////////////
12643|       |    // This is *very* important. This line should *not* be removed
12644|       |    // hastily. There are principled reasons why reserve is important
12645|       |    // for performance. If you have a benchmark with small inputs,
12646|       |    // it may not matter, but in other instances, it could.
12647|       |    ////
12648|       |    // This rounds up to the next power of two.
12649|       |    // We know that user_input.size() is in [0,
12650|       |    // std::numeric_limits<uint32_t>::max).
12651|  3.05k|    uint32_t reserve_capacity =
12652|  3.05k|        (0xFFFFFFFF >>
12653|  3.05k|         helpers::leading_zeroes(uint32_t(1 | user_input.size()))) +
12654|  3.05k|        1;
12655|  3.05k|    url.reserve(reserve_capacity);
12656|  3.05k|  }
12657|       |
12658|       |  // Optimization opportunity. Most websites do not have fragment.
12659|  3.05k|  std::optional<std::string_view> fragment = helpers::prune_hash(url_data);
12660|       |  // We add it last so that an implementation like ada::url_aggregator
12661|       |  // can append it last to its internal buffer, thus improving performance.
12662|       |
12663|       |  // Here url_data no longer has its fragment.
12664|       |  // We are going to access the data from url_data (it is immutable).
12665|       |  // At any given time, we are pointing at byte 'input_position' in url_data.
12666|       |  // The input_position variable should range from 0 to input_size.
12667|       |  // It is illegal to access url_data at input_size.
12668|  3.05k|  size_t input_position = 0;
12669|  3.05k|  const size_t input_size = url_data.size();
12670|       |  // Keep running the following state machine by switching on state.
12671|       |  // If after a run pointer points to the EOF code point, go to the next step.
12672|       |  // Otherwise, increase pointer by 1 and continue with the state machine.
12673|       |  // We never decrement input_position.
12674|  6.55k|  while (input_position <= input_size) {
  ------------------
  |  Branch (12674:10): [True: 4.00k, False: 2.55k]
  ------------------
12675|  4.00k|    ada_log("In parsing at ", input_position, " out of ", input_size,
12676|  4.00k|            " in state ", ada::to_string(state));
12677|  4.00k|    switch (state) {
12678|    500|      case state::SCHEME_START: {
  ------------------
  |  Branch (12678:7): [True: 500, False: 3.50k]
  ------------------
12679|    500|        ada_log("SCHEME_START ", helpers::substring(url_data, input_position));
12680|       |        // If c is an ASCII alpha, append c, lowercased, to buffer, and set
12681|       |        // state to scheme state.
12682|    500|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12682:13): [True: 500, False: 0]
  ------------------
12683|    500|            checkers::is_alpha(url_data[input_position])) {
  ------------------
  |  Branch (12683:13): [True: 500, False: 0]
  ------------------
12684|    500|          state = state::SCHEME;
12685|    500|          input_position++;
12686|    500|        } else {
12687|       |          // Otherwise, if state override is not given, set state to no scheme
12688|       |          // state and decrease pointer by 1.
12689|      0|          state = state::NO_SCHEME;
12690|      0|        }
12691|    500|        break;
12692|      0|      }
12693|    500|      case state::SCHEME: {
  ------------------
  |  Branch (12693:7): [True: 500, False: 3.50k]
  ------------------
12694|    500|        ada_log("SCHEME ", helpers::substring(url_data, input_position));
12695|       |        // If c is an ASCII alphanumeric, U+002B (+), U+002D (-), or U+002E (.),
12696|       |        // append c, lowercased, to buffer.
12697|  2.50k|        while ((input_position != input_size) &&
  ------------------
  |  Branch (12697:16): [True: 2.50k, False: 0]
  ------------------
12698|  2.50k|               (unicode::is_alnum_plus(url_data[input_position]))) {
  ------------------
  |  Branch (12698:16): [True: 2.00k, False: 500]
  ------------------
12699|  2.00k|          input_position++;
12700|  2.00k|        }
12701|       |        // Otherwise, if c is U+003A (:), then:
12702|    500|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12702:13): [True: 500, False: 0]
  ------------------
12703|    500|            (url_data[input_position] == ':')) {
  ------------------
  |  Branch (12703:13): [True: 500, False: 0]
  ------------------
12704|    500|          ada_log("SCHEME the scheme should be ",
12705|    500|                  url_data.substr(0, input_position));
12706|       |          if constexpr (result_type_is_ada_url) {
12707|       |            if (!url.parse_scheme(url_data.substr(0, input_position))) {
12708|       |              return url;
12709|       |            }
12710|    500|          } else {
12711|       |            // we pass the colon along instead of painfully adding it back.
12712|    500|            if (!url.parse_scheme_with_colon(
  ------------------
  |  Branch (12712:17): [True: 0, False: 500]
  ------------------
12713|    500|                    url_data.substr(0, input_position + 1))) {
12714|      0|              return url;
12715|      0|            }
12716|    500|          }
12717|    500|          ada_log("SCHEME the scheme is ", url.get_protocol());
12718|       |
12719|       |          // If url's scheme is "file", then:
12720|       |          // NOLINTNEXTLINE(bugprone-branch-clone)
12721|    500|          if (url.type == scheme::type::FILE) {
  ------------------
  |  Branch (12721:15): [True: 0, False: 500]
  ------------------
12722|       |            // Set state to file state.
12723|      0|            state = state::FILE;
12724|      0|          }
12725|       |          // Otherwise, if url is special, base is non-null, and base's scheme
12726|       |          // is url's scheme: Note: Doing base_url->scheme is unsafe if base_url
12727|       |          // != nullptr is false.
12728|    500|          else if (url.is_special() && base_url != nullptr &&
  ------------------
  |  Branch (12728:20): [True: 500, False: 0]
  |  Branch (12728:40): [True: 0, False: 500]
  ------------------
12729|      0|                   base_url->type == url.type) {
  ------------------
  |  Branch (12729:20): [True: 0, False: 0]
  ------------------
12730|       |            // Set state to special relative or authority state.
12731|      0|            state = state::SPECIAL_RELATIVE_OR_AUTHORITY;
12732|      0|          }
12733|       |          // Otherwise, if url is special, set state to special authority
12734|       |          // slashes state.
12735|    500|          else if (url.is_special()) {
  ------------------
  |  Branch (12735:20): [True: 500, False: 0]
  ------------------
12736|    500|            state = state::SPECIAL_AUTHORITY_SLASHES;
12737|    500|          }
12738|       |          // Otherwise, if remaining starts with an U+002F (/), set state to
12739|       |          // path or authority state and increase pointer by 1.
12740|      0|          else if (input_position + 1 < input_size &&
  ------------------
  |  Branch (12740:20): [True: 0, False: 0]
  ------------------
12741|      0|                   url_data[input_position + 1] == '/') {
  ------------------
  |  Branch (12741:20): [True: 0, False: 0]
  ------------------
12742|      0|            state = state::PATH_OR_AUTHORITY;
12743|      0|            input_position++;
12744|      0|          }
12745|       |          // Otherwise, set url's path to the empty string and set state to
12746|       |          // opaque path state.
12747|      0|          else {
12748|      0|            state = state::OPAQUE_PATH;
12749|      0|          }
12750|    500|        }
12751|       |        // Otherwise, if state override is not given, set buffer to the empty
12752|       |        // string, state to no scheme state, and start over (from the first code
12753|       |        // point in input).
12754|      0|        else {
12755|      0|          state = state::NO_SCHEME;
12756|      0|          input_position = 0;
12757|      0|          break;
12758|      0|        }
12759|    500|        input_position++;
12760|    500|        break;
12761|    500|      }
12762|      0|      case state::NO_SCHEME: {
  ------------------
  |  Branch (12762:7): [True: 0, False: 4.00k]
  ------------------
12763|      0|        ada_log("NO_SCHEME ", helpers::substring(url_data, input_position));
12764|       |        // The fragment was pruned from url_data before the state machine ran,
12765|       |        // so 'c is U+0023 (#)' holds exactly when a fragment was found and
12766|       |        // nothing else remains in front of it.
12767|      0|        const bool c_is_hash =
12768|      0|            fragment.has_value() && input_position == input_size;
  ------------------
  |  Branch (12768:13): [True: 0, False: 0]
  |  Branch (12768:37): [True: 0, False: 0]
  ------------------
12769|       |        // If base is null, or base has an opaque path and c is not U+0023 (#),
12770|       |        // validation error, return failure.
12771|      0|        if (base_url == nullptr || (base_url->has_opaque_path && !c_is_hash)) {
  ------------------
  |  Branch (12771:13): [True: 0, False: 0]
  |  Branch (12771:37): [True: 0, False: 0]
  |  Branch (12771:66): [True: 0, False: 0]
  ------------------
12772|      0|          ada_log("NO_SCHEME validation error");
12773|      0|          url.is_valid = false;
12774|      0|          return url;
12775|      0|        }
12776|       |        // Otherwise, if base has an opaque path and c is U+0023 (#),
12777|       |        // set url's scheme to base's scheme, url's path to base's path, url's
12778|       |        // query to base's query, and set state to fragment state.
12779|      0|        else if (base_url->has_opaque_path && c_is_hash) {
  ------------------
  |  Branch (12779:18): [True: 0, False: 0]
  |  Branch (12779:47): [True: 0, False: 0]
  ------------------
12780|      0|          ada_log("NO_SCHEME opaque base with fragment");
12781|      0|          url.copy_scheme(*base_url);
12782|      0|          url.has_opaque_path = base_url->has_opaque_path;
12783|       |
12784|       |          if constexpr (result_type_is_ada_url) {
12785|       |            url.path = base_url->path;
12786|       |            url.query = base_url->query;
12787|      0|          } else {
12788|      0|            url.update_base_pathname(base_url->get_pathname());
12789|      0|            if (base_url->has_search()) {
  ------------------
  |  Branch (12789:17): [True: 0, False: 0]
  ------------------
12790|       |              // get_search() returns "" for an empty query string (URL ends
12791|       |              // with '?'). update_base_search("") would incorrectly clear the
12792|       |              // query, so pass "?" to preserve the empty query distinction.
12793|      0|              auto s = base_url->get_search();
12794|      0|              url.update_base_search(s.empty() ? std::string_view("?") : s);
  ------------------
  |  Branch (12794:38): [True: 0, False: 0]
  ------------------
12795|      0|            }
12796|      0|          }
12797|      0|          url.update_unencoded_base_hash(*fragment);
12798|      0|          enforce_max_input_length();
12799|      0|          return url;
12800|      0|        }
12801|       |        // Otherwise, if base's scheme is not "file", set state to relative
12802|       |        // state and decrease pointer by 1.
12803|       |        // NOLINTNEXTLINE(bugprone-branch-clone)
12804|      0|        else if (base_url->type != scheme::type::FILE) {
  ------------------
  |  Branch (12804:18): [True: 0, False: 0]
  ------------------
12805|      0|          ada_log("NO_SCHEME non-file relative path");
12806|      0|          state = state::RELATIVE_SCHEME;
12807|      0|        }
12808|       |        // Otherwise, set state to file state and decrease pointer by 1.
12809|      0|        else {
12810|      0|          ada_log("NO_SCHEME file base type");
12811|      0|          state = state::FILE;
12812|      0|        }
12813|      0|        break;
12814|      0|      }
12815|    500|      case state::AUTHORITY: {
  ------------------
  |  Branch (12815:7): [True: 500, False: 3.50k]
  ------------------
12816|    500|        ada_log("AUTHORITY ", helpers::substring(url_data, input_position));
12817|       |        // most URLs have no @. Having no @ tells us that we don't have to worry
12818|       |        // about AUTHORITY. Of course, we could have @ and still not have to
12819|       |        // worry about AUTHORITY.
12820|       |        // TODO: Instead of just collecting a bool, collect the location of the
12821|       |        // '@' and do something useful with it.
12822|       |        // TODO: We could do various processing early on, using a single pass
12823|       |        // over the string to collect information about it, e.g., telling us
12824|       |        // whether there is a @ and if so, where (or how many).
12825|       |
12826|       |        // Check if url data contains an @.
12827|    500|        if (url_data.find('@', input_position) == std::string_view::npos) {
  ------------------
  |  Branch (12827:13): [True: 448, False: 52]
  ------------------
12828|    448|          state = state::HOST;
12829|    448|          break;
12830|    448|        }
12831|     52|        bool at_sign_seen{false};
12832|     52|        bool password_token_seen{false};
12833|       |        /**
12834|       |         * We expect something of the sort...
12835|       |         * https://user:pass@example.com:1234/foo/bar?baz#quux
12836|       |         * --------^
12837|       |         */
12838|     52|        do {
12839|     52|          std::string_view view = url_data.substr(input_position);
12840|       |          // The delimiters are @, /, ? \\.
12841|     52|          size_t location =
12842|     52|              url.is_special() ? helpers::find_authority_delimiter_special(view)
  ------------------
  |  Branch (12842:15): [True: 52, False: 0]
  ------------------
12843|     52|                               : helpers::find_authority_delimiter(view);
12844|     52|          std::string_view authority_view = view.substr(0, location);
12845|     52|          size_t end_of_authority = input_position + authority_view.size();
12846|       |          // If c is U+0040 (@), then:
12847|     52|          if ((end_of_authority != input_size) &&
  ------------------
  |  Branch (12847:15): [True: 52, False: 0]
  ------------------
12848|     52|              (url_data[end_of_authority] == '@')) {
  ------------------
  |  Branch (12848:15): [True: 0, False: 52]
  ------------------
12849|       |            // If atSignSeen is true, then prepend "%40" to buffer.
12850|      0|            if (at_sign_seen) {
  ------------------
  |  Branch (12850:17): [True: 0, False: 0]
  ------------------
12851|      0|              if (password_token_seen) {
  ------------------
  |  Branch (12851:19): [True: 0, False: 0]
  ------------------
12852|       |                if constexpr (result_type_is_ada_url) {
12853|       |                  url.password += "%40";
12854|      0|                } else {
12855|      0|                  url.append_base_password("%40");
12856|      0|                }
12857|      0|              } else {
12858|       |                if constexpr (result_type_is_ada_url) {
12859|       |                  url.username += "%40";
12860|      0|                } else {
12861|      0|                  url.append_base_username("%40");
12862|      0|                }
12863|      0|              }
12864|      0|            }
12865|       |
12866|      0|            at_sign_seen = true;
12867|       |
12868|      0|            if (!password_token_seen) {
  ------------------
  |  Branch (12868:17): [True: 0, False: 0]
  ------------------
12869|      0|              size_t password_token_location = authority_view.find(':');
12870|      0|              password_token_seen =
12871|      0|                  password_token_location != std::string_view::npos;
12872|       |
12873|      0|              if constexpr (store_values) {
12874|      0|                if (!password_token_seen) {
  ------------------
  |  Branch (12874:21): [True: 0, False: 0]
  ------------------
12875|       |                  if constexpr (result_type_is_ada_url) {
12876|       |                    url.username += unicode::percent_encode(
12877|       |                        authority_view,
12878|       |                        character_sets::USERINFO_PERCENT_ENCODE);
12879|      0|                  } else {
12880|      0|                    url.append_base_username(unicode::percent_encode(
12881|      0|                        authority_view,
12882|      0|                        character_sets::USERINFO_PERCENT_ENCODE));
12883|      0|                  }
12884|      0|                } else {
12885|       |                  if constexpr (result_type_is_ada_url) {
12886|       |                    url.username += unicode::percent_encode(
12887|       |                        authority_view.substr(0, password_token_location),
12888|       |                        character_sets::USERINFO_PERCENT_ENCODE);
12889|       |                    url.password += unicode::percent_encode(
12890|       |                        authority_view.substr(password_token_location + 1),
12891|       |                        character_sets::USERINFO_PERCENT_ENCODE);
12892|      0|                  } else {
12893|      0|                    url.append_base_username(unicode::percent_encode(
12894|      0|                        authority_view.substr(0, password_token_location),
12895|      0|                        character_sets::USERINFO_PERCENT_ENCODE));
12896|      0|                    url.append_base_password(unicode::percent_encode(
12897|      0|                        authority_view.substr(password_token_location + 1),
12898|      0|                        character_sets::USERINFO_PERCENT_ENCODE));
12899|      0|                  }
12900|      0|                }
12901|      0|              }
12902|      0|            } else if constexpr (store_values) {
12903|       |              if constexpr (result_type_is_ada_url) {
12904|       |                url.password += unicode::percent_encode(
12905|       |                    authority_view, character_sets::USERINFO_PERCENT_ENCODE);
12906|      0|              } else {
12907|      0|                url.append_base_password(unicode::percent_encode(
12908|      0|                    authority_view, character_sets::USERINFO_PERCENT_ENCODE));
12909|      0|              }
12910|      0|            }
12911|      0|          }
12912|       |          // Otherwise, if one of the following is true:
12913|       |          // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
12914|       |          // - url is special and c is U+005C (\)
12915|     52|          else if (end_of_authority == input_size ||
  ------------------
  |  Branch (12915:20): [True: 0, False: 52]
  ------------------
12916|     52|                   url_data[end_of_authority] == '/' ||
  ------------------
  |  Branch (12916:20): [True: 52, False: 0]
  ------------------
12917|      0|                   url_data[end_of_authority] == '?' ||
  ------------------
  |  Branch (12917:20): [True: 0, False: 0]
  ------------------
12918|     52|                   (url.is_special() && url_data[end_of_authority] == '\\')) {
  ------------------
  |  Branch (12918:21): [True: 0, False: 0]
  |  Branch (12918:41): [True: 0, False: 0]
  ------------------
12919|       |            // If atSignSeen is true and authority_view is the empty string,
12920|       |            // validation error, return failure.
12921|     52|            if (at_sign_seen && authority_view.empty()) {
  ------------------
  |  Branch (12921:17): [True: 0, False: 52]
  |  Branch (12921:33): [True: 0, False: 0]
  ------------------
12922|      0|              url.is_valid = false;
12923|      0|              return url;
12924|      0|            }
12925|     52|            state = state::HOST;
12926|     52|            break;
12927|     52|          }
12928|      0|          if (end_of_authority == input_size) {
  ------------------
  |  Branch (12928:15): [True: 0, False: 0]
  ------------------
12929|      0|            if constexpr (store_values) {
12930|      0|              if (fragment.has_value()) {
  ------------------
  |  Branch (12930:19): [True: 0, False: 0]
  ------------------
12931|      0|                url.update_unencoded_base_hash(*fragment);
12932|      0|              }
12933|      0|            }
12934|      0|            enforce_max_input_length();
12935|      0|            return url;
12936|      0|          }
12937|      0|          input_position = end_of_authority + 1;
12938|      0|        } while (true);
  ------------------
  |  Branch (12938:18): [True: 0, Folded]
  ------------------
12939|       |
12940|     52|        break;
12941|     52|      }
12942|     52|      case state::SPECIAL_RELATIVE_OR_AUTHORITY: {
  ------------------
  |  Branch (12942:7): [True: 0, False: 4.00k]
  ------------------
12943|      0|        ada_log("SPECIAL_RELATIVE_OR_AUTHORITY ",
12944|      0|                helpers::substring(url_data, input_position));
12945|       |
12946|       |        // If c is U+002F (/) and remaining starts with U+002F (/),
12947|       |        // then set state to special authority ignore slashes state and increase
12948|       |        // pointer by 1.
12949|      0|        if (url_data.substr(input_position, 2) == "//") {
  ------------------
  |  Branch (12949:13): [True: 0, False: 0]
  ------------------
12950|      0|          state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES;
12951|      0|          input_position += 2;
12952|      0|        } else {
12953|       |          // Otherwise, validation error, set state to relative state and
12954|       |          // decrease pointer by 1.
12955|      0|          state = state::RELATIVE_SCHEME;
12956|      0|        }
12957|       |
12958|      0|        break;
12959|     52|      }
12960|      0|      case state::PATH_OR_AUTHORITY: {
  ------------------
  |  Branch (12960:7): [True: 0, False: 4.00k]
  ------------------
12961|      0|        ada_log("PATH_OR_AUTHORITY ",
12962|      0|                helpers::substring(url_data, input_position));
12963|       |
12964|       |        // If c is U+002F (/), then set state to authority state.
12965|      0|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12965:13): [True: 0, False: 0]
  ------------------
12966|      0|            (url_data[input_position] == '/')) {
  ------------------
  |  Branch (12966:13): [True: 0, False: 0]
  ------------------
12967|      0|          state = state::AUTHORITY;
12968|      0|          input_position++;
12969|      0|        } else {
12970|       |          // Otherwise, set state to path state, and decrease pointer by 1.
12971|      0|          state = state::PATH;
12972|      0|        }
12973|       |
12974|      0|        break;
12975|     52|      }
12976|      0|      case state::RELATIVE_SCHEME: {
  ------------------
  |  Branch (12976:7): [True: 0, False: 4.00k]
  ------------------
12977|      0|        ada_log("RELATIVE_SCHEME ",
12978|      0|                helpers::substring(url_data, input_position));
12979|       |
12980|       |        // Set url's scheme to base's scheme.
12981|      0|        url.copy_scheme(*base_url);
12982|       |
12983|       |        // If c is U+002F (/), then set state to relative slash state.
12984|      0|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12984:13): [True: 0, False: 0]
  ------------------
12985|       |            // NOLINTNEXTLINE(bugprone-branch-clone)
12986|      0|            (url_data[input_position] == '/')) {
  ------------------
  |  Branch (12986:13): [True: 0, False: 0]
  ------------------
12987|      0|          ada_log(
12988|      0|              "RELATIVE_SCHEME if c is U+002F (/), then set state to relative "
12989|      0|              "slash state");
12990|      0|          state = state::RELATIVE_SLASH;
12991|      0|        } else if (url.is_special() && (input_position != input_size) &&
  ------------------
  |  Branch (12991:20): [True: 0, False: 0]
  |  Branch (12991:40): [True: 0, False: 0]
  ------------------
12992|      0|                   (url_data[input_position] == '\\')) {
  ------------------
  |  Branch (12992:20): [True: 0, False: 0]
  ------------------
12993|       |          // Otherwise, if url is special and c is U+005C (\), validation error,
12994|       |          // set state to relative slash state.
12995|      0|          ada_log(
12996|      0|              "RELATIVE_SCHEME  if url is special and c is U+005C, validation "
12997|      0|              "error, set state to relative slash state");
12998|      0|          state = state::RELATIVE_SLASH;
12999|      0|        } else {
13000|      0|          ada_log("RELATIVE_SCHEME otherwise");
13001|       |          // Set url's username to base's username, url's password to base's
13002|       |          // password, url's host to base's host, url's port to base's port,
13003|       |          // url's path to a clone of base's path, and url's query to base's
13004|       |          // query.
13005|       |          if constexpr (result_type_is_ada_url) {
13006|       |            url.username = base_url->username;
13007|       |            url.password = base_url->password;
13008|       |            url.host = base_url->host;
13009|       |            url.port = base_url->port;
13010|       |            // cloning the base path includes cloning the has_opaque_path flag
13011|       |            url.has_opaque_path = base_url->has_opaque_path;
13012|       |            url.path = base_url->path;
13013|       |            url.query = base_url->query;
13014|      0|          } else {
13015|      0|            url.update_base_authority(base_url->get_href(),
13016|      0|                                      base_url->get_components());
13017|      0|            url.update_host_to_base_host(base_url->get_hostname());
13018|      0|            url.update_base_port(base_url->retrieve_base_port());
13019|       |            // cloning the base path includes cloning the has_opaque_path flag
13020|      0|            url.has_opaque_path = base_url->has_opaque_path;
13021|      0|            url.update_base_pathname(base_url->get_pathname());
13022|      0|            if (base_url->has_search()) {
  ------------------
  |  Branch (13022:17): [True: 0, False: 0]
  ------------------
13023|       |              // get_search() returns "" for an empty query string (URL ends
13024|       |              // with '?'). update_base_search("") would incorrectly clear the
13025|       |              // query, so pass "?" to preserve the empty query distinction.
13026|      0|              auto s = base_url->get_search();
13027|      0|              url.update_base_search(s.empty() ? std::string_view("?") : s);
  ------------------
  |  Branch (13027:38): [True: 0, False: 0]
  ------------------
13028|      0|            }
13029|      0|          }
13030|       |
13031|      0|          url.has_opaque_path = base_url->has_opaque_path;
13032|       |
13033|       |          // If c is U+003F (?), then set url's query to the empty string, and
13034|       |          // state to query state.
13035|      0|          if ((input_position != input_size) &&
  ------------------
  |  Branch (13035:15): [True: 0, False: 0]
  ------------------
13036|      0|              (url_data[input_position] == '?')) {
  ------------------
  |  Branch (13036:15): [True: 0, False: 0]
  ------------------
13037|      0|            state = state::QUERY;
13038|      0|          }
13039|       |          // Otherwise, if c is not the EOF code point:
13040|      0|          else if (input_position != input_size) {
  ------------------
  |  Branch (13040:20): [True: 0, False: 0]
  ------------------
13041|       |            // Set url's query to null.
13042|      0|            url.clear_search();
13043|       |            if constexpr (result_type_is_ada_url) {
13044|       |              // Shorten url's path.
13045|       |              helpers::shorten_path(url.path, url.type);
13046|      0|            } else {
13047|      0|              std::string_view path = url.get_pathname();
13048|      0|              if (helpers::shorten_path(path, url.type)) {
  ------------------
  |  Branch (13048:19): [True: 0, False: 0]
  ------------------
13049|      0|                url.update_base_pathname(std::move(std::string(path)));
13050|      0|              }
13051|      0|            }
13052|       |            // Set state to path state and decrease pointer by 1.
13053|      0|            state = state::PATH;
13054|      0|            break;
13055|      0|          }
13056|      0|        }
13057|      0|        input_position++;
13058|      0|        break;
13059|      0|      }
13060|      0|      case state::RELATIVE_SLASH: {
  ------------------
  |  Branch (13060:7): [True: 0, False: 4.00k]
  ------------------
13061|      0|        ada_log("RELATIVE_SLASH ",
13062|      0|                helpers::substring(url_data, input_position));
13063|       |
13064|       |        // If url is special and c is U+002F (/) or U+005C (\), then:
13065|       |        // NOLINTNEXTLINE(bugprone-branch-clone)
13066|      0|        if (url.is_special() && (input_position != input_size) &&
  ------------------
  |  Branch (13066:13): [True: 0, False: 0]
  |  Branch (13066:33): [True: 0, False: 0]
  ------------------
13067|      0|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (13067:14): [True: 0, False: 0]
  ------------------
13068|      0|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (13068:14): [True: 0, False: 0]
  ------------------
13069|       |          // Set state to special authority ignore slashes state.
13070|      0|          state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES;
13071|      0|        }
13072|       |        // Otherwise, if c is U+002F (/), then set state to authority state.
13073|      0|        else if ((input_position != input_size) &&
  ------------------
  |  Branch (13073:18): [True: 0, False: 0]
  ------------------
13074|      0|                 (url_data[input_position] == '/')) {
  ------------------
  |  Branch (13074:18): [True: 0, False: 0]
  ------------------
13075|      0|          state = state::AUTHORITY;
13076|      0|        }
13077|       |        // Otherwise, set
13078|       |        // - url's username to base's username,
13079|       |        // - url's password to base's password,
13080|       |        // - url's host to base's host,
13081|       |        // - url's port to base's port,
13082|       |        // - state to path state, and then, decrease pointer by 1.
13083|      0|        else {
13084|       |          if constexpr (result_type_is_ada_url) {
13085|       |            url.username = base_url->username;
13086|       |            url.password = base_url->password;
13087|       |            url.host = base_url->host;
13088|       |            url.port = base_url->port;
13089|      0|          } else {
13090|      0|            url.update_base_authority(base_url->get_href(),
13091|      0|                                      base_url->get_components());
13092|      0|            url.update_host_to_base_host(base_url->get_hostname());
13093|      0|            url.update_base_port(base_url->retrieve_base_port());
13094|      0|          }
13095|      0|          state = state::PATH;
13096|      0|          break;
13097|      0|        }
13098|       |
13099|      0|        input_position++;
13100|      0|        break;
13101|      0|      }
13102|    500|      case state::SPECIAL_AUTHORITY_SLASHES: {
  ------------------
  |  Branch (13102:7): [True: 500, False: 3.50k]
  ------------------
13103|    500|        ada_log("SPECIAL_AUTHORITY_SLASHES ",
13104|    500|                helpers::substring(url_data, input_position));
13105|       |
13106|       |        // If c is U+002F (/) and remaining starts with U+002F (/),
13107|       |        // then set state to special authority ignore slashes state and increase
13108|       |        // pointer by 1.
13109|    500|        if (url_data.substr(input_position, 2) == "//") {
  ------------------
  |  Branch (13109:13): [True: 500, False: 0]
  ------------------
13110|    500|          input_position += 2;
13111|    500|        }
13112|       |
13113|    500|        [[fallthrough]];
13114|    500|      }
13115|    500|      case state::SPECIAL_AUTHORITY_IGNORE_SLASHES: {
  ------------------
  |  Branch (13115:7): [True: 0, False: 4.00k]
  ------------------
13116|    500|        ada_log("SPECIAL_AUTHORITY_IGNORE_SLASHES ",
13117|    500|                helpers::substring(url_data, input_position));
13118|       |
13119|       |        // If c is neither U+002F (/) nor U+005C (\), then set state to
13120|       |        // authority state and decrease pointer by 1.
13121|    500|        while ((input_position != input_size) &&
  ------------------
  |  Branch (13121:16): [True: 500, False: 0]
  ------------------
13122|    500|               ((url_data[input_position] == '/') ||
  ------------------
  |  Branch (13122:17): [True: 0, False: 500]
  ------------------
13123|    500|                (url_data[input_position] == '\\'))) {
  ------------------
  |  Branch (13123:17): [True: 0, False: 500]
  ------------------
13124|      0|          input_position++;
13125|      0|        }
13126|    500|        state = state::AUTHORITY;
13127|       |
13128|    500|        break;
13129|    500|      }
13130|    500|      case state::QUERY: {
  ------------------
  |  Branch (13130:7): [True: 500, False: 3.50k]
  ------------------
13131|    500|        ada_log("QUERY ", helpers::substring(url_data, input_position));
13132|    500|        if constexpr (store_values) {
13133|       |          // Let queryPercentEncodeSet be the special-query percent-encode set
13134|       |          // if url is special; otherwise the query percent-encode set.
13135|    500|          const uint8_t* query_percent_encode_set =
13136|    500|              url.is_special() ? character_sets::SPECIAL_QUERY_PERCENT_ENCODE
  ------------------
  |  Branch (13136:15): [True: 500, False: 0]
  ------------------
13137|    500|                               : character_sets::QUERY_PERCENT_ENCODE;
13138|       |
13139|       |          // Percent-encode after encoding, with encoding, buffer, and
13140|       |          // queryPercentEncodeSet, and append the result to url's query.
13141|    500|          url.update_base_search(url_data.substr(input_position),
13142|    500|                                 query_percent_encode_set);
13143|    500|          ada_log("QUERY update_base_search completed ");
13144|    500|          if (fragment.has_value()) {
  ------------------
  |  Branch (13144:15): [True: 122, False: 378]
  ------------------
13145|    122|            url.update_unencoded_base_hash(*fragment);
13146|    122|          }
13147|    500|        }
13148|    500|        enforce_max_input_length();
13149|    500|        return url;
13150|    500|      }
13151|    500|      case state::HOST: {
  ------------------
  |  Branch (13151:7): [True: 500, False: 3.50k]
  ------------------
13152|    500|        ada_log("HOST ", helpers::substring(url_data, input_position));
13153|       |
13154|    500|        std::string_view host_view = url_data.substr(input_position);
13155|    500|        auto [location, found_colon] =
13156|    500|            helpers::get_host_delimiter_location(url.is_special(), host_view);
13157|    500|        input_position = (location != std::string_view::npos)
  ------------------
  |  Branch (13157:26): [True: 500, False: 0]
  ------------------
13158|    500|                             ? input_position + location
13159|    500|                             : input_size;
13160|       |        // Otherwise, if c is U+003A (:) and insideBrackets is false, then:
13161|       |        // Note: the 'found_colon' value is true if and only if a colon was
13162|       |        // encountered while not inside brackets.
13163|    500|        if (found_colon) {
  ------------------
  |  Branch (13163:13): [True: 0, False: 500]
  ------------------
13164|       |          // If buffer is the empty string, validation error, return failure.
13165|       |          // Let host be the result of host parsing buffer with url is not
13166|       |          // special.
13167|      0|          ada_log("HOST parsing ", host_view);
13168|      0|          if (!url.parse_host(host_view)) {
  ------------------
  |  Branch (13168:15): [True: 0, False: 0]
  ------------------
13169|      0|            return url;
13170|      0|          }
13171|      0|          ada_log("HOST parsing results in ", url.get_hostname());
13172|       |          // Set url's host to host, buffer to the empty string, and state to
13173|       |          // port state.
13174|      0|          state = state::PORT;
13175|      0|          input_position++;
13176|      0|        }
13177|       |        // Otherwise, if one of the following is true:
13178|       |        // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
13179|       |        // - url is special and c is U+005C (\)
13180|       |        // The get_host_delimiter_location function either brings us to
13181|       |        // the colon outside of the bracket, or to one of those characters.
13182|    500|        else {
13183|       |          // If url is special and host_view is the empty string, validation
13184|       |          // error, return failure.
13185|    500|          if (host_view.empty() && url.is_special()) {
  ------------------
  |  Branch (13185:15): [True: 0, False: 500]
  |  Branch (13185:36): [True: 0, False: 0]
  ------------------
13186|      0|            url.is_valid = false;
13187|      0|            return url;
13188|      0|          }
13189|    500|          ada_log("HOST parsing ", host_view, " href=", url.get_href());
13190|       |          // Let host be the result of host parsing host_view with url is not
13191|       |          // special.
13192|    500|          if (host_view.empty()) {
  ------------------
  |  Branch (13192:15): [True: 0, False: 500]
  ------------------
13193|      0|            url.update_base_hostname("");
13194|    500|          } else if (!url.parse_host(host_view)) {
  ------------------
  |  Branch (13194:22): [True: 0, False: 500]
  ------------------
13195|      0|            return url;
13196|      0|          }
13197|    500|          ada_log("HOST parsing results in ", url.get_hostname(),
13198|    500|                  " href=", url.get_href());
13199|       |
13200|       |          // Set url's host to host, and state to path start state.
13201|    500|          state = state::PATH_START;
13202|    500|        }
13203|       |
13204|    500|        break;
13205|    500|      }
13206|    500|      case state::OPAQUE_PATH: {
  ------------------
  |  Branch (13206:7): [True: 0, False: 4.00k]
  ------------------
13207|      0|        ada_log("OPAQUE_PATH ", helpers::substring(url_data, input_position));
13208|       |        // Opaque path, query, and fragment are structurally always valid:
13209|       |        // the parser would just percent-encode whatever is there. When we
13210|       |        // are not storing values (can_parse), we can return immediately.
13211|       |        // We must set has_opaque_path = true before returning so that when
13212|       |        // this URL is used as an internal base inside can_parse, NO_SCHEME
13213|       |        // correctly rejects relative inputs against an opaque-path base
13214|       |        // (e.g. can_parse("", &"W:") must return false).
13215|       |        if constexpr (!store_values) {
13216|       |          url.has_opaque_path = true;
13217|       |          return url;
13218|       |        }
13219|      0|        std::string_view view = url_data.substr(input_position);
13220|       |        // If c is U+003F (?), then set url's query to the empty string and
13221|       |        // state to query state.
13222|      0|        size_t location = view.find('?');
13223|      0|        if (location != std::string_view::npos) {
  ------------------
  |  Branch (13223:13): [True: 0, False: 0]
  ------------------
13224|      0|          view.remove_suffix(view.size() - location);
13225|      0|          state = state::QUERY;
13226|      0|          input_position += location + 1;
13227|      0|        } else {
13228|      0|          input_position = input_size + 1;
13229|      0|        }
13230|      0|        url.has_opaque_path = true;
13231|       |
13232|       |        // This is a really unlikely scenario in real world. We should not seek
13233|       |        // to optimize it.
13234|      0|        if (view.ends_with(' ')) {
  ------------------
  |  Branch (13234:13): [True: 0, False: 0]
  ------------------
13235|      0|          std::string modified_view =
13236|      0|              std::string(view.substr(0, view.size() - 1)) + "%20";
13237|      0|          url.update_base_pathname(unicode::percent_encode(
13238|      0|              modified_view, character_sets::C0_CONTROL_PERCENT_ENCODE));
13239|      0|        } else {
13240|      0|          url.update_base_pathname(unicode::percent_encode(
13241|      0|              view, character_sets::C0_CONTROL_PERCENT_ENCODE));
13242|      0|        }
13243|      0|        break;
13244|    500|      }
13245|      0|      case state::PORT: {
  ------------------
  |  Branch (13245:7): [True: 0, False: 4.00k]
  ------------------
13246|      0|        ada_log("PORT ", helpers::substring(url_data, input_position));
13247|      0|        std::string_view port_view = url_data.substr(input_position);
13248|      0|        input_position += url.parse_port(port_view, true);
13249|      0|        if (!url.is_valid) {
  ------------------
  |  Branch (13249:13): [True: 0, False: 0]
  ------------------
13250|      0|          return url;
13251|      0|        }
13252|      0|        state = state::PATH_START;
13253|      0|        [[fallthrough]];
13254|      0|      }
13255|    500|      case state::PATH_START: {
  ------------------
  |  Branch (13255:7): [True: 500, False: 3.50k]
  ------------------
13256|    500|        ada_log("PATH_START ", helpers::substring(url_data, input_position));
13257|       |        // Path, query, and fragment are structurally always valid: the
13258|       |        // parser would just percent-encode whatever is there. When we are
13259|       |        // not storing values (can_parse), we can return immediately since
13260|       |        // no subsequent state can invalidate the URL.
13261|       |        if constexpr (!store_values) {
13262|       |          return url;
13263|       |        }
13264|       |
13265|       |        // If url is special, then:
13266|    500|        if (url.is_special()) {
  ------------------
  |  Branch (13266:13): [True: 500, False: 0]
  ------------------
13267|       |          // Set state to path state.
13268|    500|          state = state::PATH;
13269|       |
13270|       |          // Optimization: Avoiding going into PATH state improves the
13271|       |          // performance of urls ending with /.
13272|    500|          if (input_position == input_size) {
  ------------------
  |  Branch (13272:15): [True: 0, False: 500]
  ------------------
13273|      0|            if constexpr (store_values) {
13274|      0|              url.update_base_pathname("/");
13275|      0|              if (fragment.has_value()) {
  ------------------
  |  Branch (13275:19): [True: 0, False: 0]
  ------------------
13276|      0|                url.update_unencoded_base_hash(*fragment);
13277|      0|              }
13278|      0|            }
13279|      0|            enforce_max_input_length();
13280|      0|            return url;
13281|      0|          }
13282|       |          // If c is neither U+002F (/) nor U+005C (\), then decrease pointer
13283|       |          // by 1. We know that (input_position == input_size) is impossible
13284|       |          // here, because of the previous if-check.
13285|    500|          if ((url_data[input_position] != '/') &&
  ------------------
  |  Branch (13285:15): [True: 0, False: 500]
  ------------------
13286|      0|              (url_data[input_position] != '\\')) {
  ------------------
  |  Branch (13286:15): [True: 0, False: 0]
  ------------------
13287|      0|            break;
13288|      0|          }
13289|    500|        }
13290|       |        // Otherwise, if state override is not given and c is U+003F (?),
13291|       |        // set url's query to the empty string and state to query state.
13292|      0|        else if ((input_position != input_size) &&
  ------------------
  |  Branch (13292:18): [True: 0, False: 0]
  ------------------
13293|      0|                 (url_data[input_position] == '?')) {
  ------------------
  |  Branch (13293:18): [True: 0, False: 0]
  ------------------
13294|      0|          state = state::QUERY;
13295|      0|        }
13296|       |        // Otherwise, if c is not the EOF code point:
13297|      0|        else if (input_position != input_size) {
  ------------------
  |  Branch (13297:18): [True: 0, False: 0]
  ------------------
13298|       |          // Set state to path state.
13299|      0|          state = state::PATH;
13300|       |
13301|       |          // If c is not U+002F (/), then decrease pointer by 1.
13302|      0|          if (url_data[input_position] != '/') {
  ------------------
  |  Branch (13302:15): [True: 0, False: 0]
  ------------------
13303|      0|            break;
13304|      0|          }
13305|      0|        }
13306|       |
13307|    500|        input_position++;
13308|    500|        break;
13309|    500|      }
13310|    500|      case state::PATH: {
  ------------------
  |  Branch (13310:7): [True: 500, False: 3.50k]
  ------------------
13311|    500|        ada_log("PATH ", helpers::substring(url_data, input_position));
13312|       |        // Path, query, and fragment are structurally always valid: the
13313|       |        // parser would just percent-encode whatever is there. When we are
13314|       |        // not storing values (can_parse), we can return immediately since
13315|       |        // no subsequent state can invalidate the URL.
13316|       |        if constexpr (!store_values) {
13317|       |          return url;
13318|       |        }
13319|    500|        std::string_view view = url_data.substr(input_position);
13320|       |
13321|       |        // Most time, we do not need percent encoding.
13322|       |        // Furthermore, we can immediately locate the '?'.
13323|    500|        size_t locofquestionmark = view.find('?');
13324|    500|        if (locofquestionmark != std::string_view::npos) {
  ------------------
  |  Branch (13324:13): [True: 500, False: 0]
  ------------------
13325|    500|          state = state::QUERY;
13326|    500|          view.remove_suffix(view.size() - locofquestionmark);
13327|    500|          input_position += locofquestionmark + 1;
13328|    500|        } else {
13329|      0|          input_position = input_size + 1;
13330|      0|        }
13331|    500|        if constexpr (store_values) {
13332|       |          if constexpr (result_type_is_ada_url) {
13333|       |            helpers::parse_prepared_path(view, url.type, url.path);
13334|    500|          } else {
13335|    500|            url.consume_prepared_path(view);
13336|    500|            ADA_ASSERT_TRUE(url.validate());
13337|    500|          }
13338|    500|        }
13339|    500|        break;
13340|    500|      }
13341|      0|      case state::FILE_SLASH: {
  ------------------
  |  Branch (13341:7): [True: 0, False: 4.00k]
  ------------------
13342|      0|        ada_log("FILE_SLASH ", helpers::substring(url_data, input_position));
13343|       |
13344|       |        // If c is U+002F (/) or U+005C (\), then:
13345|      0|        if ((input_position != input_size) &&
  ------------------
  |  Branch (13345:13): [True: 0, False: 0]
  ------------------
13346|      0|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (13346:14): [True: 0, False: 0]
  ------------------
13347|      0|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (13347:14): [True: 0, False: 0]
  ------------------
13348|      0|          ada_log("FILE_SLASH c is U+002F or U+005C");
13349|       |          // Set state to file host state.
13350|      0|          state = state::FILE_HOST;
13351|      0|          input_position++;
13352|      0|        } else {
13353|      0|          ada_log("FILE_SLASH otherwise");
13354|       |          // If base is non-null and base's scheme is "file", then:
13355|       |          // Note: it is unsafe to do base_url->scheme unless you know that
13356|       |          // base_url_has_value() is true.
13357|      0|          if (base_url != nullptr && base_url->type == scheme::type::FILE) {
  ------------------
  |  Branch (13357:15): [True: 0, False: 0]
  |  Branch (13357:38): [True: 0, False: 0]
  ------------------
13358|       |            // Set url's host to base's host.
13359|       |            if constexpr (result_type_is_ada_url) {
13360|       |              url.host = base_url->host;
13361|      0|            } else {
13362|      0|              url.update_host_to_base_host(base_url->get_host());
13363|      0|            }
13364|       |            // If the code point substring from pointer to the end of input does
13365|       |            // not start with a Windows drive letter and base's path[0] is a
13366|       |            // normalized Windows drive letter, then append base's path[0] to
13367|       |            // url's path.
13368|      0|            if (!base_url->get_pathname().empty()) {
  ------------------
  |  Branch (13368:17): [True: 0, False: 0]
  ------------------
13369|      0|              if (!checkers::is_windows_drive_letter(
  ------------------
  |  Branch (13369:19): [True: 0, False: 0]
  ------------------
13370|      0|                      url_data.substr(input_position))) {
13371|      0|                std::string_view first_base_url_path =
13372|      0|                    base_url->get_pathname().substr(1);
13373|      0|                size_t loc = first_base_url_path.find('/');
13374|      0|                if (loc != std::string_view::npos) {
  ------------------
  |  Branch (13374:21): [True: 0, False: 0]
  ------------------
13375|      0|                  helpers::resize(first_base_url_path, loc);
13376|      0|                }
13377|      0|                if (checkers::is_normalized_windows_drive_letter(
  ------------------
  |  Branch (13377:21): [True: 0, False: 0]
  ------------------
13378|      0|                        first_base_url_path)) {
13379|       |                  if constexpr (result_type_is_ada_url) {
13380|       |                    url.path += '/';
13381|       |                    url.path += first_base_url_path;
13382|      0|                  } else {
13383|      0|                    url.append_base_pathname(
13384|      0|                        helpers::concat("/", first_base_url_path));
13385|      0|                  }
13386|      0|                }
13387|      0|              }
13388|      0|            }
13389|      0|          }
13390|       |
13391|       |          // Set state to path state, and decrease pointer by 1.
13392|      0|          state = state::PATH;
13393|      0|        }
13394|       |
13395|      0|        break;
13396|    500|      }
13397|      0|      case state::FILE_HOST: {
  ------------------
  |  Branch (13397:7): [True: 0, False: 4.00k]
  ------------------
13398|      0|        ada_log("FILE_HOST ", helpers::substring(url_data, input_position));
13399|      0|        std::string_view view = url_data.substr(input_position);
13400|       |
13401|      0|        size_t location = view.find_first_of("/\\?");
13402|      0|        std::string_view file_host_buffer = view.substr(
13403|      0|            0, (location != std::string_view::npos) ? location : view.size());
  ------------------
  |  Branch (13403:16): [True: 0, False: 0]
  ------------------
13404|       |
13405|      0|        if (checkers::is_windows_drive_letter(file_host_buffer)) {
  ------------------
  |  Branch (13405:13): [True: 0, False: 0]
  ------------------
13406|      0|          state = state::PATH;
13407|      0|        } else if (file_host_buffer.empty()) {
  ------------------
  |  Branch (13407:20): [True: 0, False: 0]
  ------------------
13408|       |          // Set url's host to the empty string.
13409|       |          if constexpr (result_type_is_ada_url) {
13410|       |            url.host = "";
13411|      0|          } else {
13412|      0|            url.update_base_hostname("");
13413|      0|          }
13414|       |          // Set state to path start state.
13415|      0|          state = state::PATH_START;
13416|      0|        } else {
13417|      0|          size_t consumed_bytes = file_host_buffer.size();
13418|      0|          input_position += consumed_bytes;
13419|       |          // Let host be the result of host parsing buffer with url is not
13420|       |          // special.
13421|      0|          if (!url.parse_host(file_host_buffer)) {
  ------------------
  |  Branch (13421:15): [True: 0, False: 0]
  ------------------
13422|      0|            return url;
13423|      0|          }
13424|       |
13425|       |          if constexpr (result_type_is_ada_url) {
13426|       |            // If host is "localhost", then set host to the empty string.
13427|       |            if (url.host.has_value() && url.host.value() == "localhost") {
13428|       |              url.host = "";
13429|       |            }
13430|      0|          } else {
13431|      0|            if (url.get_hostname() == "localhost") {
  ------------------
  |  Branch (13431:17): [True: 0, False: 0]
  ------------------
13432|      0|              url.update_base_hostname("");
13433|      0|            }
13434|      0|          }
13435|       |
13436|       |          // Set buffer to the empty string and state to path start state.
13437|      0|          state = state::PATH_START;
13438|      0|        }
13439|       |
13440|      0|        break;
13441|      0|      }
13442|      0|      case state::FILE: {
  ------------------
  |  Branch (13442:7): [True: 0, False: 4.00k]
  ------------------
13443|      0|        ada_log("FILE ", helpers::substring(url_data, input_position));
13444|      0|        std::string_view file_view = url_data.substr(input_position);
13445|       |
13446|      0|        url.set_protocol_as_file();
13447|       |        if constexpr (result_type_is_ada_url) {
13448|       |          // Set url's host to the empty string.
13449|       |          url.host = "";
13450|      0|        } else {
13451|      0|          url.update_base_hostname("");
13452|      0|        }
13453|       |        // If c is U+002F (/) or U+005C (\), then:
13454|      0|        if (input_position != input_size &&
  ------------------
  |  Branch (13454:13): [True: 0, False: 0]
  ------------------
13455|      0|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (13455:14): [True: 0, False: 0]
  ------------------
13456|      0|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (13456:14): [True: 0, False: 0]
  ------------------
13457|      0|          ada_log("FILE c is U+002F or U+005C");
13458|       |          // Set state to file slash state.
13459|      0|          state = state::FILE_SLASH;
13460|      0|        }
13461|       |        // Otherwise, if base is non-null and base's scheme is "file":
13462|      0|        else if (base_url != nullptr && base_url->type == scheme::type::FILE) {
  ------------------
  |  Branch (13462:18): [True: 0, False: 0]
  |  Branch (13462:41): [True: 0, False: 0]
  ------------------
13463|       |          // Set url's host to base's host, url's path to a clone of base's
13464|       |          // path, and url's query to base's query.
13465|      0|          ada_log("FILE base non-null");
13466|       |          if constexpr (result_type_is_ada_url) {
13467|       |            url.host = base_url->host;
13468|       |            url.path = base_url->path;
13469|       |            url.query = base_url->query;
13470|      0|          } else {
13471|      0|            url.update_host_to_base_host(base_url->get_hostname());
13472|      0|            url.update_base_pathname(base_url->get_pathname());
13473|      0|            if (base_url->has_search()) {
  ------------------
  |  Branch (13473:17): [True: 0, False: 0]
  ------------------
13474|       |              // get_search() returns "" for an empty query string (URL ends
13475|       |              // with '?'). update_base_search("") would incorrectly clear the
13476|       |              // query, so pass "?" to preserve the empty query distinction.
13477|      0|              auto s = base_url->get_search();
13478|      0|              url.update_base_search(s.empty() ? std::string_view("?") : s);
  ------------------
  |  Branch (13478:38): [True: 0, False: 0]
  ------------------
13479|      0|            }
13480|      0|          }
13481|      0|          url.has_opaque_path = base_url->has_opaque_path;
13482|       |
13483|       |          // If c is U+003F (?), then set url's query to the empty string and
13484|       |          // state to query state.
13485|      0|          if (input_position != input_size && url_data[input_position] == '?') {
  ------------------
  |  Branch (13485:15): [True: 0, False: 0]
  |  Branch (13485:47): [True: 0, False: 0]
  ------------------
13486|      0|            state = state::QUERY;
13487|      0|          }
13488|       |          // Otherwise, if c is not the EOF code point:
13489|      0|          else if (input_position != input_size) {
  ------------------
  |  Branch (13489:20): [True: 0, False: 0]
  ------------------
13490|       |            // Set url's query to null.
13491|      0|            url.clear_search();
13492|       |            // If the code point substring from pointer to the end of input does
13493|       |            // not start with a Windows drive letter, then shorten url's path.
13494|      0|            if (!checkers::is_windows_drive_letter(file_view)) {
  ------------------
  |  Branch (13494:17): [True: 0, False: 0]
  ------------------
13495|       |              if constexpr (result_type_is_ada_url) {
13496|       |                helpers::shorten_path(url.path, url.type);
13497|      0|              } else {
13498|      0|                std::string_view path = url.get_pathname();
13499|      0|                if (helpers::shorten_path(path, url.type)) {
  ------------------
  |  Branch (13499:21): [True: 0, False: 0]
  ------------------
13500|      0|                  url.update_base_pathname(std::move(std::string(path)));
13501|      0|                }
13502|      0|              }
13503|      0|            }
13504|       |            // Otherwise:
13505|      0|            else {
13506|       |              // Set url's path to an empty list.
13507|      0|              url.clear_pathname();
13508|      0|              url.has_opaque_path = true;
13509|      0|            }
13510|       |
13511|       |            // Set state to path state and decrease pointer by 1.
13512|      0|            state = state::PATH;
13513|      0|            break;
13514|      0|          }
13515|      0|        }
13516|       |        // Otherwise, set state to path state, and decrease pointer by 1.
13517|      0|        else {
13518|      0|          ada_log("FILE go to path");
13519|      0|          state = state::PATH;
13520|      0|          break;
13521|      0|        }
13522|       |
13523|      0|        input_position++;
13524|      0|        break;
13525|      0|      }
13526|      0|      default:
  ------------------
  |  Branch (13526:7): [True: 0, False: 4.00k]
  ------------------
13527|      0|        unreachable();
13528|  4.00k|    }
13529|  4.00k|  }
13530|  2.55k|  if constexpr (store_values) {
13531|  2.55k|    if (fragment.has_value()) {
  ------------------
  |  Branch (13531:9): [True: 0, False: 2.55k]
  ------------------
13532|      0|      url.update_unencoded_base_hash(*fragment);
13533|      0|    }
13534|  2.55k|  }
13535|  2.55k|  enforce_max_input_length();
13536|  2.55k|  return url;
13537|  3.05k|}
_ZNK3ada14url_aggregator23needs_rollback_snapshotEm:
13826|  1.61k|bool url_aggregator::needs_rollback_snapshot(size_t input_len) const noexcept {
13827|       |  // 3x should cover worst-case percent-encoding of every input byte; the
13828|       |  // constant covers the handful of delimiter bytes a setter may add ("/.", "?",
13829|       |  // "#" and so on)
13830|  1.61k|  return buffer.size() + input_len * 3 + 16 > ada::get_max_input_length();
13831|  1.61k|}
_ZN3ada14url_aggregator10set_searchENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
14048|  3.05k|void url_aggregator::set_search(const std::string_view input) {
14049|  3.05k|  ada_log("url_aggregator::set_search ", input);
14050|  3.05k|  ADA_ASSERT_TRUE(validate());
14051|  3.05k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
14052|  3.05k|  if (input.empty()) {
  ------------------
  |  Branch (14052:7): [True: 1.44k, False: 1.61k]
  ------------------
14053|  1.44k|    clear_search();
14054|  1.44k|    helpers::strip_trailing_spaces_from_opaque_path(*this);
14055|  1.44k|    return;
14056|  1.44k|  }
14057|       |
14058|  1.61k|  std::string new_value;
14059|  1.61k|  new_value = input[0] == '?' ? input.substr(1) : input;
  ------------------
  |  Branch (14059:15): [True: 0, False: 1.61k]
  ------------------
14060|  1.61k|  helpers::remove_ascii_tab_or_newline(new_value);
14061|       |
14062|  1.61k|  auto query_percent_encode_set =
14063|  1.61k|      is_special() ? ada::character_sets::SPECIAL_QUERY_PERCENT_ENCODE
  ------------------
  |  Branch (14063:7): [True: 1.61k, False: 0]
  ------------------
14064|  1.61k|                   : ada::character_sets::QUERY_PERCENT_ENCODE;
14065|       |
14066|  1.61k|  std::optional<url_aggregator> saved_url;
14067|  1.61k|  if (needs_rollback_snapshot(new_value.size())) {
  ------------------
  |  Branch (14067:7): [True: 0, False: 1.61k]
  ------------------
14068|      0|    saved_url = *this;
14069|      0|  }
14070|  1.61k|  update_base_search(new_value, query_percent_encode_set);
14071|  1.61k|  if (saved_url && buffer.size() > ada::get_max_input_length()) {
  ------------------
  |  Branch (14071:7): [True: 0, False: 1.61k]
  |  Branch (14071:20): [True: 0, False: 0]
  ------------------
14072|      0|    *this = std::move(*saved_url);
14073|      0|    return;
14074|      0|  }
14075|  1.61k|  ADA_ASSERT_TRUE(validate());
14076|  1.61k|}
_ZNK3ada14url_aggregator10get_searchEv:
14520|  3.05k|    ada_lifetime_bound {
14521|  3.05k|  ada_log("url_aggregator::get_search");
14522|       |  // If this's URL's query is either null or the empty string, then return the
14523|       |  // empty string. Return U+003F (?), followed by this's URL's query.
14524|  3.05k|  if (components.search_start == url_components::omitted) {
  ------------------
  |  Branch (14524:7): [True: 0, False: 3.05k]
  ------------------
14525|      0|    return "";
14526|      0|  }
14527|  3.05k|  auto ending_index = uint32_t(buffer.size());
14528|  3.05k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (14528:7): [True: 492, False: 2.56k]
  ------------------
14529|    492|    ending_index = components.hash_start;
14530|    492|  }
14531|  3.05k|  if (ending_index - components.search_start <= 1) {
  ------------------
  |  Branch (14531:7): [True: 1.38k, False: 1.66k]
  ------------------
14532|  1.38k|    return "";
14533|  1.38k|  }
14534|  1.66k|  return helpers::substring(buffer, components.search_start, ending_index);
14535|  3.05k|}
_ZN3ada4idna7deflate22make_fixed_litlen_huffEv:
  483|      2|inline Huff make_fixed_litlen_huff() {
  484|      2|  Huff h;
  485|      2|  uint8_t lens[288];
  486|       |  // Fixed Huffman: 0-143:8, 144-255:9, 256-279:7, 280-287:8
  487|    290|  for (int i = 0; i <= 143; i++) lens[i] = 8;
  ------------------
  |  Branch (487:19): [True: 288, False: 2]
  ------------------
  488|    226|  for (int i = 144; i <= 255; i++) lens[i] = 9;
  ------------------
  |  Branch (488:21): [True: 224, False: 2]
  ------------------
  489|     50|  for (int i = 256; i <= 279; i++) lens[i] = 7;
  ------------------
  |  Branch (489:21): [True: 48, False: 2]
  ------------------
  490|     18|  for (int i = 280; i <= 287; i++) lens[i] = 8;
  ------------------
  |  Branch (490:21): [True: 16, False: 2]
  ------------------
  491|      2|  h.build(lens, 288);
  492|      2|  return h;
  493|      2|}
_ZN3ada4idna7deflate4Huff5buildEPKhi:
  432|      4|  bool build(const uint8_t* lens, int n) {
  433|      4|    std::memset(counts, 0, sizeof(counts));
  434|      4|    std::memset(first_code, 0, sizeof(first_code));
  435|      4|    std::memset(base_idx, 0, sizeof(base_idx));
  436|      4|    nsymbols = n;
  437|      4|    max_bits = 0;
  438|    644|    for (int i = 0; i < n; i++) {
  ------------------
  |  Branch (438:21): [True: 640, False: 4]
  ------------------
  439|    640|      lengths[i] = lens[i];
  440|    640|      if (lens[i]) {
  ------------------
  |  Branch (440:11): [True: 640, False: 0]
  ------------------
  441|    640|        counts[lens[i]]++;
  442|    640|        if (lens[i] > max_bits) max_bits = lens[i];
  ------------------
  |  Branch (442:13): [True: 6, False: 634]
  ------------------
  443|    640|      }
  444|    640|    }
  445|       |    // Canonical first code for each bit length (RFC 1951).
  446|      4|    int code = 0;
  447|     64|    for (int bits = 1; bits <= MAXBITS; bits++) {
  ------------------
  |  Branch (447:24): [True: 60, False: 4]
  ------------------
  448|     60|      code = (code + counts[bits - 1]) << 1;
  449|     60|      first_code[bits] = code;
  450|     60|    }
  451|      4|    int idx = 0;
  452|     32|    for (int bits = 1; bits <= max_bits; bits++) {
  ------------------
  |  Branch (452:24): [True: 28, False: 4]
  ------------------
  453|     28|      base_idx[bits] = idx;
  454|       |      // assign symbols in symbol order for codes of this length
  455|  5.53k|      for (int sym = 0; sym < n; sym++) {
  ------------------
  |  Branch (455:25): [True: 5.50k, False: 28]
  ------------------
  456|  5.50k|        if (lengths[sym] == bits) {
  ------------------
  |  Branch (456:13): [True: 640, False: 4.86k]
  ------------------
  457|    640|          symbols[idx++] = static_cast<int16_t>(sym);
  458|    640|        }
  459|  5.50k|      }
  460|     28|    }
  461|      4|    return true;
  462|      4|  }
_ZN3ada4idna7deflate20make_fixed_dist_huffEv:
  495|      2|inline Huff make_fixed_dist_huff() {
  496|      2|  Huff h;
  497|      2|  uint8_t lens[32];
  498|     66|  for (int i = 0; i < 32; i++) lens[i] = 5;
  ------------------
  |  Branch (498:19): [True: 64, False: 2]
  ------------------
  499|      2|  h.build(lens, 32);
  500|      2|  return h;
  501|      2|}
_ZZN3ada7unicode14percent_encodeILb1EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKhRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEEENKUlcE_clEc:
 7352|   121k|  auto pointer = std::ranges::find_if(input, [character_set](const char c) {
 7353|   121k|    return character_sets::bit_at(character_set, c);
 7354|   121k|  });
url_search_params.cc:_ZZN3ada7unicode14percent_encodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKhENK3$_0clEc:
 7320|  83.1k|  auto pointer = std::ranges::find_if(input, [character_set](const char c) {
 7321|  83.1k|    return character_sets::bit_at(character_set, c);
 7322|  83.1k|  });
url_search_params.cc:_ZN3ada7unicode12_GLOBAL__N_122percent_encode_to_wideEPKcS3_PKhRNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEE:
 7702|  3.35k|                            const uint8_t character_set[], std::string& out) {
 7703|       |  // Worst case every byte becomes %XX. Avoids realloc while walking windows.
 7704|  3.35k|  out.reserve(out.size() + static_cast<size_t>(end - p) * 3);
 7705|  3.35k|#if ADA_UNICODE_SSSE3
 7706|  3.35k|  const ssse3_percent_tables tables = load_ssse3_percent_tables(character_set);
 7707|  3.35k|  percent_encode_to_ssse3(p, end, character_set, tables, out);
 7708|       |#elif ADA_NEON
 7709|       |  percent_encode_to_neon(p, end, character_set,
 7710|       |                         load_neon_percent_table(character_set), out);
 7711|       |#elif ADA_RVV
 7712|       |  percent_encode_to_rvv(p, end, character_set, out);
 7713|       |#endif
 7714|  3.35k|}
url_search_params.cc:_ZN3ada7unicode12_GLOBAL__N_125load_ssse3_percent_tablesEPKh:
 7529|  3.35k|load_ssse3_percent_tables(const uint8_t character_set[]) noexcept {
 7530|  3.35k|  ssse3_percent_tables t{};
 7531|  3.35k|  t.cs_lo = _mm_loadu_si128(reinterpret_cast<const __m128i*>(character_set));
 7532|  3.35k|  t.cs_hi =
 7533|  3.35k|      _mm_loadu_si128(reinterpret_cast<const __m128i*>(character_set + 16));
 7534|       |  // 1 << (0..7), duplicated so pshufb(index & 7) works for every lane.
 7535|  3.35k|  t.pow2 =
 7536|  3.35k|      _mm_setr_epi8(1, 2, 4, 8, 16, 32, 64, -128, 1, 2, 4, 8, 16, 32, 64, -128);
 7537|  3.35k|  t.mask_0f = _mm_set1_epi8(0x0F);
 7538|  3.35k|  t.mask_07 = _mm_set1_epi8(0x07);
 7539|  3.35k|  t.zero = _mm_setzero_si128();
 7540|  3.35k|  return t;
 7541|  3.35k|}
url_search_params.cc:_ZN3ada7unicode12_GLOBAL__N_123percent_encode_to_ssse3EPKcS3_PKhRKNS1_20ssse3_percent_tablesERNSt3__112basic_stringIcNS9_11char_traitsIcEENS9_9allocatorIcEEEE:
 7560|  3.35k|    const ssse3_percent_tables& tables, std::string& out) {
 7561|       |  // Pair 16-byte windows so a fully clean 32-byte run is one append.
 7562|  14.0k|  while (p + 32 <= end) {
  ------------------
  |  Branch (7562:10): [True: 10.6k, False: 3.35k]
  ------------------
 7563|  10.6k|    const __m128i word0 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(p));
 7564|  10.6k|    const __m128i word1 =
 7565|  10.6k|        _mm_loadu_si128(reinterpret_cast<const __m128i*>(p + 16));
 7566|  10.6k|    const int mask0 = ssse3_percent_mask(word0, tables);
 7567|  10.6k|    const int mask1 = ssse3_percent_mask(word1, tables);
 7568|  10.6k|    if ((mask0 | mask1) == 0) {
  ------------------
  |  Branch (7568:9): [True: 515, False: 10.1k]
  ------------------
 7569|    515|      out.append(p, 32);
 7570|  10.1k|    } else {
 7571|  10.1k|      if (mask0 == 0) {
  ------------------
  |  Branch (7571:11): [True: 263, False: 9.87k]
  ------------------
 7572|    263|        out.append(p, 16);
 7573|  9.87k|      } else {
 7574|  9.87k|        encode_mask_window(p, static_cast<uint32_t>(mask0), 16, out);
 7575|  9.87k|      }
 7576|  10.1k|      if (mask1 == 0) {
  ------------------
  |  Branch (7576:11): [True: 499, False: 9.63k]
  ------------------
 7577|    499|        out.append(p + 16, 16);
 7578|  9.63k|      } else {
 7579|  9.63k|        encode_mask_window(p + 16, static_cast<uint32_t>(mask1), 16, out);
 7580|  9.63k|      }
 7581|  10.1k|    }
 7582|  10.6k|    p += 32;
 7583|  10.6k|  }
 7584|  3.35k|  if (p + 16 <= end) {
  ------------------
  |  Branch (7584:7): [True: 1.64k, False: 1.70k]
  ------------------
 7585|  1.64k|    const __m128i word = _mm_loadu_si128(reinterpret_cast<const __m128i*>(p));
 7586|  1.64k|    const int mask = ssse3_percent_mask(word, tables);
 7587|  1.64k|    if (mask == 0) {
  ------------------
  |  Branch (7587:9): [True: 174, False: 1.47k]
  ------------------
 7588|    174|      out.append(p, 16);
 7589|  1.47k|    } else {
 7590|  1.47k|      encode_mask_window(p, static_cast<uint32_t>(mask), 16, out);
 7591|  1.47k|    }
 7592|  1.64k|    p += 16;
 7593|  1.64k|  }
 7594|  3.35k|  percent_encode_to_scalar(p, end, character_set, out);
 7595|  3.35k|}
url_search_params.cc:_ZN3ada7unicode12_GLOBAL__N_118ssse3_percent_maskEDv2_xRKNS1_20ssse3_percent_tablesE:
 7544|  22.9k|    __m128i word, const ssse3_percent_tables& tables) noexcept {
 7545|  22.9k|  const __m128i idx = _mm_and_si128(_mm_srli_epi16(word, 3), tables.mask_0f);
 7546|  22.9k|  const __m128i lo = _mm_shuffle_epi8(tables.cs_lo, idx);
 7547|  22.9k|  const __m128i hi = _mm_shuffle_epi8(tables.cs_hi, idx);
 7548|       |  // Bytes 0x80-0xFF are signed-negative; select the high half of the bitmap.
 7549|  22.9k|  const __m128i high_byte = _mm_cmpgt_epi8(tables.zero, word);
 7550|  22.9k|  const __m128i cs_byte = _mm_or_si128(_mm_and_si128(hi, high_byte),
 7551|  22.9k|                                       _mm_andnot_si128(high_byte, lo));
 7552|  22.9k|  const __m128i bits =
 7553|  22.9k|      _mm_shuffle_epi8(tables.pow2, _mm_and_si128(word, tables.mask_07));
 7554|  22.9k|  const __m128i hits = _mm_and_si128(cs_byte, bits);
 7555|  22.9k|  return _mm_movemask_epi8(_mm_cmpeq_epi8(hits, tables.zero)) ^ 0xFFFF;
 7556|  22.9k|}
url_search_params.cc:_ZN3ada7unicode12_GLOBAL__N_118encode_mask_windowEPKcjmRNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEE:
 7484|  20.9k|                                          size_t width, std::string& out) {
 7485|  20.9k|  uint64_t bits = mask;
 7486|  20.9k|  size_t off = 0;
 7487|   304k|  while (bits != 0) {
  ------------------
  |  Branch (7487:10): [True: 283k, False: 20.9k]
  ------------------
 7488|   283k|    const int zero_run = trailing_zeroes32(static_cast<uint32_t>(bits));
 7489|   283k|    if (zero_run != 0) {
  ------------------
  |  Branch (7489:9): [True: 15.8k, False: 267k]
  ------------------
 7490|  15.8k|      out.append(p + off, static_cast<size_t>(zero_run));
 7491|  15.8k|    }
 7492|   283k|    off += static_cast<size_t>(zero_run);
 7493|   283k|    out.append(character_sets::hex + uint8_t(p[off]) * 4, 3);
 7494|   283k|    ++off;
 7495|   283k|    bits >>= static_cast<unsigned>(zero_run + 1);
 7496|   283k|  }
 7497|  20.9k|  if (off < width) {
  ------------------
  |  Branch (7497:7): [True: 3.53k, False: 17.4k]
  ------------------
 7498|  3.53k|    out.append(p + off, width - off);
 7499|  3.53k|  }
 7500|  20.9k|}
url_search_params.cc:_ZN3ada7unicode12_GLOBAL__N_117trailing_zeroes32Ej:
 7472|   283k|ada_really_inline int trailing_zeroes32(uint32_t input_num) noexcept {
 7473|       |#ifdef ADA_REGULAR_VISUAL_STUDIO
 7474|       |  unsigned long ret;
 7475|       |  _BitScanForward(&ret, input_num);
 7476|       |  return static_cast<int>(ret);
 7477|       |#else
 7478|   283k|  return __builtin_ctz(input_num);
 7479|   283k|#endif
 7480|   283k|}
url_search_params.cc:_ZN3ada7unicode12_GLOBAL__N_124percent_encode_to_scalarEPKcS3_PKhRNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEE:
 7505|  3.35k|                                                std::string& out) {
 7506|  19.3k|  for (; p != end; ++p) {
  ------------------
  |  Branch (7506:10): [True: 15.9k, False: 3.35k]
  ------------------
 7507|  15.9k|    if (character_sets::bit_at(character_set, *p)) {
  ------------------
  |  Branch (7507:9): [True: 12.5k, False: 3.38k]
  ------------------
 7508|  12.5k|      out.append(character_sets::hex + uint8_t(*p) * 4, 3);
 7509|  12.5k|    } else {
 7510|  3.38k|      out += *p;
 7511|  3.38k|    }
 7512|  15.9k|  }
 7513|  3.35k|}
_ZN3ada7unicode19has_tabs_or_newlineENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6862|  2.77k|    std::string_view user_input) noexcept {
 6863|       |  // first check for short strings in which case we do it naively.
 6864|  2.77k|  if (user_input.size() < 16) {  // slow path
  ------------------
  |  Branch (6864:7): [True: 1.06k, False: 1.71k]
  ------------------
 6865|  1.06k|    return std::ranges::any_of(user_input, is_tabs_or_newline);
 6866|  1.06k|  }
 6867|       |  // fast path for long strings (expected to be common)
 6868|  1.71k|  size_t i = 0;
 6869|  1.71k|  const __m128i mask1 = _mm_set1_epi8('\r');
 6870|  1.71k|  const __m128i mask2 = _mm_set1_epi8('\n');
 6871|  1.71k|  const __m128i mask3 = _mm_set1_epi8('\t');
 6872|       |  // If we supported SSSE3, we could use the algorithm that we use for NEON.
 6873|  1.71k|  __m128i running{0};
 6874|  8.25k|  for (; i + 15 < user_input.size(); i += 16) {
  ------------------
  |  Branch (6874:10): [True: 6.54k, False: 1.71k]
  ------------------
 6875|  6.54k|    __m128i word = _mm_loadu_si128((const __m128i*)(user_input.data() + i));
 6876|  6.54k|    running = _mm_or_si128(
 6877|  6.54k|        _mm_or_si128(running, _mm_or_si128(_mm_cmpeq_epi8(word, mask1),
 6878|  6.54k|                                           _mm_cmpeq_epi8(word, mask2))),
 6879|  6.54k|        _mm_cmpeq_epi8(word, mask3));
 6880|  6.54k|  }
 6881|  1.71k|  if (i < user_input.size()) {
  ------------------
  |  Branch (6881:7): [True: 1.62k, False: 92]
  ------------------
 6882|  1.62k|    __m128i word = _mm_loadu_si128(
 6883|  1.62k|        (const __m128i*)(user_input.data() + user_input.length() - 16));
 6884|  1.62k|    running = _mm_or_si128(
 6885|  1.62k|        _mm_or_si128(running, _mm_or_si128(_mm_cmpeq_epi8(word, mask1),
 6886|  1.62k|                                           _mm_cmpeq_epi8(word, mask2))),
 6887|  1.62k|        _mm_cmpeq_epi8(word, mask3));
 6888|  1.62k|  }
 6889|  1.71k|  return _mm_movemask_epi8(running) != 0;
 6890|  2.77k|}
_ZN3ada7unicode18is_tabs_or_newlineEc:
 6753|  1.06k|constexpr bool is_tabs_or_newline(char c) noexcept {
 6754|  1.06k|  return c == '\r' || c == '\n' || c == '\t';
  ------------------
  |  Branch (6754:10): [True: 0, False: 1.06k]
  |  Branch (6754:23): [True: 0, False: 1.06k]
  |  Branch (6754:36): [True: 0, False: 1.06k]
  ------------------
 6755|  1.06k|}
_ZN3ada7helpers27remove_ascii_tab_or_newlineERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
 8558|  1.85k|ada_really_inline void remove_ascii_tab_or_newline(std::string& input) {
 8559|       |  // if this ever becomes a performance issue, we could use an approach similar
 8560|       |  // to has_tabs_or_newline
 8561|  1.85k|  std::erase_if(input, ada::unicode::is_ascii_tab_or_newline);
 8562|  1.85k|}
_ZN3ada7unicode23is_ascii_tab_or_newlineEc:
 7107|   164k|    const char c) noexcept {
 7108|   164k|  return c == '\t' || c == '\n' || c == '\r';
  ------------------
  |  Branch (7108:10): [True: 652, False: 163k]
  |  Branch (7108:23): [True: 1.03k, False: 162k]
  |  Branch (7108:36): [True: 464, False: 162k]
  ------------------
 7109|   164k|}
_ZN3ada7unicode22is_c0_control_or_spaceEc:
 7102|  4.98k|ada_really_inline constexpr bool is_c0_control_or_space(const char c) noexcept {
 7103|  4.98k|  return (unsigned char)c <= ' ';
 7104|  4.98k|}
_ZN3ada8checkers14path_signatureENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
   75|  1.56k|    std::string_view input) noexcept {
   76|       |  // The path percent-encode set is the query percent-encode set and U+003F (?),
   77|       |  // U+0060 (`), U+007B ({), and U+007D (}). The query percent-encode set is the
   78|       |  // C0 control percent-encode set and U+0020 SPACE, U+0022 ("), U+0023 (#),
   79|       |  // U+003C (<), and U+003E (>). The C0 control percent-encode set are the C0
   80|       |  // controls and all code points greater than U+007E (~).
   81|  1.56k|  size_t i = 0;
   82|  1.56k|  uint8_t accumulator{};
   83|  1.56k|  for (; i + 7 < input.size(); i += 8) {
  ------------------
  |  Branch (83:10): [True: 0, False: 1.56k]
  ------------------
   84|      0|    accumulator |= uint8_t(path_signature_table[uint8_t(input[i])] |
   85|      0|                           path_signature_table[uint8_t(input[i + 1])] |
   86|      0|                           path_signature_table[uint8_t(input[i + 2])] |
   87|      0|                           path_signature_table[uint8_t(input[i + 3])] |
   88|      0|                           path_signature_table[uint8_t(input[i + 4])] |
   89|      0|                           path_signature_table[uint8_t(input[i + 5])] |
   90|      0|                           path_signature_table[uint8_t(input[i + 6])] |
   91|      0|                           path_signature_table[uint8_t(input[i + 7])]);
   92|      0|  }
   93|  1.56k|  for (; i < input.size(); i++) {
  ------------------
  |  Branch (93:10): [True: 0, False: 1.56k]
  ------------------
   94|      0|    accumulator |= uint8_t(path_signature_table[uint8_t(input[i])]);
   95|      0|  }
   96|  1.56k|  return accumulator;
   97|  1.56k|}
_ZN3ada7unicode13is_alnum_plusEc:
 7079|  2.50k|ada_really_inline constexpr bool is_alnum_plus(const char c) noexcept {
 7080|  2.50k|  return is_alnum_plus_table[uint8_t(c)];
 7081|       |  // A table is almost surely much faster than the
 7082|       |  // following under most compilers: return
 7083|       |  // return (std::isalnum(c) || c == '+' || c == '-' || c == '.');
 7084|  2.50k|}
_ZZN3ada6parser25try_parse_simple_absoluteINS_14url_aggregatorEEEbNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEERT_ENKUlvE_clEv:
12222|  1.06k|    auto apply_query_and_hash = [&]() {
12223|  1.06k|      if (query_start != std::string_view::npos) {
  ------------------
  |  Branch (12223:11): [True: 1.06k, False: 0]
  ------------------
12224|  1.06k|        const size_t q_end =
12225|  1.06k|            (hash_start != std::string_view::npos) ? hash_start : len;
  ------------------
  |  Branch (12225:13): [True: 270, False: 794]
  ------------------
12226|  1.06k|        out.update_base_search(std::string_view(input.data() + query_start + 1,
12227|  1.06k|                                                q_end - query_start - 1),
12228|  1.06k|                               character_sets::SPECIAL_QUERY_PERCENT_ENCODE);
12229|  1.06k|      }
12230|  1.06k|      if (hash_start != std::string_view::npos) {
  ------------------
  |  Branch (12230:11): [True: 270, False: 794]
  ------------------
12231|    270|        out.update_unencoded_base_hash(std::string_view(
12232|    270|            input.data() + hash_start + 1, len - hash_start - 1));
12233|    270|      }
12234|  1.06k|    };
_ZN3ada7helpers10prune_hashERNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8498|    500|    std::string_view& input) noexcept {
 8499|       |  // compiles down to 20--30 instructions including a class to memchr (C
 8500|       |  // function). this function should be quite fast.
 8501|    500|  size_t location_of_first = input.find('#');
 8502|    500|  if (location_of_first == std::string_view::npos) {
  ------------------
  |  Branch (8502:7): [True: 378, False: 122]
  ------------------
 8503|    378|    return std::nullopt;
 8504|    378|  }
 8505|    122|  std::string_view hash = input;
 8506|    122|  hash.remove_prefix(location_of_first + 1);
 8507|    122|  input.remove_suffix(input.size() - location_of_first);
 8508|    122|  return hash;
 8509|    500|}
_ZN3ada7helpers32find_authority_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9451|     52|find_authority_delimiter_special(std::string_view view) noexcept {
 9452|       |  // performance note: we might be able to gain further performance
 9453|       |  // with SIMD intrinsics.
 9454|    624|  for (auto pos = view.begin(); pos != view.end(); ++pos) {
  ------------------
  |  Branch (9454:33): [True: 624, False: 0]
  ------------------
 9455|    624|    if (authority_delimiter_special[(uint8_t)*pos]) {
  ------------------
  |  Branch (9455:9): [True: 52, False: 572]
  ------------------
 9456|     52|      return pos - view.begin();
 9457|     52|    }
 9458|    624|  }
 9459|      0|  return size_t(view.size());
 9460|     52|}
_ZN3ada7helpers27get_host_delimiter_locationEbRNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9164|    500|    const bool is_special, std::string_view& view) noexcept {
 9165|       |  /**
 9166|       |   * The spec at https://url.spec.whatwg.org/#hostname-state expects us to
 9167|       |   * compute a variable called insideBrackets but this variable is only used
 9168|       |   * once, to check whether a ':' character was found outside brackets. Exact
 9169|       |   * text: "Otherwise, if c is U+003A (:) and insideBrackets is false, then:".
 9170|       |   * It is conceptually simpler and arguably more efficient to just return a
 9171|       |   * Boolean indicating whether ':' was found outside brackets.
 9172|       |   */
 9173|    500|  const size_t view_size = view.size();
 9174|    500|  size_t location = 0;
 9175|    500|  bool found_colon = false;
 9176|       |  /**
 9177|       |   * Performance analysis:
 9178|       |   *
 9179|       |   * We are basically seeking the end of the hostname which can be indicated
 9180|       |   * by the end of the view, or by one of the characters ':', '/', '?', '\\'
 9181|       |   * (where '\\' is only applicable for special URLs). However, these must
 9182|       |   * appear outside a bracket range. E.g., if you have [something?]fd: then the
 9183|       |   * '?' does not count.
 9184|       |   *
 9185|       |   * So we can skip ahead to the next delimiter, as long as we include '[' in
 9186|       |   * the set of delimiters, and that we handle it first.
 9187|       |   *
 9188|       |   * So the trick is to have a fast function that locates the next delimiter.
 9189|       |   * Unless we find '[', then it only needs to be called once! Ideally, such a
 9190|       |   * function would be provided by the C++ standard library, but it seems that
 9191|       |   * find_first_of is not very fast, so we are forced to roll our own.
 9192|       |   *
 9193|       |   * We do not break into two loops for speed, but for clarity.
 9194|       |   */
 9195|    500|  if (is_special) {
  ------------------
  |  Branch (9195:7): [True: 500, False: 0]
  ------------------
 9196|       |    // We move to the next delimiter.
 9197|    500|    location = find_next_host_delimiter_special(view, location);
 9198|       |    // Unless we find '[' then we are going only going to have to call
 9199|       |    // find_next_host_delimiter_special once.
 9200|    500|    for (; location < view_size;
  ------------------
  |  Branch (9200:12): [True: 500, False: 0]
  ------------------
 9201|    500|         location = find_next_host_delimiter_special(view, location)) {
 9202|    500|      if (view[location] == '[') {
  ------------------
  |  Branch (9202:11): [True: 0, False: 500]
  ------------------
 9203|      0|        location = view.find(']', location);
 9204|      0|        if (location == std::string_view::npos) {
  ------------------
  |  Branch (9204:13): [True: 0, False: 0]
  ------------------
 9205|       |          // performance: view.find might get translated to a memchr, which
 9206|       |          // has no notion of std::string_view::npos, so the code does not
 9207|       |          // reflect the assembly.
 9208|      0|          location = view_size;
 9209|      0|          break;
 9210|      0|        }
 9211|    500|      } else {
 9212|    500|        found_colon = view[location] == ':';
 9213|    500|        break;
 9214|    500|      }
 9215|    500|    }
 9216|    500|  } else {
 9217|       |    // We move to the next delimiter.
 9218|      0|    location = find_next_host_delimiter(view, location);
 9219|       |    // Unless we find '[' then we are going only going to have to call
 9220|       |    // find_next_host_delimiter_special once.
 9221|      0|    for (; location < view_size;
  ------------------
  |  Branch (9221:12): [True: 0, False: 0]
  ------------------
 9222|      0|         location = find_next_host_delimiter(view, location)) {
 9223|      0|      if (view[location] == '[') {
  ------------------
  |  Branch (9223:11): [True: 0, False: 0]
  ------------------
 9224|      0|        location = view.find(']', location);
 9225|      0|        if (location == std::string_view::npos) {
  ------------------
  |  Branch (9225:13): [True: 0, False: 0]
  ------------------
 9226|       |          // performance: view.find might get translated to a memchr, which
 9227|       |          // has no notion of std::string_view::npos, so the code does not
 9228|       |          // reflect the assembly.
 9229|      0|          location = view_size;
 9230|      0|          break;
 9231|      0|        }
 9232|      0|      } else {
 9233|      0|        found_colon = view[location] == ':';
 9234|      0|        break;
 9235|      0|      }
 9236|      0|    }
 9237|      0|  }
 9238|       |  // performance: remove_suffix may translate into a single instruction.
 9239|    500|  view.remove_suffix(view_size - location);
 9240|    500|  return {location, found_colon};
 9241|    500|}
_ZN3ada7helpers32find_next_host_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEm:
 8754|    500|    std::string_view view, size_t location) noexcept {
 8755|       |  // first check for short strings in which case we do it naively.
 8756|    500|  if (view.size() - location < 16) {  // slow path
  ------------------
  |  Branch (8756:7): [True: 235, False: 265]
  ------------------
 8757|  2.82k|    for (size_t i = location; i < view.size(); i++) {
  ------------------
  |  Branch (8757:31): [True: 2.82k, False: 0]
  ------------------
 8758|  2.82k|      if (view[i] == ':' || view[i] == '/' || view[i] == '\\' ||
  ------------------
  |  Branch (8758:11): [True: 0, False: 2.82k]
  |  Branch (8758:29): [True: 235, False: 2.58k]
  |  Branch (8758:47): [True: 0, False: 2.58k]
  ------------------
 8759|  2.58k|          view[i] == '?' || view[i] == '[') {
  ------------------
  |  Branch (8759:11): [True: 0, False: 2.58k]
  |  Branch (8759:29): [True: 0, False: 2.58k]
  ------------------
 8760|    235|        return i;
 8761|    235|      }
 8762|  2.82k|    }
 8763|      0|    return size_t(view.size());
 8764|    235|  }
 8765|       |  // fast path for long strings (expected to be common)
 8766|    265|  size_t i = location;
 8767|    265|  const __m128i mask1 = _mm_set1_epi8(':');
 8768|    265|  const __m128i mask2 = _mm_set1_epi8('/');
 8769|    265|  const __m128i mask3 = _mm_set1_epi8('\\');
 8770|    265|  const __m128i mask4 = _mm_set1_epi8('?');
 8771|    265|  const __m128i mask5 = _mm_set1_epi8('[');
 8772|       |
 8773|    265|  for (; i + 15 < view.size(); i += 16) {
  ------------------
  |  Branch (8773:10): [True: 265, False: 0]
  ------------------
 8774|    265|    __m128i word = _mm_loadu_si128((const __m128i*)(view.data() + i));
 8775|    265|    __m128i m1 = _mm_cmpeq_epi8(word, mask1);
 8776|    265|    __m128i m2 = _mm_cmpeq_epi8(word, mask2);
 8777|    265|    __m128i m3 = _mm_cmpeq_epi8(word, mask3);
 8778|    265|    __m128i m4 = _mm_cmpeq_epi8(word, mask4);
 8779|    265|    __m128i m5 = _mm_cmpeq_epi8(word, mask5);
 8780|    265|    __m128i m = _mm_or_si128(
 8781|    265|        _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m3, m4)), m5);
 8782|    265|    int mask = _mm_movemask_epi8(m);
 8783|    265|    if (mask != 0) {
  ------------------
  |  Branch (8783:9): [True: 265, False: 0]
  ------------------
 8784|    265|      return i + trailing_zeroes(mask);
 8785|    265|    }
 8786|    265|  }
 8787|      0|  if (i < view.size()) {
  ------------------
  |  Branch (8787:7): [True: 0, False: 0]
  ------------------
 8788|      0|    __m128i word =
 8789|      0|        _mm_loadu_si128((const __m128i*)(view.data() + view.length() - 16));
 8790|      0|    __m128i m1 = _mm_cmpeq_epi8(word, mask1);
 8791|      0|    __m128i m2 = _mm_cmpeq_epi8(word, mask2);
 8792|      0|    __m128i m3 = _mm_cmpeq_epi8(word, mask3);
 8793|      0|    __m128i m4 = _mm_cmpeq_epi8(word, mask4);
 8794|      0|    __m128i m5 = _mm_cmpeq_epi8(word, mask5);
 8795|      0|    __m128i m = _mm_or_si128(
 8796|      0|        _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m3, m4)), m5);
 8797|      0|    int mask = _mm_movemask_epi8(m);
 8798|      0|    if (mask != 0) {
  ------------------
  |  Branch (8798:9): [True: 0, False: 0]
  ------------------
 8799|      0|      return view.length() - 16 + trailing_zeroes(mask);
 8800|      0|    }
 8801|      0|  }
 8802|      0|  return size_t(view.length());
 8803|      0|}
_ZN3ada7helpers15trailing_zeroesEj:
 8579|    265|ada_really_inline int trailing_zeroes(uint32_t input_num) noexcept {
 8580|       |#ifdef ADA_REGULAR_VISUAL_STUDIO
 8581|       |  unsigned long ret;
 8582|       |  // Search the mask data from least significant bit (LSB)
 8583|       |  // to the most significant bit (MSB) for a set bit (1).
 8584|       |  _BitScanForward(&ret, input_num);
 8585|       |  return (int)ret;
 8586|       |#else   // ADA_REGULAR_VISUAL_STUDIO
 8587|    265|  return __builtin_ctzl(input_num);
 8588|    265|#endif  // ADA_REGULAR_VISUAL_STUDIO
 8589|    265|}
_ZN3ada7unicode45contains_forbidden_domain_code_point_or_upperEPKcm:
 7049|    500|                                              size_t length) noexcept {
 7050|    500|  size_t i = 0;
 7051|    500|  uint8_t accumulator{};
 7052|  1.50k|  for (; i + 4 <= length; i += 4) {
  ------------------
  |  Branch (7052:10): [True: 1.00k, False: 500]
  ------------------
 7053|  1.00k|    accumulator |=
 7054|  1.00k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i])];
 7055|  1.00k|    accumulator |=
 7056|  1.00k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 1])];
 7057|  1.00k|    accumulator |=
 7058|  1.00k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 2])];
 7059|  1.00k|    accumulator |=
 7060|  1.00k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 3])];
 7061|  1.00k|  }
 7062|  2.00k|  for (; i < length; i++) {
  ------------------
  |  Branch (7062:10): [True: 1.50k, False: 500]
  ------------------
 7063|  1.50k|    accumulator |=
 7064|  1.50k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i])];
 7065|  1.50k|  }
 7066|    500|  return accumulator;
 7067|    500|}
_ZZN3ada6parser14parse_url_implINS_14url_aggregatorELb1EEET_NSt3__117basic_string_viewIcNS4_11char_traitsIcEEEEPKS3_ENKUlvE_clEv:
12545|    500|  const auto enforce_max_input_length = [&]() {
12546|    500|    if constexpr (store_values) {
12547|    500|      if (url.is_valid) {
  ------------------
  |  Branch (12547:11): [True: 500, False: 0]
  ------------------
12548|    500|        if constexpr (result_type_is_ada_url_aggregator) {
12549|    500|          if (url.buffer.size() > max_input_length) [[unlikely]] {
  ------------------
  |  Branch (12549:15): [True: 0, False: 500]
  ------------------
12550|      0|            url.is_valid = false;
12551|      0|          }
12552|       |        } else {
12553|       |          if (url.get_href_size() > max_input_length) [[unlikely]] {
12554|       |            url.is_valid = false;
12555|       |          }
12556|       |        }
12557|    500|      }
12558|    500|    }
12559|    500|  };
url_search_params.cc:_ZN3ada6parser12_GLOBAL__N_116authority_has_atEPKhmm:
11033|  3.05k|                                        size_t n) noexcept {
11034|  3.05k|  const size_t rem = n - host_start;
11035|  3.05k|  if (rem == 0) {
  ------------------
  |  Branch (11035:7): [True: 0, False: 3.05k]
  ------------------
11036|      0|    return false;
11037|      0|  }
11038|       |#if ADA_NEON
11039|       |  if (rem >= 16) {
11040|       |    const uint8x16_t w = vld1q_u8(p + host_start);
11041|       |    const uint64_t at = neon_nibble_bits(vceqq_u8(w, vdupq_n_u8('@')));
11042|       |    if (at == 0) {
11043|       |      return false;
11044|       |    }
11045|       |    const uint64_t delim = neon_nibble_bits(vceqq_u8(w, vdupq_n_u8('/'))) |
11046|       |                           neon_nibble_bits(vceqq_u8(w, vdupq_n_u8('?'))) |
11047|       |                           neon_nibble_bits(vceqq_u8(w, vdupq_n_u8('#')));
11048|       |    return delim == 0 || std::countr_zero(at) < std::countr_zero(delim);
11049|       |  }
11050|       |#elif ADA_SSE2
11051|  3.05k|  if (rem >= 16) {
  ------------------
  |  Branch (11051:7): [True: 1.49k, False: 1.56k]
  ------------------
11052|  1.49k|    const __m128i w =
11053|  1.49k|        _mm_loadu_si128(reinterpret_cast<const __m128i*>(p + host_start));
11054|  1.49k|    const uint16_t at = static_cast<uint16_t>(
11055|  1.49k|        _mm_movemask_epi8(_mm_cmpeq_epi8(w, _mm_set1_epi8('@'))));
11056|  1.49k|    if (at == 0) {
  ------------------
  |  Branch (11056:9): [True: 1.45k, False: 34]
  ------------------
11057|  1.45k|      return false;
11058|  1.45k|    }
11059|     34|    const uint16_t delim = static_cast<uint16_t>(
11060|     34|        _mm_movemask_epi8(_mm_cmpeq_epi8(w, _mm_set1_epi8('/'))) |
11061|     34|        _mm_movemask_epi8(_mm_cmpeq_epi8(w, _mm_set1_epi8('?'))) |
11062|     34|        _mm_movemask_epi8(_mm_cmpeq_epi8(w, _mm_set1_epi8('#'))));
11063|     34|    return delim == 0 || std::countr_zero(at) < std::countr_zero(delim);
  ------------------
  |  Branch (11063:12): [True: 0, False: 34]
  |  Branch (11063:26): [True: 0, False: 34]
  ------------------
11064|  1.49k|  }
11065|  1.56k|#endif
11066|  1.56k|  const size_t lim = host_start + rem;
11067|  18.7k|  for (size_t i = host_start; i < lim; ++i) {
  ------------------
  |  Branch (11067:31): [True: 18.7k, False: 0]
  ------------------
11068|  18.7k|    const uint8_t c = p[i];
11069|  18.7k|    if (c == '@') {
  ------------------
  |  Branch (11069:9): [True: 0, False: 18.7k]
  ------------------
11070|      0|      return true;
11071|      0|    }
11072|  18.7k|    if (c == '/' || c == '?' || c == '#') {
  ------------------
  |  Branch (11072:9): [True: 1.56k, False: 17.2k]
  |  Branch (11072:21): [True: 0, False: 17.2k]
  |  Branch (11072:33): [True: 0, False: 17.2k]
  ------------------
11073|  1.56k|      return false;
11074|  1.56k|    }
11075|  18.7k|  }
11076|      0|  return false;
11077|  1.56k|}
url_search_params.cc:_ZN3ada6parser12_GLOBAL__N_115scan_plain_hostEPKhmmRmRbS5_:
11084|  3.05k|                                     bool& has_x) noexcept {
11085|  3.05k|  has_upper = false;
11086|  3.05k|  has_x = false;
11087|  3.05k|  size_t i = start;
11088|  3.05k|#if ADA_PARSER_SSSE3
11089|  3.05k|  if (len - start >= 16) {
  ------------------
  |  Branch (11089:7): [True: 1.49k, False: 1.56k]
  ------------------
11090|  1.49k|    const __m128i lo_tbl = nibble_load(k_host_nibbles.low);
11091|  1.49k|    const __m128i hi_tbl = nibble_load(k_host_nibbles.high);
11092|  1.49k|    const __m128i x_splat = _mm_set1_epi8('x');
11093|  1.49k|    auto visit = [&](size_t at) noexcept -> bool {
11094|  1.49k|      const __m128i w =
11095|  1.49k|          _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + at));
11096|  1.49k|      const int up = sse2_uppercase(w);
11097|  1.49k|      const int xs = _mm_movemask_epi8(_mm_cmpeq_epi8(w, x_splat));
11098|  1.49k|      const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl);
11099|  1.49k|      if (mask == 0) {
11100|  1.49k|        if (up != 0) {
11101|  1.49k|          has_upper = true;
11102|  1.49k|        }
11103|  1.49k|        if (xs != 0) {
11104|  1.49k|          has_x = true;
11105|  1.49k|        }
11106|  1.49k|        return false;
11107|  1.49k|      }
11108|  1.49k|      const int hit = trailing_zeroes32(static_cast<uint32_t>(mask));
11109|  1.49k|      const int valid = (1 << hit) - 1;
11110|  1.49k|      if ((up & valid) != 0) {
11111|  1.49k|        has_upper = true;
11112|  1.49k|      }
11113|  1.49k|      if ((xs & valid) != 0) {
11114|  1.49k|        has_x = true;
11115|  1.49k|      }
11116|  1.49k|      end = at + static_cast<size_t>(hit);
11117|  1.49k|      return true;
11118|  1.49k|    };
11119|  1.49k|    for (; i + 32 <= len; i += 32) {
  ------------------
  |  Branch (11119:12): [True: 887, False: 603]
  ------------------
11120|    887|      if (visit(i) || visit(i + 16)) {
  ------------------
  |  Branch (11120:11): [True: 887, False: 0]
  |  Branch (11120:23): [True: 0, False: 0]
  ------------------
11121|    887|        return k_host_class[b[end]] == 1;
11122|    887|      }
11123|    887|    }
11124|    603|    for (; i + 16 <= len; i += 16) {
  ------------------
  |  Branch (11124:12): [True: 603, False: 0]
  ------------------
11125|    603|      if (visit(i)) {
  ------------------
  |  Branch (11125:11): [True: 603, False: 0]
  ------------------
11126|    603|        return k_host_class[b[end]] == 1;
11127|    603|      }
11128|    603|    }
11129|       |    // Overlapping tail only after a full 16-byte step so the window cannot
11130|       |    // start before `start` (a prior '/' would otherwise look like a host stop).
11131|      0|    if (i > start && i < len) {
  ------------------
  |  Branch (11131:9): [True: 0, False: 0]
  |  Branch (11131:22): [True: 0, False: 0]
  ------------------
11132|      0|      if (visit(len - 16) && end >= i) {
  ------------------
  |  Branch (11132:11): [True: 0, False: 0]
  |  Branch (11132:30): [True: 0, False: 0]
  ------------------
11133|      0|        return k_host_class[b[end]] == 1;
11134|      0|      }
11135|      0|      end = len;
11136|      0|      return true;
11137|      0|    }
11138|      0|  }
11139|       |#elif ADA_SSE2
11140|       |  const __m128i x_splat = _mm_set1_epi8('x');
11141|       |  for (; i + 32 <= len; i += 32) {
11142|       |    for (size_t off = 0; off < 32; off += 16) {
11143|       |      const __m128i w =
11144|       |          _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i + off));
11145|       |      const int up = sse2_uppercase(w);
11146|       |      const int xs = _mm_movemask_epi8(_mm_cmpeq_epi8(w, x_splat));
11147|       |      const int mask = sse2_host_stop(w);
11148|       |      if (mask != 0) {
11149|       |        const int hit = trailing_zeroes32(static_cast<uint32_t>(mask));
11150|       |        const int valid = (1 << hit) - 1;
11151|       |        if ((up & valid) != 0) {
11152|       |          has_upper = true;
11153|       |        }
11154|       |        if ((xs & valid) != 0) {
11155|       |          has_x = true;
11156|       |        }
11157|       |        end = i + off + static_cast<size_t>(hit);
11158|       |        return k_host_class[b[end]] == 1;
11159|       |      }
11160|       |      if (up != 0) {
11161|       |        has_upper = true;
11162|       |      }
11163|       |      if (xs != 0) {
11164|       |        has_x = true;
11165|       |      }
11166|       |    }
11167|       |  }
11168|       |  for (; i + 16 <= len; i += 16) {
11169|       |    const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i));
11170|       |    const int up = sse2_uppercase(w);
11171|       |    const int xs = _mm_movemask_epi8(_mm_cmpeq_epi8(w, x_splat));
11172|       |    const int mask = sse2_host_stop(w);
11173|       |    if (mask != 0) {
11174|       |      const int hit = trailing_zeroes32(static_cast<uint32_t>(mask));
11175|       |      const int valid = (1 << hit) - 1;
11176|       |      if ((up & valid) != 0) {
11177|       |        has_upper = true;
11178|       |      }
11179|       |      if ((xs & valid) != 0) {
11180|       |        has_x = true;
11181|       |      }
11182|       |      end = i + static_cast<size_t>(hit);
11183|       |      return k_host_class[b[end]] == 1;
11184|       |    }
11185|       |    if (up != 0) {
11186|       |      has_upper = true;
11187|       |    }
11188|       |    if (xs != 0) {
11189|       |      has_x = true;
11190|       |    }
11191|       |  }
11192|       |#elif ADA_NEON
11193|       |  if (len - start >= 16) {
11194|       |    const uint8x16_t lo_tbl = vld1q_u8(k_host_nibbles.low);
11195|       |    const uint8x16_t hi_tbl = vld1q_u8(k_host_nibbles.high);
11196|       |    const uint8x16_t x_splat = vdupq_n_u8('x');
11197|       |    auto visit = [&](size_t at) noexcept -> bool {
11198|       |      const uint8x16_t w = vld1q_u8(b + at);
11199|       |      const uint64_t up = neon_uppercase(w);
11200|       |      const uint64_t xs = neon_nibble_bits(vceqq_u8(w, x_splat));
11201|       |      const uint64_t bits = neon_table_stop(w, lo_tbl, hi_tbl);
11202|       |      if (bits == 0) {
11203|       |        if (up != 0) {
11204|       |          has_upper = true;
11205|       |        }
11206|       |        if (xs != 0) {
11207|       |          has_x = true;
11208|       |        }
11209|       |        return false;
11210|       |      }
11211|       |      const size_t hit = static_cast<size_t>(trailing_zeroes64(bits)) >> 2;
11212|       |      const uint64_t valid = (hit == 0) ? 0 : (uint64_t{1} << (hit * 4)) - 1;
11213|       |      if ((up & valid) != 0) {
11214|       |        has_upper = true;
11215|       |      }
11216|       |      if ((xs & valid) != 0) {
11217|       |        has_x = true;
11218|       |      }
11219|       |      end = at + hit;
11220|       |      return true;
11221|       |    };
11222|       |    for (; i + 32 <= len; i += 32) {
11223|       |      if (visit(i) || visit(i + 16)) {
11224|       |        return k_host_class[b[end]] == 1;
11225|       |      }
11226|       |    }
11227|       |    for (; i + 16 <= len; i += 16) {
11228|       |      if (visit(i)) {
11229|       |        return k_host_class[b[end]] == 1;
11230|       |      }
11231|       |    }
11232|       |    if (i > start && i < len) {
11233|       |      if (visit(len - 16) && end >= i) {
11234|       |        return k_host_class[b[end]] == 1;
11235|       |      }
11236|       |      end = len;
11237|       |      return true;
11238|       |    }
11239|       |  }
11240|       |#endif
11241|  18.7k|  for (; i < len; ++i) {
  ------------------
  |  Branch (11241:10): [True: 18.7k, False: 0]
  ------------------
11242|  18.7k|    const uint8_t c = b[i];
11243|  18.7k|    const uint8_t cls = k_host_class[c];
11244|  18.7k|    if (cls == 1) {
  ------------------
  |  Branch (11244:9): [True: 1.56k, False: 17.2k]
  ------------------
11245|  1.56k|      end = i;
11246|  1.56k|      return true;
11247|  1.56k|    }
11248|  17.2k|    if (cls == 2) {
  ------------------
  |  Branch (11248:9): [True: 0, False: 17.2k]
  ------------------
11249|      0|      return false;
11250|      0|    }
11251|  17.2k|    if (c >= 'A' && c <= 'Z') {
  ------------------
  |  Branch (11251:9): [True: 15.6k, False: 1.56k]
  |  Branch (11251:21): [True: 0, False: 15.6k]
  ------------------
11252|      0|      has_upper = true;
11253|  17.2k|    } else if (c == 'x') {
  ------------------
  |  Branch (11253:16): [True: 1.56k, False: 15.6k]
  ------------------
11254|  1.56k|      has_x = true;
11255|  1.56k|    }
11256|  17.2k|  }
11257|      0|  end = len;
11258|      0|  return true;
11259|  1.56k|}
url_search_params.cc:_ZN3ada6parser12_GLOBAL__N_111nibble_loadEPKh:
10914|  7.41k|ADA_PARSER_SIMD __m128i nibble_load(const uint8_t* t) noexcept {
10915|  7.41k|  return _mm_load_si128(reinterpret_cast<const __m128i*>(t));
10916|  7.41k|}
url_search_params.cc:_ZZN3ada6parser12_GLOBAL__N_115scan_plain_hostEPKhmmRmRbS5_ENK3$_0clEm:
11093|  1.49k|    auto visit = [&](size_t at) noexcept -> bool {
11094|  1.49k|      const __m128i w =
11095|  1.49k|          _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + at));
11096|  1.49k|      const int up = sse2_uppercase(w);
11097|  1.49k|      const int xs = _mm_movemask_epi8(_mm_cmpeq_epi8(w, x_splat));
11098|  1.49k|      const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl);
11099|  1.49k|      if (mask == 0) {
  ------------------
  |  Branch (11099:11): [True: 0, False: 1.49k]
  ------------------
11100|      0|        if (up != 0) {
  ------------------
  |  Branch (11100:13): [True: 0, False: 0]
  ------------------
11101|      0|          has_upper = true;
11102|      0|        }
11103|      0|        if (xs != 0) {
  ------------------
  |  Branch (11103:13): [True: 0, False: 0]
  ------------------
11104|      0|          has_x = true;
11105|      0|        }
11106|      0|        return false;
11107|      0|      }
11108|  1.49k|      const int hit = trailing_zeroes32(static_cast<uint32_t>(mask));
11109|  1.49k|      const int valid = (1 << hit) - 1;
11110|  1.49k|      if ((up & valid) != 0) {
  ------------------
  |  Branch (11110:11): [True: 0, False: 1.49k]
  ------------------
11111|      0|        has_upper = true;
11112|      0|      }
11113|  1.49k|      if ((xs & valid) != 0) {
  ------------------
  |  Branch (11113:11): [True: 1.49k, False: 0]
  ------------------
11114|  1.49k|        has_x = true;
11115|  1.49k|      }
11116|  1.49k|      end = at + static_cast<size_t>(hit);
11117|  1.49k|      return true;
11118|  1.49k|    };
url_search_params.cc:_ZN3ada6parser12_GLOBAL__N_114sse2_uppercaseEDv2_x:
11001|  1.49k|ada_really_inline int sse2_uppercase(__m128i w) noexcept {
11002|  1.49k|  return _mm_movemask_epi8(_mm_and_si128(
11003|  1.49k|      _mm_cmpgt_epi8(w, _mm_set1_epi8(static_cast<char>('A' - 1))),
11004|  1.49k|      _mm_cmplt_epi8(w, _mm_set1_epi8(static_cast<char>('Z' + 1)))));
11005|  1.49k|}
url_search_params.cc:_ZN3ada6parser12_GLOBAL__N_117ssse3_nibble_maskEDv2_xS2_S2_:
10921|  4.80k|                                      __m128i hi_tbl) noexcept {
10922|  4.80k|  const __m128i nibble = _mm_set1_epi8(0x0F);
10923|  4.80k|  const __m128i lo = _mm_and_si128(w, nibble);
10924|  4.80k|  const __m128i hi = _mm_and_si128(_mm_srli_epi16(w, 4), nibble);
10925|  4.80k|  const __m128i hit =
10926|  4.80k|      _mm_and_si128(_mm_shuffle_epi8(lo_tbl, lo), _mm_shuffle_epi8(hi_tbl, hi));
10927|  4.80k|  return _mm_movemask_epi8(_mm_cmpeq_epi8(hit, _mm_setzero_si128())) ^ 0xFFFF;
10928|  4.80k|}
url_search_params.cc:_ZN3ada6parser12_GLOBAL__N_117trailing_zeroes32Ej:
10893|  3.59k|ada_really_inline int trailing_zeroes32(uint32_t input_num) noexcept {
10894|       |#ifdef ADA_REGULAR_VISUAL_STUDIO
10895|       |  unsigned long ret;
10896|       |  _BitScanForward(&ret, input_num);
10897|       |  return static_cast<int>(ret);
10898|       |#else
10899|  3.59k|  return __builtin_ctz(input_num);
10900|  3.59k|#endif
10901|  3.59k|}
url_search_params.cc:_ZN3ada6parser12_GLOBAL__N_113scan_path_runEPKhRmmRb:
11319|  3.05k|                                   bool& maybe_dot_segment) noexcept {
11320|  3.05k|  const size_t run_start = i;
11321|  3.05k|#if ADA_PARSER_SSSE3
11322|  3.05k|  if (i + 16 <= len) {
  ------------------
  |  Branch (11322:7): [True: 1.03k, False: 2.02k]
  ------------------
11323|  1.03k|    const __m128i lo_tbl = nibble_load(k_path_nibbles.low);
11324|  1.03k|    const __m128i hi_tbl = nibble_load(k_path_nibbles.high);
11325|  1.03k|    for (; i + 32 <= len; i += 32) {
  ------------------
  |  Branch (11325:12): [True: 723, False: 311]
  ------------------
11326|    723|      const __m128i w0 =
11327|    723|          _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i));
11328|    723|      const int m0 = ssse3_nibble_mask(w0, lo_tbl, hi_tbl);
11329|    723|      if (m0 != 0) {
  ------------------
  |  Branch (11329:11): [True: 723, False: 0]
  ------------------
11330|    723|        const int hit_bit = trailing_zeroes32(static_cast<uint32_t>(m0));
11331|    723|        note_dots_in_window(b, i, run_start, w0, (1 << hit_bit) - 1,
11332|    723|                            maybe_dot_segment);
11333|    723|        i += static_cast<size_t>(hit_bit);
11334|    723|        return;
11335|    723|      }
11336|      0|      note_dots_in_window(b, i, run_start, w0, 0xFFFF, maybe_dot_segment);
11337|      0|      const __m128i w1 =
11338|      0|          _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i + 16));
11339|      0|      const int m1 = ssse3_nibble_mask(w1, lo_tbl, hi_tbl);
11340|      0|      if (m1 != 0) {
  ------------------
  |  Branch (11340:11): [True: 0, False: 0]
  ------------------
11341|      0|        const int hit_bit = trailing_zeroes32(static_cast<uint32_t>(m1));
11342|      0|        note_dots_in_window(b, i + 16, run_start, w1, (1 << hit_bit) - 1,
11343|      0|                            maybe_dot_segment);
11344|      0|        i += 16 + static_cast<size_t>(hit_bit);
11345|      0|        return;
11346|      0|      }
11347|      0|      note_dots_in_window(b, i + 16, run_start, w1, 0xFFFF, maybe_dot_segment);
11348|      0|    }
11349|    311|    for (; i + 16 <= len; i += 16) {
  ------------------
  |  Branch (11349:12): [True: 311, False: 0]
  ------------------
11350|    311|      const __m128i w =
11351|    311|          _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i));
11352|    311|      const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl);
11353|    311|      if (mask != 0) {
  ------------------
  |  Branch (11353:11): [True: 311, False: 0]
  ------------------
11354|    311|        const int hit_bit = trailing_zeroes32(static_cast<uint32_t>(mask));
11355|    311|        note_dots_in_window(b, i, run_start, w, (1 << hit_bit) - 1,
11356|    311|                            maybe_dot_segment);
11357|    311|        i += static_cast<size_t>(hit_bit);
11358|    311|        return;
11359|    311|      }
11360|      0|      note_dots_in_window(b, i, run_start, w, 0xFFFF, maybe_dot_segment);
11361|      0|    }
11362|      0|    if (i > run_start && i < len) {
  ------------------
  |  Branch (11362:9): [True: 0, False: 0]
  |  Branch (11362:26): [True: 0, False: 0]
  ------------------
11363|      0|      const __m128i w =
11364|      0|          _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + len - 16));
11365|      0|      const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl);
11366|      0|      if (mask != 0) {
  ------------------
  |  Branch (11366:11): [True: 0, False: 0]
  ------------------
11367|      0|        const size_t hit =
11368|      0|            len - 16 +
11369|      0|            static_cast<size_t>(trailing_zeroes32(static_cast<uint32_t>(mask)));
11370|      0|        if (hit >= i) {
  ------------------
  |  Branch (11370:13): [True: 0, False: 0]
  ------------------
11371|      0|          for (size_t j = i; j < hit; ++j) {
  ------------------
  |  Branch (11371:30): [True: 0, False: 0]
  ------------------
11372|      0|            if (b[j] == '.') {
  ------------------
  |  Branch (11372:17): [True: 0, False: 0]
  ------------------
11373|      0|              note_possible_dot_segment(b, j, run_start, maybe_dot_segment);
11374|      0|            }
11375|      0|          }
11376|      0|          i = hit;
11377|      0|          return;
11378|      0|        }
11379|      0|      }
11380|      0|      for (size_t j = i; j < len; ++j) {
  ------------------
  |  Branch (11380:26): [True: 0, False: 0]
  ------------------
11381|      0|        if (b[j] == '.') {
  ------------------
  |  Branch (11381:13): [True: 0, False: 0]
  ------------------
11382|      0|          note_possible_dot_segment(b, j, run_start, maybe_dot_segment);
11383|      0|        }
11384|      0|      }
11385|      0|      i = len;
11386|      0|      return;
11387|      0|    }
11388|      0|  }
11389|       |#elif ADA_SSE2
11390|       |  for (; i + 16 <= len; i += 16) {
11391|       |    const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i));
11392|       |    const int mask = sse2_path_stop(w);
11393|       |    if (mask != 0) {
11394|       |      const int hit_bit = trailing_zeroes32(static_cast<uint32_t>(mask));
11395|       |      note_dots_in_window(b, i, run_start, w, (1 << hit_bit) - 1,
11396|       |                          maybe_dot_segment);
11397|       |      i += static_cast<size_t>(hit_bit);
11398|       |      return;
11399|       |    }
11400|       |    note_dots_in_window(b, i, run_start, w, 0xFFFF, maybe_dot_segment);
11401|       |  }
11402|       |#elif ADA_NEON
11403|       |  if (i + 16 <= len) {
11404|       |    const uint8x16_t lo_tbl = vld1q_u8(k_path_nibbles.low);
11405|       |    const uint8x16_t hi_tbl = vld1q_u8(k_path_nibbles.high);
11406|       |    for (; i + 32 <= len; i += 32) {
11407|       |      const uint8x16_t w0 = vld1q_u8(b + i);
11408|       |      const uint64_t bits0 = neon_table_stop(w0, lo_tbl, hi_tbl);
11409|       |      if (bits0 != 0) {
11410|       |        const size_t hit_off =
11411|       |            static_cast<size_t>(trailing_zeroes64(bits0)) >> 2;
11412|       |        const uint64_t valid =
11413|       |            (hit_off == 0) ? 0 : (uint64_t{1} << (hit_off * 4)) - 1;
11414|       |        note_dots_in_window_neon(b, i, run_start, w0, valid, maybe_dot_segment);
11415|       |        i += hit_off;
11416|       |        return;
11417|       |      }
11418|       |      note_dots_in_window_neon(b, i, run_start, w0, ~uint64_t{0},
11419|       |                               maybe_dot_segment);
11420|       |      const uint8x16_t w1 = vld1q_u8(b + i + 16);
11421|       |      const uint64_t bits1 = neon_table_stop(w1, lo_tbl, hi_tbl);
11422|       |      if (bits1 != 0) {
11423|       |        const size_t hit_off =
11424|       |            static_cast<size_t>(trailing_zeroes64(bits1)) >> 2;
11425|       |        const uint64_t valid =
11426|       |            (hit_off == 0) ? 0 : (uint64_t{1} << (hit_off * 4)) - 1;
11427|       |        note_dots_in_window_neon(b, i + 16, run_start, w1, valid,
11428|       |                                 maybe_dot_segment);
11429|       |        i += 16 + hit_off;
11430|       |        return;
11431|       |      }
11432|       |      note_dots_in_window_neon(b, i + 16, run_start, w1, ~uint64_t{0},
11433|       |                               maybe_dot_segment);
11434|       |    }
11435|       |    for (; i + 16 <= len; i += 16) {
11436|       |      const uint8x16_t w = vld1q_u8(b + i);
11437|       |      const uint64_t bits = neon_table_stop(w, lo_tbl, hi_tbl);
11438|       |      if (bits != 0) {
11439|       |        const size_t hit_off =
11440|       |            static_cast<size_t>(trailing_zeroes64(bits)) >> 2;
11441|       |        const uint64_t valid =
11442|       |            (hit_off == 0) ? 0 : (uint64_t{1} << (hit_off * 4)) - 1;
11443|       |        note_dots_in_window_neon(b, i, run_start, w, valid, maybe_dot_segment);
11444|       |        i += hit_off;
11445|       |        return;
11446|       |      }
11447|       |      note_dots_in_window_neon(b, i, run_start, w, ~uint64_t{0},
11448|       |                               maybe_dot_segment);
11449|       |    }
11450|       |    if (i > run_start && i < len) {
11451|       |      const uint8x16_t w = vld1q_u8(b + len - 16);
11452|       |      const uint64_t bits = neon_table_stop(w, lo_tbl, hi_tbl);
11453|       |      if (bits != 0) {
11454|       |        const size_t hit =
11455|       |            len - 16 + (static_cast<size_t>(trailing_zeroes64(bits)) >> 2);
11456|       |        if (hit >= i) {
11457|       |          for (size_t j = i; j < hit; ++j) {
11458|       |            if (b[j] == '.') {
11459|       |              note_possible_dot_segment(b, j, run_start, maybe_dot_segment);
11460|       |            }
11461|       |          }
11462|       |          i = hit;
11463|       |          return;
11464|       |        }
11465|       |      }
11466|       |      for (size_t j = i; j < len; ++j) {
11467|       |        if (b[j] == '.') {
11468|       |          note_possible_dot_segment(b, j, run_start, maybe_dot_segment);
11469|       |        }
11470|       |      }
11471|       |      i = len;
11472|       |      return;
11473|       |    }
11474|       |  }
11475|       |#endif
11476|  2.02k|  for (; i < len; ++i) {
  ------------------
  |  Branch (11476:10): [True: 2.02k, False: 0]
  ------------------
11477|  2.02k|    const uint8_t c = b[i];
11478|  2.02k|    const uint8_t cls = k_path[c];
11479|  2.02k|    if (cls != 0) {
  ------------------
  |  Branch (11479:9): [True: 2.02k, False: 0]
  ------------------
11480|  2.02k|      return;
11481|  2.02k|    }
11482|      0|    if (c == '.') {
  ------------------
  |  Branch (11482:9): [True: 0, False: 0]
  ------------------
11483|      0|      note_possible_dot_segment(b, i, run_start, maybe_dot_segment);
11484|      0|    }
11485|      0|  }
11486|  2.02k|}
url_search_params.cc:_ZN3ada6parser12_GLOBAL__N_119note_dots_in_windowEPKhmmDv2_xiRb:
11276|  1.03k|                                           bool& maybe_dot_segment) noexcept {
11277|  1.03k|  if (maybe_dot_segment || valid_mask == 0) {
  ------------------
  |  Branch (11277:7): [True: 0, False: 1.03k]
  |  Branch (11277:28): [True: 1.03k, False: 0]
  ------------------
11278|  1.03k|    return;
11279|  1.03k|  }
11280|      0|  const int dots =
11281|      0|      _mm_movemask_epi8(_mm_cmpeq_epi8(w, _mm_set1_epi8('.'))) & valid_mask;
11282|      0|  if (dots == 0) {
  ------------------
  |  Branch (11282:7): [True: 0, False: 0]
  ------------------
11283|      0|    return;
11284|      0|  }
11285|      0|  const int slashes =
11286|      0|      _mm_movemask_epi8(_mm_cmpeq_epi8(w, _mm_set1_epi8('/'))) & valid_mask;
11287|      0|  if (((dots & 1) != 0 && (i == run_start || b[i - 1] == '/')) ||
  ------------------
  |  Branch (11287:8): [True: 0, False: 0]
  |  Branch (11287:28): [True: 0, False: 0]
  |  Branch (11287:46): [True: 0, False: 0]
  ------------------
11288|      0|      (dots & (slashes << 1)) != 0) {
  ------------------
  |  Branch (11288:7): [True: 0, False: 0]
  ------------------
11289|      0|    maybe_dot_segment = true;
11290|      0|  }
11291|      0|}
url_search_params.cc:_ZN3ada6parser12_GLOBAL__N_114scan_query_runEPKhRmm:
11629|  3.05k|                                    size_t len) noexcept {
11630|  3.05k|  ADA_SCAN_STOP_RUN(k_query_nibbles, k_query, sse2_query_stop);
  ------------------
  |  |11492|  3.05k|  do {                                                                       \
  |  |11493|  3.05k|    const size_t scan_start = i;                                             \
  |  |11494|  3.05k|    if (i + 16 <= len) {                                                     \
  |  |  ------------------
  |  |  |  Branch (11494:9): [True: 994, False: 2.06k]
  |  |  ------------------
  |  |11495|    994|      const __m128i lo_tbl = nibble_load((nibbles).low);                     \
  |  |11496|    994|      const __m128i hi_tbl = nibble_load((nibbles).high);                    \
  |  |11497|  1.32k|      for (; i + 32 <= len; i += 32) {                                       \
  |  |  ------------------
  |  |  |  Branch (11497:14): [True: 935, False: 394]
  |  |  ------------------
  |  |11498|    935|        const __m128i w0 =                                                   \
  |  |11499|    935|            _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i));        \
  |  |11500|    935|        const int m0 = ssse3_nibble_mask(w0, lo_tbl, hi_tbl);                \
  |  |11501|    935|        if (m0 != 0) {                                                       \
  |  |  ------------------
  |  |  |  Branch (11501:13): [True: 529, False: 406]
  |  |  ------------------
  |  |11502|    529|          i += static_cast<size_t>(                                          \
  |  |11503|    529|              trailing_zeroes32(static_cast<uint32_t>(m0)));                 \
  |  |11504|    529|          return;                                                            \
  |  |11505|    529|        }                                                                    \
  |  |11506|    935|        const __m128i w1 =                                                   \
  |  |11507|    406|            _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i + 16));   \
  |  |11508|    406|        const int m1 = ssse3_nibble_mask(w1, lo_tbl, hi_tbl);                \
  |  |11509|    406|        if (m1 != 0) {                                                       \
  |  |  ------------------
  |  |  |  Branch (11509:13): [True: 71, False: 335]
  |  |  ------------------
  |  |11510|     71|          i += 16 + static_cast<size_t>(                                     \
  |  |11511|     71|                        trailing_zeroes32(static_cast<uint32_t>(m1)));       \
  |  |11512|     71|          return;                                                            \
  |  |11513|     71|        }                                                                    \
  |  |11514|    406|      }                                                                      \
  |  |11515|    994|      for (; i + 16 <= len; i += 16) {                                       \
  |  |  ------------------
  |  |  |  Branch (11515:14): [True: 336, False: 153]
  |  |  ------------------
  |  |11516|    336|        const __m128i w =                                                    \
  |  |11517|    336|            _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i));        \
  |  |11518|    336|        const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl);               \
  |  |11519|    336|        if (mask != 0) {                                                     \
  |  |  ------------------
  |  |  |  Branch (11519:13): [True: 241, False: 95]
  |  |  ------------------
  |  |11520|    241|          i += static_cast<size_t>(                                          \
  |  |11521|    241|              trailing_zeroes32(static_cast<uint32_t>(mask)));               \
  |  |11522|    241|          return;                                                            \
  |  |11523|    241|        }                                                                    \
  |  |11524|    336|      }                                                                      \
  |  |11525|    394|      if (i > scan_start && i < len) {                                       \
  |  |  ------------------
  |  |  |  Branch (11525:11): [True: 153, False: 0]
  |  |  |  Branch (11525:29): [True: 118, False: 35]
  |  |  ------------------
  |  |11526|    118|        const __m128i w =                                                    \
  |  |11527|    118|            _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + len - 16)); \
  |  |11528|    118|        const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl);               \
  |  |11529|    118|        if (mask != 0) {                                                     \
  |  |  ------------------
  |  |  |  Branch (11529:13): [True: 61, False: 57]
  |  |  ------------------
  |  |11530|     61|          const size_t hit = len - 16 +                                      \
  |  |11531|     61|                             static_cast<size_t>(trailing_zeroes32(          \
  |  |11532|     61|                                 static_cast<uint32_t>(mask)));              \
  |  |11533|     61|          if (hit >= i) {                                                    \
  |  |  ------------------
  |  |  |  Branch (11533:15): [True: 61, False: 0]
  |  |  ------------------
  |  |11534|     61|            i = hit;                                                         \
  |  |11535|     61|            return;                                                          \
  |  |11536|     61|          }                                                                  \
  |  |11537|     61|        }                                                                    \
  |  |11538|    118|        i = len;                                                             \
  |  |11539|     57|        return;                                                              \
  |  |11540|    118|      }                                                                      \
  |  |11541|    153|    }                                                                        \
  |  |11542|  3.20k|    for (; i < len; ++i) {                                                   \
  |  |  ------------------
  |  |  |  Branch (11542:12): [True: 1.87k, False: 1.33k]
  |  |  ------------------
  |  |11543|  1.87k|      if ((cls)[b[i]] != 0) {                                                \
  |  |  ------------------
  |  |  |  Branch (11543:11): [True: 762, False: 1.11k]
  |  |  ------------------
  |  |11544|    762|        return;                                                              \
  |  |11545|    762|      }                                                                      \
  |  |11546|  1.87k|    }                                                                        \
  |  |11547|  2.09k|  } while (0)
  |  |  ------------------
  |  |  |  Branch (11547:12): [Folded, False: 1.33k]
  |  |  ------------------
  ------------------
11631|  3.05k|}
url_search_params.cc:_ZN3ada6parser12_GLOBAL__N_113scan_hash_runEPKhRmm:
11634|    307|                                   size_t len) noexcept {
11635|    307|  ADA_SCAN_STOP_RUN(k_hash_nibbles, k_hash, sse2_hash_stop);
  ------------------
  |  |11492|    307|  do {                                                                       \
  |  |11493|    307|    const size_t scan_start = i;                                             \
  |  |11494|    307|    if (i + 16 <= len) {                                                     \
  |  |  ------------------
  |  |  |  Branch (11494:9): [True: 191, False: 116]
  |  |  ------------------
  |  |11495|    191|      const __m128i lo_tbl = nibble_load((nibbles).low);                     \
  |  |11496|    191|      const __m128i hi_tbl = nibble_load((nibbles).high);                    \
  |  |11497|    293|      for (; i + 32 <= len; i += 32) {                                       \
  |  |  ------------------
  |  |  |  Branch (11497:14): [True: 180, False: 113]
  |  |  ------------------
  |  |11498|    180|        const __m128i w0 =                                                   \
  |  |11499|    180|            _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i));        \
  |  |11500|    180|        const int m0 = ssse3_nibble_mask(w0, lo_tbl, hi_tbl);                \
  |  |11501|    180|        if (m0 != 0) {                                                       \
  |  |  ------------------
  |  |  |  Branch (11501:13): [True: 45, False: 135]
  |  |  ------------------
  |  |11502|     45|          i += static_cast<size_t>(                                          \
  |  |11503|     45|              trailing_zeroes32(static_cast<uint32_t>(m0)));                 \
  |  |11504|     45|          return;                                                            \
  |  |11505|     45|        }                                                                    \
  |  |11506|    180|        const __m128i w1 =                                                   \
  |  |11507|    135|            _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i + 16));   \
  |  |11508|    135|        const int m1 = ssse3_nibble_mask(w1, lo_tbl, hi_tbl);                \
  |  |11509|    135|        if (m1 != 0) {                                                       \
  |  |  ------------------
  |  |  |  Branch (11509:13): [True: 33, False: 102]
  |  |  ------------------
  |  |11510|     33|          i += 16 + static_cast<size_t>(                                     \
  |  |11511|     33|                        trailing_zeroes32(static_cast<uint32_t>(m1)));       \
  |  |11512|     33|          return;                                                            \
  |  |11513|     33|        }                                                                    \
  |  |11514|    135|      }                                                                      \
  |  |11515|    191|      for (; i + 16 <= len; i += 16) {                                       \
  |  |  ------------------
  |  |  |  Branch (11515:14): [True: 94, False: 83]
  |  |  ------------------
  |  |11516|     94|        const __m128i w =                                                    \
  |  |11517|     94|            _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i));        \
  |  |11518|     94|        const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl);               \
  |  |11519|     94|        if (mask != 0) {                                                     \
  |  |  ------------------
  |  |  |  Branch (11519:13): [True: 30, False: 64]
  |  |  ------------------
  |  |11520|     30|          i += static_cast<size_t>(                                          \
  |  |11521|     30|              trailing_zeroes32(static_cast<uint32_t>(mask)));               \
  |  |11522|     30|          return;                                                            \
  |  |11523|     30|        }                                                                    \
  |  |11524|     94|      }                                                                      \
  |  |11525|    113|      if (i > scan_start && i < len) {                                       \
  |  |  ------------------
  |  |  |  Branch (11525:11): [True: 83, False: 0]
  |  |  |  Branch (11525:29): [True: 75, False: 8]
  |  |  ------------------
  |  |11526|     75|        const __m128i w =                                                    \
  |  |11527|     75|            _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + len - 16)); \
  |  |11528|     75|        const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl);               \
  |  |11529|     75|        if (mask != 0) {                                                     \
  |  |  ------------------
  |  |  |  Branch (11529:13): [True: 56, False: 19]
  |  |  ------------------
  |  |11530|     56|          const size_t hit = len - 16 +                                      \
  |  |11531|     56|                             static_cast<size_t>(trailing_zeroes32(          \
  |  |11532|     56|                                 static_cast<uint32_t>(mask)));              \
  |  |11533|     56|          if (hit >= i) {                                                    \
  |  |  ------------------
  |  |  |  Branch (11533:15): [True: 56, False: 0]
  |  |  ------------------
  |  |11534|     56|            i = hit;                                                         \
  |  |11535|     56|            return;                                                          \
  |  |11536|     56|          }                                                                  \
  |  |11537|     56|        }                                                                    \
  |  |11538|     75|        i = len;                                                             \
  |  |11539|     19|        return;                                                              \
  |  |11540|     75|      }                                                                      \
  |  |11541|     83|    }                                                                        \
  |  |11542|    307|    for (; i < len; ++i) {                                                   \
  |  |  ------------------
  |  |  |  Branch (11542:12): [True: 162, False: 81]
  |  |  ------------------
  |  |11543|    162|      if ((cls)[b[i]] != 0) {                                                \
  |  |  ------------------
  |  |  |  Branch (11543:11): [True: 43, False: 119]
  |  |  ------------------
  |  |11544|     43|        return;                                                              \
  |  |11545|     43|      }                                                                      \
  |  |11546|    162|    }                                                                        \
  |  |11547|    124|  } while (0)
  |  |  ------------------
  |  |  |  Branch (11547:12): [Folded, False: 81]
  |  |  ------------------
  ------------------
11636|    307|}
url_search_params.cc:_ZN12_GLOBAL__N_132apply_shifted_non_scheme_offsetsERN3ada14url_componentsEj:
13637|    500|    ada::url_components& components, uint32_t new_difference) {
13638|    500|  components.username_end += new_difference;
13639|    500|  components.host_start += new_difference;
13640|    500|  components.host_end += new_difference;
13641|    500|  components.pathname_start += new_difference;
13642|    500|  if (components.search_start != ada::url_components::omitted) {
  ------------------
  |  Branch (13642:7): [True: 0, False: 500]
  ------------------
13643|      0|    components.search_start += new_difference;
13644|      0|  }
13645|    500|  if (components.hash_start != ada::url_components::omitted) {
  ------------------
  |  Branch (13645:7): [True: 0, False: 500]
  ------------------
13646|      0|    components.hash_start += new_difference;
13647|      0|  }
13648|    500|}
_ZN3ada14url_aggregator10parse_pathENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
14007|  1.06k|ada_really_inline void url_aggregator::parse_path(std::string_view input) {
14008|  1.06k|  ada_log("url_aggregator::parse_path ", input);
14009|  1.06k|  ADA_ASSERT_TRUE(validate());
14010|  1.06k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
14011|  1.06k|  std::string tmp_buffer;
14012|  1.06k|  std::string_view internal_input;
14013|  1.06k|  if (unicode::has_tabs_or_newline(input)) {
  ------------------
  |  Branch (14013:7): [True: 0, False: 1.06k]
  ------------------
14014|      0|    tmp_buffer = input;
14015|       |    // Optimization opportunity: Instead of copying and then pruning, we could
14016|       |    // just directly build the string from user_input.
14017|      0|    helpers::remove_ascii_tab_or_newline(tmp_buffer);
14018|      0|    internal_input = tmp_buffer;
14019|  1.06k|  } else {
14020|  1.06k|    internal_input = input;
14021|  1.06k|  }
14022|       |
14023|       |  // If url is special, then:
14024|  1.06k|  if (is_special()) {
  ------------------
  |  Branch (14024:7): [True: 1.06k, False: 0]
  ------------------
14025|  1.06k|    if (internal_input.empty()) {
  ------------------
  |  Branch (14025:9): [True: 0, False: 1.06k]
  ------------------
14026|      0|      update_base_pathname("/");
14027|  1.06k|    } else if ((internal_input[0] == '/') || (internal_input[0] == '\\')) {
  ------------------
  |  Branch (14027:16): [True: 1.06k, False: 0]
  |  Branch (14027:46): [True: 0, False: 0]
  ------------------
14028|  1.06k|      consume_prepared_path(internal_input.substr(1));
14029|  1.06k|    } else {
14030|      0|      consume_prepared_path(internal_input);
14031|      0|    }
14032|  1.06k|  } else if (!internal_input.empty()) {
  ------------------
  |  Branch (14032:14): [True: 0, False: 0]
  ------------------
14033|      0|    if (internal_input[0] == '/') {
  ------------------
  |  Branch (14033:9): [True: 0, False: 0]
  ------------------
14034|      0|      consume_prepared_path(internal_input.substr(1));
14035|      0|    } else {
14036|      0|      consume_prepared_path(internal_input);
14037|      0|    }
14038|      0|  } else {
14039|       |    // Non-special URLs with an empty host can have their paths erased
14040|       |    // Path-only URLs cannot have their paths erased
14041|      0|    if (components.host_start == components.host_end && !has_authority()) {
  ------------------
  |  Branch (14041:9): [True: 0, False: 0]
  |  Branch (14041:57): [True: 0, False: 0]
  ------------------
14042|      0|      update_base_pathname("/");
14043|      0|    }
14044|      0|  }
14045|  1.06k|  ADA_ASSERT_TRUE(validate());
14046|  1.06k|}
_ZN3ada14url_aggregator10parse_hostENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
14126|    500|ada_really_inline bool url_aggregator::parse_host(std::string_view input) {
14127|    500|  ada_log("url_aggregator:parse_host \"", input, "\" [", input.size(),
14128|    500|          " bytes]");
14129|    500|  ADA_ASSERT_TRUE(validate());
14130|    500|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
14131|    500|  if (input.empty()) {
  ------------------
  |  Branch (14131:7): [True: 0, False: 500]
  ------------------
14132|      0|    return is_valid = false;
14133|      0|  }  // technically unnecessary.
14134|       |  // If input starts with U+005B ([), then:
14135|    500|  if (input[0] == '[') {
  ------------------
  |  Branch (14135:7): [True: 0, False: 500]
  ------------------
14136|       |    // If input does not end with U+005D (]), validation error, return failure.
14137|      0|    if (input.back() != ']') {
  ------------------
  |  Branch (14137:9): [True: 0, False: 0]
  ------------------
14138|      0|      return is_valid = false;
14139|      0|    }
14140|      0|    ada_log("parse_host ipv6");
14141|       |
14142|       |    // Return the result of IPv6 parsing input with its leading U+005B ([) and
14143|       |    // trailing U+005D (]) removed.
14144|      0|    input.remove_prefix(1);
14145|      0|    input.remove_suffix(1);
14146|      0|    return parse_ipv6(input);
14147|      0|  }
14148|       |
14149|       |  // If isNotSpecial is true, then return the result of opaque-host parsing
14150|       |  // input.
14151|    500|  if (!is_special()) {
  ------------------
  |  Branch (14151:7): [True: 0, False: 500]
  ------------------
14152|      0|    return parse_opaque_host(input);
14153|      0|  }
14154|       |  // Let domain be the result of running UTF-8 decode without BOM on the
14155|       |  // percent-decoding of input. Let asciiDomain be the result of running domain
14156|       |  // to ASCII with domain and false. The most common case is an ASCII input, in
14157|       |  // which case we do not need to call the expensive 'to_ascii' if a few
14158|       |  // conditions are met: no '%' and no 'xn-' subsequence.
14159|       |
14160|       |  // Often, the input does not contain any forbidden code points, and no upper
14161|       |  // case ASCII letter, then we can just copy it to the buffer. We want to
14162|       |  // optimize for such a common case.
14163|       |
14164|       |  // Fast path: try to parse as pure decimal IPv4 first.
14165|    500|  const uint64_t fast_result = checkers::try_parse_ipv4_fast(input);
14166|    500|  if (fast_result < checkers::ipv4_fast_fail) {
  ------------------
  |  Branch (14166:7): [True: 0, False: 500]
  ------------------
14167|      0|    if (!input.empty() && input.back() == '.') {
  ------------------
  |  Branch (14167:9): [True: 0, False: 0]
  |  Branch (14167:27): [True: 0, False: 0]
  ------------------
14168|      0|      update_base_hostname(input.substr(0, input.size() - 1));
14169|      0|    } else {
14170|      0|      update_base_hostname(input);
14171|      0|    }
14172|      0|    host_type = IPV4;
14173|      0|    is_valid = true;
14174|      0|    ada_log("parse_host fast path decimal ipv4");
14175|      0|    ADA_ASSERT_TRUE(validate());
14176|      0|    return true;
14177|      0|  }
14178|    500|  uint8_t is_forbidden_or_upper =
14179|    500|      unicode::contains_forbidden_domain_code_point_or_upper(input.data(),
14180|    500|                                                             input.size());
14181|    500|  static constexpr std::string_view xn_dash{"xn-", 3};
14182|    500|  if ((is_forbidden_or_upper & 1) == 0) {
  ------------------
  |  Branch (14182:7): [True: 500, False: 0]
  ------------------
14183|    500|    if ((is_forbidden_or_upper & 2) != 0) {
  ------------------
  |  Branch (14183:9): [True: 0, False: 500]
  ------------------
14184|      0|      std::string lowered(input);
14185|      0|      unicode::to_lower_ascii(lowered.data(), lowered.size());
14186|      0|      if (lowered.find('-') == std::string_view::npos ||
  ------------------
  |  Branch (14186:11): [True: 0, False: 0]
  ------------------
14187|      0|          lowered.find(xn_dash) == std::string_view::npos) {
  ------------------
  |  Branch (14187:11): [True: 0, False: 0]
  ------------------
14188|      0|        update_base_hostname(lowered);
14189|      0|        if (checkers::is_ipv4(lowered)) {
  ------------------
  |  Branch (14189:13): [True: 0, False: 0]
  ------------------
14190|      0|          ada_log("parse_host fast path ipv4");
14191|      0|          return parse_ipv4(lowered, true);
14192|      0|        }
14193|      0|        ada_log("parse_host fast path ", get_hostname());
14194|      0|        is_valid = true;
14195|      0|        return true;
14196|      0|      }
14197|    500|    } else if (input.find('-') == std::string_view::npos ||
  ------------------
  |  Branch (14197:16): [True: 500, False: 0]
  ------------------
14198|    500|               input.find(xn_dash) == std::string_view::npos) {
  ------------------
  |  Branch (14198:16): [True: 0, False: 0]
  ------------------
14199|    500|      update_base_hostname(input);
14200|    500|      if (checkers::is_ipv4(input)) {
  ------------------
  |  Branch (14200:11): [True: 0, False: 500]
  ------------------
14201|      0|        ada_log("parse_host fast path ipv4");
14202|      0|        return parse_ipv4(input, true);
14203|      0|      }
14204|    500|      ada_log("parse_host fast path ", get_hostname());
14205|    500|      is_valid = true;
14206|    500|      return true;
14207|    500|    }
14208|    500|  } else if (const size_t first_percent = input.find('%');
14209|      0|             first_percent != std::string_view::npos) {
  ------------------
  |  Branch (14209:14): [True: 0, False: 0]
  ------------------
14210|      0|    std::string decoded = unicode::percent_decode(input, first_percent);
14211|      0|    const uint8_t decoded_flags =
14212|      0|        unicode::contains_forbidden_domain_code_point_or_upper(decoded.data(),
14213|      0|                                                               decoded.size());
14214|      0|    if ((decoded_flags & 1) == 0) {
  ------------------
  |  Branch (14214:9): [True: 0, False: 0]
  ------------------
14215|      0|      if ((decoded_flags & 2) != 0) {
  ------------------
  |  Branch (14215:11): [True: 0, False: 0]
  ------------------
14216|      0|        unicode::to_lower_ascii(decoded.data(), decoded.size());
14217|      0|      }
14218|      0|      if (decoded.find('-') == std::string_view::npos ||
  ------------------
  |  Branch (14218:11): [True: 0, False: 0]
  ------------------
14219|      0|          decoded.find(xn_dash) == std::string_view::npos) {
  ------------------
  |  Branch (14219:11): [True: 0, False: 0]
  ------------------
14220|      0|        update_base_hostname(decoded);
14221|      0|        if (checkers::is_ipv4(decoded)) {
  ------------------
  |  Branch (14221:13): [True: 0, False: 0]
  ------------------
14222|      0|          return parse_ipv4(decoded, true);
14223|      0|        }
14224|      0|        is_valid = true;
14225|      0|        return true;
14226|      0|      }
14227|      0|    }
14228|      0|  }
14229|       |  // We have encountered at least one forbidden code point or the input contains
14230|       |  // 'xn-' (case insensitive), so we need to call 'to_ascii' to perform the full
14231|       |  // conversion.
14232|       |
14233|      0|  ada_log("parse_host calling to_ascii");
14234|      0|  std::optional<std::string> host = std::string(get_hostname());
14235|      0|  is_valid = ada::unicode::to_ascii(host, input, input.find('%'));
14236|      0|  if (!is_valid) {
  ------------------
  |  Branch (14236:7): [True: 0, False: 0]
  ------------------
14237|      0|    ada_log("parse_host to_ascii returns false");
14238|      0|    return is_valid = false;
14239|      0|  }
14240|      0|  ada_log("parse_host to_ascii succeeded ", *host, " [", host->size(),
14241|      0|          " bytes]");
14242|       |
14243|      0|  if (std::ranges::any_of(host.value(),
  ------------------
  |  Branch (14243:7): [True: 0, False: 0]
  ------------------
14244|      0|                          ada::unicode::is_forbidden_domain_code_point)) {
14245|      0|    return is_valid = false;
14246|      0|  }
14247|       |
14248|       |  // If asciiDomain ends in a number, then return the result of IPv4 parsing
14249|       |  // asciiDomain.
14250|      0|  if (checkers::is_ipv4(host.value())) {
  ------------------
  |  Branch (14250:7): [True: 0, False: 0]
  ------------------
14251|      0|    ada_log("parse_host got ipv4 ", *host);
14252|      0|    return parse_ipv4(host.value(), false);
14253|      0|  }
14254|       |
14255|      0|  update_base_hostname(host.value());
14256|      0|  ADA_ASSERT_TRUE(validate());
14257|      0|  return true;
14258|      0|}
_ZN3ada14url_aggregator21consume_prepared_pathENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
15077|  1.56k|inline void url_aggregator::consume_prepared_path(std::string_view input) {
15078|  1.56k|  ada_log("url_aggregator::consume_prepared_path ", input);
15079|       |  /***
15080|       |   * This is largely duplicated code from helpers::parse_prepared_path, which is
15081|       |   * unfortunate. This particular function is nearly identical, except that it
15082|       |   * is a method on url_aggregator. The idea is that the trivial path (which is
15083|       |   * very common) merely appends to the buffer. This is the same trivial path as
15084|       |   * with helpers::parse_prepared_path, except that we have the additional check
15085|       |   * for is_at_path(). Otherwise, we grab a copy of the current path and we
15086|       |   * modify it, and then insert it back into the buffer.
15087|       |   */
15088|  1.56k|  uint8_t accumulator = checkers::path_signature(input);
15089|       |  // Let us first detect a trivial case.
15090|       |  // If it is special, we check that we have no dot, no %,  no \ and no
15091|       |  // character needing percent encoding. Otherwise, we check that we have no %,
15092|       |  // no dot, and no character needing percent encoding.
15093|  1.56k|  constexpr uint8_t need_encoding = 1;
15094|  1.56k|  constexpr uint8_t backslash_char = 2;
15095|  1.56k|  constexpr uint8_t dot_char = 4;
15096|  1.56k|  constexpr uint8_t percent_char = 8;
15097|  1.56k|  bool special = type != ada::scheme::NOT_SPECIAL;
15098|  1.56k|  bool may_need_slow_file_handling = (type == ada::scheme::type::FILE &&
  ------------------
  |  Branch (15098:39): [True: 0, False: 1.56k]
  ------------------
15099|      0|                                      checkers::is_windows_drive_letter(input));
  ------------------
  |  Branch (15099:39): [True: 0, False: 0]
  ------------------
15100|  1.56k|  bool trivial_path =
15101|  1.56k|      (special ? (accumulator == 0)
  ------------------
  |  Branch (15101:7): [True: 1.56k, False: 0]
  |  Branch (15101:8): [True: 1.56k, False: 0]
  ------------------
15102|  1.56k|               : ((accumulator & (need_encoding | dot_char | percent_char)) ==
15103|      0|                  0)) &&
15104|  1.56k|      (!may_need_slow_file_handling);
  ------------------
  |  Branch (15104:7): [True: 1.56k, False: 0]
  ------------------
15105|  1.56k|  if (accumulator == dot_char && !may_need_slow_file_handling) {
  ------------------
  |  Branch (15105:7): [True: 0, False: 1.56k]
  |  Branch (15105:34): [True: 0, False: 0]
  ------------------
15106|       |    // '4' means that we have at least one dot, but nothing that requires
15107|       |    // percent encoding or decoding. The only part that is not trivial is
15108|       |    // that we may have single dots and double dots path segments.
15109|       |    // If we have such segments, then we either have a path that begins
15110|       |    // with '.' (easy to check), or we have the sequence './'.
15111|       |    // Note: input cannot be empty, it must at least contain one character ('.')
15112|       |    // Note: we know that '\' is not present.
15113|      0|    if (input[0] != '.') {
  ------------------
  |  Branch (15113:9): [True: 0, False: 0]
  ------------------
15114|      0|      size_t slashdot = 0;
15115|      0|      bool dot_is_file = true;
15116|      0|      for (;;) {
15117|      0|        slashdot = input.find("/.", slashdot);
15118|      0|        if (slashdot == std::string_view::npos) {  // common case
  ------------------
  |  Branch (15118:13): [True: 0, False: 0]
  ------------------
15119|      0|          break;
15120|      0|        } else {  // uncommon
15121|       |          // only three cases matter: /./, /.. or a final /
15122|      0|          slashdot += 2;
15123|      0|          dot_is_file &= !(slashdot == input.size() || input[slashdot] == '.' ||
  ------------------
  |  Branch (15123:28): [True: 0, False: 0]
  |  Branch (15123:56): [True: 0, False: 0]
  ------------------
15124|      0|                           input[slashdot] == '/');
  ------------------
  |  Branch (15124:28): [True: 0, False: 0]
  ------------------
15125|      0|        }
15126|      0|      }
15127|      0|      trivial_path = dot_is_file;
15128|      0|    }
15129|      0|  }
15130|  1.56k|  if (trivial_path && is_at_path()) {
  ------------------
  |  Branch (15130:7): [True: 1.56k, False: 0]
  |  Branch (15130:23): [True: 1.56k, False: 0]
  ------------------
15131|  1.56k|    ada_log("parse_path trivial");
15132|  1.56k|    buffer += '/';
15133|  1.56k|    buffer += input;
15134|  1.56k|    return;
15135|  1.56k|  }
15136|      0|  std::string path = std::string(get_pathname());
15137|       |  // We are going to need to look a bit at the path, but let us see if we can
15138|       |  // ignore percent encoding *and* backslashes *and* percent characters.
15139|       |  // Except for the trivial case, this is likely to capture 99% of paths out
15140|       |  // there.
15141|      0|  bool fast_path =
15142|      0|      (special &&
  ------------------
  |  Branch (15142:8): [True: 0, False: 0]
  ------------------
15143|      0|       (accumulator & (need_encoding | backslash_char | percent_char)) == 0) &&
  ------------------
  |  Branch (15143:8): [True: 0, False: 0]
  ------------------
15144|      0|      (type != ada::scheme::type::FILE);
  ------------------
  |  Branch (15144:7): [True: 0, False: 0]
  ------------------
15145|      0|  if (fast_path) {
  ------------------
  |  Branch (15145:7): [True: 0, False: 0]
  ------------------
15146|      0|    ada_log("parse_prepared_path fast");
15147|       |    // Here we don't need to worry about \ or percent encoding.
15148|       |    // We also do not have a file protocol. We might have dots, however,
15149|       |    // but dots must as appear as '.', and they cannot be encoded because
15150|       |    // the symbol '%' is not present.
15151|      0|    size_t previous_location = 0;  // We start at 0.
15152|      0|    do {
15153|      0|      size_t new_location = input.find('/', previous_location);
15154|       |      // std::string_view path_view = input;
15155|       |      //  We process the last segment separately:
15156|      0|      if (new_location == std::string_view::npos) {
  ------------------
  |  Branch (15156:11): [True: 0, False: 0]
  ------------------
15157|      0|        std::string_view path_view = input.substr(previous_location);
15158|      0|        if (path_view == "..") {  // The path ends with ..
  ------------------
  |  Branch (15158:13): [True: 0, False: 0]
  ------------------
15159|       |          // e.g., if you receive ".." with an empty path, you go to "/".
15160|      0|          if (path.empty()) {
  ------------------
  |  Branch (15160:15): [True: 0, False: 0]
  ------------------
15161|      0|            path = '/';
15162|      0|            update_base_pathname(path);
15163|      0|            return;
15164|      0|          }
15165|       |          // Fast case where we have nothing to do:
15166|      0|          if (path.back() == '/') {
  ------------------
  |  Branch (15166:15): [True: 0, False: 0]
  ------------------
15167|      0|            update_base_pathname(path);
15168|      0|            return;
15169|      0|          }
15170|       |          // If you have the path "/joe/myfriend",
15171|       |          // then you delete 'myfriend'.
15172|      0|          path.resize(path.rfind('/') + 1);
15173|      0|          update_base_pathname(path);
15174|      0|          return;
15175|      0|        }
15176|      0|        path += '/';
15177|      0|        if (path_view != ".") {
  ------------------
  |  Branch (15177:13): [True: 0, False: 0]
  ------------------
15178|      0|          path.append(path_view);
15179|      0|        }
15180|      0|        update_base_pathname(path);
15181|      0|        return;
15182|      0|      } else {
15183|       |        // This is a non-final segment.
15184|      0|        std::string_view path_view =
15185|      0|            input.substr(previous_location, new_location - previous_location);
15186|      0|        previous_location = new_location + 1;
15187|      0|        if (path_view == "..") {
  ------------------
  |  Branch (15187:13): [True: 0, False: 0]
  ------------------
15188|      0|          size_t last_delimiter = path.rfind('/');
15189|      0|          if (last_delimiter != std::string::npos) {
  ------------------
  |  Branch (15189:15): [True: 0, False: 0]
  ------------------
15190|      0|            path.erase(last_delimiter);
15191|      0|          }
15192|      0|        } else if (path_view != ".") {
  ------------------
  |  Branch (15192:20): [True: 0, False: 0]
  ------------------
15193|      0|          path += '/';
15194|      0|          path.append(path_view);
15195|      0|        }
15196|      0|      }
15197|      0|    } while (true);
  ------------------
  |  Branch (15197:14): [True: 0, Folded]
  ------------------
15198|      0|  } else {
15199|      0|    ada_log("parse_path slow");
15200|       |    // we have reached the general case
15201|      0|    bool needs_percent_encoding = (accumulator & 1);
15202|      0|    std::string path_buffer_tmp;
15203|      0|    do {
15204|      0|      size_t location = (special && (accumulator & 2))
  ------------------
  |  Branch (15204:26): [True: 0, False: 0]
  |  Branch (15204:37): [True: 0, False: 0]
  ------------------
15205|      0|                            ? input.find_first_of("/\\")
15206|      0|                            : input.find('/');
15207|      0|      std::string_view path_view = input;
15208|      0|      if (location != std::string_view::npos) {
  ------------------
  |  Branch (15208:11): [True: 0, False: 0]
  ------------------
15209|      0|        path_view.remove_suffix(path_view.size() - location);
15210|      0|        input.remove_prefix(location + 1);
15211|      0|      }
15212|       |      // path_buffer is either path_view or it might point at a percent encoded
15213|       |      // temporary string.
15214|      0|      std::string_view path_buffer =
15215|      0|          (needs_percent_encoding &&
  ------------------
  |  Branch (15215:12): [True: 0, False: 0]
  ------------------
15216|      0|           ada::unicode::percent_encode<false>(
  ------------------
  |  Branch (15216:12): [True: 0, False: 0]
  ------------------
15217|      0|               path_view, character_sets::PATH_PERCENT_ENCODE, path_buffer_tmp))
15218|      0|              ? path_buffer_tmp
15219|      0|              : path_view;
15220|      0|      if (unicode::is_double_dot_path_segment(path_buffer)) {
  ------------------
  |  Branch (15220:11): [True: 0, False: 0]
  ------------------
15221|      0|        helpers::shorten_path(path, type);
15222|      0|        if (location == std::string_view::npos) {
  ------------------
  |  Branch (15222:13): [True: 0, False: 0]
  ------------------
15223|      0|          path += '/';
15224|      0|        }
15225|      0|      } else if (unicode::is_single_dot_path_segment(path_buffer) &&
  ------------------
  |  Branch (15225:18): [True: 0, False: 0]
  ------------------
15226|      0|                 (location == std::string_view::npos)) {
  ------------------
  |  Branch (15226:18): [True: 0, False: 0]
  ------------------
15227|      0|        path += '/';
15228|      0|      }
15229|       |      // Otherwise, if path_buffer is not a single-dot path segment, then:
15230|      0|      else if (!unicode::is_single_dot_path_segment(path_buffer)) {
  ------------------
  |  Branch (15230:16): [True: 0, False: 0]
  ------------------
15231|       |        // If url's scheme is "file", url's path is empty, and path_buffer is a
15232|       |        // Windows drive letter, then replace the second code point in
15233|       |        // path_buffer with U+003A (:).
15234|      0|        if (type == ada::scheme::type::FILE && path.empty() &&
  ------------------
  |  Branch (15234:13): [True: 0, False: 0]
  |  Branch (15234:48): [True: 0, False: 0]
  ------------------
15235|      0|            checkers::is_windows_drive_letter(path_buffer)) {
  ------------------
  |  Branch (15235:13): [True: 0, False: 0]
  ------------------
15236|      0|          path += '/';
15237|      0|          path += path_buffer[0];
15238|      0|          path += ':';
15239|      0|          path_buffer.remove_prefix(2);
15240|      0|          path.append(path_buffer);
15241|      0|        } else {
15242|       |          // Append path_buffer to url's path.
15243|      0|          path += '/';
15244|      0|          path.append(path_buffer);
15245|      0|        }
15246|      0|      }
15247|      0|      if (location == std::string_view::npos) {
  ------------------
  |  Branch (15247:11): [True: 0, False: 0]
  ------------------
15248|      0|        update_base_pathname(path);
15249|      0|        return;
15250|      0|      }
15251|      0|    } while (true);
  ------------------
  |  Branch (15251:14): [True: 0, Folded]
  ------------------
15252|      0|  }
15253|      0|}
_ZN3ada8checkers7is_ipv4ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
   12|    500|ada_really_inline constexpr bool is_ipv4(std::string_view view) noexcept {
   13|       |  // The string is not empty and does not contain upper case ASCII characters.
   14|    500|  if (!last_label_may_be_a_number(view)) {
  ------------------
  |  Branch (14:7): [True: 500, False: 0]
  ------------------
   15|    500|    return false;
   16|    500|  }
   17|       |  // If the address ends with a dot, we need to prune it (special case).
   18|      0|  if (view.ends_with('.')) {
  ------------------
  |  Branch (18:7): [True: 0, False: 0]
  ------------------
   19|      0|    view.remove_suffix(1);
   20|      0|  }
   21|       |  // From the last character, find the last dot.
   22|      0|  size_t last_dot = view.rfind('.');
   23|      0|  if (last_dot != std::string_view::npos) {
  ------------------
  |  Branch (23:7): [True: 0, False: 0]
  ------------------
   24|       |    // We have at least one dot.
   25|      0|    view.remove_prefix(last_dot + 1);
   26|      0|  }
   27|       |  /** Optimization opportunity: we have basically identified the last number of
   28|       |     the ipv4 if we return true here. We might as well parse it and have at
   29|       |     least one number parsed when we get to parse_ipv4. */
   30|      0|  if (std::ranges::all_of(view, ada::checkers::is_digit)) {
  ------------------
  |  Branch (30:7): [True: 0, False: 0]
  ------------------
   31|      0|    return true;
   32|      0|  }
   33|       |  // It could be hex (0x), but not if there is a single character.
   34|      0|  if (view.size() == 1) {
  ------------------
  |  Branch (34:7): [True: 0, False: 0]
  ------------------
   35|      0|    return false;
   36|      0|  }
   37|       |  // It must start with 0x.
   38|      0|  if (!view.starts_with("0x")) {
  ------------------
  |  Branch (38:7): [True: 0, False: 0]
  ------------------
   39|      0|    return false;
   40|      0|  }
   41|       |  // We must allow "0x".
   42|      0|  if (view.size() == 2) {
  ------------------
  |  Branch (42:7): [True: 0, False: 0]
  ------------------
   43|      0|    return true;
   44|      0|  }
   45|       |  // We have 0x followed by some characters, we need to check that they are
   46|       |  // hexadecimals.
   47|      0|  view.remove_prefix(2);
   48|      0|  return std::ranges::all_of(view, ada::unicode::is_lowercase_hex);
   49|      0|}
_ZN3ada14url_aggregator23parse_scheme_with_colonILb0EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE:
13655|    500|    const std::string_view input_with_colon) {
13656|    500|  ada_log("url_aggregator::parse_scheme_with_colon ", input_with_colon);
13657|    500|  ADA_ASSERT_TRUE(validate());
13658|    500|  ADA_ASSERT_TRUE(!helpers::overlaps(input_with_colon, buffer));
13659|    500|  std::string_view input{input_with_colon};
13660|    500|  input.remove_suffix(1);
13661|    500|  auto parsed_type = ada::scheme::get_scheme_type(input);
13662|    500|  const bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL);
13663|       |  /**
13664|       |   * In the common case, we will immediately recognize a special scheme (e.g.,
13665|       |   *http, https), in which case, we can go really fast.
13666|       |   **/
13667|    500|  if (is_input_special) {  // fast path!!!
  ------------------
  |  Branch (13667:7): [True: 500, False: 0]
  ------------------
13668|       |    if constexpr (has_state_override) {
13669|       |      // If url's scheme is not a special scheme and buffer is a special scheme,
13670|       |      // then return.
13671|       |      if (is_special() != is_input_special) {
13672|       |        return false;
13673|       |      }
13674|       |
13675|       |      // If url includes credentials or has a non-null port, and buffer is
13676|       |      // "file", then return.
13677|       |      if ((has_credentials() || components.port != url_components::omitted) &&
13678|       |          parsed_type == ada::scheme::type::FILE) {
13679|       |        return false;
13680|       |      }
13681|       |
13682|       |      // If url's scheme is "file" and its host is an empty host, then return.
13683|       |      // An empty host is the empty string.
13684|       |      if (type == ada::scheme::type::FILE &&
13685|       |          components.host_start == components.host_end) {
13686|       |        return false;
13687|       |      }
13688|       |    }
13689|       |
13690|    500|    type = parsed_type;
13691|    500|    set_scheme_from_view_with_colon(input_with_colon);
13692|       |
13693|       |    if constexpr (has_state_override) {
13694|       |      // This is uncommon.
13695|       |      uint16_t urls_scheme_port = get_special_port();
13696|       |
13697|       |      if (urls_scheme_port) {
13698|       |        // If url's port is url's scheme's default port, then set url's port to
13699|       |        // null.
13700|       |        if (components.port == urls_scheme_port) {
13701|       |          clear_port();
13702|       |        }
13703|       |      }
13704|       |    }
13705|    500|  } else {  // slow path
13706|      0|    std::string _buffer(input);
13707|       |    // Next function is only valid if the input is ASCII and returns false
13708|       |    // otherwise, but it seems that we always have ascii content so we do not
13709|       |    // need to check the return value.
13710|      0|    unicode::to_lower_ascii(_buffer.data(), _buffer.size());
13711|       |
13712|       |    if constexpr (has_state_override) {
13713|       |      // The state-override validation errors below ("return" in the WHATWG URL
13714|       |      // parser) leave the URL unchanged. The setter contract is
13715|       |      // "true on success, false if the scheme is invalid" -- the fast path
13716|       |      // above already returns false here, so the slow path must agree.
13717|       |
13718|       |      // If url's scheme is a special scheme and buffer is not a special scheme,
13719|       |      // then return. If url's scheme is not a special scheme and buffer is a
13720|       |      // special scheme, then return.
13721|       |      if (is_special() != ada::scheme::is_special(_buffer)) {
13722|       |        return false;
13723|       |      }
13724|       |
13725|       |      // If url includes credentials or has a non-null port, and buffer is
13726|       |      // "file", then return.
13727|       |      if ((has_credentials() || components.port != url_components::omitted) &&
13728|       |          _buffer == "file") {
13729|       |        return false;
13730|       |      }
13731|       |
13732|       |      // If url's scheme is "file" and its host is an empty host, then return.
13733|       |      // An empty host is the empty string.
13734|       |      if (type == ada::scheme::type::FILE &&
13735|       |          components.host_start == components.host_end) {
13736|       |        return false;
13737|       |      }
13738|       |    }
13739|       |
13740|      0|    set_scheme(_buffer);
13741|       |
13742|       |    if constexpr (has_state_override) {
13743|       |      // This is uncommon.
13744|       |      uint16_t urls_scheme_port = get_special_port();
13745|       |
13746|       |      if (urls_scheme_port) {
13747|       |        // If url's port is url's scheme's default port, then set url's port to
13748|       |        // null.
13749|       |        if (components.port == urls_scheme_port) {
13750|       |          clear_port();
13751|       |        }
13752|       |      }
13753|       |    }
13754|      0|  }
13755|    500|  ADA_ASSERT_TRUE(validate());
13756|    500|  return true;
13757|    500|}
_ZN3ada14url_aggregator31set_scheme_from_view_with_colonENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13781|    500|    std::string_view new_scheme_with_colon) {
13782|    500|  ada_log("url_aggregator::set_scheme_from_view_with_colon ",
13783|    500|          new_scheme_with_colon);
13784|    500|  ADA_ASSERT_TRUE(validate());
13785|    500|  ADA_ASSERT_TRUE(!new_scheme_with_colon.empty() &&
13786|    500|                  new_scheme_with_colon.back() == ':');
13787|       |  // next line could overflow but unsigned arithmetic has well-defined
13788|       |  // overflows.
13789|    500|  uint32_t new_difference =
13790|    500|      uint32_t(new_scheme_with_colon.size()) - components.protocol_end;
13791|       |
13792|    500|  if (buffer.empty()) {
  ------------------
  |  Branch (13792:7): [True: 500, False: 0]
  ------------------
13793|    500|    buffer.append(new_scheme_with_colon);
13794|    500|  } else {
13795|      0|    buffer.erase(0, components.protocol_end);
13796|      0|    buffer.insert(0, new_scheme_with_colon);
13797|      0|  }
13798|    500|  components.protocol_end += new_difference;
13799|       |
13800|    500|  apply_shifted_non_scheme_offsets(components, new_difference);
13801|    500|  ADA_ASSERT_TRUE(validate());
13802|    500|}
_ZN3ada7helpers38strip_trailing_spaces_from_opaque_pathINS_14url_aggregatorEEEvRT_:
 9427|  1.44k|ada_really_inline void strip_trailing_spaces_from_opaque_path(url_type& url) {
 9428|  1.44k|  ada_log("helpers::strip_trailing_spaces_from_opaque_path");
 9429|  1.44k|  if (!url.has_opaque_path) return;
  ------------------
  |  Branch (9429:7): [True: 1.44k, False: 0]
  ------------------
 9430|      0|  if (url.has_hash()) return;
  ------------------
  |  Branch (9430:7): [True: 0, False: 0]
  ------------------
 9431|      0|  if (url.has_search()) return;
  ------------------
  |  Branch (9431:7): [True: 0, False: 0]
  ------------------
 9432|       |
 9433|      0|  auto path = std::string(url.get_pathname());
 9434|      0|  while (!path.empty() && path.back() == ' ') {
  ------------------
  |  Branch (9434:10): [True: 0, False: 0]
  |  Branch (9434:27): [True: 0, False: 0]
  ------------------
 9435|      0|    path.resize(path.size() - 1);
 9436|      0|  }
 9437|      0|  url.update_base_pathname(path);
 9438|      0|}

_ZN3ada37url_pattern_compile_component_optionsC2ENSt3__18optionalIcEES3_:
 5755|      6|      : delimiter(new_delimiter), prefix(new_prefix) {}
_ZN3ada14character_sets6bit_atEPKhh:
 1074|   472k|ada_really_inline constexpr bool bit_at(const uint8_t a[], const uint8_t i) {
 1075|   472k|  return !!(a[i >> 3] & (1 << (i & 7)));
 1076|   472k|}
_ZN3ada8url_baseD2Ev:
 1693|  6.10k|  virtual ~url_base() = default;
_ZN2tl6detail26expected_default_ctor_baseIN3ada14url_aggregatorENS2_6errorsELb1EEC2ENS0_23default_constructor_tagE:
 3279|  3.05k|  constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEC2IS2_TnPNSt3__19enable_ifIXsr3std14is_convertibleIOT_S2_EE5valueEvE4typeELPv0ETnPNS7_IXaaaaaasr3std16is_constructibleIS2_S9_EE5valuentsr3std7is_sameINS6_5decayIS8_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameIS4_SG_EE5valuentsr3std7is_sameINS_10unexpectedIS3_EESG_EE5valueEvE4typeELSD_0EEES9_:
 3761|  3.05k|      : expected(in_place, std::forward<U>(v)) {}
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEC2IJS2_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS2_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESA_:
 3634|  3.05k|      : impl_base(in_place, std::forward<Args>(args)...),
 3635|  3.05k|        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl6detail21expected_storage_baseIN3ada14url_aggregatorENS2_6errorsELb0ELb1EEC2IJS3_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESB_:
 2649|  3.05k|      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
_ZN3ada14url_aggregatorC2EOS0_:
 7774|  3.05k|  url_aggregator(url_aggregator&& u) noexcept = default;
_ZN3ada14url_aggregatorD2Ev:
 7777|  6.10k|  ~url_aggregator() override = default;
_ZN3ada6scheme15get_scheme_typeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6789|    500|constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept {
 6790|    500|  if (scheme.empty()) {
  ------------------
  |  Branch (6790:7): [True: 0, False: 500]
  ------------------
 6791|      0|    return ada::scheme::NOT_SPECIAL;
 6792|      0|  }
 6793|    500|  int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
 6794|    500|  const std::string_view target = details::is_special_list[hash_value];
 6795|    500|  if (scheme.size() == target.size() &&
  ------------------
  |  Branch (6795:7): [True: 500, False: 0]
  ------------------
 6796|    500|      details::branchless_load5(scheme.data(), scheme.size()) ==
  ------------------
  |  Branch (6796:7): [True: 500, False: 0]
  ------------------
 6797|    500|          details::scheme_keys[hash_value]) {
 6798|    500|    return ada::scheme::type(hash_value);
 6799|    500|  } else {
 6800|      0|    return ada::scheme::NOT_SPECIAL;
 6801|      0|  }
 6802|    500|}
_ZN3ada6scheme7details16branchless_load5EPKcm:
 6730|    500|inline uint64_t branchless_load5(const char* p, size_t n) {
 6731|    500|  uint64_t input = (uint8_t)p[0];
 6732|    500|  input |= ((uint64_t)(uint8_t)p[n > 1] << 8) & (0 - (uint64_t)(n > 1));
 6733|    500|  input |= ((uint64_t)(uint8_t)p[(n > 2) * 2] << 16) & (0 - (uint64_t)(n > 2));
 6734|    500|  input |= ((uint64_t)(uint8_t)p[(n > 3) * 3] << 24) & (0 - (uint64_t)(n > 3));
 6735|    500|  input |= ((uint64_t)(uint8_t)p[(n > 4) * 4] << 32) & (0 - (uint64_t)(n > 4));
 6736|    500|  return input;
 6737|    500|}
_ZN3ada14url_aggregatorC2Ev:
 7772|  3.05k|  url_aggregator() = default;
_ZN3ada14url_componentsC2Ev:
 4952|  3.05k|  url_components() = default;
_ZN3ada8checkers19try_parse_ipv4_fastENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 1446|    500|try_parse_ipv4_fast(std::string_view input) noexcept {
 1447|    500|  const size_t len = input.size();
 1448|       |  // Shortest pure decimal: "0.0.0.0" (7). Longest + trailing dot: 16.
 1449|    500|  if (len < 7 || len > 16) [[unlikely]] {
  ------------------
  |  Branch (1449:7): [True: 0, False: 500]
  |  Branch (1449:18): [True: 0, False: 500]
  ------------------
 1450|      0|    return ipv4_fast_fail;
 1451|      0|  }
 1452|    500|  const char* data = input.data();
 1453|       |
 1454|       |#if defined(ADA_AVX512) && defined(__AVX512VBMI2__)
 1455|       |  return detail::try_parse_ipv4_avx512(data, len);
 1456|       |#else
 1457|    500|  return detail::parse_ipv4_decimal_scalar(data, data + len);
 1458|    500|#endif
 1459|    500|}
_ZN3ada8checkers6detail25parse_ipv4_decimal_scalarEPKcS3_:
 1287|    500|parse_ipv4_decimal_scalar(const char* p, const char* pend) noexcept {
 1288|    500|  uint32_t ipv4 = 0;
 1289|    500|  for (int i = 0; i < 4; ++i) {
  ------------------
  |  Branch (1289:19): [True: 500, False: 0]
  ------------------
 1290|    500|    if (p == pend) [[unlikely]] {
  ------------------
  |  Branch (1290:9): [True: 0, False: 500]
  ------------------
 1291|      0|      return ipv4_fast_fail;
 1292|      0|    }
 1293|    500|    uint32_t val;
 1294|    500|    char c = *p;
 1295|    500|    if (c >= '0' && c <= '9') [[likely]] {
  ------------------
  |  Branch (1295:9): [True: 500, False: 0]
  |  Branch (1295:21): [True: 0, False: 500]
  ------------------
 1296|      0|      val = static_cast<uint32_t>(c - '0');
 1297|      0|      ++p;
 1298|    500|    } else {
 1299|    500|      return ipv4_fast_fail;
 1300|    500|    }
 1301|      0|    if (p < pend) {
  ------------------
  |  Branch (1301:9): [True: 0, False: 0]
  ------------------
 1302|      0|      c = *p;
 1303|      0|      if (c >= '0' && c <= '9') {
  ------------------
  |  Branch (1303:11): [True: 0, False: 0]
  |  Branch (1303:23): [True: 0, False: 0]
  ------------------
 1304|      0|        if (val == 0) [[unlikely]] {
  ------------------
  |  Branch (1304:13): [True: 0, False: 0]
  ------------------
 1305|      0|          return ipv4_fast_fail;
 1306|      0|        }
 1307|      0|        val = val * 10u + static_cast<uint32_t>(c - '0');
 1308|      0|        ++p;
 1309|      0|        if (p < pend) {
  ------------------
  |  Branch (1309:13): [True: 0, False: 0]
  ------------------
 1310|      0|          c = *p;
 1311|      0|          if (c >= '0' && c <= '9') {
  ------------------
  |  Branch (1311:15): [True: 0, False: 0]
  |  Branch (1311:27): [True: 0, False: 0]
  ------------------
 1312|      0|            val = val * 10u + static_cast<uint32_t>(c - '0');
 1313|      0|            ++p;
 1314|      0|            if (val > 255u) [[unlikely]] {
  ------------------
  |  Branch (1314:17): [True: 0, False: 0]
  ------------------
 1315|      0|              return ipv4_fast_fail;
 1316|      0|            }
 1317|      0|          }
 1318|      0|        }
 1319|      0|      }
 1320|      0|    }
 1321|      0|    ipv4 = (ipv4 << 8) | val;
 1322|      0|    if (i < 3) {
  ------------------
  |  Branch (1322:9): [True: 0, False: 0]
  ------------------
 1323|      0|      if (p == pend || *p != '.') [[unlikely]] {
  ------------------
  |  Branch (1323:11): [True: 0, False: 0]
  |  Branch (1323:24): [True: 0, False: 0]
  ------------------
 1324|      0|        return ipv4_fast_fail;
 1325|      0|      }
 1326|      0|      ++p;
 1327|      0|    }
 1328|      0|  }
 1329|      0|  if (p != pend) {
  ------------------
  |  Branch (1329:7): [True: 0, False: 0]
  ------------------
 1330|      0|    if (p == pend - 1 && *p == '.') {
  ------------------
  |  Branch (1330:9): [True: 0, False: 0]
  |  Branch (1330:26): [True: 0, False: 0]
  ------------------
 1331|      0|      return ipv4;
 1332|      0|    }
 1333|      0|    return ipv4_fast_fail;
 1334|      0|  }
 1335|      0|  return ipv4;
 1336|      0|}
_ZNK3ada8url_base10is_specialEv:
 7272|  5.72k|    const noexcept {
 7273|  5.72k|  return type != ada::scheme::NOT_SPECIAL;
 7274|  5.72k|}
_ZN3ada8checkers8is_alphaEc:
 1267|    500|constexpr bool is_alpha(char x) noexcept {
 1268|    500|  return (to_lower(x) >= 'a') && (to_lower(x) <= 'z');
  ------------------
  |  Branch (1268:10): [True: 500, False: 0]
  |  Branch (1268:34): [True: 500, False: 0]
  ------------------
 1269|    500|}
_ZN3ada8checkers8to_lowerEc:
 1265|  1.00k|constexpr char to_lower(char x) noexcept { return (x | 0x20); }
_ZN3ada8checkers26last_label_may_be_a_numberENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 1240|  3.55k|constexpr bool last_label_may_be_a_number(std::string_view view) noexcept {
 1241|  3.55k|  if (view.empty()) {
  ------------------
  |  Branch (1241:7): [True: 0, False: 3.55k]
  ------------------
 1242|      0|    return false;
 1243|      0|  }
 1244|  3.55k|  const char* start = view.data();
 1245|  3.55k|  const char* end = start + view.size();
 1246|  3.55k|  if (end[-1] == '.') {
  ------------------
  |  Branch (1246:7): [True: 0, False: 3.55k]
  ------------------
 1247|      0|    --end;
 1248|      0|    if (end == start) {
  ------------------
  |  Branch (1248:9): [True: 0, False: 0]
  ------------------
 1249|      0|      return false;
 1250|      0|    }
 1251|      0|  }
 1252|  3.55k|  if (!is_ipv4_number_char(end[-1])) {
  ------------------
  |  Branch (1252:7): [True: 3.55k, False: 0]
  ------------------
 1253|  3.55k|    return false;
 1254|  3.55k|  }
 1255|      0|  const char* label = end;
 1256|      0|  while (label != start && is_ipv4_number_char(label[-1])) {
  ------------------
  |  Branch (1256:10): [True: 0, False: 0]
  |  Branch (1256:28): [True: 0, False: 0]
  ------------------
 1257|      0|    --label;
 1258|      0|  }
 1259|      0|  if (label != start && label[-1] != '.') {
  ------------------
  |  Branch (1259:7): [True: 0, False: 0]
  |  Branch (1259:25): [True: 0, False: 0]
  ------------------
 1260|      0|    return false;
 1261|      0|  }
 1262|      0|  return label != end && is_digit(*label);
  ------------------
  |  Branch (1262:10): [True: 0, False: 0]
  |  Branch (1262:26): [True: 0, False: 0]
  ------------------
 1263|      0|}
_ZN3ada8checkers19is_ipv4_number_charEc:
 1234|  3.55k|constexpr bool is_ipv4_number_char(char x) noexcept {
 1235|  3.55k|  const unsigned char c = static_cast<unsigned char>(x);
 1236|  3.55k|  return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
  ------------------
  |  Branch (1236:11): [True: 3.55k, False: 0]
  |  Branch (1236:23): [True: 0, False: 3.55k]
  |  Branch (1236:37): [True: 3.55k, False: 0]
  |  Branch (1236:49): [True: 0, False: 3.55k]
  ------------------
 1237|  3.55k|         (c >= 'A' && c <= 'F') || c == 'x' || c == 'X';
  ------------------
  |  Branch (1237:11): [True: 3.55k, False: 0]
  |  Branch (1237:23): [True: 0, False: 3.55k]
  |  Branch (1237:36): [True: 0, False: 3.55k]
  |  Branch (1237:48): [True: 0, False: 3.55k]
  ------------------
 1238|  3.55k|}
_ZN3ada14url_aggregator18replace_and_resizeEjjNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8339|    761|    uint32_t start, uint32_t end, std::string_view input) {
 8340|    761|  uint32_t current_length = end - start;
 8341|    761|  uint32_t input_size = uint32_t(input.size());
 8342|    761|  uint32_t new_difference = input_size - current_length;
 8343|       |
 8344|    761|  if (current_length == 0) {
  ------------------
  |  Branch (8344:7): [True: 500, False: 261]
  ------------------
 8345|    500|    buffer.insert(start, input);
 8346|    500|  } else if (input_size == current_length) {
  ------------------
  |  Branch (8346:14): [True: 10, False: 251]
  ------------------
 8347|     10|    if (input_size != 0) {
  ------------------
  |  Branch (8347:9): [True: 10, False: 0]
  ------------------
 8348|     10|      std::memmove(buffer.data() + start, input.data(), input_size);
 8349|     10|    }
 8350|    251|  } else if (input_size < current_length) {
  ------------------
  |  Branch (8350:14): [True: 53, False: 198]
  ------------------
 8351|     53|    buffer.erase(start, current_length - input_size);
 8352|     53|    buffer.replace(start, input_size, input);
 8353|    198|  } else {
 8354|    198|    buffer.replace(start, current_length, input.substr(0, current_length));
 8355|    198|    buffer.insert(start + current_length, input.substr(current_length));
 8356|    198|  }
 8357|       |
 8358|    761|  return new_difference;
 8359|    761|}
_ZN3ada14url_aggregator26update_unencoded_base_hashENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8315|    392|inline void url_aggregator::update_unencoded_base_hash(std::string_view input) {
 8316|    392|  ada_log("url_aggregator::update_unencoded_base_hash ", input, " [",
 8317|    392|          input.size(), " bytes], buffer is '", buffer, "' [", buffer.size(),
 8318|    392|          " bytes] components.hash_start = ", components.hash_start);
 8319|    392|  ADA_ASSERT_TRUE(validate());
 8320|    392|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 8321|    392|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8321:7): [True: 0, False: 392]
  ------------------
 8322|      0|    buffer.resize(components.hash_start);
 8323|      0|  }
 8324|    392|  components.hash_start = uint32_t(buffer.size());
 8325|    392|  buffer += "#";
 8326|    392|  bool encoding_required = unicode::percent_encode<true>(
 8327|    392|      input, ada::character_sets::FRAGMENT_PERCENT_ENCODE, buffer);
 8328|       |  // When encoding_required is false, then buffer is left unchanged, and percent
 8329|       |  // encoding was not deemed required.
 8330|    392|  if (!encoding_required) {
  ------------------
  |  Branch (8330:7): [True: 146, False: 246]
  ------------------
 8331|    146|    buffer.append(input);
 8332|    146|  }
 8333|    392|  ada_log("url_aggregator::update_unencoded_base_hash final buffer is '",
 8334|    392|          buffer, "' [", buffer.size(), " bytes]");
 8335|    392|  ADA_ASSERT_TRUE(validate());
 8336|    392|}
_ZN3ada7helpers14leading_zeroesEj:
 1978|    500|inline int leading_zeroes(uint32_t input_num) noexcept {
 1979|       |#if ADA_REGULAR_VISUAL_STUDIO
 1980|       |  unsigned long leading_zero(0);
 1981|       |  unsigned long in(input_num);
 1982|       |  return _BitScanReverse(&leading_zero, in) ? int(31 - leading_zero) : 32;
 1983|       |#else
 1984|    500|  return __builtin_clz(input_num);
 1985|    500|#endif  // ADA_REGULAR_VISUAL_STUDIO
 1986|    500|}
_ZN3ada14url_aggregator7reserveEj:
 9005|    500|constexpr void ada::url_aggregator::reserve(uint32_t capacity) {
 9006|    500|  buffer.reserve(capacity);
 9007|    500|}
_ZN3ada14url_aggregator31add_authority_slashes_if_neededEv:
 8979|    500|inline void ada::url_aggregator::add_authority_slashes_if_needed() {
 8980|    500|  ada_log("url_aggregator::add_authority_slashes_if_needed");
 8981|    500|  ADA_ASSERT_TRUE(validate());
 8982|       |  // Protocol setter will insert `http:` to the URL. It is up to hostname setter
 8983|       |  // to insert
 8984|       |  // `//` initially to the buffer, since it depends on the hostname existence.
 8985|    500|  if (has_authority()) {
  ------------------
  |  Branch (8985:7): [True: 0, False: 500]
  ------------------
 8986|      0|    return;
 8987|      0|  }
 8988|       |  // Performance: the common case is components.protocol_end == buffer.size()
 8989|       |  // Optimization opportunity: in many cases, the "//" is part of the input and
 8990|       |  // the insert could be fused with another insert.
 8991|    500|  buffer.insert(components.protocol_end, "//");
 8992|    500|  components.username_end += 2;
 8993|    500|  components.host_start += 2;
 8994|    500|  components.host_end += 2;
 8995|    500|  components.pathname_start += 2;
 8996|    500|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (8996:7): [True: 0, False: 500]
  ------------------
 8997|      0|    components.search_start += 2;
 8998|      0|  }
 8999|    500|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8999:7): [True: 0, False: 500]
  ------------------
 9000|      0|    components.hash_start += 2;
 9001|      0|  }
 9002|    500|  ADA_ASSERT_TRUE(validate());
 9003|    500|}
_ZN3ada14url_aggregator12clear_searchEv:
 8829|  1.44k|inline void url_aggregator::clear_search() {
 8830|  1.44k|  ada_log("url_aggregator::clear_search");
 8831|  1.44k|  ADA_ASSERT_TRUE(validate());
 8832|  1.44k|  if (components.search_start == url_components::omitted) {
  ------------------
  |  Branch (8832:7): [True: 0, False: 1.44k]
  ------------------
 8833|      0|    return;
 8834|      0|  }
 8835|       |
 8836|  1.44k|  if (components.hash_start == url_components::omitted) {
  ------------------
  |  Branch (8836:7): [True: 1.21k, False: 231]
  ------------------
 8837|  1.21k|    buffer.resize(components.search_start);
 8838|  1.21k|  } else {
 8839|    231|    buffer.erase(components.search_start,
 8840|    231|                 components.hash_start - components.search_start);
 8841|    231|    components.hash_start = components.search_start;
 8842|    231|  }
 8843|       |
 8844|  1.44k|  components.search_start = url_components::omitted;
 8845|       |
 8846|       |#if ADA_DEVELOPMENT_CHECKS
 8847|       |  ADA_ASSERT_EQUAL(get_search(), "",
 8848|       |                   "search should have been cleared on buffer=" + buffer +
 8849|       |                       " with " + components.to_string() + "\n" + to_diagram());
 8850|       |#endif
 8851|  1.44k|  ADA_ASSERT_TRUE(validate());
 8852|  1.44k|}
_ZN3ada14url_aggregator18update_base_searchENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKh:
 8446|  3.17k|    std::string_view input, const uint8_t query_percent_encode_set[]) {
 8447|  3.17k|  ada_log("url_aggregator::update_base_search ", input,
 8448|  3.17k|          " with encoding parameter ", to_string(), "\n", to_diagram());
 8449|  3.17k|  ADA_ASSERT_TRUE(validate());
 8450|  3.17k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 8451|       |
 8452|  3.17k|  if (components.hash_start == url_components::omitted) {
  ------------------
  |  Branch (8452:7): [True: 2.91k, False: 261]
  ------------------
 8453|  2.91k|    if (components.search_start == url_components::omitted) {
  ------------------
  |  Branch (8453:9): [True: 1.56k, False: 1.34k]
  ------------------
 8454|  1.56k|      components.search_start = uint32_t(buffer.size());
 8455|  1.56k|      buffer += "?";
 8456|  1.56k|    } else {
 8457|  1.34k|      buffer.resize(components.search_start + 1);
 8458|  1.34k|    }
 8459|       |
 8460|  2.91k|    bool encoding_required =
 8461|  2.91k|        unicode::percent_encode<true>(input, query_percent_encode_set, buffer);
 8462|       |    // When encoding_required is false, then buffer is left unchanged, and
 8463|       |    // percent encoding was not deemed required.
 8464|  2.91k|    if (!encoding_required) {
  ------------------
  |  Branch (8464:9): [True: 1.72k, False: 1.18k]
  ------------------
 8465|  1.72k|      buffer.append(input);
 8466|  1.72k|    }
 8467|  2.91k|  } else {
 8468|    261|    const size_t idx =
 8469|    261|        ada::unicode::percent_encode_index(input, query_percent_encode_set);
 8470|    261|    std::string encoded;
 8471|    261|    std::string_view replacement = input;
 8472|    261|    if (idx != input.size()) {
  ------------------
  |  Branch (8472:9): [True: 0, False: 261]
  ------------------
 8473|      0|      encoded =
 8474|      0|          ada::unicode::percent_encode(input, query_percent_encode_set, idx);
 8475|      0|      replacement = encoded;
 8476|      0|    }
 8477|       |
 8478|    261|    if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (8478:9): [True: 261, False: 0]
  ------------------
 8479|    261|      const uint32_t difference = replace_and_resize(
 8480|    261|          components.search_start + 1, components.hash_start, replacement);
 8481|    261|      components.hash_start += difference;
 8482|    261|    } else {
 8483|      0|      components.search_start = components.hash_start;
 8484|      0|      buffer.insert(components.search_start, replacement.size() + 1, '?');
 8485|      0|      if (!replacement.empty()) {
  ------------------
  |  Branch (8485:11): [True: 0, False: 0]
  ------------------
 8486|      0|        std::memmove(buffer.data() + components.search_start + 1,
 8487|      0|                     replacement.data(), replacement.size());
 8488|      0|      }
 8489|      0|      components.hash_start +=
 8490|      0|          uint32_t(replacement.size() + 1);  // Do not forget `?`
 8491|      0|    }
 8492|    261|  }
 8493|       |
 8494|  3.17k|  ADA_ASSERT_TRUE(validate());
 8495|  3.17k|}
_ZN3ada14url_aggregator20update_base_hostnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8361|    500|inline void url_aggregator::update_base_hostname(const std::string_view input) {
 8362|    500|  ada_log("url_aggregator::update_base_hostname ", input, " [", input.size(),
 8363|    500|          " bytes], buffer is '", buffer, "' [", buffer.size(), " bytes]");
 8364|    500|  ADA_ASSERT_TRUE(validate());
 8365|    500|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 8366|       |
 8367|       |  // This next line is required for when parsing a URL like `foo://`
 8368|    500|  add_authority_slashes_if_needed();
 8369|       |
 8370|    500|  bool has_credentials = components.protocol_end + 2 < components.host_start;
 8371|    500|  uint32_t new_difference =
 8372|    500|      replace_and_resize(components.host_start, components.host_end, input);
 8373|       |
 8374|    500|  if (has_credentials) {
  ------------------
  |  Branch (8374:7): [True: 0, False: 500]
  ------------------
 8375|      0|    buffer.insert(components.host_start, "@");
 8376|      0|    new_difference++;
 8377|      0|  }
 8378|    500|  components.host_end += new_difference;
 8379|    500|  components.pathname_start += new_difference;
 8380|    500|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (8380:7): [True: 0, False: 500]
  ------------------
 8381|      0|    components.search_start += new_difference;
 8382|      0|  }
 8383|    500|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8383:7): [True: 0, False: 500]
  ------------------
 8384|      0|    components.hash_start += new_difference;
 8385|      0|  }
 8386|    500|  ADA_ASSERT_TRUE(validate());
 8387|    500|}
_ZN3ada7unicode20percent_encode_indexENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKh:
 8216|    261|                                              const uint8_t character_set[]) {
 8217|    261|  const char* data = input.data();
 8218|    261|  const size_t size = input.size();
 8219|       |
 8220|       |  // Process 8 bytes at a time using unrolled loop
 8221|    261|  size_t i = 0;
 8222|  4.05k|  for (; i + 8 <= size; i += 8) {
  ------------------
  |  Branch (8222:10): [True: 3.79k, False: 261]
  ------------------
 8223|  3.79k|    unsigned char chunk[8];
 8224|  3.79k|    std::memcpy(&chunk, data + i,
 8225|  3.79k|                8);  // entices compiler to unconditionally process 8 characters
 8226|       |
 8227|       |    // Check 8 characters at once
 8228|  34.1k|    for (size_t j = 0; j < 8; j++) {
  ------------------
  |  Branch (8228:24): [True: 30.3k, False: 3.79k]
  ------------------
 8229|  30.3k|      if (character_sets::bit_at(character_set, chunk[j])) {
  ------------------
  |  Branch (8229:11): [True: 0, False: 30.3k]
  ------------------
 8230|      0|        return i + j;
 8231|      0|      }
 8232|  30.3k|    }
 8233|  3.79k|  }
 8234|       |
 8235|       |  // Handle remaining bytes
 8236|  1.17k|  for (; i < size; i++) {
  ------------------
  |  Branch (8236:10): [True: 915, False: 261]
  ------------------
 8237|    915|    if (character_sets::bit_at(character_set, data[i])) {
  ------------------
  |  Branch (8237:9): [True: 0, False: 915]
  ------------------
 8238|      0|      return i;
 8239|      0|    }
 8240|    915|  }
 8241|       |
 8242|    261|  return size;
 8243|    261|}
_ZNK3ada14url_aggregator13has_authorityEv:
 8970|    500|    const noexcept {
 8971|    500|  ada_log("url_aggregator::has_authority");
 8972|       |  // Performance: instead of doing this potentially expensive check, we could
 8973|       |  // have a boolean in the struct.
 8974|    500|  return components.protocol_end + 2 <= components.host_start &&
  ------------------
  |  Branch (8974:10): [True: 0, False: 500]
  ------------------
 8975|      0|         buffer[components.protocol_end] == '/' &&
  ------------------
  |  Branch (8975:10): [True: 0, False: 0]
  ------------------
 8976|      0|         buffer[components.protocol_end + 1] == '/';
  ------------------
  |  Branch (8976:10): [True: 0, False: 0]
  ------------------
 8977|    500|}
_ZNK2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEcvbEv:
 4074|  3.05k|  constexpr explicit operator bool() const noexcept { return this->m_has_val; }
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEptEv:
 4043|  9.16k|  TL_EXPECTED_11_CONSTEXPR T* operator->() {
 4044|  9.16k|    TL_ASSERT(has_value());
  ------------------
  |  | 2096|  9.16k|#define TL_ASSERT(x) assert(x)
  ------------------
  |  Branch (4044:5): [True: 9.16k, False: 0]
  ------------------
 4045|  9.16k|    return valptr();
 4046|  9.16k|  }
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEE6valptrEv:
 3339|  9.16k|  T* valptr() { return std::addressof(this->m_val); }
_ZNK2tl8expectedIN3ada14url_aggregatorENS1_6errorsEE9has_valueEv:
 4073|  9.16k|  constexpr bool has_value() const noexcept { return this->m_has_val; }
_ZN2tl6detail21expected_storage_baseIN3ada14url_aggregatorENS2_6errorsELb0ELb1EED2Ev:
 2671|  3.05k|  ~expected_storage_base() {
 2672|  3.05k|    if (m_has_val) {
  ------------------
  |  Branch (2672:9): [True: 3.05k, False: 0]
  ------------------
 2673|  3.05k|      m_val.~T();
 2674|  3.05k|    }
 2675|  3.05k|  }
_ZN3ada7helpers9substringENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEmm:
 1890|  1.66k|                                                       size_t pos2) {
 1891|       |#if ADA_DEVELOPMENT_CHECKS
 1892|       |  if (pos2 < pos1) {
 1893|       |    std::cerr << "Negative-length substring: [" << pos1 << " to " << pos2 << ")"
 1894|       |              << std::endl;
 1895|       |    abort();
 1896|       |  }
 1897|       |#endif
 1898|  1.66k|  return input.substr(pos1, pos2 - pos1);
 1899|  1.66k|}
_ZNK3ada14url_aggregator10is_at_pathEv:
 8402|  1.56k|    const noexcept {
 8403|  1.56k|  return buffer.size() == components.pathname_start;
 8404|  1.56k|}
_ZN3ada17url_search_paramsC2ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9447|  15.2k|  explicit url_search_params(const std::string_view input) {
 9448|  15.2k|    initialize(input);
 9449|  15.2k|  }
_ZN3ada17url_search_params10initializeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9670|  18.3k|inline void url_search_params::initialize(std::string_view input) {
 9671|  18.3k|  if (!input.empty() && input.front() == '?') {
  ------------------
  |  Branch (9671:7): [True: 6.35k, False: 11.9k]
  |  Branch (9671:25): [True: 26, False: 6.32k]
  ------------------
 9672|     26|    input.remove_prefix(1);
 9673|     26|  }
 9674|  18.3k|  if (input.empty()) {
  ------------------
  |  Branch (9674:7): [True: 11.9k, False: 6.33k]
  ------------------
 9675|  11.9k|    return;
 9676|  11.9k|  }
 9677|       |  // Refuse overlong query strings (same process-wide cap as URL parsing).
 9678|  6.33k|  if (input.size() > get_max_input_length()) {
  ------------------
  |  Branch (9678:7): [True: 0, False: 6.33k]
  ------------------
 9679|      0|    return;
 9680|      0|  }
 9681|       |
 9682|  6.33k|  params.reserve(size_t(std::count(input.begin(), input.end(), '&')) + 1);
 9683|       |
 9684|  6.33k|  auto process_key_value = [&](const std::string_view current) {
 9685|  6.33k|    const auto equal = current.find('=');
 9686|  6.33k|    if (equal == std::string_view::npos) {
 9687|  6.33k|      params.emplace_back(unicode::form_urlencoded_decode(current), "");
 9688|  6.33k|    } else {
 9689|  6.33k|      params.emplace_back(
 9690|  6.33k|          unicode::form_urlencoded_decode(current.substr(0, equal)),
 9691|  6.33k|          unicode::form_urlencoded_decode(current.substr(equal + 1)));
 9692|  6.33k|    }
 9693|  6.33k|  };
 9694|       |
 9695|  38.5k|  while (!input.empty()) {
  ------------------
  |  Branch (9695:10): [True: 38.3k, False: 189]
  ------------------
 9696|  38.3k|    const auto ampersand_index = input.find('&');
 9697|       |
 9698|  38.3k|    if (ampersand_index == std::string_view::npos) {
  ------------------
  |  Branch (9698:9): [True: 6.14k, False: 32.2k]
  ------------------
 9699|  6.14k|      if (!input.empty()) {
  ------------------
  |  Branch (9699:11): [True: 6.14k, False: 0]
  ------------------
 9700|  6.14k|        process_key_value(input);
 9701|  6.14k|      }
 9702|  6.14k|      break;
 9703|  32.2k|    } else if (ampersand_index != 0) {
  ------------------
  |  Branch (9703:16): [True: 27.9k, False: 4.28k]
  ------------------
 9704|  27.9k|      process_key_value(input.substr(0, ampersand_index));
 9705|  27.9k|    }
 9706|       |
 9707|  32.2k|    input.remove_prefix(ampersand_index + 1);
 9708|  32.2k|  }
 9709|  6.33k|}
_ZZN3ada17url_search_params10initializeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlS5_E_clES5_:
 9684|  34.0k|  auto process_key_value = [&](const std::string_view current) {
 9685|  34.0k|    const auto equal = current.find('=');
 9686|  34.0k|    if (equal == std::string_view::npos) {
  ------------------
  |  Branch (9686:9): [True: 12.7k, False: 21.3k]
  ------------------
 9687|  12.7k|      params.emplace_back(unicode::form_urlencoded_decode(current), "");
 9688|  21.3k|    } else {
 9689|  21.3k|      params.emplace_back(
 9690|  21.3k|          unicode::form_urlencoded_decode(current.substr(0, equal)),
 9691|  21.3k|          unicode::form_urlencoded_decode(current.substr(equal + 1)));
 9692|  21.3k|    }
 9693|  34.0k|  };
_ZN3ada17url_search_paramsD2Ev:
 9455|  30.5k|  ~url_search_params() = default;
_ZNK3ada17url_search_params9to_stringEv:
 9757|  27.4k|inline std::string url_search_params::to_string() const {
 9758|  27.4k|  auto character_set = ada::character_sets::WWW_FORM_URLENCODED_PERCENT_ENCODE;
 9759|  27.4k|  std::string out{};
 9760|  86.6k|  for (size_t i = 0; i < params.size(); i++) {
  ------------------
  |  Branch (9760:22): [True: 59.1k, False: 27.4k]
  ------------------
 9761|  59.1k|    auto key = ada::unicode::percent_encode(params[i].first, character_set);
 9762|  59.1k|    auto value = ada::unicode::percent_encode(params[i].second, character_set);
 9763|       |
 9764|       |    // Performance optimization: Move this inside percent_encode.
 9765|  59.1k|    std::ranges::replace(key, ' ', '+');
 9766|  59.1k|    std::ranges::replace(value, ' ', '+');
 9767|       |
 9768|  59.1k|    if (i != 0) {
  ------------------
  |  Branch (9768:9): [True: 45.6k, False: 13.5k]
  ------------------
 9769|  45.6k|      out += "&";
 9770|  45.6k|    }
 9771|  59.1k|    out.append(key);
 9772|  59.1k|    out += "=";
 9773|  59.1k|    out.append(value);
 9774|  59.1k|  }
 9775|  27.4k|  return out;
 9776|  27.4k|}
_ZNK3ada17url_search_params4sizeEv:
 9716|  27.4k|inline size_t url_search_params::size() const noexcept { return params.size(); }
_ZN3ada17url_search_params4sortEv:
 9805|  6.10k|inline void url_search_params::sort() {
 9806|       |  // Keys are expected to be valid UTF-8, but percent_decode can produce
 9807|       |  // arbitrary byte sequences. Handle truncated/invalid sequences gracefully.
 9808|  6.10k|  std::ranges::stable_sort(params, [](const key_value_pair& lhs,
 9809|  6.10k|                                      const key_value_pair& rhs) {
 9810|  6.10k|    size_t i = 0, j = 0;
 9811|  6.10k|    uint32_t low_surrogate1 = 0, low_surrogate2 = 0;
 9812|  6.10k|    while ((i < lhs.first.size() || low_surrogate1 != 0) &&
 9813|  6.10k|           (j < rhs.first.size() || low_surrogate2 != 0)) {
 9814|  6.10k|      uint32_t codePoint1 = 0, codePoint2 = 0;
 9815|       |
 9816|  6.10k|      if (low_surrogate1 != 0) {
 9817|  6.10k|        codePoint1 = low_surrogate1;
 9818|  6.10k|        low_surrogate1 = 0;
 9819|  6.10k|      } else {
 9820|  6.10k|        uint8_t c1 = uint8_t(lhs.first[i]);
 9821|  6.10k|        if (c1 > 0x7F && c1 <= 0xDF && i + 1 < lhs.first.size()) {
 9822|  6.10k|          codePoint1 = ((c1 & 0x1F) << 6) | (uint8_t(lhs.first[i + 1]) & 0x3F);
 9823|  6.10k|          i += 2;
 9824|  6.10k|        } else if (c1 > 0xDF && c1 <= 0xEF && i + 2 < lhs.first.size()) {
 9825|  6.10k|          codePoint1 = ((c1 & 0x0F) << 12) |
 9826|  6.10k|                       ((uint8_t(lhs.first[i + 1]) & 0x3F) << 6) |
 9827|  6.10k|                       (uint8_t(lhs.first[i + 2]) & 0x3F);
 9828|  6.10k|          i += 3;
 9829|  6.10k|        } else if (c1 > 0xEF && c1 <= 0xF7 && i + 3 < lhs.first.size()) {
 9830|  6.10k|          codePoint1 = ((c1 & 0x07) << 18) |
 9831|  6.10k|                       ((uint8_t(lhs.first[i + 1]) & 0x3F) << 12) |
 9832|  6.10k|                       ((uint8_t(lhs.first[i + 2]) & 0x3F) << 6) |
 9833|  6.10k|                       (uint8_t(lhs.first[i + 3]) & 0x3F);
 9834|  6.10k|          i += 4;
 9835|       |
 9836|  6.10k|          codePoint1 -= 0x10000;
 9837|  6.10k|          uint16_t high_surrogate = uint16_t(0xD800 + (codePoint1 >> 10));
 9838|  6.10k|          low_surrogate1 = uint16_t(0xDC00 + (codePoint1 & 0x3FF));
 9839|  6.10k|          codePoint1 = high_surrogate;
 9840|  6.10k|        } else {
 9841|       |          // ASCII (c1 <= 0x7F) or truncated/invalid UTF-8: treat as raw byte
 9842|  6.10k|          codePoint1 = c1;
 9843|  6.10k|          i++;
 9844|  6.10k|        }
 9845|  6.10k|      }
 9846|       |
 9847|  6.10k|      if (low_surrogate2 != 0) {
 9848|  6.10k|        codePoint2 = low_surrogate2;
 9849|  6.10k|        low_surrogate2 = 0;
 9850|  6.10k|      } else {
 9851|  6.10k|        uint8_t c2 = uint8_t(rhs.first[j]);
 9852|  6.10k|        if (c2 > 0x7F && c2 <= 0xDF && j + 1 < rhs.first.size()) {
 9853|  6.10k|          codePoint2 = ((c2 & 0x1F) << 6) | (uint8_t(rhs.first[j + 1]) & 0x3F);
 9854|  6.10k|          j += 2;
 9855|  6.10k|        } else if (c2 > 0xDF && c2 <= 0xEF && j + 2 < rhs.first.size()) {
 9856|  6.10k|          codePoint2 = ((c2 & 0x0F) << 12) |
 9857|  6.10k|                       ((uint8_t(rhs.first[j + 1]) & 0x3F) << 6) |
 9858|  6.10k|                       (uint8_t(rhs.first[j + 2]) & 0x3F);
 9859|  6.10k|          j += 3;
 9860|  6.10k|        } else if (c2 > 0xEF && c2 <= 0xF7 && j + 3 < rhs.first.size()) {
 9861|  6.10k|          codePoint2 = ((c2 & 0x07) << 18) |
 9862|  6.10k|                       ((uint8_t(rhs.first[j + 1]) & 0x3F) << 12) |
 9863|  6.10k|                       ((uint8_t(rhs.first[j + 2]) & 0x3F) << 6) |
 9864|  6.10k|                       (uint8_t(rhs.first[j + 3]) & 0x3F);
 9865|  6.10k|          j += 4;
 9866|  6.10k|          codePoint2 -= 0x10000;
 9867|  6.10k|          uint16_t high_surrogate = uint16_t(0xD800 + (codePoint2 >> 10));
 9868|  6.10k|          low_surrogate2 = uint16_t(0xDC00 + (codePoint2 & 0x3FF));
 9869|  6.10k|          codePoint2 = high_surrogate;
 9870|  6.10k|        } else {
 9871|       |          // ASCII (c2 <= 0x7F) or truncated/invalid UTF-8: treat as raw byte
 9872|  6.10k|          codePoint2 = c2;
 9873|  6.10k|          j++;
 9874|  6.10k|        }
 9875|  6.10k|      }
 9876|       |
 9877|  6.10k|      if (codePoint1 != codePoint2) {
 9878|  6.10k|        return (codePoint1 < codePoint2);
 9879|  6.10k|      }
 9880|  6.10k|    }
 9881|  6.10k|    return (j < rhs.first.size() || low_surrogate2 != 0);
 9882|  6.10k|  });
 9883|  6.10k|}
_ZZN3ada17url_search_params4sortEvENKUlRKNSt3__14pairINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES8_EESB_E_clESB_SB_:
 9809|  39.0k|                                      const key_value_pair& rhs) {
 9810|  39.0k|    size_t i = 0, j = 0;
 9811|  39.0k|    uint32_t low_surrogate1 = 0, low_surrogate2 = 0;
 9812|  63.1k|    while ((i < lhs.first.size() || low_surrogate1 != 0) &&
  ------------------
  |  Branch (9812:13): [True: 40.0k, False: 23.1k]
  |  Branch (9812:37): [True: 325, False: 22.8k]
  ------------------
 9813|  40.3k|           (j < rhs.first.size() || low_surrogate2 != 0)) {
  ------------------
  |  Branch (9813:13): [True: 38.1k, False: 2.23k]
  |  Branch (9813:37): [True: 327, False: 1.90k]
  ------------------
 9814|  38.4k|      uint32_t codePoint1 = 0, codePoint2 = 0;
 9815|       |
 9816|  38.4k|      if (low_surrogate1 != 0) {
  ------------------
  |  Branch (9816:11): [True: 1.09k, False: 37.3k]
  ------------------
 9817|  1.09k|        codePoint1 = low_surrogate1;
 9818|  1.09k|        low_surrogate1 = 0;
 9819|  37.3k|      } else {
 9820|  37.3k|        uint8_t c1 = uint8_t(lhs.first[i]);
 9821|  37.3k|        if (c1 > 0x7F && c1 <= 0xDF && i + 1 < lhs.first.size()) {
  ------------------
  |  Branch (9821:13): [True: 12.1k, False: 25.2k]
  |  Branch (9821:26): [True: 5.20k, False: 6.95k]
  |  Branch (9821:40): [True: 1.51k, False: 3.68k]
  ------------------
 9822|  1.51k|          codePoint1 = ((c1 & 0x1F) << 6) | (uint8_t(lhs.first[i + 1]) & 0x3F);
 9823|  1.51k|          i += 2;
 9824|  35.8k|        } else if (c1 > 0xDF && c1 <= 0xEF && i + 2 < lhs.first.size()) {
  ------------------
  |  Branch (9824:20): [True: 6.95k, False: 28.8k]
  |  Branch (9824:33): [True: 1.93k, False: 5.02k]
  |  Branch (9824:47): [True: 1.20k, False: 728]
  ------------------
 9825|  1.20k|          codePoint1 = ((c1 & 0x0F) << 12) |
 9826|  1.20k|                       ((uint8_t(lhs.first[i + 1]) & 0x3F) << 6) |
 9827|  1.20k|                       (uint8_t(lhs.first[i + 2]) & 0x3F);
 9828|  1.20k|          i += 3;
 9829|  34.6k|        } else if (c1 > 0xEF && c1 <= 0xF7 && i + 3 < lhs.first.size()) {
  ------------------
  |  Branch (9829:20): [True: 5.02k, False: 29.6k]
  |  Branch (9829:33): [True: 3.01k, False: 2.01k]
  |  Branch (9829:47): [True: 1.41k, False: 1.59k]
  ------------------
 9830|  1.41k|          codePoint1 = ((c1 & 0x07) << 18) |
 9831|  1.41k|                       ((uint8_t(lhs.first[i + 1]) & 0x3F) << 12) |
 9832|  1.41k|                       ((uint8_t(lhs.first[i + 2]) & 0x3F) << 6) |
 9833|  1.41k|                       (uint8_t(lhs.first[i + 3]) & 0x3F);
 9834|  1.41k|          i += 4;
 9835|       |
 9836|  1.41k|          codePoint1 -= 0x10000;
 9837|  1.41k|          uint16_t high_surrogate = uint16_t(0xD800 + (codePoint1 >> 10));
 9838|  1.41k|          low_surrogate1 = uint16_t(0xDC00 + (codePoint1 & 0x3FF));
 9839|  1.41k|          codePoint1 = high_surrogate;
 9840|  33.2k|        } else {
 9841|       |          // ASCII (c1 <= 0x7F) or truncated/invalid UTF-8: treat as raw byte
 9842|  33.2k|          codePoint1 = c1;
 9843|  33.2k|          i++;
 9844|  33.2k|        }
 9845|  37.3k|      }
 9846|       |
 9847|  38.4k|      if (low_surrogate2 != 0) {
  ------------------
  |  Branch (9847:11): [True: 1.09k, False: 37.3k]
  ------------------
 9848|  1.09k|        codePoint2 = low_surrogate2;
 9849|  1.09k|        low_surrogate2 = 0;
 9850|  37.3k|      } else {
 9851|  37.3k|        uint8_t c2 = uint8_t(rhs.first[j]);
 9852|  37.3k|        if (c2 > 0x7F && c2 <= 0xDF && j + 1 < rhs.first.size()) {
  ------------------
  |  Branch (9852:13): [True: 14.3k, False: 22.9k]
  |  Branch (9852:26): [True: 6.65k, False: 7.73k]
  |  Branch (9852:40): [True: 2.20k, False: 4.44k]
  ------------------
 9853|  2.20k|          codePoint2 = ((c2 & 0x1F) << 6) | (uint8_t(rhs.first[j + 1]) & 0x3F);
 9854|  2.20k|          j += 2;
 9855|  35.1k|        } else if (c2 > 0xDF && c2 <= 0xEF && j + 2 < rhs.first.size()) {
  ------------------
  |  Branch (9855:20): [True: 7.73k, False: 27.4k]
  |  Branch (9855:33): [True: 2.18k, False: 5.55k]
  |  Branch (9855:47): [True: 1.29k, False: 889]
  ------------------
 9856|  1.29k|          codePoint2 = ((c2 & 0x0F) << 12) |
 9857|  1.29k|                       ((uint8_t(rhs.first[j + 1]) & 0x3F) << 6) |
 9858|  1.29k|                       (uint8_t(rhs.first[j + 2]) & 0x3F);
 9859|  1.29k|          j += 3;
 9860|  33.8k|        } else if (c2 > 0xEF && c2 <= 0xF7 && j + 3 < rhs.first.size()) {
  ------------------
  |  Branch (9860:20): [True: 5.55k, False: 28.3k]
  |  Branch (9860:33): [True: 3.11k, False: 2.43k]
  |  Branch (9860:47): [True: 1.53k, False: 1.58k]
  ------------------
 9861|  1.53k|          codePoint2 = ((c2 & 0x07) << 18) |
 9862|  1.53k|                       ((uint8_t(rhs.first[j + 1]) & 0x3F) << 12) |
 9863|  1.53k|                       ((uint8_t(rhs.first[j + 2]) & 0x3F) << 6) |
 9864|  1.53k|                       (uint8_t(rhs.first[j + 3]) & 0x3F);
 9865|  1.53k|          j += 4;
 9866|  1.53k|          codePoint2 -= 0x10000;
 9867|  1.53k|          uint16_t high_surrogate = uint16_t(0xD800 + (codePoint2 >> 10));
 9868|  1.53k|          low_surrogate2 = uint16_t(0xDC00 + (codePoint2 & 0x3FF));
 9869|  1.53k|          codePoint2 = high_surrogate;
 9870|  32.3k|        } else {
 9871|       |          // ASCII (c2 <= 0x7F) or truncated/invalid UTF-8: treat as raw byte
 9872|  32.3k|          codePoint2 = c2;
 9873|  32.3k|          j++;
 9874|  32.3k|        }
 9875|  37.3k|      }
 9876|       |
 9877|  38.4k|      if (codePoint1 != codePoint2) {
  ------------------
  |  Branch (9877:11): [True: 14.2k, False: 24.1k]
  ------------------
 9878|  14.2k|        return (codePoint1 < codePoint2);
 9879|  14.2k|      }
 9880|  38.4k|    }
 9881|  24.7k|    return (j < rhs.first.size() || low_surrogate2 != 0);
  ------------------
  |  Branch (9881:13): [True: 5.13k, False: 19.5k]
  |  Branch (9881:37): [True: 11, False: 19.5k]
  ------------------
 9882|  39.0k|  });
_ZN3ada17url_search_params5resetENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9665|  3.05k|inline void url_search_params::reset(std::string_view input) {
 9666|  3.05k|  params.clear();
 9667|  3.05k|  initialize(input);
 9668|  3.05k|}
_ZN3ada17url_search_params6appendENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_:
 9712|  17.1k|                                      const std::string_view value) {
 9713|  17.1k|  params.emplace_back(key, value);
 9714|  17.1k|}
_ZN3ada17url_search_params3setENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_:
 9779|  3.05k|                                   const std::string_view value) {
 9780|  3.05k|  const auto find = [&key](const auto& param) { return param.first == key; };
 9781|       |
 9782|  3.05k|  auto it = std::ranges::find_if(params, find);
 9783|       |
 9784|  3.05k|  if (it == params.end()) {
  ------------------
  |  Branch (9784:7): [True: 0, False: 3.05k]
  ------------------
 9785|      0|    params.emplace_back(key, value);
 9786|  3.05k|  } else {
 9787|  3.05k|    it->second = value;
 9788|  3.05k|    params.erase(std::remove_if(std::next(it), params.end(), find),
 9789|  3.05k|                 params.end());
 9790|  3.05k|  }
 9791|  3.05k|}
_ZZN3ada17url_search_params3setENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_ENKUlRKT_E_clINS1_4pairINS1_12basic_stringIcS4_NS1_9allocatorIcEEEESF_EEEEDaS8_:
 9780|  6.10k|  const auto find = [&key](const auto& param) { return param.first == key; };
_ZN3ada17url_search_params6removeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9793|  4.44k|inline void url_search_params::remove(const std::string_view key) {
 9794|  4.44k|  std::erase_if(params,
 9795|  4.44k|                [&key](const auto& param) { return param.first == key; });
 9796|  4.44k|}
_ZZN3ada17url_search_params6removeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlRKT_E_clINS1_4pairINS1_12basic_stringIcS4_NS1_9allocatorIcEEEESF_EEEEDaS8_:
 9795|  9.95k|                [&key](const auto& param) { return param.first == key; });
_ZN3ada17url_search_params6removeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_:
 9799|  4.44k|                                      const std::string_view value) {
 9800|  4.44k|  std::erase_if(params, [&key, &value](const auto& param) {
 9801|  4.44k|    return param.first == key && param.second == value;
 9802|  4.44k|  });
 9803|  4.44k|}
_ZZN3ada17url_search_params6removeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_ENKUlRKT_E_clINS1_4pairINS1_12basic_stringIcS4_NS1_9allocatorIcEEEESF_EEEEDaS8_:
 9800|  3.65k|  std::erase_if(params, [&key, &value](const auto& param) {
 9801|  3.65k|    return param.first == key && param.second == value;
  ------------------
  |  Branch (9801:12): [True: 0, False: 3.65k]
  |  Branch (9801:34): [True: 0, False: 0]
  ------------------
 9802|  3.65k|  });
_ZN3ada17url_search_params3hasENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9743|  22.3k|inline bool url_search_params::has(const std::string_view key) noexcept {
 9744|  22.3k|  auto entry = std::ranges::find_if(
 9745|  22.3k|      params, [&key](const auto& param) { return param.first == key; });
 9746|  22.3k|  return entry != params.end();
 9747|  22.3k|}
_ZZN3ada17url_search_params3hasENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlRKT_E_clINS1_4pairINS1_12basic_stringIcS4_NS1_9allocatorIcEEEESF_EEEEDaS8_:
 9745|   265k|      params, [&key](const auto& param) { return param.first == key; });
_ZN3ada17url_search_params3hasENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_:
 9750|  12.7k|                                   std::string_view value) noexcept {
 9751|  12.7k|  auto entry = std::ranges::find_if(params, [&key, &value](const auto& param) {
 9752|  12.7k|    return param.first == key && param.second == value;
 9753|  12.7k|  });
 9754|  12.7k|  return entry != params.end();
 9755|  12.7k|}
_ZZN3ada17url_search_params3hasENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_ENKUlRKT_E_clINS1_4pairINS1_12basic_stringIcS4_NS1_9allocatorIcEEEESF_EEEEDaS8_:
 9751|   136k|  auto entry = std::ranges::find_if(params, [&key, &value](const auto& param) {
 9752|   136k|    return param.first == key && param.second == value;
  ------------------
  |  Branch (9752:12): [True: 15.2k, False: 121k]
  |  Branch (9752:34): [True: 11.0k, False: 4.18k]
  ------------------
 9753|   136k|  });
_ZN3ada17url_search_params3getENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9719|  18.8k|    const std::string_view key) {
 9720|  18.8k|  auto entry = std::ranges::find_if(
 9721|  18.8k|      params, [&key](const auto& param) { return param.first == key; });
 9722|       |
 9723|  18.8k|  if (entry == params.end()) {
  ------------------
  |  Branch (9723:7): [True: 5.81k, False: 13.0k]
  ------------------
 9724|  5.81k|    return std::nullopt;
 9725|  5.81k|  }
 9726|       |
 9727|  13.0k|  return entry->second;
 9728|  18.8k|}
_ZZN3ada17url_search_params3getENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlRKT_E_clINS1_4pairINS1_12basic_stringIcS4_NS1_9allocatorIcEEEESF_EEEEDaS8_:
 9721|   142k|      params, [&key](const auto& param) { return param.first == key; });
_ZN3ada17url_search_params7get_allENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9731|  6.10k|    const std::string_view key) {
 9732|  6.10k|  std::vector<std::string> out{};
 9733|       |
 9734|  16.8k|  for (auto& param : params) {
  ------------------
  |  Branch (9734:20): [True: 16.8k, False: 6.10k]
  ------------------
 9735|  16.8k|    if (param.first == key) {
  ------------------
  |  Branch (9735:9): [True: 6.12k, False: 10.7k]
  ------------------
 9736|  6.12k|      out.emplace_back(param.second);
 9737|  6.12k|    }
 9738|  16.8k|  }
 9739|       |
 9740|  6.10k|  return out;
 9741|  6.10k|}
_ZN3ada17url_search_params8get_keysEv:
 9885|  3.05k|inline url_search_params_keys_iter url_search_params::get_keys() {
 9886|  3.05k|  return url_search_params_keys_iter(*this);
 9887|  3.05k|}
_ZN3ada22url_search_params_iterINSt3__117basic_string_viewIcNS1_11char_traitsIcEEEELNS_27url_search_params_iter_typeE0EEC2ERNS_17url_search_paramsE:
 9627|  3.05k|  inline url_search_params_iter(url_search_params& params_) : params(params_) {}
_ZN3ada17url_search_params10get_valuesEv:
 9892|  3.05k|inline url_search_params_values_iter url_search_params::get_values() {
 9893|  3.05k|  return url_search_params_values_iter(*this);
 9894|  3.05k|}
_ZN3ada22url_search_params_iterINSt3__117basic_string_viewIcNS1_11char_traitsIcEEEELNS_27url_search_params_iter_typeE1EEC2ERNS_17url_search_paramsE:
 9627|  3.05k|  inline url_search_params_iter(url_search_params& params_) : params(params_) {}
_ZN3ada17url_search_params11get_entriesEv:
 9899|  3.05k|inline url_search_params_entries_iter url_search_params::get_entries() {
 9900|  3.05k|  return url_search_params_entries_iter(*this);
 9901|  3.05k|}
_ZN3ada22url_search_params_iterINSt3__14pairINS1_17basic_string_viewIcNS1_11char_traitsIcEEEES6_EELNS_27url_search_params_iter_typeE2EEC2ERNS_17url_search_paramsE:
 9627|  3.05k|  inline url_search_params_iter(url_search_params& params_) : params(params_) {}
_ZN3ada22url_search_params_iterINSt3__117basic_string_viewIcNS1_11char_traitsIcEEEELNS_27url_search_params_iter_typeE0EE4nextEv:
 9909|  10.0k|inline std::optional<std::string_view> url_search_params_keys_iter::next() {
 9910|  10.0k|  if (!has_next()) {
  ------------------
  |  Branch (9910:7): [True: 0, False: 10.0k]
  ------------------
 9911|      0|    return std::nullopt;
 9912|      0|  }
 9913|  10.0k|  return params.params[pos++].first;
 9914|  10.0k|}
_ZN3ada22url_search_params_iterINSt3__117basic_string_viewIcNS1_11char_traitsIcEEEELNS_27url_search_params_iter_typeE1EE4nextEv:
 9917|  10.0k|inline std::optional<std::string_view> url_search_params_values_iter::next() {
 9918|  10.0k|  if (!has_next()) {
  ------------------
  |  Branch (9918:7): [True: 0, False: 10.0k]
  ------------------
 9919|      0|    return std::nullopt;
 9920|      0|  }
 9921|  10.0k|  return params.params[pos++].second;
 9922|  10.0k|}
_ZN3ada22url_search_params_iterINSt3__14pairINS1_17basic_string_viewIcNS1_11char_traitsIcEEEES6_EELNS_27url_search_params_iter_typeE2EE4nextEv:
 9926|  10.0k|url_search_params_entries_iter::next() {
 9927|  10.0k|  if (!has_next()) {
  ------------------
  |  Branch (9927:7): [True: 0, False: 10.0k]
  ------------------
 9928|      0|    return std::nullopt;
 9929|      0|  }
 9930|  10.0k|  return params.params[pos++];
 9931|  10.0k|}
_ZNK3ada17url_search_params5beginEv:
 9564|  12.2k|  inline auto begin() const { return params.begin(); }
_ZNK3ada17url_search_params3endEv:
 9565|  12.2k|  inline auto end() const { return params.end(); }
_ZNK3ada17url_search_params5frontEv:
 9566|  1.14k|  inline auto front() const { return params.front(); }
_ZNK3ada17url_search_params4backEv:
 9567|  1.14k|  inline auto back() const { return params.back(); }
_ZNK3ada17url_search_paramsixEm:
 9568|  1.14k|  inline auto operator[](size_t index) const { return params[index]; }
_ZN3ada17url_search_paramsC2Ev:
 9440|  9.16k|  url_search_params() = default;
_ZN3ada17url_search_paramsC2ERKS0_:
 9451|  3.05k|  url_search_params(const url_search_params& u) = default;
_ZN3ada17url_search_paramsaSERKS0_:
 9454|  3.05k|  url_search_params& operator=(const url_search_params& u) = default;
_ZN3ada17url_search_paramsC2EOS0_:
 9452|  3.05k|  url_search_params(url_search_params&& u) noexcept = default;
_ZN3ada17url_search_paramsaSEOS0_:
 9453|  3.05k|  url_search_params& operator=(url_search_params&& u) noexcept = default;
_ZNK3ada14url_aggregator8validateEv:
 9161|  3.05k|[[nodiscard]] constexpr bool url_aggregator::validate() const noexcept {
 9162|  3.05k|  if (!is_valid) {
  ------------------
  |  Branch (9162:7): [True: 0, False: 3.05k]
  ------------------
 9163|      0|    return true;
 9164|      0|  }
 9165|  3.05k|  if (!components.check_offset_consistency()) {
  ------------------
  |  Branch (9165:7): [True: 0, False: 3.05k]
  ------------------
 9166|      0|    ada_log("url_aggregator::validate inconsistent components \n",
 9167|      0|            to_diagram());
 9168|      0|    return false;
 9169|      0|  }
 9170|       |  // We have a credible components struct, but let us investivate more
 9171|       |  // carefully:
 9172|       |  /**
 9173|       |   * https://user:pass@example.com:1234/foo/bar?baz#quux
 9174|       |   *       |     |    |          | ^^^^|       |   |
 9175|       |   *       |     |    |          | |   |       |   `----- hash_start
 9176|       |   *       |     |    |          | |   |       `--------- search_start
 9177|       |   *       |     |    |          | |   `----------------- pathname_start
 9178|       |   *       |     |    |          | `--------------------- port
 9179|       |   *       |     |    |          `----------------------- host_end
 9180|       |   *       |     |    `---------------------------------- host_start
 9181|       |   *       |     `--------------------------------------- username_end
 9182|       |   *       `--------------------------------------------- protocol_end
 9183|       |   */
 9184|  3.05k|  if (components.protocol_end == url_components::omitted) {
  ------------------
  |  Branch (9184:7): [True: 0, False: 3.05k]
  ------------------
 9185|      0|    ada_log("url_aggregator::validate omitted protocol_end \n", to_diagram());
 9186|      0|    return false;
 9187|      0|  }
 9188|  3.05k|  if (components.username_end == url_components::omitted) {
  ------------------
  |  Branch (9188:7): [True: 0, False: 3.05k]
  ------------------
 9189|      0|    ada_log("url_aggregator::validate omitted username_end \n", to_diagram());
 9190|      0|    return false;
 9191|      0|  }
 9192|  3.05k|  if (components.host_start == url_components::omitted) {
  ------------------
  |  Branch (9192:7): [True: 0, False: 3.05k]
  ------------------
 9193|      0|    ada_log("url_aggregator::validate omitted host_start \n", to_diagram());
 9194|      0|    return false;
 9195|      0|  }
 9196|  3.05k|  if (components.host_end == url_components::omitted) {
  ------------------
  |  Branch (9196:7): [True: 0, False: 3.05k]
  ------------------
 9197|      0|    ada_log("url_aggregator::validate omitted host_end \n", to_diagram());
 9198|      0|    return false;
 9199|      0|  }
 9200|  3.05k|  if (components.pathname_start == url_components::omitted) {
  ------------------
  |  Branch (9200:7): [True: 0, False: 3.05k]
  ------------------
 9201|      0|    ada_log("url_aggregator::validate omitted pathname_start \n", to_diagram());
 9202|      0|    return false;
 9203|      0|  }
 9204|       |
 9205|  3.05k|  if (components.protocol_end > buffer.size()) {
  ------------------
  |  Branch (9205:7): [True: 0, False: 3.05k]
  ------------------
 9206|      0|    ada_log("url_aggregator::validate protocol_end overflow \n", to_diagram());
 9207|      0|    return false;
 9208|      0|  }
 9209|  3.05k|  if (components.username_end > buffer.size()) {
  ------------------
  |  Branch (9209:7): [True: 0, False: 3.05k]
  ------------------
 9210|      0|    ada_log("url_aggregator::validate username_end overflow \n", to_diagram());
 9211|      0|    return false;
 9212|      0|  }
 9213|  3.05k|  if (components.host_start > buffer.size()) {
  ------------------
  |  Branch (9213:7): [True: 0, False: 3.05k]
  ------------------
 9214|      0|    ada_log("url_aggregator::validate host_start overflow \n", to_diagram());
 9215|      0|    return false;
 9216|      0|  }
 9217|  3.05k|  if (components.host_end > buffer.size()) {
  ------------------
  |  Branch (9217:7): [True: 0, False: 3.05k]
  ------------------
 9218|      0|    ada_log("url_aggregator::validate host_end overflow \n", to_diagram());
 9219|      0|    return false;
 9220|      0|  }
 9221|  3.05k|  if (components.pathname_start > buffer.size()) {
  ------------------
  |  Branch (9221:7): [True: 0, False: 3.05k]
  ------------------
 9222|      0|    ada_log("url_aggregator::validate pathname_start overflow \n",
 9223|      0|            to_diagram());
 9224|      0|    return false;
 9225|      0|  }
 9226|       |
 9227|  3.05k|  if (components.protocol_end > 0) {
  ------------------
  |  Branch (9227:7): [True: 3.05k, False: 0]
  ------------------
 9228|  3.05k|    if (buffer[components.protocol_end - 1] != ':') {
  ------------------
  |  Branch (9228:9): [True: 0, False: 3.05k]
  ------------------
 9229|      0|      ada_log(
 9230|      0|          "url_aggregator::validate missing : at the end of the protocol \n",
 9231|      0|          to_diagram());
 9232|      0|      return false;
 9233|      0|    }
 9234|  3.05k|  }
 9235|       |
 9236|  3.05k|  if (components.username_end != buffer.size() &&
  ------------------
  |  Branch (9236:7): [True: 3.05k, False: 0]
  ------------------
 9237|  3.05k|      components.username_end > components.protocol_end + 2) {
  ------------------
  |  Branch (9237:7): [True: 0, False: 3.05k]
  ------------------
 9238|      0|    if (buffer[components.username_end] != ':' &&
  ------------------
  |  Branch (9238:9): [True: 0, False: 0]
  ------------------
 9239|      0|        buffer[components.username_end] != '@') {
  ------------------
  |  Branch (9239:9): [True: 0, False: 0]
  ------------------
 9240|      0|      ada_log(
 9241|      0|          "url_aggregator::validate missing : or @ at the end of the username "
 9242|      0|          "\n",
 9243|      0|          to_diagram());
 9244|      0|      return false;
 9245|      0|    }
 9246|      0|  }
 9247|       |
 9248|  3.05k|  if (components.host_start != buffer.size()) {
  ------------------
  |  Branch (9248:7): [True: 3.05k, False: 0]
  ------------------
 9249|  3.05k|    if (components.host_start > components.username_end) {
  ------------------
  |  Branch (9249:9): [True: 0, False: 3.05k]
  ------------------
 9250|      0|      if (buffer[components.host_start] != '@') {
  ------------------
  |  Branch (9250:11): [True: 0, False: 0]
  ------------------
 9251|      0|        ada_log(
 9252|      0|            "url_aggregator::validate missing @ at the end of the password \n",
 9253|      0|            to_diagram());
 9254|      0|        return false;
 9255|      0|      }
 9256|  3.05k|    } else if (components.host_start == components.username_end &&
  ------------------
  |  Branch (9256:16): [True: 3.05k, False: 0]
  ------------------
 9257|  3.05k|               components.host_end > components.host_start) {
  ------------------
  |  Branch (9257:16): [True: 3.05k, False: 0]
  ------------------
 9258|  3.05k|      if (components.host_start == components.protocol_end + 2) {
  ------------------
  |  Branch (9258:11): [True: 3.05k, False: 0]
  ------------------
 9259|  3.05k|        if (buffer[components.protocol_end] != '/' ||
  ------------------
  |  Branch (9259:13): [True: 0, False: 3.05k]
  ------------------
 9260|  3.05k|            buffer[components.protocol_end + 1] != '/') {
  ------------------
  |  Branch (9260:13): [True: 0, False: 3.05k]
  ------------------
 9261|      0|          ada_log(
 9262|      0|              "url_aggregator::validate missing // between protocol and host "
 9263|      0|              "\n",
 9264|      0|              to_diagram());
 9265|      0|          return false;
 9266|      0|        }
 9267|  3.05k|      } else {
 9268|      0|        if (components.host_start > components.protocol_end &&
  ------------------
  |  Branch (9268:13): [True: 0, False: 0]
  ------------------
 9269|      0|            buffer[components.host_start] != '@') {
  ------------------
  |  Branch (9269:13): [True: 0, False: 0]
  ------------------
 9270|      0|          ada_log(
 9271|      0|              "url_aggregator::validate missing @ at the end of the username "
 9272|      0|              "\n",
 9273|      0|              to_diagram());
 9274|      0|          return false;
 9275|      0|        }
 9276|      0|      }
 9277|  3.05k|    } else {
 9278|      0|      if (components.host_end != components.host_start) {
  ------------------
  |  Branch (9278:11): [True: 0, False: 0]
  ------------------
 9279|      0|        ada_log("url_aggregator::validate expected omitted host \n",
 9280|      0|                to_diagram());
 9281|      0|        return false;
 9282|      0|      }
 9283|      0|    }
 9284|  3.05k|  }
 9285|  3.05k|  if (components.host_end != buffer.size() &&
  ------------------
  |  Branch (9285:7): [True: 3.05k, False: 0]
  ------------------
 9286|  3.05k|      components.pathname_start > components.host_end) {
  ------------------
  |  Branch (9286:7): [True: 0, False: 3.05k]
  ------------------
 9287|      0|    if (components.pathname_start == components.host_end + 2 &&
  ------------------
  |  Branch (9287:9): [True: 0, False: 0]
  ------------------
 9288|      0|        buffer[components.host_end] == '/' &&
  ------------------
  |  Branch (9288:9): [True: 0, False: 0]
  ------------------
 9289|      0|        buffer[components.host_end + 1] == '.') {
  ------------------
  |  Branch (9289:9): [True: 0, False: 0]
  ------------------
 9290|      0|      if (components.pathname_start + 1 >= buffer.size() ||
  ------------------
  |  Branch (9290:11): [True: 0, False: 0]
  ------------------
 9291|      0|          buffer[components.pathname_start] != '/' ||
  ------------------
  |  Branch (9291:11): [True: 0, False: 0]
  ------------------
 9292|      0|          buffer[components.pathname_start + 1] != '/') {
  ------------------
  |  Branch (9292:11): [True: 0, False: 0]
  ------------------
 9293|      0|        ada_log(
 9294|      0|            "url_aggregator::validate expected the path to begin with // \n",
 9295|      0|            to_diagram());
 9296|      0|        return false;
 9297|      0|      }
 9298|      0|    } else if (buffer[components.host_end] != ':') {
  ------------------
  |  Branch (9298:16): [True: 0, False: 0]
  ------------------
 9299|      0|      ada_log("url_aggregator::validate missing : at the port \n",
 9300|      0|              to_diagram());
 9301|      0|      return false;
 9302|      0|    }
 9303|      0|  }
 9304|  3.05k|  if (components.pathname_start != buffer.size() &&
  ------------------
  |  Branch (9304:7): [True: 3.05k, False: 0]
  ------------------
 9305|  3.05k|      components.pathname_start < components.search_start &&
  ------------------
  |  Branch (9305:7): [True: 3.05k, False: 0]
  ------------------
 9306|  3.05k|      components.pathname_start < components.hash_start && !has_opaque_path) {
  ------------------
  |  Branch (9306:7): [True: 3.05k, False: 0]
  |  Branch (9306:60): [True: 3.05k, False: 0]
  ------------------
 9307|  3.05k|    if (buffer[components.pathname_start] != '/') {
  ------------------
  |  Branch (9307:9): [True: 0, False: 3.05k]
  ------------------
 9308|      0|      ada_log("url_aggregator::validate missing / at the path \n",
 9309|      0|              to_diagram());
 9310|      0|      return false;
 9311|      0|    }
 9312|  3.05k|  }
 9313|  3.05k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (9313:7): [True: 1.61k, False: 1.44k]
  ------------------
 9314|  1.61k|    if (buffer[components.search_start] != '?') {
  ------------------
  |  Branch (9314:9): [True: 0, False: 1.61k]
  ------------------
 9315|      0|      ada_log("url_aggregator::validate missing ? at the search \n",
 9316|      0|              to_diagram());
 9317|      0|      return false;
 9318|      0|    }
 9319|  1.61k|  }
 9320|  3.05k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (9320:7): [True: 492, False: 2.56k]
  ------------------
 9321|    492|    if (buffer[components.hash_start] != '#') {
  ------------------
  |  Branch (9321:9): [True: 0, False: 492]
  ------------------
 9322|      0|      ada_log("url_aggregator::validate missing # at the hash \n",
 9323|      0|              to_diagram());
 9324|      0|      return false;
 9325|      0|    }
 9326|    492|  }
 9327|       |
 9328|  3.05k|  return true;
 9329|  3.05k|}
_ZNK3ada14url_components24check_offset_consistencyEv:
 7655|  3.05k|    const noexcept {
 7656|       |  /**
 7657|       |   * https://user:pass@example.com:1234/foo/bar?baz#quux
 7658|       |   *       |     |    |          | ^^^^|       |   |
 7659|       |   *       |     |    |          | |   |       |   `----- hash_start
 7660|       |   *       |     |    |          | |   |       `--------- search_start
 7661|       |   *       |     |    |          | |   `----------------- pathname_start
 7662|       |   *       |     |    |          | `--------------------- port
 7663|       |   *       |     |    |          `----------------------- host_end
 7664|       |   *       |     |    `---------------------------------- host_start
 7665|       |   *       |     `--------------------------------------- username_end
 7666|       |   *       `--------------------------------------------- protocol_end
 7667|       |   */
 7668|       |  // These conditions can be made more strict.
 7669|  3.05k|  if (protocol_end == url_components::omitted) {
  ------------------
  |  Branch (7669:7): [True: 0, False: 3.05k]
  ------------------
 7670|      0|    return false;
 7671|      0|  }
 7672|  3.05k|  uint32_t index = protocol_end;
 7673|       |
 7674|  3.05k|  if (username_end == url_components::omitted) {
  ------------------
  |  Branch (7674:7): [True: 0, False: 3.05k]
  ------------------
 7675|      0|    return false;
 7676|      0|  }
 7677|  3.05k|  if (username_end < index) {
  ------------------
  |  Branch (7677:7): [True: 0, False: 3.05k]
  ------------------
 7678|      0|    return false;
 7679|      0|  }
 7680|  3.05k|  index = username_end;
 7681|       |
 7682|  3.05k|  if (host_start == url_components::omitted) {
  ------------------
  |  Branch (7682:7): [True: 0, False: 3.05k]
  ------------------
 7683|      0|    return false;
 7684|      0|  }
 7685|  3.05k|  if (host_start < index) {
  ------------------
  |  Branch (7685:7): [True: 0, False: 3.05k]
  ------------------
 7686|      0|    return false;
 7687|      0|  }
 7688|  3.05k|  index = host_start;
 7689|       |
 7690|  3.05k|  if (port != url_components::omitted) {
  ------------------
  |  Branch (7690:7): [True: 0, False: 3.05k]
  ------------------
 7691|      0|    if (port > 0xffff) {
  ------------------
  |  Branch (7691:9): [True: 0, False: 0]
  ------------------
 7692|      0|      return false;
 7693|      0|    }
 7694|      0|    uint32_t port_length = helpers::fast_digit_count(port) + 1;
 7695|      0|    if (index + port_length < index) {
  ------------------
  |  Branch (7695:9): [True: 0, False: 0]
  ------------------
 7696|      0|      return false;
 7697|      0|    }
 7698|      0|    index += port_length;
 7699|      0|  }
 7700|       |
 7701|  3.05k|  if (pathname_start == url_components::omitted) {
  ------------------
  |  Branch (7701:7): [True: 0, False: 3.05k]
  ------------------
 7702|      0|    return false;
 7703|      0|  }
 7704|  3.05k|  if (pathname_start < index) {
  ------------------
  |  Branch (7704:7): [True: 0, False: 3.05k]
  ------------------
 7705|      0|    return false;
 7706|      0|  }
 7707|  3.05k|  index = pathname_start;
 7708|       |
 7709|  3.05k|  if (search_start != url_components::omitted) {
  ------------------
  |  Branch (7709:7): [True: 1.61k, False: 1.44k]
  ------------------
 7710|  1.61k|    if (search_start < index) {
  ------------------
  |  Branch (7710:9): [True: 0, False: 1.61k]
  ------------------
 7711|      0|      return false;
 7712|      0|    }
 7713|  1.61k|    index = search_start;
 7714|  1.61k|  }
 7715|       |
 7716|  3.05k|  if (hash_start != url_components::omitted) {
  ------------------
  |  Branch (7716:7): [True: 492, False: 2.56k]
  ------------------
 7717|    492|    if (hash_start < index) {
  ------------------
  |  Branch (7717:9): [True: 0, False: 492]
  ------------------
 7718|      0|      return false;
 7719|      0|    }
 7720|    492|  }
 7721|       |
 7722|  3.05k|  return true;
 7723|  3.05k|}
_ZNK3ada22url_search_params_iterINSt3__117basic_string_viewIcNS1_11char_traitsIcEEEELNS_27url_search_params_iter_typeE0EE8has_nextEv:
 9904|  23.1k|inline bool url_search_params_iter<T, Type>::has_next() const {
 9905|  23.1k|  return pos < params.params.size();
 9906|  23.1k|}
_ZNK3ada22url_search_params_iterINSt3__117basic_string_viewIcNS1_11char_traitsIcEEEELNS_27url_search_params_iter_typeE1EE8has_nextEv:
 9904|  23.1k|inline bool url_search_params_iter<T, Type>::has_next() const {
 9905|  23.1k|  return pos < params.params.size();
 9906|  23.1k|}
_ZNK3ada22url_search_params_iterINSt3__14pairINS1_17basic_string_viewIcNS1_11char_traitsIcEEEES6_EELNS_27url_search_params_iter_typeE2EE8has_nextEv:
 9904|  23.1k|inline bool url_search_params_iter<T, Type>::has_next() const {
 9905|  23.1k|  return pos < params.params.size();
 9906|  23.1k|}

LLVMFuzzerTestOneInput:
    9|  3.05k|extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   10|  3.05k|  FuzzedDataProvider fdp(data, size);
   11|  3.05k|  std::string source = fdp.ConsumeRandomLengthString(256);
   12|  3.05k|  std::string base_source = fdp.ConsumeRandomLengthString(256);
   13|  3.05k|  std::string key3 = fdp.ConsumeRandomLengthString(64);
   14|  3.05k|  std::string value3 = fdp.ConsumeRandomLengthString(64);
   15|       |
   16|       |  /**
   17|       |   * ada::url_search_params
   18|       |   */
   19|  3.05k|  volatile size_t length = 0;
   20|       |
   21|  3.05k|  auto base_source_view =
   22|  3.05k|      std::string_view(base_source.data(), base_source.length());
   23|       |
   24|       |  // Test constructor with initial value
   25|  3.05k|  auto initialized = ada::url_search_params(base_source_view);
   26|  3.05k|  length += initialized.size();
   27|  3.05k|  initialized.to_string();
   28|       |
   29|       |  // Test get() and get_all() on initialized params
   30|  3.05k|  {
   31|  3.05k|    auto val = initialized.get(source);
   32|  3.05k|    if (val.has_value()) {
  ------------------
  |  Branch (32:9): [True: 266, False: 2.78k]
  ------------------
   33|    266|      length += val->size();
   34|    266|    }
   35|  3.05k|    auto all_vals = initialized.get_all(source);
   36|  3.05k|    for (const auto& v : all_vals) {
  ------------------
  |  Branch (36:24): [True: 2.60k, False: 3.05k]
  ------------------
   37|  2.60k|      length += v.size();
   38|  2.60k|    }
   39|  3.05k|  }
   40|       |
   41|       |  // Test sort() on initialized params
   42|  3.05k|  initialized.sort();
   43|       |
   44|       |  // Test C++ range-for iteration; also verify has(k) and has(k,v) consistency.
   45|  9.65k|  for (const auto& pair : initialized) {
  ------------------
  |  Branch (45:25): [True: 9.65k, False: 3.05k]
  ------------------
   46|  9.65k|    length += pair.first.size();
   47|  9.65k|    length += pair.second.size();
   48|       |
   49|       |    // Every key seen in iteration must be reported by has(key).
   50|  9.65k|    if (!initialized.has(pair.first)) {
  ------------------
  |  Branch (50:9): [True: 0, False: 9.65k]
  ------------------
   51|      0|      printf(
   52|      0|          "url_search_params: iteration yielded key '%s' but has(key) is "
   53|      0|          "false\n",
   54|      0|          std::string(pair.first).c_str());
   55|      0|      abort();
   56|      0|    }
   57|       |
   58|       |    // has(key, value) → has(key)
   59|  9.65k|    if (initialized.has(pair.first, pair.second) &&
  ------------------
  |  Branch (59:9): [True: 9.65k, False: 0]
  ------------------
   60|  9.65k|        !initialized.has(pair.first)) {
  ------------------
  |  Branch (60:9): [True: 0, False: 9.65k]
  ------------------
   61|      0|      printf(
   62|      0|          "url_search_params: has(key,value) is true but has(key) is false "
   63|      0|          "for key '%s'\n",
   64|      0|          std::string(pair.first).c_str());
   65|      0|      abort();
   66|      0|    }
   67|       |
   68|       |    // get(key) must return a value when the key exists.
   69|  9.65k|    auto got = initialized.get(pair.first);
   70|  9.65k|    if (!got.has_value()) {
  ------------------
  |  Branch (70:9): [True: 0, False: 9.65k]
  ------------------
   71|      0|      printf(
   72|      0|          "url_search_params: has(key) is true but get(key) returned nullopt "
   73|      0|          "for key '%s'\n",
   74|      0|          std::string(pair.first).c_str());
   75|      0|      abort();
   76|      0|    }
   77|  9.65k|  }
   78|       |
   79|       |  // Test index-based access
   80|  3.05k|  if (initialized.size() > 0) {
  ------------------
  |  Branch (80:7): [True: 1.14k, False: 1.91k]
  ------------------
   81|  1.14k|    auto front = initialized.front();
   82|  1.14k|    length += front.first.size();
   83|  1.14k|    auto back = initialized.back();
   84|  1.14k|    length += back.first.size();
   85|  1.14k|    auto first = initialized[0];
   86|  1.14k|    length += first.first.size();
   87|  1.14k|  }
   88|       |
   89|       |  // Test default-constructed params with various mutations
   90|  3.05k|  auto search_params = ada::url_search_params();
   91|  3.05k|  search_params.append(source, base_source);
   92|  3.05k|  search_params.append(key3, value3);
   93|  3.05k|  search_params.set(source, base_source);
   94|  3.05k|  search_params.to_string();
   95|       |
   96|       |  // Test size()
   97|  3.05k|  length += search_params.size();
   98|       |
   99|       |  // Test has() and has(key, value) overloads
  100|  3.05k|  volatile bool has_key = search_params.has(base_source);
  101|  3.05k|  if (has_key) {
  ------------------
  |  Branch (101:7): [True: 1.85k, False: 1.20k]
  ------------------
  102|  1.85k|    search_params.append(base_source, source);
  103|  1.85k|  }
  104|       |
  105|       |  // Test get() - returns first matching value
  106|  3.05k|  {
  107|  3.05k|    auto val = search_params.get(source);
  108|  3.05k|    if (val.has_value()) {
  ------------------
  |  Branch (108:9): [True: 3.05k, False: 0]
  ------------------
  109|  3.05k|      length += val->size();
  110|  3.05k|    }
  111|  3.05k|  }
  112|       |
  113|       |  // Test get_all() - returns all matching values
  114|  3.05k|  {
  115|  3.05k|    auto all_vals = search_params.get_all(source);
  116|  3.05k|    length += all_vals.size();
  117|  3.51k|    for (const auto& v : all_vals) {
  ------------------
  |  Branch (117:24): [True: 3.51k, False: 3.05k]
  ------------------
  118|  3.51k|      length += v.size();
  119|  3.51k|    }
  120|  3.05k|  }
  121|       |
  122|       |  // Test remove(key) and remove(key, value) overloads
  123|  3.05k|  search_params.remove(source);
  124|  3.05k|  search_params.remove(source, base_source);
  125|       |
  126|       |  // Test has(key, value) after remove
  127|  3.05k|  if (search_params.has(base_source, source)) {
  ------------------
  |  Branch (127:7): [True: 1.38k, False: 1.66k]
  ------------------
  128|  1.38k|    search_params.remove(base_source);
  129|  1.38k|    search_params.remove(base_source, source);
  130|  1.38k|  }
  131|       |
  132|       |  // Append more pairs for iteration testing
  133|  3.05k|  search_params.append(key3, value3);
  134|  3.05k|  search_params.append(source, key3);
  135|  3.05k|  search_params.append(base_source, value3);
  136|       |
  137|       |  // Test sort()
  138|  3.05k|  search_params.sort();
  139|       |
  140|       |  // Test serialization after sort
  141|  3.05k|  std::string serialized = search_params.to_string();
  142|  3.05k|  length += serialized.size();
  143|       |
  144|       |  // Test JavaScript-style iterator: keys
  145|  3.05k|  auto keys = search_params.get_keys();
  146|  13.0k|  while (keys.has_next()) {
  ------------------
  |  Branch (146:10): [True: 10.0k, False: 3.05k]
  ------------------
  147|  10.0k|    auto k = keys.next();
  148|  10.0k|    if (k.has_value()) {
  ------------------
  |  Branch (148:9): [True: 10.0k, False: 0]
  ------------------
  149|  10.0k|      length += k->size();
  150|  10.0k|    }
  151|  10.0k|  }
  152|       |
  153|       |  // Test JavaScript-style iterator: values
  154|  3.05k|  auto values = search_params.get_values();
  155|  13.0k|  while (values.has_next()) {
  ------------------
  |  Branch (155:10): [True: 10.0k, False: 3.05k]
  ------------------
  156|  10.0k|    auto v = values.next();
  157|  10.0k|    if (v.has_value()) {
  ------------------
  |  Branch (157:9): [True: 10.0k, False: 0]
  ------------------
  158|  10.0k|      length += v->size();
  159|  10.0k|    }
  160|  10.0k|  }
  161|       |
  162|       |  // Test JavaScript-style iterator: entries
  163|  3.05k|  auto entries = search_params.get_entries();
  164|  13.0k|  while (entries.has_next()) {
  ------------------
  |  Branch (164:10): [True: 10.0k, False: 3.05k]
  ------------------
  165|  10.0k|    auto e = entries.next();
  166|  10.0k|    if (e.has_value()) {
  ------------------
  |  Branch (166:9): [True: 10.0k, False: 0]
  ------------------
  167|  10.0k|      length += e->first.size();
  168|  10.0k|      length += e->second.size();
  169|  10.0k|    }
  170|  10.0k|  }
  171|       |
  172|       |  // Test C++ range-for on the mutated params
  173|  10.0k|  for (const auto& pair : search_params) {
  ------------------
  |  Branch (173:25): [True: 10.0k, False: 3.05k]
  ------------------
  174|  10.0k|    length += pair.first.size();
  175|  10.0k|    length += pair.second.size();
  176|  10.0k|  }
  177|       |
  178|       |  // Test reset() - private method used by C API
  179|  3.05k|  std::string resetted_value = fdp.ConsumeRandomLengthString(256);
  180|  3.05k|  search_params.reset(resetted_value);
  181|  3.05k|  length += search_params.size();
  182|       |
  183|       |  // Test that reset() followed by iteration doesn't crash
  184|  3.29k|  for (const auto& pair : search_params) {
  ------------------
  |  Branch (184:25): [True: 3.29k, False: 3.05k]
  ------------------
  185|  3.29k|    length += pair.first.size();
  186|  3.29k|    length += pair.second.size();
  187|  3.29k|  }
  188|       |
  189|       |  // Test get() after reset
  190|  3.05k|  {
  191|  3.05k|    auto val = search_params.get(source);
  192|  3.05k|    if (val.has_value()) {
  ------------------
  |  Branch (192:9): [True: 26, False: 3.02k]
  ------------------
  193|     26|      length += val->size();
  194|     26|    }
  195|  3.05k|  }
  196|       |
  197|       |  // Test copy constructor and copy assignment
  198|  3.05k|  ada::url_search_params copied = search_params;
  199|  3.05k|  length += copied.size();
  200|  3.05k|  ada::url_search_params assigned;
  201|  3.05k|  assigned = search_params;
  202|  3.05k|  length += assigned.size();
  203|       |
  204|       |  // Test move constructor and move assignment
  205|  3.05k|  ada::url_search_params move_constructed = std::move(copied);
  206|  3.05k|  length += move_constructed.size();
  207|  3.05k|  ada::url_search_params move_assigned;
  208|  3.05k|  move_assigned = std::move(assigned);
  209|  3.05k|  length += move_assigned.size();
  210|       |
  211|       |  /**
  212|       |   * Serialisation idempotency.
  213|       |   *
  214|       |   * The application/x-www-form-urlencoded serialiser must be a fixed point:
  215|       |   * parsing the serialised form of any url_search_params and serialising
  216|       |   * again must produce the same string. This invariant is mandated by the
  217|       |   * WHATWG spec and must hold for all inputs.
  218|       |   *
  219|       |   * We test this on both the initialised params (constructed from fuzz input)
  220|       |   * and the mutated params (after append / set / remove / sort).
  221|       |   */
  222|       |
  223|       |  // Initialised params idempotency.
  224|  3.05k|  {
  225|  3.05k|    std::string s1 = initialized.to_string();
  226|  3.05k|    ada::url_search_params reparsed(s1);
  227|  3.05k|    std::string s2 = reparsed.to_string();
  228|  3.05k|    if (s1 != s2) {
  ------------------
  |  Branch (228:9): [True: 0, False: 3.05k]
  ------------------
  229|      0|      printf(
  230|      0|          "url_search_params serialisation not idempotent (initialized)!\n"
  231|      0|          "  first:  %s\n  second: %s\n",
  232|      0|          s1.c_str(), s2.c_str());
  233|      0|      abort();
  234|      0|    }
  235|  3.05k|  }
  236|       |
  237|       |  // Mutated params idempotency.
  238|  3.05k|  {
  239|  3.05k|    std::string s1 = move_assigned.to_string();
  240|  3.05k|    ada::url_search_params reparsed(s1);
  241|  3.05k|    std::string s2 = reparsed.to_string();
  242|  3.05k|    if (s1 != s2) {
  ------------------
  |  Branch (242:9): [True: 0, False: 3.05k]
  ------------------
  243|      0|      printf(
  244|      0|          "url_search_params serialisation not idempotent (mutated)!\n"
  245|      0|          "  first:  %s\n  second: %s\n",
  246|      0|          s1.c_str(), s2.c_str());
  247|      0|      abort();
  248|      0|    }
  249|  3.05k|  }
  250|       |
  251|       |  /**
  252|       |   * Round-trip via URL.
  253|       |   *
  254|       |   * Embed the fuzz input as the query component of a real URL, extract the
  255|       |   * search params from the parsed URL's search string, and verify that the
  256|       |   * resulting params serialise idempotently. This exercises the interface
  257|       |   * between URL parsing and search-params parsing.
  258|       |   */
  259|  3.05k|  {
  260|  3.05k|    std::string url_str = "https://example.com/?" + source;
  261|  3.05k|    auto parsed_url = ada::parse<ada::url_aggregator>(url_str);
  262|  3.05k|    if (parsed_url) {
  ------------------
  |  Branch (262:9): [True: 3.05k, False: 0]
  ------------------
  263|  3.05k|      std::string search_raw = std::string(parsed_url->get_search());
  264|  3.05k|      std::string_view search_view = search_raw;
  265|  3.05k|      if (!search_view.empty() && search_view[0] == '?') {
  ------------------
  |  Branch (265:11): [True: 1.66k, False: 1.38k]
  |  Branch (265:35): [True: 1.66k, False: 0]
  ------------------
  266|  1.66k|        search_view = search_view.substr(1);
  267|  1.66k|      }
  268|       |
  269|  3.05k|      ada::url_search_params sp_from_url(search_view);
  270|       |
  271|       |      // Size and iteration must not crash.
  272|  3.05k|      length += sp_from_url.size();
  273|  4.10k|      for (const auto& pair : sp_from_url) {
  ------------------
  |  Branch (273:29): [True: 4.10k, False: 3.05k]
  ------------------
  274|  4.10k|        length += pair.first.size();
  275|  4.10k|        length += pair.second.size();
  276|  4.10k|      }
  277|       |
  278|       |      // Idempotency check.
  279|  3.05k|      std::string t1 = sp_from_url.to_string();
  280|  3.05k|      ada::url_search_params sp2(t1);
  281|  3.05k|      std::string t2 = sp2.to_string();
  282|  3.05k|      if (t1 != t2) {
  ------------------
  |  Branch (282:11): [True: 0, False: 3.05k]
  ------------------
  283|      0|        printf(
  284|      0|            "url_search_params via URL round-trip not idempotent!\n"
  285|      0|            "  first:  %s\n  second: %s\n",
  286|      0|            t1.c_str(), t2.c_str());
  287|      0|        abort();
  288|      0|      }
  289|       |
  290|       |      // Set the serialised params back on the URL – must not crash.
  291|  3.05k|      parsed_url->set_search(t1);
  292|  3.05k|      volatile bool v = parsed_url->validate();
  293|  3.05k|      (void)v;
  294|  3.05k|    }
  295|  3.05k|  }
  296|       |
  297|  3.05k|  return 0;
  298|  3.05k|}

