_ZN3ada7unicode14percent_encodeILb1EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKhRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEE:
 7355|  3.23k|                    std::string& out) {
 7356|  3.23k|  ada_log("percent_encode ", input, " to output string while ",
 7357|  3.23k|          append ? "appending" : "overwriting");
 7358|  3.23k|  auto pointer = std::ranges::find_if(input, [character_set](const char c) {
 7359|  3.23k|    return character_sets::bit_at(character_set, c);
 7360|  3.23k|  });
 7361|  3.23k|  ada_log("percent_encode done checking, moved to ",
 7362|  3.23k|          std::distance(input.begin(), pointer));
 7363|       |
 7364|       |  // Optimization: Don't iterate if percent encode is not required
 7365|  3.23k|  if (pointer == input.end()) {
  ------------------
  |  Branch (7365:7): [True: 1.84k, False: 1.39k]
  ------------------
 7366|  1.84k|    ada_log("percent_encode encoding not needed.");
 7367|  1.84k|    return false;
 7368|  1.84k|  }
 7369|       |  if constexpr (!append) {
 7370|       |    out.clear();
 7371|       |  }
 7372|  1.39k|  ada_log("percent_encode appending ", std::distance(input.begin(), pointer),
 7373|  1.39k|          " bytes");
 7374|       |  // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage)
 7375|  1.39k|  out.append(input.data(), std::distance(input.begin(), pointer));
 7376|  1.39k|  ada_log("percent_encode processing ", std::distance(pointer, input.end()),
 7377|  1.39k|          " bytes");
 7378|  55.2k|  for (; pointer != input.end(); pointer++) {
  ------------------
  |  Branch (7378:10): [True: 53.8k, False: 1.39k]
  ------------------
 7379|  53.8k|    if (character_sets::bit_at(character_set, *pointer)) {
  ------------------
  |  Branch (7379:9): [True: 38.0k, False: 15.8k]
  ------------------
 7380|  38.0k|      out.append(character_sets::hex + uint8_t(*pointer) * 4, 3);
 7381|  38.0k|    } else {
 7382|  15.8k|      out += *pointer;
 7383|  15.8k|    }
 7384|  53.8k|  }
 7385|  1.39k|  return true;
 7386|  3.23k|}
_ZN3ada7unicode22form_urlencoded_decodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 7255|  53.3k|std::string form_urlencoded_decode(const std::string_view input) {
 7256|  53.3k|  const size_t len = input.size();
 7257|  53.3k|  if (len == 0) [[unlikely]] {
  ------------------
  |  Branch (7257:7): [True: 26.3k, False: 27.0k]
  ------------------
 7258|  26.3k|    return {};
 7259|  26.3k|  }
 7260|       |
 7261|       |  // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage)
 7262|  27.0k|  const char* const src = input.data();
 7263|  27.0k|  const char* const end = src + len;
 7264|  27.0k|  const char* p = src;
 7265|       |
 7266|       |  // Advance over the untransformed prefix.
 7267|   106k|  while (p < end && *p != '+' && *p != '%') {
  ------------------
  |  Branch (7267:10): [True: 96.4k, False: 10.0k]
  |  Branch (7267:21): [True: 94.5k, False: 1.93k]
  |  Branch (7267:34): [True: 79.5k, False: 15.0k]
  ------------------
 7268|  79.5k|    ++p;
 7269|  79.5k|  }
 7270|  27.0k|  if (p == end) {
  ------------------
  |  Branch (7270:7): [True: 10.0k, False: 16.9k]
  ------------------
 7271|  10.0k|    return std::string(input);
 7272|  10.0k|  }
 7273|       |
 7274|       |  // Output is always at most as long as the input: write into a single
 7275|       |  // pre-sized buffer, then shrink to the final length.
 7276|  16.9k|  std::string out(len, '\0');
 7277|  16.9k|  char* d = out.data();
 7278|  16.9k|  char* const d0 = d;
 7279|       |
 7280|  16.9k|  const size_t prefix = static_cast<size_t>(p - src);
 7281|  16.9k|  std::memcpy(d, src, prefix);
 7282|  16.9k|  d += prefix;
 7283|       |
 7284|  54.2k|  while (p < end) {
  ------------------
  |  Branch (7284:10): [True: 37.2k, False: 16.9k]
  ------------------
 7285|  37.2k|    const char c = *p;
 7286|  37.2k|    if (c == '+') {
  ------------------
  |  Branch (7286:9): [True: 7.27k, False: 30.0k]
  ------------------
 7287|  7.27k|      *d++ = ' ';
 7288|  7.27k|      ++p;
 7289|  30.0k|    } else if (c == '%') {
  ------------------
  |  Branch (7289:16): [True: 21.8k, False: 8.17k]
  ------------------
 7290|       |      // Decode runs of valid %XX tightly (common for nested URL query values).
 7291|   139k|      while (p + 2 < end && *p == '%') {
  ------------------
  |  Branch (7291:14): [True: 125k, False: 14.5k]
  |  Branch (7291:29): [True: 119k, False: 5.77k]
  ------------------
 7292|   119k|        const uint8_t hi = unhex_table[static_cast<uint8_t>(p[1])];
 7293|   119k|        const uint8_t lo = unhex_table[static_cast<uint8_t>(p[2])];
 7294|   119k|        if ((hi | lo) >= 16) {
  ------------------
  |  Branch (7294:13): [True: 1.46k, False: 117k]
  ------------------
 7295|  1.46k|          break;
 7296|  1.46k|        }
 7297|   117k|        *d++ = static_cast<char>((hi << 4) | lo);
 7298|   117k|        p += 3;
 7299|   117k|      }
 7300|  21.8k|      if (p < end && *p == '%') {
  ------------------
  |  Branch (7300:11): [True: 10.5k, False: 11.2k]
  |  Branch (7300:22): [True: 3.75k, False: 6.80k]
  ------------------
 7301|       |        // Invalid escape: copy '%' literally and continue.
 7302|  3.75k|        *d++ = *p++;
 7303|  3.75k|      }
 7304|  21.8k|    } else {
 7305|       |      // Copy a plain run until the next '+' or '%'.
 7306|  8.17k|      const char* start = p;
 7307|  8.17k|      ++p;
 7308|  34.9k|      while (p < end && *p != '+' && *p != '%') {
  ------------------
  |  Branch (7308:14): [True: 33.2k, False: 1.78k]
  |  Branch (7308:25): [True: 32.1k, False: 1.10k]
  |  Branch (7308:38): [True: 26.8k, False: 5.28k]
  ------------------
 7309|  26.8k|        ++p;
 7310|  26.8k|      }
 7311|  8.17k|      const size_t n = static_cast<size_t>(p - start);
 7312|  8.17k|      std::memcpy(d, start, n);
 7313|  8.17k|      d += n;
 7314|  8.17k|    }
 7315|  37.2k|  }
 7316|       |
 7317|  16.9k|  out.resize(static_cast<size_t>(d - d0));
 7318|  16.9k|  return out;
 7319|  27.0k|}
_ZN3ada7unicode14percent_encodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKh:
 7325|   114k|                           const uint8_t character_set[]) {
 7326|   114k|  auto pointer = std::ranges::find_if(input, [character_set](const char c) {
 7327|   114k|    return character_sets::bit_at(character_set, c);
 7328|   114k|  });
 7329|       |  // Optimization: Don't iterate if percent encode is not required
 7330|   114k|  if (pointer == input.end()) {
  ------------------
  |  Branch (7330:7): [True: 78.9k, False: 35.5k]
  ------------------
 7331|  78.9k|    return std::string(input);
 7332|  78.9k|  }
 7333|       |
 7334|  35.5k|  std::string result;
 7335|  35.5k|  result.reserve(input.length());  // in the worst case, percent encoding might
 7336|       |                                   // produce 3 characters.
 7337|  35.5k|  result.append(input.substr(0, std::distance(input.begin(), pointer)));
 7338|  35.5k|  if (static_cast<size_t>(input.end() - pointer) >= 48) {
  ------------------
  |  Branch (7338:7): [True: 3.32k, False: 32.2k]
  ------------------
 7339|  3.32k|    percent_encode_suffix(&*pointer, input.data() + input.size(), character_set,
 7340|  3.32k|                          result);
 7341|  32.2k|  } else {
 7342|   192k|    for (; pointer != input.end(); pointer++) {
  ------------------
  |  Branch (7342:12): [True: 159k, False: 32.2k]
  ------------------
 7343|   159k|      if (character_sets::bit_at(character_set, *pointer)) {
  ------------------
  |  Branch (7343:11): [True: 135k, False: 24.6k]
  ------------------
 7344|   135k|        result.append(character_sets::hex + uint8_t(*pointer) * 4, 3);
 7345|   135k|      } else {
 7346|  24.6k|        result += *pointer;
 7347|  24.6k|      }
 7348|   159k|    }
 7349|  32.2k|  }
 7350|  35.5k|  return result;
 7351|   114k|}
_ZN3ada7unicode21percent_encode_suffixEPKcS2_PKhRNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEE:
 7726|  3.32k|                           const uint8_t character_set[], std::string& out) {
 7727|  3.32k|#if ADA_UNICODE_SSSE3 || ADA_NEON || ADA_RVV
 7728|  3.32k|  if (static_cast<size_t>(end - p) >= kPercentEncodeSimdMin) {
  ------------------
  |  Branch (7728:7): [True: 3.32k, False: 0]
  ------------------
 7729|  3.32k|    percent_encode_to_wide(p, end, character_set, out);
 7730|  3.32k|    return;
 7731|  3.32k|  }
 7732|      0|#endif
 7733|      0|  percent_encode_to_scalar(p, end, character_set, out);
 7734|      0|}
_ZN3ada5parseINS_14url_aggregatorEEEN2tl8expectedIT_NS_6errorsEEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEPKS4_:
 8274|  2.99k|    std::string_view input, const result_type* base_url) {
 8275|  2.99k|  result_type u = ada::parser::parse_url_impl<result_type>(input, base_url);
 8276|  2.99k|  if (!u.is_valid) {
  ------------------
  |  Branch (8276:7): [True: 0, False: 2.99k]
  ------------------
 8277|      0|    return tl::unexpected(errors::type_error);
 8278|      0|  }
 8279|  2.99k|  return u;
 8280|  2.99k|}
_ZN3ada20get_max_input_lengthEv:
 7895|  10.7k|uint32_t get_max_input_length() {
 7896|  10.7k|  return max_input_length_.load(std::memory_order_relaxed);
 7897|  10.7k|}
_ZN3ada7helpers18trim_c0_whitespaceERNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9254|    509|void trim_c0_whitespace(std::string_view& input) noexcept {
 9255|    509|  while (!input.empty() &&
  ------------------
  |  Branch (9255:10): [True: 509, False: 0]
  ------------------
 9256|    509|         ada::unicode::is_c0_control_or_space(input.front())) {
  ------------------
  |  Branch (9256:10): [True: 0, False: 509]
  ------------------
 9257|      0|    input.remove_prefix(1);
 9258|      0|  }
 9259|  2.75k|  while (!input.empty() && ada::unicode::is_c0_control_or_space(input.back())) {
  ------------------
  |  Branch (9259:10): [True: 2.75k, False: 0]
  |  Branch (9259:28): [True: 2.24k, False: 509]
  ------------------
 9260|  2.24k|    input.remove_suffix(1);
 9261|  2.24k|  }
 9262|    509|}
_ZN3ada6parser25try_parse_simple_absoluteINS_14url_aggregatorEEEbNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEERT_:
11957|  2.99k|                                                result_type& out) {
11958|  2.99k|  constexpr bool is_ada_url = std::is_same_v<result_type, ada::url>;
11959|  2.99k|  constexpr bool is_aggregator =
11960|  2.99k|      std::is_same_v<result_type, ada::url_aggregator>;
11961|  2.99k|  static_assert(is_ada_url || is_aggregator);
11962|       |
11963|  2.99k|  const size_t len = input.size();
11964|       |  // Shortest accepted form is "ws://x" (6).
11965|  2.99k|  if (len < 6) [[unlikely]] {
  ------------------
  |  Branch (11965:7): [True: 0, False: 2.99k]
  ------------------
11966|      0|    return false;
11967|      0|  }
11968|  2.99k|  const auto* b = reinterpret_cast<const uint8_t*>(input.data());
11969|       |
11970|  2.99k|  size_t pos = 0;
11971|  2.99k|  ada::scheme::type scheme_type = ada::scheme::type::NOT_SPECIAL;
11972|  2.99k|  uint32_t protocol_end = 0;
11973|  2.99k|#if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \
11974|  2.99k|    defined(_M_X64) || defined(_M_IX86) || defined(_M_AMD64)
11975|       |  // One 8-byte load + integer compare is a single cmp/jcc on x86-64.
11976|       |  // Masked compares cover the shorter special schemes without extra loads.
11977|  2.99k|  if (len >= 8) {
  ------------------
  |  Branch (11977:7): [True: 2.99k, False: 0]
  ------------------
11978|  2.99k|    uint64_t first8 = 0;
11979|  2.99k|    std::memcpy(&first8, b, 8);
11980|  2.99k|    if (first8 == 0x2f2f3a7370747468ull) {  // "https://"
  ------------------
  |  Branch (11980:9): [True: 2.99k, False: 0]
  ------------------
11981|  2.99k|      pos = 8;
11982|  2.99k|      scheme_type = ada::scheme::type::HTTPS;
11983|  2.99k|      protocol_end = 6;
11984|  2.99k|    } else if ((first8 & 0x00ffffffffffffffull) ==
  ------------------
  |  Branch (11984:16): [True: 0, False: 0]
  ------------------
11985|      0|               0x002f2f3a70747468ull) {  // "http://"
11986|      0|      pos = 7;
11987|      0|      scheme_type = ada::scheme::type::HTTP;
11988|      0|      protocol_end = 5;
11989|      0|    } else if ((first8 & 0x0000ffffffffffffull) ==
  ------------------
  |  Branch (11989:16): [True: 0, False: 0]
  ------------------
11990|      0|               0x00002f2f3a737377ull) {  // "wss://"
11991|      0|      pos = 6;
11992|      0|      scheme_type = ada::scheme::type::WSS;
11993|      0|      protocol_end = 4;
11994|      0|    } else if ((first8 & 0x0000ffffffffffffull) ==
  ------------------
  |  Branch (11994:16): [True: 0, False: 0]
  ------------------
11995|      0|               0x00002f2f3a707466ull) {  // "ftp://"
11996|      0|      pos = 6;
11997|      0|      scheme_type = ada::scheme::type::FTP;
11998|      0|      protocol_end = 4;
11999|      0|    } else if ((first8 & 0x000000ffffffffffull) ==
  ------------------
  |  Branch (11999:16): [True: 0, False: 0]
  ------------------
12000|      0|               0x0000002f2f3a7377ull) {  // "ws://"
12001|      0|      pos = 5;
12002|      0|      scheme_type = ada::scheme::type::WS;
12003|      0|      protocol_end = 3;
12004|      0|    } else {
12005|      0|      return false;
12006|      0|    }
12007|  2.99k|  } else if (b[0] == 'w' && b[1] == 's') {
  ------------------
  |  Branch (12007:14): [True: 0, False: 0]
  |  Branch (12007:29): [True: 0, False: 0]
  ------------------
12008|      0|    if (b[2] == ':' && b[3] == '/' && b[4] == '/') {
  ------------------
  |  Branch (12008:9): [True: 0, False: 0]
  |  Branch (12008:24): [True: 0, False: 0]
  |  Branch (12008:39): [True: 0, False: 0]
  ------------------
12009|      0|      pos = 5;
12010|      0|      scheme_type = ada::scheme::type::WS;
12011|      0|      protocol_end = 3;
12012|      0|    } else if (b[2] == 's' && b[3] == ':' && b[4] == '/' && b[5] == '/') {
  ------------------
  |  Branch (12012:16): [True: 0, False: 0]
  |  Branch (12012:31): [True: 0, False: 0]
  |  Branch (12012:46): [True: 0, False: 0]
  |  Branch (12012:61): [True: 0, False: 0]
  ------------------
12013|      0|      pos = 6;
12014|      0|      scheme_type = ada::scheme::type::WSS;
12015|      0|      protocol_end = 4;
12016|      0|    } else {
12017|      0|      return false;
12018|      0|    }
12019|      0|  } else if (b[0] == 'f' && b[1] == 't' && b[2] == 'p' && b[3] == ':' &&
  ------------------
  |  Branch (12019:14): [True: 0, False: 0]
  |  Branch (12019:29): [True: 0, False: 0]
  |  Branch (12019:44): [True: 0, False: 0]
  |  Branch (12019:59): [True: 0, False: 0]
  ------------------
12020|      0|             b[4] == '/' && b[5] == '/') {
  ------------------
  |  Branch (12020:14): [True: 0, False: 0]
  |  Branch (12020:29): [True: 0, False: 0]
  ------------------
12021|      0|    pos = 6;
12022|      0|    scheme_type = ada::scheme::type::FTP;
12023|      0|    protocol_end = 4;
12024|      0|  } else if (len >= 7 && b[0] == 'h' && b[1] == 't' && b[2] == 't' &&
  ------------------
  |  Branch (12024:14): [True: 0, False: 0]
  |  Branch (12024:26): [True: 0, False: 0]
  |  Branch (12024:41): [True: 0, False: 0]
  |  Branch (12024:56): [True: 0, False: 0]
  ------------------
12025|      0|             b[3] == 'p' && b[4] == ':' && b[5] == '/' && b[6] == '/') {
  ------------------
  |  Branch (12025:14): [True: 0, False: 0]
  |  Branch (12025:29): [True: 0, False: 0]
  |  Branch (12025:44): [True: 0, False: 0]
  |  Branch (12025:59): [True: 0, False: 0]
  ------------------
12026|      0|    pos = 7;
12027|      0|    scheme_type = ada::scheme::type::HTTP;
12028|      0|    protocol_end = 5;
12029|      0|  } else {
12030|      0|    return false;
12031|      0|  }
12032|       |#else
12033|       |  // Big-endian / uncommon arches: byte-wise special-scheme match.
12034|       |  if (len >= 8 && b[0] == 'h' && b[1] == 't' && b[2] == 't' && b[3] == 'p' &&
12035|       |      b[4] == 's' && b[5] == ':' && b[6] == '/' && b[7] == '/') {
12036|       |    pos = 8;
12037|       |    scheme_type = ada::scheme::type::HTTPS;
12038|       |    protocol_end = 6;
12039|       |  } else if (len >= 7 && b[0] == 'h' && b[1] == 't' && b[2] == 't' &&
12040|       |             b[3] == 'p' && b[4] == ':' && b[5] == '/' && b[6] == '/') {
12041|       |    pos = 7;
12042|       |    scheme_type = ada::scheme::type::HTTP;
12043|       |    protocol_end = 5;
12044|       |  } else if (b[0] == 'w' && b[1] == 's') {
12045|       |    if (b[2] == ':' && b[3] == '/' && b[4] == '/') {
12046|       |      pos = 5;
12047|       |      scheme_type = ada::scheme::type::WS;
12048|       |      protocol_end = 3;
12049|       |    } else if (len >= 6 && b[2] == 's' && b[3] == ':' && b[4] == '/' &&
12050|       |               b[5] == '/') {
12051|       |      pos = 6;
12052|       |      scheme_type = ada::scheme::type::WSS;
12053|       |      protocol_end = 4;
12054|       |    } else {
12055|       |      return false;
12056|       |    }
12057|       |  } else if (b[0] == 'f' && b[1] == 't' && b[2] == 'p' && b[3] == ':' &&
12058|       |             b[4] == '/' && b[5] == '/') {
12059|       |    pos = 6;
12060|       |    scheme_type = ada::scheme::type::FTP;
12061|       |    protocol_end = 4;
12062|       |  } else {
12063|       |    return false;
12064|       |  }
12065|       |#endif
12066|  2.99k|  if (pos < len && (b[pos] == '/' || b[pos] == '\\')) [[unlikely]] {
  ------------------
  |  Branch (12066:7): [True: 2.99k, False: 0]
  |  Branch (12066:21): [True: 0, False: 2.99k]
  |  Branch (12066:38): [True: 0, False: 2.99k]
  ------------------
12067|      0|    return false;
12068|      0|  }
12069|       |
12070|       |  // Digit-led hosts are IPv4/numeric; '[' is IPv6. Skip before scanning.
12071|  2.99k|  if (pos < len && ((b[pos] >= '0' && b[pos] <= '9') || b[pos] == '[')) {
  ------------------
  |  Branch (12071:7): [True: 2.99k, False: 0]
  |  Branch (12071:22): [True: 2.99k, False: 0]
  |  Branch (12071:39): [True: 0, False: 2.99k]
  |  Branch (12071:57): [True: 0, False: 2.99k]
  ------------------
12072|      0|    return false;
12073|      0|  }
12074|       |
12075|  2.99k|  const size_t host_start = pos;
12076|  2.99k|  bool has_upper = false;
12077|  2.99k|  bool has_x = false;
12078|  2.99k|  size_t host_end = pos;
12079|  2.99k|  if (!scan_plain_host(b, pos, len, host_end, has_upper, has_x)) {
  ------------------
  |  Branch (12079:7): [True: 0, False: 2.99k]
  ------------------
12080|      0|    return false;
12081|      0|  }
12082|  2.99k|  if (host_start == host_end) [[unlikely]] {
  ------------------
  |  Branch (12082:7): [True: 0, False: 2.99k]
  ------------------
12083|      0|    return false;
12084|      0|  }
12085|  2.99k|  const size_t host_len = host_end - host_start;
12086|  2.99k|  if (host_len > 253) [[unlikely]] {
  ------------------
  |  Branch (12086:7): [True: 0, False: 2.99k]
  ------------------
12087|      0|    return false;
12088|      0|  }
12089|  2.99k|  {
12090|  2.99k|    std::string_view hv(input.data() + host_start, host_len);
12091|  2.99k|    char host_buf[256];
12092|  2.99k|    if (has_upper) [[unlikely]] {
  ------------------
  |  Branch (12092:9): [True: 0, False: 2.99k]
  ------------------
12093|      0|      std::memcpy(host_buf, input.data() + host_start, host_len);
12094|      0|      unicode::to_lower_ascii(host_buf, host_len);
12095|      0|      hv = std::string_view(host_buf, host_len);
12096|      0|    }
12097|  2.99k|    if (ada::checkers::last_label_may_be_a_number(hv)) [[unlikely]] {
  ------------------
  |  Branch (12097:9): [True: 0, False: 2.99k]
  ------------------
12098|      0|      return false;
12099|      0|    }
12100|       |    // Punycode is "xn--...". The host scan already notes a lowercase 'x';
12101|       |    // uppercase 'X' is covered by has_upper after the in-place lower.
12102|  2.99k|    static constexpr std::string_view xn{"xn-", 3};
12103|  2.99k|    if ((has_x || has_upper) && hv.find(xn) != std::string_view::npos)
  ------------------
  |  Branch (12103:10): [True: 2.99k, False: 0]
  |  Branch (12103:19): [True: 0, False: 0]
  |  Branch (12103:33): [True: 0, False: 2.99k]
  ------------------
12104|      0|        [[unlikely]] {
12105|      0|      return false;
12106|      0|    }
12107|  2.99k|  }
12108|       |
12109|  2.99k|  if (host_end < len && b[host_end] == ':') [[unlikely]] {
  ------------------
  |  Branch (12109:7): [True: 2.99k, False: 0]
  |  Branch (12109:25): [True: 0, False: 2.99k]
  ------------------
12110|      0|    return finish_simple_absolute_with_port(input, out, scheme_type,
12111|      0|                                            protocol_end, host_start, host_end,
12112|      0|                                            host_len, has_upper);
12113|      0|  }
12114|       |
12115|  2.99k|  size_t i = host_end;
12116|  2.99k|  size_t path_start = host_end;
12117|  2.99k|  size_t path_end = host_end;
12118|  2.99k|  size_t query_start = std::string_view::npos;
12119|  2.99k|  size_t hash_start = std::string_view::npos;
12120|  2.99k|  bool has_path = false;
12121|  2.99k|  bool maybe_dot_segment = false;
12122|  2.99k|  bool rest_simple = true;
12123|       |
12124|  2.99k|  if (i < len && b[i] == '/') {
  ------------------
  |  Branch (12124:7): [True: 2.99k, False: 0]
  |  Branch (12124:18): [True: 2.99k, False: 0]
  ------------------
12125|  2.99k|    has_path = true;
12126|  2.99k|    path_start = i;
12127|  2.99k|    ++i;
12128|  2.99k|    scan_path_run(b, i, len, maybe_dot_segment);
12129|  2.99k|    if (i < len) {
  ------------------
  |  Branch (12129:9): [True: 2.99k, False: 0]
  ------------------
12130|  2.99k|      const uint8_t cls = k_path[b[i]];
12131|  2.99k|      if (cls == 1) {
  ------------------
  |  Branch (12131:11): [True: 2.99k, False: 0]
  ------------------
12132|  2.99k|        path_end = i;
12133|  2.99k|        if (b[i] == '?') {
  ------------------
  |  Branch (12133:13): [True: 2.99k, False: 0]
  ------------------
12134|  2.99k|          query_start = i;
12135|  2.99k|          ++i;
12136|  2.99k|          goto scan_query;
12137|  2.99k|        }
12138|      0|        hash_start = i;
12139|      0|        ++i;
12140|      0|        goto scan_hash;
12141|  2.99k|      }
12142|      0|      rest_simple = false;
12143|      0|      for (; i < len; ++i) {
  ------------------
  |  Branch (12143:14): [True: 0, False: 0]
  ------------------
12144|      0|        if (b[i] == '?') {
  ------------------
  |  Branch (12144:13): [True: 0, False: 0]
  ------------------
12145|      0|          path_end = i;
12146|      0|          query_start = i;
12147|      0|          ++i;
12148|      0|          goto scan_query_boundary;
12149|      0|        }
12150|      0|        if (b[i] == '#') {
  ------------------
  |  Branch (12150:13): [True: 0, False: 0]
  ------------------
12151|      0|          path_end = i;
12152|      0|          hash_start = i;
12153|      0|          ++i;
12154|      0|          goto after_rest;
12155|      0|        }
12156|      0|      }
12157|      0|      path_end = i;
12158|      0|      goto after_rest;
12159|      0|    }
12160|      0|    path_end = i;
12161|      0|  } else if (i < len && b[i] == '?') {
  ------------------
  |  Branch (12161:14): [True: 0, False: 0]
  |  Branch (12161:25): [True: 0, False: 0]
  ------------------
12162|      0|    query_start = i;
12163|      0|    ++i;
12164|      0|    goto scan_query;
12165|      0|  } else if (i < len && b[i] == '#') {
  ------------------
  |  Branch (12165:14): [True: 0, False: 0]
  |  Branch (12165:25): [True: 0, False: 0]
  ------------------
12166|      0|    hash_start = i;
12167|      0|    ++i;
12168|      0|    goto scan_hash;
12169|      0|  }
12170|      0|  goto after_rest;
12171|       |
12172|  2.99k|scan_query:
12173|  2.99k|  scan_query_run(b, i, len);
12174|  2.99k|  if (i < len) {
  ------------------
  |  Branch (12174:7): [True: 1.61k, False: 1.37k]
  ------------------
12175|  1.61k|    if (b[i] == '#') {
  ------------------
  |  Branch (12175:9): [True: 285, False: 1.33k]
  ------------------
12176|    285|      hash_start = i;
12177|    285|      ++i;
12178|    285|      goto scan_hash;
12179|    285|    }
12180|  1.33k|    rest_simple = false;
12181|  1.33k|    goto scan_query_boundary;
12182|  1.61k|  }
12183|  1.37k|  goto after_rest;
12184|       |
12185|  1.37k|scan_query_boundary:
12186|  52.8k|  for (; i < len; ++i) {
  ------------------
  |  Branch (12186:10): [True: 51.7k, False: 1.14k]
  ------------------
12187|  51.7k|    if (b[i] == '#') {
  ------------------
  |  Branch (12187:9): [True: 191, False: 51.5k]
  ------------------
12188|    191|      hash_start = i;
12189|    191|      ++i;
12190|    191|      goto after_rest;
12191|    191|    }
12192|  51.7k|  }
12193|  1.14k|  goto after_rest;
12194|       |
12195|  1.14k|scan_hash:
12196|    285|  scan_hash_run(b, i, len);
12197|    285|  if (i < len) {
  ------------------
  |  Branch (12197:7): [True: 207, False: 78]
  ------------------
12198|    207|    rest_simple = false;
12199|    207|  }
12200|       |
12201|  2.99k|after_rest:
12202|  2.99k|  if (rest_simple && maybe_dot_segment) {
  ------------------
  |  Branch (12202:7): [True: 1.45k, False: 1.53k]
  |  Branch (12202:22): [True: 0, False: 1.45k]
  ------------------
12203|      0|    const std::string_view path_body(input.data() + path_start,
12204|      0|                                     path_end - path_start);
12205|      0|    if (path_has_dot_segment(path_body)) {
  ------------------
  |  Branch (12205:9): [True: 0, False: 0]
  ------------------
12206|      0|      rest_simple = false;
12207|      0|    }
12208|      0|  }
12209|       |
12210|       |  // The slow path removes ASCII tab/newline anywhere in the input and trims a
12211|       |  // trailing C0 control or space; this fast path does neither. A query or
12212|       |  // fragment reaching the helpers below would keep those bytes percent-encoded
12213|       |  // ("?a\nb" -> "?a%0Ab", "#f " -> "#f%20") instead of stripped, so hand such
12214|       |  // inputs back to the slow path.
12215|  2.99k|  if (!rest_simple && (unicode::is_c0_control_or_space(input.back()) ||
  ------------------
  |  Branch (12215:7): [True: 1.53k, False: 1.45k]
  |  Branch (12215:24): [True: 365, False: 1.17k]
  ------------------
12216|  1.17k|                       unicode::has_tabs_or_newline(input))) {
  ------------------
  |  Branch (12216:24): [True: 144, False: 1.03k]
  ------------------
12217|    509|    return false;
12218|    509|  }
12219|       |
12220|  2.48k|  out.type = scheme_type;
12221|  2.48k|  out.is_valid = true;
12222|  2.48k|  out.has_opaque_path = false;
12223|  2.48k|  out.host_type = DEFAULT;
12224|       |
12225|  2.48k|  if (!rest_simple) {
  ------------------
  |  Branch (12225:7): [True: 1.03k, False: 1.45k]
  ------------------
12226|       |    // Host is a plain domain. Finish path/query/hash with
12227|       |    // the regular helpers
12228|       |    // so percent-encoding and dot segments do not re-parse the authority.
12229|  1.03k|    const std::string_view path_view =
12230|  1.03k|        has_path
  ------------------
  |  Branch (12230:9): [True: 1.03k, False: 0]
  ------------------
12231|  1.03k|            ? std::string_view(input.data() + path_start, path_end - path_start)
12232|  1.03k|            : std::string_view{};
12233|  1.03k|    auto apply_query_and_hash = [&]() {
12234|  1.03k|      if (query_start != std::string_view::npos) {
12235|  1.03k|        const size_t q_end =
12236|  1.03k|            (hash_start != std::string_view::npos) ? hash_start : len;
12237|  1.03k|        out.update_base_search(std::string_view(input.data() + query_start + 1,
12238|  1.03k|                                                q_end - query_start - 1),
12239|  1.03k|                               character_sets::SPECIAL_QUERY_PERCENT_ENCODE);
12240|  1.03k|      }
12241|  1.03k|      if (hash_start != std::string_view::npos) {
12242|  1.03k|        out.update_unencoded_base_hash(std::string_view(
12243|  1.03k|            input.data() + hash_start + 1, len - hash_start - 1));
12244|  1.03k|      }
12245|  1.03k|    };
12246|  1.03k|    if constexpr (is_aggregator) {
12247|  1.03k|      out.buffer.assign(input.substr(0, host_end));
12248|  1.03k|      if (has_upper) {
  ------------------
  |  Branch (12248:11): [True: 0, False: 1.03k]
  ------------------
12249|      0|        unicode::to_lower_ascii(out.buffer.data() + host_start, host_len);
12250|      0|      }
12251|  1.03k|      out.components.protocol_end = protocol_end;
12252|  1.03k|      out.components.username_end = protocol_end + 2;
12253|  1.03k|      out.components.host_start = protocol_end + 2;
12254|  1.03k|      out.components.host_end = static_cast<uint32_t>(host_end);
12255|  1.03k|      out.components.port = url_components::omitted;
12256|  1.03k|      out.components.pathname_start = static_cast<uint32_t>(host_end);
12257|  1.03k|      out.components.search_start = url_components::omitted;
12258|  1.03k|      out.components.hash_start = url_components::omitted;
12259|  1.03k|      out.parse_path(path_view);
12260|  1.03k|      apply_query_and_hash();
12261|       |    } else {
12262|       |      std::string host_str(input.substr(host_start, host_len));
12263|       |      if (has_upper) {
12264|       |        unicode::to_lower_ascii(host_str.data(), host_str.size());
12265|       |      }
12266|       |      out.host = std::move(host_str);
12267|       |      out.parse_path(path_view);
12268|       |      apply_query_and_hash();
12269|       |    }
12270|  1.03k|    return true;
12271|  1.03k|  }
12272|       |
12273|  1.45k|  const bool need_slash = !has_path;
12274|  1.45k|  if constexpr (is_aggregator) {
12275|  1.45k|    if (!need_slash) {
  ------------------
  |  Branch (12275:9): [True: 1.45k, False: 0]
  ------------------
12276|       |      // assign copies once. resize()+memcpy would value-init then overwrite.
12277|  1.45k|      out.buffer.assign(input);
12278|  1.45k|      if (has_upper) {
  ------------------
  |  Branch (12278:11): [True: 0, False: 1.45k]
  ------------------
12279|      0|        unicode::to_lower_ascii(out.buffer.data() + host_start, host_len);
12280|      0|      }
12281|  1.45k|      out.components.protocol_end = protocol_end;
12282|  1.45k|      out.components.username_end = protocol_end + 2;
12283|  1.45k|      out.components.host_start = protocol_end + 2;
12284|  1.45k|      out.components.host_end = static_cast<uint32_t>(host_end);
12285|  1.45k|      out.components.port = url_components::omitted;
12286|  1.45k|      out.components.pathname_start = static_cast<uint32_t>(path_start);
12287|  1.45k|      out.components.search_start = (query_start != std::string_view::npos)
  ------------------
  |  Branch (12287:37): [True: 1.45k, False: 0]
  ------------------
12288|  1.45k|                                        ? static_cast<uint32_t>(query_start)
12289|  1.45k|                                        : url_components::omitted;
12290|  1.45k|      out.components.hash_start = (hash_start != std::string_view::npos)
  ------------------
  |  Branch (12290:35): [True: 78, False: 1.37k]
  ------------------
12291|  1.45k|                                      ? static_cast<uint32_t>(hash_start)
12292|  1.45k|                                      : url_components::omitted;
12293|  1.45k|    } else {
12294|      0|      out.buffer.clear();
12295|      0|      out.buffer.reserve(len + 1);
12296|      0|      out.buffer.append(input.substr(0, host_end));
12297|      0|      out.buffer.push_back('/');
12298|      0|      if (host_end < len) {
  ------------------
  |  Branch (12298:11): [True: 0, False: 0]
  ------------------
12299|      0|        out.buffer.append(input.substr(host_end));
12300|      0|      }
12301|      0|      if (has_upper) {
  ------------------
  |  Branch (12301:11): [True: 0, False: 0]
  ------------------
12302|      0|        unicode::to_lower_ascii(out.buffer.data() + host_start, host_len);
12303|      0|      }
12304|      0|      out.components.protocol_end = protocol_end;
12305|      0|      out.components.username_end = protocol_end + 2;
12306|      0|      out.components.host_start = protocol_end + 2;
12307|      0|      out.components.host_end = static_cast<uint32_t>(host_end);
12308|      0|      out.components.port = url_components::omitted;
12309|      0|      out.components.pathname_start = static_cast<uint32_t>(host_end);
12310|      0|      out.components.search_start = (query_start != std::string_view::npos)
  ------------------
  |  Branch (12310:37): [True: 0, False: 0]
  ------------------
12311|      0|                                        ? static_cast<uint32_t>(query_start + 1)
12312|      0|                                        : url_components::omitted;
12313|      0|      out.components.hash_start = (hash_start != std::string_view::npos)
  ------------------
  |  Branch (12313:35): [True: 0, False: 0]
  ------------------
12314|      0|                                      ? static_cast<uint32_t>(hash_start + 1)
12315|      0|                                      : url_components::omitted;
12316|      0|    }
12317|       |  } else {
12318|       |    std::string host_str(input.substr(host_start, host_len));
12319|       |    if (has_upper) {
12320|       |      unicode::to_lower_ascii(host_str.data(), host_str.size());
12321|       |    }
12322|       |    out.host = std::move(host_str);
12323|       |    if (need_slash) {
12324|       |      out.path = "/";
12325|       |    } else {
12326|       |      out.path.assign(input.data() + path_start, path_end - path_start);
12327|       |    }
12328|       |    if (query_start != std::string_view::npos) {
12329|       |      const size_t q_end =
12330|       |          (hash_start != std::string_view::npos) ? hash_start : len;
12331|       |      out.query.emplace(input.data() + query_start + 1,
12332|       |                        q_end - query_start - 1);
12333|       |    }
12334|       |    if (hash_start != std::string_view::npos) {
12335|       |      out.hash.emplace(input.data() + hash_start + 1, len - hash_start - 1);
12336|       |    }
12337|       |  }
12338|  1.45k|  return true;
12339|  2.48k|}
_ZN3ada6parser14parse_url_implINS_14url_aggregatorELb1EEET_NSt3__117basic_string_viewIcNS4_11char_traitsIcEEEEPKS3_:
12528|  2.99k|                           const result_type* base_url) {
12529|       |  // We can specialize the implementation per type.
12530|       |  // Important: result_type_is_ada_url is evaluated at *compile time*. This
12531|       |  // means that doing if constexpr(result_type_is_ada_url) { something } else {
12532|       |  // something else } is free (at runtime). This means that ada::url_aggregator
12533|       |  // and ada::url **do not have to support the exact same API**.
12534|  2.99k|  constexpr bool result_type_is_ada_url = std::is_same_v<url, result_type>;
12535|  2.99k|  constexpr bool result_type_is_ada_url_aggregator =
12536|  2.99k|      std::is_same_v<url_aggregator, result_type>;
12537|  2.99k|  static_assert(result_type_is_ada_url ||
12538|  2.99k|                result_type_is_ada_url_aggregator);  // We don't support
12539|       |                                                     // anything else for now.
12540|       |
12541|  2.99k|  ada_log("ada::parser::parse_url('", user_input, "' [", user_input.size(),
12542|  2.99k|          " bytes],", (base_url != nullptr ? base_url->to_string() : "null"),
12543|  2.99k|          ")");
12544|       |
12545|  2.99k|  result_type url{};
12546|       |
12547|  2.99k|  const uint32_t max_input_length = ada::get_max_input_length();
12548|       |
12549|       |  // Normalization (percent-encoding, IDNA) can push the serialized URL past
12550|       |  // max_input_length even when the input fit under it. The check at the end of
12551|       |  // the state machine covers URLs that run to completion, but several states
12552|       |  // return early after appending a query or fragment, so run the same check on
12553|       |  // those exits too. Without this, a query- or fragment-terminated URL such as
12554|       |  // file://x/?<...> or https://user@x/?<...> is accepted while the equivalent
12555|       |  // https://x/?<...> that takes the absolute fast path is rejected.
12556|  2.99k|  const auto enforce_max_input_length = [&]() {
12557|  2.99k|    if constexpr (store_values) {
12558|  2.99k|      if (url.is_valid) {
12559|  2.99k|        if constexpr (result_type_is_ada_url_aggregator) {
12560|  2.99k|          if (url.buffer.size() > max_input_length) [[unlikely]] {
12561|  2.99k|            url.is_valid = false;
12562|  2.99k|          }
12563|  2.99k|        } else {
12564|  2.99k|          if (url.get_href_size() > max_input_length) [[unlikely]] {
12565|  2.99k|            url.is_valid = false;
12566|  2.99k|          }
12567|  2.99k|        }
12568|  2.99k|      }
12569|  2.99k|    }
12570|  2.99k|  };
12571|       |
12572|       |  // We refuse to parse URL strings that exceed the maximum input length.
12573|       |  // By default, this is 4GB but can be configured via
12574|       |  // ada::set_max_input_length().
12575|  2.99k|  if (user_input.size() > max_input_length) [[unlikely]] {
  ------------------
  |  Branch (12575:7): [True: 0, False: 2.99k]
  ------------------
12576|      0|    url.is_valid = false;
12577|      0|  }
12578|       |  // Going forward, user_input.size() is in [0,
12579|       |  // std::numeric_limits<uint32_t>::max). If we are provided with an invalid
12580|       |  // base, or the optional_url was invalid, we must return.
12581|  2.99k|  if (base_url != nullptr) {
  ------------------
  |  Branch (12581:7): [True: 0, False: 2.99k]
  ------------------
12582|      0|    url.is_valid &= base_url->is_valid;
12583|      0|  }
12584|  2.99k|  if (!url.is_valid) {
  ------------------
  |  Branch (12584:7): [True: 0, False: 2.99k]
  ------------------
12585|      0|    return url;
12586|      0|  }
12587|       |
12588|       |  // Simple absolute / relative fast paths (before tabs/newline scan).
12589|  2.99k|  if constexpr (store_values) {
12590|  2.99k|    bool hit_fast_path = false;
12591|  2.99k|    if (base_url == nullptr) {
  ------------------
  |  Branch (12591:9): [True: 2.99k, False: 0]
  ------------------
12592|       |      // IPv4/IPv6 and userinfo miss the fast path. Skip the never_inline
12593|       |      // call so those URLs (including SetHref) do not pay for a miss.
12594|  2.99k|      const auto* p = reinterpret_cast<const uint8_t*>(user_input.data());
12595|  2.99k|      const size_t n = user_input.size();
12596|  2.99k|      size_t host_start = 0;
12597|  2.99k|      if (n >= 8 && p[4] == ':' && p[5] == '/' && p[6] == '/') {
  ------------------
  |  Branch (12597:11): [True: 2.99k, False: 0]
  |  Branch (12597:21): [True: 0, False: 2.99k]
  |  Branch (12597:36): [True: 0, False: 0]
  |  Branch (12597:51): [True: 0, False: 0]
  ------------------
12598|      0|        host_start = 7;
12599|  2.99k|      } else if (n >= 9 && p[5] == ':' && p[6] == '/' && p[7] == '/') {
  ------------------
  |  Branch (12599:18): [True: 2.99k, False: 0]
  |  Branch (12599:28): [True: 2.99k, False: 0]
  |  Branch (12599:43): [True: 2.99k, False: 0]
  |  Branch (12599:58): [True: 2.99k, False: 0]
  ------------------
12600|  2.99k|        host_start = 8;
12601|  2.99k|      }
12602|  2.99k|      const uint8_t host_first = host_start != 0 ? p[host_start] : 0;
  ------------------
  |  Branch (12602:34): [True: 2.99k, False: 0]
  ------------------
12603|  2.99k|      const bool skip_ip =
12604|  2.99k|          host_first == '[' || (host_first >= '0' && host_first <= '9');
  ------------------
  |  Branch (12604:11): [True: 0, False: 2.99k]
  |  Branch (12604:33): [True: 2.99k, False: 0]
  |  Branch (12604:54): [True: 0, False: 2.99k]
  ------------------
12605|  2.99k|      const bool skip_userinfo =
12606|  2.99k|          host_start != 0 && authority_has_at(p, host_start, n);
  ------------------
  |  Branch (12606:11): [True: 2.99k, False: 0]
  |  Branch (12606:30): [True: 0, False: 2.99k]
  ------------------
12607|  2.99k|      hit_fast_path = !skip_ip && !skip_userinfo &&
  ------------------
  |  Branch (12607:23): [True: 2.99k, False: 0]
  |  Branch (12607:35): [True: 2.99k, False: 0]
  ------------------
12608|  2.99k|                      try_parse_simple_absolute(user_input, url);
  ------------------
  |  Branch (12608:23): [True: 2.48k, False: 509]
  ------------------
12609|  2.99k|    } else {
12610|      0|      hit_fast_path = try_parse_simple_relative(user_input, *base_url, url);
12611|      0|    }
12612|  2.99k|    if (hit_fast_path) {
  ------------------
  |  Branch (12612:9): [True: 2.48k, False: 509]
  ------------------
12613|  2.48k|      if constexpr (result_type_is_ada_url_aggregator) {
12614|  2.48k|        if (url.buffer.size() > max_input_length) [[unlikely]] {
  ------------------
  |  Branch (12614:13): [True: 0, False: 2.48k]
  ------------------
12615|      0|          url.is_valid = false;
12616|      0|        }
12617|       |      } else {
12618|       |        // For a small absolute input, even worst-case normalization cannot
12619|       |        // exceed the limit: percent encoding expands at most 3x and IDNA at
12620|       |        // most 4.5x. Avoid traversing every stored component on the common
12621|       |        // default-limit path.
12622|       |        if ((base_url != nullptr ||
12623|       |             user_input.size() > static_cast<size_t>(max_input_length) / 5) &&
12624|       |            url.get_href_size() > max_input_length) [[unlikely]] {
12625|       |          url.is_valid = false;
12626|       |        }
12627|       |      }
12628|  2.48k|      return url;
12629|  2.48k|    }
12630|  2.99k|  }
12631|       |
12632|    509|  state state = state::SCHEME_START;
12633|       |
12634|  2.99k|  std::string tmp_buffer;
12635|  2.99k|  std::string_view url_data;
12636|  2.99k|  if (unicode::has_tabs_or_newline(user_input)) [[unlikely]] {
  ------------------
  |  Branch (12636:7): [True: 241, False: 2.75k]
  ------------------
12637|    241|    tmp_buffer = user_input;
12638|       |    // Optimization opportunity: Instead of copying and then pruning, we could
12639|       |    // just directly build the string from user_input.
12640|    241|    helpers::remove_ascii_tab_or_newline(tmp_buffer);
12641|    241|    url_data = tmp_buffer;
12642|  2.75k|  } else [[likely]] {
12643|  2.75k|    url_data = user_input;
12644|  2.75k|  }
12645|       |
12646|       |  // Leading and trailing control characters are uncommon and easy to deal with
12647|       |  // (no performance concern).
12648|  2.99k|  helpers::trim_c0_whitespace(url_data);
12649|       |
12650|  2.99k|  if constexpr (result_type_is_ada_url_aggregator && store_values) {
12651|       |    // Most of the time, we just need user_input.size().
12652|       |    // In some instances, we may need a bit more.
12653|       |    ///////////////////////////
12654|       |    // This is *very* important. This line should *not* be removed
12655|       |    // hastily. There are principled reasons why reserve is important
12656|       |    // for performance. If you have a benchmark with small inputs,
12657|       |    // it may not matter, but in other instances, it could.
12658|       |    ////
12659|       |    // This rounds up to the next power of two.
12660|       |    // We know that user_input.size() is in [0,
12661|       |    // std::numeric_limits<uint32_t>::max).
12662|  2.99k|    uint32_t reserve_capacity =
12663|  2.99k|        (0xFFFFFFFF >>
12664|  2.99k|         helpers::leading_zeroes(uint32_t(1 | user_input.size()))) +
12665|  2.99k|        1;
12666|  2.99k|    url.reserve(reserve_capacity);
12667|  2.99k|  }
12668|       |
12669|       |  // Optimization opportunity. Most websites do not have fragment.
12670|  2.99k|  std::optional<std::string_view> fragment = helpers::prune_hash(url_data);
12671|       |  // We add it last so that an implementation like ada::url_aggregator
12672|       |  // can append it last to its internal buffer, thus improving performance.
12673|       |
12674|       |  // Here url_data no longer has its fragment.
12675|       |  // We are going to access the data from url_data (it is immutable).
12676|       |  // At any given time, we are pointing at byte 'input_position' in url_data.
12677|       |  // The input_position variable should range from 0 to input_size.
12678|       |  // It is illegal to access url_data at input_size.
12679|  2.99k|  size_t input_position = 0;
12680|  2.99k|  const size_t input_size = url_data.size();
12681|       |  // Keep running the following state machine by switching on state.
12682|       |  // If after a run pointer points to the EOF code point, go to the next step.
12683|       |  // Otherwise, increase pointer by 1 and continue with the state machine.
12684|       |  // We never decrement input_position.
12685|  6.55k|  while (input_position <= input_size) {
  ------------------
  |  Branch (12685:10): [True: 4.07k, False: 2.48k]
  ------------------
12686|  4.07k|    ada_log("In parsing at ", input_position, " out of ", input_size,
12687|  4.07k|            " in state ", ada::to_string(state));
12688|  4.07k|    switch (state) {
12689|    509|      case state::SCHEME_START: {
  ------------------
  |  Branch (12689:7): [True: 509, False: 3.56k]
  ------------------
12690|    509|        ada_log("SCHEME_START ", helpers::substring(url_data, input_position));
12691|       |        // If c is an ASCII alpha, append c, lowercased, to buffer, and set
12692|       |        // state to scheme state.
12693|    509|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12693:13): [True: 509, False: 0]
  ------------------
12694|    509|            checkers::is_alpha(url_data[input_position])) {
  ------------------
  |  Branch (12694:13): [True: 509, False: 0]
  ------------------
12695|    509|          state = state::SCHEME;
12696|    509|          input_position++;
12697|    509|        } else {
12698|       |          // Otherwise, if state override is not given, set state to no scheme
12699|       |          // state and decrease pointer by 1.
12700|      0|          state = state::NO_SCHEME;
12701|      0|        }
12702|    509|        break;
12703|      0|      }
12704|    509|      case state::SCHEME: {
  ------------------
  |  Branch (12704:7): [True: 509, False: 3.56k]
  ------------------
12705|    509|        ada_log("SCHEME ", helpers::substring(url_data, input_position));
12706|       |        // If c is an ASCII alphanumeric, U+002B (+), U+002D (-), or U+002E (.),
12707|       |        // append c, lowercased, to buffer.
12708|  2.54k|        while ((input_position != input_size) &&
  ------------------
  |  Branch (12708:16): [True: 2.54k, False: 0]
  ------------------
12709|  2.54k|               (unicode::is_alnum_plus(url_data[input_position]))) {
  ------------------
  |  Branch (12709:16): [True: 2.03k, False: 509]
  ------------------
12710|  2.03k|          input_position++;
12711|  2.03k|        }
12712|       |        // Otherwise, if c is U+003A (:), then:
12713|    509|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12713:13): [True: 509, False: 0]
  ------------------
12714|    509|            (url_data[input_position] == ':')) {
  ------------------
  |  Branch (12714:13): [True: 509, False: 0]
  ------------------
12715|    509|          ada_log("SCHEME the scheme should be ",
12716|    509|                  url_data.substr(0, input_position));
12717|       |          if constexpr (result_type_is_ada_url) {
12718|       |            if (!url.parse_scheme(url_data.substr(0, input_position))) {
12719|       |              return url;
12720|       |            }
12721|    509|          } else {
12722|       |            // we pass the colon along instead of painfully adding it back.
12723|    509|            if (!url.parse_scheme_with_colon(
  ------------------
  |  Branch (12723:17): [True: 0, False: 509]
  ------------------
12724|    509|                    url_data.substr(0, input_position + 1))) {
12725|      0|              return url;
12726|      0|            }
12727|    509|          }
12728|    509|          ada_log("SCHEME the scheme is ", url.get_protocol());
12729|       |
12730|       |          // If url's scheme is "file", then:
12731|       |          // NOLINTNEXTLINE(bugprone-branch-clone)
12732|    509|          if (url.type == scheme::type::FILE) {
  ------------------
  |  Branch (12732:15): [True: 0, False: 509]
  ------------------
12733|       |            // Set state to file state.
12734|      0|            state = state::FILE;
12735|      0|          }
12736|       |          // Otherwise, if url is special, base is non-null, and base's scheme
12737|       |          // is url's scheme: Note: Doing base_url->scheme is unsafe if base_url
12738|       |          // != nullptr is false.
12739|    509|          else if (url.is_special() && base_url != nullptr &&
  ------------------
  |  Branch (12739:20): [True: 509, False: 0]
  |  Branch (12739:40): [True: 0, False: 509]
  ------------------
12740|      0|                   base_url->type == url.type) {
  ------------------
  |  Branch (12740:20): [True: 0, False: 0]
  ------------------
12741|       |            // Set state to special relative or authority state.
12742|      0|            state = state::SPECIAL_RELATIVE_OR_AUTHORITY;
12743|      0|          }
12744|       |          // Otherwise, if url is special, set state to special authority
12745|       |          // slashes state.
12746|    509|          else if (url.is_special()) {
  ------------------
  |  Branch (12746:20): [True: 509, False: 0]
  ------------------
12747|    509|            state = state::SPECIAL_AUTHORITY_SLASHES;
12748|    509|          }
12749|       |          // Otherwise, if remaining starts with an U+002F (/), set state to
12750|       |          // path or authority state and increase pointer by 1.
12751|      0|          else if (input_position + 1 < input_size &&
  ------------------
  |  Branch (12751:20): [True: 0, False: 0]
  ------------------
12752|      0|                   url_data[input_position + 1] == '/') {
  ------------------
  |  Branch (12752:20): [True: 0, False: 0]
  ------------------
12753|      0|            state = state::PATH_OR_AUTHORITY;
12754|      0|            input_position++;
12755|      0|          }
12756|       |          // Otherwise, set url's path to the empty string and set state to
12757|       |          // opaque path state.
12758|      0|          else {
12759|      0|            state = state::OPAQUE_PATH;
12760|      0|          }
12761|    509|        }
12762|       |        // Otherwise, if state override is not given, set buffer to the empty
12763|       |        // string, state to no scheme state, and start over (from the first code
12764|       |        // point in input).
12765|      0|        else {
12766|      0|          state = state::NO_SCHEME;
12767|      0|          input_position = 0;
12768|      0|          break;
12769|      0|        }
12770|    509|        input_position++;
12771|    509|        break;
12772|    509|      }
12773|      0|      case state::NO_SCHEME: {
  ------------------
  |  Branch (12773:7): [True: 0, False: 4.07k]
  ------------------
12774|      0|        ada_log("NO_SCHEME ", helpers::substring(url_data, input_position));
12775|       |        // The fragment was pruned from url_data before the state machine ran,
12776|       |        // so 'c is U+0023 (#)' holds exactly when a fragment was found and
12777|       |        // nothing else remains in front of it.
12778|      0|        const bool c_is_hash =
12779|      0|            fragment.has_value() && input_position == input_size;
  ------------------
  |  Branch (12779:13): [True: 0, False: 0]
  |  Branch (12779:37): [True: 0, False: 0]
  ------------------
12780|       |        // If base is null, or base has an opaque path and c is not U+0023 (#),
12781|       |        // validation error, return failure.
12782|      0|        if (base_url == nullptr || (base_url->has_opaque_path && !c_is_hash)) {
  ------------------
  |  Branch (12782:13): [True: 0, False: 0]
  |  Branch (12782:37): [True: 0, False: 0]
  |  Branch (12782:66): [True: 0, False: 0]
  ------------------
12783|      0|          ada_log("NO_SCHEME validation error");
12784|      0|          url.is_valid = false;
12785|      0|          return url;
12786|      0|        }
12787|       |        // Otherwise, if base has an opaque path and c is U+0023 (#),
12788|       |        // set url's scheme to base's scheme, url's path to base's path, url's
12789|       |        // query to base's query, and set state to fragment state.
12790|      0|        else if (base_url->has_opaque_path && c_is_hash) {
  ------------------
  |  Branch (12790:18): [True: 0, False: 0]
  |  Branch (12790:47): [True: 0, False: 0]
  ------------------
12791|      0|          ada_log("NO_SCHEME opaque base with fragment");
12792|      0|          url.copy_scheme(*base_url);
12793|      0|          url.has_opaque_path = base_url->has_opaque_path;
12794|       |
12795|       |          if constexpr (result_type_is_ada_url) {
12796|       |            url.path = base_url->path;
12797|       |            url.query = base_url->query;
12798|      0|          } else {
12799|      0|            url.update_base_pathname(base_url->get_pathname());
12800|      0|            if (base_url->has_search()) {
  ------------------
  |  Branch (12800:17): [True: 0, False: 0]
  ------------------
12801|       |              // get_search() returns "" for an empty query string (URL ends
12802|       |              // with '?'). update_base_search("") would incorrectly clear the
12803|       |              // query, so pass "?" to preserve the empty query distinction.
12804|      0|              auto s = base_url->get_search();
12805|      0|              url.update_base_search(s.empty() ? std::string_view("?") : s);
  ------------------
  |  Branch (12805:38): [True: 0, False: 0]
  ------------------
12806|      0|            }
12807|      0|          }
12808|      0|          url.update_unencoded_base_hash(*fragment);
12809|      0|          enforce_max_input_length();
12810|      0|          return url;
12811|      0|        }
12812|       |        // Otherwise, if base's scheme is not "file", set state to relative
12813|       |        // state and decrease pointer by 1.
12814|       |        // NOLINTNEXTLINE(bugprone-branch-clone)
12815|      0|        else if (base_url->type != scheme::type::FILE) {
  ------------------
  |  Branch (12815:18): [True: 0, False: 0]
  ------------------
12816|      0|          ada_log("NO_SCHEME non-file relative path");
12817|      0|          state = state::RELATIVE_SCHEME;
12818|      0|        }
12819|       |        // Otherwise, set state to file state and decrease pointer by 1.
12820|      0|        else {
12821|      0|          ada_log("NO_SCHEME file base type");
12822|      0|          state = state::FILE;
12823|      0|        }
12824|      0|        break;
12825|      0|      }
12826|    509|      case state::AUTHORITY: {
  ------------------
  |  Branch (12826:7): [True: 509, False: 3.56k]
  ------------------
12827|    509|        ada_log("AUTHORITY ", helpers::substring(url_data, input_position));
12828|       |        // most URLs have no @. Having no @ tells us that we don't have to worry
12829|       |        // about AUTHORITY. Of course, we could have @ and still not have to
12830|       |        // worry about AUTHORITY.
12831|       |        // TODO: Instead of just collecting a bool, collect the location of the
12832|       |        // '@' and do something useful with it.
12833|       |        // TODO: We could do various processing early on, using a single pass
12834|       |        // over the string to collect information about it, e.g., telling us
12835|       |        // whether there is a @ and if so, where (or how many).
12836|       |
12837|       |        // Check if url data contains an @.
12838|    509|        if (url_data.find('@', input_position) == std::string_view::npos) {
  ------------------
  |  Branch (12838:13): [True: 461, False: 48]
  ------------------
12839|    461|          state = state::HOST;
12840|    461|          break;
12841|    461|        }
12842|     48|        bool at_sign_seen{false};
12843|     48|        bool password_token_seen{false};
12844|       |        /**
12845|       |         * We expect something of the sort...
12846|       |         * https://user:pass@example.com:1234/foo/bar?baz#quux
12847|       |         * --------^
12848|       |         */
12849|     48|        do {
12850|     48|          std::string_view view = url_data.substr(input_position);
12851|       |          // The delimiters are @, /, ? \\.
12852|     48|          size_t location =
12853|     48|              url.is_special() ? helpers::find_authority_delimiter_special(view)
  ------------------
  |  Branch (12853:15): [True: 48, False: 0]
  ------------------
12854|     48|                               : helpers::find_authority_delimiter(view);
12855|     48|          std::string_view authority_view = view.substr(0, location);
12856|     48|          size_t end_of_authority = input_position + authority_view.size();
12857|       |          // If c is U+0040 (@), then:
12858|     48|          if ((end_of_authority != input_size) &&
  ------------------
  |  Branch (12858:15): [True: 48, False: 0]
  ------------------
12859|     48|              (url_data[end_of_authority] == '@')) {
  ------------------
  |  Branch (12859:15): [True: 0, False: 48]
  ------------------
12860|       |            // If atSignSeen is true, then prepend "%40" to buffer.
12861|      0|            if (at_sign_seen) {
  ------------------
  |  Branch (12861:17): [True: 0, False: 0]
  ------------------
12862|      0|              if (password_token_seen) {
  ------------------
  |  Branch (12862:19): [True: 0, False: 0]
  ------------------
12863|       |                if constexpr (result_type_is_ada_url) {
12864|       |                  url.password += "%40";
12865|      0|                } else {
12866|      0|                  url.append_base_password("%40");
12867|      0|                }
12868|      0|              } else {
12869|       |                if constexpr (result_type_is_ada_url) {
12870|       |                  url.username += "%40";
12871|      0|                } else {
12872|      0|                  url.append_base_username("%40");
12873|      0|                }
12874|      0|              }
12875|      0|            }
12876|       |
12877|      0|            at_sign_seen = true;
12878|       |
12879|      0|            if (!password_token_seen) {
  ------------------
  |  Branch (12879:17): [True: 0, False: 0]
  ------------------
12880|      0|              size_t password_token_location = authority_view.find(':');
12881|      0|              password_token_seen =
12882|      0|                  password_token_location != std::string_view::npos;
12883|       |
12884|      0|              if constexpr (store_values) {
12885|      0|                if (!password_token_seen) {
  ------------------
  |  Branch (12885:21): [True: 0, False: 0]
  ------------------
12886|       |                  if constexpr (result_type_is_ada_url) {
12887|       |                    url.username += unicode::percent_encode(
12888|       |                        authority_view,
12889|       |                        character_sets::USERINFO_PERCENT_ENCODE);
12890|      0|                  } else {
12891|      0|                    url.append_base_username(unicode::percent_encode(
12892|      0|                        authority_view,
12893|      0|                        character_sets::USERINFO_PERCENT_ENCODE));
12894|      0|                  }
12895|      0|                } else {
12896|       |                  if constexpr (result_type_is_ada_url) {
12897|       |                    url.username += unicode::percent_encode(
12898|       |                        authority_view.substr(0, password_token_location),
12899|       |                        character_sets::USERINFO_PERCENT_ENCODE);
12900|       |                    url.password += unicode::percent_encode(
12901|       |                        authority_view.substr(password_token_location + 1),
12902|       |                        character_sets::USERINFO_PERCENT_ENCODE);
12903|      0|                  } else {
12904|      0|                    url.append_base_username(unicode::percent_encode(
12905|      0|                        authority_view.substr(0, password_token_location),
12906|      0|                        character_sets::USERINFO_PERCENT_ENCODE));
12907|      0|                    url.append_base_password(unicode::percent_encode(
12908|      0|                        authority_view.substr(password_token_location + 1),
12909|      0|                        character_sets::USERINFO_PERCENT_ENCODE));
12910|      0|                  }
12911|      0|                }
12912|      0|              }
12913|      0|            } else if constexpr (store_values) {
12914|       |              if constexpr (result_type_is_ada_url) {
12915|       |                url.password += unicode::percent_encode(
12916|       |                    authority_view, character_sets::USERINFO_PERCENT_ENCODE);
12917|      0|              } else {
12918|      0|                url.append_base_password(unicode::percent_encode(
12919|      0|                    authority_view, character_sets::USERINFO_PERCENT_ENCODE));
12920|      0|              }
12921|      0|            }
12922|      0|          }
12923|       |          // Otherwise, if one of the following is true:
12924|       |          // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
12925|       |          // - url is special and c is U+005C (\)
12926|     48|          else if (end_of_authority == input_size ||
  ------------------
  |  Branch (12926:20): [True: 0, False: 48]
  ------------------
12927|     48|                   url_data[end_of_authority] == '/' ||
  ------------------
  |  Branch (12927:20): [True: 48, False: 0]
  ------------------
12928|      0|                   url_data[end_of_authority] == '?' ||
  ------------------
  |  Branch (12928:20): [True: 0, False: 0]
  ------------------
12929|     48|                   (url.is_special() && url_data[end_of_authority] == '\\')) {
  ------------------
  |  Branch (12929:21): [True: 0, False: 0]
  |  Branch (12929:41): [True: 0, False: 0]
  ------------------
12930|       |            // If atSignSeen is true and authority_view is the empty string,
12931|       |            // validation error, return failure.
12932|     48|            if (at_sign_seen && authority_view.empty()) {
  ------------------
  |  Branch (12932:17): [True: 0, False: 48]
  |  Branch (12932:33): [True: 0, False: 0]
  ------------------
12933|      0|              url.is_valid = false;
12934|      0|              return url;
12935|      0|            }
12936|     48|            state = state::HOST;
12937|     48|            break;
12938|     48|          }
12939|      0|          if (end_of_authority == input_size) {
  ------------------
  |  Branch (12939:15): [True: 0, False: 0]
  ------------------
12940|      0|            if constexpr (store_values) {
12941|      0|              if (fragment.has_value()) {
  ------------------
  |  Branch (12941:19): [True: 0, False: 0]
  ------------------
12942|      0|                url.update_unencoded_base_hash(*fragment);
12943|      0|              }
12944|      0|            }
12945|      0|            enforce_max_input_length();
12946|      0|            return url;
12947|      0|          }
12948|      0|          input_position = end_of_authority + 1;
12949|      0|        } while (true);
  ------------------
  |  Branch (12949:18): [True: 0, Folded]
  ------------------
12950|       |
12951|     48|        break;
12952|     48|      }
12953|     48|      case state::SPECIAL_RELATIVE_OR_AUTHORITY: {
  ------------------
  |  Branch (12953:7): [True: 0, False: 4.07k]
  ------------------
12954|      0|        ada_log("SPECIAL_RELATIVE_OR_AUTHORITY ",
12955|      0|                helpers::substring(url_data, input_position));
12956|       |
12957|       |        // If c is U+002F (/) and remaining starts with U+002F (/),
12958|       |        // then set state to special authority ignore slashes state and increase
12959|       |        // pointer by 1.
12960|      0|        if (url_data.substr(input_position, 2) == "//") {
  ------------------
  |  Branch (12960:13): [True: 0, False: 0]
  ------------------
12961|      0|          state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES;
12962|      0|          input_position += 2;
12963|      0|        } else {
12964|       |          // Otherwise, validation error, set state to relative state and
12965|       |          // decrease pointer by 1.
12966|      0|          state = state::RELATIVE_SCHEME;
12967|      0|        }
12968|       |
12969|      0|        break;
12970|     48|      }
12971|      0|      case state::PATH_OR_AUTHORITY: {
  ------------------
  |  Branch (12971:7): [True: 0, False: 4.07k]
  ------------------
12972|      0|        ada_log("PATH_OR_AUTHORITY ",
12973|      0|                helpers::substring(url_data, input_position));
12974|       |
12975|       |        // If c is U+002F (/), then set state to authority state.
12976|      0|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12976:13): [True: 0, False: 0]
  ------------------
12977|      0|            (url_data[input_position] == '/')) {
  ------------------
  |  Branch (12977:13): [True: 0, False: 0]
  ------------------
12978|      0|          state = state::AUTHORITY;
12979|      0|          input_position++;
12980|      0|        } else {
12981|       |          // Otherwise, set state to path state, and decrease pointer by 1.
12982|      0|          state = state::PATH;
12983|      0|        }
12984|       |
12985|      0|        break;
12986|     48|      }
12987|      0|      case state::RELATIVE_SCHEME: {
  ------------------
  |  Branch (12987:7): [True: 0, False: 4.07k]
  ------------------
12988|      0|        ada_log("RELATIVE_SCHEME ",
12989|      0|                helpers::substring(url_data, input_position));
12990|       |
12991|       |        // Set url's scheme to base's scheme.
12992|      0|        url.copy_scheme(*base_url);
12993|       |
12994|       |        // If c is U+002F (/), then set state to relative slash state.
12995|      0|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12995:13): [True: 0, False: 0]
  ------------------
12996|       |            // NOLINTNEXTLINE(bugprone-branch-clone)
12997|      0|            (url_data[input_position] == '/')) {
  ------------------
  |  Branch (12997:13): [True: 0, False: 0]
  ------------------
12998|      0|          ada_log(
12999|      0|              "RELATIVE_SCHEME if c is U+002F (/), then set state to relative "
13000|      0|              "slash state");
13001|      0|          state = state::RELATIVE_SLASH;
13002|      0|        } else if (url.is_special() && (input_position != input_size) &&
  ------------------
  |  Branch (13002:20): [True: 0, False: 0]
  |  Branch (13002:40): [True: 0, False: 0]
  ------------------
13003|      0|                   (url_data[input_position] == '\\')) {
  ------------------
  |  Branch (13003:20): [True: 0, False: 0]
  ------------------
13004|       |          // Otherwise, if url is special and c is U+005C (\), validation error,
13005|       |          // set state to relative slash state.
13006|      0|          ada_log(
13007|      0|              "RELATIVE_SCHEME  if url is special and c is U+005C, validation "
13008|      0|              "error, set state to relative slash state");
13009|      0|          state = state::RELATIVE_SLASH;
13010|      0|        } else {
13011|      0|          ada_log("RELATIVE_SCHEME otherwise");
13012|       |          // Set url's username to base's username, url's password to base's
13013|       |          // password, url's host to base's host, url's port to base's port,
13014|       |          // url's path to a clone of base's path, and url's query to base's
13015|       |          // query.
13016|       |          if constexpr (result_type_is_ada_url) {
13017|       |            url.username = base_url->username;
13018|       |            url.password = base_url->password;
13019|       |            url.host = base_url->host;
13020|       |            url.port = base_url->port;
13021|       |            // cloning the base path includes cloning the has_opaque_path flag
13022|       |            url.has_opaque_path = base_url->has_opaque_path;
13023|       |            url.path = base_url->path;
13024|       |            url.query = base_url->query;
13025|      0|          } else {
13026|      0|            url.update_base_authority(base_url->get_href(),
13027|      0|                                      base_url->get_components());
13028|      0|            url.update_host_to_base_host(base_url->get_hostname());
13029|      0|            url.update_base_port(base_url->retrieve_base_port());
13030|       |            // cloning the base path includes cloning the has_opaque_path flag
13031|      0|            url.has_opaque_path = base_url->has_opaque_path;
13032|      0|            url.update_base_pathname(base_url->get_pathname());
13033|      0|            if (base_url->has_search()) {
  ------------------
  |  Branch (13033:17): [True: 0, False: 0]
  ------------------
13034|       |              // get_search() returns "" for an empty query string (URL ends
13035|       |              // with '?'). update_base_search("") would incorrectly clear the
13036|       |              // query, so pass "?" to preserve the empty query distinction.
13037|      0|              auto s = base_url->get_search();
13038|      0|              url.update_base_search(s.empty() ? std::string_view("?") : s);
  ------------------
  |  Branch (13038:38): [True: 0, False: 0]
  ------------------
13039|      0|            }
13040|      0|          }
13041|       |
13042|      0|          url.has_opaque_path = base_url->has_opaque_path;
13043|       |
13044|       |          // If c is U+003F (?), then set url's query to the empty string, and
13045|       |          // state to query state.
13046|      0|          if ((input_position != input_size) &&
  ------------------
  |  Branch (13046:15): [True: 0, False: 0]
  ------------------
13047|      0|              (url_data[input_position] == '?')) {
  ------------------
  |  Branch (13047:15): [True: 0, False: 0]
  ------------------
13048|      0|            state = state::QUERY;
13049|      0|          }
13050|       |          // Otherwise, if c is not the EOF code point:
13051|      0|          else if (input_position != input_size) {
  ------------------
  |  Branch (13051:20): [True: 0, False: 0]
  ------------------
13052|       |            // Set url's query to null.
13053|      0|            url.clear_search();
13054|       |            if constexpr (result_type_is_ada_url) {
13055|       |              // Shorten url's path.
13056|       |              helpers::shorten_path(url.path, url.type);
13057|      0|            } else {
13058|      0|              std::string_view path = url.get_pathname();
13059|      0|              if (helpers::shorten_path(path, url.type)) {
  ------------------
  |  Branch (13059:19): [True: 0, False: 0]
  ------------------
13060|      0|                url.update_base_pathname(std::move(std::string(path)));
13061|      0|              }
13062|      0|            }
13063|       |            // Set state to path state and decrease pointer by 1.
13064|      0|            state = state::PATH;
13065|      0|            break;
13066|      0|          }
13067|      0|        }
13068|      0|        input_position++;
13069|      0|        break;
13070|      0|      }
13071|      0|      case state::RELATIVE_SLASH: {
  ------------------
  |  Branch (13071:7): [True: 0, False: 4.07k]
  ------------------
13072|      0|        ada_log("RELATIVE_SLASH ",
13073|      0|                helpers::substring(url_data, input_position));
13074|       |
13075|       |        // If url is special and c is U+002F (/) or U+005C (\), then:
13076|       |        // NOLINTNEXTLINE(bugprone-branch-clone)
13077|      0|        if (url.is_special() && (input_position != input_size) &&
  ------------------
  |  Branch (13077:13): [True: 0, False: 0]
  |  Branch (13077:33): [True: 0, False: 0]
  ------------------
13078|      0|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (13078:14): [True: 0, False: 0]
  ------------------
13079|      0|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (13079:14): [True: 0, False: 0]
  ------------------
13080|       |          // Set state to special authority ignore slashes state.
13081|      0|          state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES;
13082|      0|        }
13083|       |        // Otherwise, if c is U+002F (/), then set state to authority state.
13084|      0|        else if ((input_position != input_size) &&
  ------------------
  |  Branch (13084:18): [True: 0, False: 0]
  ------------------
13085|      0|                 (url_data[input_position] == '/')) {
  ------------------
  |  Branch (13085:18): [True: 0, False: 0]
  ------------------
13086|      0|          state = state::AUTHORITY;
13087|      0|        }
13088|       |        // Otherwise, set
13089|       |        // - url's username to base's username,
13090|       |        // - url's password to base's password,
13091|       |        // - url's host to base's host,
13092|       |        // - url's port to base's port,
13093|       |        // - state to path state, and then, decrease pointer by 1.
13094|      0|        else {
13095|       |          if constexpr (result_type_is_ada_url) {
13096|       |            url.username = base_url->username;
13097|       |            url.password = base_url->password;
13098|       |            url.host = base_url->host;
13099|       |            url.port = base_url->port;
13100|      0|          } else {
13101|      0|            url.update_base_authority(base_url->get_href(),
13102|      0|                                      base_url->get_components());
13103|      0|            url.update_host_to_base_host(base_url->get_hostname());
13104|      0|            url.update_base_port(base_url->retrieve_base_port());
13105|      0|          }
13106|      0|          state = state::PATH;
13107|      0|          break;
13108|      0|        }
13109|       |
13110|      0|        input_position++;
13111|      0|        break;
13112|      0|      }
13113|    509|      case state::SPECIAL_AUTHORITY_SLASHES: {
  ------------------
  |  Branch (13113:7): [True: 509, False: 3.56k]
  ------------------
13114|    509|        ada_log("SPECIAL_AUTHORITY_SLASHES ",
13115|    509|                helpers::substring(url_data, input_position));
13116|       |
13117|       |        // If c is U+002F (/) and remaining starts with U+002F (/),
13118|       |        // then set state to special authority ignore slashes state and increase
13119|       |        // pointer by 1.
13120|    509|        if (url_data.substr(input_position, 2) == "//") {
  ------------------
  |  Branch (13120:13): [True: 509, False: 0]
  ------------------
13121|    509|          input_position += 2;
13122|    509|        }
13123|       |
13124|    509|        [[fallthrough]];
13125|    509|      }
13126|    509|      case state::SPECIAL_AUTHORITY_IGNORE_SLASHES: {
  ------------------
  |  Branch (13126:7): [True: 0, False: 4.07k]
  ------------------
13127|    509|        ada_log("SPECIAL_AUTHORITY_IGNORE_SLASHES ",
13128|    509|                helpers::substring(url_data, input_position));
13129|       |
13130|       |        // If c is neither U+002F (/) nor U+005C (\), then set state to
13131|       |        // authority state and decrease pointer by 1.
13132|    509|        while ((input_position != input_size) &&
  ------------------
  |  Branch (13132:16): [True: 509, False: 0]
  ------------------
13133|    509|               ((url_data[input_position] == '/') ||
  ------------------
  |  Branch (13133:17): [True: 0, False: 509]
  ------------------
13134|    509|                (url_data[input_position] == '\\'))) {
  ------------------
  |  Branch (13134:17): [True: 0, False: 509]
  ------------------
13135|      0|          input_position++;
13136|      0|        }
13137|    509|        state = state::AUTHORITY;
13138|       |
13139|    509|        break;
13140|    509|      }
13141|    509|      case state::QUERY: {
  ------------------
  |  Branch (13141:7): [True: 509, False: 3.56k]
  ------------------
13142|    509|        ada_log("QUERY ", helpers::substring(url_data, input_position));
13143|    509|        if constexpr (store_values) {
13144|       |          // Let queryPercentEncodeSet be the special-query percent-encode set
13145|       |          // if url is special; otherwise the query percent-encode set.
13146|    509|          const uint8_t* query_percent_encode_set =
13147|    509|              url.is_special() ? character_sets::SPECIAL_QUERY_PERCENT_ENCODE
  ------------------
  |  Branch (13147:15): [True: 509, False: 0]
  ------------------
13148|    509|                               : character_sets::QUERY_PERCENT_ENCODE;
13149|       |
13150|       |          // Percent-encode after encoding, with encoding, buffer, and
13151|       |          // queryPercentEncodeSet, and append the result to url's query.
13152|    509|          url.update_base_search(url_data.substr(input_position),
13153|    509|                                 query_percent_encode_set);
13154|    509|          ada_log("QUERY update_base_search completed ");
13155|    509|          if (fragment.has_value()) {
  ------------------
  |  Branch (13155:15): [True: 133, False: 376]
  ------------------
13156|    133|            url.update_unencoded_base_hash(*fragment);
13157|    133|          }
13158|    509|        }
13159|    509|        enforce_max_input_length();
13160|    509|        return url;
13161|    509|      }
13162|    509|      case state::HOST: {
  ------------------
  |  Branch (13162:7): [True: 509, False: 3.56k]
  ------------------
13163|    509|        ada_log("HOST ", helpers::substring(url_data, input_position));
13164|       |
13165|    509|        std::string_view host_view = url_data.substr(input_position);
13166|    509|        auto [location, found_colon] =
13167|    509|            helpers::get_host_delimiter_location(url.is_special(), host_view);
13168|    509|        input_position = (location != std::string_view::npos)
  ------------------
  |  Branch (13168:26): [True: 509, False: 0]
  ------------------
13169|    509|                             ? input_position + location
13170|    509|                             : input_size;
13171|       |        // Otherwise, if c is U+003A (:) and insideBrackets is false, then:
13172|       |        // Note: the 'found_colon' value is true if and only if a colon was
13173|       |        // encountered while not inside brackets.
13174|    509|        if (found_colon) {
  ------------------
  |  Branch (13174:13): [True: 0, False: 509]
  ------------------
13175|       |          // If buffer is the empty string, validation error, return failure.
13176|       |          // Let host be the result of host parsing buffer with url is not
13177|       |          // special.
13178|      0|          ada_log("HOST parsing ", host_view);
13179|      0|          if (!url.parse_host(host_view)) {
  ------------------
  |  Branch (13179:15): [True: 0, False: 0]
  ------------------
13180|      0|            return url;
13181|      0|          }
13182|      0|          ada_log("HOST parsing results in ", url.get_hostname());
13183|       |          // Set url's host to host, buffer to the empty string, and state to
13184|       |          // port state.
13185|      0|          state = state::PORT;
13186|      0|          input_position++;
13187|      0|        }
13188|       |        // Otherwise, if one of the following is true:
13189|       |        // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
13190|       |        // - url is special and c is U+005C (\)
13191|       |        // The get_host_delimiter_location function either brings us to
13192|       |        // the colon outside of the bracket, or to one of those characters.
13193|    509|        else {
13194|       |          // If url is special and host_view is the empty string, validation
13195|       |          // error, return failure.
13196|    509|          if (host_view.empty() && url.is_special()) {
  ------------------
  |  Branch (13196:15): [True: 0, False: 509]
  |  Branch (13196:36): [True: 0, False: 0]
  ------------------
13197|      0|            url.is_valid = false;
13198|      0|            return url;
13199|      0|          }
13200|    509|          ada_log("HOST parsing ", host_view, " href=", url.get_href());
13201|       |          // Let host be the result of host parsing host_view with url is not
13202|       |          // special.
13203|    509|          if (host_view.empty()) {
  ------------------
  |  Branch (13203:15): [True: 0, False: 509]
  ------------------
13204|      0|            url.update_base_hostname("");
13205|    509|          } else if (!url.parse_host(host_view)) {
  ------------------
  |  Branch (13205:22): [True: 0, False: 509]
  ------------------
13206|      0|            return url;
13207|      0|          }
13208|    509|          ada_log("HOST parsing results in ", url.get_hostname(),
13209|    509|                  " href=", url.get_href());
13210|       |
13211|       |          // Set url's host to host, and state to path start state.
13212|    509|          state = state::PATH_START;
13213|    509|        }
13214|       |
13215|    509|        break;
13216|    509|      }
13217|    509|      case state::OPAQUE_PATH: {
  ------------------
  |  Branch (13217:7): [True: 0, False: 4.07k]
  ------------------
13218|      0|        ada_log("OPAQUE_PATH ", helpers::substring(url_data, input_position));
13219|       |        // Opaque path, query, and fragment are structurally always valid:
13220|       |        // the parser would just percent-encode whatever is there. When we
13221|       |        // are not storing values (can_parse), we can return immediately.
13222|       |        // We must set has_opaque_path = true before returning so that when
13223|       |        // this URL is used as an internal base inside can_parse, NO_SCHEME
13224|       |        // correctly rejects relative inputs against an opaque-path base
13225|       |        // (e.g. can_parse("", &"W:") must return false).
13226|       |        if constexpr (!store_values) {
13227|       |          url.has_opaque_path = true;
13228|       |          return url;
13229|       |        }
13230|      0|        std::string_view view = url_data.substr(input_position);
13231|       |        // If c is U+003F (?), then set url's query to the empty string and
13232|       |        // state to query state.
13233|      0|        size_t location = view.find('?');
13234|      0|        if (location != std::string_view::npos) {
  ------------------
  |  Branch (13234:13): [True: 0, False: 0]
  ------------------
13235|      0|          view.remove_suffix(view.size() - location);
13236|      0|          state = state::QUERY;
13237|      0|          input_position += location + 1;
13238|      0|        } else {
13239|      0|          input_position = input_size + 1;
13240|      0|        }
13241|      0|        url.has_opaque_path = true;
13242|       |
13243|       |        // This is a really unlikely scenario in real world. We should not seek
13244|       |        // to optimize it.
13245|      0|        if (view.ends_with(' ')) {
  ------------------
  |  Branch (13245:13): [True: 0, False: 0]
  ------------------
13246|      0|          std::string modified_view =
13247|      0|              std::string(view.substr(0, view.size() - 1)) + "%20";
13248|      0|          url.update_base_pathname(unicode::percent_encode(
13249|      0|              modified_view, character_sets::C0_CONTROL_PERCENT_ENCODE));
13250|      0|        } else {
13251|      0|          url.update_base_pathname(unicode::percent_encode(
13252|      0|              view, character_sets::C0_CONTROL_PERCENT_ENCODE));
13253|      0|        }
13254|      0|        break;
13255|    509|      }
13256|      0|      case state::PORT: {
  ------------------
  |  Branch (13256:7): [True: 0, False: 4.07k]
  ------------------
13257|      0|        ada_log("PORT ", helpers::substring(url_data, input_position));
13258|      0|        std::string_view port_view = url_data.substr(input_position);
13259|      0|        input_position += url.parse_port(port_view, true);
13260|      0|        if (!url.is_valid) {
  ------------------
  |  Branch (13260:13): [True: 0, False: 0]
  ------------------
13261|      0|          return url;
13262|      0|        }
13263|      0|        state = state::PATH_START;
13264|      0|        [[fallthrough]];
13265|      0|      }
13266|    509|      case state::PATH_START: {
  ------------------
  |  Branch (13266:7): [True: 509, False: 3.56k]
  ------------------
13267|    509|        ada_log("PATH_START ", helpers::substring(url_data, input_position));
13268|       |        // Path, query, and fragment are structurally always valid: the
13269|       |        // parser would just percent-encode whatever is there. When we are
13270|       |        // not storing values (can_parse), we can return immediately since
13271|       |        // no subsequent state can invalidate the URL.
13272|       |        if constexpr (!store_values) {
13273|       |          return url;
13274|       |        }
13275|       |
13276|       |        // If url is special, then:
13277|    509|        if (url.is_special()) {
  ------------------
  |  Branch (13277:13): [True: 509, False: 0]
  ------------------
13278|       |          // Set state to path state.
13279|    509|          state = state::PATH;
13280|       |
13281|       |          // Optimization: Avoiding going into PATH state improves the
13282|       |          // performance of urls ending with /.
13283|    509|          if (input_position == input_size) {
  ------------------
  |  Branch (13283:15): [True: 0, False: 509]
  ------------------
13284|      0|            if constexpr (store_values) {
13285|      0|              url.update_base_pathname("/");
13286|      0|              if (fragment.has_value()) {
  ------------------
  |  Branch (13286:19): [True: 0, False: 0]
  ------------------
13287|      0|                url.update_unencoded_base_hash(*fragment);
13288|      0|              }
13289|      0|            }
13290|      0|            enforce_max_input_length();
13291|      0|            return url;
13292|      0|          }
13293|       |          // If c is neither U+002F (/) nor U+005C (\), then decrease pointer
13294|       |          // by 1. We know that (input_position == input_size) is impossible
13295|       |          // here, because of the previous if-check.
13296|    509|          if ((url_data[input_position] != '/') &&
  ------------------
  |  Branch (13296:15): [True: 0, False: 509]
  ------------------
13297|      0|              (url_data[input_position] != '\\')) {
  ------------------
  |  Branch (13297:15): [True: 0, False: 0]
  ------------------
13298|      0|            break;
13299|      0|          }
13300|    509|        }
13301|       |        // Otherwise, if state override is not given and c is U+003F (?),
13302|       |        // set url's query to the empty string and state to query state.
13303|      0|        else if ((input_position != input_size) &&
  ------------------
  |  Branch (13303:18): [True: 0, False: 0]
  ------------------
13304|      0|                 (url_data[input_position] == '?')) {
  ------------------
  |  Branch (13304:18): [True: 0, False: 0]
  ------------------
13305|      0|          state = state::QUERY;
13306|      0|        }
13307|       |        // Otherwise, if c is not the EOF code point:
13308|      0|        else if (input_position != input_size) {
  ------------------
  |  Branch (13308:18): [True: 0, False: 0]
  ------------------
13309|       |          // Set state to path state.
13310|      0|          state = state::PATH;
13311|       |
13312|       |          // If c is not U+002F (/), then decrease pointer by 1.
13313|      0|          if (url_data[input_position] != '/') {
  ------------------
  |  Branch (13313:15): [True: 0, False: 0]
  ------------------
13314|      0|            break;
13315|      0|          }
13316|      0|        }
13317|       |
13318|    509|        input_position++;
13319|    509|        break;
13320|    509|      }
13321|    509|      case state::PATH: {
  ------------------
  |  Branch (13321:7): [True: 509, False: 3.56k]
  ------------------
13322|    509|        ada_log("PATH ", helpers::substring(url_data, input_position));
13323|       |        // Path, query, and fragment are structurally always valid: the
13324|       |        // parser would just percent-encode whatever is there. When we are
13325|       |        // not storing values (can_parse), we can return immediately since
13326|       |        // no subsequent state can invalidate the URL.
13327|       |        if constexpr (!store_values) {
13328|       |          return url;
13329|       |        }
13330|    509|        std::string_view view = url_data.substr(input_position);
13331|       |
13332|       |        // Most time, we do not need percent encoding.
13333|       |        // Furthermore, we can immediately locate the '?'.
13334|    509|        size_t locofquestionmark = view.find('?');
13335|    509|        if (locofquestionmark != std::string_view::npos) {
  ------------------
  |  Branch (13335:13): [True: 509, False: 0]
  ------------------
13336|    509|          state = state::QUERY;
13337|    509|          view.remove_suffix(view.size() - locofquestionmark);
13338|    509|          input_position += locofquestionmark + 1;
13339|    509|        } else {
13340|      0|          input_position = input_size + 1;
13341|      0|        }
13342|    509|        if constexpr (store_values) {
13343|       |          if constexpr (result_type_is_ada_url) {
13344|       |            helpers::parse_prepared_path(view, url.type, url.path);
13345|    509|          } else {
13346|    509|            url.consume_prepared_path(view);
13347|    509|            ADA_ASSERT_TRUE(url.validate());
13348|    509|          }
13349|    509|        }
13350|    509|        break;
13351|    509|      }
13352|      0|      case state::FILE_SLASH: {
  ------------------
  |  Branch (13352:7): [True: 0, False: 4.07k]
  ------------------
13353|      0|        ada_log("FILE_SLASH ", helpers::substring(url_data, input_position));
13354|       |
13355|       |        // If c is U+002F (/) or U+005C (\), then:
13356|      0|        if ((input_position != input_size) &&
  ------------------
  |  Branch (13356:13): [True: 0, False: 0]
  ------------------
13357|      0|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (13357:14): [True: 0, False: 0]
  ------------------
13358|      0|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (13358:14): [True: 0, False: 0]
  ------------------
13359|      0|          ada_log("FILE_SLASH c is U+002F or U+005C");
13360|       |          // Set state to file host state.
13361|      0|          state = state::FILE_HOST;
13362|      0|          input_position++;
13363|      0|        } else {
13364|      0|          ada_log("FILE_SLASH otherwise");
13365|       |          // If base is non-null and base's scheme is "file", then:
13366|       |          // Note: it is unsafe to do base_url->scheme unless you know that
13367|       |          // base_url_has_value() is true.
13368|      0|          if (base_url != nullptr && base_url->type == scheme::type::FILE) {
  ------------------
  |  Branch (13368:15): [True: 0, False: 0]
  |  Branch (13368:38): [True: 0, False: 0]
  ------------------
13369|       |            // Set url's host to base's host.
13370|       |            if constexpr (result_type_is_ada_url) {
13371|       |              url.host = base_url->host;
13372|      0|            } else {
13373|      0|              url.update_host_to_base_host(base_url->get_host());
13374|      0|            }
13375|       |            // If the code point substring from pointer to the end of input does
13376|       |            // not start with a Windows drive letter and base's path[0] is a
13377|       |            // normalized Windows drive letter, then append base's path[0] to
13378|       |            // url's path.
13379|      0|            if (!base_url->get_pathname().empty()) {
  ------------------
  |  Branch (13379:17): [True: 0, False: 0]
  ------------------
13380|      0|              if (!checkers::is_windows_drive_letter(
  ------------------
  |  Branch (13380:19): [True: 0, False: 0]
  ------------------
13381|      0|                      url_data.substr(input_position))) {
13382|      0|                std::string_view first_base_url_path =
13383|      0|                    base_url->get_pathname().substr(1);
13384|      0|                size_t loc = first_base_url_path.find('/');
13385|      0|                if (loc != std::string_view::npos) {
  ------------------
  |  Branch (13385:21): [True: 0, False: 0]
  ------------------
13386|      0|                  helpers::resize(first_base_url_path, loc);
13387|      0|                }
13388|      0|                if (checkers::is_normalized_windows_drive_letter(
  ------------------
  |  Branch (13388:21): [True: 0, False: 0]
  ------------------
13389|      0|                        first_base_url_path)) {
13390|       |                  if constexpr (result_type_is_ada_url) {
13391|       |                    url.path += '/';
13392|       |                    url.path += first_base_url_path;
13393|      0|                  } else {
13394|      0|                    url.append_base_pathname(
13395|      0|                        helpers::concat("/", first_base_url_path));
13396|      0|                  }
13397|      0|                }
13398|      0|              }
13399|      0|            }
13400|      0|          }
13401|       |
13402|       |          // Set state to path state, and decrease pointer by 1.
13403|      0|          state = state::PATH;
13404|      0|        }
13405|       |
13406|      0|        break;
13407|    509|      }
13408|      0|      case state::FILE_HOST: {
  ------------------
  |  Branch (13408:7): [True: 0, False: 4.07k]
  ------------------
13409|      0|        ada_log("FILE_HOST ", helpers::substring(url_data, input_position));
13410|      0|        std::string_view view = url_data.substr(input_position);
13411|       |
13412|      0|        size_t location = view.find_first_of("/\\?");
13413|      0|        std::string_view file_host_buffer = view.substr(
13414|      0|            0, (location != std::string_view::npos) ? location : view.size());
  ------------------
  |  Branch (13414:16): [True: 0, False: 0]
  ------------------
13415|       |
13416|      0|        if (checkers::is_windows_drive_letter(file_host_buffer)) {
  ------------------
  |  Branch (13416:13): [True: 0, False: 0]
  ------------------
13417|      0|          state = state::PATH;
13418|      0|        } else if (file_host_buffer.empty()) {
  ------------------
  |  Branch (13418:20): [True: 0, False: 0]
  ------------------
13419|       |          // Set url's host to the empty string.
13420|       |          if constexpr (result_type_is_ada_url) {
13421|       |            url.host = "";
13422|      0|          } else {
13423|      0|            url.update_base_hostname("");
13424|      0|          }
13425|       |          // Set state to path start state.
13426|      0|          state = state::PATH_START;
13427|      0|        } else {
13428|      0|          size_t consumed_bytes = file_host_buffer.size();
13429|      0|          input_position += consumed_bytes;
13430|       |          // Let host be the result of host parsing buffer with url is not
13431|       |          // special.
13432|      0|          if (!url.parse_host(file_host_buffer)) {
  ------------------
  |  Branch (13432:15): [True: 0, False: 0]
  ------------------
13433|      0|            return url;
13434|      0|          }
13435|       |
13436|       |          if constexpr (result_type_is_ada_url) {
13437|       |            // If host is "localhost", then set host to the empty string.
13438|       |            if (url.host.has_value() && url.host.value() == "localhost") {
13439|       |              url.host = "";
13440|       |            }
13441|      0|          } else {
13442|      0|            if (url.get_hostname() == "localhost") {
  ------------------
  |  Branch (13442:17): [True: 0, False: 0]
  ------------------
13443|      0|              url.update_base_hostname("");
13444|      0|            }
13445|      0|          }
13446|       |
13447|       |          // Set buffer to the empty string and state to path start state.
13448|      0|          state = state::PATH_START;
13449|      0|        }
13450|       |
13451|      0|        break;
13452|      0|      }
13453|      0|      case state::FILE: {
  ------------------
  |  Branch (13453:7): [True: 0, False: 4.07k]
  ------------------
13454|      0|        ada_log("FILE ", helpers::substring(url_data, input_position));
13455|      0|        std::string_view file_view = url_data.substr(input_position);
13456|       |
13457|      0|        url.set_protocol_as_file();
13458|       |        if constexpr (result_type_is_ada_url) {
13459|       |          // Set url's host to the empty string.
13460|       |          url.host = "";
13461|      0|        } else {
13462|      0|          url.update_base_hostname("");
13463|      0|        }
13464|       |        // If c is U+002F (/) or U+005C (\), then:
13465|      0|        if (input_position != input_size &&
  ------------------
  |  Branch (13465:13): [True: 0, False: 0]
  ------------------
13466|      0|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (13466:14): [True: 0, False: 0]
  ------------------
13467|      0|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (13467:14): [True: 0, False: 0]
  ------------------
13468|      0|          ada_log("FILE c is U+002F or U+005C");
13469|       |          // Set state to file slash state.
13470|      0|          state = state::FILE_SLASH;
13471|      0|        }
13472|       |        // Otherwise, if base is non-null and base's scheme is "file":
13473|      0|        else if (base_url != nullptr && base_url->type == scheme::type::FILE) {
  ------------------
  |  Branch (13473:18): [True: 0, False: 0]
  |  Branch (13473:41): [True: 0, False: 0]
  ------------------
13474|       |          // Set url's host to base's host, url's path to a clone of base's
13475|       |          // path, and url's query to base's query.
13476|      0|          ada_log("FILE base non-null");
13477|       |          if constexpr (result_type_is_ada_url) {
13478|       |            url.host = base_url->host;
13479|       |            url.path = base_url->path;
13480|       |            url.query = base_url->query;
13481|      0|          } else {
13482|      0|            url.update_host_to_base_host(base_url->get_hostname());
13483|      0|            url.update_base_pathname(base_url->get_pathname());
13484|      0|            if (base_url->has_search()) {
  ------------------
  |  Branch (13484:17): [True: 0, False: 0]
  ------------------
13485|       |              // get_search() returns "" for an empty query string (URL ends
13486|       |              // with '?'). update_base_search("") would incorrectly clear the
13487|       |              // query, so pass "?" to preserve the empty query distinction.
13488|      0|              auto s = base_url->get_search();
13489|      0|              url.update_base_search(s.empty() ? std::string_view("?") : s);
  ------------------
  |  Branch (13489:38): [True: 0, False: 0]
  ------------------
13490|      0|            }
13491|      0|          }
13492|      0|          url.has_opaque_path = base_url->has_opaque_path;
13493|       |
13494|       |          // If c is U+003F (?), then set url's query to the empty string and
13495|       |          // state to query state.
13496|      0|          if (input_position != input_size && url_data[input_position] == '?') {
  ------------------
  |  Branch (13496:15): [True: 0, False: 0]
  |  Branch (13496:47): [True: 0, False: 0]
  ------------------
13497|      0|            state = state::QUERY;
13498|      0|          }
13499|       |          // Otherwise, if c is not the EOF code point:
13500|      0|          else if (input_position != input_size) {
  ------------------
  |  Branch (13500:20): [True: 0, False: 0]
  ------------------
13501|       |            // Set url's query to null.
13502|      0|            url.clear_search();
13503|       |            // If the code point substring from pointer to the end of input does
13504|       |            // not start with a Windows drive letter, then shorten url's path.
13505|      0|            if (!checkers::is_windows_drive_letter(file_view)) {
  ------------------
  |  Branch (13505:17): [True: 0, False: 0]
  ------------------
13506|       |              if constexpr (result_type_is_ada_url) {
13507|       |                helpers::shorten_path(url.path, url.type);
13508|      0|              } else {
13509|      0|                std::string_view path = url.get_pathname();
13510|      0|                if (helpers::shorten_path(path, url.type)) {
  ------------------
  |  Branch (13510:21): [True: 0, False: 0]
  ------------------
13511|      0|                  url.update_base_pathname(std::move(std::string(path)));
13512|      0|                }
13513|      0|              }
13514|      0|            }
13515|       |            // Otherwise:
13516|      0|            else {
13517|       |              // Set url's path to an empty list.
13518|      0|              url.clear_pathname();
13519|      0|              url.has_opaque_path = true;
13520|      0|            }
13521|       |
13522|       |            // Set state to path state and decrease pointer by 1.
13523|      0|            state = state::PATH;
13524|      0|            break;
13525|      0|          }
13526|      0|        }
13527|       |        // Otherwise, set state to path state, and decrease pointer by 1.
13528|      0|        else {
13529|      0|          ada_log("FILE go to path");
13530|      0|          state = state::PATH;
13531|      0|          break;
13532|      0|        }
13533|       |
13534|      0|        input_position++;
13535|      0|        break;
13536|      0|      }
13537|      0|      default:
  ------------------
  |  Branch (13537:7): [True: 0, False: 4.07k]
  ------------------
13538|      0|        unreachable();
13539|  4.07k|    }
13540|  4.07k|  }
13541|  2.48k|  if constexpr (store_values) {
13542|  2.48k|    if (fragment.has_value()) {
  ------------------
  |  Branch (13542:9): [True: 0, False: 2.48k]
  ------------------
13543|      0|      url.update_unencoded_base_hash(*fragment);
13544|      0|    }
13545|  2.48k|  }
13546|  2.48k|  enforce_max_input_length();
13547|  2.48k|  return url;
13548|  2.99k|}
_ZNK3ada14url_aggregator23needs_rollback_snapshotEm:
13837|  1.57k|bool url_aggregator::needs_rollback_snapshot(size_t input_len) const noexcept {
13838|       |  // 3x should cover worst-case percent-encoding of every input byte; the
13839|       |  // constant covers the handful of delimiter bytes a setter may add ("/.", "?",
13840|       |  // "#" and so on)
13841|  1.57k|  return buffer.size() + input_len * 3 + 16 > ada::get_max_input_length();
13842|  1.57k|}
_ZN3ada14url_aggregator10set_searchENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
14059|  2.99k|void url_aggregator::set_search(const std::string_view input) {
14060|  2.99k|  ada_log("url_aggregator::set_search ", input);
14061|  2.99k|  ADA_ASSERT_TRUE(validate());
14062|  2.99k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
14063|  2.99k|  if (input.empty()) {
  ------------------
  |  Branch (14063:7): [True: 1.42k, False: 1.57k]
  ------------------
14064|  1.42k|    clear_search();
14065|  1.42k|    helpers::strip_trailing_spaces_from_opaque_path(*this);
14066|  1.42k|    return;
14067|  1.42k|  }
14068|       |
14069|  1.57k|  std::string new_value;
14070|  1.57k|  new_value = input[0] == '?' ? input.substr(1) : input;
  ------------------
  |  Branch (14070:15): [True: 0, False: 1.57k]
  ------------------
14071|  1.57k|  helpers::remove_ascii_tab_or_newline(new_value);
14072|       |
14073|  1.57k|  auto query_percent_encode_set =
14074|  1.57k|      is_special() ? ada::character_sets::SPECIAL_QUERY_PERCENT_ENCODE
  ------------------
  |  Branch (14074:7): [True: 1.57k, False: 0]
  ------------------
14075|  1.57k|                   : ada::character_sets::QUERY_PERCENT_ENCODE;
14076|       |
14077|  1.57k|  std::optional<url_aggregator> saved_url;
14078|  1.57k|  if (needs_rollback_snapshot(new_value.size())) {
  ------------------
  |  Branch (14078:7): [True: 0, False: 1.57k]
  ------------------
14079|      0|    saved_url = *this;
14080|      0|  }
14081|  1.57k|  update_base_search(new_value, query_percent_encode_set);
14082|  1.57k|  if (saved_url && buffer.size() > ada::get_max_input_length()) {
  ------------------
  |  Branch (14082:7): [True: 0, False: 1.57k]
  |  Branch (14082:20): [True: 0, False: 0]
  ------------------
14083|      0|    *this = std::move(*saved_url);
14084|      0|    return;
14085|      0|  }
14086|  1.57k|  ADA_ASSERT_TRUE(validate());
14087|  1.57k|}
_ZNK3ada14url_aggregator10get_searchEv:
14531|  2.99k|    ada_lifetime_bound {
14532|  2.99k|  ada_log("url_aggregator::get_search");
14533|       |  // If this's URL's query is either null or the empty string, then return the
14534|       |  // empty string. Return U+003F (?), followed by this's URL's query.
14535|  2.99k|  if (components.search_start == url_components::omitted) {
  ------------------
  |  Branch (14535:7): [True: 0, False: 2.99k]
  ------------------
14536|      0|    return "";
14537|      0|  }
14538|  2.99k|  auto ending_index = uint32_t(buffer.size());
14539|  2.99k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (14539:7): [True: 476, False: 2.51k]
  ------------------
14540|    476|    ending_index = components.hash_start;
14541|    476|  }
14542|  2.99k|  if (ending_index - components.search_start <= 1) {
  ------------------
  |  Branch (14542:7): [True: 1.36k, False: 1.63k]
  ------------------
14543|  1.36k|    return "";
14544|  1.36k|  }
14545|  1.63k|  return helpers::substring(buffer, components.search_start, ending_index);
14546|  2.99k|}
_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:
 7358|   117k|  auto pointer = std::ranges::find_if(input, [character_set](const char c) {
 7359|   117k|    return character_sets::bit_at(character_set, c);
 7360|   117k|  });
url_search_params.cc:_ZZN3ada7unicode14percent_encodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKhENK3$_0clEc:
 7326|  90.0k|  auto pointer = std::ranges::find_if(input, [character_set](const char c) {
 7327|  90.0k|    return character_sets::bit_at(character_set, c);
 7328|  90.0k|  });
url_search_params.cc:_ZN3ada7unicode12_GLOBAL__N_122percent_encode_to_wideEPKcS3_PKhRNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEE:
 7708|  3.32k|                            const uint8_t character_set[], std::string& out) {
 7709|       |  // Worst case every byte becomes %XX. Avoids realloc while walking windows.
 7710|  3.32k|  out.reserve(out.size() + static_cast<size_t>(end - p) * 3);
 7711|  3.32k|#if ADA_UNICODE_SSSE3
 7712|  3.32k|  const ssse3_percent_tables tables = load_ssse3_percent_tables(character_set);
 7713|  3.32k|  percent_encode_to_ssse3(p, end, character_set, tables, out);
 7714|       |#elif ADA_NEON
 7715|       |  percent_encode_to_neon(p, end, character_set,
 7716|       |                         load_neon_percent_table(character_set), out);
 7717|       |#elif ADA_RVV
 7718|       |  percent_encode_to_rvv(p, end, character_set, out);
 7719|       |#endif
 7720|  3.32k|}
url_search_params.cc:_ZN3ada7unicode12_GLOBAL__N_125load_ssse3_percent_tablesEPKh:
 7535|  3.32k|load_ssse3_percent_tables(const uint8_t character_set[]) noexcept {
 7536|  3.32k|  ssse3_percent_tables t{};
 7537|  3.32k|  t.cs_lo = _mm_loadu_si128(reinterpret_cast<const __m128i*>(character_set));
 7538|  3.32k|  t.cs_hi =
 7539|  3.32k|      _mm_loadu_si128(reinterpret_cast<const __m128i*>(character_set + 16));
 7540|       |  // 1 << (0..7), duplicated so pshufb(index & 7) works for every lane.
 7541|  3.32k|  t.pow2 =
 7542|  3.32k|      _mm_setr_epi8(1, 2, 4, 8, 16, 32, 64, -128, 1, 2, 4, 8, 16, 32, 64, -128);
 7543|  3.32k|  t.mask_0f = _mm_set1_epi8(0x0F);
 7544|  3.32k|  t.mask_07 = _mm_set1_epi8(0x07);
 7545|  3.32k|  t.zero = _mm_setzero_si128();
 7546|  3.32k|  return t;
 7547|  3.32k|}
url_search_params.cc:_ZN3ada7unicode12_GLOBAL__N_123percent_encode_to_ssse3EPKcS3_PKhRKNS1_20ssse3_percent_tablesERNSt3__112basic_stringIcNS9_11char_traitsIcEENS9_9allocatorIcEEEE:
 7566|  3.32k|    const ssse3_percent_tables& tables, std::string& out) {
 7567|       |  // Pair 16-byte windows so a fully clean 32-byte run is one append.
 7568|  13.6k|  while (p + 32 <= end) {
  ------------------
  |  Branch (7568:10): [True: 10.3k, False: 3.32k]
  ------------------
 7569|  10.3k|    const __m128i word0 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(p));
 7570|  10.3k|    const __m128i word1 =
 7571|  10.3k|        _mm_loadu_si128(reinterpret_cast<const __m128i*>(p + 16));
 7572|  10.3k|    const int mask0 = ssse3_percent_mask(word0, tables);
 7573|  10.3k|    const int mask1 = ssse3_percent_mask(word1, tables);
 7574|  10.3k|    if ((mask0 | mask1) == 0) {
  ------------------
  |  Branch (7574:9): [True: 408, False: 9.96k]
  ------------------
 7575|    408|      out.append(p, 32);
 7576|  9.96k|    } else {
 7577|  9.96k|      if (mask0 == 0) {
  ------------------
  |  Branch (7577:11): [True: 235, False: 9.72k]
  ------------------
 7578|    235|        out.append(p, 16);
 7579|  9.72k|      } else {
 7580|  9.72k|        encode_mask_window(p, static_cast<uint32_t>(mask0), 16, out);
 7581|  9.72k|      }
 7582|  9.96k|      if (mask1 == 0) {
  ------------------
  |  Branch (7582:11): [True: 529, False: 9.43k]
  ------------------
 7583|    529|        out.append(p + 16, 16);
 7584|  9.43k|      } else {
 7585|  9.43k|        encode_mask_window(p + 16, static_cast<uint32_t>(mask1), 16, out);
 7586|  9.43k|      }
 7587|  9.96k|    }
 7588|  10.3k|    p += 32;
 7589|  10.3k|  }
 7590|  3.32k|  if (p + 16 <= end) {
  ------------------
  |  Branch (7590:7): [True: 1.71k, False: 1.60k]
  ------------------
 7591|  1.71k|    const __m128i word = _mm_loadu_si128(reinterpret_cast<const __m128i*>(p));
 7592|  1.71k|    const int mask = ssse3_percent_mask(word, tables);
 7593|  1.71k|    if (mask == 0) {
  ------------------
  |  Branch (7593:9): [True: 194, False: 1.52k]
  ------------------
 7594|    194|      out.append(p, 16);
 7595|  1.52k|    } else {
 7596|  1.52k|      encode_mask_window(p, static_cast<uint32_t>(mask), 16, out);
 7597|  1.52k|    }
 7598|  1.71k|    p += 16;
 7599|  1.71k|  }
 7600|  3.32k|  percent_encode_to_scalar(p, end, character_set, out);
 7601|  3.32k|}
url_search_params.cc:_ZN3ada7unicode12_GLOBAL__N_118ssse3_percent_maskEDv2_xRKNS1_20ssse3_percent_tablesE:
 7550|  22.4k|    __m128i word, const ssse3_percent_tables& tables) noexcept {
 7551|  22.4k|  const __m128i idx = _mm_and_si128(_mm_srli_epi16(word, 3), tables.mask_0f);
 7552|  22.4k|  const __m128i lo = _mm_shuffle_epi8(tables.cs_lo, idx);
 7553|  22.4k|  const __m128i hi = _mm_shuffle_epi8(tables.cs_hi, idx);
 7554|       |  // Bytes 0x80-0xFF are signed-negative; select the high half of the bitmap.
 7555|  22.4k|  const __m128i high_byte = _mm_cmpgt_epi8(tables.zero, word);
 7556|  22.4k|  const __m128i cs_byte = _mm_or_si128(_mm_and_si128(hi, high_byte),
 7557|  22.4k|                                       _mm_andnot_si128(high_byte, lo));
 7558|  22.4k|  const __m128i bits =
 7559|  22.4k|      _mm_shuffle_epi8(tables.pow2, _mm_and_si128(word, tables.mask_07));
 7560|  22.4k|  const __m128i hits = _mm_and_si128(cs_byte, bits);
 7561|  22.4k|  return _mm_movemask_epi8(_mm_cmpeq_epi8(hits, tables.zero)) ^ 0xFFFF;
 7562|  22.4k|}
url_search_params.cc:_ZN3ada7unicode12_GLOBAL__N_118encode_mask_windowEPKcjmRNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEE:
 7490|  20.6k|                                          size_t width, std::string& out) {
 7491|  20.6k|  uint64_t bits = mask;
 7492|  20.6k|  size_t off = 0;
 7493|   297k|  while (bits != 0) {
  ------------------
  |  Branch (7493:10): [True: 276k, False: 20.6k]
  ------------------
 7494|   276k|    const int zero_run = trailing_zeroes32(static_cast<uint32_t>(bits));
 7495|   276k|    if (zero_run != 0) {
  ------------------
  |  Branch (7495:9): [True: 15.8k, False: 260k]
  ------------------
 7496|  15.8k|      out.append(p + off, static_cast<size_t>(zero_run));
 7497|  15.8k|    }
 7498|   276k|    off += static_cast<size_t>(zero_run);
 7499|   276k|    out.append(character_sets::hex + uint8_t(p[off]) * 4, 3);
 7500|   276k|    ++off;
 7501|   276k|    bits >>= static_cast<unsigned>(zero_run + 1);
 7502|   276k|  }
 7503|  20.6k|  if (off < width) {
  ------------------
  |  Branch (7503:7): [True: 3.64k, False: 17.0k]
  ------------------
 7504|  3.64k|    out.append(p + off, width - off);
 7505|  3.64k|  }
 7506|  20.6k|}
url_search_params.cc:_ZN3ada7unicode12_GLOBAL__N_117trailing_zeroes32Ej:
 7478|   276k|ada_really_inline int trailing_zeroes32(uint32_t input_num) noexcept {
 7479|       |#ifdef ADA_REGULAR_VISUAL_STUDIO
 7480|       |  unsigned long ret;
 7481|       |  _BitScanForward(&ret, input_num);
 7482|       |  return static_cast<int>(ret);
 7483|       |#else
 7484|   276k|  return __builtin_ctz(input_num);
 7485|   276k|#endif
 7486|   276k|}
url_search_params.cc:_ZN3ada7unicode12_GLOBAL__N_124percent_encode_to_scalarEPKcS3_PKhRNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEE:
 7511|  3.32k|                                                std::string& out) {
 7512|  19.3k|  for (; p != end; ++p) {
  ------------------
  |  Branch (7512:10): [True: 16.0k, False: 3.32k]
  ------------------
 7513|  16.0k|    if (character_sets::bit_at(character_set, *p)) {
  ------------------
  |  Branch (7513:9): [True: 12.3k, False: 3.69k]
  ------------------
 7514|  12.3k|      out.append(character_sets::hex + uint8_t(*p) * 4, 3);
 7515|  12.3k|    } else {
 7516|  3.69k|      out += *p;
 7517|  3.69k|    }
 7518|  16.0k|  }
 7519|  3.32k|}
_ZN3ada7unicode19has_tabs_or_newlineENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6868|  2.71k|    std::string_view user_input) noexcept {
 6869|       |  // first check for short strings in which case we do it naively.
 6870|  2.71k|  if (user_input.size() < 16) {  // slow path
  ------------------
  |  Branch (6870:7): [True: 1.03k, False: 1.68k]
  ------------------
 6871|  1.03k|    return std::ranges::any_of(user_input, is_tabs_or_newline);
 6872|  1.03k|  }
 6873|       |  // fast path for long strings (expected to be common)
 6874|  1.68k|  size_t i = 0;
 6875|  1.68k|  const __m128i mask1 = _mm_set1_epi8('\r');
 6876|  1.68k|  const __m128i mask2 = _mm_set1_epi8('\n');
 6877|  1.68k|  const __m128i mask3 = _mm_set1_epi8('\t');
 6878|       |  // If we supported SSSE3, we could use the algorithm that we use for NEON.
 6879|  1.68k|  __m128i running{0};
 6880|  8.02k|  for (; i + 15 < user_input.size(); i += 16) {
  ------------------
  |  Branch (6880:10): [True: 6.34k, False: 1.68k]
  ------------------
 6881|  6.34k|    __m128i word = _mm_loadu_si128((const __m128i*)(user_input.data() + i));
 6882|  6.34k|    running = _mm_or_si128(
 6883|  6.34k|        _mm_or_si128(running, _mm_or_si128(_mm_cmpeq_epi8(word, mask1),
 6884|  6.34k|                                           _mm_cmpeq_epi8(word, mask2))),
 6885|  6.34k|        _mm_cmpeq_epi8(word, mask3));
 6886|  6.34k|  }
 6887|  1.68k|  if (i < user_input.size()) {
  ------------------
  |  Branch (6887:7): [True: 1.59k, False: 84]
  ------------------
 6888|  1.59k|    __m128i word = _mm_loadu_si128(
 6889|  1.59k|        (const __m128i*)(user_input.data() + user_input.length() - 16));
 6890|  1.59k|    running = _mm_or_si128(
 6891|  1.59k|        _mm_or_si128(running, _mm_or_si128(_mm_cmpeq_epi8(word, mask1),
 6892|  1.59k|                                           _mm_cmpeq_epi8(word, mask2))),
 6893|  1.59k|        _mm_cmpeq_epi8(word, mask3));
 6894|  1.59k|  }
 6895|  1.68k|  return _mm_movemask_epi8(running) != 0;
 6896|  2.71k|}
_ZN3ada7unicode18is_tabs_or_newlineEc:
 6753|  1.03k|constexpr bool is_tabs_or_newline(char c) noexcept {
 6754|  1.03k|  return c == '\r' || c == '\n' || c == '\t';
  ------------------
  |  Branch (6754:10): [True: 0, False: 1.03k]
  |  Branch (6754:23): [True: 0, False: 1.03k]
  |  Branch (6754:36): [True: 0, False: 1.03k]
  ------------------
 6755|  1.03k|}
_ZN3ada7helpers27remove_ascii_tab_or_newlineERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
 8564|  1.81k|ada_really_inline void remove_ascii_tab_or_newline(std::string& input) {
 8565|       |  // if this ever becomes a performance issue, we could use an approach similar
 8566|       |  // to has_tabs_or_newline
 8567|  1.81k|  std::erase_if(input, ada::unicode::is_ascii_tab_or_newline);
 8568|  1.81k|}
_ZN3ada7unicode23is_ascii_tab_or_newlineEc:
 7113|   159k|    const char c) noexcept {
 7114|   159k|  return c == '\t' || c == '\n' || c == '\r';
  ------------------
  |  Branch (7114:10): [True: 454, False: 159k]
  |  Branch (7114:23): [True: 1.25k, False: 158k]
  |  Branch (7114:36): [True: 325, False: 157k]
  ------------------
 7115|   159k|}
_ZN3ada7unicode22is_c0_control_or_spaceEc:
 7108|  4.80k|ada_really_inline constexpr bool is_c0_control_or_space(const char c) noexcept {
 7109|  4.80k|  return (unsigned char)c <= ' ';
 7110|  4.80k|}
_ZN3ada8checkers14path_signatureENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
   75|  1.53k|    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.53k|  size_t i = 0;
   82|  1.53k|  uint8_t accumulator{};
   83|  1.53k|  for (; i + 7 < input.size(); i += 8) {
  ------------------
  |  Branch (83:10): [True: 0, False: 1.53k]
  ------------------
   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.53k|  for (; i < input.size(); i++) {
  ------------------
  |  Branch (93:10): [True: 0, False: 1.53k]
  ------------------
   94|      0|    accumulator |= uint8_t(path_signature_table[uint8_t(input[i])]);
   95|      0|  }
   96|  1.53k|  return accumulator;
   97|  1.53k|}
_ZN3ada7unicode13is_alnum_plusEc:
 7085|  2.54k|ada_really_inline constexpr bool is_alnum_plus(const char c) noexcept {
 7086|  2.54k|  return is_alnum_plus_table[uint8_t(c)];
 7087|       |  // A table is almost surely much faster than the
 7088|       |  // following under most compilers: return
 7089|       |  // return (std::isalnum(c) || c == '+' || c == '-' || c == '.');
 7090|  2.54k|}
_ZZN3ada6parser25try_parse_simple_absoluteINS_14url_aggregatorEEEbNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEERT_ENKUlvE_clEv:
12233|  1.03k|    auto apply_query_and_hash = [&]() {
12234|  1.03k|      if (query_start != std::string_view::npos) {
  ------------------
  |  Branch (12234:11): [True: 1.03k, False: 0]
  ------------------
12235|  1.03k|        const size_t q_end =
12236|  1.03k|            (hash_start != std::string_view::npos) ? hash_start : len;
  ------------------
  |  Branch (12236:13): [True: 265, False: 765]
  ------------------
12237|  1.03k|        out.update_base_search(std::string_view(input.data() + query_start + 1,
12238|  1.03k|                                                q_end - query_start - 1),
12239|  1.03k|                               character_sets::SPECIAL_QUERY_PERCENT_ENCODE);
12240|  1.03k|      }
12241|  1.03k|      if (hash_start != std::string_view::npos) {
  ------------------
  |  Branch (12241:11): [True: 265, False: 765]
  ------------------
12242|    265|        out.update_unencoded_base_hash(std::string_view(
12243|    265|            input.data() + hash_start + 1, len - hash_start - 1));
12244|    265|      }
12245|  1.03k|    };
_ZN3ada7helpers10prune_hashERNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8504|    509|    std::string_view& input) noexcept {
 8505|       |  // compiles down to 20--30 instructions including a class to memchr (C
 8506|       |  // function). this function should be quite fast.
 8507|    509|  size_t location_of_first = input.find('#');
 8508|    509|  if (location_of_first == std::string_view::npos) {
  ------------------
  |  Branch (8508:7): [True: 376, False: 133]
  ------------------
 8509|    376|    return std::nullopt;
 8510|    376|  }
 8511|    133|  std::string_view hash = input;
 8512|    133|  hash.remove_prefix(location_of_first + 1);
 8513|    133|  input.remove_suffix(input.size() - location_of_first);
 8514|    133|  return hash;
 8515|    509|}
_ZN3ada7helpers32find_authority_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9462|     48|find_authority_delimiter_special(std::string_view view) noexcept {
 9463|       |  // performance note: we might be able to gain further performance
 9464|       |  // with SIMD intrinsics.
 9465|    576|  for (auto pos = view.begin(); pos != view.end(); ++pos) {
  ------------------
  |  Branch (9465:33): [True: 576, False: 0]
  ------------------
 9466|    576|    if (authority_delimiter_special[(uint8_t)*pos]) {
  ------------------
  |  Branch (9466:9): [True: 48, False: 528]
  ------------------
 9467|     48|      return pos - view.begin();
 9468|     48|    }
 9469|    576|  }
 9470|      0|  return size_t(view.size());
 9471|     48|}
_ZN3ada7helpers27get_host_delimiter_locationEbRNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9175|    509|    const bool is_special, std::string_view& view) noexcept {
 9176|       |  /**
 9177|       |   * The spec at https://url.spec.whatwg.org/#hostname-state expects us to
 9178|       |   * compute a variable called insideBrackets but this variable is only used
 9179|       |   * once, to check whether a ':' character was found outside brackets. Exact
 9180|       |   * text: "Otherwise, if c is U+003A (:) and insideBrackets is false, then:".
 9181|       |   * It is conceptually simpler and arguably more efficient to just return a
 9182|       |   * Boolean indicating whether ':' was found outside brackets.
 9183|       |   */
 9184|    509|  const size_t view_size = view.size();
 9185|    509|  size_t location = 0;
 9186|    509|  bool found_colon = false;
 9187|       |  /**
 9188|       |   * Performance analysis:
 9189|       |   *
 9190|       |   * We are basically seeking the end of the hostname which can be indicated
 9191|       |   * by the end of the view, or by one of the characters ':', '/', '?', '\\'
 9192|       |   * (where '\\' is only applicable for special URLs). However, these must
 9193|       |   * appear outside a bracket range. E.g., if you have [something?]fd: then the
 9194|       |   * '?' does not count.
 9195|       |   *
 9196|       |   * So we can skip ahead to the next delimiter, as long as we include '[' in
 9197|       |   * the set of delimiters, and that we handle it first.
 9198|       |   *
 9199|       |   * So the trick is to have a fast function that locates the next delimiter.
 9200|       |   * Unless we find '[', then it only needs to be called once! Ideally, such a
 9201|       |   * function would be provided by the C++ standard library, but it seems that
 9202|       |   * find_first_of is not very fast, so we are forced to roll our own.
 9203|       |   *
 9204|       |   * We do not break into two loops for speed, but for clarity.
 9205|       |   */
 9206|    509|  if (is_special) {
  ------------------
  |  Branch (9206:7): [True: 509, False: 0]
  ------------------
 9207|       |    // We move to the next delimiter.
 9208|    509|    location = find_next_host_delimiter_special(view, location);
 9209|       |    // Unless we find '[' then we are going only going to have to call
 9210|       |    // find_next_host_delimiter_special once.
 9211|    509|    for (; location < view_size;
  ------------------
  |  Branch (9211:12): [True: 509, False: 0]
  ------------------
 9212|    509|         location = find_next_host_delimiter_special(view, location)) {
 9213|    509|      if (view[location] == '[') {
  ------------------
  |  Branch (9213:11): [True: 0, False: 509]
  ------------------
 9214|      0|        location = view.find(']', location);
 9215|      0|        if (location == std::string_view::npos) {
  ------------------
  |  Branch (9215:13): [True: 0, False: 0]
  ------------------
 9216|       |          // performance: view.find might get translated to a memchr, which
 9217|       |          // has no notion of std::string_view::npos, so the code does not
 9218|       |          // reflect the assembly.
 9219|      0|          location = view_size;
 9220|      0|          break;
 9221|      0|        }
 9222|    509|      } else {
 9223|    509|        found_colon = view[location] == ':';
 9224|    509|        break;
 9225|    509|      }
 9226|    509|    }
 9227|    509|  } else {
 9228|       |    // We move to the next delimiter.
 9229|      0|    location = find_next_host_delimiter(view, location);
 9230|       |    // Unless we find '[' then we are going only going to have to call
 9231|       |    // find_next_host_delimiter_special once.
 9232|      0|    for (; location < view_size;
  ------------------
  |  Branch (9232:12): [True: 0, False: 0]
  ------------------
 9233|      0|         location = find_next_host_delimiter(view, location)) {
 9234|      0|      if (view[location] == '[') {
  ------------------
  |  Branch (9234:11): [True: 0, False: 0]
  ------------------
 9235|      0|        location = view.find(']', location);
 9236|      0|        if (location == std::string_view::npos) {
  ------------------
  |  Branch (9236:13): [True: 0, False: 0]
  ------------------
 9237|       |          // performance: view.find might get translated to a memchr, which
 9238|       |          // has no notion of std::string_view::npos, so the code does not
 9239|       |          // reflect the assembly.
 9240|      0|          location = view_size;
 9241|      0|          break;
 9242|      0|        }
 9243|      0|      } else {
 9244|      0|        found_colon = view[location] == ':';
 9245|      0|        break;
 9246|      0|      }
 9247|      0|    }
 9248|      0|  }
 9249|       |  // performance: remove_suffix may translate into a single instruction.
 9250|    509|  view.remove_suffix(view_size - location);
 9251|    509|  return {location, found_colon};
 9252|    509|}
_ZN3ada7helpers32find_next_host_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEm:
 8765|    509|    std::string_view view, size_t location) noexcept {
 8766|       |  // first check for short strings in which case we do it naively.
 8767|    509|  if (view.size() - location < 16) {  // slow path
  ------------------
  |  Branch (8767:7): [True: 246, False: 263]
  ------------------
 8768|  2.95k|    for (size_t i = location; i < view.size(); i++) {
  ------------------
  |  Branch (8768:31): [True: 2.95k, False: 0]
  ------------------
 8769|  2.95k|      if (view[i] == ':' || view[i] == '/' || view[i] == '\\' ||
  ------------------
  |  Branch (8769:11): [True: 0, False: 2.95k]
  |  Branch (8769:29): [True: 246, False: 2.70k]
  |  Branch (8769:47): [True: 0, False: 2.70k]
  ------------------
 8770|  2.70k|          view[i] == '?' || view[i] == '[') {
  ------------------
  |  Branch (8770:11): [True: 0, False: 2.70k]
  |  Branch (8770:29): [True: 0, False: 2.70k]
  ------------------
 8771|    246|        return i;
 8772|    246|      }
 8773|  2.95k|    }
 8774|      0|    return size_t(view.size());
 8775|    246|  }
 8776|       |  // fast path for long strings (expected to be common)
 8777|    263|  size_t i = location;
 8778|    263|  const __m128i mask1 = _mm_set1_epi8(':');
 8779|    263|  const __m128i mask2 = _mm_set1_epi8('/');
 8780|    263|  const __m128i mask3 = _mm_set1_epi8('\\');
 8781|    263|  const __m128i mask4 = _mm_set1_epi8('?');
 8782|    263|  const __m128i mask5 = _mm_set1_epi8('[');
 8783|       |
 8784|    263|  for (; i + 15 < view.size(); i += 16) {
  ------------------
  |  Branch (8784:10): [True: 263, False: 0]
  ------------------
 8785|    263|    __m128i word = _mm_loadu_si128((const __m128i*)(view.data() + i));
 8786|    263|    __m128i m1 = _mm_cmpeq_epi8(word, mask1);
 8787|    263|    __m128i m2 = _mm_cmpeq_epi8(word, mask2);
 8788|    263|    __m128i m3 = _mm_cmpeq_epi8(word, mask3);
 8789|    263|    __m128i m4 = _mm_cmpeq_epi8(word, mask4);
 8790|    263|    __m128i m5 = _mm_cmpeq_epi8(word, mask5);
 8791|    263|    __m128i m = _mm_or_si128(
 8792|    263|        _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m3, m4)), m5);
 8793|    263|    int mask = _mm_movemask_epi8(m);
 8794|    263|    if (mask != 0) {
  ------------------
  |  Branch (8794:9): [True: 263, False: 0]
  ------------------
 8795|    263|      return i + trailing_zeroes(mask);
 8796|    263|    }
 8797|    263|  }
 8798|      0|  if (i < view.size()) {
  ------------------
  |  Branch (8798:7): [True: 0, False: 0]
  ------------------
 8799|      0|    __m128i word =
 8800|      0|        _mm_loadu_si128((const __m128i*)(view.data() + view.length() - 16));
 8801|      0|    __m128i m1 = _mm_cmpeq_epi8(word, mask1);
 8802|      0|    __m128i m2 = _mm_cmpeq_epi8(word, mask2);
 8803|      0|    __m128i m3 = _mm_cmpeq_epi8(word, mask3);
 8804|      0|    __m128i m4 = _mm_cmpeq_epi8(word, mask4);
 8805|      0|    __m128i m5 = _mm_cmpeq_epi8(word, mask5);
 8806|      0|    __m128i m = _mm_or_si128(
 8807|      0|        _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m3, m4)), m5);
 8808|      0|    int mask = _mm_movemask_epi8(m);
 8809|      0|    if (mask != 0) {
  ------------------
  |  Branch (8809:9): [True: 0, False: 0]
  ------------------
 8810|      0|      return view.length() - 16 + trailing_zeroes(mask);
 8811|      0|    }
 8812|      0|  }
 8813|      0|  return size_t(view.length());
 8814|      0|}
_ZN3ada7helpers15trailing_zeroesEj:
 8585|    263|ada_really_inline int trailing_zeroes(uint32_t input_num) noexcept {
 8586|       |#ifdef ADA_REGULAR_VISUAL_STUDIO
 8587|       |  unsigned long ret;
 8588|       |  // Search the mask data from least significant bit (LSB)
 8589|       |  // to the most significant bit (MSB) for a set bit (1).
 8590|       |  _BitScanForward(&ret, input_num);
 8591|       |  return (int)ret;
 8592|       |#else   // ADA_REGULAR_VISUAL_STUDIO
 8593|    263|  return __builtin_ctzl(input_num);
 8594|    263|#endif  // ADA_REGULAR_VISUAL_STUDIO
 8595|    263|}
_ZN3ada7unicode45contains_forbidden_domain_code_point_or_upperEPKcm:
 7055|    509|                                              size_t length) noexcept {
 7056|    509|  size_t i = 0;
 7057|    509|  uint8_t accumulator{};
 7058|  1.52k|  for (; i + 4 <= length; i += 4) {
  ------------------
  |  Branch (7058:10): [True: 1.01k, False: 509]
  ------------------
 7059|  1.01k|    accumulator |=
 7060|  1.01k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i])];
 7061|  1.01k|    accumulator |=
 7062|  1.01k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 1])];
 7063|  1.01k|    accumulator |=
 7064|  1.01k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 2])];
 7065|  1.01k|    accumulator |=
 7066|  1.01k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 3])];
 7067|  1.01k|  }
 7068|  2.03k|  for (; i < length; i++) {
  ------------------
  |  Branch (7068:10): [True: 1.52k, False: 509]
  ------------------
 7069|  1.52k|    accumulator |=
 7070|  1.52k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i])];
 7071|  1.52k|  }
 7072|    509|  return accumulator;
 7073|    509|}
_ZZN3ada6parser14parse_url_implINS_14url_aggregatorELb1EEET_NSt3__117basic_string_viewIcNS4_11char_traitsIcEEEEPKS3_ENKUlvE_clEv:
12556|    509|  const auto enforce_max_input_length = [&]() {
12557|    509|    if constexpr (store_values) {
12558|    509|      if (url.is_valid) {
  ------------------
  |  Branch (12558:11): [True: 509, False: 0]
  ------------------
12559|    509|        if constexpr (result_type_is_ada_url_aggregator) {
12560|    509|          if (url.buffer.size() > max_input_length) [[unlikely]] {
  ------------------
  |  Branch (12560:15): [True: 0, False: 509]
  ------------------
12561|      0|            url.is_valid = false;
12562|      0|          }
12563|       |        } else {
12564|       |          if (url.get_href_size() > max_input_length) [[unlikely]] {
12565|       |            url.is_valid = false;
12566|       |          }
12567|       |        }
12568|    509|      }
12569|    509|    }
12570|    509|  };
url_search_params.cc:_ZN3ada6parser12_GLOBAL__N_116authority_has_atEPKhmm:
11044|  2.99k|                                        size_t n) noexcept {
11045|  2.99k|  const size_t rem = n - host_start;
11046|  2.99k|  if (rem == 0) {
  ------------------
  |  Branch (11046:7): [True: 0, False: 2.99k]
  ------------------
11047|      0|    return false;
11048|      0|  }
11049|       |#if ADA_NEON
11050|       |  if (rem >= 16) {
11051|       |    const uint8x16_t w = vld1q_u8(p + host_start);
11052|       |    const uint64_t at = neon_nibble_bits(vceqq_u8(w, vdupq_n_u8('@')));
11053|       |    if (at == 0) {
11054|       |      return false;
11055|       |    }
11056|       |    const uint64_t delim = neon_nibble_bits(vceqq_u8(w, vdupq_n_u8('/'))) |
11057|       |                           neon_nibble_bits(vceqq_u8(w, vdupq_n_u8('?'))) |
11058|       |                           neon_nibble_bits(vceqq_u8(w, vdupq_n_u8('#')));
11059|       |    return delim == 0 || std::countr_zero(at) < std::countr_zero(delim);
11060|       |  }
11061|       |#elif ADA_SSE2
11062|  2.99k|  if (rem >= 16) {
  ------------------
  |  Branch (11062:7): [True: 1.44k, False: 1.54k]
  ------------------
11063|  1.44k|    const __m128i w =
11064|  1.44k|        _mm_loadu_si128(reinterpret_cast<const __m128i*>(p + host_start));
11065|  1.44k|    const uint16_t at = static_cast<uint16_t>(
11066|  1.44k|        _mm_movemask_epi8(_mm_cmpeq_epi8(w, _mm_set1_epi8('@'))));
11067|  1.44k|    if (at == 0) {
  ------------------
  |  Branch (11067:9): [True: 1.40k, False: 43]
  ------------------
11068|  1.40k|      return false;
11069|  1.40k|    }
11070|     43|    const uint16_t delim = static_cast<uint16_t>(
11071|     43|        _mm_movemask_epi8(_mm_cmpeq_epi8(w, _mm_set1_epi8('/'))) |
11072|     43|        _mm_movemask_epi8(_mm_cmpeq_epi8(w, _mm_set1_epi8('?'))) |
11073|     43|        _mm_movemask_epi8(_mm_cmpeq_epi8(w, _mm_set1_epi8('#'))));
11074|     43|    return delim == 0 || std::countr_zero(at) < std::countr_zero(delim);
  ------------------
  |  Branch (11074:12): [True: 0, False: 43]
  |  Branch (11074:26): [True: 0, False: 43]
  ------------------
11075|  1.44k|  }
11076|  1.54k|#endif
11077|  1.54k|  const size_t lim = host_start + rem;
11078|  18.5k|  for (size_t i = host_start; i < lim; ++i) {
  ------------------
  |  Branch (11078:31): [True: 18.5k, False: 0]
  ------------------
11079|  18.5k|    const uint8_t c = p[i];
11080|  18.5k|    if (c == '@') {
  ------------------
  |  Branch (11080:9): [True: 0, False: 18.5k]
  ------------------
11081|      0|      return true;
11082|      0|    }
11083|  18.5k|    if (c == '/' || c == '?' || c == '#') {
  ------------------
  |  Branch (11083:9): [True: 1.54k, False: 17.0k]
  |  Branch (11083:21): [True: 0, False: 17.0k]
  |  Branch (11083:33): [True: 0, False: 17.0k]
  ------------------
11084|  1.54k|      return false;
11085|  1.54k|    }
11086|  18.5k|  }
11087|      0|  return false;
11088|  1.54k|}
url_search_params.cc:_ZN3ada6parser12_GLOBAL__N_115scan_plain_hostEPKhmmRmRbS5_:
11095|  2.99k|                                     bool& has_x) noexcept {
11096|  2.99k|  has_upper = false;
11097|  2.99k|  has_x = false;
11098|  2.99k|  size_t i = start;
11099|  2.99k|#if ADA_PARSER_SSSE3
11100|  2.99k|  if (len - start >= 16) {
  ------------------
  |  Branch (11100:7): [True: 1.44k, False: 1.54k]
  ------------------
11101|  1.44k|    const __m128i lo_tbl = nibble_load(k_host_nibbles.low);
11102|  1.44k|    const __m128i hi_tbl = nibble_load(k_host_nibbles.high);
11103|  1.44k|    const __m128i x_splat = _mm_set1_epi8('x');
11104|  1.44k|    auto visit = [&](size_t at) noexcept -> bool {
11105|  1.44k|      const __m128i w =
11106|  1.44k|          _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + at));
11107|  1.44k|      const int up = sse2_uppercase(w);
11108|  1.44k|      const int xs = _mm_movemask_epi8(_mm_cmpeq_epi8(w, x_splat));
11109|  1.44k|      const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl);
11110|  1.44k|      if (mask == 0) {
11111|  1.44k|        if (up != 0) {
11112|  1.44k|          has_upper = true;
11113|  1.44k|        }
11114|  1.44k|        if (xs != 0) {
11115|  1.44k|          has_x = true;
11116|  1.44k|        }
11117|  1.44k|        return false;
11118|  1.44k|      }
11119|  1.44k|      const int hit = trailing_zeroes32(static_cast<uint32_t>(mask));
11120|  1.44k|      const int valid = (1 << hit) - 1;
11121|  1.44k|      if ((up & valid) != 0) {
11122|  1.44k|        has_upper = true;
11123|  1.44k|      }
11124|  1.44k|      if ((xs & valid) != 0) {
11125|  1.44k|        has_x = true;
11126|  1.44k|      }
11127|  1.44k|      end = at + static_cast<size_t>(hit);
11128|  1.44k|      return true;
11129|  1.44k|    };
11130|  1.44k|    for (; i + 32 <= len; i += 32) {
  ------------------
  |  Branch (11130:12): [True: 872, False: 575]
  ------------------
11131|    872|      if (visit(i) || visit(i + 16)) {
  ------------------
  |  Branch (11131:11): [True: 872, False: 0]
  |  Branch (11131:23): [True: 0, False: 0]
  ------------------
11132|    872|        return k_host_class[b[end]] == 1;
11133|    872|      }
11134|    872|    }
11135|    575|    for (; i + 16 <= len; i += 16) {
  ------------------
  |  Branch (11135:12): [True: 575, False: 0]
  ------------------
11136|    575|      if (visit(i)) {
  ------------------
  |  Branch (11136:11): [True: 575, False: 0]
  ------------------
11137|    575|        return k_host_class[b[end]] == 1;
11138|    575|      }
11139|    575|    }
11140|       |    // Overlapping tail only after a full 16-byte step so the window cannot
11141|       |    // start before `start` (a prior '/' would otherwise look like a host stop).
11142|      0|    if (i > start && i < len) {
  ------------------
  |  Branch (11142:9): [True: 0, False: 0]
  |  Branch (11142:22): [True: 0, False: 0]
  ------------------
11143|      0|      if (visit(len - 16) && end >= i) {
  ------------------
  |  Branch (11143:11): [True: 0, False: 0]
  |  Branch (11143:30): [True: 0, False: 0]
  ------------------
11144|      0|        return k_host_class[b[end]] == 1;
11145|      0|      }
11146|      0|      end = len;
11147|      0|      return true;
11148|      0|    }
11149|      0|  }
11150|       |#elif ADA_SSE2
11151|       |  const __m128i x_splat = _mm_set1_epi8('x');
11152|       |  for (; i + 32 <= len; i += 32) {
11153|       |    for (size_t off = 0; off < 32; off += 16) {
11154|       |      const __m128i w =
11155|       |          _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i + off));
11156|       |      const int up = sse2_uppercase(w);
11157|       |      const int xs = _mm_movemask_epi8(_mm_cmpeq_epi8(w, x_splat));
11158|       |      const int mask = sse2_host_stop(w);
11159|       |      if (mask != 0) {
11160|       |        const int hit = trailing_zeroes32(static_cast<uint32_t>(mask));
11161|       |        const int valid = (1 << hit) - 1;
11162|       |        if ((up & valid) != 0) {
11163|       |          has_upper = true;
11164|       |        }
11165|       |        if ((xs & valid) != 0) {
11166|       |          has_x = true;
11167|       |        }
11168|       |        end = i + off + static_cast<size_t>(hit);
11169|       |        return k_host_class[b[end]] == 1;
11170|       |      }
11171|       |      if (up != 0) {
11172|       |        has_upper = true;
11173|       |      }
11174|       |      if (xs != 0) {
11175|       |        has_x = true;
11176|       |      }
11177|       |    }
11178|       |  }
11179|       |  for (; i + 16 <= len; i += 16) {
11180|       |    const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i));
11181|       |    const int up = sse2_uppercase(w);
11182|       |    const int xs = _mm_movemask_epi8(_mm_cmpeq_epi8(w, x_splat));
11183|       |    const int mask = sse2_host_stop(w);
11184|       |    if (mask != 0) {
11185|       |      const int hit = trailing_zeroes32(static_cast<uint32_t>(mask));
11186|       |      const int valid = (1 << hit) - 1;
11187|       |      if ((up & valid) != 0) {
11188|       |        has_upper = true;
11189|       |      }
11190|       |      if ((xs & valid) != 0) {
11191|       |        has_x = true;
11192|       |      }
11193|       |      end = i + static_cast<size_t>(hit);
11194|       |      return k_host_class[b[end]] == 1;
11195|       |    }
11196|       |    if (up != 0) {
11197|       |      has_upper = true;
11198|       |    }
11199|       |    if (xs != 0) {
11200|       |      has_x = true;
11201|       |    }
11202|       |  }
11203|       |#elif ADA_NEON
11204|       |  if (len - start >= 16) {
11205|       |    const uint8x16_t lo_tbl = vld1q_u8(k_host_nibbles.low);
11206|       |    const uint8x16_t hi_tbl = vld1q_u8(k_host_nibbles.high);
11207|       |    const uint8x16_t x_splat = vdupq_n_u8('x');
11208|       |    auto visit = [&](size_t at) noexcept -> bool {
11209|       |      const uint8x16_t w = vld1q_u8(b + at);
11210|       |      const uint64_t up = neon_uppercase(w);
11211|       |      const uint64_t xs = neon_nibble_bits(vceqq_u8(w, x_splat));
11212|       |      const uint64_t bits = neon_table_stop(w, lo_tbl, hi_tbl);
11213|       |      if (bits == 0) {
11214|       |        if (up != 0) {
11215|       |          has_upper = true;
11216|       |        }
11217|       |        if (xs != 0) {
11218|       |          has_x = true;
11219|       |        }
11220|       |        return false;
11221|       |      }
11222|       |      const size_t hit = static_cast<size_t>(trailing_zeroes64(bits)) >> 2;
11223|       |      const uint64_t valid = (hit == 0) ? 0 : (uint64_t{1} << (hit * 4)) - 1;
11224|       |      if ((up & valid) != 0) {
11225|       |        has_upper = true;
11226|       |      }
11227|       |      if ((xs & valid) != 0) {
11228|       |        has_x = true;
11229|       |      }
11230|       |      end = at + hit;
11231|       |      return true;
11232|       |    };
11233|       |    for (; i + 32 <= len; i += 32) {
11234|       |      if (visit(i) || visit(i + 16)) {
11235|       |        return k_host_class[b[end]] == 1;
11236|       |      }
11237|       |    }
11238|       |    for (; i + 16 <= len; i += 16) {
11239|       |      if (visit(i)) {
11240|       |        return k_host_class[b[end]] == 1;
11241|       |      }
11242|       |    }
11243|       |    if (i > start && i < len) {
11244|       |      if (visit(len - 16) && end >= i) {
11245|       |        return k_host_class[b[end]] == 1;
11246|       |      }
11247|       |      end = len;
11248|       |      return true;
11249|       |    }
11250|       |  }
11251|       |#endif
11252|  18.5k|  for (; i < len; ++i) {
  ------------------
  |  Branch (11252:10): [True: 18.5k, False: 0]
  ------------------
11253|  18.5k|    const uint8_t c = b[i];
11254|  18.5k|    const uint8_t cls = k_host_class[c];
11255|  18.5k|    if (cls == 1) {
  ------------------
  |  Branch (11255:9): [True: 1.54k, False: 17.0k]
  ------------------
11256|  1.54k|      end = i;
11257|  1.54k|      return true;
11258|  1.54k|    }
11259|  17.0k|    if (cls == 2) {
  ------------------
  |  Branch (11259:9): [True: 0, False: 17.0k]
  ------------------
11260|      0|      return false;
11261|      0|    }
11262|  17.0k|    if (c >= 'A' && c <= 'Z') {
  ------------------
  |  Branch (11262:9): [True: 15.4k, False: 1.54k]
  |  Branch (11262:21): [True: 0, False: 15.4k]
  ------------------
11263|      0|      has_upper = true;
11264|  17.0k|    } else if (c == 'x') {
  ------------------
  |  Branch (11264:16): [True: 1.54k, False: 15.4k]
  ------------------
11265|  1.54k|      has_x = true;
11266|  1.54k|    }
11267|  17.0k|  }
11268|      0|  end = len;
11269|      0|  return true;
11270|  1.54k|}
url_search_params.cc:_ZN3ada6parser12_GLOBAL__N_111nibble_loadEPKh:
10925|  7.24k|ADA_PARSER_SIMD __m128i nibble_load(const uint8_t* t) noexcept {
10926|  7.24k|  return _mm_load_si128(reinterpret_cast<const __m128i*>(t));
10927|  7.24k|}
url_search_params.cc:_ZZN3ada6parser12_GLOBAL__N_115scan_plain_hostEPKhmmRmRbS5_ENK3$_0clEm:
11104|  1.44k|    auto visit = [&](size_t at) noexcept -> bool {
11105|  1.44k|      const __m128i w =
11106|  1.44k|          _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + at));
11107|  1.44k|      const int up = sse2_uppercase(w);
11108|  1.44k|      const int xs = _mm_movemask_epi8(_mm_cmpeq_epi8(w, x_splat));
11109|  1.44k|      const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl);
11110|  1.44k|      if (mask == 0) {
  ------------------
  |  Branch (11110:11): [True: 0, False: 1.44k]
  ------------------
11111|      0|        if (up != 0) {
  ------------------
  |  Branch (11111:13): [True: 0, False: 0]
  ------------------
11112|      0|          has_upper = true;
11113|      0|        }
11114|      0|        if (xs != 0) {
  ------------------
  |  Branch (11114:13): [True: 0, False: 0]
  ------------------
11115|      0|          has_x = true;
11116|      0|        }
11117|      0|        return false;
11118|      0|      }
11119|  1.44k|      const int hit = trailing_zeroes32(static_cast<uint32_t>(mask));
11120|  1.44k|      const int valid = (1 << hit) - 1;
11121|  1.44k|      if ((up & valid) != 0) {
  ------------------
  |  Branch (11121:11): [True: 0, False: 1.44k]
  ------------------
11122|      0|        has_upper = true;
11123|      0|      }
11124|  1.44k|      if ((xs & valid) != 0) {
  ------------------
  |  Branch (11124:11): [True: 1.44k, False: 0]
  ------------------
11125|  1.44k|        has_x = true;
11126|  1.44k|      }
11127|  1.44k|      end = at + static_cast<size_t>(hit);
11128|  1.44k|      return true;
11129|  1.44k|    };
url_search_params.cc:_ZN3ada6parser12_GLOBAL__N_114sse2_uppercaseEDv2_x:
11012|  1.44k|ada_really_inline int sse2_uppercase(__m128i w) noexcept {
11013|  1.44k|  return _mm_movemask_epi8(_mm_and_si128(
11014|  1.44k|      _mm_cmpgt_epi8(w, _mm_set1_epi8(static_cast<char>('A' - 1))),
11015|  1.44k|      _mm_cmplt_epi8(w, _mm_set1_epi8(static_cast<char>('Z' + 1)))));
11016|  1.44k|}
url_search_params.cc:_ZN3ada6parser12_GLOBAL__N_117ssse3_nibble_maskEDv2_xS2_S2_:
10932|  4.71k|                                      __m128i hi_tbl) noexcept {
10933|  4.71k|  const __m128i nibble = _mm_set1_epi8(0x0F);
10934|  4.71k|  const __m128i lo = _mm_and_si128(w, nibble);
10935|  4.71k|  const __m128i hi = _mm_and_si128(_mm_srli_epi16(w, 4), nibble);
10936|  4.71k|  const __m128i hit =
10937|  4.71k|      _mm_and_si128(_mm_shuffle_epi8(lo_tbl, lo), _mm_shuffle_epi8(hi_tbl, hi));
10938|  4.71k|  return _mm_movemask_epi8(_mm_cmpeq_epi8(hit, _mm_setzero_si128())) ^ 0xFFFF;
10939|  4.71k|}
url_search_params.cc:_ZN3ada6parser12_GLOBAL__N_117trailing_zeroes32Ej:
10904|  3.50k|ada_really_inline int trailing_zeroes32(uint32_t input_num) noexcept {
10905|       |#ifdef ADA_REGULAR_VISUAL_STUDIO
10906|       |  unsigned long ret;
10907|       |  _BitScanForward(&ret, input_num);
10908|       |  return static_cast<int>(ret);
10909|       |#else
10910|  3.50k|  return __builtin_ctz(input_num);
10911|  3.50k|#endif
10912|  3.50k|}
url_search_params.cc:_ZN3ada6parser12_GLOBAL__N_113scan_path_runEPKhRmmRb:
11330|  2.99k|                                   bool& maybe_dot_segment) noexcept {
11331|  2.99k|  const size_t run_start = i;
11332|  2.99k|#if ADA_PARSER_SSSE3
11333|  2.99k|  if (i + 16 <= len) {
  ------------------
  |  Branch (11333:7): [True: 1.00k, False: 1.99k]
  ------------------
11334|  1.00k|    const __m128i lo_tbl = nibble_load(k_path_nibbles.low);
11335|  1.00k|    const __m128i hi_tbl = nibble_load(k_path_nibbles.high);
11336|  1.00k|    for (; i + 32 <= len; i += 32) {
  ------------------
  |  Branch (11336:12): [True: 703, False: 302]
  ------------------
11337|    703|      const __m128i w0 =
11338|    703|          _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i));
11339|    703|      const int m0 = ssse3_nibble_mask(w0, lo_tbl, hi_tbl);
11340|    703|      if (m0 != 0) {
  ------------------
  |  Branch (11340:11): [True: 703, False: 0]
  ------------------
11341|    703|        const int hit_bit = trailing_zeroes32(static_cast<uint32_t>(m0));
11342|    703|        note_dots_in_window(b, i, run_start, w0, (1 << hit_bit) - 1,
11343|    703|                            maybe_dot_segment);
11344|    703|        i += static_cast<size_t>(hit_bit);
11345|    703|        return;
11346|    703|      }
11347|      0|      note_dots_in_window(b, i, run_start, w0, 0xFFFF, maybe_dot_segment);
11348|      0|      const __m128i w1 =
11349|      0|          _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i + 16));
11350|      0|      const int m1 = ssse3_nibble_mask(w1, lo_tbl, hi_tbl);
11351|      0|      if (m1 != 0) {
  ------------------
  |  Branch (11351:11): [True: 0, False: 0]
  ------------------
11352|      0|        const int hit_bit = trailing_zeroes32(static_cast<uint32_t>(m1));
11353|      0|        note_dots_in_window(b, i + 16, run_start, w1, (1 << hit_bit) - 1,
11354|      0|                            maybe_dot_segment);
11355|      0|        i += 16 + static_cast<size_t>(hit_bit);
11356|      0|        return;
11357|      0|      }
11358|      0|      note_dots_in_window(b, i + 16, run_start, w1, 0xFFFF, maybe_dot_segment);
11359|      0|    }
11360|    302|    for (; i + 16 <= len; i += 16) {
  ------------------
  |  Branch (11360:12): [True: 302, False: 0]
  ------------------
11361|    302|      const __m128i w =
11362|    302|          _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i));
11363|    302|      const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl);
11364|    302|      if (mask != 0) {
  ------------------
  |  Branch (11364:11): [True: 302, False: 0]
  ------------------
11365|    302|        const int hit_bit = trailing_zeroes32(static_cast<uint32_t>(mask));
11366|    302|        note_dots_in_window(b, i, run_start, w, (1 << hit_bit) - 1,
11367|    302|                            maybe_dot_segment);
11368|    302|        i += static_cast<size_t>(hit_bit);
11369|    302|        return;
11370|    302|      }
11371|      0|      note_dots_in_window(b, i, run_start, w, 0xFFFF, maybe_dot_segment);
11372|      0|    }
11373|      0|    if (i > run_start && i < len) {
  ------------------
  |  Branch (11373:9): [True: 0, False: 0]
  |  Branch (11373:26): [True: 0, False: 0]
  ------------------
11374|      0|      const __m128i w =
11375|      0|          _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + len - 16));
11376|      0|      const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl);
11377|      0|      if (mask != 0) {
  ------------------
  |  Branch (11377:11): [True: 0, False: 0]
  ------------------
11378|      0|        const size_t hit =
11379|      0|            len - 16 +
11380|      0|            static_cast<size_t>(trailing_zeroes32(static_cast<uint32_t>(mask)));
11381|      0|        if (hit >= i) {
  ------------------
  |  Branch (11381:13): [True: 0, False: 0]
  ------------------
11382|      0|          for (size_t j = i; j < hit; ++j) {
  ------------------
  |  Branch (11382:30): [True: 0, False: 0]
  ------------------
11383|      0|            if (b[j] == '.') {
  ------------------
  |  Branch (11383:17): [True: 0, False: 0]
  ------------------
11384|      0|              note_possible_dot_segment(b, j, run_start, maybe_dot_segment);
11385|      0|            }
11386|      0|          }
11387|      0|          i = hit;
11388|      0|          return;
11389|      0|        }
11390|      0|      }
11391|      0|      for (size_t j = i; j < len; ++j) {
  ------------------
  |  Branch (11391:26): [True: 0, False: 0]
  ------------------
11392|      0|        if (b[j] == '.') {
  ------------------
  |  Branch (11392:13): [True: 0, False: 0]
  ------------------
11393|      0|          note_possible_dot_segment(b, j, run_start, maybe_dot_segment);
11394|      0|        }
11395|      0|      }
11396|      0|      i = len;
11397|      0|      return;
11398|      0|    }
11399|      0|  }
11400|       |#elif ADA_SSE2
11401|       |  for (; i + 16 <= len; i += 16) {
11402|       |    const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i));
11403|       |    const int mask = sse2_path_stop(w);
11404|       |    if (mask != 0) {
11405|       |      const int hit_bit = trailing_zeroes32(static_cast<uint32_t>(mask));
11406|       |      note_dots_in_window(b, i, run_start, w, (1 << hit_bit) - 1,
11407|       |                          maybe_dot_segment);
11408|       |      i += static_cast<size_t>(hit_bit);
11409|       |      return;
11410|       |    }
11411|       |    note_dots_in_window(b, i, run_start, w, 0xFFFF, maybe_dot_segment);
11412|       |  }
11413|       |#elif ADA_NEON
11414|       |  if (i + 16 <= len) {
11415|       |    const uint8x16_t lo_tbl = vld1q_u8(k_path_nibbles.low);
11416|       |    const uint8x16_t hi_tbl = vld1q_u8(k_path_nibbles.high);
11417|       |    for (; i + 32 <= len; i += 32) {
11418|       |      const uint8x16_t w0 = vld1q_u8(b + i);
11419|       |      const uint64_t bits0 = neon_table_stop(w0, lo_tbl, hi_tbl);
11420|       |      if (bits0 != 0) {
11421|       |        const size_t hit_off =
11422|       |            static_cast<size_t>(trailing_zeroes64(bits0)) >> 2;
11423|       |        const uint64_t valid =
11424|       |            (hit_off == 0) ? 0 : (uint64_t{1} << (hit_off * 4)) - 1;
11425|       |        note_dots_in_window_neon(b, i, run_start, w0, valid, maybe_dot_segment);
11426|       |        i += hit_off;
11427|       |        return;
11428|       |      }
11429|       |      note_dots_in_window_neon(b, i, run_start, w0, ~uint64_t{0},
11430|       |                               maybe_dot_segment);
11431|       |      const uint8x16_t w1 = vld1q_u8(b + i + 16);
11432|       |      const uint64_t bits1 = neon_table_stop(w1, lo_tbl, hi_tbl);
11433|       |      if (bits1 != 0) {
11434|       |        const size_t hit_off =
11435|       |            static_cast<size_t>(trailing_zeroes64(bits1)) >> 2;
11436|       |        const uint64_t valid =
11437|       |            (hit_off == 0) ? 0 : (uint64_t{1} << (hit_off * 4)) - 1;
11438|       |        note_dots_in_window_neon(b, i + 16, run_start, w1, valid,
11439|       |                                 maybe_dot_segment);
11440|       |        i += 16 + hit_off;
11441|       |        return;
11442|       |      }
11443|       |      note_dots_in_window_neon(b, i + 16, run_start, w1, ~uint64_t{0},
11444|       |                               maybe_dot_segment);
11445|       |    }
11446|       |    for (; i + 16 <= len; i += 16) {
11447|       |      const uint8x16_t w = vld1q_u8(b + i);
11448|       |      const uint64_t bits = neon_table_stop(w, lo_tbl, hi_tbl);
11449|       |      if (bits != 0) {
11450|       |        const size_t hit_off =
11451|       |            static_cast<size_t>(trailing_zeroes64(bits)) >> 2;
11452|       |        const uint64_t valid =
11453|       |            (hit_off == 0) ? 0 : (uint64_t{1} << (hit_off * 4)) - 1;
11454|       |        note_dots_in_window_neon(b, i, run_start, w, valid, maybe_dot_segment);
11455|       |        i += hit_off;
11456|       |        return;
11457|       |      }
11458|       |      note_dots_in_window_neon(b, i, run_start, w, ~uint64_t{0},
11459|       |                               maybe_dot_segment);
11460|       |    }
11461|       |    if (i > run_start && i < len) {
11462|       |      const uint8x16_t w = vld1q_u8(b + len - 16);
11463|       |      const uint64_t bits = neon_table_stop(w, lo_tbl, hi_tbl);
11464|       |      if (bits != 0) {
11465|       |        const size_t hit =
11466|       |            len - 16 + (static_cast<size_t>(trailing_zeroes64(bits)) >> 2);
11467|       |        if (hit >= i) {
11468|       |          for (size_t j = i; j < hit; ++j) {
11469|       |            if (b[j] == '.') {
11470|       |              note_possible_dot_segment(b, j, run_start, maybe_dot_segment);
11471|       |            }
11472|       |          }
11473|       |          i = hit;
11474|       |          return;
11475|       |        }
11476|       |      }
11477|       |      for (size_t j = i; j < len; ++j) {
11478|       |        if (b[j] == '.') {
11479|       |          note_possible_dot_segment(b, j, run_start, maybe_dot_segment);
11480|       |        }
11481|       |      }
11482|       |      i = len;
11483|       |      return;
11484|       |    }
11485|       |  }
11486|       |#endif
11487|  1.99k|  for (; i < len; ++i) {
  ------------------
  |  Branch (11487:10): [True: 1.99k, False: 0]
  ------------------
11488|  1.99k|    const uint8_t c = b[i];
11489|  1.99k|    const uint8_t cls = k_path[c];
11490|  1.99k|    if (cls != 0) {
  ------------------
  |  Branch (11490:9): [True: 1.99k, False: 0]
  ------------------
11491|  1.99k|      return;
11492|  1.99k|    }
11493|      0|    if (c == '.') {
  ------------------
  |  Branch (11493:9): [True: 0, False: 0]
  ------------------
11494|      0|      note_possible_dot_segment(b, i, run_start, maybe_dot_segment);
11495|      0|    }
11496|      0|  }
11497|  1.99k|}
url_search_params.cc:_ZN3ada6parser12_GLOBAL__N_119note_dots_in_windowEPKhmmDv2_xiRb:
11287|  1.00k|                                           bool& maybe_dot_segment) noexcept {
11288|  1.00k|  if (maybe_dot_segment || valid_mask == 0) {
  ------------------
  |  Branch (11288:7): [True: 0, False: 1.00k]
  |  Branch (11288:28): [True: 1.00k, False: 0]
  ------------------
11289|  1.00k|    return;
11290|  1.00k|  }
11291|      0|  const int dots =
11292|      0|      _mm_movemask_epi8(_mm_cmpeq_epi8(w, _mm_set1_epi8('.'))) & valid_mask;
11293|      0|  if (dots == 0) {
  ------------------
  |  Branch (11293:7): [True: 0, False: 0]
  ------------------
11294|      0|    return;
11295|      0|  }
11296|      0|  const int slashes =
11297|      0|      _mm_movemask_epi8(_mm_cmpeq_epi8(w, _mm_set1_epi8('/'))) & valid_mask;
11298|      0|  if (((dots & 1) != 0 && (i == run_start || b[i - 1] == '/')) ||
  ------------------
  |  Branch (11298:8): [True: 0, False: 0]
  |  Branch (11298:28): [True: 0, False: 0]
  |  Branch (11298:46): [True: 0, False: 0]
  ------------------
11299|      0|      (dots & (slashes << 1)) != 0) {
  ------------------
  |  Branch (11299:7): [True: 0, False: 0]
  ------------------
11300|      0|    maybe_dot_segment = true;
11301|      0|  }
11302|      0|}
url_search_params.cc:_ZN3ada6parser12_GLOBAL__N_114scan_query_runEPKhRmm:
11640|  2.99k|                                    size_t len) noexcept {
11641|  2.99k|  ADA_SCAN_STOP_RUN(k_query_nibbles, k_query, sse2_query_stop);
  ------------------
  |  |11503|  2.99k|  do {                                                                       \
  |  |11504|  2.99k|    const size_t scan_start = i;                                             \
  |  |11505|  2.99k|    if (i + 16 <= len) {                                                     \
  |  |  ------------------
  |  |  |  Branch (11505:9): [True: 970, False: 2.02k]
  |  |  ------------------
  |  |11506|    970|      const __m128i lo_tbl = nibble_load((nibbles).low);                     \
  |  |11507|    970|      const __m128i hi_tbl = nibble_load((nibbles).high);                    \
  |  |11508|  1.33k|      for (; i + 32 <= len; i += 32) {                                       \
  |  |  ------------------
  |  |  |  Branch (11508:14): [True: 941, False: 390]
  |  |  ------------------
  |  |11509|    941|        const __m128i w0 =                                                   \
  |  |11510|    941|            _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i));        \
  |  |11511|    941|        const int m0 = ssse3_nibble_mask(w0, lo_tbl, hi_tbl);                \
  |  |11512|    941|        if (m0 != 0) {                                                       \
  |  |  ------------------
  |  |  |  Branch (11512:13): [True: 519, False: 422]
  |  |  ------------------
  |  |11513|    519|          i += static_cast<size_t>(                                          \
  |  |11514|    519|              trailing_zeroes32(static_cast<uint32_t>(m0)));                 \
  |  |11515|    519|          return;                                                            \
  |  |11516|    519|        }                                                                    \
  |  |11517|    941|        const __m128i w1 =                                                   \
  |  |11518|    422|            _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i + 16));   \
  |  |11519|    422|        const int m1 = ssse3_nibble_mask(w1, lo_tbl, hi_tbl);                \
  |  |11520|    422|        if (m1 != 0) {                                                       \
  |  |  ------------------
  |  |  |  Branch (11520:13): [True: 61, False: 361]
  |  |  ------------------
  |  |11521|     61|          i += 16 + static_cast<size_t>(                                     \
  |  |11522|     61|                        trailing_zeroes32(static_cast<uint32_t>(m1)));       \
  |  |11523|     61|          return;                                                            \
  |  |11524|     61|        }                                                                    \
  |  |11525|    422|      }                                                                      \
  |  |11526|    970|      for (; i + 16 <= len; i += 16) {                                       \
  |  |  ------------------
  |  |  |  Branch (11526:14): [True: 334, False: 154]
  |  |  ------------------
  |  |11527|    334|        const __m128i w =                                                    \
  |  |11528|    334|            _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i));        \
  |  |11529|    334|        const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl);               \
  |  |11530|    334|        if (mask != 0) {                                                     \
  |  |  ------------------
  |  |  |  Branch (11530:13): [True: 236, False: 98]
  |  |  ------------------
  |  |11531|    236|          i += static_cast<size_t>(                                          \
  |  |11532|    236|              trailing_zeroes32(static_cast<uint32_t>(mask)));               \
  |  |11533|    236|          return;                                                            \
  |  |11534|    236|        }                                                                    \
  |  |11535|    334|      }                                                                      \
  |  |11536|    390|      if (i > scan_start && i < len) {                                       \
  |  |  ------------------
  |  |  |  Branch (11536:11): [True: 154, False: 0]
  |  |  |  Branch (11536:29): [True: 124, False: 30]
  |  |  ------------------
  |  |11537|    124|        const __m128i w =                                                    \
  |  |11538|    124|            _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + len - 16)); \
  |  |11539|    124|        const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl);               \
  |  |11540|    124|        if (mask != 0) {                                                     \
  |  |  ------------------
  |  |  |  Branch (11540:13): [True: 62, False: 62]
  |  |  ------------------
  |  |11541|     62|          const size_t hit = len - 16 +                                      \
  |  |11542|     62|                             static_cast<size_t>(trailing_zeroes32(          \
  |  |11543|     62|                                 static_cast<uint32_t>(mask)));              \
  |  |11544|     62|          if (hit >= i) {                                                    \
  |  |  ------------------
  |  |  |  Branch (11544:15): [True: 62, False: 0]
  |  |  ------------------
  |  |11545|     62|            i = hit;                                                         \
  |  |11546|     62|            return;                                                          \
  |  |11547|     62|          }                                                                  \
  |  |11548|     62|        }                                                                    \
  |  |11549|    124|        i = len;                                                             \
  |  |11550|     62|        return;                                                              \
  |  |11551|    124|      }                                                                      \
  |  |11552|    154|    }                                                                        \
  |  |11553|  3.04k|    for (; i < len; ++i) {                                                   \
  |  |  ------------------
  |  |  |  Branch (11553:12): [True: 1.72k, False: 1.31k]
  |  |  ------------------
  |  |11554|  1.72k|      if ((cls)[b[i]] != 0) {                                                \
  |  |  ------------------
  |  |  |  Branch (11554:11): [True: 739, False: 987]
  |  |  ------------------
  |  |11555|    739|        return;                                                              \
  |  |11556|    739|      }                                                                      \
  |  |11557|  1.72k|    }                                                                        \
  |  |11558|  2.05k|  } while (0)
  |  |  ------------------
  |  |  |  Branch (11558:12): [Folded, False: 1.31k]
  |  |  ------------------
  ------------------
11642|  2.99k|}
url_search_params.cc:_ZN3ada6parser12_GLOBAL__N_113scan_hash_runEPKhRmm:
11645|    285|                                   size_t len) noexcept {
11646|    285|  ADA_SCAN_STOP_RUN(k_hash_nibbles, k_hash, sse2_hash_stop);
  ------------------
  |  |11503|    285|  do {                                                                       \
  |  |11504|    285|    const size_t scan_start = i;                                             \
  |  |11505|    285|    if (i + 16 <= len) {                                                     \
  |  |  ------------------
  |  |  |  Branch (11505:9): [True: 199, False: 86]
  |  |  ------------------
  |  |11506|    199|      const __m128i lo_tbl = nibble_load((nibbles).low);                     \
  |  |11507|    199|      const __m128i hi_tbl = nibble_load((nibbles).high);                    \
  |  |11508|    277|      for (; i + 32 <= len; i += 32) {                                       \
  |  |  ------------------
  |  |  |  Branch (11508:14): [True: 151, False: 126]
  |  |  ------------------
  |  |11509|    151|        const __m128i w0 =                                                   \
  |  |11510|    151|            _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i));        \
  |  |11511|    151|        const int m0 = ssse3_nibble_mask(w0, lo_tbl, hi_tbl);                \
  |  |11512|    151|        if (m0 != 0) {                                                       \
  |  |  ------------------
  |  |  |  Branch (11512:13): [True: 41, False: 110]
  |  |  ------------------
  |  |11513|     41|          i += static_cast<size_t>(                                          \
  |  |11514|     41|              trailing_zeroes32(static_cast<uint32_t>(m0)));                 \
  |  |11515|     41|          return;                                                            \
  |  |11516|     41|        }                                                                    \
  |  |11517|    151|        const __m128i w1 =                                                   \
  |  |11518|    110|            _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i + 16));   \
  |  |11519|    110|        const int m1 = ssse3_nibble_mask(w1, lo_tbl, hi_tbl);                \
  |  |11520|    110|        if (m1 != 0) {                                                       \
  |  |  ------------------
  |  |  |  Branch (11520:13): [True: 32, False: 78]
  |  |  ------------------
  |  |11521|     32|          i += 16 + static_cast<size_t>(                                     \
  |  |11522|     32|                        trailing_zeroes32(static_cast<uint32_t>(m1)));       \
  |  |11523|     32|          return;                                                            \
  |  |11524|     32|        }                                                                    \
  |  |11525|    110|      }                                                                      \
  |  |11526|    199|      for (; i + 16 <= len; i += 16) {                                       \
  |  |  ------------------
  |  |  |  Branch (11526:14): [True: 101, False: 85]
  |  |  ------------------
  |  |11527|    101|        const __m128i w =                                                    \
  |  |11528|    101|            _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i));        \
  |  |11529|    101|        const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl);               \
  |  |11530|    101|        if (mask != 0) {                                                     \
  |  |  ------------------
  |  |  |  Branch (11530:13): [True: 41, False: 60]
  |  |  ------------------
  |  |11531|     41|          i += static_cast<size_t>(                                          \
  |  |11532|     41|              trailing_zeroes32(static_cast<uint32_t>(mask)));               \
  |  |11533|     41|          return;                                                            \
  |  |11534|     41|        }                                                                    \
  |  |11535|    101|      }                                                                      \
  |  |11536|    126|      if (i > scan_start && i < len) {                                       \
  |  |  ------------------
  |  |  |  Branch (11536:11): [True: 85, False: 0]
  |  |  |  Branch (11536:29): [True: 77, False: 8]
  |  |  ------------------
  |  |11537|     77|        const __m128i w =                                                    \
  |  |11538|     77|            _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + len - 16)); \
  |  |11539|     77|        const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl);               \
  |  |11540|     77|        if (mask != 0) {                                                     \
  |  |  ------------------
  |  |  |  Branch (11540:13): [True: 60, False: 17]
  |  |  ------------------
  |  |11541|     60|          const size_t hit = len - 16 +                                      \
  |  |11542|     60|                             static_cast<size_t>(trailing_zeroes32(          \
  |  |11543|     60|                                 static_cast<uint32_t>(mask)));              \
  |  |11544|     60|          if (hit >= i) {                                                    \
  |  |  ------------------
  |  |  |  Branch (11544:15): [True: 60, False: 0]
  |  |  ------------------
  |  |11545|     60|            i = hit;                                                         \
  |  |11546|     60|            return;                                                          \
  |  |11547|     60|          }                                                                  \
  |  |11548|     60|        }                                                                    \
  |  |11549|     77|        i = len;                                                             \
  |  |11550|     17|        return;                                                              \
  |  |11551|     77|      }                                                                      \
  |  |11552|     85|    }                                                                        \
  |  |11553|    285|    for (; i < len; ++i) {                                                   \
  |  |  ------------------
  |  |  |  Branch (11553:12): [True: 155, False: 61]
  |  |  ------------------
  |  |11554|    155|      if ((cls)[b[i]] != 0) {                                                \
  |  |  ------------------
  |  |  |  Branch (11554:11): [True: 33, False: 122]
  |  |  ------------------
  |  |11555|     33|        return;                                                              \
  |  |11556|     33|      }                                                                      \
  |  |11557|    155|    }                                                                        \
  |  |11558|     94|  } while (0)
  |  |  ------------------
  |  |  |  Branch (11558:12): [Folded, False: 61]
  |  |  ------------------
  ------------------
11647|    285|}
url_search_params.cc:_ZN12_GLOBAL__N_132apply_shifted_non_scheme_offsetsERN3ada14url_componentsEj:
13648|    509|    ada::url_components& components, uint32_t new_difference) {
13649|    509|  components.username_end += new_difference;
13650|    509|  components.host_start += new_difference;
13651|    509|  components.host_end += new_difference;
13652|    509|  components.pathname_start += new_difference;
13653|    509|  if (components.search_start != ada::url_components::omitted) {
  ------------------
  |  Branch (13653:7): [True: 0, False: 509]
  ------------------
13654|      0|    components.search_start += new_difference;
13655|      0|  }
13656|    509|  if (components.hash_start != ada::url_components::omitted) {
  ------------------
  |  Branch (13656:7): [True: 0, False: 509]
  ------------------
13657|      0|    components.hash_start += new_difference;
13658|      0|  }
13659|    509|}
_ZN3ada14url_aggregator10parse_pathENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
14018|  1.03k|ada_really_inline void url_aggregator::parse_path(std::string_view input) {
14019|  1.03k|  ada_log("url_aggregator::parse_path ", input);
14020|  1.03k|  ADA_ASSERT_TRUE(validate());
14021|  1.03k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
14022|  1.03k|  std::string tmp_buffer;
14023|  1.03k|  std::string_view internal_input;
14024|  1.03k|  if (unicode::has_tabs_or_newline(input)) {
  ------------------
  |  Branch (14024:7): [True: 0, False: 1.03k]
  ------------------
14025|      0|    tmp_buffer = input;
14026|       |    // Optimization opportunity: Instead of copying and then pruning, we could
14027|       |    // just directly build the string from user_input.
14028|      0|    helpers::remove_ascii_tab_or_newline(tmp_buffer);
14029|      0|    internal_input = tmp_buffer;
14030|  1.03k|  } else {
14031|  1.03k|    internal_input = input;
14032|  1.03k|  }
14033|       |
14034|       |  // If url is special, then:
14035|  1.03k|  if (is_special()) {
  ------------------
  |  Branch (14035:7): [True: 1.03k, False: 0]
  ------------------
14036|  1.03k|    if (internal_input.empty()) {
  ------------------
  |  Branch (14036:9): [True: 0, False: 1.03k]
  ------------------
14037|      0|      update_base_pathname("/");
14038|  1.03k|    } else if ((internal_input[0] == '/') || (internal_input[0] == '\\')) {
  ------------------
  |  Branch (14038:16): [True: 1.03k, False: 0]
  |  Branch (14038:46): [True: 0, False: 0]
  ------------------
14039|  1.03k|      consume_prepared_path(internal_input.substr(1));
14040|  1.03k|    } else {
14041|      0|      consume_prepared_path(internal_input);
14042|      0|    }
14043|  1.03k|  } else if (!internal_input.empty()) {
  ------------------
  |  Branch (14043:14): [True: 0, False: 0]
  ------------------
14044|      0|    if (internal_input[0] == '/') {
  ------------------
  |  Branch (14044:9): [True: 0, False: 0]
  ------------------
14045|      0|      consume_prepared_path(internal_input.substr(1));
14046|      0|    } else {
14047|      0|      consume_prepared_path(internal_input);
14048|      0|    }
14049|      0|  } else {
14050|       |    // Non-special URLs with an empty host can have their paths erased
14051|       |    // Path-only URLs cannot have their paths erased
14052|      0|    if (components.host_start == components.host_end && !has_authority()) {
  ------------------
  |  Branch (14052:9): [True: 0, False: 0]
  |  Branch (14052:57): [True: 0, False: 0]
  ------------------
14053|      0|      update_base_pathname("/");
14054|      0|    }
14055|      0|  }
14056|  1.03k|  ADA_ASSERT_TRUE(validate());
14057|  1.03k|}
_ZN3ada14url_aggregator10parse_hostENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
14137|    509|ada_really_inline bool url_aggregator::parse_host(std::string_view input) {
14138|    509|  ada_log("url_aggregator:parse_host \"", input, "\" [", input.size(),
14139|    509|          " bytes]");
14140|    509|  ADA_ASSERT_TRUE(validate());
14141|    509|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
14142|    509|  if (input.empty()) {
  ------------------
  |  Branch (14142:7): [True: 0, False: 509]
  ------------------
14143|      0|    return is_valid = false;
14144|      0|  }  // technically unnecessary.
14145|       |  // If input starts with U+005B ([), then:
14146|    509|  if (input[0] == '[') {
  ------------------
  |  Branch (14146:7): [True: 0, False: 509]
  ------------------
14147|       |    // If input does not end with U+005D (]), validation error, return failure.
14148|      0|    if (input.back() != ']') {
  ------------------
  |  Branch (14148:9): [True: 0, False: 0]
  ------------------
14149|      0|      return is_valid = false;
14150|      0|    }
14151|      0|    ada_log("parse_host ipv6");
14152|       |
14153|       |    // Return the result of IPv6 parsing input with its leading U+005B ([) and
14154|       |    // trailing U+005D (]) removed.
14155|      0|    input.remove_prefix(1);
14156|      0|    input.remove_suffix(1);
14157|      0|    return parse_ipv6(input);
14158|      0|  }
14159|       |
14160|       |  // If isNotSpecial is true, then return the result of opaque-host parsing
14161|       |  // input.
14162|    509|  if (!is_special()) {
  ------------------
  |  Branch (14162:7): [True: 0, False: 509]
  ------------------
14163|      0|    return parse_opaque_host(input);
14164|      0|  }
14165|       |  // Let domain be the result of running UTF-8 decode without BOM on the
14166|       |  // percent-decoding of input. Let asciiDomain be the result of running domain
14167|       |  // to ASCII with domain and false. The most common case is an ASCII input, in
14168|       |  // which case we do not need to call the expensive 'to_ascii' if a few
14169|       |  // conditions are met: no '%' and no 'xn-' subsequence.
14170|       |
14171|       |  // Often, the input does not contain any forbidden code points, and no upper
14172|       |  // case ASCII letter, then we can just copy it to the buffer. We want to
14173|       |  // optimize for such a common case.
14174|       |
14175|       |  // Fast path: try to parse as pure decimal IPv4 first.
14176|    509|  const uint64_t fast_result = checkers::try_parse_ipv4_fast(input);
14177|    509|  if (fast_result < checkers::ipv4_fast_fail) {
  ------------------
  |  Branch (14177:7): [True: 0, False: 509]
  ------------------
14178|      0|    if (!input.empty() && input.back() == '.') {
  ------------------
  |  Branch (14178:9): [True: 0, False: 0]
  |  Branch (14178:27): [True: 0, False: 0]
  ------------------
14179|      0|      update_base_hostname(input.substr(0, input.size() - 1));
14180|      0|    } else {
14181|      0|      update_base_hostname(input);
14182|      0|    }
14183|      0|    host_type = IPV4;
14184|      0|    is_valid = true;
14185|      0|    ada_log("parse_host fast path decimal ipv4");
14186|      0|    ADA_ASSERT_TRUE(validate());
14187|      0|    return true;
14188|      0|  }
14189|    509|  uint8_t is_forbidden_or_upper =
14190|    509|      unicode::contains_forbidden_domain_code_point_or_upper(input.data(),
14191|    509|                                                             input.size());
14192|    509|  static constexpr std::string_view xn_dash{"xn-", 3};
14193|    509|  if ((is_forbidden_or_upper & 1) == 0) {
  ------------------
  |  Branch (14193:7): [True: 509, False: 0]
  ------------------
14194|    509|    if ((is_forbidden_or_upper & 2) != 0) {
  ------------------
  |  Branch (14194:9): [True: 0, False: 509]
  ------------------
14195|      0|      std::string lowered(input);
14196|      0|      unicode::to_lower_ascii(lowered.data(), lowered.size());
14197|      0|      if (lowered.find('-') == std::string_view::npos ||
  ------------------
  |  Branch (14197:11): [True: 0, False: 0]
  ------------------
14198|      0|          lowered.find(xn_dash) == std::string_view::npos) {
  ------------------
  |  Branch (14198:11): [True: 0, False: 0]
  ------------------
14199|      0|        update_base_hostname(lowered);
14200|      0|        if (checkers::is_ipv4(lowered)) {
  ------------------
  |  Branch (14200:13): [True: 0, False: 0]
  ------------------
14201|      0|          ada_log("parse_host fast path ipv4");
14202|      0|          return parse_ipv4(lowered, true);
14203|      0|        }
14204|      0|        ada_log("parse_host fast path ", get_hostname());
14205|      0|        is_valid = true;
14206|      0|        return true;
14207|      0|      }
14208|    509|    } else if (input.find('-') == std::string_view::npos ||
  ------------------
  |  Branch (14208:16): [True: 509, False: 0]
  ------------------
14209|    509|               input.find(xn_dash) == std::string_view::npos) {
  ------------------
  |  Branch (14209:16): [True: 0, False: 0]
  ------------------
14210|    509|      update_base_hostname(input);
14211|    509|      if (checkers::is_ipv4(input)) {
  ------------------
  |  Branch (14211:11): [True: 0, False: 509]
  ------------------
14212|      0|        ada_log("parse_host fast path ipv4");
14213|      0|        return parse_ipv4(input, true);
14214|      0|      }
14215|    509|      ada_log("parse_host fast path ", get_hostname());
14216|    509|      is_valid = true;
14217|    509|      return true;
14218|    509|    }
14219|    509|  } else if (const size_t first_percent = input.find('%');
14220|      0|             first_percent != std::string_view::npos) {
  ------------------
  |  Branch (14220:14): [True: 0, False: 0]
  ------------------
14221|      0|    std::string decoded = unicode::percent_decode(input, first_percent);
14222|      0|    const uint8_t decoded_flags =
14223|      0|        unicode::contains_forbidden_domain_code_point_or_upper(decoded.data(),
14224|      0|                                                               decoded.size());
14225|      0|    if ((decoded_flags & 1) == 0) {
  ------------------
  |  Branch (14225:9): [True: 0, False: 0]
  ------------------
14226|      0|      if ((decoded_flags & 2) != 0) {
  ------------------
  |  Branch (14226:11): [True: 0, False: 0]
  ------------------
14227|      0|        unicode::to_lower_ascii(decoded.data(), decoded.size());
14228|      0|      }
14229|      0|      if (decoded.find('-') == std::string_view::npos ||
  ------------------
  |  Branch (14229:11): [True: 0, False: 0]
  ------------------
14230|      0|          decoded.find(xn_dash) == std::string_view::npos) {
  ------------------
  |  Branch (14230:11): [True: 0, False: 0]
  ------------------
14231|      0|        update_base_hostname(decoded);
14232|      0|        if (checkers::is_ipv4(decoded)) {
  ------------------
  |  Branch (14232:13): [True: 0, False: 0]
  ------------------
14233|      0|          return parse_ipv4(decoded, true);
14234|      0|        }
14235|      0|        is_valid = true;
14236|      0|        return true;
14237|      0|      }
14238|      0|    }
14239|      0|  }
14240|       |  // We have encountered at least one forbidden code point or the input contains
14241|       |  // 'xn-' (case insensitive), so we need to call 'to_ascii' to perform the full
14242|       |  // conversion.
14243|       |
14244|      0|  ada_log("parse_host calling to_ascii");
14245|      0|  std::optional<std::string> host = std::string(get_hostname());
14246|      0|  is_valid = ada::unicode::to_ascii(host, input, input.find('%'));
14247|      0|  if (!is_valid) {
  ------------------
  |  Branch (14247:7): [True: 0, False: 0]
  ------------------
14248|      0|    ada_log("parse_host to_ascii returns false");
14249|      0|    return is_valid = false;
14250|      0|  }
14251|      0|  ada_log("parse_host to_ascii succeeded ", *host, " [", host->size(),
14252|      0|          " bytes]");
14253|       |
14254|      0|  if (std::ranges::any_of(host.value(),
  ------------------
  |  Branch (14254:7): [True: 0, False: 0]
  ------------------
14255|      0|                          ada::unicode::is_forbidden_domain_code_point)) {
14256|      0|    return is_valid = false;
14257|      0|  }
14258|       |
14259|       |  // If asciiDomain ends in a number, then return the result of IPv4 parsing
14260|       |  // asciiDomain.
14261|      0|  if (checkers::is_ipv4(host.value())) {
  ------------------
  |  Branch (14261:7): [True: 0, False: 0]
  ------------------
14262|      0|    ada_log("parse_host got ipv4 ", *host);
14263|      0|    return parse_ipv4(host.value(), false);
14264|      0|  }
14265|       |
14266|      0|  update_base_hostname(host.value());
14267|      0|  ADA_ASSERT_TRUE(validate());
14268|      0|  return true;
14269|      0|}
_ZN3ada14url_aggregator21consume_prepared_pathENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
15088|  1.53k|inline void url_aggregator::consume_prepared_path(std::string_view input) {
15089|  1.53k|  ada_log("url_aggregator::consume_prepared_path ", input);
15090|       |  /***
15091|       |   * This is largely duplicated code from helpers::parse_prepared_path, which is
15092|       |   * unfortunate. This particular function is nearly identical, except that it
15093|       |   * is a method on url_aggregator. The idea is that the trivial path (which is
15094|       |   * very common) merely appends to the buffer. This is the same trivial path as
15095|       |   * with helpers::parse_prepared_path, except that we have the additional check
15096|       |   * for is_at_path(). Otherwise, we grab a copy of the current path and we
15097|       |   * modify it, and then insert it back into the buffer.
15098|       |   */
15099|  1.53k|  uint8_t accumulator = checkers::path_signature(input);
15100|       |  // Let us first detect a trivial case.
15101|       |  // If it is special, we check that we have no dot, no %,  no \ and no
15102|       |  // character needing percent encoding. Otherwise, we check that we have no %,
15103|       |  // no dot, and no character needing percent encoding.
15104|  1.53k|  constexpr uint8_t need_encoding = 1;
15105|  1.53k|  constexpr uint8_t backslash_char = 2;
15106|  1.53k|  constexpr uint8_t dot_char = 4;
15107|  1.53k|  constexpr uint8_t percent_char = 8;
15108|  1.53k|  bool special = type != ada::scheme::NOT_SPECIAL;
15109|  1.53k|  bool may_need_slow_file_handling = (type == ada::scheme::type::FILE &&
  ------------------
  |  Branch (15109:39): [True: 0, False: 1.53k]
  ------------------
15110|      0|                                      checkers::is_windows_drive_letter(input));
  ------------------
  |  Branch (15110:39): [True: 0, False: 0]
  ------------------
15111|  1.53k|  bool trivial_path =
15112|  1.53k|      (special ? (accumulator == 0)
  ------------------
  |  Branch (15112:7): [True: 1.53k, False: 0]
  |  Branch (15112:8): [True: 1.53k, False: 0]
  ------------------
15113|  1.53k|               : ((accumulator & (need_encoding | dot_char | percent_char)) ==
15114|      0|                  0)) &&
15115|  1.53k|      (!may_need_slow_file_handling);
  ------------------
  |  Branch (15115:7): [True: 1.53k, False: 0]
  ------------------
15116|  1.53k|  if (accumulator == dot_char && !may_need_slow_file_handling) {
  ------------------
  |  Branch (15116:7): [True: 0, False: 1.53k]
  |  Branch (15116:34): [True: 0, False: 0]
  ------------------
15117|       |    // '4' means that we have at least one dot, but nothing that requires
15118|       |    // percent encoding or decoding. The only part that is not trivial is
15119|       |    // that we may have single dots and double dots path segments.
15120|       |    // If we have such segments, then we either have a path that begins
15121|       |    // with '.' (easy to check), or we have the sequence './'.
15122|       |    // Note: input cannot be empty, it must at least contain one character ('.')
15123|       |    // Note: we know that '\' is not present.
15124|      0|    if (input[0] != '.') {
  ------------------
  |  Branch (15124:9): [True: 0, False: 0]
  ------------------
15125|      0|      size_t slashdot = 0;
15126|      0|      bool dot_is_file = true;
15127|      0|      for (;;) {
15128|      0|        slashdot = input.find("/.", slashdot);
15129|      0|        if (slashdot == std::string_view::npos) {  // common case
  ------------------
  |  Branch (15129:13): [True: 0, False: 0]
  ------------------
15130|      0|          break;
15131|      0|        } else {  // uncommon
15132|       |          // only three cases matter: /./, /.. or a final /
15133|      0|          slashdot += 2;
15134|      0|          dot_is_file &= !(slashdot == input.size() || input[slashdot] == '.' ||
  ------------------
  |  Branch (15134:28): [True: 0, False: 0]
  |  Branch (15134:56): [True: 0, False: 0]
  ------------------
15135|      0|                           input[slashdot] == '/');
  ------------------
  |  Branch (15135:28): [True: 0, False: 0]
  ------------------
15136|      0|        }
15137|      0|      }
15138|      0|      trivial_path = dot_is_file;
15139|      0|    }
15140|      0|  }
15141|  1.53k|  if (trivial_path && is_at_path()) {
  ------------------
  |  Branch (15141:7): [True: 1.53k, False: 0]
  |  Branch (15141:23): [True: 1.53k, False: 0]
  ------------------
15142|  1.53k|    ada_log("parse_path trivial");
15143|  1.53k|    buffer += '/';
15144|  1.53k|    buffer += input;
15145|  1.53k|    return;
15146|  1.53k|  }
15147|      0|  std::string path = std::string(get_pathname());
15148|       |  // We are going to need to look a bit at the path, but let us see if we can
15149|       |  // ignore percent encoding *and* backslashes *and* percent characters.
15150|       |  // Except for the trivial case, this is likely to capture 99% of paths out
15151|       |  // there.
15152|      0|  bool fast_path =
15153|      0|      (special &&
  ------------------
  |  Branch (15153:8): [True: 0, False: 0]
  ------------------
15154|      0|       (accumulator & (need_encoding | backslash_char | percent_char)) == 0) &&
  ------------------
  |  Branch (15154:8): [True: 0, False: 0]
  ------------------
15155|      0|      (type != ada::scheme::type::FILE);
  ------------------
  |  Branch (15155:7): [True: 0, False: 0]
  ------------------
15156|      0|  if (fast_path) {
  ------------------
  |  Branch (15156:7): [True: 0, False: 0]
  ------------------
15157|      0|    ada_log("parse_prepared_path fast");
15158|       |    // Here we don't need to worry about \ or percent encoding.
15159|       |    // We also do not have a file protocol. We might have dots, however,
15160|       |    // but dots must as appear as '.', and they cannot be encoded because
15161|       |    // the symbol '%' is not present.
15162|      0|    size_t previous_location = 0;  // We start at 0.
15163|      0|    do {
15164|      0|      size_t new_location = input.find('/', previous_location);
15165|       |      // std::string_view path_view = input;
15166|       |      //  We process the last segment separately:
15167|      0|      if (new_location == std::string_view::npos) {
  ------------------
  |  Branch (15167:11): [True: 0, False: 0]
  ------------------
15168|      0|        std::string_view path_view = input.substr(previous_location);
15169|      0|        if (path_view == "..") {  // The path ends with ..
  ------------------
  |  Branch (15169:13): [True: 0, False: 0]
  ------------------
15170|       |          // e.g., if you receive ".." with an empty path, you go to "/".
15171|      0|          if (path.empty()) {
  ------------------
  |  Branch (15171:15): [True: 0, False: 0]
  ------------------
15172|      0|            path = '/';
15173|      0|            update_base_pathname(path);
15174|      0|            return;
15175|      0|          }
15176|       |          // Fast case where we have nothing to do:
15177|      0|          if (path.back() == '/') {
  ------------------
  |  Branch (15177:15): [True: 0, False: 0]
  ------------------
15178|      0|            update_base_pathname(path);
15179|      0|            return;
15180|      0|          }
15181|       |          // If you have the path "/joe/myfriend",
15182|       |          // then you delete 'myfriend'.
15183|      0|          path.resize(path.rfind('/') + 1);
15184|      0|          update_base_pathname(path);
15185|      0|          return;
15186|      0|        }
15187|      0|        path += '/';
15188|      0|        if (path_view != ".") {
  ------------------
  |  Branch (15188:13): [True: 0, False: 0]
  ------------------
15189|      0|          path.append(path_view);
15190|      0|        }
15191|      0|        update_base_pathname(path);
15192|      0|        return;
15193|      0|      } else {
15194|       |        // This is a non-final segment.
15195|      0|        std::string_view path_view =
15196|      0|            input.substr(previous_location, new_location - previous_location);
15197|      0|        previous_location = new_location + 1;
15198|      0|        if (path_view == "..") {
  ------------------
  |  Branch (15198:13): [True: 0, False: 0]
  ------------------
15199|      0|          size_t last_delimiter = path.rfind('/');
15200|      0|          if (last_delimiter != std::string::npos) {
  ------------------
  |  Branch (15200:15): [True: 0, False: 0]
  ------------------
15201|      0|            path.erase(last_delimiter);
15202|      0|          }
15203|      0|        } else if (path_view != ".") {
  ------------------
  |  Branch (15203:20): [True: 0, False: 0]
  ------------------
15204|      0|          path += '/';
15205|      0|          path.append(path_view);
15206|      0|        }
15207|      0|      }
15208|      0|    } while (true);
  ------------------
  |  Branch (15208:14): [True: 0, Folded]
  ------------------
15209|      0|  } else {
15210|      0|    ada_log("parse_path slow");
15211|       |    // we have reached the general case
15212|      0|    bool needs_percent_encoding = (accumulator & 1);
15213|      0|    std::string path_buffer_tmp;
15214|      0|    do {
15215|      0|      size_t location = (special && (accumulator & 2))
  ------------------
  |  Branch (15215:26): [True: 0, False: 0]
  |  Branch (15215:37): [True: 0, False: 0]
  ------------------
15216|      0|                            ? input.find_first_of("/\\")
15217|      0|                            : input.find('/');
15218|      0|      std::string_view path_view = input;
15219|      0|      if (location != std::string_view::npos) {
  ------------------
  |  Branch (15219:11): [True: 0, False: 0]
  ------------------
15220|      0|        path_view.remove_suffix(path_view.size() - location);
15221|      0|        input.remove_prefix(location + 1);
15222|      0|      }
15223|       |      // path_buffer is either path_view or it might point at a percent encoded
15224|       |      // temporary string.
15225|      0|      std::string_view path_buffer =
15226|      0|          (needs_percent_encoding &&
  ------------------
  |  Branch (15226:12): [True: 0, False: 0]
  ------------------
15227|      0|           ada::unicode::percent_encode<false>(
  ------------------
  |  Branch (15227:12): [True: 0, False: 0]
  ------------------
15228|      0|               path_view, character_sets::PATH_PERCENT_ENCODE, path_buffer_tmp))
15229|      0|              ? path_buffer_tmp
15230|      0|              : path_view;
15231|      0|      if (unicode::is_double_dot_path_segment(path_buffer)) {
  ------------------
  |  Branch (15231:11): [True: 0, False: 0]
  ------------------
15232|      0|        helpers::shorten_path(path, type);
15233|      0|        if (location == std::string_view::npos) {
  ------------------
  |  Branch (15233:13): [True: 0, False: 0]
  ------------------
15234|      0|          path += '/';
15235|      0|        }
15236|      0|      } else if (unicode::is_single_dot_path_segment(path_buffer) &&
  ------------------
  |  Branch (15236:18): [True: 0, False: 0]
  ------------------
15237|      0|                 (location == std::string_view::npos)) {
  ------------------
  |  Branch (15237:18): [True: 0, False: 0]
  ------------------
15238|      0|        path += '/';
15239|      0|      }
15240|       |      // Otherwise, if path_buffer is not a single-dot path segment, then:
15241|      0|      else if (!unicode::is_single_dot_path_segment(path_buffer)) {
  ------------------
  |  Branch (15241:16): [True: 0, False: 0]
  ------------------
15242|       |        // If url's scheme is "file", url's path is empty, and path_buffer is a
15243|       |        // Windows drive letter, then replace the second code point in
15244|       |        // path_buffer with U+003A (:).
15245|      0|        if (type == ada::scheme::type::FILE && path.empty() &&
  ------------------
  |  Branch (15245:13): [True: 0, False: 0]
  |  Branch (15245:48): [True: 0, False: 0]
  ------------------
15246|      0|            checkers::is_windows_drive_letter(path_buffer)) {
  ------------------
  |  Branch (15246:13): [True: 0, False: 0]
  ------------------
15247|      0|          path += '/';
15248|      0|          path += path_buffer[0];
15249|      0|          path += ':';
15250|      0|          path_buffer.remove_prefix(2);
15251|      0|          path.append(path_buffer);
15252|      0|        } else {
15253|       |          // Append path_buffer to url's path.
15254|      0|          path += '/';
15255|      0|          path.append(path_buffer);
15256|      0|        }
15257|      0|      }
15258|      0|      if (location == std::string_view::npos) {
  ------------------
  |  Branch (15258:11): [True: 0, False: 0]
  ------------------
15259|      0|        update_base_pathname(path);
15260|      0|        return;
15261|      0|      }
15262|      0|    } while (true);
  ------------------
  |  Branch (15262:14): [True: 0, Folded]
  ------------------
15263|      0|  }
15264|      0|}
_ZN3ada8checkers7is_ipv4ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
   12|    509|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|    509|  if (!last_label_may_be_a_number(view)) {
  ------------------
  |  Branch (14:7): [True: 509, False: 0]
  ------------------
   15|    509|    return false;
   16|    509|  }
   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:
13666|    509|    const std::string_view input_with_colon) {
13667|    509|  ada_log("url_aggregator::parse_scheme_with_colon ", input_with_colon);
13668|    509|  ADA_ASSERT_TRUE(validate());
13669|    509|  ADA_ASSERT_TRUE(!helpers::overlaps(input_with_colon, buffer));
13670|    509|  std::string_view input{input_with_colon};
13671|    509|  input.remove_suffix(1);
13672|    509|  auto parsed_type = ada::scheme::get_scheme_type(input);
13673|    509|  const bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL);
13674|       |  /**
13675|       |   * In the common case, we will immediately recognize a special scheme (e.g.,
13676|       |   *http, https), in which case, we can go really fast.
13677|       |   **/
13678|    509|  if (is_input_special) {  // fast path!!!
  ------------------
  |  Branch (13678:7): [True: 509, False: 0]
  ------------------
13679|       |    if constexpr (has_state_override) {
13680|       |      // If url's scheme is not a special scheme and buffer is a special scheme,
13681|       |      // then return.
13682|       |      if (is_special() != is_input_special) {
13683|       |        return false;
13684|       |      }
13685|       |
13686|       |      // If url includes credentials or has a non-null port, and buffer is
13687|       |      // "file", then return.
13688|       |      if ((has_credentials() || components.port != url_components::omitted) &&
13689|       |          parsed_type == ada::scheme::type::FILE) {
13690|       |        return false;
13691|       |      }
13692|       |
13693|       |      // If url's scheme is "file" and its host is an empty host, then return.
13694|       |      // An empty host is the empty string.
13695|       |      if (type == ada::scheme::type::FILE &&
13696|       |          components.host_start == components.host_end) {
13697|       |        return false;
13698|       |      }
13699|       |    }
13700|       |
13701|    509|    type = parsed_type;
13702|    509|    set_scheme_from_view_with_colon(input_with_colon);
13703|       |
13704|       |    if constexpr (has_state_override) {
13705|       |      // This is uncommon.
13706|       |      uint16_t urls_scheme_port = get_special_port();
13707|       |
13708|       |      if (urls_scheme_port) {
13709|       |        // If url's port is url's scheme's default port, then set url's port to
13710|       |        // null.
13711|       |        if (components.port == urls_scheme_port) {
13712|       |          clear_port();
13713|       |        }
13714|       |      }
13715|       |    }
13716|    509|  } else {  // slow path
13717|      0|    std::string _buffer(input);
13718|       |    // Next function is only valid if the input is ASCII and returns false
13719|       |    // otherwise, but it seems that we always have ascii content so we do not
13720|       |    // need to check the return value.
13721|      0|    unicode::to_lower_ascii(_buffer.data(), _buffer.size());
13722|       |
13723|       |    if constexpr (has_state_override) {
13724|       |      // The state-override validation errors below ("return" in the WHATWG URL
13725|       |      // parser) leave the URL unchanged. The setter contract is
13726|       |      // "true on success, false if the scheme is invalid" -- the fast path
13727|       |      // above already returns false here, so the slow path must agree.
13728|       |
13729|       |      // If url's scheme is a special scheme and buffer is not a special scheme,
13730|       |      // then return. If url's scheme is not a special scheme and buffer is a
13731|       |      // special scheme, then return.
13732|       |      if (is_special() != ada::scheme::is_special(_buffer)) {
13733|       |        return false;
13734|       |      }
13735|       |
13736|       |      // If url includes credentials or has a non-null port, and buffer is
13737|       |      // "file", then return.
13738|       |      if ((has_credentials() || components.port != url_components::omitted) &&
13739|       |          _buffer == "file") {
13740|       |        return false;
13741|       |      }
13742|       |
13743|       |      // If url's scheme is "file" and its host is an empty host, then return.
13744|       |      // An empty host is the empty string.
13745|       |      if (type == ada::scheme::type::FILE &&
13746|       |          components.host_start == components.host_end) {
13747|       |        return false;
13748|       |      }
13749|       |    }
13750|       |
13751|      0|    set_scheme(_buffer);
13752|       |
13753|       |    if constexpr (has_state_override) {
13754|       |      // This is uncommon.
13755|       |      uint16_t urls_scheme_port = get_special_port();
13756|       |
13757|       |      if (urls_scheme_port) {
13758|       |        // If url's port is url's scheme's default port, then set url's port to
13759|       |        // null.
13760|       |        if (components.port == urls_scheme_port) {
13761|       |          clear_port();
13762|       |        }
13763|       |      }
13764|       |    }
13765|      0|  }
13766|    509|  ADA_ASSERT_TRUE(validate());
13767|    509|  return true;
13768|    509|}
_ZN3ada14url_aggregator31set_scheme_from_view_with_colonENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13792|    509|    std::string_view new_scheme_with_colon) {
13793|    509|  ada_log("url_aggregator::set_scheme_from_view_with_colon ",
13794|    509|          new_scheme_with_colon);
13795|    509|  ADA_ASSERT_TRUE(validate());
13796|    509|  ADA_ASSERT_TRUE(!new_scheme_with_colon.empty() &&
13797|    509|                  new_scheme_with_colon.back() == ':');
13798|       |  // next line could overflow but unsigned arithmetic has well-defined
13799|       |  // overflows.
13800|    509|  uint32_t new_difference =
13801|    509|      uint32_t(new_scheme_with_colon.size()) - components.protocol_end;
13802|       |
13803|    509|  if (buffer.empty()) {
  ------------------
  |  Branch (13803:7): [True: 509, False: 0]
  ------------------
13804|    509|    buffer.append(new_scheme_with_colon);
13805|    509|  } else {
13806|      0|    buffer.erase(0, components.protocol_end);
13807|      0|    buffer.insert(0, new_scheme_with_colon);
13808|      0|  }
13809|    509|  components.protocol_end += new_difference;
13810|       |
13811|    509|  apply_shifted_non_scheme_offsets(components, new_difference);
13812|    509|  ADA_ASSERT_TRUE(validate());
13813|    509|}
_ZN3ada7helpers38strip_trailing_spaces_from_opaque_pathINS_14url_aggregatorEEEvRT_:
 9438|  1.42k|ada_really_inline void strip_trailing_spaces_from_opaque_path(url_type& url) {
 9439|  1.42k|  ada_log("helpers::strip_trailing_spaces_from_opaque_path");
 9440|  1.42k|  if (!url.has_opaque_path) return;
  ------------------
  |  Branch (9440:7): [True: 1.42k, False: 0]
  ------------------
 9441|      0|  if (url.has_hash()) return;
  ------------------
  |  Branch (9441:7): [True: 0, False: 0]
  ------------------
 9442|      0|  if (url.has_search()) return;
  ------------------
  |  Branch (9442:7): [True: 0, False: 0]
  ------------------
 9443|       |
 9444|      0|  auto path = std::string(url.get_pathname());
 9445|      0|  while (!path.empty() && path.back() == ' ') {
  ------------------
  |  Branch (9445:10): [True: 0, False: 0]
  |  Branch (9445:27): [True: 0, False: 0]
  ------------------
 9446|      0|    path.resize(path.size() - 1);
 9447|      0|  }
 9448|      0|  url.update_base_pathname(path);
 9449|      0|}

_ZN3ada37url_pattern_compile_component_optionsC2ENSt3__18optionalIcEES3_:
 5809|      6|      : delimiter(new_delimiter), prefix(new_prefix) {}
_ZN3ada14character_sets6bit_atEPKhh:
 1081|   468k|ada_really_inline constexpr bool bit_at(const uint8_t a[], const uint8_t i) {
 1082|   468k|  return !!(a[i >> 3] & (1 << (i & 7)));
 1083|   468k|}
_ZN3ada8url_baseD2Ev:
 1700|  5.99k|  virtual ~url_base() = default;
_ZN2tl6detail26expected_default_ctor_baseIN3ada14url_aggregatorENS2_6errorsELb1EEC2ENS0_23default_constructor_tagE:
 3286|  2.99k|  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_:
 3768|  2.99k|      : expected(in_place, std::forward<U>(v)) {}
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEC2IJS2_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS2_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESA_:
 3641|  2.99k|      : impl_base(in_place, std::forward<Args>(args)...),
 3642|  2.99k|        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl6detail21expected_storage_baseIN3ada14url_aggregatorENS2_6errorsELb0ELb1EEC2IJS3_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESB_:
 2656|  2.99k|      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
_ZN3ada14url_aggregatorC2EOS0_:
 7831|  2.99k|  url_aggregator(url_aggregator&& u) noexcept = default;
_ZN3ada14url_aggregatorD2Ev:
 7834|  5.99k|  ~url_aggregator() override = default;
_ZN3ada6scheme15get_scheme_typeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6846|    509|constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept {
 6847|    509|  if (scheme.empty()) {
  ------------------
  |  Branch (6847:7): [True: 0, False: 509]
  ------------------
 6848|      0|    return ada::scheme::NOT_SPECIAL;
 6849|      0|  }
 6850|    509|  int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
 6851|    509|  const std::string_view target = details::is_special_list[hash_value];
 6852|    509|  if (scheme.size() == target.size() &&
  ------------------
  |  Branch (6852:7): [True: 509, False: 0]
  ------------------
 6853|    509|      details::branchless_load5(scheme.data(), scheme.size()) ==
  ------------------
  |  Branch (6853:7): [True: 509, False: 0]
  ------------------
 6854|    509|          details::scheme_keys[hash_value]) {
 6855|    509|    return ada::scheme::type(hash_value);
 6856|    509|  } else {
 6857|      0|    return ada::scheme::NOT_SPECIAL;
 6858|      0|  }
 6859|    509|}
_ZN3ada6scheme7details16branchless_load5EPKcm:
 6787|    509|inline uint64_t branchless_load5(const char* p, size_t n) {
 6788|    509|  uint64_t input = (uint8_t)p[0];
 6789|    509|  input |= ((uint64_t)(uint8_t)p[n > 1] << 8) & (0 - (uint64_t)(n > 1));
 6790|    509|  input |= ((uint64_t)(uint8_t)p[(n > 2) * 2] << 16) & (0 - (uint64_t)(n > 2));
 6791|    509|  input |= ((uint64_t)(uint8_t)p[(n > 3) * 3] << 24) & (0 - (uint64_t)(n > 3));
 6792|    509|  input |= ((uint64_t)(uint8_t)p[(n > 4) * 4] << 32) & (0 - (uint64_t)(n > 4));
 6793|    509|  return input;
 6794|    509|}
_ZN3ada14url_aggregatorC2Ev:
 7829|  2.99k|  url_aggregator() = default;
_ZN3ada14url_componentsC2Ev:
 4960|  2.99k|  url_components() = default;
_ZN3ada8checkers19try_parse_ipv4_fastENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 1453|    509|try_parse_ipv4_fast(std::string_view input) noexcept {
 1454|    509|  const size_t len = input.size();
 1455|       |  // Shortest pure decimal: "0.0.0.0" (7). Longest + trailing dot: 16.
 1456|    509|  if (len < 7 || len > 16) [[unlikely]] {
  ------------------
  |  Branch (1456:7): [True: 0, False: 509]
  |  Branch (1456:18): [True: 0, False: 509]
  ------------------
 1457|      0|    return ipv4_fast_fail;
 1458|      0|  }
 1459|    509|  const char* data = input.data();
 1460|       |
 1461|       |#if defined(ADA_AVX512) && defined(__AVX512VBMI2__)
 1462|       |  return detail::try_parse_ipv4_avx512(data, len);
 1463|       |#else
 1464|    509|  return detail::parse_ipv4_decimal_scalar(data, data + len);
 1465|    509|#endif
 1466|    509|}
_ZN3ada8checkers6detail25parse_ipv4_decimal_scalarEPKcS3_:
 1294|    509|parse_ipv4_decimal_scalar(const char* p, const char* pend) noexcept {
 1295|    509|  uint32_t ipv4 = 0;
 1296|    509|  for (int i = 0; i < 4; ++i) {
  ------------------
  |  Branch (1296:19): [True: 509, False: 0]
  ------------------
 1297|    509|    if (p == pend) [[unlikely]] {
  ------------------
  |  Branch (1297:9): [True: 0, False: 509]
  ------------------
 1298|      0|      return ipv4_fast_fail;
 1299|      0|    }
 1300|    509|    uint32_t val;
 1301|    509|    char c = *p;
 1302|    509|    if (c >= '0' && c <= '9') [[likely]] {
  ------------------
  |  Branch (1302:9): [True: 509, False: 0]
  |  Branch (1302:21): [True: 0, False: 509]
  ------------------
 1303|      0|      val = static_cast<uint32_t>(c - '0');
 1304|      0|      ++p;
 1305|    509|    } else {
 1306|    509|      return ipv4_fast_fail;
 1307|    509|    }
 1308|      0|    if (p < pend) {
  ------------------
  |  Branch (1308:9): [True: 0, False: 0]
  ------------------
 1309|      0|      c = *p;
 1310|      0|      if (c >= '0' && c <= '9') {
  ------------------
  |  Branch (1310:11): [True: 0, False: 0]
  |  Branch (1310:23): [True: 0, False: 0]
  ------------------
 1311|      0|        if (val == 0) [[unlikely]] {
  ------------------
  |  Branch (1311:13): [True: 0, False: 0]
  ------------------
 1312|      0|          return ipv4_fast_fail;
 1313|      0|        }
 1314|      0|        val = val * 10u + static_cast<uint32_t>(c - '0');
 1315|      0|        ++p;
 1316|      0|        if (p < pend) {
  ------------------
  |  Branch (1316:13): [True: 0, False: 0]
  ------------------
 1317|      0|          c = *p;
 1318|      0|          if (c >= '0' && c <= '9') {
  ------------------
  |  Branch (1318:15): [True: 0, False: 0]
  |  Branch (1318:27): [True: 0, False: 0]
  ------------------
 1319|      0|            val = val * 10u + static_cast<uint32_t>(c - '0');
 1320|      0|            ++p;
 1321|      0|            if (val > 255u) [[unlikely]] {
  ------------------
  |  Branch (1321:17): [True: 0, False: 0]
  ------------------
 1322|      0|              return ipv4_fast_fail;
 1323|      0|            }
 1324|      0|          }
 1325|      0|        }
 1326|      0|      }
 1327|      0|    }
 1328|      0|    ipv4 = (ipv4 << 8) | val;
 1329|      0|    if (i < 3) {
  ------------------
  |  Branch (1329:9): [True: 0, False: 0]
  ------------------
 1330|      0|      if (p == pend || *p != '.') [[unlikely]] {
  ------------------
  |  Branch (1330:11): [True: 0, False: 0]
  |  Branch (1330:24): [True: 0, False: 0]
  ------------------
 1331|      0|        return ipv4_fast_fail;
 1332|      0|      }
 1333|      0|      ++p;
 1334|      0|    }
 1335|      0|  }
 1336|      0|  if (p != pend) {
  ------------------
  |  Branch (1336:7): [True: 0, False: 0]
  ------------------
 1337|      0|    if (p == pend - 1 && *p == '.') {
  ------------------
  |  Branch (1337:9): [True: 0, False: 0]
  |  Branch (1337:26): [True: 0, False: 0]
  ------------------
 1338|      0|      return ipv4;
 1339|      0|    }
 1340|      0|    return ipv4_fast_fail;
 1341|      0|  }
 1342|      0|  return ipv4;
 1343|      0|}
_ZNK3ada8url_base10is_specialEv:
 7329|  5.70k|    const noexcept {
 7330|  5.70k|  return type != ada::scheme::NOT_SPECIAL;
 7331|  5.70k|}
_ZN3ada8checkers8is_alphaEc:
 1274|    509|constexpr bool is_alpha(char x) noexcept {
 1275|    509|  return (to_lower(x) >= 'a') && (to_lower(x) <= 'z');
  ------------------
  |  Branch (1275:10): [True: 509, False: 0]
  |  Branch (1275:34): [True: 509, False: 0]
  ------------------
 1276|    509|}
_ZN3ada8checkers8to_lowerEc:
 1272|  1.01k|constexpr char to_lower(char x) noexcept { return (x | 0x20); }
_ZN3ada8checkers26last_label_may_be_a_numberENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 1247|  3.50k|constexpr bool last_label_may_be_a_number(std::string_view view) noexcept {
 1248|  3.50k|  if (view.empty()) {
  ------------------
  |  Branch (1248:7): [True: 0, False: 3.50k]
  ------------------
 1249|      0|    return false;
 1250|      0|  }
 1251|  3.50k|  const char* start = view.data();
 1252|  3.50k|  const char* end = start + view.size();
 1253|  3.50k|  if (end[-1] == '.') {
  ------------------
  |  Branch (1253:7): [True: 0, False: 3.50k]
  ------------------
 1254|      0|    --end;
 1255|      0|    if (end == start) {
  ------------------
  |  Branch (1255:9): [True: 0, False: 0]
  ------------------
 1256|      0|      return false;
 1257|      0|    }
 1258|      0|  }
 1259|  3.50k|  if (!is_ipv4_number_char(end[-1])) {
  ------------------
  |  Branch (1259:7): [True: 3.50k, False: 0]
  ------------------
 1260|  3.50k|    return false;
 1261|  3.50k|  }
 1262|      0|  const char* label = end;
 1263|      0|  while (label != start && is_ipv4_number_char(label[-1])) {
  ------------------
  |  Branch (1263:10): [True: 0, False: 0]
  |  Branch (1263:28): [True: 0, False: 0]
  ------------------
 1264|      0|    --label;
 1265|      0|  }
 1266|      0|  if (label != start && label[-1] != '.') {
  ------------------
  |  Branch (1266:7): [True: 0, False: 0]
  |  Branch (1266:25): [True: 0, False: 0]
  ------------------
 1267|      0|    return false;
 1268|      0|  }
 1269|      0|  return label != end && is_digit(*label);
  ------------------
  |  Branch (1269:10): [True: 0, False: 0]
  |  Branch (1269:26): [True: 0, False: 0]
  ------------------
 1270|      0|}
_ZN3ada8checkers19is_ipv4_number_charEc:
 1241|  3.50k|constexpr bool is_ipv4_number_char(char x) noexcept {
 1242|  3.50k|  const unsigned char c = static_cast<unsigned char>(x);
 1243|  3.50k|  return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
  ------------------
  |  Branch (1243:11): [True: 3.50k, False: 0]
  |  Branch (1243:23): [True: 0, False: 3.50k]
  |  Branch (1243:37): [True: 3.50k, False: 0]
  |  Branch (1243:49): [True: 0, False: 3.50k]
  ------------------
 1244|  3.50k|         (c >= 'A' && c <= 'F') || c == 'x' || c == 'X';
  ------------------
  |  Branch (1244:11): [True: 3.50k, False: 0]
  |  Branch (1244:23): [True: 0, False: 3.50k]
  |  Branch (1244:36): [True: 0, False: 3.50k]
  |  Branch (1244:48): [True: 0, False: 3.50k]
  ------------------
 1245|  3.50k|}
_ZN3ada14url_aggregator18replace_and_resizeEjjNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8396|    780|    uint32_t start, uint32_t end, std::string_view input) {
 8397|    780|  uint32_t current_length = end - start;
 8398|    780|  uint32_t input_size = uint32_t(input.size());
 8399|    780|  uint32_t new_difference = input_size - current_length;
 8400|       |
 8401|    780|  if (current_length == 0) {
  ------------------
  |  Branch (8401:7): [True: 509, False: 271]
  ------------------
 8402|    509|    buffer.insert(start, input);
 8403|    509|  } else if (input_size == current_length) {
  ------------------
  |  Branch (8403:14): [True: 3, False: 268]
  ------------------
 8404|      3|    if (input_size != 0) {
  ------------------
  |  Branch (8404:9): [True: 3, False: 0]
  ------------------
 8405|      3|      std::memmove(buffer.data() + start, input.data(), input_size);
 8406|      3|    }
 8407|    268|  } else if (input_size < current_length) {
  ------------------
  |  Branch (8407:14): [True: 73, False: 195]
  ------------------
 8408|     73|    buffer.erase(start, current_length - input_size);
 8409|     73|    buffer.replace(start, input_size, input);
 8410|    195|  } else {
 8411|    195|    buffer.replace(start, current_length, input.substr(0, current_length));
 8412|    195|    buffer.insert(start + current_length, input.substr(current_length));
 8413|    195|  }
 8414|       |
 8415|    780|  return new_difference;
 8416|    780|}
_ZN3ada14url_aggregator26update_unencoded_base_hashENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8372|    398|inline void url_aggregator::update_unencoded_base_hash(std::string_view input) {
 8373|    398|  ada_log("url_aggregator::update_unencoded_base_hash ", input, " [",
 8374|    398|          input.size(), " bytes], buffer is '", buffer, "' [", buffer.size(),
 8375|    398|          " bytes] components.hash_start = ", components.hash_start);
 8376|    398|  ADA_ASSERT_TRUE(validate());
 8377|    398|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 8378|    398|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8378:7): [True: 0, False: 398]
  ------------------
 8379|      0|    buffer.resize(components.hash_start);
 8380|      0|  }
 8381|    398|  components.hash_start = uint32_t(buffer.size());
 8382|    398|  buffer += "#";
 8383|    398|  bool encoding_required = unicode::percent_encode<true>(
 8384|    398|      input, ada::character_sets::FRAGMENT_PERCENT_ENCODE, buffer);
 8385|       |  // When encoding_required is false, then buffer is left unchanged, and percent
 8386|       |  // encoding was not deemed required.
 8387|    398|  if (!encoding_required) {
  ------------------
  |  Branch (8387:7): [True: 159, False: 239]
  ------------------
 8388|    159|    buffer.append(input);
 8389|    159|  }
 8390|    398|  ada_log("url_aggregator::update_unencoded_base_hash final buffer is '",
 8391|    398|          buffer, "' [", buffer.size(), " bytes]");
 8392|    398|  ADA_ASSERT_TRUE(validate());
 8393|    398|}
_ZN3ada7helpers14leading_zeroesEj:
 1985|    509|inline int leading_zeroes(uint32_t input_num) noexcept {
 1986|       |#if ADA_REGULAR_VISUAL_STUDIO
 1987|       |  unsigned long leading_zero(0);
 1988|       |  unsigned long in(input_num);
 1989|       |  return _BitScanReverse(&leading_zero, in) ? int(31 - leading_zero) : 32;
 1990|       |#else
 1991|    509|  return __builtin_clz(input_num);
 1992|    509|#endif  // ADA_REGULAR_VISUAL_STUDIO
 1993|    509|}
_ZN3ada14url_aggregator7reserveEj:
 9062|    509|constexpr void ada::url_aggregator::reserve(uint32_t capacity) {
 9063|    509|  buffer.reserve(capacity);
 9064|    509|}
_ZN3ada14url_aggregator31add_authority_slashes_if_neededEv:
 9036|    509|inline void ada::url_aggregator::add_authority_slashes_if_needed() {
 9037|    509|  ada_log("url_aggregator::add_authority_slashes_if_needed");
 9038|    509|  ADA_ASSERT_TRUE(validate());
 9039|       |  // Protocol setter will insert `http:` to the URL. It is up to hostname setter
 9040|       |  // to insert
 9041|       |  // `//` initially to the buffer, since it depends on the hostname existence.
 9042|    509|  if (has_authority()) {
  ------------------
  |  Branch (9042:7): [True: 0, False: 509]
  ------------------
 9043|      0|    return;
 9044|      0|  }
 9045|       |  // Performance: the common case is components.protocol_end == buffer.size()
 9046|       |  // Optimization opportunity: in many cases, the "//" is part of the input and
 9047|       |  // the insert could be fused with another insert.
 9048|    509|  buffer.insert(components.protocol_end, "//");
 9049|    509|  components.username_end += 2;
 9050|    509|  components.host_start += 2;
 9051|    509|  components.host_end += 2;
 9052|    509|  components.pathname_start += 2;
 9053|    509|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (9053:7): [True: 0, False: 509]
  ------------------
 9054|      0|    components.search_start += 2;
 9055|      0|  }
 9056|    509|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (9056:7): [True: 0, False: 509]
  ------------------
 9057|      0|    components.hash_start += 2;
 9058|      0|  }
 9059|    509|  ADA_ASSERT_TRUE(validate());
 9060|    509|}
_ZN3ada14url_aggregator12clear_searchEv:
 8886|  1.42k|inline void url_aggregator::clear_search() {
 8887|  1.42k|  ada_log("url_aggregator::clear_search");
 8888|  1.42k|  ADA_ASSERT_TRUE(validate());
 8889|  1.42k|  if (components.search_start == url_components::omitted) {
  ------------------
  |  Branch (8889:7): [True: 0, False: 1.42k]
  ------------------
 8890|      0|    return;
 8891|      0|  }
 8892|       |
 8893|  1.42k|  if (components.hash_start == url_components::omitted) {
  ------------------
  |  Branch (8893:7): [True: 1.21k, False: 205]
  ------------------
 8894|  1.21k|    buffer.resize(components.search_start);
 8895|  1.21k|  } else {
 8896|    205|    buffer.erase(components.search_start,
 8897|    205|                 components.hash_start - components.search_start);
 8898|    205|    components.hash_start = components.search_start;
 8899|    205|  }
 8900|       |
 8901|  1.42k|  components.search_start = url_components::omitted;
 8902|       |
 8903|       |#if ADA_DEVELOPMENT_CHECKS
 8904|       |  ADA_ASSERT_EQUAL(get_search(), "",
 8905|       |                   "search should have been cleared on buffer=" + buffer +
 8906|       |                       " with " + components.to_string() + "\n" + to_diagram());
 8907|       |#endif
 8908|  1.42k|  ADA_ASSERT_TRUE(validate());
 8909|  1.42k|}
_ZN3ada14url_aggregator18update_base_searchENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKh:
 8503|  3.11k|    std::string_view input, const uint8_t query_percent_encode_set[]) {
 8504|  3.11k|  ada_log("url_aggregator::update_base_search ", input,
 8505|  3.11k|          " with encoding parameter ", to_string(), "\n", to_diagram());
 8506|  3.11k|  ADA_ASSERT_TRUE(validate());
 8507|  3.11k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 8508|       |
 8509|  3.11k|  if (components.hash_start == url_components::omitted) {
  ------------------
  |  Branch (8509:7): [True: 2.84k, False: 271]
  ------------------
 8510|  2.84k|    if (components.search_start == url_components::omitted) {
  ------------------
  |  Branch (8510:9): [True: 1.53k, False: 1.30k]
  ------------------
 8511|  1.53k|      components.search_start = uint32_t(buffer.size());
 8512|  1.53k|      buffer += "?";
 8513|  1.53k|    } else {
 8514|  1.30k|      buffer.resize(components.search_start + 1);
 8515|  1.30k|    }
 8516|       |
 8517|  2.84k|    bool encoding_required =
 8518|  2.84k|        unicode::percent_encode<true>(input, query_percent_encode_set, buffer);
 8519|       |    // When encoding_required is false, then buffer is left unchanged, and
 8520|       |    // percent encoding was not deemed required.
 8521|  2.84k|    if (!encoding_required) {
  ------------------
  |  Branch (8521:9): [True: 1.68k, False: 1.15k]
  ------------------
 8522|  1.68k|      buffer.append(input);
 8523|  1.68k|    }
 8524|  2.84k|  } else {
 8525|    271|    const size_t idx =
 8526|    271|        ada::unicode::percent_encode_index(input, query_percent_encode_set);
 8527|    271|    std::string encoded;
 8528|    271|    std::string_view replacement = input;
 8529|    271|    if (idx != input.size()) {
  ------------------
  |  Branch (8529:9): [True: 0, False: 271]
  ------------------
 8530|      0|      encoded =
 8531|      0|          ada::unicode::percent_encode(input, query_percent_encode_set, idx);
 8532|      0|      replacement = encoded;
 8533|      0|    }
 8534|       |
 8535|    271|    if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (8535:9): [True: 271, False: 0]
  ------------------
 8536|    271|      const uint32_t difference = replace_and_resize(
 8537|    271|          components.search_start + 1, components.hash_start, replacement);
 8538|    271|      components.hash_start += difference;
 8539|    271|    } else {
 8540|      0|      components.search_start = components.hash_start;
 8541|      0|      buffer.insert(components.search_start, replacement.size() + 1, '?');
 8542|      0|      if (!replacement.empty()) {
  ------------------
  |  Branch (8542:11): [True: 0, False: 0]
  ------------------
 8543|      0|        std::memmove(buffer.data() + components.search_start + 1,
 8544|      0|                     replacement.data(), replacement.size());
 8545|      0|      }
 8546|      0|      components.hash_start +=
 8547|      0|          uint32_t(replacement.size() + 1);  // Do not forget `?`
 8548|      0|    }
 8549|    271|  }
 8550|       |
 8551|  3.11k|  ADA_ASSERT_TRUE(validate());
 8552|  3.11k|}
_ZN3ada14url_aggregator20update_base_hostnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8418|    509|inline void url_aggregator::update_base_hostname(const std::string_view input) {
 8419|    509|  ada_log("url_aggregator::update_base_hostname ", input, " [", input.size(),
 8420|    509|          " bytes], buffer is '", buffer, "' [", buffer.size(), " bytes]");
 8421|    509|  ADA_ASSERT_TRUE(validate());
 8422|    509|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 8423|       |
 8424|       |  // This next line is required for when parsing a URL like `foo://`
 8425|    509|  add_authority_slashes_if_needed();
 8426|       |
 8427|    509|  bool has_credentials = components.protocol_end + 2 < components.host_start;
 8428|    509|  uint32_t new_difference =
 8429|    509|      replace_and_resize(components.host_start, components.host_end, input);
 8430|       |
 8431|    509|  if (has_credentials) {
  ------------------
  |  Branch (8431:7): [True: 0, False: 509]
  ------------------
 8432|      0|    buffer.insert(components.host_start, "@");
 8433|      0|    new_difference++;
 8434|      0|  }
 8435|    509|  components.host_end += new_difference;
 8436|    509|  components.pathname_start += new_difference;
 8437|    509|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (8437:7): [True: 0, False: 509]
  ------------------
 8438|      0|    components.search_start += new_difference;
 8439|      0|  }
 8440|    509|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8440:7): [True: 0, False: 509]
  ------------------
 8441|      0|    components.hash_start += new_difference;
 8442|      0|  }
 8443|    509|  ADA_ASSERT_TRUE(validate());
 8444|    509|}
_ZN3ada7unicode20percent_encode_indexENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKh:
 8273|    271|                                              const uint8_t character_set[]) {
 8274|    271|  const char* data = input.data();
 8275|    271|  const size_t size = input.size();
 8276|       |
 8277|       |  // Process 8 bytes at a time using unrolled loop
 8278|    271|  size_t i = 0;
 8279|  4.00k|  for (; i + 8 <= size; i += 8) {
  ------------------
  |  Branch (8279:10): [True: 3.73k, False: 271]
  ------------------
 8280|  3.73k|    unsigned char chunk[8];
 8281|  3.73k|    std::memcpy(&chunk, data + i,
 8282|  3.73k|                8);  // entices compiler to unconditionally process 8 characters
 8283|       |
 8284|       |    // Check 8 characters at once
 8285|  33.6k|    for (size_t j = 0; j < 8; j++) {
  ------------------
  |  Branch (8285:24): [True: 29.8k, False: 3.73k]
  ------------------
 8286|  29.8k|      if (character_sets::bit_at(character_set, chunk[j])) {
  ------------------
  |  Branch (8286:11): [True: 0, False: 29.8k]
  ------------------
 8287|      0|        return i + j;
 8288|      0|      }
 8289|  29.8k|    }
 8290|  3.73k|  }
 8291|       |
 8292|       |  // Handle remaining bytes
 8293|  1.19k|  for (; i < size; i++) {
  ------------------
  |  Branch (8293:10): [True: 923, False: 271]
  ------------------
 8294|    923|    if (character_sets::bit_at(character_set, data[i])) {
  ------------------
  |  Branch (8294:9): [True: 0, False: 923]
  ------------------
 8295|      0|      return i;
 8296|      0|    }
 8297|    923|  }
 8298|       |
 8299|    271|  return size;
 8300|    271|}
_ZNK3ada14url_aggregator13has_authorityEv:
 9027|    509|    const noexcept {
 9028|    509|  ada_log("url_aggregator::has_authority");
 9029|       |  // Performance: instead of doing this potentially expensive check, we could
 9030|       |  // have a boolean in the struct.
 9031|    509|  return components.protocol_end + 2 <= components.host_start &&
  ------------------
  |  Branch (9031:10): [True: 0, False: 509]
  ------------------
 9032|      0|         buffer[components.protocol_end] == '/' &&
  ------------------
  |  Branch (9032:10): [True: 0, False: 0]
  ------------------
 9033|      0|         buffer[components.protocol_end + 1] == '/';
  ------------------
  |  Branch (9033:10): [True: 0, False: 0]
  ------------------
 9034|    509|}
_ZNK2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEcvbEv:
 4081|  2.99k|  constexpr explicit operator bool() const noexcept { return this->m_has_val; }
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEptEv:
 4050|  8.98k|  TL_EXPECTED_11_CONSTEXPR T* operator->() {
 4051|  8.98k|    TL_ASSERT(has_value());
  ------------------
  |  | 2103|  8.98k|#define TL_ASSERT(x) assert(x)
  ------------------
  |  Branch (4051:5): [True: 8.98k, False: 0]
  ------------------
 4052|  8.98k|    return valptr();
 4053|  8.98k|  }
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEE6valptrEv:
 3346|  8.98k|  T* valptr() { return std::addressof(this->m_val); }
_ZNK2tl8expectedIN3ada14url_aggregatorENS1_6errorsEE9has_valueEv:
 4080|  8.98k|  constexpr bool has_value() const noexcept { return this->m_has_val; }
_ZN2tl6detail21expected_storage_baseIN3ada14url_aggregatorENS2_6errorsELb0ELb1EED2Ev:
 2678|  2.99k|  ~expected_storage_base() {
 2679|  2.99k|    if (m_has_val) {
  ------------------
  |  Branch (2679:9): [True: 2.99k, False: 0]
  ------------------
 2680|  2.99k|      m_val.~T();
 2681|  2.99k|    }
 2682|  2.99k|  }
_ZN3ada7helpers9substringENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEmm:
 1897|  1.63k|                                                       size_t pos2) {
 1898|       |#if ADA_DEVELOPMENT_CHECKS
 1899|       |  if (pos2 < pos1) {
 1900|       |    std::cerr << "Negative-length substring: [" << pos1 << " to " << pos2 << ")"
 1901|       |              << std::endl;
 1902|       |    abort();
 1903|       |  }
 1904|       |#endif
 1905|  1.63k|  return input.substr(pos1, pos2 - pos1);
 1906|  1.63k|}
_ZNK3ada14url_aggregator10is_at_pathEv:
 8459|  1.53k|    const noexcept {
 8460|  1.53k|  return buffer.size() == components.pathname_start;
 8461|  1.53k|}
_ZN3ada17url_search_paramsC2ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9504|  14.9k|  explicit url_search_params(const std::string_view input) {
 9505|  14.9k|    initialize(input);
 9506|  14.9k|  }
_ZN3ada17url_search_params10initializeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9727|  17.9k|inline void url_search_params::initialize(std::string_view input) {
 9728|  17.9k|  if (!input.empty() && input.front() == '?') {
  ------------------
  |  Branch (9728:7): [True: 6.21k, False: 11.7k]
  |  Branch (9728:25): [True: 14, False: 6.19k]
  ------------------
 9729|     14|    input.remove_prefix(1);
 9730|     14|  }
 9731|  17.9k|  if (input.empty()) {
  ------------------
  |  Branch (9731:7): [True: 11.7k, False: 6.20k]
  ------------------
 9732|  11.7k|    return;
 9733|  11.7k|  }
 9734|       |  // Refuse overlong query strings (same process-wide cap as URL parsing).
 9735|  6.20k|  if (input.size() > get_max_input_length()) {
  ------------------
  |  Branch (9735:7): [True: 0, False: 6.20k]
  ------------------
 9736|      0|    return;
 9737|      0|  }
 9738|       |
 9739|  6.20k|  params.reserve(size_t(std::count(input.begin(), input.end(), '&')) + 1);
 9740|       |
 9741|  6.20k|  auto process_key_value = [&](const std::string_view current) {
 9742|  6.20k|    const auto equal = current.find('=');
 9743|  6.20k|    if (equal == std::string_view::npos) {
 9744|  6.20k|      params.emplace_back(unicode::form_urlencoded_decode(current), "");
 9745|  6.20k|    } else {
 9746|  6.20k|      params.emplace_back(
 9747|  6.20k|          unicode::form_urlencoded_decode(current.substr(0, equal)),
 9748|  6.20k|          unicode::form_urlencoded_decode(current.substr(equal + 1)));
 9749|  6.20k|    }
 9750|  6.20k|  };
 9751|       |
 9752|  37.5k|  while (!input.empty()) {
  ------------------
  |  Branch (9752:10): [True: 37.3k, False: 184]
  ------------------
 9753|  37.3k|    const auto ampersand_index = input.find('&');
 9754|       |
 9755|  37.3k|    if (ampersand_index == std::string_view::npos) {
  ------------------
  |  Branch (9755:9): [True: 6.01k, False: 31.3k]
  ------------------
 9756|  6.01k|      if (!input.empty()) {
  ------------------
  |  Branch (9756:11): [True: 6.01k, False: 0]
  ------------------
 9757|  6.01k|        process_key_value(input);
 9758|  6.01k|      }
 9759|  6.01k|      break;
 9760|  31.3k|    } else if (ampersand_index != 0) {
  ------------------
  |  Branch (9760:16): [True: 26.5k, False: 4.73k]
  ------------------
 9761|  26.5k|      process_key_value(input.substr(0, ampersand_index));
 9762|  26.5k|    }
 9763|       |
 9764|  31.3k|    input.remove_prefix(ampersand_index + 1);
 9765|  31.3k|  }
 9766|  6.20k|}
_ZZN3ada17url_search_params10initializeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlS5_E_clES5_:
 9741|  32.5k|  auto process_key_value = [&](const std::string_view current) {
 9742|  32.5k|    const auto equal = current.find('=');
 9743|  32.5k|    if (equal == std::string_view::npos) {
  ------------------
  |  Branch (9743:9): [True: 11.8k, False: 20.7k]
  ------------------
 9744|  11.8k|      params.emplace_back(unicode::form_urlencoded_decode(current), "");
 9745|  20.7k|    } else {
 9746|  20.7k|      params.emplace_back(
 9747|  20.7k|          unicode::form_urlencoded_decode(current.substr(0, equal)),
 9748|  20.7k|          unicode::form_urlencoded_decode(current.substr(equal + 1)));
 9749|  20.7k|    }
 9750|  32.5k|  };
_ZN3ada17url_search_paramsD2Ev:
 9512|  29.9k|  ~url_search_params() = default;
_ZNK3ada17url_search_params9to_stringEv:
 9814|  26.9k|inline std::string url_search_params::to_string() const {
 9815|  26.9k|  auto character_set = ada::character_sets::WWW_FORM_URLENCODED_PERCENT_ENCODE;
 9816|  26.9k|  std::string out{};
 9817|  84.2k|  for (size_t i = 0; i < params.size(); i++) {
  ------------------
  |  Branch (9817:22): [True: 57.2k, False: 26.9k]
  ------------------
 9818|  57.2k|    auto key = ada::unicode::percent_encode(params[i].first, character_set);
 9819|  57.2k|    auto value = ada::unicode::percent_encode(params[i].second, character_set);
 9820|       |
 9821|       |    // Performance optimization: Move this inside percent_encode.
 9822|  57.2k|    std::ranges::replace(key, ' ', '+');
 9823|  57.2k|    std::ranges::replace(value, ' ', '+');
 9824|       |
 9825|  57.2k|    if (i != 0) {
  ------------------
  |  Branch (9825:9): [True: 44.0k, False: 13.2k]
  ------------------
 9826|  44.0k|      out += "&";
 9827|  44.0k|    }
 9828|  57.2k|    out.append(key);
 9829|  57.2k|    out += "=";
 9830|  57.2k|    out.append(value);
 9831|  57.2k|  }
 9832|  26.9k|  return out;
 9833|  26.9k|}
_ZNK3ada17url_search_params4sizeEv:
 9773|  26.9k|inline size_t url_search_params::size() const noexcept { return params.size(); }
_ZN3ada17url_search_params4sortEv:
 9862|  5.99k|inline void url_search_params::sort() {
 9863|       |  // Keys are expected to be valid UTF-8, but percent_decode can produce
 9864|       |  // arbitrary byte sequences. Handle truncated/invalid sequences gracefully.
 9865|  5.99k|  std::ranges::stable_sort(params, [](const key_value_pair& lhs,
 9866|  5.99k|                                      const key_value_pair& rhs) {
 9867|  5.99k|    size_t i = 0, j = 0;
 9868|  5.99k|    uint32_t low_surrogate1 = 0, low_surrogate2 = 0;
 9869|  5.99k|    while ((i < lhs.first.size() || low_surrogate1 != 0) &&
 9870|  5.99k|           (j < rhs.first.size() || low_surrogate2 != 0)) {
 9871|  5.99k|      uint32_t codePoint1 = 0, codePoint2 = 0;
 9872|       |
 9873|  5.99k|      if (low_surrogate1 != 0) {
 9874|  5.99k|        codePoint1 = low_surrogate1;
 9875|  5.99k|        low_surrogate1 = 0;
 9876|  5.99k|      } else {
 9877|  5.99k|        uint8_t c1 = uint8_t(lhs.first[i]);
 9878|  5.99k|        if (c1 > 0x7F && c1 <= 0xDF && i + 1 < lhs.first.size()) {
 9879|  5.99k|          codePoint1 = ((c1 & 0x1F) << 6) | (uint8_t(lhs.first[i + 1]) & 0x3F);
 9880|  5.99k|          i += 2;
 9881|  5.99k|        } else if (c1 > 0xDF && c1 <= 0xEF && i + 2 < lhs.first.size()) {
 9882|  5.99k|          codePoint1 = ((c1 & 0x0F) << 12) |
 9883|  5.99k|                       ((uint8_t(lhs.first[i + 1]) & 0x3F) << 6) |
 9884|  5.99k|                       (uint8_t(lhs.first[i + 2]) & 0x3F);
 9885|  5.99k|          i += 3;
 9886|  5.99k|        } else if (c1 > 0xEF && c1 <= 0xF7 && i + 3 < lhs.first.size()) {
 9887|  5.99k|          codePoint1 = ((c1 & 0x07) << 18) |
 9888|  5.99k|                       ((uint8_t(lhs.first[i + 1]) & 0x3F) << 12) |
 9889|  5.99k|                       ((uint8_t(lhs.first[i + 2]) & 0x3F) << 6) |
 9890|  5.99k|                       (uint8_t(lhs.first[i + 3]) & 0x3F);
 9891|  5.99k|          i += 4;
 9892|       |
 9893|  5.99k|          codePoint1 -= 0x10000;
 9894|  5.99k|          uint16_t high_surrogate = uint16_t(0xD800 + (codePoint1 >> 10));
 9895|  5.99k|          low_surrogate1 = uint16_t(0xDC00 + (codePoint1 & 0x3FF));
 9896|  5.99k|          codePoint1 = high_surrogate;
 9897|  5.99k|        } else {
 9898|       |          // ASCII (c1 <= 0x7F) or truncated/invalid UTF-8: treat as raw byte
 9899|  5.99k|          codePoint1 = c1;
 9900|  5.99k|          i++;
 9901|  5.99k|        }
 9902|  5.99k|      }
 9903|       |
 9904|  5.99k|      if (low_surrogate2 != 0) {
 9905|  5.99k|        codePoint2 = low_surrogate2;
 9906|  5.99k|        low_surrogate2 = 0;
 9907|  5.99k|      } else {
 9908|  5.99k|        uint8_t c2 = uint8_t(rhs.first[j]);
 9909|  5.99k|        if (c2 > 0x7F && c2 <= 0xDF && j + 1 < rhs.first.size()) {
 9910|  5.99k|          codePoint2 = ((c2 & 0x1F) << 6) | (uint8_t(rhs.first[j + 1]) & 0x3F);
 9911|  5.99k|          j += 2;
 9912|  5.99k|        } else if (c2 > 0xDF && c2 <= 0xEF && j + 2 < rhs.first.size()) {
 9913|  5.99k|          codePoint2 = ((c2 & 0x0F) << 12) |
 9914|  5.99k|                       ((uint8_t(rhs.first[j + 1]) & 0x3F) << 6) |
 9915|  5.99k|                       (uint8_t(rhs.first[j + 2]) & 0x3F);
 9916|  5.99k|          j += 3;
 9917|  5.99k|        } else if (c2 > 0xEF && c2 <= 0xF7 && j + 3 < rhs.first.size()) {
 9918|  5.99k|          codePoint2 = ((c2 & 0x07) << 18) |
 9919|  5.99k|                       ((uint8_t(rhs.first[j + 1]) & 0x3F) << 12) |
 9920|  5.99k|                       ((uint8_t(rhs.first[j + 2]) & 0x3F) << 6) |
 9921|  5.99k|                       (uint8_t(rhs.first[j + 3]) & 0x3F);
 9922|  5.99k|          j += 4;
 9923|  5.99k|          codePoint2 -= 0x10000;
 9924|  5.99k|          uint16_t high_surrogate = uint16_t(0xD800 + (codePoint2 >> 10));
 9925|  5.99k|          low_surrogate2 = uint16_t(0xDC00 + (codePoint2 & 0x3FF));
 9926|  5.99k|          codePoint2 = high_surrogate;
 9927|  5.99k|        } else {
 9928|       |          // ASCII (c2 <= 0x7F) or truncated/invalid UTF-8: treat as raw byte
 9929|  5.99k|          codePoint2 = c2;
 9930|  5.99k|          j++;
 9931|  5.99k|        }
 9932|  5.99k|      }
 9933|       |
 9934|  5.99k|      if (codePoint1 != codePoint2) {
 9935|  5.99k|        return (codePoint1 < codePoint2);
 9936|  5.99k|      }
 9937|  5.99k|    }
 9938|  5.99k|    return (j < rhs.first.size() || low_surrogate2 != 0);
 9939|  5.99k|  });
 9940|  5.99k|}
_ZZN3ada17url_search_params4sortEvENKUlRKNSt3__14pairINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEES8_EESB_E_clESB_SB_:
 9866|  38.8k|                                      const key_value_pair& rhs) {
 9867|  38.8k|    size_t i = 0, j = 0;
 9868|  38.8k|    uint32_t low_surrogate1 = 0, low_surrogate2 = 0;
 9869|  63.0k|    while ((i < lhs.first.size() || low_surrogate1 != 0) &&
  ------------------
  |  Branch (9869:13): [True: 40.1k, False: 22.8k]
  |  Branch (9869:37): [True: 311, False: 22.5k]
  ------------------
 9870|  40.5k|           (j < rhs.first.size() || low_surrogate2 != 0)) {
  ------------------
  |  Branch (9870:13): [True: 38.3k, False: 2.14k]
  |  Branch (9870:37): [True: 315, False: 1.82k]
  ------------------
 9871|  38.6k|      uint32_t codePoint1 = 0, codePoint2 = 0;
 9872|       |
 9873|  38.6k|      if (low_surrogate1 != 0) {
  ------------------
  |  Branch (9873:11): [True: 1.03k, False: 37.6k]
  ------------------
 9874|  1.03k|        codePoint1 = low_surrogate1;
 9875|  1.03k|        low_surrogate1 = 0;
 9876|  37.6k|      } else {
 9877|  37.6k|        uint8_t c1 = uint8_t(lhs.first[i]);
 9878|  37.6k|        if (c1 > 0x7F && c1 <= 0xDF && i + 1 < lhs.first.size()) {
  ------------------
  |  Branch (9878:13): [True: 12.3k, False: 25.2k]
  |  Branch (9878:26): [True: 4.52k, False: 7.86k]
  |  Branch (9878:40): [True: 1.69k, False: 2.82k]
  ------------------
 9879|  1.69k|          codePoint1 = ((c1 & 0x1F) << 6) | (uint8_t(lhs.first[i + 1]) & 0x3F);
 9880|  1.69k|          i += 2;
 9881|  35.9k|        } else if (c1 > 0xDF && c1 <= 0xEF && i + 2 < lhs.first.size()) {
  ------------------
  |  Branch (9881:20): [True: 7.86k, False: 28.0k]
  |  Branch (9881:33): [True: 2.05k, False: 5.80k]
  |  Branch (9881:47): [True: 1.06k, False: 993]
  ------------------
 9882|  1.06k|          codePoint1 = ((c1 & 0x0F) << 12) |
 9883|  1.06k|                       ((uint8_t(lhs.first[i + 1]) & 0x3F) << 6) |
 9884|  1.06k|                       (uint8_t(lhs.first[i + 2]) & 0x3F);
 9885|  1.06k|          i += 3;
 9886|  34.8k|        } else if (c1 > 0xEF && c1 <= 0xF7 && i + 3 < lhs.first.size()) {
  ------------------
  |  Branch (9886:20): [True: 5.80k, False: 29.0k]
  |  Branch (9886:33): [True: 3.71k, False: 2.08k]
  |  Branch (9886:47): [True: 1.33k, False: 2.37k]
  ------------------
 9887|  1.33k|          codePoint1 = ((c1 & 0x07) << 18) |
 9888|  1.33k|                       ((uint8_t(lhs.first[i + 1]) & 0x3F) << 12) |
 9889|  1.33k|                       ((uint8_t(lhs.first[i + 2]) & 0x3F) << 6) |
 9890|  1.33k|                       (uint8_t(lhs.first[i + 3]) & 0x3F);
 9891|  1.33k|          i += 4;
 9892|       |
 9893|  1.33k|          codePoint1 -= 0x10000;
 9894|  1.33k|          uint16_t high_surrogate = uint16_t(0xD800 + (codePoint1 >> 10));
 9895|  1.33k|          low_surrogate1 = uint16_t(0xDC00 + (codePoint1 & 0x3FF));
 9896|  1.33k|          codePoint1 = high_surrogate;
 9897|  33.5k|        } else {
 9898|       |          // ASCII (c1 <= 0x7F) or truncated/invalid UTF-8: treat as raw byte
 9899|  33.5k|          codePoint1 = c1;
 9900|  33.5k|          i++;
 9901|  33.5k|        }
 9902|  37.6k|      }
 9903|       |
 9904|  38.6k|      if (low_surrogate2 != 0) {
  ------------------
  |  Branch (9904:11): [True: 1.03k, False: 37.6k]
  ------------------
 9905|  1.03k|        codePoint2 = low_surrogate2;
 9906|  1.03k|        low_surrogate2 = 0;
 9907|  37.6k|      } else {
 9908|  37.6k|        uint8_t c2 = uint8_t(rhs.first[j]);
 9909|  37.6k|        if (c2 > 0x7F && c2 <= 0xDF && j + 1 < rhs.first.size()) {
  ------------------
  |  Branch (9909:13): [True: 14.3k, False: 23.3k]
  |  Branch (9909:26): [True: 5.82k, False: 8.48k]
  |  Branch (9909:40): [True: 2.39k, False: 3.43k]
  ------------------
 9910|  2.39k|          codePoint2 = ((c2 & 0x1F) << 6) | (uint8_t(rhs.first[j + 1]) & 0x3F);
 9911|  2.39k|          j += 2;
 9912|  35.2k|        } else if (c2 > 0xDF && c2 <= 0xEF && j + 2 < rhs.first.size()) {
  ------------------
  |  Branch (9912:20): [True: 8.48k, False: 26.7k]
  |  Branch (9912:33): [True: 2.19k, False: 6.28k]
  |  Branch (9912:47): [True: 1.12k, False: 1.06k]
  ------------------
 9913|  1.12k|          codePoint2 = ((c2 & 0x0F) << 12) |
 9914|  1.12k|                       ((uint8_t(rhs.first[j + 1]) & 0x3F) << 6) |
 9915|  1.12k|                       (uint8_t(rhs.first[j + 2]) & 0x3F);
 9916|  1.12k|          j += 3;
 9917|  34.1k|        } else if (c2 > 0xEF && c2 <= 0xF7 && j + 3 < rhs.first.size()) {
  ------------------
  |  Branch (9917:20): [True: 6.28k, False: 27.8k]
  |  Branch (9917:33): [True: 3.77k, False: 2.50k]
  |  Branch (9917:47): [True: 1.47k, False: 2.30k]
  ------------------
 9918|  1.47k|          codePoint2 = ((c2 & 0x07) << 18) |
 9919|  1.47k|                       ((uint8_t(rhs.first[j + 1]) & 0x3F) << 12) |
 9920|  1.47k|                       ((uint8_t(rhs.first[j + 2]) & 0x3F) << 6) |
 9921|  1.47k|                       (uint8_t(rhs.first[j + 3]) & 0x3F);
 9922|  1.47k|          j += 4;
 9923|  1.47k|          codePoint2 -= 0x10000;
 9924|  1.47k|          uint16_t high_surrogate = uint16_t(0xD800 + (codePoint2 >> 10));
 9925|  1.47k|          low_surrogate2 = uint16_t(0xDC00 + (codePoint2 & 0x3FF));
 9926|  1.47k|          codePoint2 = high_surrogate;
 9927|  32.6k|        } else {
 9928|       |          // ASCII (c2 <= 0x7F) or truncated/invalid UTF-8: treat as raw byte
 9929|  32.6k|          codePoint2 = c2;
 9930|  32.6k|          j++;
 9931|  32.6k|        }
 9932|  37.6k|      }
 9933|       |
 9934|  38.6k|      if (codePoint1 != codePoint2) {
  ------------------
  |  Branch (9934:11): [True: 14.4k, False: 24.2k]
  ------------------
 9935|  14.4k|        return (codePoint1 < codePoint2);
 9936|  14.4k|      }
 9937|  38.6k|    }
 9938|  24.4k|    return (j < rhs.first.size() || low_surrogate2 != 0);
  ------------------
  |  Branch (9938:13): [True: 5.18k, False: 19.2k]
  |  Branch (9938:37): [True: 11, False: 19.2k]
  ------------------
 9939|  38.8k|  });
_ZN3ada17url_search_params5resetENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9722|  2.99k|inline void url_search_params::reset(std::string_view input) {
 9723|  2.99k|  params.clear();
 9724|  2.99k|  initialize(input);
 9725|  2.99k|}
_ZN3ada17url_search_params6appendENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_:
 9769|  16.7k|                                      const std::string_view value) {
 9770|  16.7k|  params.emplace_back(key, value);
 9771|  16.7k|}
_ZN3ada17url_search_params3setENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_:
 9836|  2.99k|                                   const std::string_view value) {
 9837|  2.99k|  const auto find = [&key](const auto& param) { return param.first == key; };
 9838|       |
 9839|  2.99k|  auto it = std::ranges::find_if(params, find);
 9840|       |
 9841|  2.99k|  if (it == params.end()) {
  ------------------
  |  Branch (9841:7): [True: 0, False: 2.99k]
  ------------------
 9842|      0|    params.emplace_back(key, value);
 9843|  2.99k|  } else {
 9844|  2.99k|    it->second = value;
 9845|  2.99k|    params.erase(std::remove_if(std::next(it), params.end(), find),
 9846|  2.99k|                 params.end());
 9847|  2.99k|  }
 9848|  2.99k|}
_ZZN3ada17url_search_params3setENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_ENKUlRKT_E_clINS1_4pairINS1_12basic_stringIcS4_NS1_9allocatorIcEEEESF_EEEEDaS8_:
 9837|  5.99k|  const auto find = [&key](const auto& param) { return param.first == key; };
_ZN3ada17url_search_params6removeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9850|  4.35k|inline void url_search_params::remove(const std::string_view key) {
 9851|  4.35k|  std::erase_if(params,
 9852|  4.35k|                [&key](const auto& param) { return param.first == key; });
 9853|  4.35k|}
_ZZN3ada17url_search_params6removeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlRKT_E_clINS1_4pairINS1_12basic_stringIcS4_NS1_9allocatorIcEEEESF_EEEEDaS8_:
 9852|  9.76k|                [&key](const auto& param) { return param.first == key; });
_ZN3ada17url_search_params6removeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_:
 9856|  4.35k|                                      const std::string_view value) {
 9857|  4.35k|  std::erase_if(params, [&key, &value](const auto& param) {
 9858|  4.35k|    return param.first == key && param.second == value;
 9859|  4.35k|  });
 9860|  4.35k|}
_ZZN3ada17url_search_params6removeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_ENKUlRKT_E_clINS1_4pairINS1_12basic_stringIcS4_NS1_9allocatorIcEEEESF_EEEEDaS8_:
 9857|  3.59k|  std::erase_if(params, [&key, &value](const auto& param) {
 9858|  3.59k|    return param.first == key && param.second == value;
  ------------------
  |  Branch (9858:12): [True: 0, False: 3.59k]
  |  Branch (9858:34): [True: 0, False: 0]
  ------------------
 9859|  3.59k|  });
_ZN3ada17url_search_params3hasENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9800|  22.1k|inline bool url_search_params::has(const std::string_view key) noexcept {
 9801|  22.1k|  auto entry = std::ranges::find_if(
 9802|  22.1k|      params, [&key](const auto& param) { return param.first == key; });
 9803|  22.1k|  return entry != params.end();
 9804|  22.1k|}
_ZZN3ada17url_search_params3hasENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlRKT_E_clINS1_4pairINS1_12basic_stringIcS4_NS1_9allocatorIcEEEESF_EEEEDaS8_:
 9802|   262k|      params, [&key](const auto& param) { return param.first == key; });
_ZN3ada17url_search_params3hasENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_:
 9807|  12.5k|                                   std::string_view value) noexcept {
 9808|  12.5k|  auto entry = std::ranges::find_if(params, [&key, &value](const auto& param) {
 9809|  12.5k|    return param.first == key && param.second == value;
 9810|  12.5k|  });
 9811|  12.5k|  return entry != params.end();
 9812|  12.5k|}
_ZZN3ada17url_search_params3hasENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_ENKUlRKT_E_clINS1_4pairINS1_12basic_stringIcS4_NS1_9allocatorIcEEEESF_EEEEDaS8_:
 9808|   135k|  auto entry = std::ranges::find_if(params, [&key, &value](const auto& param) {
 9809|   135k|    return param.first == key && param.second == value;
  ------------------
  |  Branch (9809:12): [True: 16.1k, False: 119k]
  |  Branch (9809:34): [True: 10.9k, False: 5.22k]
  ------------------
 9810|   135k|  });
_ZN3ada17url_search_params3getENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9776|  18.5k|    const std::string_view key) {
 9777|  18.5k|  auto entry = std::ranges::find_if(
 9778|  18.5k|      params, [&key](const auto& param) { return param.first == key; });
 9779|       |
 9780|  18.5k|  if (entry == params.end()) {
  ------------------
  |  Branch (9780:7): [True: 5.70k, False: 12.8k]
  ------------------
 9781|  5.70k|    return std::nullopt;
 9782|  5.70k|  }
 9783|       |
 9784|  12.8k|  return entry->second;
 9785|  18.5k|}
_ZZN3ada17url_search_params3getENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlRKT_E_clINS1_4pairINS1_12basic_stringIcS4_NS1_9allocatorIcEEEESF_EEEEDaS8_:
 9778|   139k|      params, [&key](const auto& param) { return param.first == key; });
_ZN3ada17url_search_params7get_allENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9788|  5.99k|    const std::string_view key) {
 9789|  5.99k|  std::vector<std::string> out{};
 9790|       |
 9791|  16.6k|  for (auto& param : params) {
  ------------------
  |  Branch (9791:20): [True: 16.6k, False: 5.99k]
  ------------------
 9792|  16.6k|    if (param.first == key) {
  ------------------
  |  Branch (9792:9): [True: 5.88k, False: 10.7k]
  ------------------
 9793|  5.88k|      out.emplace_back(param.second);
 9794|  5.88k|    }
 9795|  16.6k|  }
 9796|       |
 9797|  5.99k|  return out;
 9798|  5.99k|}
_ZN3ada17url_search_params8get_keysEv:
 9942|  2.99k|inline url_search_params_keys_iter url_search_params::get_keys() {
 9943|  2.99k|  return url_search_params_keys_iter(*this);
 9944|  2.99k|}
_ZN3ada22url_search_params_iterINSt3__117basic_string_viewIcNS1_11char_traitsIcEEEELNS_27url_search_params_iter_typeE0EEC2ERNS_17url_search_paramsE:
 9684|  2.99k|  inline url_search_params_iter(url_search_params& params_) : params(params_) {}
_ZN3ada17url_search_params10get_valuesEv:
 9949|  2.99k|inline url_search_params_values_iter url_search_params::get_values() {
 9950|  2.99k|  return url_search_params_values_iter(*this);
 9951|  2.99k|}
_ZN3ada22url_search_params_iterINSt3__117basic_string_viewIcNS1_11char_traitsIcEEEELNS_27url_search_params_iter_typeE1EEC2ERNS_17url_search_paramsE:
 9684|  2.99k|  inline url_search_params_iter(url_search_params& params_) : params(params_) {}
_ZN3ada17url_search_params11get_entriesEv:
 9956|  2.99k|inline url_search_params_entries_iter url_search_params::get_entries() {
 9957|  2.99k|  return url_search_params_entries_iter(*this);
 9958|  2.99k|}
_ZN3ada22url_search_params_iterINSt3__14pairINS1_17basic_string_viewIcNS1_11char_traitsIcEEEES6_EELNS_27url_search_params_iter_typeE2EEC2ERNS_17url_search_paramsE:
 9684|  2.99k|  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:
 9966|  9.85k|inline std::optional<std::string_view> url_search_params_keys_iter::next() {
 9967|  9.85k|  if (!has_next()) {
  ------------------
  |  Branch (9967:7): [True: 0, False: 9.85k]
  ------------------
 9968|      0|    return std::nullopt;
 9969|      0|  }
 9970|  9.85k|  return params.params[pos++].first;
 9971|  9.85k|}
_ZN3ada22url_search_params_iterINSt3__117basic_string_viewIcNS1_11char_traitsIcEEEELNS_27url_search_params_iter_typeE1EE4nextEv:
 9974|  9.85k|inline std::optional<std::string_view> url_search_params_values_iter::next() {
 9975|  9.85k|  if (!has_next()) {
  ------------------
  |  Branch (9975:7): [True: 0, False: 9.85k]
  ------------------
 9976|      0|    return std::nullopt;
 9977|      0|  }
 9978|  9.85k|  return params.params[pos++].second;
 9979|  9.85k|}
_ZN3ada22url_search_params_iterINSt3__14pairINS1_17basic_string_viewIcNS1_11char_traitsIcEEEES6_EELNS_27url_search_params_iter_typeE2EE4nextEv:
 9983|  9.85k|url_search_params_entries_iter::next() {
 9984|  9.85k|  if (!has_next()) {
  ------------------
  |  Branch (9984:7): [True: 0, False: 9.85k]
  ------------------
 9985|      0|    return std::nullopt;
 9986|      0|  }
 9987|  9.85k|  return params.params[pos++];
 9988|  9.85k|}
_ZNK3ada17url_search_params5beginEv:
 9621|  11.9k|  inline auto begin() const { return params.begin(); }
_ZNK3ada17url_search_params3endEv:
 9622|  11.9k|  inline auto end() const { return params.end(); }
_ZNK3ada17url_search_params5frontEv:
 9623|  1.11k|  inline auto front() const { return params.front(); }
_ZNK3ada17url_search_params4backEv:
 9624|  1.11k|  inline auto back() const { return params.back(); }
_ZNK3ada17url_search_paramsixEm:
 9625|  1.11k|  inline auto operator[](size_t index) const { return params[index]; }
_ZN3ada17url_search_paramsC2Ev:
 9497|  8.98k|  url_search_params() = default;
_ZN3ada17url_search_paramsC2ERKS0_:
 9508|  2.99k|  url_search_params(const url_search_params& u) = default;
_ZN3ada17url_search_paramsaSERKS0_:
 9511|  2.99k|  url_search_params& operator=(const url_search_params& u) = default;
_ZN3ada17url_search_paramsC2EOS0_:
 9509|  2.99k|  url_search_params(url_search_params&& u) noexcept = default;
_ZN3ada17url_search_paramsaSEOS0_:
 9510|  2.99k|  url_search_params& operator=(url_search_params&& u) noexcept = default;
_ZNK3ada14url_aggregator8validateEv:
 9218|  2.99k|[[nodiscard]] constexpr bool url_aggregator::validate() const noexcept {
 9219|  2.99k|  if (!is_valid) {
  ------------------
  |  Branch (9219:7): [True: 0, False: 2.99k]
  ------------------
 9220|      0|    return true;
 9221|      0|  }
 9222|  2.99k|  if (!components.check_offset_consistency()) {
  ------------------
  |  Branch (9222:7): [True: 0, False: 2.99k]
  ------------------
 9223|      0|    ada_log("url_aggregator::validate inconsistent components \n",
 9224|      0|            to_diagram());
 9225|      0|    return false;
 9226|      0|  }
 9227|       |  // We have a credible components struct, but let us investivate more
 9228|       |  // carefully:
 9229|       |  /**
 9230|       |   * https://user:pass@example.com:1234/foo/bar?baz#quux
 9231|       |   *       |     |    |          | ^^^^|       |   |
 9232|       |   *       |     |    |          | |   |       |   `----- hash_start
 9233|       |   *       |     |    |          | |   |       `--------- search_start
 9234|       |   *       |     |    |          | |   `----------------- pathname_start
 9235|       |   *       |     |    |          | `--------------------- port
 9236|       |   *       |     |    |          `----------------------- host_end
 9237|       |   *       |     |    `---------------------------------- host_start
 9238|       |   *       |     `--------------------------------------- username_end
 9239|       |   *       `--------------------------------------------- protocol_end
 9240|       |   */
 9241|  2.99k|  if (components.protocol_end == url_components::omitted) {
  ------------------
  |  Branch (9241:7): [True: 0, False: 2.99k]
  ------------------
 9242|      0|    ada_log("url_aggregator::validate omitted protocol_end \n", to_diagram());
 9243|      0|    return false;
 9244|      0|  }
 9245|  2.99k|  if (components.username_end == url_components::omitted) {
  ------------------
  |  Branch (9245:7): [True: 0, False: 2.99k]
  ------------------
 9246|      0|    ada_log("url_aggregator::validate omitted username_end \n", to_diagram());
 9247|      0|    return false;
 9248|      0|  }
 9249|  2.99k|  if (components.host_start == url_components::omitted) {
  ------------------
  |  Branch (9249:7): [True: 0, False: 2.99k]
  ------------------
 9250|      0|    ada_log("url_aggregator::validate omitted host_start \n", to_diagram());
 9251|      0|    return false;
 9252|      0|  }
 9253|  2.99k|  if (components.host_end == url_components::omitted) {
  ------------------
  |  Branch (9253:7): [True: 0, False: 2.99k]
  ------------------
 9254|      0|    ada_log("url_aggregator::validate omitted host_end \n", to_diagram());
 9255|      0|    return false;
 9256|      0|  }
 9257|  2.99k|  if (components.pathname_start == url_components::omitted) {
  ------------------
  |  Branch (9257:7): [True: 0, False: 2.99k]
  ------------------
 9258|      0|    ada_log("url_aggregator::validate omitted pathname_start \n", to_diagram());
 9259|      0|    return false;
 9260|      0|  }
 9261|       |
 9262|  2.99k|  if (components.protocol_end > buffer.size()) {
  ------------------
  |  Branch (9262:7): [True: 0, False: 2.99k]
  ------------------
 9263|      0|    ada_log("url_aggregator::validate protocol_end overflow \n", to_diagram());
 9264|      0|    return false;
 9265|      0|  }
 9266|  2.99k|  if (components.username_end > buffer.size()) {
  ------------------
  |  Branch (9266:7): [True: 0, False: 2.99k]
  ------------------
 9267|      0|    ada_log("url_aggregator::validate username_end overflow \n", to_diagram());
 9268|      0|    return false;
 9269|      0|  }
 9270|  2.99k|  if (components.host_start > buffer.size()) {
  ------------------
  |  Branch (9270:7): [True: 0, False: 2.99k]
  ------------------
 9271|      0|    ada_log("url_aggregator::validate host_start overflow \n", to_diagram());
 9272|      0|    return false;
 9273|      0|  }
 9274|  2.99k|  if (components.host_end > buffer.size()) {
  ------------------
  |  Branch (9274:7): [True: 0, False: 2.99k]
  ------------------
 9275|      0|    ada_log("url_aggregator::validate host_end overflow \n", to_diagram());
 9276|      0|    return false;
 9277|      0|  }
 9278|  2.99k|  if (components.pathname_start > buffer.size()) {
  ------------------
  |  Branch (9278:7): [True: 0, False: 2.99k]
  ------------------
 9279|      0|    ada_log("url_aggregator::validate pathname_start overflow \n",
 9280|      0|            to_diagram());
 9281|      0|    return false;
 9282|      0|  }
 9283|       |
 9284|  2.99k|  if (components.protocol_end > 0) {
  ------------------
  |  Branch (9284:7): [True: 2.99k, False: 0]
  ------------------
 9285|  2.99k|    if (buffer[components.protocol_end - 1] != ':') {
  ------------------
  |  Branch (9285:9): [True: 0, False: 2.99k]
  ------------------
 9286|      0|      ada_log(
 9287|      0|          "url_aggregator::validate missing : at the end of the protocol \n",
 9288|      0|          to_diagram());
 9289|      0|      return false;
 9290|      0|    }
 9291|  2.99k|  }
 9292|       |
 9293|  2.99k|  if (components.username_end != buffer.size() &&
  ------------------
  |  Branch (9293:7): [True: 2.99k, False: 0]
  ------------------
 9294|  2.99k|      components.username_end > components.protocol_end + 2) {
  ------------------
  |  Branch (9294:7): [True: 0, False: 2.99k]
  ------------------
 9295|      0|    if (buffer[components.username_end] != ':' &&
  ------------------
  |  Branch (9295:9): [True: 0, False: 0]
  ------------------
 9296|      0|        buffer[components.username_end] != '@') {
  ------------------
  |  Branch (9296:9): [True: 0, False: 0]
  ------------------
 9297|      0|      ada_log(
 9298|      0|          "url_aggregator::validate missing : or @ at the end of the username "
 9299|      0|          "\n",
 9300|      0|          to_diagram());
 9301|      0|      return false;
 9302|      0|    }
 9303|      0|  }
 9304|       |
 9305|  2.99k|  if (components.host_start != buffer.size()) {
  ------------------
  |  Branch (9305:7): [True: 2.99k, False: 0]
  ------------------
 9306|  2.99k|    if (components.host_start > components.username_end) {
  ------------------
  |  Branch (9306:9): [True: 0, False: 2.99k]
  ------------------
 9307|      0|      if (buffer[components.host_start] != '@') {
  ------------------
  |  Branch (9307:11): [True: 0, False: 0]
  ------------------
 9308|      0|        ada_log(
 9309|      0|            "url_aggregator::validate missing @ at the end of the password \n",
 9310|      0|            to_diagram());
 9311|      0|        return false;
 9312|      0|      }
 9313|  2.99k|    } else if (components.host_start == components.username_end &&
  ------------------
  |  Branch (9313:16): [True: 2.99k, False: 0]
  ------------------
 9314|  2.99k|               components.host_end > components.host_start) {
  ------------------
  |  Branch (9314:16): [True: 2.99k, False: 0]
  ------------------
 9315|  2.99k|      if (components.host_start == components.protocol_end + 2) {
  ------------------
  |  Branch (9315:11): [True: 2.99k, False: 0]
  ------------------
 9316|  2.99k|        if (buffer[components.protocol_end] != '/' ||
  ------------------
  |  Branch (9316:13): [True: 0, False: 2.99k]
  ------------------
 9317|  2.99k|            buffer[components.protocol_end + 1] != '/') {
  ------------------
  |  Branch (9317:13): [True: 0, False: 2.99k]
  ------------------
 9318|      0|          ada_log(
 9319|      0|              "url_aggregator::validate missing // between protocol and host "
 9320|      0|              "\n",
 9321|      0|              to_diagram());
 9322|      0|          return false;
 9323|      0|        }
 9324|  2.99k|      } else {
 9325|      0|        if (components.host_start > components.protocol_end &&
  ------------------
  |  Branch (9325:13): [True: 0, False: 0]
  ------------------
 9326|      0|            buffer[components.host_start] != '@') {
  ------------------
  |  Branch (9326:13): [True: 0, False: 0]
  ------------------
 9327|      0|          ada_log(
 9328|      0|              "url_aggregator::validate missing @ at the end of the username "
 9329|      0|              "\n",
 9330|      0|              to_diagram());
 9331|      0|          return false;
 9332|      0|        }
 9333|      0|      }
 9334|  2.99k|    } else {
 9335|      0|      if (components.host_end != components.host_start) {
  ------------------
  |  Branch (9335:11): [True: 0, False: 0]
  ------------------
 9336|      0|        ada_log("url_aggregator::validate expected omitted host \n",
 9337|      0|                to_diagram());
 9338|      0|        return false;
 9339|      0|      }
 9340|      0|    }
 9341|  2.99k|  }
 9342|  2.99k|  if (components.host_end != buffer.size() &&
  ------------------
  |  Branch (9342:7): [True: 2.99k, False: 0]
  ------------------
 9343|  2.99k|      components.pathname_start > components.host_end) {
  ------------------
  |  Branch (9343:7): [True: 0, False: 2.99k]
  ------------------
 9344|      0|    if (components.pathname_start == components.host_end + 2 &&
  ------------------
  |  Branch (9344:9): [True: 0, False: 0]
  ------------------
 9345|      0|        buffer[components.host_end] == '/' &&
  ------------------
  |  Branch (9345:9): [True: 0, False: 0]
  ------------------
 9346|      0|        buffer[components.host_end + 1] == '.') {
  ------------------
  |  Branch (9346:9): [True: 0, False: 0]
  ------------------
 9347|      0|      if (components.pathname_start + 1 >= buffer.size() ||
  ------------------
  |  Branch (9347:11): [True: 0, False: 0]
  ------------------
 9348|      0|          buffer[components.pathname_start] != '/' ||
  ------------------
  |  Branch (9348:11): [True: 0, False: 0]
  ------------------
 9349|      0|          buffer[components.pathname_start + 1] != '/') {
  ------------------
  |  Branch (9349:11): [True: 0, False: 0]
  ------------------
 9350|      0|        ada_log(
 9351|      0|            "url_aggregator::validate expected the path to begin with // \n",
 9352|      0|            to_diagram());
 9353|      0|        return false;
 9354|      0|      }
 9355|      0|    } else if (buffer[components.host_end] != ':') {
  ------------------
  |  Branch (9355:16): [True: 0, False: 0]
  ------------------
 9356|      0|      ada_log("url_aggregator::validate missing : at the port \n",
 9357|      0|              to_diagram());
 9358|      0|      return false;
 9359|      0|    }
 9360|      0|  }
 9361|  2.99k|  if (components.pathname_start != buffer.size() &&
  ------------------
  |  Branch (9361:7): [True: 2.99k, False: 0]
  ------------------
 9362|  2.99k|      components.pathname_start < components.search_start &&
  ------------------
  |  Branch (9362:7): [True: 2.99k, False: 0]
  ------------------
 9363|  2.99k|      components.pathname_start < components.hash_start && !has_opaque_path) {
  ------------------
  |  Branch (9363:7): [True: 2.99k, False: 0]
  |  Branch (9363:60): [True: 2.99k, False: 0]
  ------------------
 9364|  2.99k|    if (buffer[components.pathname_start] != '/') {
  ------------------
  |  Branch (9364:9): [True: 0, False: 2.99k]
  ------------------
 9365|      0|      ada_log("url_aggregator::validate missing / at the path \n",
 9366|      0|              to_diagram());
 9367|      0|      return false;
 9368|      0|    }
 9369|  2.99k|  }
 9370|  2.99k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (9370:7): [True: 1.57k, False: 1.42k]
  ------------------
 9371|  1.57k|    if (buffer[components.search_start] != '?') {
  ------------------
  |  Branch (9371:9): [True: 0, False: 1.57k]
  ------------------
 9372|      0|      ada_log("url_aggregator::validate missing ? at the search \n",
 9373|      0|              to_diagram());
 9374|      0|      return false;
 9375|      0|    }
 9376|  1.57k|  }
 9377|  2.99k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (9377:7): [True: 476, False: 2.51k]
  ------------------
 9378|    476|    if (buffer[components.hash_start] != '#') {
  ------------------
  |  Branch (9378:9): [True: 0, False: 476]
  ------------------
 9379|      0|      ada_log("url_aggregator::validate missing # at the hash \n",
 9380|      0|              to_diagram());
 9381|      0|      return false;
 9382|      0|    }
 9383|    476|  }
 9384|       |
 9385|  2.99k|  return true;
 9386|  2.99k|}
_ZNK3ada14url_components24check_offset_consistencyEv:
 7712|  2.99k|    const noexcept {
 7713|       |  /**
 7714|       |   * https://user:pass@example.com:1234/foo/bar?baz#quux
 7715|       |   *       |     |    |          | ^^^^|       |   |
 7716|       |   *       |     |    |          | |   |       |   `----- hash_start
 7717|       |   *       |     |    |          | |   |       `--------- search_start
 7718|       |   *       |     |    |          | |   `----------------- pathname_start
 7719|       |   *       |     |    |          | `--------------------- port
 7720|       |   *       |     |    |          `----------------------- host_end
 7721|       |   *       |     |    `---------------------------------- host_start
 7722|       |   *       |     `--------------------------------------- username_end
 7723|       |   *       `--------------------------------------------- protocol_end
 7724|       |   */
 7725|       |  // These conditions can be made more strict.
 7726|  2.99k|  if (protocol_end == url_components::omitted) {
  ------------------
  |  Branch (7726:7): [True: 0, False: 2.99k]
  ------------------
 7727|      0|    return false;
 7728|      0|  }
 7729|  2.99k|  uint32_t index = protocol_end;
 7730|       |
 7731|  2.99k|  if (username_end == url_components::omitted) {
  ------------------
  |  Branch (7731:7): [True: 0, False: 2.99k]
  ------------------
 7732|      0|    return false;
 7733|      0|  }
 7734|  2.99k|  if (username_end < index) {
  ------------------
  |  Branch (7734:7): [True: 0, False: 2.99k]
  ------------------
 7735|      0|    return false;
 7736|      0|  }
 7737|  2.99k|  index = username_end;
 7738|       |
 7739|  2.99k|  if (host_start == url_components::omitted) {
  ------------------
  |  Branch (7739:7): [True: 0, False: 2.99k]
  ------------------
 7740|      0|    return false;
 7741|      0|  }
 7742|  2.99k|  if (host_start < index) {
  ------------------
  |  Branch (7742:7): [True: 0, False: 2.99k]
  ------------------
 7743|      0|    return false;
 7744|      0|  }
 7745|  2.99k|  index = host_start;
 7746|       |
 7747|  2.99k|  if (port != url_components::omitted) {
  ------------------
  |  Branch (7747:7): [True: 0, False: 2.99k]
  ------------------
 7748|      0|    if (port > 0xffff) {
  ------------------
  |  Branch (7748:9): [True: 0, False: 0]
  ------------------
 7749|      0|      return false;
 7750|      0|    }
 7751|      0|    uint32_t port_length = helpers::fast_digit_count(port) + 1;
 7752|      0|    if (index + port_length < index) {
  ------------------
  |  Branch (7752:9): [True: 0, False: 0]
  ------------------
 7753|      0|      return false;
 7754|      0|    }
 7755|      0|    index += port_length;
 7756|      0|  }
 7757|       |
 7758|  2.99k|  if (pathname_start == url_components::omitted) {
  ------------------
  |  Branch (7758:7): [True: 0, False: 2.99k]
  ------------------
 7759|      0|    return false;
 7760|      0|  }
 7761|  2.99k|  if (pathname_start < index) {
  ------------------
  |  Branch (7761:7): [True: 0, False: 2.99k]
  ------------------
 7762|      0|    return false;
 7763|      0|  }
 7764|  2.99k|  index = pathname_start;
 7765|       |
 7766|  2.99k|  if (search_start != url_components::omitted) {
  ------------------
  |  Branch (7766:7): [True: 1.57k, False: 1.42k]
  ------------------
 7767|  1.57k|    if (search_start < index) {
  ------------------
  |  Branch (7767:9): [True: 0, False: 1.57k]
  ------------------
 7768|      0|      return false;
 7769|      0|    }
 7770|  1.57k|    index = search_start;
 7771|  1.57k|  }
 7772|       |
 7773|  2.99k|  if (hash_start != url_components::omitted) {
  ------------------
  |  Branch (7773:7): [True: 476, False: 2.51k]
  ------------------
 7774|    476|    if (hash_start < index) {
  ------------------
  |  Branch (7774:9): [True: 0, False: 476]
  ------------------
 7775|      0|      return false;
 7776|      0|    }
 7777|    476|  }
 7778|       |
 7779|  2.99k|  return true;
 7780|  2.99k|}
_ZNK3ada22url_search_params_iterINSt3__117basic_string_viewIcNS1_11char_traitsIcEEEELNS_27url_search_params_iter_typeE0EE8has_nextEv:
 9961|  22.7k|inline bool url_search_params_iter<T, Type>::has_next() const {
 9962|  22.7k|  return pos < params.params.size();
 9963|  22.7k|}
_ZNK3ada22url_search_params_iterINSt3__117basic_string_viewIcNS1_11char_traitsIcEEEELNS_27url_search_params_iter_typeE1EE8has_nextEv:
 9961|  22.7k|inline bool url_search_params_iter<T, Type>::has_next() const {
 9962|  22.7k|  return pos < params.params.size();
 9963|  22.7k|}
_ZNK3ada22url_search_params_iterINSt3__14pairINS1_17basic_string_viewIcNS1_11char_traitsIcEEEES6_EELNS_27url_search_params_iter_typeE2EE8has_nextEv:
 9961|  22.7k|inline bool url_search_params_iter<T, Type>::has_next() const {
 9962|  22.7k|  return pos < params.params.size();
 9963|  22.7k|}

LLVMFuzzerTestOneInput:
    9|  2.99k|extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   10|  2.99k|  FuzzedDataProvider fdp(data, size);
   11|  2.99k|  std::string source = fdp.ConsumeRandomLengthString(256);
   12|  2.99k|  std::string base_source = fdp.ConsumeRandomLengthString(256);
   13|  2.99k|  std::string key3 = fdp.ConsumeRandomLengthString(64);
   14|  2.99k|  std::string value3 = fdp.ConsumeRandomLengthString(64);
   15|       |
   16|       |  /**
   17|       |   * ada::url_search_params
   18|       |   */
   19|  2.99k|  volatile size_t length = 0;
   20|       |
   21|  2.99k|  auto base_source_view =
   22|  2.99k|      std::string_view(base_source.data(), base_source.length());
   23|       |
   24|       |  // Test constructor with initial value
   25|  2.99k|  auto initialized = ada::url_search_params(base_source_view);
   26|  2.99k|  length += initialized.size();
   27|  2.99k|  initialized.to_string();
   28|       |
   29|       |  // Test get() and get_all() on initialized params
   30|  2.99k|  {
   31|  2.99k|    auto val = initialized.get(source);
   32|  2.99k|    if (val.has_value()) {
  ------------------
  |  Branch (32:9): [True: 259, False: 2.73k]
  ------------------
   33|    259|      length += val->size();
   34|    259|    }
   35|  2.99k|    auto all_vals = initialized.get_all(source);
   36|  2.99k|    for (const auto& v : all_vals) {
  ------------------
  |  Branch (36:24): [True: 2.43k, False: 2.99k]
  ------------------
   37|  2.43k|      length += v.size();
   38|  2.43k|    }
   39|  2.99k|  }
   40|       |
   41|       |  // Test sort() on initialized params
   42|  2.99k|  initialized.sort();
   43|       |
   44|       |  // Test C++ range-for iteration; also verify has(k) and has(k,v) consistency.
   45|  9.58k|  for (const auto& pair : initialized) {
  ------------------
  |  Branch (45:25): [True: 9.58k, False: 2.99k]
  ------------------
   46|  9.58k|    length += pair.first.size();
   47|  9.58k|    length += pair.second.size();
   48|       |
   49|       |    // Every key seen in iteration must be reported by has(key).
   50|  9.58k|    if (!initialized.has(pair.first)) {
  ------------------
  |  Branch (50:9): [True: 0, False: 9.58k]
  ------------------
   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.58k|    if (initialized.has(pair.first, pair.second) &&
  ------------------
  |  Branch (59:9): [True: 9.58k, False: 0]
  ------------------
   60|  9.58k|        !initialized.has(pair.first)) {
  ------------------
  |  Branch (60:9): [True: 0, False: 9.58k]
  ------------------
   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.58k|    auto got = initialized.get(pair.first);
   70|  9.58k|    if (!got.has_value()) {
  ------------------
  |  Branch (70:9): [True: 0, False: 9.58k]
  ------------------
   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.58k|  }
   78|       |
   79|       |  // Test index-based access
   80|  2.99k|  if (initialized.size() > 0) {
  ------------------
  |  Branch (80:7): [True: 1.11k, False: 1.88k]
  ------------------
   81|  1.11k|    auto front = initialized.front();
   82|  1.11k|    length += front.first.size();
   83|  1.11k|    auto back = initialized.back();
   84|  1.11k|    length += back.first.size();
   85|  1.11k|    auto first = initialized[0];
   86|  1.11k|    length += first.first.size();
   87|  1.11k|  }
   88|       |
   89|       |  // Test default-constructed params with various mutations
   90|  2.99k|  auto search_params = ada::url_search_params();
   91|  2.99k|  search_params.append(source, base_source);
   92|  2.99k|  search_params.append(key3, value3);
   93|  2.99k|  search_params.set(source, base_source);
   94|  2.99k|  search_params.to_string();
   95|       |
   96|       |  // Test size()
   97|  2.99k|  length += search_params.size();
   98|       |
   99|       |  // Test has() and has(key, value) overloads
  100|  2.99k|  volatile bool has_key = search_params.has(base_source);
  101|  2.99k|  if (has_key) {
  ------------------
  |  Branch (101:7): [True: 1.81k, False: 1.18k]
  ------------------
  102|  1.81k|    search_params.append(base_source, source);
  103|  1.81k|  }
  104|       |
  105|       |  // Test get() - returns first matching value
  106|  2.99k|  {
  107|  2.99k|    auto val = search_params.get(source);
  108|  2.99k|    if (val.has_value()) {
  ------------------
  |  Branch (108:9): [True: 2.99k, False: 0]
  ------------------
  109|  2.99k|      length += val->size();
  110|  2.99k|    }
  111|  2.99k|  }
  112|       |
  113|       |  // Test get_all() - returns all matching values
  114|  2.99k|  {
  115|  2.99k|    auto all_vals = search_params.get_all(source);
  116|  2.99k|    length += all_vals.size();
  117|  3.44k|    for (const auto& v : all_vals) {
  ------------------
  |  Branch (117:24): [True: 3.44k, False: 2.99k]
  ------------------
  118|  3.44k|      length += v.size();
  119|  3.44k|    }
  120|  2.99k|  }
  121|       |
  122|       |  // Test remove(key) and remove(key, value) overloads
  123|  2.99k|  search_params.remove(source);
  124|  2.99k|  search_params.remove(source, base_source);
  125|       |
  126|       |  // Test has(key, value) after remove
  127|  2.99k|  if (search_params.has(base_source, source)) {
  ------------------
  |  Branch (127:7): [True: 1.36k, False: 1.63k]
  ------------------
  128|  1.36k|    search_params.remove(base_source);
  129|  1.36k|    search_params.remove(base_source, source);
  130|  1.36k|  }
  131|       |
  132|       |  // Append more pairs for iteration testing
  133|  2.99k|  search_params.append(key3, value3);
  134|  2.99k|  search_params.append(source, key3);
  135|  2.99k|  search_params.append(base_source, value3);
  136|       |
  137|       |  // Test sort()
  138|  2.99k|  search_params.sort();
  139|       |
  140|       |  // Test serialization after sort
  141|  2.99k|  std::string serialized = search_params.to_string();
  142|  2.99k|  length += serialized.size();
  143|       |
  144|       |  // Test JavaScript-style iterator: keys
  145|  2.99k|  auto keys = search_params.get_keys();
  146|  12.8k|  while (keys.has_next()) {
  ------------------
  |  Branch (146:10): [True: 9.85k, False: 2.99k]
  ------------------
  147|  9.85k|    auto k = keys.next();
  148|  9.85k|    if (k.has_value()) {
  ------------------
  |  Branch (148:9): [True: 9.85k, False: 0]
  ------------------
  149|  9.85k|      length += k->size();
  150|  9.85k|    }
  151|  9.85k|  }
  152|       |
  153|       |  // Test JavaScript-style iterator: values
  154|  2.99k|  auto values = search_params.get_values();
  155|  12.8k|  while (values.has_next()) {
  ------------------
  |  Branch (155:10): [True: 9.85k, False: 2.99k]
  ------------------
  156|  9.85k|    auto v = values.next();
  157|  9.85k|    if (v.has_value()) {
  ------------------
  |  Branch (157:9): [True: 9.85k, False: 0]
  ------------------
  158|  9.85k|      length += v->size();
  159|  9.85k|    }
  160|  9.85k|  }
  161|       |
  162|       |  // Test JavaScript-style iterator: entries
  163|  2.99k|  auto entries = search_params.get_entries();
  164|  12.8k|  while (entries.has_next()) {
  ------------------
  |  Branch (164:10): [True: 9.85k, False: 2.99k]
  ------------------
  165|  9.85k|    auto e = entries.next();
  166|  9.85k|    if (e.has_value()) {
  ------------------
  |  Branch (166:9): [True: 9.85k, False: 0]
  ------------------
  167|  9.85k|      length += e->first.size();
  168|  9.85k|      length += e->second.size();
  169|  9.85k|    }
  170|  9.85k|  }
  171|       |
  172|       |  // Test C++ range-for on the mutated params
  173|  9.85k|  for (const auto& pair : search_params) {
  ------------------
  |  Branch (173:25): [True: 9.85k, False: 2.99k]
  ------------------
  174|  9.85k|    length += pair.first.size();
  175|  9.85k|    length += pair.second.size();
  176|  9.85k|  }
  177|       |
  178|       |  // Test reset() - private method used by C API
  179|  2.99k|  std::string resetted_value = fdp.ConsumeRandomLengthString(256);
  180|  2.99k|  search_params.reset(resetted_value);
  181|  2.99k|  length += search_params.size();
  182|       |
  183|       |  // Test that reset() followed by iteration doesn't crash
  184|  2.99k|  for (const auto& pair : search_params) {
  ------------------
  |  Branch (184:25): [True: 2.51k, False: 2.99k]
  ------------------
  185|  2.51k|    length += pair.first.size();
  186|  2.51k|    length += pair.second.size();
  187|  2.51k|  }
  188|       |
  189|       |  // Test get() after reset
  190|  2.99k|  {
  191|  2.99k|    auto val = search_params.get(source);
  192|  2.99k|    if (val.has_value()) {
  ------------------
  |  Branch (192:9): [True: 30, False: 2.96k]
  ------------------
  193|     30|      length += val->size();
  194|     30|    }
  195|  2.99k|  }
  196|       |
  197|       |  // Test copy constructor and copy assignment
  198|  2.99k|  ada::url_search_params copied = search_params;
  199|  2.99k|  length += copied.size();
  200|  2.99k|  ada::url_search_params assigned;
  201|  2.99k|  assigned = search_params;
  202|  2.99k|  length += assigned.size();
  203|       |
  204|       |  // Test move constructor and move assignment
  205|  2.99k|  ada::url_search_params move_constructed = std::move(copied);
  206|  2.99k|  length += move_constructed.size();
  207|  2.99k|  ada::url_search_params move_assigned;
  208|  2.99k|  move_assigned = std::move(assigned);
  209|  2.99k|  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|  2.99k|  {
  225|  2.99k|    std::string s1 = initialized.to_string();
  226|  2.99k|    ada::url_search_params reparsed(s1);
  227|  2.99k|    std::string s2 = reparsed.to_string();
  228|  2.99k|    if (s1 != s2) {
  ------------------
  |  Branch (228:9): [True: 0, False: 2.99k]
  ------------------
  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|  2.99k|  }
  236|       |
  237|       |  // Mutated params idempotency.
  238|  2.99k|  {
  239|  2.99k|    std::string s1 = move_assigned.to_string();
  240|  2.99k|    ada::url_search_params reparsed(s1);
  241|  2.99k|    std::string s2 = reparsed.to_string();
  242|  2.99k|    if (s1 != s2) {
  ------------------
  |  Branch (242:9): [True: 0, False: 2.99k]
  ------------------
  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|  2.99k|  }
  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|  2.99k|  {
  260|  2.99k|    std::string url_str = "https://example.com/?" + source;
  261|  2.99k|    auto parsed_url = ada::parse<ada::url_aggregator>(url_str);
  262|  2.99k|    if (parsed_url) {
  ------------------
  |  Branch (262:9): [True: 2.99k, False: 0]
  ------------------
  263|  2.99k|      std::string search_raw = std::string(parsed_url->get_search());
  264|  2.99k|      std::string_view search_view = search_raw;
  265|  2.99k|      if (!search_view.empty() && search_view[0] == '?') {
  ------------------
  |  Branch (265:11): [True: 1.63k, False: 1.36k]
  |  Branch (265:35): [True: 1.63k, False: 0]
  ------------------
  266|  1.63k|        search_view = search_view.substr(1);
  267|  1.63k|      }
  268|       |
  269|  2.99k|      ada::url_search_params sp_from_url(search_view);
  270|       |
  271|       |      // Size and iteration must not crash.
  272|  2.99k|      length += sp_from_url.size();
  273|  4.19k|      for (const auto& pair : sp_from_url) {
  ------------------
  |  Branch (273:29): [True: 4.19k, False: 2.99k]
  ------------------
  274|  4.19k|        length += pair.first.size();
  275|  4.19k|        length += pair.second.size();
  276|  4.19k|      }
  277|       |
  278|       |      // Idempotency check.
  279|  2.99k|      std::string t1 = sp_from_url.to_string();
  280|  2.99k|      ada::url_search_params sp2(t1);
  281|  2.99k|      std::string t2 = sp2.to_string();
  282|  2.99k|      if (t1 != t2) {
  ------------------
  |  Branch (282:11): [True: 0, False: 2.99k]
  ------------------
  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|  2.99k|      parsed_url->set_search(t1);
  292|  2.99k|      volatile bool v = parsed_url->validate();
  293|  2.99k|      (void)v;
  294|  2.99k|    }
  295|  2.99k|  }
  296|       |
  297|  2.99k|  return 0;
  298|  2.99k|}

