_ZN3ada4idna13utf8_to_utf32EPKcmPDi:
  160|  5.34k|size_t utf8_to_utf32(const char* buf, size_t len, char32_t* utf32_output) {
  161|  5.34k|  const uint8_t* data = reinterpret_cast<const uint8_t*>(buf);
  162|  5.34k|  size_t pos = 0;
  163|  5.34k|  const char32_t* start{utf32_output};
  164|   106k|  while (pos < len) {
  ------------------
  |  Branch (164:10): [True: 101k, False: 4.86k]
  ------------------
  165|       |    // try to convert the next block of 16 ASCII bytes
  166|   101k|    if (pos + 16 <= len) {  // if it is safe to read 16 more
  ------------------
  |  Branch (166:9): [True: 71.6k, False: 30.0k]
  ------------------
  167|       |                            // bytes, check that they are ascii
  168|  71.6k|      uint64_t v1;
  169|  71.6k|      std::memcpy(&v1, data + pos, sizeof(uint64_t));
  170|  71.6k|      uint64_t v2;
  171|  71.6k|      std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t));
  172|  71.6k|      uint64_t v{v1 | v2};
  173|  71.6k|      if ((v & 0x8080808080808080) == 0) {
  ------------------
  |  Branch (173:11): [True: 4.22k, False: 67.4k]
  ------------------
  174|  4.22k|        size_t final_pos = pos + 16;
  175|  71.7k|        while (pos < final_pos) {
  ------------------
  |  Branch (175:16): [True: 67.5k, False: 4.22k]
  ------------------
  176|  67.5k|          *utf32_output++ = char32_t(buf[pos]);
  177|  67.5k|          pos++;
  178|  67.5k|        }
  179|  4.22k|        continue;
  180|  4.22k|      }
  181|  71.6k|    }
  182|  97.4k|    uint8_t leading_byte = data[pos];  // leading byte
  183|  97.4k|    if (leading_byte < 0b10000000) {
  ------------------
  |  Branch (183:9): [True: 55.0k, False: 42.4k]
  ------------------
  184|       |      // converting one ASCII byte !!!
  185|  55.0k|      *utf32_output++ = char32_t(leading_byte);
  186|  55.0k|      pos++;
  187|  55.0k|    } else if ((leading_byte & 0b11100000) == 0b11000000) {
  ------------------
  |  Branch (187:16): [True: 8.36k, False: 34.0k]
  ------------------
  188|       |      // We have a two-byte UTF-8
  189|  8.36k|      if (pos + 1 >= len) {
  ------------------
  |  Branch (189:11): [True: 64, False: 8.30k]
  ------------------
  190|     64|        return 0;
  191|     64|      }  // minimal bound checking
  192|  8.30k|      if ((data[pos + 1] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (192:11): [True: 96, False: 8.20k]
  ------------------
  193|     96|        return 0;
  194|     96|      }
  195|       |      // range check
  196|  8.20k|      uint32_t code_point =
  197|  8.20k|          (leading_byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111);
  198|  8.20k|      if (code_point < 0x80 || 0x7ff < code_point) {
  ------------------
  |  Branch (198:11): [True: 8, False: 8.20k]
  |  Branch (198:32): [True: 0, False: 8.20k]
  ------------------
  199|      8|        return 0;
  200|      8|      }
  201|  8.20k|      *utf32_output++ = char32_t(code_point);
  202|  8.20k|      pos += 2;
  203|  34.0k|    } else if ((leading_byte & 0b11110000) == 0b11100000) {
  ------------------
  |  Branch (203:16): [True: 32.8k, False: 1.19k]
  ------------------
  204|       |      // We have a three-byte UTF-8
  205|  32.8k|      if (pos + 2 >= len) {
  ------------------
  |  Branch (205:11): [True: 16, False: 32.8k]
  ------------------
  206|     16|        return 0;
  207|     16|      }  // minimal bound checking
  208|       |
  209|  32.8k|      if ((data[pos + 1] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (209:11): [True: 26, False: 32.8k]
  ------------------
  210|     26|        return 0;
  211|     26|      }
  212|  32.8k|      if ((data[pos + 2] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (212:11): [True: 10, False: 32.8k]
  ------------------
  213|     10|        return 0;
  214|     10|      }
  215|       |      // range check
  216|  32.8k|      uint32_t code_point = (leading_byte & 0b00001111) << 12 |
  217|  32.8k|                            (data[pos + 1] & 0b00111111) << 6 |
  218|  32.8k|                            (data[pos + 2] & 0b00111111);
  219|  32.8k|      if (code_point < 0x800 || 0xffff < code_point ||
  ------------------
  |  Branch (219:11): [True: 8, False: 32.8k]
  |  Branch (219:33): [True: 0, False: 32.8k]
  ------------------
  220|  32.8k|          (0xd7ff < code_point && code_point < 0xe000)) {
  ------------------
  |  Branch (220:12): [True: 8.75k, False: 24.0k]
  |  Branch (220:35): [True: 6, False: 8.75k]
  ------------------
  221|     14|        return 0;
  222|     14|      }
  223|  32.8k|      *utf32_output++ = char32_t(code_point);
  224|  32.8k|      pos += 3;
  225|  32.8k|    } else if ((leading_byte & 0b11111000) == 0b11110000) {  // 0b11110000
  ------------------
  |  Branch (225:16): [True: 1.03k, False: 160]
  ------------------
  226|       |      // we have a 4-byte UTF-8 word.
  227|  1.03k|      if (pos + 3 >= len) {
  ------------------
  |  Branch (227:11): [True: 20, False: 1.01k]
  ------------------
  228|     20|        return 0;
  229|     20|      }  // minimal bound checking
  230|  1.01k|      if ((data[pos + 1] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (230:11): [True: 22, False: 990]
  ------------------
  231|     22|        return 0;
  232|     22|      }
  233|    990|      if ((data[pos + 2] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (233:11): [True: 6, False: 984]
  ------------------
  234|      6|        return 0;
  235|      6|      }
  236|    984|      if ((data[pos + 3] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (236:11): [True: 12, False: 972]
  ------------------
  237|     12|        return 0;
  238|     12|      }
  239|       |
  240|       |      // range check
  241|    972|      uint32_t code_point = (leading_byte & 0b00000111) << 18 |
  242|    972|                            (data[pos + 1] & 0b00111111) << 12 |
  243|    972|                            (data[pos + 2] & 0b00111111) << 6 |
  244|    972|                            (data[pos + 3] & 0b00111111);
  245|    972|      if (code_point <= 0xffff || 0x10ffff < code_point) {
  ------------------
  |  Branch (245:11): [True: 14, False: 958]
  |  Branch (245:35): [True: 12, False: 946]
  ------------------
  246|     26|        return 0;
  247|     26|      }
  248|    946|      *utf32_output++ = char32_t(code_point);
  249|    946|      pos += 4;
  250|    946|    } else {
  251|    160|      return 0;
  252|    160|    }
  253|  97.4k|  }
  254|  4.86k|  return utf32_output - start;
  255|  5.34k|}
_ZN3ada4idna22utf32_length_from_utf8EPKcm:
  270|  5.38k|size_t utf32_length_from_utf8(const char* buf, size_t len) {
  271|  5.38k|  const int8_t* p = reinterpret_cast<const int8_t*>(buf);
  272|  5.38k|  return std::count_if(p, std::next(p, len), [](int8_t c) {
  273|       |    // -65 is 0b10111111, anything larger in two-complement's
  274|       |    // should start a new code point.
  275|  5.38k|    return c > -65;
  276|  5.38k|  });
  277|  5.38k|}
_ZN3ada4idna7deflate9BitReader3getEi:
  405|   457k|  uint32_t get(int n) {
  406|   457k|    if (!ensure(n)) return UINT32_MAX;
  ------------------
  |  Branch (406:9): [True: 0, False: 457k]
  ------------------
  407|   457k|    uint32_t v = acc & ((1u << n) - 1);
  408|   457k|    acc >>= n;
  409|   457k|    bits -= n;
  410|   457k|    return v;
  411|   457k|  }
_ZN3ada4idna9ascii_mapEPcm:
 5126|   119k|void ascii_map(char* input, size_t length) {
 5127|   119k|  auto broadcast = [](uint8_t v) -> uint64_t {
 5128|   119k|    return 0x101010101010101ull * v;
 5129|   119k|  };
 5130|   119k|  uint64_t broadcast_80 = broadcast(0x80);
 5131|   119k|  uint64_t broadcast_Ap = broadcast(128 - 'A');
 5132|   119k|  uint64_t broadcast_Zp = broadcast(128 - 'Z' - 1);
 5133|   119k|  size_t i = 0;
 5134|       |
 5135|   317k|  for (; i + 7 < length; i += 8) {
  ------------------
  |  Branch (5135:10): [True: 198k, False: 119k]
  ------------------
 5136|   198k|    uint64_t word{};
 5137|   198k|    std::memcpy(&word, input + i, sizeof(word));
 5138|   198k|    word ^=
 5139|   198k|        (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
 5140|   198k|    std::memcpy(input + i, &word, sizeof(word));
 5141|   198k|  }
 5142|   119k|  if (i < length) {
  ------------------
  |  Branch (5142:7): [True: 62.2k, False: 57.1k]
  ------------------
 5143|  62.2k|    uint64_t word{};
 5144|  62.2k|    std::memcpy(&word, input + i, length - i);
 5145|  62.2k|    word ^=
 5146|  62.2k|        (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
 5147|  62.2k|    std::memcpy(input + i, &word, length - i);
 5148|  62.2k|  }
 5149|   119k|}
_ZN3ada4idna3mapENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEERNS1_12basic_stringIDiS4_NS1_9allocatorIDiEEEE:
 5153|  7.68k|bool map(std::u32string_view input, std::u32string& out) {
 5154|       |  //  [Map](https://www.unicode.org/reports/tr46/#ProcessingStepMap).
 5155|  7.68k|  out.clear();
 5156|  7.68k|  if (!ensure_tables()) {
  ------------------
  |  Branch (5156:7): [True: 0, False: 7.68k]
  ------------------
 5157|      0|    return false;
 5158|      0|  }
 5159|       |
 5160|       |  // Pass 1: validate and compute exact output length.
 5161|  7.68k|  size_t out_size = 0;
 5162|   183k|  for (char32_t x : input) {
  ------------------
  |  Branch (5162:19): [True: 183k, False: 7.29k]
  ------------------
 5163|   183k|    uint16_t status = idna_lookup(static_cast<uint32_t>(x));
 5164|   183k|    if (status == IDNA_DISALLOWED) {
  ------------------
  |  Branch (5164:9): [True: 388, False: 183k]
  ------------------
 5165|    388|      return false;
 5166|    388|    }
 5167|   183k|    if (status == IDNA_VALID) {
  ------------------
  |  Branch (5167:9): [True: 126k, False: 56.0k]
  ------------------
 5168|   126k|      ++out_size;
 5169|   126k|      continue;
 5170|   126k|    }
 5171|  56.0k|    if (static_cast<size_t>(status) >= idna_utf8_mappings_size) {
  ------------------
  |  Branch (5171:9): [True: 0, False: 56.0k]
  ------------------
 5172|      0|      return false;
 5173|      0|    }
 5174|  56.0k|    out_size += utf8_count_codepoints(idna_utf8_mappings + status);
 5175|  56.0k|  }
 5176|       |
 5177|       |  // Pass 2: write into a single allocation.
 5178|  7.29k|  out.resize(out_size);
 5179|  7.29k|  size_t w = 0;
 5180|   181k|  for (char32_t x : input) {
  ------------------
  |  Branch (5180:19): [True: 181k, False: 7.29k]
  ------------------
 5181|   181k|    uint16_t status = idna_lookup(static_cast<uint32_t>(x));
 5182|   181k|    if (status == IDNA_VALID) {
  ------------------
  |  Branch (5182:9): [True: 125k, False: 56.0k]
  ------------------
 5183|   125k|      out[w++] = x;
 5184|   125k|      continue;
 5185|   125k|    }
 5186|       |    // IGNORED or mapped (status already validated in pass 1).
 5187|  56.0k|    const uint8_t* ptr = idna_utf8_mappings + status;
 5188|   356k|    while (*ptr != 0) {
  ------------------
  |  Branch (5188:12): [True: 300k, False: 56.0k]
  ------------------
 5189|   300k|      out[w++] = utf8_next(ptr);
 5190|   300k|    }
 5191|  56.0k|  }
 5192|  7.29k|  return true;
 5193|  7.68k|}
_ZN3ada4idna28compute_decomposition_lengthENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5286|  1.40k|    const std::u32string_view input) noexcept {
 5287|  1.40k|  bool decomposition_needed{false};
 5288|  1.40k|  size_t additional_elements{0};
 5289|  61.8k|  for (char32_t current_character : input) {
  ------------------
  |  Branch (5289:35): [True: 61.8k, False: 1.40k]
  ------------------
 5290|  61.8k|    size_t decomposition_length{0};
 5291|       |
 5292|  61.8k|    if (current_character >= hangul_sbase &&
  ------------------
  |  Branch (5292:9): [True: 3.27k, False: 58.5k]
  ------------------
 5293|  3.27k|        current_character < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (5293:9): [True: 2.10k, False: 1.16k]
  ------------------
 5294|       |      // Full NFD-style Hangul decomp for the decompose() step.
 5295|  2.10k|      decomposition_length = 2;
 5296|  2.10k|      if ((current_character - hangul_sbase) % hangul_tcount) {
  ------------------
  |  Branch (5296:11): [True: 1.47k, False: 628]
  ------------------
 5297|  1.47k|        decomposition_length = 3;
 5298|  1.47k|      }
 5299|  59.7k|    } else if (current_character < 0x110000) {
  ------------------
  |  Branch (5299:16): [True: 59.7k, False: 0]
  ------------------
 5300|  59.7k|      const uint8_t di = decomposition_index[current_character >> 8];
 5301|  59.7k|      const uint16_t* const decomposition =
 5302|  59.7k|          decomposition_block_row(di) + (current_character % 256);
 5303|  59.7k|      decomposition_length = (decomposition[1] >> 2) - (decomposition[0] >> 2);
 5304|  59.7k|      if ((decomposition_length > 0) && (decomposition[0] & 1)) {
  ------------------
  |  Branch (5304:11): [True: 746, False: 59.0k]
  |  Branch (5304:41): [True: 0, False: 746]
  ------------------
 5305|      0|        decomposition_length = 0;
 5306|      0|      }
 5307|  59.7k|    }
 5308|  61.8k|    if (decomposition_length != 0) {
  ------------------
  |  Branch (5308:9): [True: 2.84k, False: 59.0k]
  ------------------
 5309|  2.84k|      decomposition_needed = true;
 5310|  2.84k|      additional_elements += decomposition_length - 1;
 5311|  2.84k|    }
 5312|  61.8k|  }
 5313|  1.40k|  return {decomposition_needed, additional_elements};
 5314|  1.40k|}
_ZN3ada4idna9decomposeERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEEm:
 5316|    824|void decompose(std::u32string& input, size_t additional_elements) {
 5317|    824|  input.resize(input.size() + additional_elements);
 5318|    824|  for (size_t descending_idx = input.size(),
 5319|    824|              input_count = descending_idx - additional_elements;
 5320|  43.5k|       input_count--;) {
  ------------------
  |  Branch (5320:8): [True: 42.7k, False: 824]
  ------------------
 5321|  42.7k|    if (input[input_count] >= hangul_sbase &&
  ------------------
  |  Branch (5321:9): [True: 2.58k, False: 40.1k]
  ------------------
 5322|  2.58k|        input[input_count] < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (5322:9): [True: 2.10k, False: 486]
  ------------------
 5323|       |      // Hangul decomposition.
 5324|  2.10k|      char32_t s_index = input[input_count] - hangul_sbase;
 5325|  2.10k|      if (s_index % hangul_tcount != 0) {
  ------------------
  |  Branch (5325:11): [True: 1.47k, False: 628]
  ------------------
 5326|  1.47k|        input[--descending_idx] = hangul_tbase + s_index % hangul_tcount;
 5327|  1.47k|      }
 5328|  2.10k|      input[--descending_idx] =
 5329|  2.10k|          hangul_vbase + (s_index % hangul_ncount) / hangul_tcount;
 5330|  2.10k|      input[--descending_idx] = hangul_lbase + s_index / hangul_ncount;
 5331|  40.6k|    } else if (input[input_count] < 0x110000) {
  ------------------
  |  Branch (5331:16): [True: 40.6k, False: 0]
  ------------------
 5332|  40.6k|      const uint16_t* decomposition =
 5333|  40.6k|          decomposition_block_row(
 5334|  40.6k|              decomposition_index[input[input_count] >> 8]) +
 5335|  40.6k|          (input[input_count] % 256);
 5336|  40.6k|      uint16_t decomposition_length =
 5337|  40.6k|          (decomposition[1] >> 2) - (decomposition[0] >> 2);
 5338|  40.6k|      if (decomposition_length > 0 && (decomposition[0] & 1)) {
  ------------------
  |  Branch (5338:11): [True: 746, False: 39.9k]
  |  Branch (5338:39): [True: 0, False: 746]
  ------------------
 5339|      0|        decomposition_length = 0;
 5340|      0|      }
 5341|  40.6k|      if (decomposition_length > 0) {
  ------------------
  |  Branch (5341:11): [True: 746, False: 39.9k]
  ------------------
 5342|    746|        const size_t base = static_cast<size_t>(decomposition[0] >> 2);
 5343|    746|        if (base + decomposition_length > decomposition_data_size) {
  ------------------
  |  Branch (5343:13): [True: 0, False: 746]
  ------------------
 5344|      0|          input[--descending_idx] = input[input_count];
 5345|    746|        } else {
 5346|  2.44k|          while (decomposition_length-- > 0) {
  ------------------
  |  Branch (5346:18): [True: 1.70k, False: 746]
  ------------------
 5347|  1.70k|            input[--descending_idx] =
 5348|  1.70k|                decomposition_data[base + decomposition_length];
 5349|  1.70k|          }
 5350|    746|        }
 5351|  39.9k|      } else {
 5352|  39.9k|        input[--descending_idx] = input[input_count];
 5353|  39.9k|      }
 5354|  40.6k|    } else {
 5355|      0|      input[--descending_idx] = input[input_count];
 5356|      0|    }
 5357|  42.7k|  }
 5358|    824|}
_ZN3ada4idna7get_cccEDi:
 5360|  1.30M|uint8_t get_ccc(char32_t c) noexcept {
 5361|  1.30M|  if (c >= 0x110000) {
  ------------------
  |  Branch (5361:7): [True: 0, False: 1.30M]
  ------------------
 5362|      0|    return 0;
 5363|      0|  }
 5364|  1.30M|  return ccc_block_row(ccc_index[c >> 8])[c % 256];
 5365|  1.30M|}
_ZN3ada4idna10sort_marksERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEE:
 5367|  1.40k|void sort_marks(std::u32string& input) {
 5368|  66.3k|  for (size_t idx = 1; idx < input.size(); idx++) {
  ------------------
  |  Branch (5368:24): [True: 64.9k, False: 1.40k]
  ------------------
 5369|  64.9k|    uint8_t ccc = get_ccc(input[idx]);
 5370|  64.9k|    if (ccc == 0) {
  ------------------
  |  Branch (5370:9): [True: 61.1k, False: 3.81k]
  ------------------
 5371|  61.1k|      continue;
 5372|  61.1k|    }
 5373|  3.81k|    auto current_character = input[idx];
 5374|  3.81k|    size_t back_idx = idx;
 5375|  5.62k|    while (back_idx != 0 && get_ccc(input[back_idx - 1]) > ccc) {
  ------------------
  |  Branch (5375:12): [True: 5.46k, False: 162]
  |  Branch (5375:29): [True: 1.81k, False: 3.65k]
  ------------------
 5376|  1.81k|      input[back_idx] = input[back_idx - 1];
 5377|  1.81k|      back_idx--;
 5378|  1.81k|    }
 5379|  3.81k|    input[back_idx] = current_character;
 5380|  3.81k|  }
 5381|  1.40k|}
_ZN3ada4idna13decompose_nfcERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEE:
 5383|  1.40k|void decompose_nfc(std::u32string& input) {
 5384|       |  /**
 5385|       |   * Decompose the domain_name string to Unicode Normalization Form C.
 5386|       |   * @see https://www.unicode.org/reports/tr46/#ProcessingStepDecompose
 5387|       |   */
 5388|  1.40k|  auto [decomposition_needed, additional_elements] =
 5389|  1.40k|      compute_decomposition_length(input);
 5390|  1.40k|  if (decomposition_needed) {
  ------------------
  |  Branch (5390:7): [True: 824, False: 578]
  ------------------
 5391|    824|    decompose(input, additional_elements);
 5392|    824|  }
 5393|  1.40k|  sort_marks(input);
 5394|  1.40k|}
_ZN3ada4idna14is_already_nfcENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5477|  7.94k|bool is_already_nfc(std::u32string_view input) noexcept {
 5478|  7.94k|  if (input.empty()) {
  ------------------
  |  Branch (5478:7): [True: 0, False: 7.94k]
  ------------------
 5479|      0|    return true;
 5480|      0|  }
 5481|  7.94k|  if (!tables_are_ready() && !ensure_tables()) {
  ------------------
  |  Branch (5481:7): [True: 0, False: 7.94k]
  |  Branch (5481:30): [True: 0, False: 0]
  ------------------
 5482|      0|    return false;
 5483|      0|  }
 5484|       |  // 1) Singleton decompositions are never NFC (e.g. U+212B ANGSTROM SIGN).
 5485|       |  //    Multi-code-point decomps are primary composites that are NFC as-is.
 5486|   421k|  for (char32_t c : input) {
  ------------------
  |  Branch (5486:19): [True: 421k, False: 7.94k]
  ------------------
 5487|   421k|    if (canonical_decomp_length(c) == 1) {
  ------------------
  |  Branch (5487:9): [True: 0, False: 421k]
  ------------------
 5488|      0|      return false;
 5489|      0|    }
 5490|   421k|  }
 5491|       |  // 2) Combining marks already in canonical order. prev_ccc carries the
 5492|       |  //    trailing class of the previous character's canonical decomposition so a
 5493|       |  //    composite starter followed by a lower-class mark is caught.
 5494|  7.94k|  uint8_t prev_ccc = 0;
 5495|   417k|  for (char32_t c : input) {
  ------------------
  |  Branch (5495:19): [True: 417k, False: 7.49k]
  ------------------
 5496|   417k|    uint8_t ccc = get_ccc(c);
 5497|   417k|    if (ccc != 0 && prev_ccc > ccc) {
  ------------------
  |  Branch (5497:9): [True: 6.20k, False: 411k]
  |  Branch (5497:21): [True: 456, False: 5.75k]
  ------------------
 5498|    456|      return false;
 5499|    456|    }
 5500|   417k|    prev_ccc = trailing_ccc(c);
 5501|   417k|  }
 5502|       |  // 3) No pairwise composition would apply (including Hangul L+V / LV+T).
 5503|  7.49k|  return !would_compose(input);
 5504|  7.94k|}
_ZN3ada4idna7composeERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEE:
 5506|  1.40k|void compose(std::u32string& input) {
 5507|       |  /**
 5508|       |   * Compose the domain_name string to Unicode Normalization Form C.
 5509|       |   * @see https://www.unicode.org/reports/tr46/#ProcessingStepCompose
 5510|       |   */
 5511|  1.40k|  size_t input_count{0};
 5512|  1.40k|  size_t composition_count{0};
 5513|  60.5k|  for (; input_count < input.size(); input_count++, composition_count++) {
  ------------------
  |  Branch (5513:10): [True: 59.1k, False: 1.40k]
  ------------------
 5514|  59.1k|    input[composition_count] = input[input_count];
 5515|  59.1k|    if (input[input_count] >= hangul_lbase &&
  ------------------
  |  Branch (5515:9): [True: 6.22k, False: 52.8k]
  ------------------
 5516|  6.22k|        input[input_count] < hangul_lbase + hangul_lcount) {
  ------------------
  |  Branch (5516:9): [True: 3.15k, False: 3.06k]
  ------------------
 5517|  3.15k|      if (input_count + 1 < input.size() &&
  ------------------
  |  Branch (5517:11): [True: 3.07k, False: 78]
  ------------------
 5518|  3.07k|          input[input_count + 1] >= hangul_vbase &&
  ------------------
  |  Branch (5518:11): [True: 2.55k, False: 518]
  ------------------
 5519|  2.55k|          input[input_count + 1] < hangul_vbase + hangul_vcount) {
  ------------------
  |  Branch (5519:11): [True: 2.19k, False: 368]
  ------------------
 5520|  2.19k|        input[composition_count] =
 5521|  2.19k|            hangul_sbase +
 5522|  2.19k|            ((input[input_count] - hangul_lbase) * hangul_vcount +
 5523|  2.19k|             input[input_count + 1] - hangul_vbase) *
 5524|  2.19k|                hangul_tcount;
 5525|  2.19k|        input_count++;
 5526|  2.19k|        if (input_count + 1 < input.size() &&
  ------------------
  |  Branch (5526:13): [True: 2.09k, False: 98]
  ------------------
 5527|  2.09k|            input[input_count + 1] > hangul_tbase &&
  ------------------
  |  Branch (5527:13): [True: 1.68k, False: 404]
  ------------------
 5528|  1.68k|            input[input_count + 1] < hangul_tbase + hangul_tcount) {
  ------------------
  |  Branch (5528:13): [True: 1.47k, False: 214]
  ------------------
 5529|  1.47k|          input[composition_count] += input[++input_count] - hangul_tbase;
 5530|  1.47k|        }
 5531|  2.19k|      }
 5532|  55.9k|    } else if (input[input_count] >= hangul_sbase &&
  ------------------
  |  Branch (5532:16): [True: 824, False: 55.1k]
  ------------------
 5533|    824|               input[input_count] < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (5533:16): [True: 0, False: 824]
  ------------------
 5534|      0|      if ((input[input_count] - hangul_sbase) % hangul_tcount &&
  ------------------
  |  Branch (5534:11): [True: 0, False: 0]
  ------------------
 5535|      0|          input_count + 1 < input.size() &&
  ------------------
  |  Branch (5535:11): [True: 0, False: 0]
  ------------------
 5536|      0|          input[input_count + 1] > hangul_tbase &&
  ------------------
  |  Branch (5536:11): [True: 0, False: 0]
  ------------------
 5537|      0|          input[input_count + 1] < hangul_tbase + hangul_tcount) {
  ------------------
  |  Branch (5537:11): [True: 0, False: 0]
  ------------------
 5538|      0|        input[composition_count] += input[++input_count] - hangul_tbase;
 5539|      0|      }
 5540|  55.9k|    } else if (input[input_count] < 0x110000) {
  ------------------
  |  Branch (5540:16): [True: 55.9k, False: 0]
  ------------------
 5541|  55.9k|      const uint16_t* composition =
 5542|  55.9k|          composition_block_row(composition_index[input[input_count] >> 8]) +
 5543|  55.9k|          (input[input_count] % 256);
 5544|  55.9k|      size_t initial_composition_count = composition_count;
 5545|  59.5k|      for (int32_t previous_ccc = -1; input_count + 1 < input.size();
  ------------------
  |  Branch (5545:39): [True: 58.3k, False: 1.19k]
  ------------------
 5546|  58.3k|           input_count++) {
 5547|  58.3k|        uint8_t ccc = get_ccc(input[input_count + 1]);
 5548|       |
 5549|  58.3k|        if (composition[1] != composition[0] && previous_ccc < ccc) {
  ------------------
  |  Branch (5549:13): [True: 14.0k, False: 44.3k]
  |  Branch (5549:49): [True: 13.5k, False: 486]
  ------------------
 5550|  13.5k|          int left = composition[0];
 5551|  13.5k|          int right = composition[1];
 5552|  13.5k|          if (left < 0 || right < left ||
  ------------------
  |  Branch (5552:15): [True: 0, False: 13.5k]
  |  Branch (5552:27): [True: 0, False: 13.5k]
  ------------------
 5553|  13.5k|              static_cast<size_t>(right) > composition_data_size) {
  ------------------
  |  Branch (5553:15): [True: 0, False: 13.5k]
  ------------------
 5554|      0|            break;
 5555|      0|          }
 5556|  28.8k|          while (left + 2 < right) {
  ------------------
  |  Branch (5556:18): [True: 15.2k, False: 13.5k]
  ------------------
 5557|  15.2k|            int middle = left + (((right - left) >> 1) & ~1);
 5558|  15.2k|            if (composition_data[static_cast<size_t>(middle)] <=
  ------------------
  |  Branch (5558:17): [True: 3.05k, False: 12.2k]
  ------------------
 5559|  15.2k|                input[input_count + 1]) {
 5560|  3.05k|              left = middle;
 5561|  3.05k|            }
 5562|  15.2k|            if (composition_data[static_cast<size_t>(middle)] >=
  ------------------
  |  Branch (5562:17): [True: 13.3k, False: 1.95k]
  ------------------
 5563|  15.2k|                input[input_count + 1]) {
 5564|  13.3k|              right = middle;
 5565|  13.3k|            }
 5566|  15.2k|          }
 5567|  13.5k|          if (static_cast<size_t>(left + 1) < composition_data_size &&
  ------------------
  |  Branch (5567:15): [True: 13.5k, False: 0]
  ------------------
 5568|  13.5k|              composition_data[static_cast<size_t>(left)] ==
  ------------------
  |  Branch (5568:15): [True: 1.56k, False: 11.9k]
  ------------------
 5569|  13.5k|                  input[input_count + 1]) {
 5570|  1.56k|            char32_t composed = composition_data[static_cast<size_t>(left + 1)];
 5571|  1.56k|            input[initial_composition_count] = composed;
 5572|  1.56k|            composition =
 5573|  1.56k|                composition_block_row(composition_index[composed >> 8]) +
 5574|  1.56k|                (composed % 256);
 5575|  1.56k|            continue;
 5576|  1.56k|          }
 5577|  13.5k|        }
 5578|       |
 5579|  56.8k|        if (ccc == 0) {
  ------------------
  |  Branch (5579:13): [True: 54.7k, False: 2.07k]
  ------------------
 5580|  54.7k|          break;
 5581|  54.7k|        }
 5582|  2.07k|        previous_ccc = ccc;
 5583|  2.07k|        input[++composition_count] = input[input_count + 1];
 5584|  2.07k|      }
 5585|  55.9k|    }
 5586|  59.1k|  }
 5587|       |
 5588|  1.40k|  if (composition_count < input_count) {
  ------------------
  |  Branch (5588:7): [True: 1.25k, False: 148]
  ------------------
 5589|  1.25k|    input.resize(composition_count);
 5590|  1.25k|  }
 5591|  1.40k|}
_ZN3ada4idna9normalizeERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEE:
 5593|  1.40k|bool normalize(std::u32string& input) {
 5594|       |  /**
 5595|       |   * Normalize the characters according to IDNA (Unicode Normalization Form C).
 5596|       |   * @see https://www.unicode.org/reports/tr46/#ProcessingStepNormalize
 5597|       |   */
 5598|  1.40k|  if (!ensure_tables() || decomposition_index == nullptr ||
  ------------------
  |  Branch (5598:7): [True: 0, False: 1.40k]
  |  Branch (5598:27): [True: 0, False: 1.40k]
  ------------------
 5599|  1.40k|      composition_index == nullptr) {
  ------------------
  |  Branch (5599:7): [True: 0, False: 1.40k]
  ------------------
 5600|      0|    return false;
 5601|      0|  }
 5602|  1.40k|  if (is_already_nfc(input)) {
  ------------------
  |  Branch (5602:7): [True: 0, False: 1.40k]
  ------------------
 5603|      0|    return true;
 5604|      0|  }
 5605|  1.40k|  decompose_nfc(input);
 5606|  1.40k|  compose(input);
 5607|  1.40k|  return true;
 5608|  1.40k|}
_ZN3ada4idna17punycode_to_utf32ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEERNS1_12basic_stringIDiNS3_IDiEENS1_9allocatorIDiEEEE:
 5668|  3.06k|bool punycode_to_utf32(std::string_view input, std::u32string &out) {
 5669|  3.06k|  int32_t written_out{0};
 5670|  3.06k|  out.reserve(out.size() + input.size());
 5671|  3.06k|  uint32_t n = initial_n;
 5672|  3.06k|  int32_t i = 0;
 5673|  3.06k|  int32_t bias = initial_bias;
 5674|       |  // grab ascii content
 5675|  3.06k|  size_t end_of_ascii = input.find_last_of('-');
 5676|  3.06k|  if (end_of_ascii != std::string_view::npos) {
  ------------------
  |  Branch (5676:7): [True: 1.08k, False: 1.97k]
  ------------------
 5677|  14.8k|    for (uint8_t c : input.substr(0, end_of_ascii)) {
  ------------------
  |  Branch (5677:20): [True: 14.8k, False: 1.08k]
  ------------------
 5678|  14.8k|      if (c >= 0x80) {
  ------------------
  |  Branch (5678:11): [True: 0, False: 14.8k]
  ------------------
 5679|      0|        return false;
 5680|      0|      }
 5681|  14.8k|      out.push_back(c);
 5682|  14.8k|      written_out++;
 5683|  14.8k|    }
 5684|  1.08k|    input.remove_prefix(end_of_ascii + 1);
 5685|  1.08k|  }
 5686|  25.0k|  while (!input.empty()) {
  ------------------
  |  Branch (5686:10): [True: 22.0k, False: 2.92k]
  ------------------
 5687|  22.0k|    int32_t oldi = i;
 5688|  22.0k|    int32_t w = 1;
 5689|  35.7k|    for (int32_t k = base;; k += base) {
 5690|  35.7k|      if (input.empty()) {
  ------------------
  |  Branch (5690:11): [True: 36, False: 35.6k]
  ------------------
 5691|     36|        return false;
 5692|     36|      }
 5693|  35.6k|      uint8_t code_point = input.front();
 5694|  35.6k|      input.remove_prefix(1);
 5695|  35.6k|      int32_t digit = char_to_digit_value(code_point);
 5696|  35.6k|      if (digit < 0) {
  ------------------
  |  Branch (5696:11): [True: 42, False: 35.6k]
  ------------------
 5697|     42|        return false;
 5698|     42|      }
 5699|  35.6k|      if (digit > (0x7fffffff - i) / w) {
  ------------------
  |  Branch (5699:11): [True: 8, False: 35.6k]
  ------------------
 5700|      8|        return false;
 5701|      8|      }
 5702|  35.6k|      i = i + digit * w;
 5703|  35.6k|      int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias;
  ------------------
  |  Branch (5703:19): [True: 8.00k, False: 27.6k]
  |  Branch (5703:38): [True: 25.2k, False: 2.39k]
  ------------------
 5704|  35.6k|      if (digit < t) {
  ------------------
  |  Branch (5704:11): [True: 21.9k, False: 13.6k]
  ------------------
 5705|  21.9k|        break;
 5706|  21.9k|      }
 5707|  13.6k|      if (w > 0x7fffffff / (base - t)) {
  ------------------
  |  Branch (5707:11): [True: 0, False: 13.6k]
  ------------------
 5708|      0|        return false;
 5709|      0|      }
 5710|  13.6k|      w = w * (base - t);
 5711|  13.6k|    }
 5712|  21.9k|    bias = adapt(i - oldi, written_out + 1, oldi == 0);
 5713|  21.9k|    if (i / (written_out + 1) > int32_t(0x7fffffff - n)) {
  ------------------
  |  Branch (5713:9): [True: 56, False: 21.9k]
  ------------------
 5714|     56|      return false;
 5715|     56|    }
 5716|  21.9k|    n = n + i / (written_out + 1);
 5717|  21.9k|    i = i % (written_out + 1);
 5718|  21.9k|    if (n < 0x80) {
  ------------------
  |  Branch (5718:9): [True: 0, False: 21.9k]
  ------------------
 5719|      0|      return false;
 5720|      0|    }
 5721|  21.9k|    out.insert(out.begin() + i, n);
 5722|  21.9k|    written_out++;
 5723|  21.9k|    ++i;
 5724|  21.9k|  }
 5725|       |  // See https://github.com/whatwg/url/issues/803
 5726|       |  // Reject labels whose decoded form begins with "xn--" (double-encoded ACE).
 5727|  2.92k|  if (out.size() >= 4 && out[0] == U'x' && out[1] == U'n' && out[2] == U'-' &&
  ------------------
  |  Branch (5727:7): [True: 1.56k, False: 1.36k]
  |  Branch (5727:26): [True: 406, False: 1.15k]
  |  Branch (5727:44): [True: 230, False: 176]
  |  Branch (5727:62): [True: 124, False: 106]
  ------------------
 5728|    124|      out[3] == U'-') {
  ------------------
  |  Branch (5728:7): [True: 8, False: 116]
  ------------------
 5729|      8|    return false;
 5730|      8|  }
 5731|  2.91k|  return true;
 5732|  2.92k|}
_ZN3ada4idna17utf32_to_punycodeENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEERNS1_12basic_stringIcNS3_IcEENS1_9allocatorIcEEEE:
 5812|  24.2k|bool utf32_to_punycode(std::u32string_view input, std::string &out) {
 5813|  24.2k|  out.reserve(input.size() + out.size());
 5814|  24.2k|  uint32_t n = initial_n;
 5815|  24.2k|  int32_t d = 0;
 5816|  24.2k|  int32_t bias = initial_bias;
 5817|  24.2k|  size_t h = 0;
 5818|       |  // first push the ascii content
 5819|   210k|  for (uint32_t c : input) {
  ------------------
  |  Branch (5819:19): [True: 210k, False: 24.2k]
  ------------------
 5820|   210k|    if (c < 0x80) {
  ------------------
  |  Branch (5820:9): [True: 66.0k, False: 144k]
  ------------------
 5821|  66.0k|      ++h;
 5822|  66.0k|      out.push_back(char(c));
 5823|  66.0k|    }
 5824|   210k|    if (c > 0x10ffff || (c >= 0xd800 && c < 0xe000)) {
  ------------------
  |  Branch (5824:9): [True: 0, False: 210k]
  |  Branch (5824:26): [True: 754, False: 209k]
  |  Branch (5824:41): [True: 0, False: 754]
  ------------------
 5825|      0|      return false;
 5826|      0|    }
 5827|   210k|  }
 5828|  24.2k|  size_t b = h;
 5829|  24.2k|  if (b > 0) {
  ------------------
  |  Branch (5829:7): [True: 19.8k, False: 4.34k]
  ------------------
 5830|  19.8k|    out.push_back('-');
 5831|  19.8k|  }
 5832|  71.7k|  while (h < input.size()) {
  ------------------
  |  Branch (5832:10): [True: 47.5k, False: 24.2k]
  ------------------
 5833|  47.5k|    uint32_t m = 0x10FFFF;
 5834|  1.79M|    for (auto code_point : input) {
  ------------------
  |  Branch (5834:26): [True: 1.79M, False: 47.5k]
  ------------------
 5835|  1.79M|      if (code_point >= n && code_point < m) m = code_point;
  ------------------
  |  Branch (5835:11): [True: 691k, False: 1.10M]
  |  Branch (5835:30): [True: 52.0k, False: 639k]
  ------------------
 5836|  1.79M|    }
 5837|       |
 5838|  47.5k|    if ((m - n) > (0x7fffffff - d) / (h + 1)) {
  ------------------
  |  Branch (5838:9): [True: 0, False: 47.5k]
  ------------------
 5839|      0|      return false;
 5840|      0|    }
 5841|  47.5k|    d = d + int32_t((m - n) * (h + 1));
 5842|  47.5k|    n = m;
 5843|  1.79M|    for (auto c : input) {
  ------------------
  |  Branch (5843:17): [True: 1.79M, False: 47.5k]
  ------------------
 5844|  1.79M|      if (c < n) {
  ------------------
  |  Branch (5844:11): [True: 1.10M, False: 691k]
  ------------------
 5845|  1.10M|        if (d == 0x7fffffff) {
  ------------------
  |  Branch (5845:13): [True: 0, False: 1.10M]
  ------------------
 5846|      0|          return false;
 5847|      0|        }
 5848|  1.10M|        ++d;
 5849|  1.10M|      }
 5850|  1.79M|      if (c == n) {
  ------------------
  |  Branch (5850:11): [True: 144k, False: 1.65M]
  ------------------
 5851|   144k|        int32_t q = d;
 5852|   278k|        for (int32_t k = base;; k += base) {
 5853|   278k|          int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias;
  ------------------
  |  Branch (5853:23): [True: 51.0k, False: 227k]
  |  Branch (5853:42): [True: 206k, False: 20.4k]
  ------------------
 5854|       |
 5855|   278k|          if (q < t) {
  ------------------
  |  Branch (5855:15): [True: 144k, False: 134k]
  ------------------
 5856|   144k|            break;
 5857|   144k|          }
 5858|   134k|          out.push_back(digit_to_char(t + ((q - t) % (base - t))));
 5859|   134k|          q = (q - t) / (base - t);
 5860|   134k|        }
 5861|   144k|        out.push_back(digit_to_char(q));
 5862|   144k|        bias = adapt(d, int32_t(h + 1), h == b);
 5863|   144k|        d = 0;
 5864|   144k|        ++h;
 5865|   144k|      }
 5866|  1.79M|    }
 5867|  47.5k|    ++d;
 5868|  47.5k|    ++n;
 5869|  47.5k|  }
 5870|  24.2k|  return true;
 5871|  24.2k|}
_ZN3ada4idna14is_label_validENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5955|  27.2k|bool is_label_valid(const std::u32string_view label) {
 5956|  27.2k|  if (label.empty()) {
  ------------------
  |  Branch (5956:7): [True: 0, False: 27.2k]
  ------------------
 5957|      0|    return true;
 5958|      0|  }
 5959|  27.2k|  if (!ensure_tables() || combining_ranges == nullptr || dir_start == nullptr ||
  ------------------
  |  Branch (5959:7): [True: 0, False: 27.2k]
  |  Branch (5959:27): [True: 0, False: 27.2k]
  |  Branch (5959:58): [True: 0, False: 27.2k]
  ------------------
 5960|  27.2k|      dir_final == nullptr || dir_value == nullptr) {
  ------------------
  |  Branch (5960:7): [True: 0, False: 27.2k]
  |  Branch (5960:31): [True: 0, False: 27.2k]
  ------------------
 5961|      0|    return false;
 5962|      0|  }
 5963|       |
 5964|       |  ///////////////
 5965|       |  // We have a normalization step which ensures that we are in NFC.
 5966|       |  // If we receive punycode, we normalize and check that the normalized
 5967|       |  // version matches the original.
 5968|       |  // --------------------------------------
 5969|       |  // The label must be in Unicode Normalization Form NFC.
 5970|       |
 5971|       |  // Current URL standard indicatest that CheckHyphens is set to false.
 5972|       |  // ---------------------------------------
 5973|       |  // If CheckHyphens, the label must not contain a U+002D HYPHEN-MINUS character
 5974|       |  // in both the third and fourth positions. If CheckHyphens, the label must
 5975|       |  // neither begin nor end with a U+002D HYPHEN-MINUS character.
 5976|       |
 5977|       |  // This is not necessary because we segment the
 5978|       |  // labels by '.'.
 5979|       |  // ---------------------------------------
 5980|       |  // The label must not contain a U+002E ( . ) FULL STOP.
 5981|       |  // if (label.find('.') != std::string_view::npos) return false;
 5982|       |
 5983|       |  // The label must not begin with a combining mark.
 5984|       |  // Range membership via lower_bound on range end.
 5985|  27.2k|  const std::span<const uint32_t[2]> comb_span{combining_ranges,
 5986|  27.2k|                                               combining_range_count};
 5987|  27.2k|  const auto comb_it = std::ranges::lower_bound(
 5988|  27.2k|      comb_span, label.front(), {}, [](const auto& range) { return range[1]; });
 5989|  27.2k|  if (comb_it != comb_span.end() && label.front() >= (*comb_it)[0]) {
  ------------------
  |  Branch (5989:7): [True: 27.2k, False: 0]
  |  Branch (5989:7): [True: 108, False: 27.1k]
  |  Branch (5989:37): [True: 108, False: 27.1k]
  ------------------
 5990|    108|    return false;
 5991|    108|  }
 5992|       |  // We verify this next step as part of the mapping:
 5993|       |  // ---------------------------------------------
 5994|       |  // Each code point in the label must only have certain status values
 5995|       |  // according to Section 5, IDNA Mapping Table:
 5996|       |  // - For Transitional Processing, each value must be valid.
 5997|       |  // - For Nontransitional Processing, each value must be either valid or
 5998|       |  // deviation.
 5999|       |
 6000|       |  // If CheckJoiners, the label must satisfy the ContextJ rules from Appendix
 6001|       |  // A, in The Unicode Code Points and Internationalized Domain Names for
 6002|       |  // Applications (IDNA) [IDNA2008].
 6003|  27.1k|  constexpr static uint32_t virama[] = {
 6004|  27.1k|      0x094D,  0x09CD,  0x0A4D,  0x0ACD,  0x0B4D,  0x0BCD,  0x0C4D,  0x0CCD,
 6005|  27.1k|      0x0D3B,  0x0D3C,  0x0D4D,  0x0DCA,  0x0E3A,  0x0EBA,  0x0F84,  0x1039,
 6006|  27.1k|      0x103A,  0x1714,  0x1734,  0x17D2,  0x1A60,  0x1B44,  0x1BAA,  0x1BAB,
 6007|  27.1k|      0x1BF2,  0x1BF3,  0x2D7F,  0xA806,  0xA82C,  0xA8C4,  0xA953,  0xA9C0,
 6008|  27.1k|      0xAAF6,  0xABED,  0x10A3F, 0x11046, 0x1107F, 0x110B9, 0x11133, 0x11134,
 6009|  27.1k|      0x111C0, 0x11235, 0x112EA, 0x1134D, 0x11442, 0x114C2, 0x115BF, 0x1163F,
 6010|  27.1k|      0x116B6, 0x1172B, 0x11839, 0x1193D, 0x1193E, 0x119E0, 0x11A34, 0x11A47,
 6011|  27.1k|      0x11A99, 0x11C3F, 0x11D44, 0x11D45, 0x11D97};
 6012|  27.1k|  constexpr static uint32_t R[] = {
 6013|  27.1k|      0x622, 0x623, 0x624, 0x625, 0x627, 0x629, 0x62f, 0x630, 0x631,
 6014|  27.1k|      0x632, 0x648, 0x671, 0x672, 0x673, 0x675, 0x676, 0x677, 0x688,
 6015|  27.1k|      0x689, 0x68a, 0x68b, 0x68c, 0x68d, 0x68e, 0x68f, 0x690, 0x691,
 6016|  27.1k|      0x692, 0x693, 0x694, 0x695, 0x696, 0x697, 0x698, 0x699, 0x6c0,
 6017|  27.1k|      0x6c3, 0x6c4, 0x6c5, 0x6c6, 0x6c7, 0x6c8, 0x6c9, 0x6ca, 0x6cb,
 6018|  27.1k|      0x6cd, 0x6cf, 0x6d2, 0x6d3, 0x6d5, 0x6ee, 0x6ef, 0x710, 0x715,
 6019|  27.1k|      0x716, 0x717, 0x718, 0x719, 0x71e, 0x728, 0x72a, 0x72c, 0x72f,
 6020|  27.1k|      0x74d, 0x759, 0x75a, 0x75b, 0x854, 0x8aa, 0x8ab, 0x8ac};
 6021|  27.1k|  constexpr static uint32_t L[] = {0xa872};
 6022|  27.1k|  constexpr static uint32_t D[] = {
 6023|  27.1k|      0x620,  0x626,  0x628,  0x62a,  0x62b,  0x62c,  0x62d,  0x62e,  0x633,
 6024|  27.1k|      0x634,  0x635,  0x636,  0x637,  0x638,  0x639,  0x63a,  0x63b,  0x63c,
 6025|  27.1k|      0x63d,  0x63e,  0x63f,  0x641,  0x642,  0x643,  0x644,  0x645,  0x646,
 6026|  27.1k|      0x647,  0x649,  0x64a,  0x66e,  0x66f,  0x678,  0x679,  0x67a,  0x67b,
 6027|  27.1k|      0x67c,  0x67d,  0x67e,  0x67f,  0x680,  0x681,  0x682,  0x683,  0x684,
 6028|  27.1k|      0x685,  0x686,  0x687,  0x69a,  0x69b,  0x69c,  0x69d,  0x69e,  0x69f,
 6029|  27.1k|      0x6a0,  0x6a1,  0x6a2,  0x6a3,  0x6a4,  0x6a5,  0x6a6,  0x6a7,  0x6a8,
 6030|  27.1k|      0x6a9,  0x6aa,  0x6ab,  0x6ac,  0x6ad,  0x6ae,  0x6af,  0x6b0,  0x6b1,
 6031|  27.1k|      0x6b2,  0x6b3,  0x6b4,  0x6b5,  0x6b6,  0x6b7,  0x6b8,  0x6b9,  0x6ba,
 6032|  27.1k|      0x6bb,  0x6bc,  0x6bd,  0x6be,  0x6bf,  0x6c1,  0x6c2,  0x6cc,  0x6ce,
 6033|  27.1k|      0x6d0,  0x6d1,  0x6fa,  0x6fb,  0x6fc,  0x6ff,  0x712,  0x713,  0x714,
 6034|  27.1k|      0x71a,  0x71b,  0x71c,  0x71d,  0x71f,  0x720,  0x721,  0x722,  0x723,
 6035|  27.1k|      0x724,  0x725,  0x726,  0x727,  0x729,  0x72b,  0x72d,  0x72e,  0x74e,
 6036|  27.1k|      0x74f,  0x750,  0x751,  0x752,  0x753,  0x754,  0x755,  0x756,  0x757,
 6037|  27.1k|      0x758,  0x75c,  0x75d,  0x75e,  0x75f,  0x760,  0x761,  0x762,  0x763,
 6038|  27.1k|      0x764,  0x765,  0x766,  0x850,  0x851,  0x852,  0x853,  0x855,  0x8a0,
 6039|  27.1k|      0x8a2,  0x8a3,  0x8a4,  0x8a5,  0x8a6,  0x8a7,  0x8a8,  0x8a9,  0x1807,
 6040|  27.1k|      0x1820, 0x1821, 0x1822, 0x1823, 0x1824, 0x1825, 0x1826, 0x1827, 0x1828,
 6041|  27.1k|      0x1829, 0x182a, 0x182b, 0x182c, 0x182d, 0x182e, 0x182f, 0x1830, 0x1831,
 6042|  27.1k|      0x1832, 0x1833, 0x1834, 0x1835, 0x1836, 0x1837, 0x1838, 0x1839, 0x183a,
 6043|  27.1k|      0x183b, 0x183c, 0x183d, 0x183e, 0x183f, 0x1840, 0x1841, 0x1842, 0x1843,
 6044|  27.1k|      0x1844, 0x1845, 0x1846, 0x1847, 0x1848, 0x1849, 0x184a, 0x184b, 0x184c,
 6045|  27.1k|      0x184d, 0x184e, 0x184f, 0x1850, 0x1851, 0x1852, 0x1853, 0x1854, 0x1855,
 6046|  27.1k|      0x1856, 0x1857, 0x1858, 0x1859, 0x185a, 0x185b, 0x185c, 0x185d, 0x185e,
 6047|  27.1k|      0x185f, 0x1860, 0x1861, 0x1862, 0x1863, 0x1864, 0x1865, 0x1866, 0x1867,
 6048|  27.1k|      0x1868, 0x1869, 0x186a, 0x186b, 0x186c, 0x186d, 0x186e, 0x186f, 0x1870,
 6049|  27.1k|      0x1871, 0x1872, 0x1873, 0x1874, 0x1875, 0x1876, 0x1877, 0x1887, 0x1888,
 6050|  27.1k|      0x1889, 0x188a, 0x188b, 0x188c, 0x188d, 0x188e, 0x188f, 0x1890, 0x1891,
 6051|  27.1k|      0x1892, 0x1893, 0x1894, 0x1895, 0x1896, 0x1897, 0x1898, 0x1899, 0x189a,
 6052|  27.1k|      0x189b, 0x189c, 0x189d, 0x189e, 0x189f, 0x18a0, 0x18a1, 0x18a2, 0x18a3,
 6053|  27.1k|      0x18a4, 0x18a5, 0x18a6, 0x18a7, 0x18a8, 0x18aa, 0xa840, 0xa841, 0xa842,
 6054|  27.1k|      0xa843, 0xa844, 0xa845, 0xa846, 0xa847, 0xa848, 0xa849, 0xa84a, 0xa84b,
 6055|  27.1k|      0xa84c, 0xa84d, 0xa84e, 0xa84f, 0xa850, 0xa851, 0xa852, 0xa853, 0xa854,
 6056|  27.1k|      0xa855, 0xa856, 0xa857, 0xa858, 0xa859, 0xa85a, 0xa85b, 0xa85c, 0xa85d,
 6057|  27.1k|      0xa85e, 0xa85f, 0xa860, 0xa861, 0xa862, 0xa863, 0xa864, 0xa865, 0xa866,
 6058|  27.1k|      0xa867, 0xa868, 0xa869, 0xa86a, 0xa86b, 0xa86c, 0xa86d, 0xa86e, 0xa86f,
 6059|  27.1k|      0xa870, 0xa871};
 6060|       |
 6061|   202k|  for (size_t i = 0; i < label.size(); i++) {
  ------------------
  |  Branch (6061:22): [True: 177k, False: 25.5k]
  ------------------
 6062|   177k|    uint32_t c = label[i];
 6063|   177k|    if (c == 0x200c) {
  ------------------
  |  Branch (6063:9): [True: 1.22k, False: 175k]
  ------------------
 6064|  1.22k|      if (i > 0) {
  ------------------
  |  Branch (6064:11): [True: 1.21k, False: 6]
  ------------------
 6065|  1.21k|        if (std::ranges::binary_search(virama, label[i - 1])) {
  ------------------
  |  Branch (6065:13): [True: 192, False: 1.02k]
  ------------------
 6066|    192|          return true;
 6067|    192|        }
 6068|  1.21k|      }
 6069|  1.03k|      if ((i == 0) || (i + 1 >= label.size())) {
  ------------------
  |  Branch (6069:11): [True: 6, False: 1.02k]
  |  Branch (6069:23): [True: 72, False: 954]
  ------------------
 6070|     78|        return false;
 6071|     78|      }
 6072|       |      // we go backward looking for L or D
 6073|    954|      auto is_l_or_d = [](uint32_t code) {
 6074|    954|        return std::ranges::binary_search(L, code) ||
 6075|    954|               std::ranges::binary_search(D, code);
 6076|    954|      };
 6077|    954|      auto is_r_or_d = [](uint32_t code) {
 6078|    954|        return std::ranges::binary_search(R, code) ||
 6079|    954|               std::ranges::binary_search(D, code);
 6080|    954|      };
 6081|    954|      std::u32string_view before = label.substr(0, i);
 6082|    954|      std::u32string_view after = label.substr(i + 1);
 6083|    954|      return (std::find_if(before.begin(), before.end(), is_l_or_d) !=
  ------------------
  |  Branch (6083:14): [True: 886, False: 68]
  ------------------
 6084|    954|              before.end()) &&
 6085|    886|             (std::find_if(after.begin(), after.end(), is_r_or_d) !=
  ------------------
  |  Branch (6085:14): [True: 774, False: 112]
  ------------------
 6086|    886|              after.end());
 6087|   175k|    } else if (c == 0x200d) {
  ------------------
  |  Branch (6087:16): [True: 376, False: 175k]
  ------------------
 6088|    376|      if (i > 0) {
  ------------------
  |  Branch (6088:11): [True: 370, False: 6]
  ------------------
 6089|    370|        if (std::ranges::binary_search(virama, label[i - 1])) {
  ------------------
  |  Branch (6089:13): [True: 316, False: 54]
  ------------------
 6090|    316|          return true;
 6091|    316|        }
 6092|    370|      }
 6093|     60|      return false;
 6094|    376|    }
 6095|   177k|  }
 6096|       |
 6097|       |  // If CheckBidi, and if the domain name is a  Bidi domain name, then the label
 6098|       |  // must satisfy all six of the numbered conditions in [IDNA2008] RFC 5893,
 6099|       |  // Section 2.
 6100|       |
 6101|       |  // The following rule, consisting of six conditions, applies to labels
 6102|       |  // in Bidi domain names.  The requirements that this rule satisfies are
 6103|       |  // described in Section 3.  All of the conditions must be satisfied for
 6104|       |  // the rule to be satisfied.
 6105|       |  //
 6106|       |  //  1.  The first character must be a character with Bidi property L, R,
 6107|       |  //     or AL.  If it has the R or AL property, it is an RTL label; if it
 6108|       |  //     has the L property, it is an LTR label.
 6109|       |  //
 6110|       |  //  2.  In an RTL label, only characters with the Bidi properties R, AL,
 6111|       |  //      AN, EN, ES, CS, ET, ON, BN, or NSM are allowed.
 6112|       |  //
 6113|       |  //   3.  In an RTL label, the end of the label must be a character with
 6114|       |  //       Bidi property R, AL, EN, or AN, followed by zero or more
 6115|       |  //       characters with Bidi property NSM.
 6116|       |  //
 6117|       |  //   4.  In an RTL label, if an EN is present, no AN may be present, and
 6118|       |  //       vice versa.
 6119|       |  //
 6120|       |  //  5.  In an LTR label, only characters with the Bidi properties L, EN,
 6121|       |  //       ES, CS, ET, ON, BN, or NSM are allowed.
 6122|       |  //
 6123|       |  //   6.  In an LTR label, the end of the label must be a character with
 6124|       |  //       Bidi property L or EN, followed by zero or more characters with
 6125|       |  //       Bidi property NSM.
 6126|       |
 6127|  25.5k|  size_t last_non_nsm_char = find_last_not_of_nsm(label);
 6128|  25.5k|  if (last_non_nsm_char == std::u32string_view::npos) {
  ------------------
  |  Branch (6128:7): [True: 0, False: 25.5k]
  ------------------
 6129|      0|    return false;
 6130|      0|  }
 6131|       |
 6132|       |  // A "Bidi domain name" is a domain name that contains at least one RTL label.
 6133|       |  // The following rule, consisting of six conditions, applies to labels in Bidi
 6134|       |  // domain names.
 6135|  25.5k|  if (is_rtl_label(label)) {
  ------------------
  |  Branch (6135:7): [True: 1.91k, False: 23.6k]
  ------------------
 6136|       |    // The first character must be a character with Bidi property L, R,
 6137|       |    // or AL. If it has the R or AL property, it is an RTL label; if it
 6138|       |    // has the L property, it is an LTR label.
 6139|       |
 6140|  1.91k|    if (find_direction(label[0]) == direction::L) {
  ------------------
  |  Branch (6140:9): [True: 212, False: 1.70k]
  ------------------
 6141|       |      // Eval as LTR
 6142|       |
 6143|       |      // In an LTR label, only characters with the Bidi properties L, EN,
 6144|       |      // ES, CS, ET, ON, BN, or NSM are allowed.
 6145|  2.60k|      for (size_t i = 0; i <= last_non_nsm_char; i++) {
  ------------------
  |  Branch (6145:26): [True: 2.60k, False: 0]
  ------------------
 6146|  2.60k|        const direction d = find_direction(label[i]);
 6147|  2.60k|        if (!(d == direction::L || d == direction::EN || d == direction::ES ||
  ------------------
  |  Branch (6147:15): [True: 692, False: 1.91k]
  |  Branch (6147:36): [True: 218, False: 1.69k]
  |  Branch (6147:58): [True: 192, False: 1.50k]
  ------------------
 6148|  1.50k|              d == direction::CS || d == direction::ET || d == direction::ON ||
  ------------------
  |  Branch (6148:15): [True: 204, False: 1.30k]
  |  Branch (6148:37): [True: 206, False: 1.09k]
  |  Branch (6148:59): [True: 214, False: 880]
  ------------------
 6149|    880|              d == direction::BN || d == direction::NSM)) {
  ------------------
  |  Branch (6149:15): [True: 464, False: 416]
  |  Branch (6149:37): [True: 204, False: 212]
  ------------------
 6150|    212|          return false;
 6151|    212|        }
 6152|  2.60k|      }
 6153|       |
 6154|      0|      const direction last_dir = find_direction(label[last_non_nsm_char]);
 6155|      0|      if (!(last_dir == direction::L || last_dir == direction::EN)) {
  ------------------
  |  Branch (6155:13): [True: 0, False: 0]
  |  Branch (6155:41): [True: 0, False: 0]
  ------------------
 6156|      0|        return false;
 6157|      0|      }
 6158|       |
 6159|      0|      return true;
 6160|       |
 6161|  1.70k|    } else {
 6162|       |      // Eval as RTL
 6163|       |
 6164|       |      // The first character must be R or AL; a leading AN (or any other
 6165|       |      // direction) does not start a valid RTL label.
 6166|  1.70k|      const direction first_dir = find_direction(label[0]);
 6167|  1.70k|      if (first_dir != direction::R && first_dir != direction::AL) {
  ------------------
  |  Branch (6167:11): [True: 900, False: 806]
  |  Branch (6167:40): [True: 42, False: 858]
  ------------------
 6168|     42|        return false;
 6169|     42|      }
 6170|       |
 6171|  1.66k|      bool has_an = false;
 6172|  1.66k|      bool has_en = false;
 6173|  6.16k|      for (size_t i = 0; i <= last_non_nsm_char; i++) {
  ------------------
  |  Branch (6173:26): [True: 4.65k, False: 1.50k]
  ------------------
 6174|  4.65k|        const direction d = find_direction(label[i]);
 6175|       |
 6176|       |        // In an RTL label, if an EN is present, no AN may be present, and vice
 6177|       |        // versa.
 6178|  4.65k|        if ((d == direction::EN && ((has_en = true) && has_an)) ||
  ------------------
  |  Branch (6178:14): [True: 566, False: 4.08k]
  |  Branch (6178:37): [True: 566, False: 0]
  |  Branch (6178:56): [True: 6, False: 560]
  ------------------
 6179|  4.64k|            (d == direction::AN && ((has_an = true) && has_en))) {
  ------------------
  |  Branch (6179:14): [True: 394, False: 4.25k]
  |  Branch (6179:37): [True: 394, False: 0]
  |  Branch (6179:56): [True: 6, False: 388]
  ------------------
 6180|     12|          return false;
 6181|     12|        }
 6182|       |
 6183|  4.64k|        if (!(d == direction::R || d == direction::AL || d == direction::AN ||
  ------------------
  |  Branch (6183:15): [True: 1.03k, False: 3.60k]
  |  Branch (6183:36): [True: 1.22k, False: 2.38k]
  |  Branch (6183:58): [True: 388, False: 1.99k]
  ------------------
 6184|  1.99k|              d == direction::EN || d == direction::ES || d == direction::CS ||
  ------------------
  |  Branch (6184:15): [True: 560, False: 1.43k]
  |  Branch (6184:37): [True: 192, False: 1.24k]
  |  Branch (6184:59): [True: 244, False: 996]
  ------------------
 6185|    996|              d == direction::ET || d == direction::ON || d == direction::BN ||
  ------------------
  |  Branch (6185:15): [True: 194, False: 802]
  |  Branch (6185:37): [True: 216, False: 586]
  |  Branch (6185:59): [True: 322, False: 264]
  ------------------
 6186|    264|              d == direction::NSM)) {
  ------------------
  |  Branch (6186:15): [True: 192, False: 72]
  ------------------
 6187|     72|          return false;
 6188|     72|        }
 6189|       |
 6190|  4.57k|        if (i == last_non_nsm_char &&
  ------------------
  |  Branch (6190:13): [True: 1.58k, False: 2.99k]
  ------------------
 6191|  1.58k|            !(d == direction::R || d == direction::AL || d == direction::AN ||
  ------------------
  |  Branch (6191:15): [True: 400, False: 1.18k]
  |  Branch (6191:36): [True: 696, False: 484]
  |  Branch (6191:58): [True: 200, False: 284]
  ------------------
 6192|    284|              d == direction::EN)) {
  ------------------
  |  Branch (6192:15): [True: 210, False: 74]
  ------------------
 6193|     74|          return false;
 6194|     74|        }
 6195|  4.57k|      }
 6196|       |
 6197|  1.50k|      return true;
 6198|  1.66k|    }
 6199|  1.91k|  }
 6200|       |
 6201|  23.6k|  return true;
 6202|  25.5k|}
_ZN3ada4idna8to_asciiENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEERNS1_12basic_stringIcS4_NS1_9allocatorIcEEEE:
 6359|   124k|[[nodiscard]] bool to_ascii(std::string_view ut8_string, std::string& out) {
 6360|   124k|  out.clear();
 6361|   124k|  if (ut8_string.size() > max_domain_input_bytes) {
  ------------------
  |  Branch (6361:7): [True: 0, False: 124k]
  ------------------
 6362|      0|    return false;
 6363|      0|  }
 6364|   124k|  if (is_ascii(ut8_string)) {
  ------------------
  |  Branch (6364:7): [True: 119k, False: 5.38k]
  ------------------
 6365|   119k|    from_ascii_to_ascii(ut8_string, out);
 6366|   119k|    return true;
 6367|   119k|  }
 6368|       |
 6369|       |#ifdef ADA_USE_SIMDUTF
 6370|       |  size_t utf32_length =
 6371|       |      simdutf::utf32_length_from_utf8(ut8_string.data(), ut8_string.size());
 6372|       |  if (utf32_length == 0 && !ut8_string.empty()) {
 6373|       |    return false;
 6374|       |  }
 6375|       |  std::u32string working(utf32_length, U'\0');
 6376|       |  size_t actual_utf32_length = simdutf::convert_utf8_to_utf32(
 6377|       |      ut8_string.data(), ut8_string.size(), working.data());
 6378|       |#else
 6379|  5.38k|  size_t utf32_length =
 6380|  5.38k|      ada::idna::utf32_length_from_utf8(ut8_string.data(), ut8_string.size());
 6381|  5.38k|  if (utf32_length == 0 && !ut8_string.empty()) {
  ------------------
  |  Branch (6381:7): [True: 44, False: 5.34k]
  |  Branch (6381:28): [True: 44, False: 0]
  ------------------
 6382|     44|    return false;
 6383|     44|  }
 6384|  5.34k|  std::u32string working(utf32_length, U'\0');
 6385|  5.34k|  size_t actual_utf32_length = ada::idna::utf8_to_utf32(
 6386|  5.34k|      ut8_string.data(), ut8_string.size(), working.data());
 6387|  5.34k|#endif
 6388|  5.34k|  if (actual_utf32_length == 0 || actual_utf32_length != utf32_length) {
  ------------------
  |  Branch (6388:7): [True: 480, False: 4.86k]
  |  Branch (6388:35): [True: 0, False: 4.86k]
  ------------------
 6389|    480|    return false;
 6390|    480|  }
 6391|  4.86k|  working.resize(actual_utf32_length);
 6392|       |
 6393|       |  // Map into a second buffer with exact sizing (no growth reallocs).
 6394|  4.86k|  std::u32string mapped;
 6395|  4.86k|  if (!ada::idna::map(working, mapped)) {
  ------------------
  |  Branch (6395:7): [True: 66, False: 4.79k]
  ------------------
 6396|     66|    return false;
 6397|     66|  }
 6398|       |  // Drop UTF-32 input; reuse `working` as scratch for ACE validation below.
 6399|  4.79k|  working.clear();
 6400|       |
 6401|       |  // Skip NFC when already normalized (ASCII is a fast subset of this check).
 6402|  4.79k|  if (!is_ascii(mapped) && !is_already_nfc(mapped)) {
  ------------------
  |  Branch (6402:7): [True: 4.16k, False: 628]
  |  Branch (6402:28): [True: 744, False: 3.42k]
  ------------------
 6403|    744|    if (!normalize(mapped)) {
  ------------------
  |  Branch (6403:9): [True: 0, False: 744]
  ------------------
 6404|      0|      return false;
 6405|      0|    }
 6406|    744|  }
 6407|       |
 6408|       |  // Estimate ASCII output size (punycode may expand non-ASCII labels).
 6409|  4.79k|  out.reserve(mapped.size() + 8);
 6410|       |
 6411|       |  // Walk labels with a single pointer scan (no repeated string::find).
 6412|  4.79k|  const char32_t* p = mapped.data();
 6413|  4.79k|  const char32_t* const end = p + mapped.size();
 6414|  4.79k|  std::u32string post_map;
 6415|       |
 6416|  33.9k|  while (p < end) {
  ------------------
  |  Branch (6416:10): [True: 30.8k, False: 3.07k]
  ------------------
 6417|  30.8k|    const char32_t* label_begin = p;
 6418|   362k|    while (p < end && *p != U'.') {
  ------------------
  |  Branch (6418:12): [True: 358k, False: 4.12k]
  |  Branch (6418:23): [True: 331k, False: 26.7k]
  ------------------
 6419|   331k|      ++p;
 6420|   331k|    }
 6421|  30.8k|    const size_t label_size = static_cast<size_t>(p - label_begin);
 6422|  30.8k|    std::u32string_view label_view(label_begin, label_size);
 6423|  30.8k|    const bool is_last_label = (p == end);
 6424|  30.8k|    if (p < end) {
  ------------------
  |  Branch (6424:9): [True: 26.7k, False: 4.12k]
  ------------------
 6425|  26.7k|      ++p;  // skip dot
 6426|  26.7k|    }
 6427|       |
 6428|  30.8k|    if (label_size == 0) {
  ------------------
  |  Branch (6428:9): [True: 656, False: 30.2k]
  ------------------
 6429|       |      // empty label
 6430|  30.2k|    } else if (is_ace_prefix(label_view)) {
  ------------------
  |  Branch (6430:16): [True: 3.09k, False: 27.1k]
  ------------------
 6431|  65.0k|      for (char32_t c : label_view) {
  ------------------
  |  Branch (6431:23): [True: 65.0k, False: 3.06k]
  ------------------
 6432|  65.0k|        if (c >= 0x80) {
  ------------------
  |  Branch (6432:13): [True: 32, False: 64.9k]
  ------------------
 6433|     32|          out.clear();
 6434|     32|          return false;
 6435|     32|        }
 6436|  65.0k|      }
 6437|  3.06k|      append_ascii_label(out, label_view);
 6438|  3.06k|      std::string_view puny_segment_ascii(
 6439|  3.06k|          out.data() + (out.size() - label_size) + 4, label_size - 4);
 6440|  3.06k|      working.clear();
 6441|  3.06k|      if (!ada::idna::punycode_to_utf32(puny_segment_ascii, working)) {
  ------------------
  |  Branch (6441:11): [True: 150, False: 2.91k]
  ------------------
 6442|    150|        out.clear();
 6443|    150|        return false;
 6444|    150|      }
 6445|  2.91k|      if (is_ascii(working)) {
  ------------------
  |  Branch (6445:11): [True: 94, False: 2.82k]
  ------------------
 6446|     94|        out.clear();
 6447|     94|        return false;
 6448|     94|      }
 6449|  2.82k|      if (!ada::idna::map(working, post_map) || working != post_map) {
  ------------------
  |  Branch (6449:11): [True: 322, False: 2.49k]
  |  Branch (6449:49): [True: 120, False: 2.37k]
  ------------------
 6450|    442|        out.clear();
 6451|    442|        return false;
 6452|    442|      }
 6453|       |      // Mapping must be stable; NFC must not change the mapped form either.
 6454|  2.37k|      if (!is_ascii(post_map) && !is_already_nfc(post_map)) {
  ------------------
  |  Branch (6454:11): [True: 2.37k, False: 0]
  |  Branch (6454:34): [True: 658, False: 1.72k]
  ------------------
 6455|    658|        if (!normalize(post_map) || post_map != working) {
  ------------------
  |  Branch (6455:13): [True: 0, False: 658]
  |  Branch (6455:37): [True: 164, False: 494]
  ------------------
 6456|    164|          out.clear();
 6457|    164|          return false;
 6458|    164|        }
 6459|    658|      }
 6460|  2.21k|      if (post_map.empty() || !is_label_valid(post_map)) {
  ------------------
  |  Branch (6460:11): [True: 0, False: 2.21k]
  |  Branch (6460:31): [True: 32, False: 2.18k]
  ------------------
 6461|     32|        out.clear();
 6462|     32|        return false;
 6463|     32|      }
 6464|  27.1k|    } else if (is_ascii(label_view)) {
  ------------------
  |  Branch (6464:16): [True: 2.09k, False: 25.0k]
  ------------------
 6465|  2.09k|      append_ascii_label(out, label_view);
 6466|  25.0k|    } else {
 6467|  25.0k|      if (!is_label_valid(label_view)) {
  ------------------
  |  Branch (6467:11): [True: 806, False: 24.2k]
  ------------------
 6468|    806|        out.clear();
 6469|    806|        return false;
 6470|    806|      }
 6471|  24.2k|      out.append("xn--");
 6472|  24.2k|      if (!ada::idna::utf32_to_punycode(label_view, out)) {
  ------------------
  |  Branch (6472:11): [True: 0, False: 24.2k]
  ------------------
 6473|      0|        out.clear();
 6474|      0|        return false;
 6475|      0|      }
 6476|  24.2k|    }
 6477|  29.1k|    if (!is_last_label) {
  ------------------
  |  Branch (6477:9): [True: 26.2k, False: 2.89k]
  ------------------
 6478|  26.2k|      out.push_back('.');
 6479|  26.2k|    }
 6480|  29.1k|  }
 6481|  3.07k|  return true;
 6482|  4.79k|}
_ZN3ada4idna8to_asciiENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6484|   124k|std::string to_ascii(std::string_view ut8_string) {
 6485|   124k|  std::string out;
 6486|   124k|  if (!to_ascii(ut8_string, out)) {
  ------------------
  |  Branch (6486:7): [True: 2.31k, False: 122k]
  ------------------
 6487|  2.31k|    return {};
 6488|  2.31k|  }
 6489|   122k|  return out;
 6490|   124k|}
_ZN3ada7unicode14percent_encodeILb1EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKhRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEE:
 7349|  24.1k|                    std::string& out) {
 7350|  24.1k|  ada_log("percent_encode ", input, " to output string while ",
 7351|  24.1k|          append ? "appending" : "overwriting");
 7352|  24.1k|  auto pointer = std::ranges::find_if(input, [character_set](const char c) {
 7353|  24.1k|    return character_sets::bit_at(character_set, c);
 7354|  24.1k|  });
 7355|  24.1k|  ada_log("percent_encode done checking, moved to ",
 7356|  24.1k|          std::distance(input.begin(), pointer));
 7357|       |
 7358|       |  // Optimization: Don't iterate if percent encode is not required
 7359|  24.1k|  if (pointer == input.end()) {
  ------------------
  |  Branch (7359:7): [True: 23.5k, False: 588]
  ------------------
 7360|  23.5k|    ada_log("percent_encode encoding not needed.");
 7361|  23.5k|    return false;
 7362|  23.5k|  }
 7363|       |  if constexpr (!append) {
 7364|       |    out.clear();
 7365|       |  }
 7366|    588|  ada_log("percent_encode appending ", std::distance(input.begin(), pointer),
 7367|    588|          " bytes");
 7368|       |  // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage)
 7369|    588|  out.append(input.data(), std::distance(input.begin(), pointer));
 7370|    588|  ada_log("percent_encode processing ", std::distance(pointer, input.end()),
 7371|    588|          " bytes");
 7372|  36.3k|  for (; pointer != input.end(); pointer++) {
  ------------------
  |  Branch (7372:10): [True: 35.8k, False: 588]
  ------------------
 7373|  35.8k|    if (character_sets::bit_at(character_set, *pointer)) {
  ------------------
  |  Branch (7373:9): [True: 22.7k, False: 13.0k]
  ------------------
 7374|  22.7k|      out.append(character_sets::hex + uint8_t(*pointer) * 4, 3);
 7375|  22.7k|    } else {
 7376|  13.0k|      out += *pointer;
 7377|  13.0k|    }
 7378|  35.8k|  }
 7379|    588|  return true;
 7380|  24.1k|}
_ZN3ada7unicode14percent_encodeILb0EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKhRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEE:
 7349|  26.4k|                    std::string& out) {
 7350|  26.4k|  ada_log("percent_encode ", input, " to output string while ",
 7351|  26.4k|          append ? "appending" : "overwriting");
 7352|  26.4k|  auto pointer = std::ranges::find_if(input, [character_set](const char c) {
 7353|  26.4k|    return character_sets::bit_at(character_set, c);
 7354|  26.4k|  });
 7355|  26.4k|  ada_log("percent_encode done checking, moved to ",
 7356|  26.4k|          std::distance(input.begin(), pointer));
 7357|       |
 7358|       |  // Optimization: Don't iterate if percent encode is not required
 7359|  26.4k|  if (pointer == input.end()) {
  ------------------
  |  Branch (7359:7): [True: 17.3k, False: 9.12k]
  ------------------
 7360|  17.3k|    ada_log("percent_encode encoding not needed.");
 7361|  17.3k|    return false;
 7362|  17.3k|  }
 7363|  9.12k|  if constexpr (!append) {
 7364|  9.12k|    out.clear();
 7365|  9.12k|  }
 7366|  9.12k|  ada_log("percent_encode appending ", std::distance(input.begin(), pointer),
 7367|  9.12k|          " bytes");
 7368|       |  // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage)
 7369|  9.12k|  out.append(input.data(), std::distance(input.begin(), pointer));
 7370|  9.12k|  ada_log("percent_encode processing ", std::distance(pointer, input.end()),
 7371|  9.12k|          " bytes");
 7372|   100k|  for (; pointer != input.end(); pointer++) {
  ------------------
  |  Branch (7372:10): [True: 90.9k, False: 9.12k]
  ------------------
 7373|  90.9k|    if (character_sets::bit_at(character_set, *pointer)) {
  ------------------
  |  Branch (7373:9): [True: 75.6k, False: 15.2k]
  ------------------
 7374|  75.6k|      out.append(character_sets::hex + uint8_t(*pointer) * 4, 3);
 7375|  75.6k|    } else {
 7376|  15.2k|      out += *pointer;
 7377|  15.2k|    }
 7378|  90.9k|  }
 7379|  9.12k|  return true;
 7380|  26.4k|}
_ZN3ada7unicode14percent_decodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEm:
 7180|  38.8k|std::string percent_decode(const std::string_view input, size_t first_percent) {
 7181|       |  // next line is for safety only, we expect users to avoid calling
 7182|       |  // percent_decode when first_percent is outside the range.
 7183|  38.8k|  if (first_percent == std::string_view::npos) {
  ------------------
  |  Branch (7183:7): [True: 0, False: 38.8k]
  ------------------
 7184|      0|    return std::string(input);
 7185|      0|  }
 7186|       |
 7187|       |  // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage)
 7188|  38.8k|  const char* const src = input.data();
 7189|  38.8k|  const char* const end = src + input.size();
 7190|       |
 7191|       |  // Decoding never grows the string, so a single pre-sized buffer written via
 7192|       |  // bulk memcpy of the plain runs (then shrunk to the final length) avoids the
 7193|       |  // byte-at-a-time appends of the naive version.
 7194|  38.8k|  std::string out(input.size(), '\0');
 7195|  38.8k|  char* d = out.data();
 7196|  38.8k|  char* const d0 = d;
 7197|       |
 7198|  38.8k|  std::memcpy(d, src, first_percent);
 7199|  38.8k|  d += first_percent;
 7200|       |
 7201|  38.8k|  const char* p = src + first_percent;
 7202|   122k|  while (p < end) {
  ------------------
  |  Branch (7202:10): [True: 83.9k, False: 38.8k]
  ------------------
 7203|  83.9k|    if (*p == '%') {
  ------------------
  |  Branch (7203:9): [True: 43.5k, False: 40.4k]
  ------------------
 7204|       |      // Decode runs of valid %XX tightly (common for nested/encoded URLs).
 7205|  85.4k|      while (p + 2 < end && *p == '%') {
  ------------------
  |  Branch (7205:14): [True: 84.1k, False: 1.36k]
  |  Branch (7205:29): [True: 45.6k, False: 38.4k]
  ------------------
 7206|  45.6k|        if (!is_ascii_hex_digit(p[1]) || !is_ascii_hex_digit(p[2])) {
  ------------------
  |  Branch (7206:13): [True: 2.59k, False: 43.0k]
  |  Branch (7206:42): [True: 1.11k, False: 41.9k]
  ------------------
 7207|  3.70k|          break;
 7208|  3.70k|        }
 7209|  41.9k|        *d++ = static_cast<char>(convert_hex_to_binary(p[1]) * 16 +
 7210|  41.9k|                                 convert_hex_to_binary(p[2]));
 7211|  41.9k|        p += 3;
 7212|  41.9k|      }
 7213|  43.5k|      if (p < end && *p == '%') {
  ------------------
  |  Branch (7213:11): [True: 42.6k, False: 832]
  |  Branch (7213:22): [True: 4.02k, False: 38.6k]
  ------------------
 7214|       |        // Not a valid escape (too few chars left or bad hex): copy '%'
 7215|       |        // literally and keep scanning after it.
 7216|  4.02k|        *d++ = *p++;
 7217|  4.02k|      }
 7218|  43.5k|    } else {
 7219|  40.4k|      const char* q = static_cast<const char*>(
 7220|  40.4k|          std::memchr(p, '%', static_cast<size_t>(end - p)));
 7221|  40.4k|      const char* run_end = q ? q : end;
  ------------------
  |  Branch (7221:29): [True: 2.62k, False: 37.8k]
  ------------------
 7222|  40.4k|      const size_t n = static_cast<size_t>(run_end - p);
 7223|  40.4k|      std::memcpy(d, p, n);
 7224|  40.4k|      d += n;
 7225|  40.4k|      p = run_end;
 7226|  40.4k|    }
 7227|  83.9k|  }
 7228|       |
 7229|  38.8k|  out.resize(static_cast<size_t>(d - d0));
 7230|  38.8k|  return out;
 7231|  38.8k|}
_ZN3ada7unicode14percent_encodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKh:
 7319|   190k|                           const uint8_t character_set[]) {
 7320|   190k|  auto pointer = std::ranges::find_if(input, [character_set](const char c) {
 7321|   190k|    return character_sets::bit_at(character_set, c);
 7322|   190k|  });
 7323|       |  // Optimization: Don't iterate if percent encode is not required
 7324|   190k|  if (pointer == input.end()) {
  ------------------
  |  Branch (7324:7): [True: 186k, False: 3.48k]
  ------------------
 7325|   186k|    return std::string(input);
 7326|   186k|  }
 7327|       |
 7328|  3.48k|  std::string result;
 7329|  3.48k|  result.reserve(input.length());  // in the worst case, percent encoding might
 7330|       |                                   // produce 3 characters.
 7331|  3.48k|  result.append(input.substr(0, std::distance(input.begin(), pointer)));
 7332|  3.48k|  if (static_cast<size_t>(input.end() - pointer) >= 48) {
  ------------------
  |  Branch (7332:7): [True: 741, False: 2.74k]
  ------------------
 7333|    741|    percent_encode_suffix(&*pointer, input.data() + input.size(), character_set,
 7334|    741|                          result);
 7335|  2.74k|  } else {
 7336|  20.5k|    for (; pointer != input.end(); pointer++) {
  ------------------
  |  Branch (7336:12): [True: 17.8k, False: 2.74k]
  ------------------
 7337|  17.8k|      if (character_sets::bit_at(character_set, *pointer)) {
  ------------------
  |  Branch (7337:11): [True: 11.9k, False: 5.84k]
  ------------------
 7338|  11.9k|        result.append(character_sets::hex + uint8_t(*pointer) * 4, 3);
 7339|  11.9k|      } else {
 7340|  5.84k|        result += *pointer;
 7341|  5.84k|      }
 7342|  17.8k|    }
 7343|  2.74k|  }
 7344|  3.48k|  return result;
 7345|   190k|}
_ZN3ada7unicode8to_asciiERNSt3__18optionalINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEENS1_17basic_string_viewIcS5_EEm:
 7390|   124k|              size_t first_percent) {
 7391|   124k|  std::string percent_decoded_buffer;
 7392|   124k|  std::string_view input = plain;
 7393|   124k|  if (first_percent != std::string_view::npos) {
  ------------------
  |  Branch (7393:7): [True: 772, False: 124k]
  ------------------
 7394|    772|    percent_decoded_buffer = unicode::percent_decode(plain, first_percent);
 7395|    772|    input = percent_decoded_buffer;
 7396|    772|  }
 7397|       |  // input is a non-empty UTF-8 string, must be percent decoded
 7398|   124k|  std::string idna_ascii = ada::idna::to_ascii(input);
 7399|   124k|  if (idna_ascii.empty() || contains_forbidden_domain_code_point(
  ------------------
  |  Branch (7399:7): [True: 2.32k, False: 122k]
  |  Branch (7399:29): [True: 854, False: 121k]
  ------------------
 7400|   122k|                                idna_ascii.data(), idna_ascii.size())) {
 7401|  3.18k|    return false;
 7402|  3.18k|  }
 7403|   121k|  out = std::move(idna_ascii);
 7404|   121k|  return true;
 7405|   124k|}
_ZN3ada7unicode14percent_encodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKhm:
 7408|     42|                           const uint8_t character_set[], size_t index) {
 7409|     42|  std::string out;
 7410|       |  // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage)
 7411|     42|  out.append(input.data(), index);
 7412|     42|  auto pointer = input.begin() + index;
 7413|     42|  if (static_cast<size_t>(input.end() - pointer) >= 48) {
  ------------------
  |  Branch (7413:7): [True: 2, False: 40]
  ------------------
 7414|      2|    percent_encode_suffix(&*pointer, input.data() + input.size(), character_set,
 7415|      2|                          out);
 7416|     40|  } else {
 7417|    577|    for (; pointer != input.end(); pointer++) {
  ------------------
  |  Branch (7417:12): [True: 537, False: 40]
  ------------------
 7418|    537|      if (character_sets::bit_at(character_set, *pointer)) {
  ------------------
  |  Branch (7418:11): [True: 204, False: 333]
  ------------------
 7419|    204|        out.append(character_sets::hex + uint8_t(*pointer) * 4, 3);
 7420|    333|      } else {
 7421|    333|        out += *pointer;
 7422|    333|      }
 7423|    537|    }
 7424|     40|  }
 7425|     42|  return out;
 7426|     42|}
_ZN3ada7unicode21percent_encode_suffixEPKcS2_PKhRNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEE:
 7720|    743|                           const uint8_t character_set[], std::string& out) {
 7721|    743|#if ADA_UNICODE_SSSE3 || ADA_NEON || ADA_RVV
 7722|    743|  if (static_cast<size_t>(end - p) >= kPercentEncodeSimdMin) {
  ------------------
  |  Branch (7722:7): [True: 743, False: 0]
  ------------------
 7723|    743|    percent_encode_to_wide(p, end, character_set, out);
 7724|    743|    return;
 7725|    743|  }
 7726|      0|#endif
 7727|      0|  percent_encode_to_scalar(p, end, character_set, out);
 7728|      0|}
_ZN3ada11serializers36find_longest_sequence_of_ipv6_piecesERKNSt3__15arrayItLm8EEERmS6_:
 7793|    852|    size_t& compress_length) noexcept {
 7794|    852|  compress = 0;
 7795|    852|  compress_length = 0;
 7796|    852|  size_t i = 0;
 7797|  3.24k|  while (i < 8) {
  ------------------
  |  Branch (7797:10): [True: 2.39k, False: 852]
  ------------------
 7798|  2.39k|    if (address[i] != 0) {
  ------------------
  |  Branch (7798:9): [True: 1.35k, False: 1.04k]
  ------------------
 7799|  1.35k|      ++i;
 7800|  1.35k|      continue;
 7801|  1.35k|    }
 7802|  1.04k|    size_t next = i + 1;
 7803|  5.46k|    while (next < 8 && address[next] == 0) {
  ------------------
  |  Branch (7803:12): [True: 4.95k, False: 508]
  |  Branch (7803:24): [True: 4.42k, False: 534]
  ------------------
 7804|  4.42k|      ++next;
 7805|  4.42k|    }
 7806|  1.04k|    const size_t count = next - i;
 7807|  1.04k|    if (count > compress_length) {
  ------------------
  |  Branch (7807:9): [True: 900, False: 142]
  ------------------
 7808|    900|      compress_length = count;
 7809|    900|      compress = i;
 7810|    900|    }
 7811|  1.04k|    i = next;
 7812|  1.04k|  }
 7813|    852|}
_ZN3ada11serializers4ipv6ERKNSt3__15arrayItLm8EEE:
 7815|    852|std::string ipv6(const std::array<uint16_t, 8>& address) {
 7816|    852|  size_t compress = 0;
 7817|    852|  size_t compress_length = 0;
 7818|    852|  find_longest_sequence_of_ipv6_pieces(address, compress, compress_length);
 7819|       |
 7820|       |  // Skip compression when the longest zero run is a single piece.
 7821|    852|  if (compress_length <= 1) {
  ------------------
  |  Branch (7821:7): [True: 50, False: 802]
  ------------------
 7822|     50|    compress = compress_length = 8;
 7823|     50|  }
 7824|       |
 7825|       |  // Max: '[' + 8*4 hex + 7 ':' + ']' = 41
 7826|    852|  std::string output(4 * 8 + 7 + 2, '\0');
 7827|    852|  char* point = output.data();
 7828|    852|  *point++ = '[';
 7829|    852|  size_t piece_index = 0;
 7830|  2.05k|  while (true) {
  ------------------
  |  Branch (7830:10): [True: 2.05k, Folded]
  ------------------
 7831|  2.05k|    if (piece_index == compress) {
  ------------------
  |  Branch (7831:9): [True: 802, False: 1.25k]
  ------------------
 7832|    802|      *point++ = ':';
 7833|       |      // If we skip a value initially, we need to write '::'.
 7834|    802|      if (piece_index == 0) {
  ------------------
  |  Branch (7834:11): [True: 526, False: 276]
  ------------------
 7835|    526|        *point++ = ':';
 7836|    526|      }
 7837|    802|      piece_index += compress_length;
 7838|    802|      if (piece_index == 8) {
  ------------------
  |  Branch (7838:11): [True: 446, False: 356]
  ------------------
 7839|    446|        break;
 7840|    446|      }
 7841|    802|    }
 7842|  1.60k|    point = write_hex_u16(point, address[piece_index]);
 7843|  1.60k|    ++piece_index;
 7844|  1.60k|    if (piece_index == 8) {
  ------------------
  |  Branch (7844:9): [True: 406, False: 1.20k]
  ------------------
 7845|    406|      break;
 7846|    406|    }
 7847|  1.20k|    *point++ = ':';
 7848|  1.20k|  }
 7849|    852|  *point++ = ']';
 7850|    852|  output.resize(static_cast<size_t>(point - output.data()));
 7851|    852|  return output;
 7852|    852|}
_ZN3ada11serializers4ipv4Em:
 7854|  40.0k|std::string ipv4(const uint64_t address) {
 7855|  40.0k|  std::string output(15, '\0');
 7856|  40.0k|  char* point = output.data();
 7857|  40.0k|  point = write_u8(point, static_cast<uint8_t>(address >> 24));
 7858|  40.0k|  *point++ = '.';
 7859|  40.0k|  point = write_u8(point, static_cast<uint8_t>(address >> 16));
 7860|  40.0k|  *point++ = '.';
 7861|  40.0k|  point = write_u8(point, static_cast<uint8_t>(address >> 8));
 7862|  40.0k|  *point++ = '.';
 7863|  40.0k|  point = write_u8(point, static_cast<uint8_t>(address));
 7864|  40.0k|  output.resize(static_cast<size_t>(point - output.data()));
 7865|  40.0k|  return output;
 7866|  40.0k|}
_ZN3ada5parseINS_3urlEEEN2tl8expectedIT_NS_6errorsEEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEPKS4_:
 8268|   604k|    std::string_view input, const result_type* base_url) {
 8269|   604k|  result_type u = ada::parser::parse_url_impl<result_type>(input, base_url);
 8270|   604k|  if (!u.is_valid) {
  ------------------
  |  Branch (8270:7): [True: 21.3k, False: 583k]
  ------------------
 8271|  21.3k|    return tl::unexpected(errors::type_error);
 8272|  21.3k|  }
 8273|   583k|  return u;
 8274|   604k|}
_ZN3ada5parseINS_14url_aggregatorEEEN2tl8expectedIT_NS_6errorsEEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEPKS4_:
 8268|   604k|    std::string_view input, const result_type* base_url) {
 8269|   604k|  result_type u = ada::parser::parse_url_impl<result_type>(input, base_url);
 8270|   604k|  if (!u.is_valid) {
  ------------------
  |  Branch (8270:7): [True: 21.3k, False: 583k]
  ------------------
 8271|  21.3k|    return tl::unexpected(errors::type_error);
 8272|  21.3k|  }
 8273|   583k|  return u;
 8274|   604k|}
_ZN3ada20get_max_input_lengthEv:
 7889|  1.59M|uint32_t get_max_input_length() {
 7890|  1.59M|  return max_input_length_.load(std::memory_order_relaxed);
 7891|  1.59M|}
_ZN3ada7helpers18trim_c0_whitespaceERNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9243|   523k|void trim_c0_whitespace(std::string_view& input) noexcept {
 9244|   524k|  while (!input.empty() &&
  ------------------
  |  Branch (9244:10): [True: 524k, False: 0]
  ------------------
 9245|   524k|         ada::unicode::is_c0_control_or_space(input.front())) {
  ------------------
  |  Branch (9245:10): [True: 470, False: 523k]
  ------------------
 9246|    470|    input.remove_prefix(1);
 9247|    470|  }
 9248|   526k|  while (!input.empty() && ada::unicode::is_c0_control_or_space(input.back())) {
  ------------------
  |  Branch (9248:10): [True: 526k, False: 0]
  |  Branch (9248:28): [True: 3.40k, False: 523k]
  ------------------
 9249|  3.40k|    input.remove_suffix(1);
 9250|  3.40k|  }
 9251|   523k|}
_ZN3ada7helpers8overlapsENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEERKNS1_12basic_stringIcS4_NS1_9allocatorIcEEEE:
 9418|  18.3k|bool overlaps(std::string_view input1, const std::string& input2) noexcept {
 9419|  18.3k|  ada_log("helpers::overlaps check if string_view '", input1, "' [",
 9420|  18.3k|          input1.size(), " bytes] is part of string '", input2, "' [",
 9421|  18.3k|          input2.size(), " bytes]");
 9422|  18.3k|  return !input1.empty() && !input2.empty() && input1.data() >= input2.data() &&
  ------------------
  |  Branch (9422:10): [True: 18.3k, False: 0]
  |  Branch (9422:29): [True: 18.3k, False: 0]
  |  Branch (9422:48): [True: 18.3k, False: 2]
  ------------------
 9423|  18.3k|         input1.data() < input2.data() + input2.size();
  ------------------
  |  Branch (9423:10): [True: 0, False: 18.3k]
  ------------------
 9424|  18.3k|}
_ZN3ada3url17parse_opaque_hostENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9799|    669|bool url::parse_opaque_host(std::string_view input) {
 9800|    669|  ada_log("parse_opaque_host ", input, " [", input.size(), " bytes]");
 9801|    669|  if (std::ranges::any_of(input, ada::unicode::is_forbidden_host_code_point)) {
  ------------------
  |  Branch (9801:7): [True: 33, False: 636]
  ------------------
 9802|     33|    return is_valid = false;
 9803|     33|  }
 9804|       |
 9805|       |  // Return the result of running UTF-8 percent-encode on input using the C0
 9806|       |  // control percent-encode set.
 9807|    636|  host = ada::unicode::percent_encode(
 9808|    636|      input, ada::character_sets::C0_CONTROL_PERCENT_ENCODE);
 9809|    636|  return true;
 9810|    669|}
_ZN3ada3url10parse_ipv4ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9812|  57.0k|bool url::parse_ipv4(std::string_view input) {
 9813|  57.0k|  ada_log("parse_ipv4 ", input, " [", input.size(), " bytes]");
 9814|  57.0k|  if (input.empty()) {
  ------------------
  |  Branch (9814:7): [True: 0, False: 57.0k]
  ------------------
 9815|      0|    return is_valid = false;
 9816|      0|  }
 9817|  57.0k|  std::string_view original_input = input;
 9818|  57.0k|  if (original_input.back() == '.') {
  ------------------
  |  Branch (9818:7): [True: 27.5k, False: 29.5k]
  ------------------
 9819|  27.5k|    original_input.remove_suffix(1);
 9820|  27.5k|  }
 9821|  57.0k|  if (input.back() == '.') {
  ------------------
  |  Branch (9821:7): [True: 27.5k, False: 29.5k]
  ------------------
 9822|  27.5k|    input.remove_suffix(1);
 9823|  27.5k|    if (input.empty()) {
  ------------------
  |  Branch (9823:9): [True: 0, False: 27.5k]
  ------------------
 9824|      0|      return is_valid = false;
 9825|      0|    }
 9826|  27.5k|  }
 9827|       |
 9828|  57.0k|  const uint64_t fast = checkers::try_parse_ipv4_fast(input);
 9829|  57.0k|  if (fast < checkers::ipv4_fast_fail) [[likely]] {
  ------------------
  |  Branch (9829:7): [True: 18.3k, False: 38.7k]
  ------------------
 9830|  18.3k|    host = original_input;
 9831|  18.3k|    host_type = IPV4;
 9832|  18.3k|    return true;
 9833|  18.3k|  }
 9834|       |
 9835|  38.7k|  const char* p = input.data();
 9836|  38.7k|  const char* end = p + input.size();
 9837|  38.7k|  uint64_t ipv4 = 0;
 9838|  38.7k|  int digit_count = 0;
 9839|  38.7k|  int pure_decimal_count = 0;
 9840|       |
 9841|  48.8k|  for (; digit_count < 4 && p < end; ++digit_count) {
  ------------------
  |  Branch (9841:10): [True: 48.8k, False: 14]
  |  Branch (9841:29): [True: 48.8k, False: 0]
  ------------------
 9842|  48.8k|    uint64_t segment = 0;
 9843|  48.8k|    bool pure = false;
 9844|  48.8k|    if (!detail::parse_ipv4_number(p, end, segment, pure)) {
  ------------------
  |  Branch (9844:9): [True: 18.6k, False: 30.1k]
  ------------------
 9845|  18.6k|      return is_valid = false;
 9846|  18.6k|    }
 9847|  30.1k|    if (pure) {
  ------------------
  |  Branch (9847:9): [True: 11.2k, False: 18.9k]
  ------------------
 9848|  11.2k|      ++pure_decimal_count;
 9849|  11.2k|    }
 9850|  30.1k|    if (p >= end) {
  ------------------
  |  Branch (9850:9): [True: 20.0k, False: 10.1k]
  ------------------
 9851|  20.0k|      const unsigned shift = static_cast<unsigned>(32 - digit_count * 8);
 9852|  20.0k|      if (segment >= (uint64_t{1} << shift)) {
  ------------------
  |  Branch (9852:11): [True: 23, False: 20.0k]
  ------------------
 9853|     23|        return is_valid = false;
 9854|     23|      }
 9855|  20.0k|      ipv4 = (ipv4 << shift) | segment;
 9856|  20.0k|      host = (pure_decimal_count == 4) ? std::string(original_input)
  ------------------
  |  Branch (9856:14): [True: 0, False: 20.0k]
  ------------------
 9857|  20.0k|                                       : ada::serializers::ipv4(ipv4);
 9858|  20.0k|      host_type = IPV4;
 9859|  20.0k|      return true;
 9860|  20.0k|    }
 9861|  10.1k|    if (segment > 255 || *p != '.') {
  ------------------
  |  Branch (9861:9): [True: 47, False: 10.0k]
  |  Branch (9861:26): [True: 0, False: 10.0k]
  ------------------
 9862|     47|      return is_valid = false;
 9863|     47|    }
 9864|  10.0k|    ipv4 = (ipv4 << 8) | segment;
 9865|  10.0k|    ++p;
 9866|  10.0k|  }
 9867|     14|  if (digit_count != 4 || p != end) {
  ------------------
  |  Branch (9867:7): [True: 0, False: 14]
  |  Branch (9867:27): [True: 14, False: 0]
  ------------------
 9868|     14|    return is_valid = false;
 9869|     14|  }
 9870|      0|  host = (pure_decimal_count == 4) ? std::string(original_input)
  ------------------
  |  Branch (9870:10): [True: 0, False: 0]
  ------------------
 9871|      0|                                   : ada::serializers::ipv4(ipv4);
 9872|      0|  host_type = IPV4;
 9873|      0|  return true;
 9874|     14|}
_ZN3ada3url10parse_ipv6ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9876|    604|bool url::parse_ipv6(std::string_view input) {
 9877|    604|  ada_log("parse_ipv6 ", input, " [", input.size(), " bytes]");
 9878|    604|  if (input.empty() || input.size() > 45) [[unlikely]] {
  ------------------
  |  Branch (9878:7): [True: 19, False: 585]
  |  Branch (9878:24): [True: 13, False: 572]
  ------------------
 9879|     32|    return is_valid = false;
 9880|     32|  }
 9881|    572|  std::array<uint16_t, 8> address{};
 9882|       |#if defined(ADA_AVX512_IPV6)
 9883|       |  if (bool simd_valid; detail::try_parse_ipv6_avx512(input.data(), input.size(),
 9884|       |                                                     address, simd_valid)) {
 9885|       |    if (!simd_valid) [[unlikely]] {
 9886|       |      return is_valid = false;
 9887|       |    }
 9888|       |    host = ada::serializers::ipv6(address);
 9889|       |    host_type = IPV6;
 9890|       |    return true;
 9891|       |  }
 9892|       |  address = {};
 9893|       |#endif
 9894|    572|  const char* pointer = input.data();
 9895|    572|  const char* const end = pointer + input.size();
 9896|    572|  int piece_index = 0;
 9897|    572|  int compress = -1;
 9898|       |
 9899|    572|  if (*pointer == ':') {
  ------------------
  |  Branch (9899:7): [True: 275, False: 297]
  ------------------
 9900|    275|    if (input.size() == 1 || pointer[1] != ':') [[unlikely]] {
  ------------------
  |  Branch (9900:9): [True: 3, False: 272]
  |  Branch (9900:30): [True: 7, False: 265]
  ------------------
 9901|     10|      return is_valid = false;
 9902|     10|    }
 9903|    265|    pointer += 2;
 9904|    265|    compress = ++piece_index;
 9905|    265|  }
 9906|       |
 9907|  1.60k|  while (pointer != end) {
  ------------------
  |  Branch (9907:10): [True: 1.15k, False: 447]
  ------------------
 9908|  1.15k|    if (piece_index == 8) [[unlikely]] {
  ------------------
  |  Branch (9908:9): [True: 3, False: 1.15k]
  ------------------
 9909|      3|      return is_valid = false;
 9910|      3|    }
 9911|  1.15k|    if (*pointer == ':') {
  ------------------
  |  Branch (9911:9): [True: 157, False: 993]
  ------------------
 9912|    157|      if (compress != -1) [[unlikely]] {
  ------------------
  |  Branch (9912:11): [True: 3, False: 154]
  ------------------
 9913|      3|        return is_valid = false;
 9914|      3|      }
 9915|    154|      ++pointer;
 9916|    154|      compress = ++piece_index;
 9917|    154|      continue;
 9918|    157|    }
 9919|       |
 9920|    993|    uint16_t value = 0;
 9921|    993|    const int length = detail::parse_hex_piece(pointer, end, value);
 9922|       |
 9923|    993|    if (pointer != end && *pointer == '.') {
  ------------------
  |  Branch (9923:9): [True: 763, False: 230]
  |  Branch (9923:27): [True: 77, False: 686]
  ------------------
 9924|     77|      if (length == 0) [[unlikely]] {
  ------------------
  |  Branch (9924:11): [True: 3, False: 74]
  ------------------
 9925|      3|        return is_valid = false;
 9926|      3|      }
 9927|     74|      pointer -= length;
 9928|     74|      if (piece_index > 6) [[unlikely]] {
  ------------------
  |  Branch (9928:11): [True: 3, False: 71]
  ------------------
 9929|      3|        return is_valid = false;
 9930|      3|      }
 9931|       |
 9932|     71|      int numbers_seen = 0;
 9933|    209|      while (pointer != end) {
  ------------------
  |  Branch (9933:14): [True: 191, False: 18]
  ------------------
 9934|    191|        int ipv4_piece = -1;
 9935|    191|        if (numbers_seen > 0) {
  ------------------
  |  Branch (9935:13): [True: 120, False: 71]
  ------------------
 9936|    120|          if (*pointer == '.' && numbers_seen < 4) {
  ------------------
  |  Branch (9936:15): [True: 104, False: 16]
  |  Branch (9936:34): [True: 98, False: 6]
  ------------------
 9937|     98|            ++pointer;
 9938|     98|          } else {
 9939|     22|            return is_valid = false;
 9940|     22|          }
 9941|    120|        }
 9942|    169|        if (pointer == end || *pointer < '0' || *pointer > '9') [[unlikely]] {
  ------------------
  |  Branch (9942:13): [True: 14, False: 155]
  |  Branch (9942:31): [True: 6, False: 149]
  |  Branch (9942:49): [True: 3, False: 146]
  ------------------
 9943|     23|          return is_valid = false;
 9944|     23|        }
 9945|    146|        ipv4_piece = *pointer - '0';
 9946|    146|        ++pointer;
 9947|    146|        if (pointer != end && *pointer >= '0' && *pointer <= '9') {
  ------------------
  |  Branch (9947:13): [True: 136, False: 10]
  |  Branch (9947:31): [True: 59, False: 77]
  |  Branch (9947:50): [True: 55, False: 4]
  ------------------
 9948|     55|          if (ipv4_piece == 0) [[unlikely]] {
  ------------------
  |  Branch (9948:15): [True: 3, False: 52]
  ------------------
 9949|      3|            return is_valid = false;
 9950|      3|          }
 9951|     52|          ipv4_piece = ipv4_piece * 10 + (*pointer - '0');
 9952|     52|          ++pointer;
 9953|     52|          if (pointer != end && *pointer >= '0' && *pointer <= '9') {
  ------------------
  |  Branch (9953:15): [True: 49, False: 3]
  |  Branch (9953:33): [True: 28, False: 21]
  |  Branch (9953:52): [True: 25, False: 3]
  ------------------
 9954|     25|            ipv4_piece = ipv4_piece * 10 + (*pointer - '0');
 9955|     25|            ++pointer;
 9956|     25|            if (ipv4_piece > 255) [[unlikely]] {
  ------------------
  |  Branch (9956:17): [True: 5, False: 20]
  ------------------
 9957|      5|              return is_valid = false;
 9958|      5|            }
 9959|     25|          }
 9960|     52|        }
 9961|    138|        address[static_cast<size_t>(piece_index)] = static_cast<uint16_t>(
 9962|    138|            address[static_cast<size_t>(piece_index)] * 0x100 +
 9963|    138|            static_cast<uint16_t>(ipv4_piece));
 9964|    138|        ++numbers_seen;
 9965|    138|        if (numbers_seen == 2 || numbers_seen == 4) {
  ------------------
  |  Branch (9965:13): [True: 42, False: 96]
  |  Branch (9965:34): [True: 14, False: 82]
  ------------------
 9966|     56|          ++piece_index;
 9967|     56|        }
 9968|    138|      }
 9969|     18|      if (numbers_seen != 4) [[unlikely]] {
  ------------------
  |  Branch (9969:11): [True: 12, False: 6]
  ------------------
 9970|     12|        return is_valid = false;
 9971|     12|      }
 9972|      6|      break;
 9973|     18|    }
 9974|       |
 9975|    916|    if (length == 0) [[unlikely]] {
  ------------------
  |  Branch (9975:9): [True: 18, False: 898]
  ------------------
 9976|     18|      return is_valid = false;
 9977|     18|    }
 9978|       |
 9979|    898|    if (pointer != end && *pointer == ':') {
  ------------------
  |  Branch (9979:9): [True: 668, False: 230]
  |  Branch (9979:27): [True: 657, False: 11]
  ------------------
 9980|    657|      ++pointer;
 9981|    657|      if (pointer == end) [[unlikely]] {
  ------------------
  |  Branch (9981:11): [True: 3, False: 654]
  ------------------
 9982|      3|        return is_valid = false;
 9983|      3|      }
 9984|    657|    } else if (pointer != end) [[unlikely]] {
  ------------------
  |  Branch (9984:16): [True: 11, False: 230]
  ------------------
 9985|     11|      return is_valid = false;
 9986|     11|    }
 9987|       |
 9988|    884|    address[static_cast<size_t>(piece_index)] = value;
 9989|    884|    ++piece_index;
 9990|    884|  }
 9991|       |
 9992|    453|  if (compress != -1) {
  ------------------
  |  Branch (9992:7): [True: 408, False: 45]
  ------------------
 9993|    408|    const int right = piece_index - compress;
 9994|    408|    if (right > 0) {
  ------------------
  |  Branch (9994:9): [True: 191, False: 217]
  ------------------
 9995|    191|      const size_t dest = static_cast<size_t>(8 - right);
 9996|    191|      const size_t src = static_cast<size_t>(compress);
 9997|    191|      if (dest != src) {
  ------------------
  |  Branch (9997:11): [True: 181, False: 10]
  ------------------
 9998|    478|        for (size_t i = static_cast<size_t>(right); i-- > 0;) {
  ------------------
  |  Branch (9998:53): [True: 297, False: 181]
  ------------------
 9999|    297|          address[dest + i] = address[src + i];
10000|    297|          address[src + i] = 0;
10001|    297|        }
10002|    181|      }
10003|    191|    }
10004|    408|  } else if (piece_index != 8) [[unlikely]] {
  ------------------
  |  Branch (10004:14): [True: 27, False: 18]
  ------------------
10005|     27|    return is_valid = false;
10006|     27|  }
10007|       |
10008|    426|  host = ada::serializers::ipv6(address);
10009|    426|  ada_log("parse_ipv6 ", *host);
10010|    426|  host_type = IPV6;
10011|    426|  return true;
10012|    453|}
_ZNK3ada3url12get_protocolEv:
10341|   194k|[[nodiscard]] std::string url::get_protocol() const {
10342|   194k|  if (is_special()) {
  ------------------
  |  Branch (10342:7): [True: 193k, False: 605]
  ------------------
10343|   193k|    return helpers::concat(ada::scheme::details::is_special_list[type], ":");
10344|   193k|  }
10345|       |  // We only move the 'scheme' if it is non-special.
10346|    605|  return helpers::concat(non_special_scheme, ":");
10347|   194k|}
_ZNK3ada3url8get_hostEv:
10349|   194k|[[nodiscard]] std::string url::get_host() const {
10350|       |  // If url's host is null, then return the empty string.
10351|       |  // If url's port is null, return url's host, serialized.
10352|       |  // Return url's host, serialized, followed by U+003A (:) and url's port,
10353|       |  // serialized.
10354|   194k|  if (!host.has_value()) {
  ------------------
  |  Branch (10354:7): [True: 371, False: 194k]
  ------------------
10355|    371|    return "";
10356|    371|  }
10357|   194k|  if (port.has_value()) {
  ------------------
  |  Branch (10357:7): [True: 20.0k, False: 174k]
  ------------------
10358|  20.0k|    return host.value() + ":" + get_port();
10359|  20.0k|  }
10360|   174k|  return host.value();
10361|   194k|}
_ZNK3ada3url12get_hostnameEv:
10363|   194k|[[nodiscard]] std::string url::get_hostname() const {
10364|   194k|  return host.value_or("");
10365|   194k|}
_ZNK3ada3url10get_searchEv:
10367|   194k|[[nodiscard]] std::string url::get_search() const {
10368|       |  // If this's URL's query is either null or the empty string, then return the
10369|       |  // empty string. Return U+003F (?), followed by this's URL's query.
10370|   194k|  return (!query.has_value() || (query->empty())) ? "" : "?" + query.value();
  ------------------
  |  Branch (10370:11): [True: 161k, False: 33.0k]
  |  Branch (10370:33): [True: 1.10k, False: 31.9k]
  ------------------
10371|   194k|}
_ZNK3ada3url12get_usernameEv:
10373|   194k|[[nodiscard]] const std::string& url::get_username() const noexcept {
10374|   194k|  return username;
10375|   194k|}
_ZNK3ada3url12get_passwordEv:
10377|   194k|[[nodiscard]] const std::string& url::get_password() const noexcept {
10378|   194k|  return password;
10379|   194k|}
_ZNK3ada3url8get_portEv:
10381|   214k|[[nodiscard]] std::string url::get_port() const {
10382|   214k|  return port.has_value() ? std::to_string(port.value()) : "";
  ------------------
  |  Branch (10382:10): [True: 40.0k, False: 174k]
  ------------------
10383|   214k|}
_ZNK3ada3url8get_hashEv:
10385|   194k|[[nodiscard]] std::string url::get_hash() const {
10386|       |  // If this's URL's fragment is either null or the empty string, then return
10387|       |  // the empty string. Return U+0023 (#), followed by this's URL's fragment.
10388|   194k|  return (!hash.has_value() || (hash->empty())) ? "" : "#" + hash.value();
  ------------------
  |  Branch (10388:11): [True: 170k, False: 23.8k]
  |  Branch (10388:32): [True: 1.49k, False: 22.3k]
  ------------------
10389|   194k|}
_ZN3ada3url8set_hrefENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
10679|   194k|bool url::set_href(const std::string_view input) {
10680|   194k|  ada::result<ada::url> out = ada::parse<ada::url>(input);
10681|       |
10682|   194k|  if (out) {
  ------------------
  |  Branch (10682:7): [True: 194k, False: 0]
  ------------------
10683|       |    // The parser enforces get_max_input_length() on both the input and the
10684|       |    // normalized result. This is a defense-in-depth check.
10685|   194k|    if (out->get_href_size() > ada::get_max_input_length()) {
  ------------------
  |  Branch (10685:9): [True: 0, False: 194k]
  ------------------
10686|      0|      return false;
10687|      0|    }
10688|   194k|    *this = *out;
10689|   194k|  }
10690|       |
10691|   194k|  return out.has_value();
10692|   194k|}
_ZN3ada6parser25try_parse_simple_absoluteINS_3urlEEEbNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEERT_:
11946|   430k|                                                result_type& out) {
11947|   430k|  constexpr bool is_ada_url = std::is_same_v<result_type, ada::url>;
11948|   430k|  constexpr bool is_aggregator =
11949|   430k|      std::is_same_v<result_type, ada::url_aggregator>;
11950|   430k|  static_assert(is_ada_url || is_aggregator);
11951|       |
11952|   430k|  const size_t len = input.size();
11953|       |  // Shortest accepted form is "ws://x" (6).
11954|   430k|  if (len < 6) [[unlikely]] {
  ------------------
  |  Branch (11954:7): [True: 8, False: 430k]
  ------------------
11955|      8|    return false;
11956|      8|  }
11957|   430k|  const auto* b = reinterpret_cast<const uint8_t*>(input.data());
11958|       |
11959|   430k|  size_t pos = 0;
11960|   430k|  ada::scheme::type scheme_type = ada::scheme::type::NOT_SPECIAL;
11961|   430k|  uint32_t protocol_end = 0;
11962|   430k|#if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \
11963|   430k|    defined(_M_X64) || defined(_M_IX86) || defined(_M_AMD64)
11964|       |  // One 8-byte load + integer compare is a single cmp/jcc on x86-64.
11965|       |  // Masked compares cover the shorter special schemes without extra loads.
11966|   430k|  if (len >= 8) {
  ------------------
  |  Branch (11966:7): [True: 430k, False: 173]
  ------------------
11967|   430k|    uint64_t first8 = 0;
11968|   430k|    std::memcpy(&first8, b, 8);
11969|   430k|    if (first8 == 0x2f2f3a7370747468ull) {  // "https://"
  ------------------
  |  Branch (11969:9): [True: 337k, False: 92.2k]
  ------------------
11970|   337k|      pos = 8;
11971|   337k|      scheme_type = ada::scheme::type::HTTPS;
11972|   337k|      protocol_end = 6;
11973|   337k|    } else if ((first8 & 0x00ffffffffffffffull) ==
  ------------------
  |  Branch (11973:16): [True: 85.7k, False: 6.49k]
  ------------------
11974|  92.2k|               0x002f2f3a70747468ull) {  // "http://"
11975|  85.7k|      pos = 7;
11976|  85.7k|      scheme_type = ada::scheme::type::HTTP;
11977|  85.7k|      protocol_end = 5;
11978|  85.7k|    } else if ((first8 & 0x0000ffffffffffffull) ==
  ------------------
  |  Branch (11978:16): [True: 11, False: 6.47k]
  ------------------
11979|  6.49k|               0x00002f2f3a737377ull) {  // "wss://"
11980|     11|      pos = 6;
11981|     11|      scheme_type = ada::scheme::type::WSS;
11982|     11|      protocol_end = 4;
11983|  6.47k|    } else if ((first8 & 0x0000ffffffffffffull) ==
  ------------------
  |  Branch (11983:16): [True: 56, False: 6.42k]
  ------------------
11984|  6.47k|               0x00002f2f3a707466ull) {  // "ftp://"
11985|     56|      pos = 6;
11986|     56|      scheme_type = ada::scheme::type::FTP;
11987|     56|      protocol_end = 4;
11988|  6.42k|    } else if ((first8 & 0x000000ffffffffffull) ==
  ------------------
  |  Branch (11988:16): [True: 167, False: 6.25k]
  ------------------
11989|  6.42k|               0x0000002f2f3a7377ull) {  // "ws://"
11990|    167|      pos = 5;
11991|    167|      scheme_type = ada::scheme::type::WS;
11992|    167|      protocol_end = 3;
11993|  6.25k|    } else {
11994|  6.25k|      return false;
11995|  6.25k|    }
11996|   430k|  } else if (b[0] == 'w' && b[1] == 's') {
  ------------------
  |  Branch (11996:14): [True: 29, False: 144]
  |  Branch (11996:29): [True: 13, False: 16]
  ------------------
11997|     13|    if (b[2] == ':' && b[3] == '/' && b[4] == '/') {
  ------------------
  |  Branch (11997:9): [True: 2, False: 11]
  |  Branch (11997:24): [True: 2, False: 0]
  |  Branch (11997:39): [True: 2, False: 0]
  ------------------
11998|      2|      pos = 5;
11999|      2|      scheme_type = ada::scheme::type::WS;
12000|      2|      protocol_end = 3;
12001|     11|    } else if (b[2] == 's' && b[3] == ':' && b[4] == '/' && b[5] == '/') {
  ------------------
  |  Branch (12001:16): [True: 2, False: 9]
  |  Branch (12001:31): [True: 0, False: 2]
  |  Branch (12001:46): [True: 0, False: 0]
  |  Branch (12001:61): [True: 0, False: 0]
  ------------------
12002|      0|      pos = 6;
12003|      0|      scheme_type = ada::scheme::type::WSS;
12004|      0|      protocol_end = 4;
12005|     11|    } else {
12006|     11|      return false;
12007|     11|    }
12008|    160|  } else if (b[0] == 'f' && b[1] == 't' && b[2] == 'p' && b[3] == ':' &&
  ------------------
  |  Branch (12008:14): [True: 31, False: 129]
  |  Branch (12008:29): [True: 16, False: 15]
  |  Branch (12008:44): [True: 6, False: 10]
  |  Branch (12008:59): [True: 0, False: 6]
  ------------------
12009|      0|             b[4] == '/' && b[5] == '/') {
  ------------------
  |  Branch (12009:14): [True: 0, False: 0]
  |  Branch (12009:29): [True: 0, False: 0]
  ------------------
12010|      0|    pos = 6;
12011|      0|    scheme_type = ada::scheme::type::FTP;
12012|      0|    protocol_end = 4;
12013|    160|  } else if (len >= 7 && b[0] == 'h' && b[1] == 't' && b[2] == 't' &&
  ------------------
  |  Branch (12013:14): [True: 128, False: 32]
  |  Branch (12013:26): [True: 80, False: 48]
  |  Branch (12013:41): [True: 60, False: 20]
  |  Branch (12013:56): [True: 46, False: 14]
  ------------------
12014|     46|             b[3] == 'p' && b[4] == ':' && b[5] == '/' && b[6] == '/') {
  ------------------
  |  Branch (12014:14): [True: 38, False: 8]
  |  Branch (12014:29): [True: 19, False: 19]
  |  Branch (12014:44): [True: 9, False: 10]
  |  Branch (12014:59): [True: 2, False: 7]
  ------------------
12015|      2|    pos = 7;
12016|      2|    scheme_type = ada::scheme::type::HTTP;
12017|      2|    protocol_end = 5;
12018|    158|  } else {
12019|    158|    return false;
12020|    158|  }
12021|       |#else
12022|       |  // Big-endian / uncommon arches: byte-wise special-scheme match.
12023|       |  if (len >= 8 && b[0] == 'h' && b[1] == 't' && b[2] == 't' && b[3] == 'p' &&
12024|       |      b[4] == 's' && b[5] == ':' && b[6] == '/' && b[7] == '/') {
12025|       |    pos = 8;
12026|       |    scheme_type = ada::scheme::type::HTTPS;
12027|       |    protocol_end = 6;
12028|       |  } else if (len >= 7 && b[0] == 'h' && b[1] == 't' && b[2] == 't' &&
12029|       |             b[3] == 'p' && b[4] == ':' && b[5] == '/' && b[6] == '/') {
12030|       |    pos = 7;
12031|       |    scheme_type = ada::scheme::type::HTTP;
12032|       |    protocol_end = 5;
12033|       |  } else if (b[0] == 'w' && b[1] == 's') {
12034|       |    if (b[2] == ':' && b[3] == '/' && b[4] == '/') {
12035|       |      pos = 5;
12036|       |      scheme_type = ada::scheme::type::WS;
12037|       |      protocol_end = 3;
12038|       |    } else if (len >= 6 && b[2] == 's' && b[3] == ':' && b[4] == '/' &&
12039|       |               b[5] == '/') {
12040|       |      pos = 6;
12041|       |      scheme_type = ada::scheme::type::WSS;
12042|       |      protocol_end = 4;
12043|       |    } else {
12044|       |      return false;
12045|       |    }
12046|       |  } else if (b[0] == 'f' && b[1] == 't' && b[2] == 'p' && b[3] == ':' &&
12047|       |             b[4] == '/' && b[5] == '/') {
12048|       |    pos = 6;
12049|       |    scheme_type = ada::scheme::type::FTP;
12050|       |    protocol_end = 4;
12051|       |  } else {
12052|       |    return false;
12053|       |  }
12054|       |#endif
12055|   423k|  if (pos < len && (b[pos] == '/' || b[pos] == '\\')) [[unlikely]] {
  ------------------
  |  Branch (12055:7): [True: 423k, False: 2]
  |  Branch (12055:21): [True: 126, False: 423k]
  |  Branch (12055:38): [True: 12, False: 423k]
  ------------------
12056|    138|    return false;
12057|    138|  }
12058|       |
12059|       |  // Digit-led hosts are IPv4/numeric; '[' is IPv6. Skip before scanning.
12060|   423k|  if (pos < len && ((b[pos] >= '0' && b[pos] <= '9') || b[pos] == '[')) {
  ------------------
  |  Branch (12060:7): [True: 423k, False: 2]
  |  Branch (12060:22): [True: 421k, False: 2.24k]
  |  Branch (12060:39): [True: 20, False: 421k]
  |  Branch (12060:57): [True: 6, False: 423k]
  ------------------
12061|     26|    return false;
12062|     26|  }
12063|       |
12064|   423k|  const size_t host_start = pos;
12065|   423k|  bool has_upper = false;
12066|   423k|  bool has_x = false;
12067|   423k|  size_t host_end = pos;
12068|   423k|  if (!scan_plain_host(b, pos, len, host_end, has_upper, has_x)) {
  ------------------
  |  Branch (12068:7): [True: 2.95k, False: 420k]
  ------------------
12069|  2.95k|    return false;
12070|  2.95k|  }
12071|   420k|  if (host_start == host_end) [[unlikely]] {
  ------------------
  |  Branch (12071:7): [True: 84, False: 420k]
  ------------------
12072|     84|    return false;
12073|     84|  }
12074|   420k|  const size_t host_len = host_end - host_start;
12075|   420k|  if (host_len > 253) [[unlikely]] {
  ------------------
  |  Branch (12075:7): [True: 284, False: 420k]
  ------------------
12076|    284|    return false;
12077|    284|  }
12078|   420k|  {
12079|   420k|    std::string_view hv(input.data() + host_start, host_len);
12080|   420k|    char host_buf[256];
12081|   420k|    if (has_upper) [[unlikely]] {
  ------------------
  |  Branch (12081:9): [True: 9.78k, False: 410k]
  ------------------
12082|  9.78k|      std::memcpy(host_buf, input.data() + host_start, host_len);
12083|  9.78k|      unicode::to_lower_ascii(host_buf, host_len);
12084|  9.78k|      hv = std::string_view(host_buf, host_len);
12085|  9.78k|    }
12086|   420k|    if (ada::checkers::last_label_may_be_a_number(hv)) [[unlikely]] {
  ------------------
  |  Branch (12086:9): [True: 18.4k, False: 401k]
  ------------------
12087|  18.4k|      return false;
12088|  18.4k|    }
12089|       |    // Punycode is "xn--...". The host scan already notes a lowercase 'x';
12090|       |    // uppercase 'X' is covered by has_upper after the in-place lower.
12091|   401k|    static constexpr std::string_view xn{"xn-", 3};
12092|   401k|    if ((has_x || has_upper) && hv.find(xn) != std::string_view::npos)
  ------------------
  |  Branch (12092:10): [True: 367k, False: 34.7k]
  |  Branch (12092:19): [True: 397, False: 34.3k]
  |  Branch (12092:33): [True: 58.3k, False: 309k]
  ------------------
12093|  58.3k|        [[unlikely]] {
12094|  58.3k|      return false;
12095|  58.3k|    }
12096|   401k|  }
12097|       |
12098|   343k|  if (host_end < len && b[host_end] == ':') [[unlikely]] {
  ------------------
  |  Branch (12098:7): [True: 334k, False: 9.35k]
  |  Branch (12098:25): [True: 59.0k, False: 275k]
  ------------------
12099|  59.0k|    return finish_simple_absolute_with_port(input, out, scheme_type,
12100|  59.0k|                                            protocol_end, host_start, host_end,
12101|  59.0k|                                            host_len, has_upper);
12102|  59.0k|  }
12103|       |
12104|   284k|  size_t i = host_end;
12105|   284k|  size_t path_start = host_end;
12106|   284k|  size_t path_end = host_end;
12107|   284k|  size_t query_start = std::string_view::npos;
12108|   284k|  size_t hash_start = std::string_view::npos;
12109|   284k|  bool has_path = false;
12110|   284k|  bool maybe_dot_segment = false;
12111|   284k|  bool rest_simple = true;
12112|       |
12113|   284k|  if (i < len && b[i] == '/') {
  ------------------
  |  Branch (12113:7): [True: 275k, False: 9.35k]
  |  Branch (12113:18): [True: 256k, False: 18.7k]
  ------------------
12114|   256k|    has_path = true;
12115|   256k|    path_start = i;
12116|   256k|    ++i;
12117|   256k|    scan_path_run(b, i, len, maybe_dot_segment);
12118|   256k|    if (i < len) {
  ------------------
  |  Branch (12118:9): [True: 107k, False: 149k]
  ------------------
12119|   107k|      const uint8_t cls = k_path[b[i]];
12120|   107k|      if (cls == 1) {
  ------------------
  |  Branch (12120:11): [True: 95.6k, False: 11.6k]
  ------------------
12121|  95.6k|        path_end = i;
12122|  95.6k|        if (b[i] == '?') {
  ------------------
  |  Branch (12122:13): [True: 76.5k, False: 19.1k]
  ------------------
12123|  76.5k|          query_start = i;
12124|  76.5k|          ++i;
12125|  76.5k|          goto scan_query;
12126|  76.5k|        }
12127|  19.1k|        hash_start = i;
12128|  19.1k|        ++i;
12129|  19.1k|        goto scan_hash;
12130|  95.6k|      }
12131|  11.6k|      rest_simple = false;
12132|   262k|      for (; i < len; ++i) {
  ------------------
  |  Branch (12132:14): [True: 251k, False: 10.5k]
  ------------------
12133|   251k|        if (b[i] == '?') {
  ------------------
  |  Branch (12133:13): [True: 898, False: 250k]
  ------------------
12134|    898|          path_end = i;
12135|    898|          query_start = i;
12136|    898|          ++i;
12137|    898|          goto scan_query_boundary;
12138|    898|        }
12139|   250k|        if (b[i] == '#') {
  ------------------
  |  Branch (12139:13): [True: 229, False: 250k]
  ------------------
12140|    229|          path_end = i;
12141|    229|          hash_start = i;
12142|    229|          ++i;
12143|    229|          goto after_rest;
12144|    229|        }
12145|   250k|      }
12146|  10.5k|      path_end = i;
12147|  10.5k|      goto after_rest;
12148|  11.6k|    }
12149|   149k|    path_end = i;
12150|   149k|  } else if (i < len && b[i] == '?') {
  ------------------
  |  Branch (12150:14): [True: 18.7k, False: 9.35k]
  |  Branch (12150:25): [True: 9.46k, False: 9.29k]
  ------------------
12151|  9.46k|    query_start = i;
12152|  9.46k|    ++i;
12153|  9.46k|    goto scan_query;
12154|  18.6k|  } else if (i < len && b[i] == '#') {
  ------------------
  |  Branch (12154:14): [True: 9.29k, False: 9.35k]
  |  Branch (12154:25): [True: 9.29k, False: 0]
  ------------------
12155|  9.29k|    hash_start = i;
12156|  9.29k|    ++i;
12157|  9.29k|    goto scan_hash;
12158|  9.29k|  }
12159|   158k|  goto after_rest;
12160|       |
12161|   158k|scan_query:
12162|  85.9k|  scan_query_run(b, i, len);
12163|  85.9k|  if (i < len) {
  ------------------
  |  Branch (12163:7): [True: 29.9k, False: 56.0k]
  ------------------
12164|  29.9k|    if (b[i] == '#') {
  ------------------
  |  Branch (12164:9): [True: 29.7k, False: 155]
  ------------------
12165|  29.7k|      hash_start = i;
12166|  29.7k|      ++i;
12167|  29.7k|      goto scan_hash;
12168|  29.7k|    }
12169|    155|    rest_simple = false;
12170|    155|    goto scan_query_boundary;
12171|  29.9k|  }
12172|  56.0k|  goto after_rest;
12173|       |
12174|  56.0k|scan_query_boundary:
12175|  26.0k|  for (; i < len; ++i) {
  ------------------
  |  Branch (12175:10): [True: 25.6k, False: 348]
  ------------------
12176|  25.6k|    if (b[i] == '#') {
  ------------------
  |  Branch (12176:9): [True: 705, False: 24.9k]
  ------------------
12177|    705|      hash_start = i;
12178|    705|      ++i;
12179|    705|      goto after_rest;
12180|    705|    }
12181|  25.6k|  }
12182|    348|  goto after_rest;
12183|       |
12184|  58.2k|scan_hash:
12185|  58.2k|  scan_hash_run(b, i, len);
12186|  58.2k|  if (i < len) {
  ------------------
  |  Branch (12186:7): [True: 105, False: 58.1k]
  ------------------
12187|    105|    rest_simple = false;
12188|    105|  }
12189|       |
12190|   284k|after_rest:
12191|   284k|  if (rest_simple && maybe_dot_segment) {
  ------------------
  |  Branch (12191:7): [True: 272k, False: 11.9k]
  |  Branch (12191:22): [True: 9.88k, False: 262k]
  ------------------
12192|  9.88k|    const std::string_view path_body(input.data() + path_start,
12193|  9.88k|                                     path_end - path_start);
12194|  9.88k|    if (path_has_dot_segment(path_body)) {
  ------------------
  |  Branch (12194:9): [True: 9.51k, False: 369]
  ------------------
12195|  9.51k|      rest_simple = false;
12196|  9.51k|    }
12197|  9.88k|  }
12198|       |
12199|       |  // The slow path removes ASCII tab/newline anywhere in the input and trims a
12200|       |  // trailing C0 control or space; this fast path does neither. A query or
12201|       |  // fragment reaching the helpers below would keep those bytes percent-encoded
12202|       |  // ("?a\nb" -> "?a%0Ab", "#f " -> "#f%20") instead of stripped, so hand such
12203|       |  // inputs back to the slow path.
12204|   284k|  if (!rest_simple && (unicode::is_c0_control_or_space(input.back()) ||
  ------------------
  |  Branch (12204:7): [True: 21.4k, False: 263k]
  |  Branch (12204:24): [True: 34, False: 21.4k]
  ------------------
12205|  21.4k|                       unicode::has_tabs_or_newline(input))) {
  ------------------
  |  Branch (12205:24): [True: 90, False: 21.3k]
  ------------------
12206|    124|    return false;
12207|    124|  }
12208|       |
12209|   284k|  out.type = scheme_type;
12210|   284k|  out.is_valid = true;
12211|   284k|  out.has_opaque_path = false;
12212|   284k|  out.host_type = DEFAULT;
12213|       |
12214|   284k|  if (!rest_simple) {
  ------------------
  |  Branch (12214:7): [True: 21.3k, False: 263k]
  ------------------
12215|       |    // Host is a plain domain. Finish path/query/hash with
12216|       |    // the regular helpers
12217|       |    // so percent-encoding and dot segments do not re-parse the authority.
12218|  21.3k|    const std::string_view path_view =
12219|  21.3k|        has_path
  ------------------
  |  Branch (12219:9): [True: 21.1k, False: 161]
  ------------------
12220|  21.3k|            ? std::string_view(input.data() + path_start, path_end - path_start)
12221|  21.3k|            : std::string_view{};
12222|  21.3k|    auto apply_query_and_hash = [&]() {
12223|  21.3k|      if (query_start != std::string_view::npos) {
12224|  21.3k|        const size_t q_end =
12225|  21.3k|            (hash_start != std::string_view::npos) ? hash_start : len;
12226|  21.3k|        out.update_base_search(std::string_view(input.data() + query_start + 1,
12227|  21.3k|                                                q_end - query_start - 1),
12228|  21.3k|                               character_sets::SPECIAL_QUERY_PERCENT_ENCODE);
12229|  21.3k|      }
12230|  21.3k|      if (hash_start != std::string_view::npos) {
12231|  21.3k|        out.update_unencoded_base_hash(std::string_view(
12232|  21.3k|            input.data() + hash_start + 1, len - hash_start - 1));
12233|  21.3k|      }
12234|  21.3k|    };
12235|       |    if constexpr (is_aggregator) {
12236|       |      out.buffer.assign(input.substr(0, host_end));
12237|       |      if (has_upper) {
12238|       |        unicode::to_lower_ascii(out.buffer.data() + host_start, host_len);
12239|       |      }
12240|       |      out.components.protocol_end = protocol_end;
12241|       |      out.components.username_end = protocol_end + 2;
12242|       |      out.components.host_start = protocol_end + 2;
12243|       |      out.components.host_end = static_cast<uint32_t>(host_end);
12244|       |      out.components.port = url_components::omitted;
12245|       |      out.components.pathname_start = static_cast<uint32_t>(host_end);
12246|       |      out.components.search_start = url_components::omitted;
12247|       |      out.components.hash_start = url_components::omitted;
12248|       |      out.parse_path(path_view);
12249|       |      apply_query_and_hash();
12250|  21.3k|    } else {
12251|  21.3k|      std::string host_str(input.substr(host_start, host_len));
12252|  21.3k|      if (has_upper) {
  ------------------
  |  Branch (12252:11): [True: 172, False: 21.1k]
  ------------------
12253|    172|        unicode::to_lower_ascii(host_str.data(), host_str.size());
12254|    172|      }
12255|  21.3k|      out.host = std::move(host_str);
12256|  21.3k|      out.parse_path(path_view);
12257|  21.3k|      apply_query_and_hash();
12258|  21.3k|    }
12259|  21.3k|    return true;
12260|  21.3k|  }
12261|       |
12262|   263k|  const bool need_slash = !has_path;
12263|       |  if constexpr (is_aggregator) {
12264|       |    if (!need_slash) {
12265|       |      // assign copies once. resize()+memcpy would value-init then overwrite.
12266|       |      out.buffer.assign(input);
12267|       |      if (has_upper) {
12268|       |        unicode::to_lower_ascii(out.buffer.data() + host_start, host_len);
12269|       |      }
12270|       |      out.components.protocol_end = protocol_end;
12271|       |      out.components.username_end = protocol_end + 2;
12272|       |      out.components.host_start = protocol_end + 2;
12273|       |      out.components.host_end = static_cast<uint32_t>(host_end);
12274|       |      out.components.port = url_components::omitted;
12275|       |      out.components.pathname_start = static_cast<uint32_t>(path_start);
12276|       |      out.components.search_start = (query_start != std::string_view::npos)
12277|       |                                        ? static_cast<uint32_t>(query_start)
12278|       |                                        : url_components::omitted;
12279|       |      out.components.hash_start = (hash_start != std::string_view::npos)
12280|       |                                      ? static_cast<uint32_t>(hash_start)
12281|       |                                      : url_components::omitted;
12282|       |    } else {
12283|       |      out.buffer.clear();
12284|       |      out.buffer.reserve(len + 1);
12285|       |      out.buffer.append(input.substr(0, host_end));
12286|       |      out.buffer.push_back('/');
12287|       |      if (host_end < len) {
12288|       |        out.buffer.append(input.substr(host_end));
12289|       |      }
12290|       |      if (has_upper) {
12291|       |        unicode::to_lower_ascii(out.buffer.data() + host_start, host_len);
12292|       |      }
12293|       |      out.components.protocol_end = protocol_end;
12294|       |      out.components.username_end = protocol_end + 2;
12295|       |      out.components.host_start = protocol_end + 2;
12296|       |      out.components.host_end = static_cast<uint32_t>(host_end);
12297|       |      out.components.port = url_components::omitted;
12298|       |      out.components.pathname_start = static_cast<uint32_t>(host_end);
12299|       |      out.components.search_start = (query_start != std::string_view::npos)
12300|       |                                        ? static_cast<uint32_t>(query_start + 1)
12301|       |                                        : url_components::omitted;
12302|       |      out.components.hash_start = (hash_start != std::string_view::npos)
12303|       |                                      ? static_cast<uint32_t>(hash_start + 1)
12304|       |                                      : url_components::omitted;
12305|       |    }
12306|   263k|  } else {
12307|   263k|    std::string host_str(input.substr(host_start, host_len));
12308|   263k|    if (has_upper) {
  ------------------
  |  Branch (12308:9): [True: 9.26k, False: 253k]
  ------------------
12309|  9.26k|      unicode::to_lower_ascii(host_str.data(), host_str.size());
12310|  9.26k|    }
12311|   263k|    out.host = std::move(host_str);
12312|   263k|    if (need_slash) {
  ------------------
  |  Branch (12312:9): [True: 27.9k, False: 235k]
  ------------------
12313|  27.9k|      out.path = "/";
12314|   235k|    } else {
12315|   235k|      out.path.assign(input.data() + path_start, path_end - path_start);
12316|   235k|    }
12317|   263k|    if (query_start != std::string_view::npos) {
  ------------------
  |  Branch (12317:9): [True: 85.6k, False: 177k]
  ------------------
12318|  85.6k|      const size_t q_end =
12319|  85.6k|          (hash_start != std::string_view::npos) ? hash_start : len;
  ------------------
  |  Branch (12319:11): [True: 29.6k, False: 55.9k]
  ------------------
12320|  85.6k|      out.query.emplace(input.data() + query_start + 1,
12321|  85.6k|                        q_end - query_start - 1);
12322|  85.6k|    }
12323|   263k|    if (hash_start != std::string_view::npos) {
  ------------------
  |  Branch (12323:9): [True: 58.0k, False: 205k]
  ------------------
12324|  58.0k|      out.hash.emplace(input.data() + hash_start + 1, len - hash_start - 1);
12325|  58.0k|    }
12326|   263k|  }
12327|   263k|  return true;
12328|   284k|}
_ZN3ada6parser25try_parse_simple_absoluteINS_14url_aggregatorEEEbNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEERT_:
11946|   430k|                                                result_type& out) {
11947|   430k|  constexpr bool is_ada_url = std::is_same_v<result_type, ada::url>;
11948|   430k|  constexpr bool is_aggregator =
11949|   430k|      std::is_same_v<result_type, ada::url_aggregator>;
11950|   430k|  static_assert(is_ada_url || is_aggregator);
11951|       |
11952|   430k|  const size_t len = input.size();
11953|       |  // Shortest accepted form is "ws://x" (6).
11954|   430k|  if (len < 6) [[unlikely]] {
  ------------------
  |  Branch (11954:7): [True: 8, False: 430k]
  ------------------
11955|      8|    return false;
11956|      8|  }
11957|   430k|  const auto* b = reinterpret_cast<const uint8_t*>(input.data());
11958|       |
11959|   430k|  size_t pos = 0;
11960|   430k|  ada::scheme::type scheme_type = ada::scheme::type::NOT_SPECIAL;
11961|   430k|  uint32_t protocol_end = 0;
11962|   430k|#if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || \
11963|   430k|    defined(_M_X64) || defined(_M_IX86) || defined(_M_AMD64)
11964|       |  // One 8-byte load + integer compare is a single cmp/jcc on x86-64.
11965|       |  // Masked compares cover the shorter special schemes without extra loads.
11966|   430k|  if (len >= 8) {
  ------------------
  |  Branch (11966:7): [True: 430k, False: 173]
  ------------------
11967|   430k|    uint64_t first8 = 0;
11968|   430k|    std::memcpy(&first8, b, 8);
11969|   430k|    if (first8 == 0x2f2f3a7370747468ull) {  // "https://"
  ------------------
  |  Branch (11969:9): [True: 337k, False: 92.2k]
  ------------------
11970|   337k|      pos = 8;
11971|   337k|      scheme_type = ada::scheme::type::HTTPS;
11972|   337k|      protocol_end = 6;
11973|   337k|    } else if ((first8 & 0x00ffffffffffffffull) ==
  ------------------
  |  Branch (11973:16): [True: 85.7k, False: 6.49k]
  ------------------
11974|  92.2k|               0x002f2f3a70747468ull) {  // "http://"
11975|  85.7k|      pos = 7;
11976|  85.7k|      scheme_type = ada::scheme::type::HTTP;
11977|  85.7k|      protocol_end = 5;
11978|  85.7k|    } else if ((first8 & 0x0000ffffffffffffull) ==
  ------------------
  |  Branch (11978:16): [True: 11, False: 6.47k]
  ------------------
11979|  6.49k|               0x00002f2f3a737377ull) {  // "wss://"
11980|     11|      pos = 6;
11981|     11|      scheme_type = ada::scheme::type::WSS;
11982|     11|      protocol_end = 4;
11983|  6.47k|    } else if ((first8 & 0x0000ffffffffffffull) ==
  ------------------
  |  Branch (11983:16): [True: 56, False: 6.42k]
  ------------------
11984|  6.47k|               0x00002f2f3a707466ull) {  // "ftp://"
11985|     56|      pos = 6;
11986|     56|      scheme_type = ada::scheme::type::FTP;
11987|     56|      protocol_end = 4;
11988|  6.42k|    } else if ((first8 & 0x000000ffffffffffull) ==
  ------------------
  |  Branch (11988:16): [True: 167, False: 6.25k]
  ------------------
11989|  6.42k|               0x0000002f2f3a7377ull) {  // "ws://"
11990|    167|      pos = 5;
11991|    167|      scheme_type = ada::scheme::type::WS;
11992|    167|      protocol_end = 3;
11993|  6.25k|    } else {
11994|  6.25k|      return false;
11995|  6.25k|    }
11996|   430k|  } else if (b[0] == 'w' && b[1] == 's') {
  ------------------
  |  Branch (11996:14): [True: 29, False: 144]
  |  Branch (11996:29): [True: 13, False: 16]
  ------------------
11997|     13|    if (b[2] == ':' && b[3] == '/' && b[4] == '/') {
  ------------------
  |  Branch (11997:9): [True: 2, False: 11]
  |  Branch (11997:24): [True: 2, False: 0]
  |  Branch (11997:39): [True: 2, False: 0]
  ------------------
11998|      2|      pos = 5;
11999|      2|      scheme_type = ada::scheme::type::WS;
12000|      2|      protocol_end = 3;
12001|     11|    } else if (b[2] == 's' && b[3] == ':' && b[4] == '/' && b[5] == '/') {
  ------------------
  |  Branch (12001:16): [True: 2, False: 9]
  |  Branch (12001:31): [True: 0, False: 2]
  |  Branch (12001:46): [True: 0, False: 0]
  |  Branch (12001:61): [True: 0, False: 0]
  ------------------
12002|      0|      pos = 6;
12003|      0|      scheme_type = ada::scheme::type::WSS;
12004|      0|      protocol_end = 4;
12005|     11|    } else {
12006|     11|      return false;
12007|     11|    }
12008|    160|  } else if (b[0] == 'f' && b[1] == 't' && b[2] == 'p' && b[3] == ':' &&
  ------------------
  |  Branch (12008:14): [True: 31, False: 129]
  |  Branch (12008:29): [True: 16, False: 15]
  |  Branch (12008:44): [True: 6, False: 10]
  |  Branch (12008:59): [True: 0, False: 6]
  ------------------
12009|      0|             b[4] == '/' && b[5] == '/') {
  ------------------
  |  Branch (12009:14): [True: 0, False: 0]
  |  Branch (12009:29): [True: 0, False: 0]
  ------------------
12010|      0|    pos = 6;
12011|      0|    scheme_type = ada::scheme::type::FTP;
12012|      0|    protocol_end = 4;
12013|    160|  } else if (len >= 7 && b[0] == 'h' && b[1] == 't' && b[2] == 't' &&
  ------------------
  |  Branch (12013:14): [True: 128, False: 32]
  |  Branch (12013:26): [True: 80, False: 48]
  |  Branch (12013:41): [True: 60, False: 20]
  |  Branch (12013:56): [True: 46, False: 14]
  ------------------
12014|     46|             b[3] == 'p' && b[4] == ':' && b[5] == '/' && b[6] == '/') {
  ------------------
  |  Branch (12014:14): [True: 38, False: 8]
  |  Branch (12014:29): [True: 19, False: 19]
  |  Branch (12014:44): [True: 9, False: 10]
  |  Branch (12014:59): [True: 2, False: 7]
  ------------------
12015|      2|    pos = 7;
12016|      2|    scheme_type = ada::scheme::type::HTTP;
12017|      2|    protocol_end = 5;
12018|    158|  } else {
12019|    158|    return false;
12020|    158|  }
12021|       |#else
12022|       |  // Big-endian / uncommon arches: byte-wise special-scheme match.
12023|       |  if (len >= 8 && b[0] == 'h' && b[1] == 't' && b[2] == 't' && b[3] == 'p' &&
12024|       |      b[4] == 's' && b[5] == ':' && b[6] == '/' && b[7] == '/') {
12025|       |    pos = 8;
12026|       |    scheme_type = ada::scheme::type::HTTPS;
12027|       |    protocol_end = 6;
12028|       |  } else if (len >= 7 && b[0] == 'h' && b[1] == 't' && b[2] == 't' &&
12029|       |             b[3] == 'p' && b[4] == ':' && b[5] == '/' && b[6] == '/') {
12030|       |    pos = 7;
12031|       |    scheme_type = ada::scheme::type::HTTP;
12032|       |    protocol_end = 5;
12033|       |  } else if (b[0] == 'w' && b[1] == 's') {
12034|       |    if (b[2] == ':' && b[3] == '/' && b[4] == '/') {
12035|       |      pos = 5;
12036|       |      scheme_type = ada::scheme::type::WS;
12037|       |      protocol_end = 3;
12038|       |    } else if (len >= 6 && b[2] == 's' && b[3] == ':' && b[4] == '/' &&
12039|       |               b[5] == '/') {
12040|       |      pos = 6;
12041|       |      scheme_type = ada::scheme::type::WSS;
12042|       |      protocol_end = 4;
12043|       |    } else {
12044|       |      return false;
12045|       |    }
12046|       |  } else if (b[0] == 'f' && b[1] == 't' && b[2] == 'p' && b[3] == ':' &&
12047|       |             b[4] == '/' && b[5] == '/') {
12048|       |    pos = 6;
12049|       |    scheme_type = ada::scheme::type::FTP;
12050|       |    protocol_end = 4;
12051|       |  } else {
12052|       |    return false;
12053|       |  }
12054|       |#endif
12055|   423k|  if (pos < len && (b[pos] == '/' || b[pos] == '\\')) [[unlikely]] {
  ------------------
  |  Branch (12055:7): [True: 423k, False: 2]
  |  Branch (12055:21): [True: 126, False: 423k]
  |  Branch (12055:38): [True: 12, False: 423k]
  ------------------
12056|    138|    return false;
12057|    138|  }
12058|       |
12059|       |  // Digit-led hosts are IPv4/numeric; '[' is IPv6. Skip before scanning.
12060|   423k|  if (pos < len && ((b[pos] >= '0' && b[pos] <= '9') || b[pos] == '[')) {
  ------------------
  |  Branch (12060:7): [True: 423k, False: 2]
  |  Branch (12060:22): [True: 421k, False: 2.24k]
  |  Branch (12060:39): [True: 20, False: 421k]
  |  Branch (12060:57): [True: 6, False: 423k]
  ------------------
12061|     26|    return false;
12062|     26|  }
12063|       |
12064|   423k|  const size_t host_start = pos;
12065|   423k|  bool has_upper = false;
12066|   423k|  bool has_x = false;
12067|   423k|  size_t host_end = pos;
12068|   423k|  if (!scan_plain_host(b, pos, len, host_end, has_upper, has_x)) {
  ------------------
  |  Branch (12068:7): [True: 2.95k, False: 420k]
  ------------------
12069|  2.95k|    return false;
12070|  2.95k|  }
12071|   420k|  if (host_start == host_end) [[unlikely]] {
  ------------------
  |  Branch (12071:7): [True: 84, False: 420k]
  ------------------
12072|     84|    return false;
12073|     84|  }
12074|   420k|  const size_t host_len = host_end - host_start;
12075|   420k|  if (host_len > 253) [[unlikely]] {
  ------------------
  |  Branch (12075:7): [True: 284, False: 420k]
  ------------------
12076|    284|    return false;
12077|    284|  }
12078|   420k|  {
12079|   420k|    std::string_view hv(input.data() + host_start, host_len);
12080|   420k|    char host_buf[256];
12081|   420k|    if (has_upper) [[unlikely]] {
  ------------------
  |  Branch (12081:9): [True: 9.78k, False: 410k]
  ------------------
12082|  9.78k|      std::memcpy(host_buf, input.data() + host_start, host_len);
12083|  9.78k|      unicode::to_lower_ascii(host_buf, host_len);
12084|  9.78k|      hv = std::string_view(host_buf, host_len);
12085|  9.78k|    }
12086|   420k|    if (ada::checkers::last_label_may_be_a_number(hv)) [[unlikely]] {
  ------------------
  |  Branch (12086:9): [True: 18.4k, False: 401k]
  ------------------
12087|  18.4k|      return false;
12088|  18.4k|    }
12089|       |    // Punycode is "xn--...". The host scan already notes a lowercase 'x';
12090|       |    // uppercase 'X' is covered by has_upper after the in-place lower.
12091|   401k|    static constexpr std::string_view xn{"xn-", 3};
12092|   401k|    if ((has_x || has_upper) && hv.find(xn) != std::string_view::npos)
  ------------------
  |  Branch (12092:10): [True: 367k, False: 34.7k]
  |  Branch (12092:19): [True: 397, False: 34.3k]
  |  Branch (12092:33): [True: 58.3k, False: 309k]
  ------------------
12093|  58.3k|        [[unlikely]] {
12094|  58.3k|      return false;
12095|  58.3k|    }
12096|   401k|  }
12097|       |
12098|   343k|  if (host_end < len && b[host_end] == ':') [[unlikely]] {
  ------------------
  |  Branch (12098:7): [True: 334k, False: 9.35k]
  |  Branch (12098:25): [True: 59.0k, False: 275k]
  ------------------
12099|  59.0k|    return finish_simple_absolute_with_port(input, out, scheme_type,
12100|  59.0k|                                            protocol_end, host_start, host_end,
12101|  59.0k|                                            host_len, has_upper);
12102|  59.0k|  }
12103|       |
12104|   284k|  size_t i = host_end;
12105|   284k|  size_t path_start = host_end;
12106|   284k|  size_t path_end = host_end;
12107|   284k|  size_t query_start = std::string_view::npos;
12108|   284k|  size_t hash_start = std::string_view::npos;
12109|   284k|  bool has_path = false;
12110|   284k|  bool maybe_dot_segment = false;
12111|   284k|  bool rest_simple = true;
12112|       |
12113|   284k|  if (i < len && b[i] == '/') {
  ------------------
  |  Branch (12113:7): [True: 275k, False: 9.35k]
  |  Branch (12113:18): [True: 256k, False: 18.7k]
  ------------------
12114|   256k|    has_path = true;
12115|   256k|    path_start = i;
12116|   256k|    ++i;
12117|   256k|    scan_path_run(b, i, len, maybe_dot_segment);
12118|   256k|    if (i < len) {
  ------------------
  |  Branch (12118:9): [True: 107k, False: 149k]
  ------------------
12119|   107k|      const uint8_t cls = k_path[b[i]];
12120|   107k|      if (cls == 1) {
  ------------------
  |  Branch (12120:11): [True: 95.6k, False: 11.6k]
  ------------------
12121|  95.6k|        path_end = i;
12122|  95.6k|        if (b[i] == '?') {
  ------------------
  |  Branch (12122:13): [True: 76.5k, False: 19.1k]
  ------------------
12123|  76.5k|          query_start = i;
12124|  76.5k|          ++i;
12125|  76.5k|          goto scan_query;
12126|  76.5k|        }
12127|  19.1k|        hash_start = i;
12128|  19.1k|        ++i;
12129|  19.1k|        goto scan_hash;
12130|  95.6k|      }
12131|  11.6k|      rest_simple = false;
12132|   262k|      for (; i < len; ++i) {
  ------------------
  |  Branch (12132:14): [True: 251k, False: 10.5k]
  ------------------
12133|   251k|        if (b[i] == '?') {
  ------------------
  |  Branch (12133:13): [True: 898, False: 250k]
  ------------------
12134|    898|          path_end = i;
12135|    898|          query_start = i;
12136|    898|          ++i;
12137|    898|          goto scan_query_boundary;
12138|    898|        }
12139|   250k|        if (b[i] == '#') {
  ------------------
  |  Branch (12139:13): [True: 229, False: 250k]
  ------------------
12140|    229|          path_end = i;
12141|    229|          hash_start = i;
12142|    229|          ++i;
12143|    229|          goto after_rest;
12144|    229|        }
12145|   250k|      }
12146|  10.5k|      path_end = i;
12147|  10.5k|      goto after_rest;
12148|  11.6k|    }
12149|   149k|    path_end = i;
12150|   149k|  } else if (i < len && b[i] == '?') {
  ------------------
  |  Branch (12150:14): [True: 18.7k, False: 9.35k]
  |  Branch (12150:25): [True: 9.46k, False: 9.29k]
  ------------------
12151|  9.46k|    query_start = i;
12152|  9.46k|    ++i;
12153|  9.46k|    goto scan_query;
12154|  18.6k|  } else if (i < len && b[i] == '#') {
  ------------------
  |  Branch (12154:14): [True: 9.29k, False: 9.35k]
  |  Branch (12154:25): [True: 9.29k, False: 0]
  ------------------
12155|  9.29k|    hash_start = i;
12156|  9.29k|    ++i;
12157|  9.29k|    goto scan_hash;
12158|  9.29k|  }
12159|   158k|  goto after_rest;
12160|       |
12161|   158k|scan_query:
12162|  85.9k|  scan_query_run(b, i, len);
12163|  85.9k|  if (i < len) {
  ------------------
  |  Branch (12163:7): [True: 29.9k, False: 56.0k]
  ------------------
12164|  29.9k|    if (b[i] == '#') {
  ------------------
  |  Branch (12164:9): [True: 29.7k, False: 155]
  ------------------
12165|  29.7k|      hash_start = i;
12166|  29.7k|      ++i;
12167|  29.7k|      goto scan_hash;
12168|  29.7k|    }
12169|    155|    rest_simple = false;
12170|    155|    goto scan_query_boundary;
12171|  29.9k|  }
12172|  56.0k|  goto after_rest;
12173|       |
12174|  56.0k|scan_query_boundary:
12175|  26.0k|  for (; i < len; ++i) {
  ------------------
  |  Branch (12175:10): [True: 25.6k, False: 348]
  ------------------
12176|  25.6k|    if (b[i] == '#') {
  ------------------
  |  Branch (12176:9): [True: 705, False: 24.9k]
  ------------------
12177|    705|      hash_start = i;
12178|    705|      ++i;
12179|    705|      goto after_rest;
12180|    705|    }
12181|  25.6k|  }
12182|    348|  goto after_rest;
12183|       |
12184|  58.2k|scan_hash:
12185|  58.2k|  scan_hash_run(b, i, len);
12186|  58.2k|  if (i < len) {
  ------------------
  |  Branch (12186:7): [True: 105, False: 58.1k]
  ------------------
12187|    105|    rest_simple = false;
12188|    105|  }
12189|       |
12190|   284k|after_rest:
12191|   284k|  if (rest_simple && maybe_dot_segment) {
  ------------------
  |  Branch (12191:7): [True: 272k, False: 11.9k]
  |  Branch (12191:22): [True: 9.88k, False: 262k]
  ------------------
12192|  9.88k|    const std::string_view path_body(input.data() + path_start,
12193|  9.88k|                                     path_end - path_start);
12194|  9.88k|    if (path_has_dot_segment(path_body)) {
  ------------------
  |  Branch (12194:9): [True: 9.51k, False: 369]
  ------------------
12195|  9.51k|      rest_simple = false;
12196|  9.51k|    }
12197|  9.88k|  }
12198|       |
12199|       |  // The slow path removes ASCII tab/newline anywhere in the input and trims a
12200|       |  // trailing C0 control or space; this fast path does neither. A query or
12201|       |  // fragment reaching the helpers below would keep those bytes percent-encoded
12202|       |  // ("?a\nb" -> "?a%0Ab", "#f " -> "#f%20") instead of stripped, so hand such
12203|       |  // inputs back to the slow path.
12204|   284k|  if (!rest_simple && (unicode::is_c0_control_or_space(input.back()) ||
  ------------------
  |  Branch (12204:7): [True: 21.4k, False: 263k]
  |  Branch (12204:24): [True: 34, False: 21.4k]
  ------------------
12205|  21.4k|                       unicode::has_tabs_or_newline(input))) {
  ------------------
  |  Branch (12205:24): [True: 90, False: 21.3k]
  ------------------
12206|    124|    return false;
12207|    124|  }
12208|       |
12209|   284k|  out.type = scheme_type;
12210|   284k|  out.is_valid = true;
12211|   284k|  out.has_opaque_path = false;
12212|   284k|  out.host_type = DEFAULT;
12213|       |
12214|   284k|  if (!rest_simple) {
  ------------------
  |  Branch (12214:7): [True: 21.3k, False: 263k]
  ------------------
12215|       |    // Host is a plain domain. Finish path/query/hash with
12216|       |    // the regular helpers
12217|       |    // so percent-encoding and dot segments do not re-parse the authority.
12218|  21.3k|    const std::string_view path_view =
12219|  21.3k|        has_path
  ------------------
  |  Branch (12219:9): [True: 21.1k, False: 161]
  ------------------
12220|  21.3k|            ? std::string_view(input.data() + path_start, path_end - path_start)
12221|  21.3k|            : std::string_view{};
12222|  21.3k|    auto apply_query_and_hash = [&]() {
12223|  21.3k|      if (query_start != std::string_view::npos) {
12224|  21.3k|        const size_t q_end =
12225|  21.3k|            (hash_start != std::string_view::npos) ? hash_start : len;
12226|  21.3k|        out.update_base_search(std::string_view(input.data() + query_start + 1,
12227|  21.3k|                                                q_end - query_start - 1),
12228|  21.3k|                               character_sets::SPECIAL_QUERY_PERCENT_ENCODE);
12229|  21.3k|      }
12230|  21.3k|      if (hash_start != std::string_view::npos) {
12231|  21.3k|        out.update_unencoded_base_hash(std::string_view(
12232|  21.3k|            input.data() + hash_start + 1, len - hash_start - 1));
12233|  21.3k|      }
12234|  21.3k|    };
12235|  21.3k|    if constexpr (is_aggregator) {
12236|  21.3k|      out.buffer.assign(input.substr(0, host_end));
12237|  21.3k|      if (has_upper) {
  ------------------
  |  Branch (12237:11): [True: 172, False: 21.1k]
  ------------------
12238|    172|        unicode::to_lower_ascii(out.buffer.data() + host_start, host_len);
12239|    172|      }
12240|  21.3k|      out.components.protocol_end = protocol_end;
12241|  21.3k|      out.components.username_end = protocol_end + 2;
12242|  21.3k|      out.components.host_start = protocol_end + 2;
12243|  21.3k|      out.components.host_end = static_cast<uint32_t>(host_end);
12244|  21.3k|      out.components.port = url_components::omitted;
12245|  21.3k|      out.components.pathname_start = static_cast<uint32_t>(host_end);
12246|  21.3k|      out.components.search_start = url_components::omitted;
12247|  21.3k|      out.components.hash_start = url_components::omitted;
12248|  21.3k|      out.parse_path(path_view);
12249|  21.3k|      apply_query_and_hash();
12250|       |    } else {
12251|       |      std::string host_str(input.substr(host_start, host_len));
12252|       |      if (has_upper) {
12253|       |        unicode::to_lower_ascii(host_str.data(), host_str.size());
12254|       |      }
12255|       |      out.host = std::move(host_str);
12256|       |      out.parse_path(path_view);
12257|       |      apply_query_and_hash();
12258|       |    }
12259|  21.3k|    return true;
12260|  21.3k|  }
12261|       |
12262|   263k|  const bool need_slash = !has_path;
12263|   263k|  if constexpr (is_aggregator) {
12264|   263k|    if (!need_slash) {
  ------------------
  |  Branch (12264:9): [True: 235k, False: 27.9k]
  ------------------
12265|       |      // assign copies once. resize()+memcpy would value-init then overwrite.
12266|   235k|      out.buffer.assign(input);
12267|   235k|      if (has_upper) {
  ------------------
  |  Branch (12267:11): [True: 9.19k, False: 225k]
  ------------------
12268|  9.19k|        unicode::to_lower_ascii(out.buffer.data() + host_start, host_len);
12269|  9.19k|      }
12270|   235k|      out.components.protocol_end = protocol_end;
12271|   235k|      out.components.username_end = protocol_end + 2;
12272|   235k|      out.components.host_start = protocol_end + 2;
12273|   235k|      out.components.host_end = static_cast<uint32_t>(host_end);
12274|   235k|      out.components.port = url_components::omitted;
12275|   235k|      out.components.pathname_start = static_cast<uint32_t>(path_start);
12276|   235k|      out.components.search_start = (query_start != std::string_view::npos)
  ------------------
  |  Branch (12276:37): [True: 76.3k, False: 158k]
  ------------------
12277|   235k|                                        ? static_cast<uint32_t>(query_start)
12278|   235k|                                        : url_components::omitted;
12279|   235k|      out.components.hash_start = (hash_start != std::string_view::npos)
  ------------------
  |  Branch (12279:35): [True: 48.6k, False: 186k]
  ------------------
12280|   235k|                                      ? static_cast<uint32_t>(hash_start)
12281|   235k|                                      : url_components::omitted;
12282|   235k|    } else {
12283|  27.9k|      out.buffer.clear();
12284|  27.9k|      out.buffer.reserve(len + 1);
12285|  27.9k|      out.buffer.append(input.substr(0, host_end));
12286|  27.9k|      out.buffer.push_back('/');
12287|  27.9k|      if (host_end < len) {
  ------------------
  |  Branch (12287:11): [True: 18.5k, False: 9.35k]
  ------------------
12288|  18.5k|        out.buffer.append(input.substr(host_end));
12289|  18.5k|      }
12290|  27.9k|      if (has_upper) {
  ------------------
  |  Branch (12290:11): [True: 71, False: 27.8k]
  ------------------
12291|     71|        unicode::to_lower_ascii(out.buffer.data() + host_start, host_len);
12292|     71|      }
12293|  27.9k|      out.components.protocol_end = protocol_end;
12294|  27.9k|      out.components.username_end = protocol_end + 2;
12295|  27.9k|      out.components.host_start = protocol_end + 2;
12296|  27.9k|      out.components.host_end = static_cast<uint32_t>(host_end);
12297|  27.9k|      out.components.port = url_components::omitted;
12298|  27.9k|      out.components.pathname_start = static_cast<uint32_t>(host_end);
12299|  27.9k|      out.components.search_start = (query_start != std::string_view::npos)
  ------------------
  |  Branch (12299:37): [True: 9.34k, False: 18.5k]
  ------------------
12300|  27.9k|                                        ? static_cast<uint32_t>(query_start + 1)
12301|  27.9k|                                        : url_components::omitted;
12302|  27.9k|      out.components.hash_start = (hash_start != std::string_view::npos)
  ------------------
  |  Branch (12302:35): [True: 9.33k, False: 18.5k]
  ------------------
12303|  27.9k|                                      ? static_cast<uint32_t>(hash_start + 1)
12304|  27.9k|                                      : url_components::omitted;
12305|  27.9k|    }
12306|       |  } else {
12307|       |    std::string host_str(input.substr(host_start, host_len));
12308|       |    if (has_upper) {
12309|       |      unicode::to_lower_ascii(host_str.data(), host_str.size());
12310|       |    }
12311|       |    out.host = std::move(host_str);
12312|       |    if (need_slash) {
12313|       |      out.path = "/";
12314|       |    } else {
12315|       |      out.path.assign(input.data() + path_start, path_end - path_start);
12316|       |    }
12317|       |    if (query_start != std::string_view::npos) {
12318|       |      const size_t q_end =
12319|       |          (hash_start != std::string_view::npos) ? hash_start : len;
12320|       |      out.query.emplace(input.data() + query_start + 1,
12321|       |                        q_end - query_start - 1);
12322|       |    }
12323|       |    if (hash_start != std::string_view::npos) {
12324|       |      out.hash.emplace(input.data() + hash_start + 1, len - hash_start - 1);
12325|       |    }
12326|       |  }
12327|   263k|  return true;
12328|   284k|}
_ZN3ada6parser32finish_simple_absolute_with_portINS_3urlEEEbNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEERT_NS_6scheme4typeEjmmmb:
11674|  59.0k|    bool has_upper) {
11675|  59.0k|  constexpr bool is_ada_url = std::is_same_v<result_type, ada::url>;
11676|  59.0k|  constexpr bool is_aggregator =
11677|  59.0k|      std::is_same_v<result_type, ada::url_aggregator>;
11678|  59.0k|  static_assert(is_ada_url || is_aggregator);
11679|       |
11680|  59.0k|  const size_t len = input.size();
11681|  59.0k|  const auto* b = reinterpret_cast<const uint8_t*>(input.data());
11682|  59.0k|  size_t p = host_end + 1;
11683|  59.0k|  uint32_t port_value = 0;
11684|  59.0k|  bool any_digit = false;
11685|   255k|  while (p < len && b[p] >= '0' && b[p] <= '9') {
  ------------------
  |  Branch (11685:10): [True: 255k, False: 48]
  |  Branch (11685:21): [True: 196k, False: 58.7k]
  |  Branch (11685:36): [True: 196k, False: 246]
  ------------------
11686|   196k|    any_digit = true;
11687|   196k|    port_value = port_value * 10 + static_cast<uint32_t>(b[p] - '0');
11688|   196k|    if (port_value > 65535) [[unlikely]] {
  ------------------
  |  Branch (11688:9): [True: 19, False: 196k]
  ------------------
11689|     19|      return false;
11690|     19|    }
11691|   196k|    ++p;
11692|   196k|  }
11693|  59.0k|  if (p < len && b[p] != '/' && b[p] != '?' && b[p] != '#') [[unlikely]] {
  ------------------
  |  Branch (11693:7): [True: 58.9k, False: 48]
  |  Branch (11693:18): [True: 362, False: 58.6k]
  |  Branch (11693:33): [True: 280, False: 82]
  |  Branch (11693:48): [True: 220, False: 60]
  ------------------
11694|    220|    return false;
11695|    220|  }
11696|  58.7k|  uint32_t parsed_port = url_components::omitted;
11697|  58.7k|  const uint16_t default_port = ada::scheme::get_special_port(scheme_type);
11698|  58.7k|  if (any_digit && port_value != default_port) {
  ------------------
  |  Branch (11698:7): [True: 58.3k, False: 415]
  |  Branch (11698:20): [True: 58.3k, False: 4]
  ------------------
11699|  58.3k|    parsed_port = port_value;
11700|  58.3k|  }
11701|  58.7k|  const size_t authority_end = p;
11702|       |
11703|  58.7k|  size_t i = authority_end;
11704|  58.7k|  size_t path_start = host_end;
11705|  58.7k|  size_t path_end = host_end;
11706|  58.7k|  size_t query_start = std::string_view::npos;
11707|  58.7k|  size_t hash_start = std::string_view::npos;
11708|  58.7k|  bool has_path = false;
11709|  58.7k|  bool maybe_dot_segment = false;
11710|  58.7k|  bool rest_simple = true;
11711|       |
11712|  58.7k|  if (i < len && b[i] == '/') {
  ------------------
  |  Branch (11712:7): [True: 58.7k, False: 48]
  |  Branch (11712:18): [True: 58.6k, False: 142]
  ------------------
11713|  58.6k|    has_path = true;
11714|  58.6k|    path_start = i;
11715|  58.6k|    ++i;
11716|  58.6k|    scan_path_run(b, i, len, maybe_dot_segment);
11717|  58.6k|    if (i < len) {
  ------------------
  |  Branch (11717:9): [True: 3.20k, False: 55.3k]
  ------------------
11718|  3.20k|      const uint8_t cls = k_path[b[i]];
11719|  3.20k|      if (cls == 1) {
  ------------------
  |  Branch (11719:11): [True: 1.90k, False: 1.30k]
  ------------------
11720|  1.90k|        path_end = i;
11721|  1.90k|        if (b[i] == '?') {
  ------------------
  |  Branch (11721:13): [True: 1.48k, False: 419]
  ------------------
11722|  1.48k|          query_start = i;
11723|  1.48k|          ++i;
11724|  1.48k|          goto scan_query;
11725|  1.48k|        }
11726|    419|        hash_start = i;
11727|    419|        ++i;
11728|    419|        goto scan_hash;
11729|  1.90k|      }
11730|  1.30k|      rest_simple = false;
11731|  78.4k|      for (; i < len; ++i) {
  ------------------
  |  Branch (11731:14): [True: 77.9k, False: 543]
  ------------------
11732|  77.9k|        if (b[i] == '?') {
  ------------------
  |  Branch (11732:13): [True: 588, False: 77.3k]
  ------------------
11733|    588|          path_end = i;
11734|    588|          query_start = i;
11735|    588|          ++i;
11736|    588|          goto scan_query_boundary;
11737|    588|        }
11738|  77.3k|        if (b[i] == '#') {
  ------------------
  |  Branch (11738:13): [True: 171, False: 77.1k]
  ------------------
11739|    171|          path_end = i;
11740|    171|          hash_start = i;
11741|    171|          ++i;
11742|    171|          goto after_rest;
11743|    171|        }
11744|  77.3k|      }
11745|    543|      path_end = i;
11746|    543|      goto after_rest;
11747|  1.30k|    }
11748|  55.3k|    path_end = i;
11749|  55.3k|  } else if (i < len && b[i] == '?') {
  ------------------
  |  Branch (11749:14): [True: 142, False: 48]
  |  Branch (11749:25): [True: 82, False: 60]
  ------------------
11750|     82|    query_start = i;
11751|     82|    ++i;
11752|     82|    goto scan_query;
11753|    108|  } else if (i < len && b[i] == '#') {
  ------------------
  |  Branch (11753:14): [True: 60, False: 48]
  |  Branch (11753:25): [True: 60, False: 0]
  ------------------
11754|     60|    hash_start = i;
11755|     60|    ++i;
11756|     60|    goto scan_hash;
11757|     60|  }
11758|  55.4k|  goto after_rest;
11759|       |
11760|  55.4k|scan_query:
11761|  1.57k|  scan_query_run(b, i, len);
11762|  1.57k|  if (i < len) {
  ------------------
  |  Branch (11762:7): [True: 1.21k, False: 358]
  ------------------
11763|  1.21k|    if (b[i] == '#') {
  ------------------
  |  Branch (11763:9): [True: 1.15k, False: 61]
  ------------------
11764|  1.15k|      hash_start = i;
11765|  1.15k|      ++i;
11766|  1.15k|      goto scan_hash;
11767|  1.15k|    }
11768|     61|    rest_simple = false;
11769|     61|    goto scan_query_boundary;
11770|  1.21k|  }
11771|    358|  goto after_rest;
11772|       |
11773|    649|scan_query_boundary:
11774|  12.6k|  for (; i < len; ++i) {
  ------------------
  |  Branch (11774:10): [True: 12.4k, False: 230]
  ------------------
11775|  12.4k|    if (b[i] == '#') {
  ------------------
  |  Branch (11775:9): [True: 419, False: 12.0k]
  ------------------
11776|    419|      hash_start = i;
11777|    419|      ++i;
11778|    419|      goto after_rest;
11779|    419|    }
11780|  12.4k|  }
11781|    230|  goto after_rest;
11782|       |
11783|  1.63k|scan_hash:
11784|  1.63k|  scan_hash_run(b, i, len);
11785|  1.63k|  if (i < len) {
  ------------------
  |  Branch (11785:7): [True: 45, False: 1.58k]
  ------------------
11786|     45|    rest_simple = false;
11787|     45|  }
11788|       |
11789|  58.7k|after_rest:
11790|  58.7k|  if (rest_simple && maybe_dot_segment) {
  ------------------
  |  Branch (11790:7): [True: 57.3k, False: 1.40k]
  |  Branch (11790:22): [True: 357, False: 57.0k]
  ------------------
11791|    357|    const std::string_view path_body(input.data() + path_start,
11792|    357|                                     path_end - path_start);
11793|    357|    if (path_has_dot_segment(path_body)) {
  ------------------
  |  Branch (11793:9): [True: 310, False: 47]
  ------------------
11794|    310|      rest_simple = false;
11795|    310|    }
11796|    357|  }
11797|       |
11798|       |  // The slow path removes ASCII tab/newline anywhere in the input and trims a
11799|       |  // trailing C0 control or space; this fast path does neither. A query or
11800|       |  // fragment reaching the helpers below would keep those bytes percent-encoded
11801|       |  // ("?a\nb" -> "?a%0Ab", "#f " -> "#f%20") instead of stripped, so hand such
11802|       |  // inputs back to the slow path.
11803|  58.7k|  if (!rest_simple && (unicode::is_c0_control_or_space(input.back()) ||
  ------------------
  |  Branch (11803:7): [True: 1.71k, False: 57.0k]
  |  Branch (11803:24): [True: 19, False: 1.69k]
  ------------------
11804|  1.69k|                       unicode::has_tabs_or_newline(input))) {
  ------------------
  |  Branch (11804:24): [True: 34, False: 1.66k]
  ------------------
11805|     53|    return false;
11806|     53|  }
11807|       |
11808|  58.7k|  out.type = scheme_type;
11809|  58.7k|  out.is_valid = true;
11810|  58.7k|  out.has_opaque_path = false;
11811|  58.7k|  out.host_type = DEFAULT;
11812|       |
11813|  58.7k|  const uint32_t port_bytes = (parsed_port != url_components::omitted)
  ------------------
  |  Branch (11813:31): [True: 58.3k, False: 394]
  ------------------
11814|  58.7k|                                  ? (1 + port_decimal_digit_count(parsed_port))
11815|  58.7k|                                  : 0;
11816|       |
11817|  58.7k|  if (!rest_simple) {
  ------------------
  |  Branch (11817:7): [True: 1.66k, False: 57.0k]
  ------------------
11818|  1.66k|    const std::string_view path_view =
11819|  1.66k|        has_path
  ------------------
  |  Branch (11819:9): [True: 1.63k, False: 35]
  ------------------
11820|  1.66k|            ? std::string_view(input.data() + path_start, path_end - path_start)
11821|  1.66k|            : std::string_view{};
11822|  1.66k|    auto apply_query_and_hash = [&]() {
11823|  1.66k|      if (query_start != std::string_view::npos) {
11824|  1.66k|        const size_t q_end =
11825|  1.66k|            (hash_start != std::string_view::npos) ? hash_start : len;
11826|  1.66k|        out.update_base_search(std::string_view(input.data() + query_start + 1,
11827|  1.66k|                                                q_end - query_start - 1),
11828|  1.66k|                               character_sets::SPECIAL_QUERY_PERCENT_ENCODE);
11829|  1.66k|      }
11830|  1.66k|      if (hash_start != std::string_view::npos) {
11831|  1.66k|        out.update_unencoded_base_hash(std::string_view(
11832|  1.66k|            input.data() + hash_start + 1, len - hash_start - 1));
11833|  1.66k|      }
11834|  1.66k|    };
11835|       |    if constexpr (is_aggregator) {
11836|       |      out.buffer.assign(input.substr(0, host_end));
11837|       |      if (parsed_port != url_components::omitted) {
11838|       |        append_canonical_port(out.buffer, parsed_port);
11839|       |      }
11840|       |      if (has_upper) {
11841|       |        unicode::to_lower_ascii(out.buffer.data() + host_start, host_len);
11842|       |      }
11843|       |      out.components.protocol_end = protocol_end;
11844|       |      out.components.username_end = protocol_end + 2;
11845|       |      out.components.host_start = protocol_end + 2;
11846|       |      out.components.host_end = static_cast<uint32_t>(host_end);
11847|       |      out.components.port = parsed_port;
11848|       |      out.components.pathname_start = static_cast<uint32_t>(out.buffer.size());
11849|       |      out.components.search_start = url_components::omitted;
11850|       |      out.components.hash_start = url_components::omitted;
11851|       |      out.parse_path(path_view);
11852|       |      apply_query_and_hash();
11853|  1.66k|    } else {
11854|  1.66k|      std::string host_str(input.substr(host_start, host_len));
11855|  1.66k|      if (has_upper) {
  ------------------
  |  Branch (11855:11): [True: 91, False: 1.57k]
  ------------------
11856|     91|        unicode::to_lower_ascii(host_str.data(), host_str.size());
11857|     91|      }
11858|  1.66k|      out.host = std::move(host_str);
11859|  1.66k|      if (parsed_port != url_components::omitted) {
  ------------------
  |  Branch (11859:11): [True: 1.32k, False: 344]
  ------------------
11860|  1.32k|        out.port = static_cast<uint16_t>(parsed_port);
11861|  1.32k|      }
11862|  1.66k|      out.parse_path(path_view);
11863|  1.66k|      apply_query_and_hash();
11864|  1.66k|    }
11865|  1.66k|    return true;
11866|  1.66k|  }
11867|       |
11868|  57.0k|  const bool insert_slash = !has_path;
11869|       |  if constexpr (is_aggregator) {
11870|       |    const size_t out_len =
11871|       |        host_end + port_bytes + (insert_slash ? 1 : 0) + (len - authority_end);
11872|       |    const bool omit_port_bytes = parsed_port == url_components::omitted;
11873|       |    if (out_len == len && !insert_slash && !omit_port_bytes) {
11874|       |      out.buffer.assign(input);
11875|       |    } else {
11876|       |      out.buffer.clear();
11877|       |      out.buffer.reserve(out_len);
11878|       |      out.buffer.append(input.substr(0, host_end));
11879|       |      if (parsed_port != url_components::omitted) {
11880|       |        append_canonical_port(out.buffer, parsed_port);
11881|       |      }
11882|       |      if (insert_slash) {
11883|       |        out.buffer.push_back('/');
11884|       |      }
11885|       |      if (authority_end < len) {
11886|       |        out.buffer.append(input.substr(authority_end));
11887|       |      }
11888|       |    }
11889|       |    if (has_upper) {
11890|       |      unicode::to_lower_ascii(out.buffer.data() + host_start, host_len);
11891|       |    }
11892|       |    const uint32_t pathname_start =
11893|       |        static_cast<uint32_t>(host_end) + port_bytes;
11894|       |    const int32_t tail_delta = static_cast<int32_t>(pathname_start) +
11895|       |                               (insert_slash ? 1 : 0) -
11896|       |                               static_cast<int32_t>(authority_end);
11897|       |    out.components.protocol_end = protocol_end;
11898|       |    out.components.username_end = protocol_end + 2;
11899|       |    out.components.host_start = protocol_end + 2;
11900|       |    out.components.host_end = static_cast<uint32_t>(host_end);
11901|       |    out.components.port = parsed_port;
11902|       |    out.components.pathname_start = pathname_start;
11903|       |    out.components.search_start =
11904|       |        (query_start != std::string_view::npos)
11905|       |            ? static_cast<uint32_t>(static_cast<int32_t>(query_start) +
11906|       |                                    tail_delta)
11907|       |            : url_components::omitted;
11908|       |    out.components.hash_start =
11909|       |        (hash_start != std::string_view::npos)
11910|       |            ? static_cast<uint32_t>(static_cast<int32_t>(hash_start) +
11911|       |                                    tail_delta)
11912|       |            : url_components::omitted;
11913|  57.0k|  } else {
11914|  57.0k|    std::string host_str(input.substr(host_start, host_len));
11915|  57.0k|    if (has_upper) {
  ------------------
  |  Branch (11915:9): [True: 39, False: 57.0k]
  ------------------
11916|     39|      unicode::to_lower_ascii(host_str.data(), host_str.size());
11917|     39|    }
11918|  57.0k|    out.host = std::move(host_str);
11919|  57.0k|    if (parsed_port != url_components::omitted) {
  ------------------
  |  Branch (11919:9): [True: 57.0k, False: 50]
  ------------------
11920|  57.0k|      out.port = static_cast<uint16_t>(parsed_port);
11921|  57.0k|    }
11922|  57.0k|    if (insert_slash) {
  ------------------
  |  Branch (11922:9): [True: 143, False: 56.9k]
  ------------------
11923|    143|      out.path = "/";
11924|  56.9k|    } else {
11925|  56.9k|      out.path.assign(input.data() + path_start, path_end - path_start);
11926|  56.9k|    }
11927|  57.0k|    if (query_start != std::string_view::npos) {
  ------------------
  |  Branch (11927:9): [True: 1.38k, False: 55.6k]
  ------------------
11928|  1.38k|      const size_t q_end =
11929|  1.38k|          (hash_start != std::string_view::npos) ? hash_start : len;
  ------------------
  |  Branch (11929:11): [True: 1.05k, False: 333]
  ------------------
11930|  1.38k|      out.query.emplace(input.data() + query_start + 1,
11931|  1.38k|                        q_end - query_start - 1);
11932|  1.38k|    }
11933|  57.0k|    if (hash_start != std::string_view::npos) {
  ------------------
  |  Branch (11933:9): [True: 1.45k, False: 55.6k]
  ------------------
11934|  1.45k|      out.hash.emplace(input.data() + hash_start + 1, len - hash_start - 1);
11935|  1.45k|    }
11936|  57.0k|  }
11937|  57.0k|  return true;
11938|  58.7k|}
_ZN3ada6parser32finish_simple_absolute_with_portINS_14url_aggregatorEEEbNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEERT_NS_6scheme4typeEjmmmb:
11674|  59.0k|    bool has_upper) {
11675|  59.0k|  constexpr bool is_ada_url = std::is_same_v<result_type, ada::url>;
11676|  59.0k|  constexpr bool is_aggregator =
11677|  59.0k|      std::is_same_v<result_type, ada::url_aggregator>;
11678|  59.0k|  static_assert(is_ada_url || is_aggregator);
11679|       |
11680|  59.0k|  const size_t len = input.size();
11681|  59.0k|  const auto* b = reinterpret_cast<const uint8_t*>(input.data());
11682|  59.0k|  size_t p = host_end + 1;
11683|  59.0k|  uint32_t port_value = 0;
11684|  59.0k|  bool any_digit = false;
11685|   255k|  while (p < len && b[p] >= '0' && b[p] <= '9') {
  ------------------
  |  Branch (11685:10): [True: 255k, False: 48]
  |  Branch (11685:21): [True: 196k, False: 58.7k]
  |  Branch (11685:36): [True: 196k, False: 246]
  ------------------
11686|   196k|    any_digit = true;
11687|   196k|    port_value = port_value * 10 + static_cast<uint32_t>(b[p] - '0');
11688|   196k|    if (port_value > 65535) [[unlikely]] {
  ------------------
  |  Branch (11688:9): [True: 19, False: 196k]
  ------------------
11689|     19|      return false;
11690|     19|    }
11691|   196k|    ++p;
11692|   196k|  }
11693|  59.0k|  if (p < len && b[p] != '/' && b[p] != '?' && b[p] != '#') [[unlikely]] {
  ------------------
  |  Branch (11693:7): [True: 58.9k, False: 48]
  |  Branch (11693:18): [True: 362, False: 58.6k]
  |  Branch (11693:33): [True: 280, False: 82]
  |  Branch (11693:48): [True: 220, False: 60]
  ------------------
11694|    220|    return false;
11695|    220|  }
11696|  58.7k|  uint32_t parsed_port = url_components::omitted;
11697|  58.7k|  const uint16_t default_port = ada::scheme::get_special_port(scheme_type);
11698|  58.7k|  if (any_digit && port_value != default_port) {
  ------------------
  |  Branch (11698:7): [True: 58.3k, False: 415]
  |  Branch (11698:20): [True: 58.3k, False: 4]
  ------------------
11699|  58.3k|    parsed_port = port_value;
11700|  58.3k|  }
11701|  58.7k|  const size_t authority_end = p;
11702|       |
11703|  58.7k|  size_t i = authority_end;
11704|  58.7k|  size_t path_start = host_end;
11705|  58.7k|  size_t path_end = host_end;
11706|  58.7k|  size_t query_start = std::string_view::npos;
11707|  58.7k|  size_t hash_start = std::string_view::npos;
11708|  58.7k|  bool has_path = false;
11709|  58.7k|  bool maybe_dot_segment = false;
11710|  58.7k|  bool rest_simple = true;
11711|       |
11712|  58.7k|  if (i < len && b[i] == '/') {
  ------------------
  |  Branch (11712:7): [True: 58.7k, False: 48]
  |  Branch (11712:18): [True: 58.6k, False: 142]
  ------------------
11713|  58.6k|    has_path = true;
11714|  58.6k|    path_start = i;
11715|  58.6k|    ++i;
11716|  58.6k|    scan_path_run(b, i, len, maybe_dot_segment);
11717|  58.6k|    if (i < len) {
  ------------------
  |  Branch (11717:9): [True: 3.20k, False: 55.3k]
  ------------------
11718|  3.20k|      const uint8_t cls = k_path[b[i]];
11719|  3.20k|      if (cls == 1) {
  ------------------
  |  Branch (11719:11): [True: 1.90k, False: 1.30k]
  ------------------
11720|  1.90k|        path_end = i;
11721|  1.90k|        if (b[i] == '?') {
  ------------------
  |  Branch (11721:13): [True: 1.48k, False: 419]
  ------------------
11722|  1.48k|          query_start = i;
11723|  1.48k|          ++i;
11724|  1.48k|          goto scan_query;
11725|  1.48k|        }
11726|    419|        hash_start = i;
11727|    419|        ++i;
11728|    419|        goto scan_hash;
11729|  1.90k|      }
11730|  1.30k|      rest_simple = false;
11731|  78.4k|      for (; i < len; ++i) {
  ------------------
  |  Branch (11731:14): [True: 77.9k, False: 543]
  ------------------
11732|  77.9k|        if (b[i] == '?') {
  ------------------
  |  Branch (11732:13): [True: 588, False: 77.3k]
  ------------------
11733|    588|          path_end = i;
11734|    588|          query_start = i;
11735|    588|          ++i;
11736|    588|          goto scan_query_boundary;
11737|    588|        }
11738|  77.3k|        if (b[i] == '#') {
  ------------------
  |  Branch (11738:13): [True: 171, False: 77.1k]
  ------------------
11739|    171|          path_end = i;
11740|    171|          hash_start = i;
11741|    171|          ++i;
11742|    171|          goto after_rest;
11743|    171|        }
11744|  77.3k|      }
11745|    543|      path_end = i;
11746|    543|      goto after_rest;
11747|  1.30k|    }
11748|  55.3k|    path_end = i;
11749|  55.3k|  } else if (i < len && b[i] == '?') {
  ------------------
  |  Branch (11749:14): [True: 142, False: 48]
  |  Branch (11749:25): [True: 82, False: 60]
  ------------------
11750|     82|    query_start = i;
11751|     82|    ++i;
11752|     82|    goto scan_query;
11753|    108|  } else if (i < len && b[i] == '#') {
  ------------------
  |  Branch (11753:14): [True: 60, False: 48]
  |  Branch (11753:25): [True: 60, False: 0]
  ------------------
11754|     60|    hash_start = i;
11755|     60|    ++i;
11756|     60|    goto scan_hash;
11757|     60|  }
11758|  55.4k|  goto after_rest;
11759|       |
11760|  55.4k|scan_query:
11761|  1.57k|  scan_query_run(b, i, len);
11762|  1.57k|  if (i < len) {
  ------------------
  |  Branch (11762:7): [True: 1.21k, False: 358]
  ------------------
11763|  1.21k|    if (b[i] == '#') {
  ------------------
  |  Branch (11763:9): [True: 1.15k, False: 61]
  ------------------
11764|  1.15k|      hash_start = i;
11765|  1.15k|      ++i;
11766|  1.15k|      goto scan_hash;
11767|  1.15k|    }
11768|     61|    rest_simple = false;
11769|     61|    goto scan_query_boundary;
11770|  1.21k|  }
11771|    358|  goto after_rest;
11772|       |
11773|    649|scan_query_boundary:
11774|  12.6k|  for (; i < len; ++i) {
  ------------------
  |  Branch (11774:10): [True: 12.4k, False: 230]
  ------------------
11775|  12.4k|    if (b[i] == '#') {
  ------------------
  |  Branch (11775:9): [True: 419, False: 12.0k]
  ------------------
11776|    419|      hash_start = i;
11777|    419|      ++i;
11778|    419|      goto after_rest;
11779|    419|    }
11780|  12.4k|  }
11781|    230|  goto after_rest;
11782|       |
11783|  1.63k|scan_hash:
11784|  1.63k|  scan_hash_run(b, i, len);
11785|  1.63k|  if (i < len) {
  ------------------
  |  Branch (11785:7): [True: 45, False: 1.58k]
  ------------------
11786|     45|    rest_simple = false;
11787|     45|  }
11788|       |
11789|  58.7k|after_rest:
11790|  58.7k|  if (rest_simple && maybe_dot_segment) {
  ------------------
  |  Branch (11790:7): [True: 57.3k, False: 1.40k]
  |  Branch (11790:22): [True: 357, False: 57.0k]
  ------------------
11791|    357|    const std::string_view path_body(input.data() + path_start,
11792|    357|                                     path_end - path_start);
11793|    357|    if (path_has_dot_segment(path_body)) {
  ------------------
  |  Branch (11793:9): [True: 310, False: 47]
  ------------------
11794|    310|      rest_simple = false;
11795|    310|    }
11796|    357|  }
11797|       |
11798|       |  // The slow path removes ASCII tab/newline anywhere in the input and trims a
11799|       |  // trailing C0 control or space; this fast path does neither. A query or
11800|       |  // fragment reaching the helpers below would keep those bytes percent-encoded
11801|       |  // ("?a\nb" -> "?a%0Ab", "#f " -> "#f%20") instead of stripped, so hand such
11802|       |  // inputs back to the slow path.
11803|  58.7k|  if (!rest_simple && (unicode::is_c0_control_or_space(input.back()) ||
  ------------------
  |  Branch (11803:7): [True: 1.71k, False: 57.0k]
  |  Branch (11803:24): [True: 19, False: 1.69k]
  ------------------
11804|  1.69k|                       unicode::has_tabs_or_newline(input))) {
  ------------------
  |  Branch (11804:24): [True: 34, False: 1.66k]
  ------------------
11805|     53|    return false;
11806|     53|  }
11807|       |
11808|  58.7k|  out.type = scheme_type;
11809|  58.7k|  out.is_valid = true;
11810|  58.7k|  out.has_opaque_path = false;
11811|  58.7k|  out.host_type = DEFAULT;
11812|       |
11813|  58.7k|  const uint32_t port_bytes = (parsed_port != url_components::omitted)
  ------------------
  |  Branch (11813:31): [True: 58.3k, False: 394]
  ------------------
11814|  58.7k|                                  ? (1 + port_decimal_digit_count(parsed_port))
11815|  58.7k|                                  : 0;
11816|       |
11817|  58.7k|  if (!rest_simple) {
  ------------------
  |  Branch (11817:7): [True: 1.66k, False: 57.0k]
  ------------------
11818|  1.66k|    const std::string_view path_view =
11819|  1.66k|        has_path
  ------------------
  |  Branch (11819:9): [True: 1.63k, False: 35]
  ------------------
11820|  1.66k|            ? std::string_view(input.data() + path_start, path_end - path_start)
11821|  1.66k|            : std::string_view{};
11822|  1.66k|    auto apply_query_and_hash = [&]() {
11823|  1.66k|      if (query_start != std::string_view::npos) {
11824|  1.66k|        const size_t q_end =
11825|  1.66k|            (hash_start != std::string_view::npos) ? hash_start : len;
11826|  1.66k|        out.update_base_search(std::string_view(input.data() + query_start + 1,
11827|  1.66k|                                                q_end - query_start - 1),
11828|  1.66k|                               character_sets::SPECIAL_QUERY_PERCENT_ENCODE);
11829|  1.66k|      }
11830|  1.66k|      if (hash_start != std::string_view::npos) {
11831|  1.66k|        out.update_unencoded_base_hash(std::string_view(
11832|  1.66k|            input.data() + hash_start + 1, len - hash_start - 1));
11833|  1.66k|      }
11834|  1.66k|    };
11835|  1.66k|    if constexpr (is_aggregator) {
11836|  1.66k|      out.buffer.assign(input.substr(0, host_end));
11837|  1.66k|      if (parsed_port != url_components::omitted) {
  ------------------
  |  Branch (11837:11): [True: 1.32k, False: 344]
  ------------------
11838|  1.32k|        append_canonical_port(out.buffer, parsed_port);
11839|  1.32k|      }
11840|  1.66k|      if (has_upper) {
  ------------------
  |  Branch (11840:11): [True: 91, False: 1.57k]
  ------------------
11841|     91|        unicode::to_lower_ascii(out.buffer.data() + host_start, host_len);
11842|     91|      }
11843|  1.66k|      out.components.protocol_end = protocol_end;
11844|  1.66k|      out.components.username_end = protocol_end + 2;
11845|  1.66k|      out.components.host_start = protocol_end + 2;
11846|  1.66k|      out.components.host_end = static_cast<uint32_t>(host_end);
11847|  1.66k|      out.components.port = parsed_port;
11848|  1.66k|      out.components.pathname_start = static_cast<uint32_t>(out.buffer.size());
11849|  1.66k|      out.components.search_start = url_components::omitted;
11850|  1.66k|      out.components.hash_start = url_components::omitted;
11851|  1.66k|      out.parse_path(path_view);
11852|  1.66k|      apply_query_and_hash();
11853|       |    } else {
11854|       |      std::string host_str(input.substr(host_start, host_len));
11855|       |      if (has_upper) {
11856|       |        unicode::to_lower_ascii(host_str.data(), host_str.size());
11857|       |      }
11858|       |      out.host = std::move(host_str);
11859|       |      if (parsed_port != url_components::omitted) {
11860|       |        out.port = static_cast<uint16_t>(parsed_port);
11861|       |      }
11862|       |      out.parse_path(path_view);
11863|       |      apply_query_and_hash();
11864|       |    }
11865|  1.66k|    return true;
11866|  1.66k|  }
11867|       |
11868|  57.0k|  const bool insert_slash = !has_path;
11869|  57.0k|  if constexpr (is_aggregator) {
11870|  57.0k|    const size_t out_len =
11871|  57.0k|        host_end + port_bytes + (insert_slash ? 1 : 0) + (len - authority_end);
  ------------------
  |  Branch (11871:34): [True: 143, False: 56.9k]
  ------------------
11872|  57.0k|    const bool omit_port_bytes = parsed_port == url_components::omitted;
11873|  57.0k|    if (out_len == len && !insert_slash && !omit_port_bytes) {
  ------------------
  |  Branch (11873:9): [True: 47.7k, False: 9.30k]
  |  Branch (11873:27): [True: 47.7k, False: 26]
  |  Branch (11873:44): [True: 47.7k, False: 0]
  ------------------
11874|  47.7k|      out.buffer.assign(input);
11875|  47.7k|    } else {
11876|  9.32k|      out.buffer.clear();
11877|  9.32k|      out.buffer.reserve(out_len);
11878|  9.32k|      out.buffer.append(input.substr(0, host_end));
11879|  9.32k|      if (parsed_port != url_components::omitted) {
  ------------------
  |  Branch (11879:11): [True: 9.27k, False: 50]
  ------------------
11880|  9.27k|        append_canonical_port(out.buffer, parsed_port);
11881|  9.27k|      }
11882|  9.32k|      if (insert_slash) {
  ------------------
  |  Branch (11882:11): [True: 143, False: 9.18k]
  ------------------
11883|    143|        out.buffer.push_back('/');
11884|    143|      }
11885|  9.32k|      if (authority_end < len) {
  ------------------
  |  Branch (11885:11): [True: 9.27k, False: 48]
  ------------------
11886|  9.27k|        out.buffer.append(input.substr(authority_end));
11887|  9.27k|      }
11888|  9.32k|    }
11889|  57.0k|    if (has_upper) {
  ------------------
  |  Branch (11889:9): [True: 39, False: 57.0k]
  ------------------
11890|     39|      unicode::to_lower_ascii(out.buffer.data() + host_start, host_len);
11891|     39|    }
11892|  57.0k|    const uint32_t pathname_start =
11893|  57.0k|        static_cast<uint32_t>(host_end) + port_bytes;
11894|  57.0k|    const int32_t tail_delta = static_cast<int32_t>(pathname_start) +
11895|  57.0k|                               (insert_slash ? 1 : 0) -
  ------------------
  |  Branch (11895:33): [True: 143, False: 56.9k]
  ------------------
11896|  57.0k|                               static_cast<int32_t>(authority_end);
11897|  57.0k|    out.components.protocol_end = protocol_end;
11898|  57.0k|    out.components.username_end = protocol_end + 2;
11899|  57.0k|    out.components.host_start = protocol_end + 2;
11900|  57.0k|    out.components.host_end = static_cast<uint32_t>(host_end);
11901|  57.0k|    out.components.port = parsed_port;
11902|  57.0k|    out.components.pathname_start = pathname_start;
11903|  57.0k|    out.components.search_start =
11904|  57.0k|        (query_start != std::string_view::npos)
  ------------------
  |  Branch (11904:9): [True: 1.38k, False: 55.6k]
  ------------------
11905|  57.0k|            ? static_cast<uint32_t>(static_cast<int32_t>(query_start) +
11906|  1.38k|                                    tail_delta)
11907|  57.0k|            : url_components::omitted;
11908|  57.0k|    out.components.hash_start =
11909|  57.0k|        (hash_start != std::string_view::npos)
  ------------------
  |  Branch (11909:9): [True: 1.45k, False: 55.6k]
  ------------------
11910|  57.0k|            ? static_cast<uint32_t>(static_cast<int32_t>(hash_start) +
11911|  1.45k|                                    tail_delta)
11912|  57.0k|            : url_components::omitted;
11913|       |  } else {
11914|       |    std::string host_str(input.substr(host_start, host_len));
11915|       |    if (has_upper) {
11916|       |      unicode::to_lower_ascii(host_str.data(), host_str.size());
11917|       |    }
11918|       |    out.host = std::move(host_str);
11919|       |    if (parsed_port != url_components::omitted) {
11920|       |      out.port = static_cast<uint16_t>(parsed_port);
11921|       |    }
11922|       |    if (insert_slash) {
11923|       |      out.path = "/";
11924|       |    } else {
11925|       |      out.path.assign(input.data() + path_start, path_end - path_start);
11926|       |    }
11927|       |    if (query_start != std::string_view::npos) {
11928|       |      const size_t q_end =
11929|       |          (hash_start != std::string_view::npos) ? hash_start : len;
11930|       |      out.query.emplace(input.data() + query_start + 1,
11931|       |                        q_end - query_start - 1);
11932|       |    }
11933|       |    if (hash_start != std::string_view::npos) {
11934|       |      out.hash.emplace(input.data() + hash_start + 1, len - hash_start - 1);
11935|       |    }
11936|       |  }
11937|  57.0k|  return true;
11938|  58.7k|}
_ZN3ada6parser14parse_url_implINS_3urlELb1EEET_NSt3__117basic_string_viewIcNS4_11char_traitsIcEEEEPKS3_:
12517|   604k|                           const result_type* base_url) {
12518|       |  // We can specialize the implementation per type.
12519|       |  // Important: result_type_is_ada_url is evaluated at *compile time*. This
12520|       |  // means that doing if constexpr(result_type_is_ada_url) { something } else {
12521|       |  // something else } is free (at runtime). This means that ada::url_aggregator
12522|       |  // and ada::url **do not have to support the exact same API**.
12523|   604k|  constexpr bool result_type_is_ada_url = std::is_same_v<url, result_type>;
12524|   604k|  constexpr bool result_type_is_ada_url_aggregator =
12525|   604k|      std::is_same_v<url_aggregator, result_type>;
12526|   604k|  static_assert(result_type_is_ada_url ||
12527|   604k|                result_type_is_ada_url_aggregator);  // We don't support
12528|       |                                                     // anything else for now.
12529|       |
12530|   604k|  ada_log("ada::parser::parse_url('", user_input, "' [", user_input.size(),
12531|   604k|          " bytes],", (base_url != nullptr ? base_url->to_string() : "null"),
12532|   604k|          ")");
12533|       |
12534|   604k|  result_type url{};
12535|       |
12536|   604k|  const uint32_t max_input_length = ada::get_max_input_length();
12537|       |
12538|       |  // Normalization (percent-encoding, IDNA) can push the serialized URL past
12539|       |  // max_input_length even when the input fit under it. The check at the end of
12540|       |  // the state machine covers URLs that run to completion, but several states
12541|       |  // return early after appending a query or fragment, so run the same check on
12542|       |  // those exits too. Without this, a query- or fragment-terminated URL such as
12543|       |  // file://x/?<...> or https://user@x/?<...> is accepted while the equivalent
12544|       |  // https://x/?<...> that takes the absolute fast path is rejected.
12545|   604k|  const auto enforce_max_input_length = [&]() {
12546|   604k|    if constexpr (store_values) {
12547|   604k|      if (url.is_valid) {
12548|   604k|        if constexpr (result_type_is_ada_url_aggregator) {
12549|   604k|          if (url.buffer.size() > max_input_length) [[unlikely]] {
12550|   604k|            url.is_valid = false;
12551|   604k|          }
12552|   604k|        } else {
12553|   604k|          if (url.get_href_size() > max_input_length) [[unlikely]] {
12554|   604k|            url.is_valid = false;
12555|   604k|          }
12556|   604k|        }
12557|   604k|      }
12558|   604k|    }
12559|   604k|  };
12560|       |
12561|       |  // We refuse to parse URL strings that exceed the maximum input length.
12562|       |  // By default, this is 4GB but can be configured via
12563|       |  // ada::set_max_input_length().
12564|   604k|  if (user_input.size() > max_input_length) [[unlikely]] {
  ------------------
  |  Branch (12564:7): [True: 0, False: 604k]
  ------------------
12565|      0|    url.is_valid = false;
12566|      0|  }
12567|       |  // Going forward, user_input.size() is in [0,
12568|       |  // std::numeric_limits<uint32_t>::max). If we are provided with an invalid
12569|       |  // base, or the optional_url was invalid, we must return.
12570|   604k|  if (base_url != nullptr) {
  ------------------
  |  Branch (12570:7): [True: 0, False: 604k]
  ------------------
12571|      0|    url.is_valid &= base_url->is_valid;
12572|      0|  }
12573|   604k|  if (!url.is_valid) {
  ------------------
  |  Branch (12573:7): [True: 0, False: 604k]
  ------------------
12574|      0|    return url;
12575|      0|  }
12576|       |
12577|       |  // Simple absolute / relative fast paths (before tabs/newline scan).
12578|   604k|  if constexpr (store_values) {
12579|   604k|    bool hit_fast_path = false;
12580|   604k|    if (base_url == nullptr) {
  ------------------
  |  Branch (12580:9): [True: 604k, False: 0]
  ------------------
12581|       |      // IPv4/IPv6 and userinfo miss the fast path. Skip the never_inline
12582|       |      // call so those URLs (including SetHref) do not pay for a miss.
12583|   604k|      const auto* p = reinterpret_cast<const uint8_t*>(user_input.data());
12584|   604k|      const size_t n = user_input.size();
12585|   604k|      size_t host_start = 0;
12586|   604k|      if (n >= 8 && p[4] == ':' && p[5] == '/' && p[6] == '/') {
  ------------------
  |  Branch (12586:11): [True: 604k, False: 181]
  |  Branch (12586:21): [True: 232k, False: 372k]
  |  Branch (12586:36): [True: 231k, False: 828]
  |  Branch (12586:51): [True: 231k, False: 153]
  ------------------
12587|   231k|        host_start = 7;
12588|   373k|      } else if (n >= 9 && p[5] == ':' && p[6] == '/' && p[7] == '/') {
  ------------------
  |  Branch (12588:18): [True: 373k, False: 190]
  |  Branch (12588:28): [True: 370k, False: 2.60k]
  |  Branch (12588:43): [True: 370k, False: 834]
  |  Branch (12588:58): [True: 370k, False: 93]
  ------------------
12589|   370k|        host_start = 8;
12590|   370k|      }
12591|   604k|      const uint8_t host_first = host_start != 0 ? p[host_start] : 0;
  ------------------
  |  Branch (12591:34): [True: 601k, False: 3.72k]
  ------------------
12592|   604k|      const bool skip_ip =
12593|   604k|          host_first == '[' || (host_first >= '0' && host_first <= '9');
  ------------------
  |  Branch (12593:11): [True: 553, False: 604k]
  |  Branch (12593:33): [True: 597k, False: 6.80k]
  |  Branch (12593:54): [True: 135k, False: 462k]
  ------------------
12594|   604k|      const bool skip_userinfo =
12595|   604k|          host_start != 0 && authority_has_at(p, host_start, n);
  ------------------
  |  Branch (12595:11): [True: 601k, False: 3.72k]
  |  Branch (12595:30): [True: 38.5k, False: 562k]
  ------------------
12596|   604k|      hit_fast_path = !skip_ip && !skip_userinfo &&
  ------------------
  |  Branch (12596:23): [True: 468k, False: 136k]
  |  Branch (12596:35): [True: 430k, False: 38.5k]
  ------------------
12597|   430k|                      try_parse_simple_absolute(user_input, url);
  ------------------
  |  Branch (12597:23): [True: 343k, False: 87.1k]
  ------------------
12598|   604k|    } else {
12599|      0|      hit_fast_path = try_parse_simple_relative(user_input, *base_url, url);
12600|      0|    }
12601|   604k|    if (hit_fast_path) {
  ------------------
  |  Branch (12601:9): [True: 343k, False: 261k]
  ------------------
12602|       |      if constexpr (result_type_is_ada_url_aggregator) {
12603|       |        if (url.buffer.size() > max_input_length) [[unlikely]] {
12604|       |          url.is_valid = false;
12605|       |        }
12606|   343k|      } else {
12607|       |        // For a small absolute input, even worst-case normalization cannot
12608|       |        // exceed the limit: percent encoding expands at most 3x and IDNA at
12609|       |        // most 4.5x. Avoid traversing every stored component on the common
12610|       |        // default-limit path.
12611|   343k|        if ((base_url != nullptr ||
  ------------------
  |  Branch (12611:14): [True: 0, False: 343k]
  ------------------
12612|   343k|             user_input.size() > static_cast<size_t>(max_input_length) / 5) &&
  ------------------
  |  Branch (12612:14): [True: 0, False: 343k]
  ------------------
12613|      0|            url.get_href_size() > max_input_length) [[unlikely]] {
  ------------------
  |  Branch (12613:13): [True: 0, False: 0]
  ------------------
12614|      0|          url.is_valid = false;
12615|      0|        }
12616|   343k|      }
12617|   343k|      return url;
12618|   343k|    }
12619|   604k|  }
12620|       |
12621|   261k|  state state = state::SCHEME_START;
12622|       |
12623|   604k|  std::string tmp_buffer;
12624|   604k|  std::string_view url_data;
12625|   604k|  if (unicode::has_tabs_or_newline(user_input)) [[unlikely]] {
  ------------------
  |  Branch (12625:7): [True: 474, False: 604k]
  ------------------
12626|    474|    tmp_buffer = user_input;
12627|       |    // Optimization opportunity: Instead of copying and then pruning, we could
12628|       |    // just directly build the string from user_input.
12629|    474|    helpers::remove_ascii_tab_or_newline(tmp_buffer);
12630|    474|    url_data = tmp_buffer;
12631|   604k|  } else [[likely]] {
12632|   604k|    url_data = user_input;
12633|   604k|  }
12634|       |
12635|       |  // Leading and trailing control characters are uncommon and easy to deal with
12636|       |  // (no performance concern).
12637|   604k|  helpers::trim_c0_whitespace(url_data);
12638|       |
12639|       |  if constexpr (result_type_is_ada_url_aggregator && store_values) {
12640|       |    // Most of the time, we just need user_input.size().
12641|       |    // In some instances, we may need a bit more.
12642|       |    ///////////////////////////
12643|       |    // This is *very* important. This line should *not* be removed
12644|       |    // hastily. There are principled reasons why reserve is important
12645|       |    // for performance. If you have a benchmark with small inputs,
12646|       |    // it may not matter, but in other instances, it could.
12647|       |    ////
12648|       |    // This rounds up to the next power of two.
12649|       |    // We know that user_input.size() is in [0,
12650|       |    // std::numeric_limits<uint32_t>::max).
12651|       |    uint32_t reserve_capacity =
12652|       |        (0xFFFFFFFF >>
12653|       |         helpers::leading_zeroes(uint32_t(1 | user_input.size()))) +
12654|       |        1;
12655|       |    url.reserve(reserve_capacity);
12656|       |  }
12657|       |
12658|       |  // Optimization opportunity. Most websites do not have fragment.
12659|   604k|  std::optional<std::string_view> fragment = helpers::prune_hash(url_data);
12660|       |  // We add it last so that an implementation like ada::url_aggregator
12661|       |  // can append it last to its internal buffer, thus improving performance.
12662|       |
12663|       |  // Here url_data no longer has its fragment.
12664|       |  // We are going to access the data from url_data (it is immutable).
12665|       |  // At any given time, we are pointing at byte 'input_position' in url_data.
12666|       |  // The input_position variable should range from 0 to input_size.
12667|       |  // It is illegal to access url_data at input_size.
12668|   604k|  size_t input_position = 0;
12669|   604k|  const size_t input_size = url_data.size();
12670|       |  // Keep running the following state machine by switching on state.
12671|       |  // If after a run pointer points to the EOF code point, go to the next step.
12672|       |  // Otherwise, increase pointer by 1 and continue with the state machine.
12673|       |  // We never decrement input_position.
12674|  2.30M|  while (input_position <= input_size) {
  ------------------
  |  Branch (12674:10): [True: 1.76M, False: 543k]
  ------------------
12675|  1.76M|    ada_log("In parsing at ", input_position, " out of ", input_size,
12676|  1.76M|            " in state ", ada::to_string(state));
12677|  1.76M|    switch (state) {
12678|   261k|      case state::SCHEME_START: {
  ------------------
  |  Branch (12678:7): [True: 261k, False: 1.50M]
  ------------------
12679|   261k|        ada_log("SCHEME_START ", helpers::substring(url_data, input_position));
12680|       |        // If c is an ASCII alpha, append c, lowercased, to buffer, and set
12681|       |        // state to scheme state.
12682|   261k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12682:13): [True: 261k, False: 3]
  ------------------
12683|   261k|            checkers::is_alpha(url_data[input_position])) {
  ------------------
  |  Branch (12683:13): [True: 261k, False: 127]
  ------------------
12684|   261k|          state = state::SCHEME;
12685|   261k|          input_position++;
12686|   261k|        } else {
12687|       |          // Otherwise, if state override is not given, set state to no scheme
12688|       |          // state and decrease pointer by 1.
12689|    130|          state = state::NO_SCHEME;
12690|    130|        }
12691|   261k|        break;
12692|      0|      }
12693|   261k|      case state::SCHEME: {
  ------------------
  |  Branch (12693:7): [True: 261k, False: 1.50M]
  ------------------
12694|   261k|        ada_log("SCHEME ", helpers::substring(url_data, input_position));
12695|       |        // If c is an ASCII alphanumeric, U+002B (+), U+002D (-), or U+002E (.),
12696|       |        // append c, lowercased, to buffer.
12697|  1.13M|        while ((input_position != input_size) &&
  ------------------
  |  Branch (12697:16): [True: 1.13M, False: 4]
  ------------------
12698|  1.13M|               (unicode::is_alnum_plus(url_data[input_position]))) {
  ------------------
  |  Branch (12698:16): [True: 874k, False: 261k]
  ------------------
12699|   874k|          input_position++;
12700|   874k|        }
12701|       |        // Otherwise, if c is U+003A (:), then:
12702|   261k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12702:13): [True: 261k, False: 4]
  ------------------
12703|   261k|            (url_data[input_position] == ':')) {
  ------------------
  |  Branch (12703:13): [True: 261k, False: 81]
  ------------------
12704|   261k|          ada_log("SCHEME the scheme should be ",
12705|   261k|                  url_data.substr(0, input_position));
12706|   261k|          if constexpr (result_type_is_ada_url) {
12707|   261k|            if (!url.parse_scheme(url_data.substr(0, input_position))) {
  ------------------
  |  Branch (12707:17): [True: 0, False: 261k]
  ------------------
12708|      0|              return url;
12709|      0|            }
12710|       |          } else {
12711|       |            // we pass the colon along instead of painfully adding it back.
12712|       |            if (!url.parse_scheme_with_colon(
12713|       |                    url_data.substr(0, input_position + 1))) {
12714|       |              return url;
12715|       |            }
12716|       |          }
12717|   261k|          ada_log("SCHEME the scheme is ", url.get_protocol());
12718|       |
12719|       |          // If url's scheme is "file", then:
12720|       |          // NOLINTNEXTLINE(bugprone-branch-clone)
12721|   261k|          if (url.type == scheme::type::FILE) {
  ------------------
  |  Branch (12721:15): [True: 1.57k, False: 260k]
  ------------------
12722|       |            // Set state to file state.
12723|  1.57k|            state = state::FILE;
12724|  1.57k|          }
12725|       |          // Otherwise, if url is special, base is non-null, and base's scheme
12726|       |          // is url's scheme: Note: Doing base_url->scheme is unsafe if base_url
12727|       |          // != nullptr is false.
12728|   260k|          else if (url.is_special() && base_url != nullptr &&
  ------------------
  |  Branch (12728:20): [True: 258k, False: 1.88k]
  |  Branch (12728:40): [True: 0, False: 258k]
  ------------------
12729|      0|                   base_url->type == url.type) {
  ------------------
  |  Branch (12729:20): [True: 0, False: 0]
  ------------------
12730|       |            // Set state to special relative or authority state.
12731|      0|            state = state::SPECIAL_RELATIVE_OR_AUTHORITY;
12732|      0|          }
12733|       |          // Otherwise, if url is special, set state to special authority
12734|       |          // slashes state.
12735|   260k|          else if (url.is_special()) {
  ------------------
  |  Branch (12735:20): [True: 258k, False: 1.88k]
  ------------------
12736|   258k|            state = state::SPECIAL_AUTHORITY_SLASHES;
12737|   258k|          }
12738|       |          // Otherwise, if remaining starts with an U+002F (/), set state to
12739|       |          // path or authority state and increase pointer by 1.
12740|  1.88k|          else if (input_position + 1 < input_size &&
  ------------------
  |  Branch (12740:20): [True: 1.72k, False: 159]
  ------------------
12741|  1.72k|                   url_data[input_position + 1] == '/') {
  ------------------
  |  Branch (12741:20): [True: 1.16k, False: 564]
  ------------------
12742|  1.16k|            state = state::PATH_OR_AUTHORITY;
12743|  1.16k|            input_position++;
12744|  1.16k|          }
12745|       |          // Otherwise, set url's path to the empty string and set state to
12746|       |          // opaque path state.
12747|    723|          else {
12748|    723|            state = state::OPAQUE_PATH;
12749|    723|          }
12750|   261k|        }
12751|       |        // Otherwise, if state override is not given, set buffer to the empty
12752|       |        // string, state to no scheme state, and start over (from the first code
12753|       |        // point in input).
12754|     85|        else {
12755|     85|          state = state::NO_SCHEME;
12756|     85|          input_position = 0;
12757|     85|          break;
12758|     85|        }
12759|   261k|        input_position++;
12760|   261k|        break;
12761|   261k|      }
12762|    215|      case state::NO_SCHEME: {
  ------------------
  |  Branch (12762:7): [True: 215, False: 1.76M]
  ------------------
12763|    215|        ada_log("NO_SCHEME ", helpers::substring(url_data, input_position));
12764|       |        // The fragment was pruned from url_data before the state machine ran,
12765|       |        // so 'c is U+0023 (#)' holds exactly when a fragment was found and
12766|       |        // nothing else remains in front of it.
12767|    215|        const bool c_is_hash =
12768|    215|            fragment.has_value() && input_position == input_size;
  ------------------
  |  Branch (12768:13): [True: 140, False: 75]
  |  Branch (12768:37): [True: 3, False: 137]
  ------------------
12769|       |        // If base is null, or base has an opaque path and c is not U+0023 (#),
12770|       |        // validation error, return failure.
12771|    215|        if (base_url == nullptr || (base_url->has_opaque_path && !c_is_hash)) {
  ------------------
  |  Branch (12771:13): [True: 215, False: 0]
  |  Branch (12771:37): [True: 0, False: 0]
  |  Branch (12771:66): [True: 0, False: 0]
  ------------------
12772|    215|          ada_log("NO_SCHEME validation error");
12773|    215|          url.is_valid = false;
12774|    215|          return url;
12775|    215|        }
12776|       |        // Otherwise, if base has an opaque path and c is U+0023 (#),
12777|       |        // set url's scheme to base's scheme, url's path to base's path, url's
12778|       |        // query to base's query, and set state to fragment state.
12779|      0|        else if (base_url->has_opaque_path && c_is_hash) {
  ------------------
  |  Branch (12779:18): [True: 0, False: 0]
  |  Branch (12779:47): [True: 0, False: 0]
  ------------------
12780|      0|          ada_log("NO_SCHEME opaque base with fragment");
12781|      0|          url.copy_scheme(*base_url);
12782|      0|          url.has_opaque_path = base_url->has_opaque_path;
12783|       |
12784|      0|          if constexpr (result_type_is_ada_url) {
12785|      0|            url.path = base_url->path;
12786|      0|            url.query = base_url->query;
12787|       |          } else {
12788|       |            url.update_base_pathname(base_url->get_pathname());
12789|       |            if (base_url->has_search()) {
12790|       |              // get_search() returns "" for an empty query string (URL ends
12791|       |              // with '?'). update_base_search("") would incorrectly clear the
12792|       |              // query, so pass "?" to preserve the empty query distinction.
12793|       |              auto s = base_url->get_search();
12794|       |              url.update_base_search(s.empty() ? std::string_view("?") : s);
12795|       |            }
12796|       |          }
12797|      0|          url.update_unencoded_base_hash(*fragment);
12798|      0|          enforce_max_input_length();
12799|      0|          return url;
12800|      0|        }
12801|       |        // Otherwise, if base's scheme is not "file", set state to relative
12802|       |        // state and decrease pointer by 1.
12803|       |        // NOLINTNEXTLINE(bugprone-branch-clone)
12804|      0|        else if (base_url->type != scheme::type::FILE) {
  ------------------
  |  Branch (12804:18): [True: 0, False: 0]
  ------------------
12805|      0|          ada_log("NO_SCHEME non-file relative path");
12806|      0|          state = state::RELATIVE_SCHEME;
12807|      0|        }
12808|       |        // Otherwise, set state to file state and decrease pointer by 1.
12809|      0|        else {
12810|      0|          ada_log("NO_SCHEME file base type");
12811|      0|          state = state::FILE;
12812|      0|        }
12813|      0|        break;
12814|    215|      }
12815|   258k|      case state::AUTHORITY: {
  ------------------
  |  Branch (12815:7): [True: 258k, False: 1.50M]
  ------------------
12816|   258k|        ada_log("AUTHORITY ", helpers::substring(url_data, input_position));
12817|       |        // most URLs have no @. Having no @ tells us that we don't have to worry
12818|       |        // about AUTHORITY. Of course, we could have @ and still not have to
12819|       |        // worry about AUTHORITY.
12820|       |        // TODO: Instead of just collecting a bool, collect the location of the
12821|       |        // '@' and do something useful with it.
12822|       |        // TODO: We could do various processing early on, using a single pass
12823|       |        // over the string to collect information about it, e.g., telling us
12824|       |        // whether there is a @ and if so, where (or how many).
12825|       |
12826|       |        // Check if url data contains an @.
12827|   258k|        if (url_data.find('@', input_position) == std::string_view::npos) {
  ------------------
  |  Branch (12827:13): [True: 219k, False: 39.7k]
  ------------------
12828|   219k|          state = state::HOST;
12829|   219k|          break;
12830|   219k|        }
12831|  39.7k|        bool at_sign_seen{false};
12832|  39.7k|        bool password_token_seen{false};
12833|       |        /**
12834|       |         * We expect something of the sort...
12835|       |         * https://user:pass@example.com:1234/foo/bar?baz#quux
12836|       |         * --------^
12837|       |         */
12838|  92.6k|        do {
12839|  92.6k|          std::string_view view = url_data.substr(input_position);
12840|       |          // The delimiters are @, /, ? \\.
12841|  92.6k|          size_t location =
12842|  92.6k|              url.is_special() ? helpers::find_authority_delimiter_special(view)
  ------------------
  |  Branch (12842:15): [True: 92.4k, False: 206]
  ------------------
12843|  92.6k|                               : helpers::find_authority_delimiter(view);
12844|  92.6k|          std::string_view authority_view = view.substr(0, location);
12845|  92.6k|          size_t end_of_authority = input_position + authority_view.size();
12846|       |          // If c is U+0040 (@), then:
12847|  92.6k|          if ((end_of_authority != input_size) &&
  ------------------
  |  Branch (12847:15): [True: 82.9k, False: 9.67k]
  ------------------
12848|  82.9k|              (url_data[end_of_authority] == '@')) {
  ------------------
  |  Branch (12848:15): [True: 52.9k, False: 30.0k]
  ------------------
12849|       |            // If atSignSeen is true, then prepend "%40" to buffer.
12850|  52.9k|            if (at_sign_seen) {
  ------------------
  |  Branch (12850:17): [True: 13.4k, False: 39.4k]
  ------------------
12851|  13.4k|              if (password_token_seen) {
  ------------------
  |  Branch (12851:19): [True: 3.86k, False: 9.56k]
  ------------------
12852|  3.86k|                if constexpr (result_type_is_ada_url) {
12853|  3.86k|                  url.password += "%40";
12854|       |                } else {
12855|       |                  url.append_base_password("%40");
12856|       |                }
12857|  9.56k|              } else {
12858|  9.56k|                if constexpr (result_type_is_ada_url) {
12859|  9.56k|                  url.username += "%40";
12860|       |                } else {
12861|       |                  url.append_base_username("%40");
12862|       |                }
12863|  9.56k|              }
12864|  13.4k|            }
12865|       |
12866|  52.9k|            at_sign_seen = true;
12867|       |
12868|  52.9k|            if (!password_token_seen) {
  ------------------
  |  Branch (12868:17): [True: 49.0k, False: 3.86k]
  ------------------
12869|  49.0k|              size_t password_token_location = authority_view.find(':');
12870|  49.0k|              password_token_seen =
12871|  49.0k|                  password_token_location != std::string_view::npos;
12872|       |
12873|  49.0k|              if constexpr (store_values) {
12874|  49.0k|                if (!password_token_seen) {
  ------------------
  |  Branch (12874:21): [True: 20.0k, False: 29.0k]
  ------------------
12875|  20.0k|                  if constexpr (result_type_is_ada_url) {
12876|  20.0k|                    url.username += unicode::percent_encode(
12877|  20.0k|                        authority_view,
12878|  20.0k|                        character_sets::USERINFO_PERCENT_ENCODE);
12879|       |                  } else {
12880|       |                    url.append_base_username(unicode::percent_encode(
12881|       |                        authority_view,
12882|       |                        character_sets::USERINFO_PERCENT_ENCODE));
12883|       |                  }
12884|  29.0k|                } else {
12885|  29.0k|                  if constexpr (result_type_is_ada_url) {
12886|  29.0k|                    url.username += unicode::percent_encode(
12887|  29.0k|                        authority_view.substr(0, password_token_location),
12888|  29.0k|                        character_sets::USERINFO_PERCENT_ENCODE);
12889|  29.0k|                    url.password += unicode::percent_encode(
12890|  29.0k|                        authority_view.substr(password_token_location + 1),
12891|  29.0k|                        character_sets::USERINFO_PERCENT_ENCODE);
12892|       |                  } else {
12893|       |                    url.append_base_username(unicode::percent_encode(
12894|       |                        authority_view.substr(0, password_token_location),
12895|       |                        character_sets::USERINFO_PERCENT_ENCODE));
12896|       |                    url.append_base_password(unicode::percent_encode(
12897|       |                        authority_view.substr(password_token_location + 1),
12898|       |                        character_sets::USERINFO_PERCENT_ENCODE));
12899|       |                  }
12900|  29.0k|                }
12901|  49.0k|              }
12902|  49.0k|            } else if constexpr (store_values) {
12903|  3.86k|              if constexpr (result_type_is_ada_url) {
12904|  3.86k|                url.password += unicode::percent_encode(
12905|  3.86k|                    authority_view, character_sets::USERINFO_PERCENT_ENCODE);
12906|       |              } else {
12907|       |                url.append_base_password(unicode::percent_encode(
12908|       |                    authority_view, character_sets::USERINFO_PERCENT_ENCODE));
12909|       |              }
12910|  3.86k|            }
12911|  52.9k|          }
12912|       |          // Otherwise, if one of the following is true:
12913|       |          // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
12914|       |          // - url is special and c is U+005C (\)
12915|  39.7k|          else if (end_of_authority == input_size ||
  ------------------
  |  Branch (12915:20): [True: 9.67k, False: 30.0k]
  ------------------
12916|  30.0k|                   url_data[end_of_authority] == '/' ||
  ------------------
  |  Branch (12916:20): [True: 29.8k, False: 163]
  ------------------
12917|    163|                   url_data[end_of_authority] == '?' ||
  ------------------
  |  Branch (12917:20): [True: 128, False: 35]
  ------------------
12918|  39.7k|                   (url.is_special() && url_data[end_of_authority] == '\\')) {
  ------------------
  |  Branch (12918:21): [True: 35, False: 0]
  |  Branch (12918:41): [True: 35, False: 0]
  ------------------
12919|       |            // If atSignSeen is true and authority_view is the empty string,
12920|       |            // validation error, return failure.
12921|  39.7k|            if (at_sign_seen && authority_view.empty()) {
  ------------------
  |  Branch (12921:17): [True: 39.4k, False: 245]
  |  Branch (12921:33): [True: 219, False: 39.2k]
  ------------------
12922|    219|              url.is_valid = false;
12923|    219|              return url;
12924|    219|            }
12925|  39.5k|            state = state::HOST;
12926|  39.5k|            break;
12927|  39.7k|          }
12928|  52.9k|          if (end_of_authority == input_size) {
  ------------------
  |  Branch (12928:15): [True: 0, False: 52.9k]
  ------------------
12929|      0|            if constexpr (store_values) {
12930|      0|              if (fragment.has_value()) {
  ------------------
  |  Branch (12930:19): [True: 0, False: 0]
  ------------------
12931|      0|                url.update_unencoded_base_hash(*fragment);
12932|      0|              }
12933|      0|            }
12934|      0|            enforce_max_input_length();
12935|      0|            return url;
12936|      0|          }
12937|  52.9k|          input_position = end_of_authority + 1;
12938|  52.9k|        } while (true);
  ------------------
  |  Branch (12938:18): [True: 52.9k, Folded]
  ------------------
12939|       |
12940|  39.5k|        break;
12941|  39.7k|      }
12942|  39.5k|      case state::SPECIAL_RELATIVE_OR_AUTHORITY: {
  ------------------
  |  Branch (12942:7): [True: 0, False: 1.76M]
  ------------------
12943|      0|        ada_log("SPECIAL_RELATIVE_OR_AUTHORITY ",
12944|      0|                helpers::substring(url_data, input_position));
12945|       |
12946|       |        // If c is U+002F (/) and remaining starts with U+002F (/),
12947|       |        // then set state to special authority ignore slashes state and increase
12948|       |        // pointer by 1.
12949|      0|        if (url_data.substr(input_position, 2) == "//") {
  ------------------
  |  Branch (12949:13): [True: 0, False: 0]
  ------------------
12950|      0|          state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES;
12951|      0|          input_position += 2;
12952|      0|        } else {
12953|       |          // Otherwise, validation error, set state to relative state and
12954|       |          // decrease pointer by 1.
12955|      0|          state = state::RELATIVE_SCHEME;
12956|      0|        }
12957|       |
12958|      0|        break;
12959|  39.7k|      }
12960|  1.16k|      case state::PATH_OR_AUTHORITY: {
  ------------------
  |  Branch (12960:7): [True: 1.16k, False: 1.76M]
  ------------------
12961|  1.16k|        ada_log("PATH_OR_AUTHORITY ",
12962|  1.16k|                helpers::substring(url_data, input_position));
12963|       |
12964|       |        // If c is U+002F (/), then set state to authority state.
12965|  1.16k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12965:13): [True: 1.12k, False: 36]
  ------------------
12966|  1.12k|            (url_data[input_position] == '/')) {
  ------------------
  |  Branch (12966:13): [True: 772, False: 354]
  ------------------
12967|    772|          state = state::AUTHORITY;
12968|    772|          input_position++;
12969|    772|        } else {
12970|       |          // Otherwise, set state to path state, and decrease pointer by 1.
12971|    390|          state = state::PATH;
12972|    390|        }
12973|       |
12974|  1.16k|        break;
12975|  39.7k|      }
12976|      0|      case state::RELATIVE_SCHEME: {
  ------------------
  |  Branch (12976:7): [True: 0, False: 1.76M]
  ------------------
12977|      0|        ada_log("RELATIVE_SCHEME ",
12978|      0|                helpers::substring(url_data, input_position));
12979|       |
12980|       |        // Set url's scheme to base's scheme.
12981|      0|        url.copy_scheme(*base_url);
12982|       |
12983|       |        // If c is U+002F (/), then set state to relative slash state.
12984|      0|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12984:13): [True: 0, False: 0]
  ------------------
12985|       |            // NOLINTNEXTLINE(bugprone-branch-clone)
12986|      0|            (url_data[input_position] == '/')) {
  ------------------
  |  Branch (12986:13): [True: 0, False: 0]
  ------------------
12987|      0|          ada_log(
12988|      0|              "RELATIVE_SCHEME if c is U+002F (/), then set state to relative "
12989|      0|              "slash state");
12990|      0|          state = state::RELATIVE_SLASH;
12991|      0|        } else if (url.is_special() && (input_position != input_size) &&
  ------------------
  |  Branch (12991:20): [True: 0, False: 0]
  |  Branch (12991:40): [True: 0, False: 0]
  ------------------
12992|      0|                   (url_data[input_position] == '\\')) {
  ------------------
  |  Branch (12992:20): [True: 0, False: 0]
  ------------------
12993|       |          // Otherwise, if url is special and c is U+005C (\), validation error,
12994|       |          // set state to relative slash state.
12995|      0|          ada_log(
12996|      0|              "RELATIVE_SCHEME  if url is special and c is U+005C, validation "
12997|      0|              "error, set state to relative slash state");
12998|      0|          state = state::RELATIVE_SLASH;
12999|      0|        } else {
13000|      0|          ada_log("RELATIVE_SCHEME otherwise");
13001|       |          // Set url's username to base's username, url's password to base's
13002|       |          // password, url's host to base's host, url's port to base's port,
13003|       |          // url's path to a clone of base's path, and url's query to base's
13004|       |          // query.
13005|      0|          if constexpr (result_type_is_ada_url) {
13006|      0|            url.username = base_url->username;
13007|      0|            url.password = base_url->password;
13008|      0|            url.host = base_url->host;
13009|      0|            url.port = base_url->port;
13010|       |            // cloning the base path includes cloning the has_opaque_path flag
13011|      0|            url.has_opaque_path = base_url->has_opaque_path;
13012|      0|            url.path = base_url->path;
13013|      0|            url.query = base_url->query;
13014|       |          } else {
13015|       |            url.update_base_authority(base_url->get_href(),
13016|       |                                      base_url->get_components());
13017|       |            url.update_host_to_base_host(base_url->get_hostname());
13018|       |            url.update_base_port(base_url->retrieve_base_port());
13019|       |            // cloning the base path includes cloning the has_opaque_path flag
13020|       |            url.has_opaque_path = base_url->has_opaque_path;
13021|       |            url.update_base_pathname(base_url->get_pathname());
13022|       |            if (base_url->has_search()) {
13023|       |              // get_search() returns "" for an empty query string (URL ends
13024|       |              // with '?'). update_base_search("") would incorrectly clear the
13025|       |              // query, so pass "?" to preserve the empty query distinction.
13026|       |              auto s = base_url->get_search();
13027|       |              url.update_base_search(s.empty() ? std::string_view("?") : s);
13028|       |            }
13029|       |          }
13030|       |
13031|      0|          url.has_opaque_path = base_url->has_opaque_path;
13032|       |
13033|       |          // If c is U+003F (?), then set url's query to the empty string, and
13034|       |          // state to query state.
13035|      0|          if ((input_position != input_size) &&
  ------------------
  |  Branch (13035:15): [True: 0, False: 0]
  ------------------
13036|      0|              (url_data[input_position] == '?')) {
  ------------------
  |  Branch (13036:15): [True: 0, False: 0]
  ------------------
13037|      0|            state = state::QUERY;
13038|      0|          }
13039|       |          // Otherwise, if c is not the EOF code point:
13040|      0|          else if (input_position != input_size) {
  ------------------
  |  Branch (13040:20): [True: 0, False: 0]
  ------------------
13041|       |            // Set url's query to null.
13042|      0|            url.clear_search();
13043|      0|            if constexpr (result_type_is_ada_url) {
13044|       |              // Shorten url's path.
13045|      0|              helpers::shorten_path(url.path, url.type);
13046|       |            } else {
13047|       |              std::string_view path = url.get_pathname();
13048|       |              if (helpers::shorten_path(path, url.type)) {
13049|       |                url.update_base_pathname(std::move(std::string(path)));
13050|       |              }
13051|       |            }
13052|       |            // Set state to path state and decrease pointer by 1.
13053|      0|            state = state::PATH;
13054|      0|            break;
13055|      0|          }
13056|      0|        }
13057|      0|        input_position++;
13058|      0|        break;
13059|      0|      }
13060|      0|      case state::RELATIVE_SLASH: {
  ------------------
  |  Branch (13060:7): [True: 0, False: 1.76M]
  ------------------
13061|      0|        ada_log("RELATIVE_SLASH ",
13062|      0|                helpers::substring(url_data, input_position));
13063|       |
13064|       |        // If url is special and c is U+002F (/) or U+005C (\), then:
13065|       |        // NOLINTNEXTLINE(bugprone-branch-clone)
13066|      0|        if (url.is_special() && (input_position != input_size) &&
  ------------------
  |  Branch (13066:13): [True: 0, False: 0]
  |  Branch (13066:33): [True: 0, False: 0]
  ------------------
13067|      0|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (13067:14): [True: 0, False: 0]
  ------------------
13068|      0|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (13068:14): [True: 0, False: 0]
  ------------------
13069|       |          // Set state to special authority ignore slashes state.
13070|      0|          state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES;
13071|      0|        }
13072|       |        // Otherwise, if c is U+002F (/), then set state to authority state.
13073|      0|        else if ((input_position != input_size) &&
  ------------------
  |  Branch (13073:18): [True: 0, False: 0]
  ------------------
13074|      0|                 (url_data[input_position] == '/')) {
  ------------------
  |  Branch (13074:18): [True: 0, False: 0]
  ------------------
13075|      0|          state = state::AUTHORITY;
13076|      0|        }
13077|       |        // Otherwise, set
13078|       |        // - url's username to base's username,
13079|       |        // - url's password to base's password,
13080|       |        // - url's host to base's host,
13081|       |        // - url's port to base's port,
13082|       |        // - state to path state, and then, decrease pointer by 1.
13083|      0|        else {
13084|      0|          if constexpr (result_type_is_ada_url) {
13085|      0|            url.username = base_url->username;
13086|      0|            url.password = base_url->password;
13087|      0|            url.host = base_url->host;
13088|      0|            url.port = base_url->port;
13089|       |          } else {
13090|       |            url.update_base_authority(base_url->get_href(),
13091|       |                                      base_url->get_components());
13092|       |            url.update_host_to_base_host(base_url->get_hostname());
13093|       |            url.update_base_port(base_url->retrieve_base_port());
13094|       |          }
13095|      0|          state = state::PATH;
13096|      0|          break;
13097|      0|        }
13098|       |
13099|      0|        input_position++;
13100|      0|        break;
13101|      0|      }
13102|   258k|      case state::SPECIAL_AUTHORITY_SLASHES: {
  ------------------
  |  Branch (13102:7): [True: 258k, False: 1.50M]
  ------------------
13103|   258k|        ada_log("SPECIAL_AUTHORITY_SLASHES ",
13104|   258k|                helpers::substring(url_data, input_position));
13105|       |
13106|       |        // If c is U+002F (/) and remaining starts with U+002F (/),
13107|       |        // then set state to special authority ignore slashes state and increase
13108|       |        // pointer by 1.
13109|   258k|        if (url_data.substr(input_position, 2) == "//") {
  ------------------
  |  Branch (13109:13): [True: 256k, False: 1.65k]
  ------------------
13110|   256k|          input_position += 2;
13111|   256k|        }
13112|       |
13113|   258k|        [[fallthrough]];
13114|   258k|      }
13115|   258k|      case state::SPECIAL_AUTHORITY_IGNORE_SLASHES: {
  ------------------
  |  Branch (13115:7): [True: 0, False: 1.76M]
  ------------------
13116|   258k|        ada_log("SPECIAL_AUTHORITY_IGNORE_SLASHES ",
13117|   258k|                helpers::substring(url_data, input_position));
13118|       |
13119|       |        // If c is neither U+002F (/) nor U+005C (\), then set state to
13120|       |        // authority state and decrease pointer by 1.
13121|   260k|        while ((input_position != input_size) &&
  ------------------
  |  Branch (13121:16): [True: 259k, False: 66]
  ------------------
13122|   259k|               ((url_data[input_position] == '/') ||
  ------------------
  |  Branch (13122:17): [True: 652, False: 259k]
  ------------------
13123|   259k|                (url_data[input_position] == '\\'))) {
  ------------------
  |  Branch (13123:17): [True: 1.25k, False: 258k]
  ------------------
13124|  1.90k|          input_position++;
13125|  1.90k|        }
13126|   258k|        state = state::AUTHORITY;
13127|       |
13128|   258k|        break;
13129|   258k|      }
13130|  10.2k|      case state::QUERY: {
  ------------------
  |  Branch (13130:7): [True: 10.2k, False: 1.75M]
  ------------------
13131|  10.2k|        ada_log("QUERY ", helpers::substring(url_data, input_position));
13132|  10.2k|        if constexpr (store_values) {
13133|       |          // Let queryPercentEncodeSet be the special-query percent-encode set
13134|       |          // if url is special; otherwise the query percent-encode set.
13135|  10.2k|          const uint8_t* query_percent_encode_set =
13136|  10.2k|              url.is_special() ? character_sets::SPECIAL_QUERY_PERCENT_ENCODE
  ------------------
  |  Branch (13136:15): [True: 9.05k, False: 1.16k]
  ------------------
13137|  10.2k|                               : character_sets::QUERY_PERCENT_ENCODE;
13138|       |
13139|       |          // Percent-encode after encoding, with encoding, buffer, and
13140|       |          // queryPercentEncodeSet, and append the result to url's query.
13141|  10.2k|          url.update_base_search(url_data.substr(input_position),
13142|  10.2k|                                 query_percent_encode_set);
13143|  10.2k|          ada_log("QUERY update_base_search completed ");
13144|  10.2k|          if (fragment.has_value()) {
  ------------------
  |  Branch (13144:15): [True: 7.51k, False: 2.70k]
  ------------------
13145|  7.51k|            url.update_unencoded_base_hash(*fragment);
13146|  7.51k|          }
13147|  10.2k|        }
13148|  10.2k|        enforce_max_input_length();
13149|  10.2k|        return url;
13150|   258k|      }
13151|   258k|      case state::HOST: {
  ------------------
  |  Branch (13151:7): [True: 258k, False: 1.50M]
  ------------------
13152|   258k|        ada_log("HOST ", helpers::substring(url_data, input_position));
13153|       |
13154|   258k|        std::string_view host_view = url_data.substr(input_position);
13155|   258k|        auto [location, found_colon] =
13156|   258k|            helpers::get_host_delimiter_location(url.is_special(), host_view);
13157|   258k|        input_position = (location != std::string_view::npos)
  ------------------
  |  Branch (13157:26): [True: 258k, False: 0]
  ------------------
13158|   258k|                             ? input_position + location
13159|   258k|                             : input_size;
13160|       |        // Otherwise, if c is U+003A (:) and insideBrackets is false, then:
13161|       |        // Note: the 'found_colon' value is true if and only if a colon was
13162|       |        // encountered while not inside brackets.
13163|   258k|        if (found_colon) {
  ------------------
  |  Branch (13163:13): [True: 2.47k, False: 256k]
  ------------------
13164|       |          // If buffer is the empty string, validation error, return failure.
13165|       |          // Let host be the result of host parsing buffer with url is not
13166|       |          // special.
13167|  2.47k|          ada_log("HOST parsing ", host_view);
13168|  2.47k|          if (!url.parse_host(host_view)) {
  ------------------
  |  Branch (13168:15): [True: 186, False: 2.29k]
  ------------------
13169|    186|            return url;
13170|    186|          }
13171|  2.29k|          ada_log("HOST parsing results in ", url.get_hostname());
13172|       |          // Set url's host to host, buffer to the empty string, and state to
13173|       |          // port state.
13174|  2.29k|          state = state::PORT;
13175|  2.29k|          input_position++;
13176|  2.29k|        }
13177|       |        // Otherwise, if one of the following is true:
13178|       |        // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
13179|       |        // - url is special and c is U+005C (\)
13180|       |        // The get_host_delimiter_location function either brings us to
13181|       |        // the colon outside of the bracket, or to one of those characters.
13182|   256k|        else {
13183|       |          // If url is special and host_view is the empty string, validation
13184|       |          // error, return failure.
13185|   256k|          if (host_view.empty() && url.is_special()) {
  ------------------
  |  Branch (13185:15): [True: 166, False: 256k]
  |  Branch (13185:36): [True: 100, False: 66]
  ------------------
13186|    100|            url.is_valid = false;
13187|    100|            return url;
13188|    100|          }
13189|   256k|          ada_log("HOST parsing ", host_view, " href=", url.get_href());
13190|       |          // Let host be the result of host parsing host_view with url is not
13191|       |          // special.
13192|   256k|          if (host_view.empty()) {
  ------------------
  |  Branch (13192:15): [True: 66, False: 256k]
  ------------------
13193|     66|            url.update_base_hostname("");
13194|   256k|          } else if (!url.parse_host(host_view)) {
  ------------------
  |  Branch (13194:22): [True: 20.3k, False: 235k]
  ------------------
13195|  20.3k|            return url;
13196|  20.3k|          }
13197|   235k|          ada_log("HOST parsing results in ", url.get_hostname(),
13198|   235k|                  " href=", url.get_href());
13199|       |
13200|       |          // Set url's host to host, and state to path start state.
13201|   235k|          state = state::PATH_START;
13202|   235k|        }
13203|       |
13204|   238k|        break;
13205|   258k|      }
13206|   238k|      case state::OPAQUE_PATH: {
  ------------------
  |  Branch (13206:7): [True: 723, False: 1.76M]
  ------------------
13207|    723|        ada_log("OPAQUE_PATH ", helpers::substring(url_data, input_position));
13208|       |        // Opaque path, query, and fragment are structurally always valid:
13209|       |        // the parser would just percent-encode whatever is there. When we
13210|       |        // are not storing values (can_parse), we can return immediately.
13211|       |        // We must set has_opaque_path = true before returning so that when
13212|       |        // this URL is used as an internal base inside can_parse, NO_SCHEME
13213|       |        // correctly rejects relative inputs against an opaque-path base
13214|       |        // (e.g. can_parse("", &"W:") must return false).
13215|       |        if constexpr (!store_values) {
13216|       |          url.has_opaque_path = true;
13217|       |          return url;
13218|       |        }
13219|    723|        std::string_view view = url_data.substr(input_position);
13220|       |        // If c is U+003F (?), then set url's query to the empty string and
13221|       |        // state to query state.
13222|    723|        size_t location = view.find('?');
13223|    723|        if (location != std::string_view::npos) {
  ------------------
  |  Branch (13223:13): [True: 423, False: 300]
  ------------------
13224|    423|          view.remove_suffix(view.size() - location);
13225|    423|          state = state::QUERY;
13226|    423|          input_position += location + 1;
13227|    423|        } else {
13228|    300|          input_position = input_size + 1;
13229|    300|        }
13230|    723|        url.has_opaque_path = true;
13231|       |
13232|       |        // This is a really unlikely scenario in real world. We should not seek
13233|       |        // to optimize it.
13234|    723|        if (view.ends_with(' ')) {
  ------------------
  |  Branch (13234:13): [True: 9, False: 714]
  ------------------
13235|      9|          std::string modified_view =
13236|      9|              std::string(view.substr(0, view.size() - 1)) + "%20";
13237|      9|          url.update_base_pathname(unicode::percent_encode(
13238|      9|              modified_view, character_sets::C0_CONTROL_PERCENT_ENCODE));
13239|    714|        } else {
13240|    714|          url.update_base_pathname(unicode::percent_encode(
13241|    714|              view, character_sets::C0_CONTROL_PERCENT_ENCODE));
13242|    714|        }
13243|    723|        break;
13244|   258k|      }
13245|  2.29k|      case state::PORT: {
  ------------------
  |  Branch (13245:7): [True: 2.29k, False: 1.76M]
  ------------------
13246|  2.29k|        ada_log("PORT ", helpers::substring(url_data, input_position));
13247|  2.29k|        std::string_view port_view = url_data.substr(input_position);
13248|  2.29k|        input_position += url.parse_port(port_view, true);
13249|  2.29k|        if (!url.is_valid) {
  ------------------
  |  Branch (13249:13): [True: 231, False: 2.06k]
  ------------------
13250|    231|          return url;
13251|    231|        }
13252|  2.06k|        state = state::PATH_START;
13253|  2.06k|        [[fallthrough]];
13254|  2.06k|      }
13255|   239k|      case state::PATH_START: {
  ------------------
  |  Branch (13255:7): [True: 237k, False: 1.52M]
  ------------------
13256|   239k|        ada_log("PATH_START ", helpers::substring(url_data, input_position));
13257|       |        // Path, query, and fragment are structurally always valid: the
13258|       |        // parser would just percent-encode whatever is there. When we are
13259|       |        // not storing values (can_parse), we can return immediately since
13260|       |        // no subsequent state can invalidate the URL.
13261|       |        if constexpr (!store_values) {
13262|       |          return url;
13263|       |        }
13264|       |
13265|       |        // If url is special, then:
13266|   239k|        if (url.is_special()) {
  ------------------
  |  Branch (13266:13): [True: 238k, False: 702]
  ------------------
13267|       |          // Set state to path state.
13268|   238k|          state = state::PATH;
13269|       |
13270|       |          // Optimization: Avoiding going into PATH state improves the
13271|       |          // performance of urls ending with /.
13272|   238k|          if (input_position == input_size) {
  ------------------
  |  Branch (13272:15): [True: 29.8k, False: 208k]
  ------------------
13273|  29.8k|            if constexpr (store_values) {
13274|  29.8k|              url.update_base_pathname("/");
13275|  29.8k|              if (fragment.has_value()) {
  ------------------
  |  Branch (13275:19): [True: 261, False: 29.5k]
  ------------------
13276|    261|                url.update_unencoded_base_hash(*fragment);
13277|    261|              }
13278|  29.8k|            }
13279|  29.8k|            enforce_max_input_length();
13280|  29.8k|            return url;
13281|  29.8k|          }
13282|       |          // If c is neither U+002F (/) nor U+005C (\), then decrease pointer
13283|       |          // by 1. We know that (input_position == input_size) is impossible
13284|       |          // here, because of the previous if-check.
13285|   208k|          if ((url_data[input_position] != '/') &&
  ------------------
  |  Branch (13285:15): [True: 1.05k, False: 207k]
  ------------------
13286|  1.05k|              (url_data[input_position] != '\\')) {
  ------------------
  |  Branch (13286:15): [True: 640, False: 410]
  ------------------
13287|    640|            break;
13288|    640|          }
13289|   208k|        }
13290|       |        // Otherwise, if state override is not given and c is U+003F (?),
13291|       |        // set url's query to the empty string and state to query state.
13292|    702|        else if ((input_position != input_size) &&
  ------------------
  |  Branch (13292:18): [True: 546, False: 156]
  ------------------
13293|    546|                 (url_data[input_position] == '?')) {
  ------------------
  |  Branch (13293:18): [True: 102, False: 444]
  ------------------
13294|    102|          state = state::QUERY;
13295|    102|        }
13296|       |        // Otherwise, if c is not the EOF code point:
13297|    600|        else if (input_position != input_size) {
  ------------------
  |  Branch (13297:18): [True: 444, False: 156]
  ------------------
13298|       |          // Set state to path state.
13299|    444|          state = state::PATH;
13300|       |
13301|       |          // If c is not U+002F (/), then decrease pointer by 1.
13302|    444|          if (url_data[input_position] != '/') {
  ------------------
  |  Branch (13302:15): [True: 0, False: 444]
  ------------------
13303|      0|            break;
13304|      0|          }
13305|    444|        }
13306|       |
13307|   208k|        input_position++;
13308|   208k|        break;
13309|   239k|      }
13310|   209k|      case state::PATH: {
  ------------------
  |  Branch (13310:7): [True: 209k, False: 1.55M]
  ------------------
13311|   209k|        ada_log("PATH ", helpers::substring(url_data, input_position));
13312|       |        // Path, query, and fragment are structurally always valid: the
13313|       |        // parser would just percent-encode whatever is there. When we are
13314|       |        // not storing values (can_parse), we can return immediately since
13315|       |        // no subsequent state can invalidate the URL.
13316|       |        if constexpr (!store_values) {
13317|       |          return url;
13318|       |        }
13319|   209k|        std::string_view view = url_data.substr(input_position);
13320|       |
13321|       |        // Most time, we do not need percent encoding.
13322|       |        // Furthermore, we can immediately locate the '?'.
13323|   209k|        size_t locofquestionmark = view.find('?');
13324|   209k|        if (locofquestionmark != std::string_view::npos) {
  ------------------
  |  Branch (13324:13): [True: 9.69k, False: 199k]
  ------------------
13325|  9.69k|          state = state::QUERY;
13326|  9.69k|          view.remove_suffix(view.size() - locofquestionmark);
13327|  9.69k|          input_position += locofquestionmark + 1;
13328|   199k|        } else {
13329|   199k|          input_position = input_size + 1;
13330|   199k|        }
13331|   209k|        if constexpr (store_values) {
13332|   209k|          if constexpr (result_type_is_ada_url) {
13333|   209k|            helpers::parse_prepared_path(view, url.type, url.path);
13334|       |          } else {
13335|       |            url.consume_prepared_path(view);
13336|       |            ADA_ASSERT_TRUE(url.validate());
13337|       |          }
13338|   209k|        }
13339|   209k|        break;
13340|   239k|      }
13341|  1.44k|      case state::FILE_SLASH: {
  ------------------
  |  Branch (13341:7): [True: 1.44k, False: 1.76M]
  ------------------
13342|  1.44k|        ada_log("FILE_SLASH ", helpers::substring(url_data, input_position));
13343|       |
13344|       |        // If c is U+002F (/) or U+005C (\), then:
13345|  1.44k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (13345:13): [True: 1.44k, False: 1]
  ------------------
13346|  1.44k|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (13346:14): [True: 1.42k, False: 16]
  ------------------
13347|  1.42k|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (13347:14): [True: 2, False: 14]
  ------------------
13348|  1.42k|          ada_log("FILE_SLASH c is U+002F or U+005C");
13349|       |          // Set state to file host state.
13350|  1.42k|          state = state::FILE_HOST;
13351|  1.42k|          input_position++;
13352|  1.42k|        } else {
13353|     15|          ada_log("FILE_SLASH otherwise");
13354|       |          // If base is non-null and base's scheme is "file", then:
13355|       |          // Note: it is unsafe to do base_url->scheme unless you know that
13356|       |          // base_url_has_value() is true.
13357|     15|          if (base_url != nullptr && base_url->type == scheme::type::FILE) {
  ------------------
  |  Branch (13357:15): [True: 0, False: 15]
  |  Branch (13357:38): [True: 0, False: 0]
  ------------------
13358|       |            // Set url's host to base's host.
13359|      0|            if constexpr (result_type_is_ada_url) {
13360|      0|              url.host = base_url->host;
13361|       |            } else {
13362|       |              url.update_host_to_base_host(base_url->get_host());
13363|       |            }
13364|       |            // If the code point substring from pointer to the end of input does
13365|       |            // not start with a Windows drive letter and base's path[0] is a
13366|       |            // normalized Windows drive letter, then append base's path[0] to
13367|       |            // url's path.
13368|      0|            if (!base_url->get_pathname().empty()) {
  ------------------
  |  Branch (13368:17): [True: 0, False: 0]
  ------------------
13369|      0|              if (!checkers::is_windows_drive_letter(
  ------------------
  |  Branch (13369:19): [True: 0, False: 0]
  ------------------
13370|      0|                      url_data.substr(input_position))) {
13371|      0|                std::string_view first_base_url_path =
13372|      0|                    base_url->get_pathname().substr(1);
13373|      0|                size_t loc = first_base_url_path.find('/');
13374|      0|                if (loc != std::string_view::npos) {
  ------------------
  |  Branch (13374:21): [True: 0, False: 0]
  ------------------
13375|      0|                  helpers::resize(first_base_url_path, loc);
13376|      0|                }
13377|      0|                if (checkers::is_normalized_windows_drive_letter(
  ------------------
  |  Branch (13377:21): [True: 0, False: 0]
  ------------------
13378|      0|                        first_base_url_path)) {
13379|      0|                  if constexpr (result_type_is_ada_url) {
13380|      0|                    url.path += '/';
13381|      0|                    url.path += first_base_url_path;
13382|       |                  } else {
13383|       |                    url.append_base_pathname(
13384|       |                        helpers::concat("/", first_base_url_path));
13385|       |                  }
13386|      0|                }
13387|      0|              }
13388|      0|            }
13389|      0|          }
13390|       |
13391|       |          // Set state to path state, and decrease pointer by 1.
13392|     15|          state = state::PATH;
13393|     15|        }
13394|       |
13395|  1.44k|        break;
13396|   239k|      }
13397|  1.42k|      case state::FILE_HOST: {
  ------------------
  |  Branch (13397:7): [True: 1.42k, False: 1.76M]
  ------------------
13398|  1.42k|        ada_log("FILE_HOST ", helpers::substring(url_data, input_position));
13399|  1.42k|        std::string_view view = url_data.substr(input_position);
13400|       |
13401|  1.42k|        size_t location = view.find_first_of("/\\?");
13402|  1.42k|        std::string_view file_host_buffer = view.substr(
13403|  1.42k|            0, (location != std::string_view::npos) ? location : view.size());
  ------------------
  |  Branch (13403:16): [True: 1.38k, False: 43]
  ------------------
13404|       |
13405|  1.42k|        if (checkers::is_windows_drive_letter(file_host_buffer)) {
  ------------------
  |  Branch (13405:13): [True: 1, False: 1.42k]
  ------------------
13406|      1|          state = state::PATH;
13407|  1.42k|        } else if (file_host_buffer.empty()) {
  ------------------
  |  Branch (13407:20): [True: 310, False: 1.11k]
  ------------------
13408|       |          // Set url's host to the empty string.
13409|    310|          if constexpr (result_type_is_ada_url) {
13410|    310|            url.host = "";
13411|       |          } else {
13412|       |            url.update_base_hostname("");
13413|       |          }
13414|       |          // Set state to path start state.
13415|    310|          state = state::PATH_START;
13416|  1.11k|        } else {
13417|  1.11k|          size_t consumed_bytes = file_host_buffer.size();
13418|  1.11k|          input_position += consumed_bytes;
13419|       |          // Let host be the result of host parsing buffer with url is not
13420|       |          // special.
13421|  1.11k|          if (!url.parse_host(file_host_buffer)) {
  ------------------
  |  Branch (13421:15): [True: 89, False: 1.02k]
  ------------------
13422|     89|            return url;
13423|     89|          }
13424|       |
13425|  1.02k|          if constexpr (result_type_is_ada_url) {
13426|       |            // If host is "localhost", then set host to the empty string.
13427|  1.02k|            if (url.host.has_value() && url.host.value() == "localhost") {
  ------------------
  |  Branch (13427:17): [True: 1.02k, False: 0]
  |  Branch (13427:41): [True: 3, False: 1.02k]
  ------------------
13428|      3|              url.host = "";
13429|      3|            }
13430|       |          } else {
13431|       |            if (url.get_hostname() == "localhost") {
13432|       |              url.update_base_hostname("");
13433|       |            }
13434|       |          }
13435|       |
13436|       |          // Set buffer to the empty string and state to path start state.
13437|  1.02k|          state = state::PATH_START;
13438|  1.02k|        }
13439|       |
13440|  1.34k|        break;
13441|  1.42k|      }
13442|  1.57k|      case state::FILE: {
  ------------------
  |  Branch (13442:7): [True: 1.57k, False: 1.76M]
  ------------------
13443|  1.57k|        ada_log("FILE ", helpers::substring(url_data, input_position));
13444|  1.57k|        std::string_view file_view = url_data.substr(input_position);
13445|       |
13446|  1.57k|        url.set_protocol_as_file();
13447|  1.57k|        if constexpr (result_type_is_ada_url) {
13448|       |          // Set url's host to the empty string.
13449|  1.57k|          url.host = "";
13450|       |        } else {
13451|       |          url.update_base_hostname("");
13452|       |        }
13453|       |        // If c is U+002F (/) or U+005C (\), then:
13454|  1.57k|        if (input_position != input_size &&
  ------------------
  |  Branch (13454:13): [True: 1.57k, False: 1]
  ------------------
13455|  1.57k|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (13455:14): [True: 1.44k, False: 132]
  ------------------
13456|  1.44k|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (13456:14): [True: 3, False: 129]
  ------------------
13457|  1.44k|          ada_log("FILE c is U+002F or U+005C");
13458|       |          // Set state to file slash state.
13459|  1.44k|          state = state::FILE_SLASH;
13460|  1.44k|        }
13461|       |        // Otherwise, if base is non-null and base's scheme is "file":
13462|    130|        else if (base_url != nullptr && base_url->type == scheme::type::FILE) {
  ------------------
  |  Branch (13462:18): [True: 0, False: 130]
  |  Branch (13462:41): [True: 0, False: 0]
  ------------------
13463|       |          // Set url's host to base's host, url's path to a clone of base's
13464|       |          // path, and url's query to base's query.
13465|      0|          ada_log("FILE base non-null");
13466|      0|          if constexpr (result_type_is_ada_url) {
13467|      0|            url.host = base_url->host;
13468|      0|            url.path = base_url->path;
13469|      0|            url.query = base_url->query;
13470|       |          } else {
13471|       |            url.update_host_to_base_host(base_url->get_hostname());
13472|       |            url.update_base_pathname(base_url->get_pathname());
13473|       |            if (base_url->has_search()) {
13474|       |              // get_search() returns "" for an empty query string (URL ends
13475|       |              // with '?'). update_base_search("") would incorrectly clear the
13476|       |              // query, so pass "?" to preserve the empty query distinction.
13477|       |              auto s = base_url->get_search();
13478|       |              url.update_base_search(s.empty() ? std::string_view("?") : s);
13479|       |            }
13480|       |          }
13481|      0|          url.has_opaque_path = base_url->has_opaque_path;
13482|       |
13483|       |          // If c is U+003F (?), then set url's query to the empty string and
13484|       |          // state to query state.
13485|      0|          if (input_position != input_size && url_data[input_position] == '?') {
  ------------------
  |  Branch (13485:15): [True: 0, False: 0]
  |  Branch (13485:47): [True: 0, False: 0]
  ------------------
13486|      0|            state = state::QUERY;
13487|      0|          }
13488|       |          // Otherwise, if c is not the EOF code point:
13489|      0|          else if (input_position != input_size) {
  ------------------
  |  Branch (13489:20): [True: 0, False: 0]
  ------------------
13490|       |            // Set url's query to null.
13491|      0|            url.clear_search();
13492|       |            // If the code point substring from pointer to the end of input does
13493|       |            // not start with a Windows drive letter, then shorten url's path.
13494|      0|            if (!checkers::is_windows_drive_letter(file_view)) {
  ------------------
  |  Branch (13494:17): [True: 0, False: 0]
  ------------------
13495|      0|              if constexpr (result_type_is_ada_url) {
13496|      0|                helpers::shorten_path(url.path, url.type);
13497|       |              } else {
13498|       |                std::string_view path = url.get_pathname();
13499|       |                if (helpers::shorten_path(path, url.type)) {
13500|       |                  url.update_base_pathname(std::move(std::string(path)));
13501|       |                }
13502|       |              }
13503|      0|            }
13504|       |            // Otherwise:
13505|      0|            else {
13506|       |              // Set url's path to an empty list.
13507|      0|              url.clear_pathname();
13508|      0|              url.has_opaque_path = true;
13509|      0|            }
13510|       |
13511|       |            // Set state to path state and decrease pointer by 1.
13512|      0|            state = state::PATH;
13513|      0|            break;
13514|      0|          }
13515|      0|        }
13516|       |        // Otherwise, set state to path state, and decrease pointer by 1.
13517|    130|        else {
13518|    130|          ada_log("FILE go to path");
13519|    130|          state = state::PATH;
13520|    130|          break;
13521|    130|        }
13522|       |
13523|  1.44k|        input_position++;
13524|  1.44k|        break;
13525|  1.57k|      }
13526|      0|      default:
  ------------------
  |  Branch (13526:7): [True: 0, False: 1.76M]
  ------------------
13527|      0|        unreachable();
13528|  1.76M|    }
13529|  1.76M|  }
13530|   543k|  if constexpr (store_values) {
13531|   543k|    if (fragment.has_value()) {
  ------------------
  |  Branch (13531:9): [True: 2.34k, False: 541k]
  ------------------
13532|  2.34k|      url.update_unencoded_base_hash(*fragment);
13533|  2.34k|    }
13534|   543k|  }
13535|   543k|  enforce_max_input_length();
13536|   543k|  return url;
13537|   604k|}
_ZN3ada6parser14parse_url_implINS_14url_aggregatorELb1EEET_NSt3__117basic_string_viewIcNS4_11char_traitsIcEEEEPKS3_:
12517|   604k|                           const result_type* base_url) {
12518|       |  // We can specialize the implementation per type.
12519|       |  // Important: result_type_is_ada_url is evaluated at *compile time*. This
12520|       |  // means that doing if constexpr(result_type_is_ada_url) { something } else {
12521|       |  // something else } is free (at runtime). This means that ada::url_aggregator
12522|       |  // and ada::url **do not have to support the exact same API**.
12523|   604k|  constexpr bool result_type_is_ada_url = std::is_same_v<url, result_type>;
12524|   604k|  constexpr bool result_type_is_ada_url_aggregator =
12525|   604k|      std::is_same_v<url_aggregator, result_type>;
12526|   604k|  static_assert(result_type_is_ada_url ||
12527|   604k|                result_type_is_ada_url_aggregator);  // We don't support
12528|       |                                                     // anything else for now.
12529|       |
12530|   604k|  ada_log("ada::parser::parse_url('", user_input, "' [", user_input.size(),
12531|   604k|          " bytes],", (base_url != nullptr ? base_url->to_string() : "null"),
12532|   604k|          ")");
12533|       |
12534|   604k|  result_type url{};
12535|       |
12536|   604k|  const uint32_t max_input_length = ada::get_max_input_length();
12537|       |
12538|       |  // Normalization (percent-encoding, IDNA) can push the serialized URL past
12539|       |  // max_input_length even when the input fit under it. The check at the end of
12540|       |  // the state machine covers URLs that run to completion, but several states
12541|       |  // return early after appending a query or fragment, so run the same check on
12542|       |  // those exits too. Without this, a query- or fragment-terminated URL such as
12543|       |  // file://x/?<...> or https://user@x/?<...> is accepted while the equivalent
12544|       |  // https://x/?<...> that takes the absolute fast path is rejected.
12545|   604k|  const auto enforce_max_input_length = [&]() {
12546|   604k|    if constexpr (store_values) {
12547|   604k|      if (url.is_valid) {
12548|   604k|        if constexpr (result_type_is_ada_url_aggregator) {
12549|   604k|          if (url.buffer.size() > max_input_length) [[unlikely]] {
12550|   604k|            url.is_valid = false;
12551|   604k|          }
12552|   604k|        } else {
12553|   604k|          if (url.get_href_size() > max_input_length) [[unlikely]] {
12554|   604k|            url.is_valid = false;
12555|   604k|          }
12556|   604k|        }
12557|   604k|      }
12558|   604k|    }
12559|   604k|  };
12560|       |
12561|       |  // We refuse to parse URL strings that exceed the maximum input length.
12562|       |  // By default, this is 4GB but can be configured via
12563|       |  // ada::set_max_input_length().
12564|   604k|  if (user_input.size() > max_input_length) [[unlikely]] {
  ------------------
  |  Branch (12564:7): [True: 0, False: 604k]
  ------------------
12565|      0|    url.is_valid = false;
12566|      0|  }
12567|       |  // Going forward, user_input.size() is in [0,
12568|       |  // std::numeric_limits<uint32_t>::max). If we are provided with an invalid
12569|       |  // base, or the optional_url was invalid, we must return.
12570|   604k|  if (base_url != nullptr) {
  ------------------
  |  Branch (12570:7): [True: 0, False: 604k]
  ------------------
12571|      0|    url.is_valid &= base_url->is_valid;
12572|      0|  }
12573|   604k|  if (!url.is_valid) {
  ------------------
  |  Branch (12573:7): [True: 0, False: 604k]
  ------------------
12574|      0|    return url;
12575|      0|  }
12576|       |
12577|       |  // Simple absolute / relative fast paths (before tabs/newline scan).
12578|   604k|  if constexpr (store_values) {
12579|   604k|    bool hit_fast_path = false;
12580|   604k|    if (base_url == nullptr) {
  ------------------
  |  Branch (12580:9): [True: 604k, False: 0]
  ------------------
12581|       |      // IPv4/IPv6 and userinfo miss the fast path. Skip the never_inline
12582|       |      // call so those URLs (including SetHref) do not pay for a miss.
12583|   604k|      const auto* p = reinterpret_cast<const uint8_t*>(user_input.data());
12584|   604k|      const size_t n = user_input.size();
12585|   604k|      size_t host_start = 0;
12586|   604k|      if (n >= 8 && p[4] == ':' && p[5] == '/' && p[6] == '/') {
  ------------------
  |  Branch (12586:11): [True: 604k, False: 181]
  |  Branch (12586:21): [True: 232k, False: 372k]
  |  Branch (12586:36): [True: 231k, False: 828]
  |  Branch (12586:51): [True: 231k, False: 153]
  ------------------
12587|   231k|        host_start = 7;
12588|   373k|      } else if (n >= 9 && p[5] == ':' && p[6] == '/' && p[7] == '/') {
  ------------------
  |  Branch (12588:18): [True: 373k, False: 190]
  |  Branch (12588:28): [True: 370k, False: 2.60k]
  |  Branch (12588:43): [True: 370k, False: 834]
  |  Branch (12588:58): [True: 370k, False: 93]
  ------------------
12589|   370k|        host_start = 8;
12590|   370k|      }
12591|   604k|      const uint8_t host_first = host_start != 0 ? p[host_start] : 0;
  ------------------
  |  Branch (12591:34): [True: 601k, False: 3.72k]
  ------------------
12592|   604k|      const bool skip_ip =
12593|   604k|          host_first == '[' || (host_first >= '0' && host_first <= '9');
  ------------------
  |  Branch (12593:11): [True: 553, False: 604k]
  |  Branch (12593:33): [True: 597k, False: 6.80k]
  |  Branch (12593:54): [True: 135k, False: 462k]
  ------------------
12594|   604k|      const bool skip_userinfo =
12595|   604k|          host_start != 0 && authority_has_at(p, host_start, n);
  ------------------
  |  Branch (12595:11): [True: 601k, False: 3.72k]
  |  Branch (12595:30): [True: 38.5k, False: 562k]
  ------------------
12596|   604k|      hit_fast_path = !skip_ip && !skip_userinfo &&
  ------------------
  |  Branch (12596:23): [True: 468k, False: 136k]
  |  Branch (12596:35): [True: 430k, False: 38.5k]
  ------------------
12597|   430k|                      try_parse_simple_absolute(user_input, url);
  ------------------
  |  Branch (12597:23): [True: 343k, False: 87.1k]
  ------------------
12598|   604k|    } else {
12599|      0|      hit_fast_path = try_parse_simple_relative(user_input, *base_url, url);
12600|      0|    }
12601|   604k|    if (hit_fast_path) {
  ------------------
  |  Branch (12601:9): [True: 343k, False: 261k]
  ------------------
12602|   343k|      if constexpr (result_type_is_ada_url_aggregator) {
12603|   343k|        if (url.buffer.size() > max_input_length) [[unlikely]] {
  ------------------
  |  Branch (12603:13): [True: 0, False: 343k]
  ------------------
12604|      0|          url.is_valid = false;
12605|      0|        }
12606|       |      } else {
12607|       |        // For a small absolute input, even worst-case normalization cannot
12608|       |        // exceed the limit: percent encoding expands at most 3x and IDNA at
12609|       |        // most 4.5x. Avoid traversing every stored component on the common
12610|       |        // default-limit path.
12611|       |        if ((base_url != nullptr ||
12612|       |             user_input.size() > static_cast<size_t>(max_input_length) / 5) &&
12613|       |            url.get_href_size() > max_input_length) [[unlikely]] {
12614|       |          url.is_valid = false;
12615|       |        }
12616|       |      }
12617|   343k|      return url;
12618|   343k|    }
12619|   604k|  }
12620|       |
12621|   261k|  state state = state::SCHEME_START;
12622|       |
12623|   604k|  std::string tmp_buffer;
12624|   604k|  std::string_view url_data;
12625|   604k|  if (unicode::has_tabs_or_newline(user_input)) [[unlikely]] {
  ------------------
  |  Branch (12625:7): [True: 474, False: 604k]
  ------------------
12626|    474|    tmp_buffer = user_input;
12627|       |    // Optimization opportunity: Instead of copying and then pruning, we could
12628|       |    // just directly build the string from user_input.
12629|    474|    helpers::remove_ascii_tab_or_newline(tmp_buffer);
12630|    474|    url_data = tmp_buffer;
12631|   604k|  } else [[likely]] {
12632|   604k|    url_data = user_input;
12633|   604k|  }
12634|       |
12635|       |  // Leading and trailing control characters are uncommon and easy to deal with
12636|       |  // (no performance concern).
12637|   604k|  helpers::trim_c0_whitespace(url_data);
12638|       |
12639|   604k|  if constexpr (result_type_is_ada_url_aggregator && store_values) {
12640|       |    // Most of the time, we just need user_input.size().
12641|       |    // In some instances, we may need a bit more.
12642|       |    ///////////////////////////
12643|       |    // This is *very* important. This line should *not* be removed
12644|       |    // hastily. There are principled reasons why reserve is important
12645|       |    // for performance. If you have a benchmark with small inputs,
12646|       |    // it may not matter, but in other instances, it could.
12647|       |    ////
12648|       |    // This rounds up to the next power of two.
12649|       |    // We know that user_input.size() is in [0,
12650|       |    // std::numeric_limits<uint32_t>::max).
12651|   604k|    uint32_t reserve_capacity =
12652|   604k|        (0xFFFFFFFF >>
12653|   604k|         helpers::leading_zeroes(uint32_t(1 | user_input.size()))) +
12654|   604k|        1;
12655|   604k|    url.reserve(reserve_capacity);
12656|   604k|  }
12657|       |
12658|       |  // Optimization opportunity. Most websites do not have fragment.
12659|   604k|  std::optional<std::string_view> fragment = helpers::prune_hash(url_data);
12660|       |  // We add it last so that an implementation like ada::url_aggregator
12661|       |  // can append it last to its internal buffer, thus improving performance.
12662|       |
12663|       |  // Here url_data no longer has its fragment.
12664|       |  // We are going to access the data from url_data (it is immutable).
12665|       |  // At any given time, we are pointing at byte 'input_position' in url_data.
12666|       |  // The input_position variable should range from 0 to input_size.
12667|       |  // It is illegal to access url_data at input_size.
12668|   604k|  size_t input_position = 0;
12669|   604k|  const size_t input_size = url_data.size();
12670|       |  // Keep running the following state machine by switching on state.
12671|       |  // If after a run pointer points to the EOF code point, go to the next step.
12672|       |  // Otherwise, increase pointer by 1 and continue with the state machine.
12673|       |  // We never decrement input_position.
12674|  2.30M|  while (input_position <= input_size) {
  ------------------
  |  Branch (12674:10): [True: 1.76M, False: 543k]
  ------------------
12675|  1.76M|    ada_log("In parsing at ", input_position, " out of ", input_size,
12676|  1.76M|            " in state ", ada::to_string(state));
12677|  1.76M|    switch (state) {
12678|   261k|      case state::SCHEME_START: {
  ------------------
  |  Branch (12678:7): [True: 261k, False: 1.50M]
  ------------------
12679|   261k|        ada_log("SCHEME_START ", helpers::substring(url_data, input_position));
12680|       |        // If c is an ASCII alpha, append c, lowercased, to buffer, and set
12681|       |        // state to scheme state.
12682|   261k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12682:13): [True: 261k, False: 3]
  ------------------
12683|   261k|            checkers::is_alpha(url_data[input_position])) {
  ------------------
  |  Branch (12683:13): [True: 261k, False: 127]
  ------------------
12684|   261k|          state = state::SCHEME;
12685|   261k|          input_position++;
12686|   261k|        } else {
12687|       |          // Otherwise, if state override is not given, set state to no scheme
12688|       |          // state and decrease pointer by 1.
12689|    130|          state = state::NO_SCHEME;
12690|    130|        }
12691|   261k|        break;
12692|      0|      }
12693|   261k|      case state::SCHEME: {
  ------------------
  |  Branch (12693:7): [True: 261k, False: 1.50M]
  ------------------
12694|   261k|        ada_log("SCHEME ", helpers::substring(url_data, input_position));
12695|       |        // If c is an ASCII alphanumeric, U+002B (+), U+002D (-), or U+002E (.),
12696|       |        // append c, lowercased, to buffer.
12697|  1.13M|        while ((input_position != input_size) &&
  ------------------
  |  Branch (12697:16): [True: 1.13M, False: 4]
  ------------------
12698|  1.13M|               (unicode::is_alnum_plus(url_data[input_position]))) {
  ------------------
  |  Branch (12698:16): [True: 874k, False: 261k]
  ------------------
12699|   874k|          input_position++;
12700|   874k|        }
12701|       |        // Otherwise, if c is U+003A (:), then:
12702|   261k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12702:13): [True: 261k, False: 4]
  ------------------
12703|   261k|            (url_data[input_position] == ':')) {
  ------------------
  |  Branch (12703:13): [True: 261k, False: 81]
  ------------------
12704|   261k|          ada_log("SCHEME the scheme should be ",
12705|   261k|                  url_data.substr(0, input_position));
12706|       |          if constexpr (result_type_is_ada_url) {
12707|       |            if (!url.parse_scheme(url_data.substr(0, input_position))) {
12708|       |              return url;
12709|       |            }
12710|   261k|          } else {
12711|       |            // we pass the colon along instead of painfully adding it back.
12712|   261k|            if (!url.parse_scheme_with_colon(
  ------------------
  |  Branch (12712:17): [True: 0, False: 261k]
  ------------------
12713|   261k|                    url_data.substr(0, input_position + 1))) {
12714|      0|              return url;
12715|      0|            }
12716|   261k|          }
12717|   261k|          ada_log("SCHEME the scheme is ", url.get_protocol());
12718|       |
12719|       |          // If url's scheme is "file", then:
12720|       |          // NOLINTNEXTLINE(bugprone-branch-clone)
12721|   261k|          if (url.type == scheme::type::FILE) {
  ------------------
  |  Branch (12721:15): [True: 1.57k, False: 260k]
  ------------------
12722|       |            // Set state to file state.
12723|  1.57k|            state = state::FILE;
12724|  1.57k|          }
12725|       |          // Otherwise, if url is special, base is non-null, and base's scheme
12726|       |          // is url's scheme: Note: Doing base_url->scheme is unsafe if base_url
12727|       |          // != nullptr is false.
12728|   260k|          else if (url.is_special() && base_url != nullptr &&
  ------------------
  |  Branch (12728:20): [True: 258k, False: 1.88k]
  |  Branch (12728:40): [True: 0, False: 258k]
  ------------------
12729|      0|                   base_url->type == url.type) {
  ------------------
  |  Branch (12729:20): [True: 0, False: 0]
  ------------------
12730|       |            // Set state to special relative or authority state.
12731|      0|            state = state::SPECIAL_RELATIVE_OR_AUTHORITY;
12732|      0|          }
12733|       |          // Otherwise, if url is special, set state to special authority
12734|       |          // slashes state.
12735|   260k|          else if (url.is_special()) {
  ------------------
  |  Branch (12735:20): [True: 258k, False: 1.88k]
  ------------------
12736|   258k|            state = state::SPECIAL_AUTHORITY_SLASHES;
12737|   258k|          }
12738|       |          // Otherwise, if remaining starts with an U+002F (/), set state to
12739|       |          // path or authority state and increase pointer by 1.
12740|  1.88k|          else if (input_position + 1 < input_size &&
  ------------------
  |  Branch (12740:20): [True: 1.72k, False: 159]
  ------------------
12741|  1.72k|                   url_data[input_position + 1] == '/') {
  ------------------
  |  Branch (12741:20): [True: 1.16k, False: 564]
  ------------------
12742|  1.16k|            state = state::PATH_OR_AUTHORITY;
12743|  1.16k|            input_position++;
12744|  1.16k|          }
12745|       |          // Otherwise, set url's path to the empty string and set state to
12746|       |          // opaque path state.
12747|    723|          else {
12748|    723|            state = state::OPAQUE_PATH;
12749|    723|          }
12750|   261k|        }
12751|       |        // Otherwise, if state override is not given, set buffer to the empty
12752|       |        // string, state to no scheme state, and start over (from the first code
12753|       |        // point in input).
12754|     85|        else {
12755|     85|          state = state::NO_SCHEME;
12756|     85|          input_position = 0;
12757|     85|          break;
12758|     85|        }
12759|   261k|        input_position++;
12760|   261k|        break;
12761|   261k|      }
12762|    215|      case state::NO_SCHEME: {
  ------------------
  |  Branch (12762:7): [True: 215, False: 1.76M]
  ------------------
12763|    215|        ada_log("NO_SCHEME ", helpers::substring(url_data, input_position));
12764|       |        // The fragment was pruned from url_data before the state machine ran,
12765|       |        // so 'c is U+0023 (#)' holds exactly when a fragment was found and
12766|       |        // nothing else remains in front of it.
12767|    215|        const bool c_is_hash =
12768|    215|            fragment.has_value() && input_position == input_size;
  ------------------
  |  Branch (12768:13): [True: 140, False: 75]
  |  Branch (12768:37): [True: 3, False: 137]
  ------------------
12769|       |        // If base is null, or base has an opaque path and c is not U+0023 (#),
12770|       |        // validation error, return failure.
12771|    215|        if (base_url == nullptr || (base_url->has_opaque_path && !c_is_hash)) {
  ------------------
  |  Branch (12771:13): [True: 215, False: 0]
  |  Branch (12771:37): [True: 0, False: 0]
  |  Branch (12771:66): [True: 0, False: 0]
  ------------------
12772|    215|          ada_log("NO_SCHEME validation error");
12773|    215|          url.is_valid = false;
12774|    215|          return url;
12775|    215|        }
12776|       |        // Otherwise, if base has an opaque path and c is U+0023 (#),
12777|       |        // set url's scheme to base's scheme, url's path to base's path, url's
12778|       |        // query to base's query, and set state to fragment state.
12779|      0|        else if (base_url->has_opaque_path && c_is_hash) {
  ------------------
  |  Branch (12779:18): [True: 0, False: 0]
  |  Branch (12779:47): [True: 0, False: 0]
  ------------------
12780|      0|          ada_log("NO_SCHEME opaque base with fragment");
12781|      0|          url.copy_scheme(*base_url);
12782|      0|          url.has_opaque_path = base_url->has_opaque_path;
12783|       |
12784|       |          if constexpr (result_type_is_ada_url) {
12785|       |            url.path = base_url->path;
12786|       |            url.query = base_url->query;
12787|      0|          } else {
12788|      0|            url.update_base_pathname(base_url->get_pathname());
12789|      0|            if (base_url->has_search()) {
  ------------------
  |  Branch (12789:17): [True: 0, False: 0]
  ------------------
12790|       |              // get_search() returns "" for an empty query string (URL ends
12791|       |              // with '?'). update_base_search("") would incorrectly clear the
12792|       |              // query, so pass "?" to preserve the empty query distinction.
12793|      0|              auto s = base_url->get_search();
12794|      0|              url.update_base_search(s.empty() ? std::string_view("?") : s);
  ------------------
  |  Branch (12794:38): [True: 0, False: 0]
  ------------------
12795|      0|            }
12796|      0|          }
12797|      0|          url.update_unencoded_base_hash(*fragment);
12798|      0|          enforce_max_input_length();
12799|      0|          return url;
12800|      0|        }
12801|       |        // Otherwise, if base's scheme is not "file", set state to relative
12802|       |        // state and decrease pointer by 1.
12803|       |        // NOLINTNEXTLINE(bugprone-branch-clone)
12804|      0|        else if (base_url->type != scheme::type::FILE) {
  ------------------
  |  Branch (12804:18): [True: 0, False: 0]
  ------------------
12805|      0|          ada_log("NO_SCHEME non-file relative path");
12806|      0|          state = state::RELATIVE_SCHEME;
12807|      0|        }
12808|       |        // Otherwise, set state to file state and decrease pointer by 1.
12809|      0|        else {
12810|      0|          ada_log("NO_SCHEME file base type");
12811|      0|          state = state::FILE;
12812|      0|        }
12813|      0|        break;
12814|    215|      }
12815|   258k|      case state::AUTHORITY: {
  ------------------
  |  Branch (12815:7): [True: 258k, False: 1.50M]
  ------------------
12816|   258k|        ada_log("AUTHORITY ", helpers::substring(url_data, input_position));
12817|       |        // most URLs have no @. Having no @ tells us that we don't have to worry
12818|       |        // about AUTHORITY. Of course, we could have @ and still not have to
12819|       |        // worry about AUTHORITY.
12820|       |        // TODO: Instead of just collecting a bool, collect the location of the
12821|       |        // '@' and do something useful with it.
12822|       |        // TODO: We could do various processing early on, using a single pass
12823|       |        // over the string to collect information about it, e.g., telling us
12824|       |        // whether there is a @ and if so, where (or how many).
12825|       |
12826|       |        // Check if url data contains an @.
12827|   258k|        if (url_data.find('@', input_position) == std::string_view::npos) {
  ------------------
  |  Branch (12827:13): [True: 219k, False: 39.7k]
  ------------------
12828|   219k|          state = state::HOST;
12829|   219k|          break;
12830|   219k|        }
12831|  39.7k|        bool at_sign_seen{false};
12832|  39.7k|        bool password_token_seen{false};
12833|       |        /**
12834|       |         * We expect something of the sort...
12835|       |         * https://user:pass@example.com:1234/foo/bar?baz#quux
12836|       |         * --------^
12837|       |         */
12838|  92.6k|        do {
12839|  92.6k|          std::string_view view = url_data.substr(input_position);
12840|       |          // The delimiters are @, /, ? \\.
12841|  92.6k|          size_t location =
12842|  92.6k|              url.is_special() ? helpers::find_authority_delimiter_special(view)
  ------------------
  |  Branch (12842:15): [True: 92.4k, False: 206]
  ------------------
12843|  92.6k|                               : helpers::find_authority_delimiter(view);
12844|  92.6k|          std::string_view authority_view = view.substr(0, location);
12845|  92.6k|          size_t end_of_authority = input_position + authority_view.size();
12846|       |          // If c is U+0040 (@), then:
12847|  92.6k|          if ((end_of_authority != input_size) &&
  ------------------
  |  Branch (12847:15): [True: 82.9k, False: 9.67k]
  ------------------
12848|  82.9k|              (url_data[end_of_authority] == '@')) {
  ------------------
  |  Branch (12848:15): [True: 52.9k, False: 30.0k]
  ------------------
12849|       |            // If atSignSeen is true, then prepend "%40" to buffer.
12850|  52.9k|            if (at_sign_seen) {
  ------------------
  |  Branch (12850:17): [True: 13.4k, False: 39.4k]
  ------------------
12851|  13.4k|              if (password_token_seen) {
  ------------------
  |  Branch (12851:19): [True: 3.86k, False: 9.56k]
  ------------------
12852|       |                if constexpr (result_type_is_ada_url) {
12853|       |                  url.password += "%40";
12854|  3.86k|                } else {
12855|  3.86k|                  url.append_base_password("%40");
12856|  3.86k|                }
12857|  9.56k|              } else {
12858|       |                if constexpr (result_type_is_ada_url) {
12859|       |                  url.username += "%40";
12860|  9.56k|                } else {
12861|  9.56k|                  url.append_base_username("%40");
12862|  9.56k|                }
12863|  9.56k|              }
12864|  13.4k|            }
12865|       |
12866|  52.9k|            at_sign_seen = true;
12867|       |
12868|  52.9k|            if (!password_token_seen) {
  ------------------
  |  Branch (12868:17): [True: 49.0k, False: 3.86k]
  ------------------
12869|  49.0k|              size_t password_token_location = authority_view.find(':');
12870|  49.0k|              password_token_seen =
12871|  49.0k|                  password_token_location != std::string_view::npos;
12872|       |
12873|  49.0k|              if constexpr (store_values) {
12874|  49.0k|                if (!password_token_seen) {
  ------------------
  |  Branch (12874:21): [True: 20.0k, False: 29.0k]
  ------------------
12875|       |                  if constexpr (result_type_is_ada_url) {
12876|       |                    url.username += unicode::percent_encode(
12877|       |                        authority_view,
12878|       |                        character_sets::USERINFO_PERCENT_ENCODE);
12879|  20.0k|                  } else {
12880|  20.0k|                    url.append_base_username(unicode::percent_encode(
12881|  20.0k|                        authority_view,
12882|  20.0k|                        character_sets::USERINFO_PERCENT_ENCODE));
12883|  20.0k|                  }
12884|  29.0k|                } else {
12885|       |                  if constexpr (result_type_is_ada_url) {
12886|       |                    url.username += unicode::percent_encode(
12887|       |                        authority_view.substr(0, password_token_location),
12888|       |                        character_sets::USERINFO_PERCENT_ENCODE);
12889|       |                    url.password += unicode::percent_encode(
12890|       |                        authority_view.substr(password_token_location + 1),
12891|       |                        character_sets::USERINFO_PERCENT_ENCODE);
12892|  29.0k|                  } else {
12893|  29.0k|                    url.append_base_username(unicode::percent_encode(
12894|  29.0k|                        authority_view.substr(0, password_token_location),
12895|  29.0k|                        character_sets::USERINFO_PERCENT_ENCODE));
12896|  29.0k|                    url.append_base_password(unicode::percent_encode(
12897|  29.0k|                        authority_view.substr(password_token_location + 1),
12898|  29.0k|                        character_sets::USERINFO_PERCENT_ENCODE));
12899|  29.0k|                  }
12900|  29.0k|                }
12901|  49.0k|              }
12902|  49.0k|            } else if constexpr (store_values) {
12903|       |              if constexpr (result_type_is_ada_url) {
12904|       |                url.password += unicode::percent_encode(
12905|       |                    authority_view, character_sets::USERINFO_PERCENT_ENCODE);
12906|  3.86k|              } else {
12907|  3.86k|                url.append_base_password(unicode::percent_encode(
12908|  3.86k|                    authority_view, character_sets::USERINFO_PERCENT_ENCODE));
12909|  3.86k|              }
12910|  3.86k|            }
12911|  52.9k|          }
12912|       |          // Otherwise, if one of the following is true:
12913|       |          // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
12914|       |          // - url is special and c is U+005C (\)
12915|  39.7k|          else if (end_of_authority == input_size ||
  ------------------
  |  Branch (12915:20): [True: 9.67k, False: 30.0k]
  ------------------
12916|  30.0k|                   url_data[end_of_authority] == '/' ||
  ------------------
  |  Branch (12916:20): [True: 29.8k, False: 163]
  ------------------
12917|    163|                   url_data[end_of_authority] == '?' ||
  ------------------
  |  Branch (12917:20): [True: 128, False: 35]
  ------------------
12918|  39.7k|                   (url.is_special() && url_data[end_of_authority] == '\\')) {
  ------------------
  |  Branch (12918:21): [True: 35, False: 0]
  |  Branch (12918:41): [True: 35, False: 0]
  ------------------
12919|       |            // If atSignSeen is true and authority_view is the empty string,
12920|       |            // validation error, return failure.
12921|  39.7k|            if (at_sign_seen && authority_view.empty()) {
  ------------------
  |  Branch (12921:17): [True: 39.4k, False: 245]
  |  Branch (12921:33): [True: 219, False: 39.2k]
  ------------------
12922|    219|              url.is_valid = false;
12923|    219|              return url;
12924|    219|            }
12925|  39.5k|            state = state::HOST;
12926|  39.5k|            break;
12927|  39.7k|          }
12928|  52.9k|          if (end_of_authority == input_size) {
  ------------------
  |  Branch (12928:15): [True: 0, False: 52.9k]
  ------------------
12929|      0|            if constexpr (store_values) {
12930|      0|              if (fragment.has_value()) {
  ------------------
  |  Branch (12930:19): [True: 0, False: 0]
  ------------------
12931|      0|                url.update_unencoded_base_hash(*fragment);
12932|      0|              }
12933|      0|            }
12934|      0|            enforce_max_input_length();
12935|      0|            return url;
12936|      0|          }
12937|  52.9k|          input_position = end_of_authority + 1;
12938|  52.9k|        } while (true);
  ------------------
  |  Branch (12938:18): [True: 52.9k, Folded]
  ------------------
12939|       |
12940|  39.5k|        break;
12941|  39.7k|      }
12942|  39.5k|      case state::SPECIAL_RELATIVE_OR_AUTHORITY: {
  ------------------
  |  Branch (12942:7): [True: 0, False: 1.76M]
  ------------------
12943|      0|        ada_log("SPECIAL_RELATIVE_OR_AUTHORITY ",
12944|      0|                helpers::substring(url_data, input_position));
12945|       |
12946|       |        // If c is U+002F (/) and remaining starts with U+002F (/),
12947|       |        // then set state to special authority ignore slashes state and increase
12948|       |        // pointer by 1.
12949|      0|        if (url_data.substr(input_position, 2) == "//") {
  ------------------
  |  Branch (12949:13): [True: 0, False: 0]
  ------------------
12950|      0|          state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES;
12951|      0|          input_position += 2;
12952|      0|        } else {
12953|       |          // Otherwise, validation error, set state to relative state and
12954|       |          // decrease pointer by 1.
12955|      0|          state = state::RELATIVE_SCHEME;
12956|      0|        }
12957|       |
12958|      0|        break;
12959|  39.7k|      }
12960|  1.16k|      case state::PATH_OR_AUTHORITY: {
  ------------------
  |  Branch (12960:7): [True: 1.16k, False: 1.76M]
  ------------------
12961|  1.16k|        ada_log("PATH_OR_AUTHORITY ",
12962|  1.16k|                helpers::substring(url_data, input_position));
12963|       |
12964|       |        // If c is U+002F (/), then set state to authority state.
12965|  1.16k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12965:13): [True: 1.12k, False: 36]
  ------------------
12966|  1.12k|            (url_data[input_position] == '/')) {
  ------------------
  |  Branch (12966:13): [True: 772, False: 354]
  ------------------
12967|    772|          state = state::AUTHORITY;
12968|    772|          input_position++;
12969|    772|        } else {
12970|       |          // Otherwise, set state to path state, and decrease pointer by 1.
12971|    390|          state = state::PATH;
12972|    390|        }
12973|       |
12974|  1.16k|        break;
12975|  39.7k|      }
12976|      0|      case state::RELATIVE_SCHEME: {
  ------------------
  |  Branch (12976:7): [True: 0, False: 1.76M]
  ------------------
12977|      0|        ada_log("RELATIVE_SCHEME ",
12978|      0|                helpers::substring(url_data, input_position));
12979|       |
12980|       |        // Set url's scheme to base's scheme.
12981|      0|        url.copy_scheme(*base_url);
12982|       |
12983|       |        // If c is U+002F (/), then set state to relative slash state.
12984|      0|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12984:13): [True: 0, False: 0]
  ------------------
12985|       |            // NOLINTNEXTLINE(bugprone-branch-clone)
12986|      0|            (url_data[input_position] == '/')) {
  ------------------
  |  Branch (12986:13): [True: 0, False: 0]
  ------------------
12987|      0|          ada_log(
12988|      0|              "RELATIVE_SCHEME if c is U+002F (/), then set state to relative "
12989|      0|              "slash state");
12990|      0|          state = state::RELATIVE_SLASH;
12991|      0|        } else if (url.is_special() && (input_position != input_size) &&
  ------------------
  |  Branch (12991:20): [True: 0, False: 0]
  |  Branch (12991:40): [True: 0, False: 0]
  ------------------
12992|      0|                   (url_data[input_position] == '\\')) {
  ------------------
  |  Branch (12992:20): [True: 0, False: 0]
  ------------------
12993|       |          // Otherwise, if url is special and c is U+005C (\), validation error,
12994|       |          // set state to relative slash state.
12995|      0|          ada_log(
12996|      0|              "RELATIVE_SCHEME  if url is special and c is U+005C, validation "
12997|      0|              "error, set state to relative slash state");
12998|      0|          state = state::RELATIVE_SLASH;
12999|      0|        } else {
13000|      0|          ada_log("RELATIVE_SCHEME otherwise");
13001|       |          // Set url's username to base's username, url's password to base's
13002|       |          // password, url's host to base's host, url's port to base's port,
13003|       |          // url's path to a clone of base's path, and url's query to base's
13004|       |          // query.
13005|       |          if constexpr (result_type_is_ada_url) {
13006|       |            url.username = base_url->username;
13007|       |            url.password = base_url->password;
13008|       |            url.host = base_url->host;
13009|       |            url.port = base_url->port;
13010|       |            // cloning the base path includes cloning the has_opaque_path flag
13011|       |            url.has_opaque_path = base_url->has_opaque_path;
13012|       |            url.path = base_url->path;
13013|       |            url.query = base_url->query;
13014|      0|          } else {
13015|      0|            url.update_base_authority(base_url->get_href(),
13016|      0|                                      base_url->get_components());
13017|      0|            url.update_host_to_base_host(base_url->get_hostname());
13018|      0|            url.update_base_port(base_url->retrieve_base_port());
13019|       |            // cloning the base path includes cloning the has_opaque_path flag
13020|      0|            url.has_opaque_path = base_url->has_opaque_path;
13021|      0|            url.update_base_pathname(base_url->get_pathname());
13022|      0|            if (base_url->has_search()) {
  ------------------
  |  Branch (13022:17): [True: 0, False: 0]
  ------------------
13023|       |              // get_search() returns "" for an empty query string (URL ends
13024|       |              // with '?'). update_base_search("") would incorrectly clear the
13025|       |              // query, so pass "?" to preserve the empty query distinction.
13026|      0|              auto s = base_url->get_search();
13027|      0|              url.update_base_search(s.empty() ? std::string_view("?") : s);
  ------------------
  |  Branch (13027:38): [True: 0, False: 0]
  ------------------
13028|      0|            }
13029|      0|          }
13030|       |
13031|      0|          url.has_opaque_path = base_url->has_opaque_path;
13032|       |
13033|       |          // If c is U+003F (?), then set url's query to the empty string, and
13034|       |          // state to query state.
13035|      0|          if ((input_position != input_size) &&
  ------------------
  |  Branch (13035:15): [True: 0, False: 0]
  ------------------
13036|      0|              (url_data[input_position] == '?')) {
  ------------------
  |  Branch (13036:15): [True: 0, False: 0]
  ------------------
13037|      0|            state = state::QUERY;
13038|      0|          }
13039|       |          // Otherwise, if c is not the EOF code point:
13040|      0|          else if (input_position != input_size) {
  ------------------
  |  Branch (13040:20): [True: 0, False: 0]
  ------------------
13041|       |            // Set url's query to null.
13042|      0|            url.clear_search();
13043|       |            if constexpr (result_type_is_ada_url) {
13044|       |              // Shorten url's path.
13045|       |              helpers::shorten_path(url.path, url.type);
13046|      0|            } else {
13047|      0|              std::string_view path = url.get_pathname();
13048|      0|              if (helpers::shorten_path(path, url.type)) {
  ------------------
  |  Branch (13048:19): [True: 0, False: 0]
  ------------------
13049|      0|                url.update_base_pathname(std::move(std::string(path)));
13050|      0|              }
13051|      0|            }
13052|       |            // Set state to path state and decrease pointer by 1.
13053|      0|            state = state::PATH;
13054|      0|            break;
13055|      0|          }
13056|      0|        }
13057|      0|        input_position++;
13058|      0|        break;
13059|      0|      }
13060|      0|      case state::RELATIVE_SLASH: {
  ------------------
  |  Branch (13060:7): [True: 0, False: 1.76M]
  ------------------
13061|      0|        ada_log("RELATIVE_SLASH ",
13062|      0|                helpers::substring(url_data, input_position));
13063|       |
13064|       |        // If url is special and c is U+002F (/) or U+005C (\), then:
13065|       |        // NOLINTNEXTLINE(bugprone-branch-clone)
13066|      0|        if (url.is_special() && (input_position != input_size) &&
  ------------------
  |  Branch (13066:13): [True: 0, False: 0]
  |  Branch (13066:33): [True: 0, False: 0]
  ------------------
13067|      0|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (13067:14): [True: 0, False: 0]
  ------------------
13068|      0|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (13068:14): [True: 0, False: 0]
  ------------------
13069|       |          // Set state to special authority ignore slashes state.
13070|      0|          state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES;
13071|      0|        }
13072|       |        // Otherwise, if c is U+002F (/), then set state to authority state.
13073|      0|        else if ((input_position != input_size) &&
  ------------------
  |  Branch (13073:18): [True: 0, False: 0]
  ------------------
13074|      0|                 (url_data[input_position] == '/')) {
  ------------------
  |  Branch (13074:18): [True: 0, False: 0]
  ------------------
13075|      0|          state = state::AUTHORITY;
13076|      0|        }
13077|       |        // Otherwise, set
13078|       |        // - url's username to base's username,
13079|       |        // - url's password to base's password,
13080|       |        // - url's host to base's host,
13081|       |        // - url's port to base's port,
13082|       |        // - state to path state, and then, decrease pointer by 1.
13083|      0|        else {
13084|       |          if constexpr (result_type_is_ada_url) {
13085|       |            url.username = base_url->username;
13086|       |            url.password = base_url->password;
13087|       |            url.host = base_url->host;
13088|       |            url.port = base_url->port;
13089|      0|          } else {
13090|      0|            url.update_base_authority(base_url->get_href(),
13091|      0|                                      base_url->get_components());
13092|      0|            url.update_host_to_base_host(base_url->get_hostname());
13093|      0|            url.update_base_port(base_url->retrieve_base_port());
13094|      0|          }
13095|      0|          state = state::PATH;
13096|      0|          break;
13097|      0|        }
13098|       |
13099|      0|        input_position++;
13100|      0|        break;
13101|      0|      }
13102|   258k|      case state::SPECIAL_AUTHORITY_SLASHES: {
  ------------------
  |  Branch (13102:7): [True: 258k, False: 1.50M]
  ------------------
13103|   258k|        ada_log("SPECIAL_AUTHORITY_SLASHES ",
13104|   258k|                helpers::substring(url_data, input_position));
13105|       |
13106|       |        // If c is U+002F (/) and remaining starts with U+002F (/),
13107|       |        // then set state to special authority ignore slashes state and increase
13108|       |        // pointer by 1.
13109|   258k|        if (url_data.substr(input_position, 2) == "//") {
  ------------------
  |  Branch (13109:13): [True: 256k, False: 1.65k]
  ------------------
13110|   256k|          input_position += 2;
13111|   256k|        }
13112|       |
13113|   258k|        [[fallthrough]];
13114|   258k|      }
13115|   258k|      case state::SPECIAL_AUTHORITY_IGNORE_SLASHES: {
  ------------------
  |  Branch (13115:7): [True: 0, False: 1.76M]
  ------------------
13116|   258k|        ada_log("SPECIAL_AUTHORITY_IGNORE_SLASHES ",
13117|   258k|                helpers::substring(url_data, input_position));
13118|       |
13119|       |        // If c is neither U+002F (/) nor U+005C (\), then set state to
13120|       |        // authority state and decrease pointer by 1.
13121|   260k|        while ((input_position != input_size) &&
  ------------------
  |  Branch (13121:16): [True: 259k, False: 66]
  ------------------
13122|   259k|               ((url_data[input_position] == '/') ||
  ------------------
  |  Branch (13122:17): [True: 652, False: 259k]
  ------------------
13123|   259k|                (url_data[input_position] == '\\'))) {
  ------------------
  |  Branch (13123:17): [True: 1.25k, False: 258k]
  ------------------
13124|  1.90k|          input_position++;
13125|  1.90k|        }
13126|   258k|        state = state::AUTHORITY;
13127|       |
13128|   258k|        break;
13129|   258k|      }
13130|  10.2k|      case state::QUERY: {
  ------------------
  |  Branch (13130:7): [True: 10.2k, False: 1.75M]
  ------------------
13131|  10.2k|        ada_log("QUERY ", helpers::substring(url_data, input_position));
13132|  10.2k|        if constexpr (store_values) {
13133|       |          // Let queryPercentEncodeSet be the special-query percent-encode set
13134|       |          // if url is special; otherwise the query percent-encode set.
13135|  10.2k|          const uint8_t* query_percent_encode_set =
13136|  10.2k|              url.is_special() ? character_sets::SPECIAL_QUERY_PERCENT_ENCODE
  ------------------
  |  Branch (13136:15): [True: 9.05k, False: 1.16k]
  ------------------
13137|  10.2k|                               : character_sets::QUERY_PERCENT_ENCODE;
13138|       |
13139|       |          // Percent-encode after encoding, with encoding, buffer, and
13140|       |          // queryPercentEncodeSet, and append the result to url's query.
13141|  10.2k|          url.update_base_search(url_data.substr(input_position),
13142|  10.2k|                                 query_percent_encode_set);
13143|  10.2k|          ada_log("QUERY update_base_search completed ");
13144|  10.2k|          if (fragment.has_value()) {
  ------------------
  |  Branch (13144:15): [True: 7.51k, False: 2.70k]
  ------------------
13145|  7.51k|            url.update_unencoded_base_hash(*fragment);
13146|  7.51k|          }
13147|  10.2k|        }
13148|  10.2k|        enforce_max_input_length();
13149|  10.2k|        return url;
13150|   258k|      }
13151|   258k|      case state::HOST: {
  ------------------
  |  Branch (13151:7): [True: 258k, False: 1.50M]
  ------------------
13152|   258k|        ada_log("HOST ", helpers::substring(url_data, input_position));
13153|       |
13154|   258k|        std::string_view host_view = url_data.substr(input_position);
13155|   258k|        auto [location, found_colon] =
13156|   258k|            helpers::get_host_delimiter_location(url.is_special(), host_view);
13157|   258k|        input_position = (location != std::string_view::npos)
  ------------------
  |  Branch (13157:26): [True: 258k, False: 0]
  ------------------
13158|   258k|                             ? input_position + location
13159|   258k|                             : input_size;
13160|       |        // Otherwise, if c is U+003A (:) and insideBrackets is false, then:
13161|       |        // Note: the 'found_colon' value is true if and only if a colon was
13162|       |        // encountered while not inside brackets.
13163|   258k|        if (found_colon) {
  ------------------
  |  Branch (13163:13): [True: 2.47k, False: 256k]
  ------------------
13164|       |          // If buffer is the empty string, validation error, return failure.
13165|       |          // Let host be the result of host parsing buffer with url is not
13166|       |          // special.
13167|  2.47k|          ada_log("HOST parsing ", host_view);
13168|  2.47k|          if (!url.parse_host(host_view)) {
  ------------------
  |  Branch (13168:15): [True: 186, False: 2.29k]
  ------------------
13169|    186|            return url;
13170|    186|          }
13171|  2.29k|          ada_log("HOST parsing results in ", url.get_hostname());
13172|       |          // Set url's host to host, buffer to the empty string, and state to
13173|       |          // port state.
13174|  2.29k|          state = state::PORT;
13175|  2.29k|          input_position++;
13176|  2.29k|        }
13177|       |        // Otherwise, if one of the following is true:
13178|       |        // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
13179|       |        // - url is special and c is U+005C (\)
13180|       |        // The get_host_delimiter_location function either brings us to
13181|       |        // the colon outside of the bracket, or to one of those characters.
13182|   256k|        else {
13183|       |          // If url is special and host_view is the empty string, validation
13184|       |          // error, return failure.
13185|   256k|          if (host_view.empty() && url.is_special()) {
  ------------------
  |  Branch (13185:15): [True: 166, False: 256k]
  |  Branch (13185:36): [True: 100, False: 66]
  ------------------
13186|    100|            url.is_valid = false;
13187|    100|            return url;
13188|    100|          }
13189|   256k|          ada_log("HOST parsing ", host_view, " href=", url.get_href());
13190|       |          // Let host be the result of host parsing host_view with url is not
13191|       |          // special.
13192|   256k|          if (host_view.empty()) {
  ------------------
  |  Branch (13192:15): [True: 66, False: 256k]
  ------------------
13193|     66|            url.update_base_hostname("");
13194|   256k|          } else if (!url.parse_host(host_view)) {
  ------------------
  |  Branch (13194:22): [True: 20.3k, False: 235k]
  ------------------
13195|  20.3k|            return url;
13196|  20.3k|          }
13197|   235k|          ada_log("HOST parsing results in ", url.get_hostname(),
13198|   235k|                  " href=", url.get_href());
13199|       |
13200|       |          // Set url's host to host, and state to path start state.
13201|   235k|          state = state::PATH_START;
13202|   235k|        }
13203|       |
13204|   238k|        break;
13205|   258k|      }
13206|   238k|      case state::OPAQUE_PATH: {
  ------------------
  |  Branch (13206:7): [True: 723, False: 1.76M]
  ------------------
13207|    723|        ada_log("OPAQUE_PATH ", helpers::substring(url_data, input_position));
13208|       |        // Opaque path, query, and fragment are structurally always valid:
13209|       |        // the parser would just percent-encode whatever is there. When we
13210|       |        // are not storing values (can_parse), we can return immediately.
13211|       |        // We must set has_opaque_path = true before returning so that when
13212|       |        // this URL is used as an internal base inside can_parse, NO_SCHEME
13213|       |        // correctly rejects relative inputs against an opaque-path base
13214|       |        // (e.g. can_parse("", &"W:") must return false).
13215|       |        if constexpr (!store_values) {
13216|       |          url.has_opaque_path = true;
13217|       |          return url;
13218|       |        }
13219|    723|        std::string_view view = url_data.substr(input_position);
13220|       |        // If c is U+003F (?), then set url's query to the empty string and
13221|       |        // state to query state.
13222|    723|        size_t location = view.find('?');
13223|    723|        if (location != std::string_view::npos) {
  ------------------
  |  Branch (13223:13): [True: 423, False: 300]
  ------------------
13224|    423|          view.remove_suffix(view.size() - location);
13225|    423|          state = state::QUERY;
13226|    423|          input_position += location + 1;
13227|    423|        } else {
13228|    300|          input_position = input_size + 1;
13229|    300|        }
13230|    723|        url.has_opaque_path = true;
13231|       |
13232|       |        // This is a really unlikely scenario in real world. We should not seek
13233|       |        // to optimize it.
13234|    723|        if (view.ends_with(' ')) {
  ------------------
  |  Branch (13234:13): [True: 9, False: 714]
  ------------------
13235|      9|          std::string modified_view =
13236|      9|              std::string(view.substr(0, view.size() - 1)) + "%20";
13237|      9|          url.update_base_pathname(unicode::percent_encode(
13238|      9|              modified_view, character_sets::C0_CONTROL_PERCENT_ENCODE));
13239|    714|        } else {
13240|    714|          url.update_base_pathname(unicode::percent_encode(
13241|    714|              view, character_sets::C0_CONTROL_PERCENT_ENCODE));
13242|    714|        }
13243|    723|        break;
13244|   258k|      }
13245|  2.29k|      case state::PORT: {
  ------------------
  |  Branch (13245:7): [True: 2.29k, False: 1.76M]
  ------------------
13246|  2.29k|        ada_log("PORT ", helpers::substring(url_data, input_position));
13247|  2.29k|        std::string_view port_view = url_data.substr(input_position);
13248|  2.29k|        input_position += url.parse_port(port_view, true);
13249|  2.29k|        if (!url.is_valid) {
  ------------------
  |  Branch (13249:13): [True: 231, False: 2.06k]
  ------------------
13250|    231|          return url;
13251|    231|        }
13252|  2.06k|        state = state::PATH_START;
13253|  2.06k|        [[fallthrough]];
13254|  2.06k|      }
13255|   239k|      case state::PATH_START: {
  ------------------
  |  Branch (13255:7): [True: 237k, False: 1.52M]
  ------------------
13256|   239k|        ada_log("PATH_START ", helpers::substring(url_data, input_position));
13257|       |        // Path, query, and fragment are structurally always valid: the
13258|       |        // parser would just percent-encode whatever is there. When we are
13259|       |        // not storing values (can_parse), we can return immediately since
13260|       |        // no subsequent state can invalidate the URL.
13261|       |        if constexpr (!store_values) {
13262|       |          return url;
13263|       |        }
13264|       |
13265|       |        // If url is special, then:
13266|   239k|        if (url.is_special()) {
  ------------------
  |  Branch (13266:13): [True: 238k, False: 702]
  ------------------
13267|       |          // Set state to path state.
13268|   238k|          state = state::PATH;
13269|       |
13270|       |          // Optimization: Avoiding going into PATH state improves the
13271|       |          // performance of urls ending with /.
13272|   238k|          if (input_position == input_size) {
  ------------------
  |  Branch (13272:15): [True: 29.8k, False: 208k]
  ------------------
13273|  29.8k|            if constexpr (store_values) {
13274|  29.8k|              url.update_base_pathname("/");
13275|  29.8k|              if (fragment.has_value()) {
  ------------------
  |  Branch (13275:19): [True: 261, False: 29.5k]
  ------------------
13276|    261|                url.update_unencoded_base_hash(*fragment);
13277|    261|              }
13278|  29.8k|            }
13279|  29.8k|            enforce_max_input_length();
13280|  29.8k|            return url;
13281|  29.8k|          }
13282|       |          // If c is neither U+002F (/) nor U+005C (\), then decrease pointer
13283|       |          // by 1. We know that (input_position == input_size) is impossible
13284|       |          // here, because of the previous if-check.
13285|   208k|          if ((url_data[input_position] != '/') &&
  ------------------
  |  Branch (13285:15): [True: 1.05k, False: 207k]
  ------------------
13286|  1.05k|              (url_data[input_position] != '\\')) {
  ------------------
  |  Branch (13286:15): [True: 640, False: 410]
  ------------------
13287|    640|            break;
13288|    640|          }
13289|   208k|        }
13290|       |        // Otherwise, if state override is not given and c is U+003F (?),
13291|       |        // set url's query to the empty string and state to query state.
13292|    702|        else if ((input_position != input_size) &&
  ------------------
  |  Branch (13292:18): [True: 546, False: 156]
  ------------------
13293|    546|                 (url_data[input_position] == '?')) {
  ------------------
  |  Branch (13293:18): [True: 102, False: 444]
  ------------------
13294|    102|          state = state::QUERY;
13295|    102|        }
13296|       |        // Otherwise, if c is not the EOF code point:
13297|    600|        else if (input_position != input_size) {
  ------------------
  |  Branch (13297:18): [True: 444, False: 156]
  ------------------
13298|       |          // Set state to path state.
13299|    444|          state = state::PATH;
13300|       |
13301|       |          // If c is not U+002F (/), then decrease pointer by 1.
13302|    444|          if (url_data[input_position] != '/') {
  ------------------
  |  Branch (13302:15): [True: 0, False: 444]
  ------------------
13303|      0|            break;
13304|      0|          }
13305|    444|        }
13306|       |
13307|   208k|        input_position++;
13308|   208k|        break;
13309|   239k|      }
13310|   209k|      case state::PATH: {
  ------------------
  |  Branch (13310:7): [True: 209k, False: 1.55M]
  ------------------
13311|   209k|        ada_log("PATH ", helpers::substring(url_data, input_position));
13312|       |        // Path, query, and fragment are structurally always valid: the
13313|       |        // parser would just percent-encode whatever is there. When we are
13314|       |        // not storing values (can_parse), we can return immediately since
13315|       |        // no subsequent state can invalidate the URL.
13316|       |        if constexpr (!store_values) {
13317|       |          return url;
13318|       |        }
13319|   209k|        std::string_view view = url_data.substr(input_position);
13320|       |
13321|       |        // Most time, we do not need percent encoding.
13322|       |        // Furthermore, we can immediately locate the '?'.
13323|   209k|        size_t locofquestionmark = view.find('?');
13324|   209k|        if (locofquestionmark != std::string_view::npos) {
  ------------------
  |  Branch (13324:13): [True: 9.69k, False: 199k]
  ------------------
13325|  9.69k|          state = state::QUERY;
13326|  9.69k|          view.remove_suffix(view.size() - locofquestionmark);
13327|  9.69k|          input_position += locofquestionmark + 1;
13328|   199k|        } else {
13329|   199k|          input_position = input_size + 1;
13330|   199k|        }
13331|   209k|        if constexpr (store_values) {
13332|       |          if constexpr (result_type_is_ada_url) {
13333|       |            helpers::parse_prepared_path(view, url.type, url.path);
13334|   209k|          } else {
13335|   209k|            url.consume_prepared_path(view);
13336|   209k|            ADA_ASSERT_TRUE(url.validate());
13337|   209k|          }
13338|   209k|        }
13339|   209k|        break;
13340|   239k|      }
13341|  1.44k|      case state::FILE_SLASH: {
  ------------------
  |  Branch (13341:7): [True: 1.44k, False: 1.76M]
  ------------------
13342|  1.44k|        ada_log("FILE_SLASH ", helpers::substring(url_data, input_position));
13343|       |
13344|       |        // If c is U+002F (/) or U+005C (\), then:
13345|  1.44k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (13345:13): [True: 1.44k, False: 1]
  ------------------
13346|  1.44k|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (13346:14): [True: 1.42k, False: 16]
  ------------------
13347|  1.42k|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (13347:14): [True: 2, False: 14]
  ------------------
13348|  1.42k|          ada_log("FILE_SLASH c is U+002F or U+005C");
13349|       |          // Set state to file host state.
13350|  1.42k|          state = state::FILE_HOST;
13351|  1.42k|          input_position++;
13352|  1.42k|        } else {
13353|     15|          ada_log("FILE_SLASH otherwise");
13354|       |          // If base is non-null and base's scheme is "file", then:
13355|       |          // Note: it is unsafe to do base_url->scheme unless you know that
13356|       |          // base_url_has_value() is true.
13357|     15|          if (base_url != nullptr && base_url->type == scheme::type::FILE) {
  ------------------
  |  Branch (13357:15): [True: 0, False: 15]
  |  Branch (13357:38): [True: 0, False: 0]
  ------------------
13358|       |            // Set url's host to base's host.
13359|       |            if constexpr (result_type_is_ada_url) {
13360|       |              url.host = base_url->host;
13361|      0|            } else {
13362|      0|              url.update_host_to_base_host(base_url->get_host());
13363|      0|            }
13364|       |            // If the code point substring from pointer to the end of input does
13365|       |            // not start with a Windows drive letter and base's path[0] is a
13366|       |            // normalized Windows drive letter, then append base's path[0] to
13367|       |            // url's path.
13368|      0|            if (!base_url->get_pathname().empty()) {
  ------------------
  |  Branch (13368:17): [True: 0, False: 0]
  ------------------
13369|      0|              if (!checkers::is_windows_drive_letter(
  ------------------
  |  Branch (13369:19): [True: 0, False: 0]
  ------------------
13370|      0|                      url_data.substr(input_position))) {
13371|      0|                std::string_view first_base_url_path =
13372|      0|                    base_url->get_pathname().substr(1);
13373|      0|                size_t loc = first_base_url_path.find('/');
13374|      0|                if (loc != std::string_view::npos) {
  ------------------
  |  Branch (13374:21): [True: 0, False: 0]
  ------------------
13375|      0|                  helpers::resize(first_base_url_path, loc);
13376|      0|                }
13377|      0|                if (checkers::is_normalized_windows_drive_letter(
  ------------------
  |  Branch (13377:21): [True: 0, False: 0]
  ------------------
13378|      0|                        first_base_url_path)) {
13379|       |                  if constexpr (result_type_is_ada_url) {
13380|       |                    url.path += '/';
13381|       |                    url.path += first_base_url_path;
13382|      0|                  } else {
13383|      0|                    url.append_base_pathname(
13384|      0|                        helpers::concat("/", first_base_url_path));
13385|      0|                  }
13386|      0|                }
13387|      0|              }
13388|      0|            }
13389|      0|          }
13390|       |
13391|       |          // Set state to path state, and decrease pointer by 1.
13392|     15|          state = state::PATH;
13393|     15|        }
13394|       |
13395|  1.44k|        break;
13396|   239k|      }
13397|  1.42k|      case state::FILE_HOST: {
  ------------------
  |  Branch (13397:7): [True: 1.42k, False: 1.76M]
  ------------------
13398|  1.42k|        ada_log("FILE_HOST ", helpers::substring(url_data, input_position));
13399|  1.42k|        std::string_view view = url_data.substr(input_position);
13400|       |
13401|  1.42k|        size_t location = view.find_first_of("/\\?");
13402|  1.42k|        std::string_view file_host_buffer = view.substr(
13403|  1.42k|            0, (location != std::string_view::npos) ? location : view.size());
  ------------------
  |  Branch (13403:16): [True: 1.38k, False: 43]
  ------------------
13404|       |
13405|  1.42k|        if (checkers::is_windows_drive_letter(file_host_buffer)) {
  ------------------
  |  Branch (13405:13): [True: 1, False: 1.42k]
  ------------------
13406|      1|          state = state::PATH;
13407|  1.42k|        } else if (file_host_buffer.empty()) {
  ------------------
  |  Branch (13407:20): [True: 310, False: 1.11k]
  ------------------
13408|       |          // Set url's host to the empty string.
13409|       |          if constexpr (result_type_is_ada_url) {
13410|       |            url.host = "";
13411|    310|          } else {
13412|    310|            url.update_base_hostname("");
13413|    310|          }
13414|       |          // Set state to path start state.
13415|    310|          state = state::PATH_START;
13416|  1.11k|        } else {
13417|  1.11k|          size_t consumed_bytes = file_host_buffer.size();
13418|  1.11k|          input_position += consumed_bytes;
13419|       |          // Let host be the result of host parsing buffer with url is not
13420|       |          // special.
13421|  1.11k|          if (!url.parse_host(file_host_buffer)) {
  ------------------
  |  Branch (13421:15): [True: 89, False: 1.02k]
  ------------------
13422|     89|            return url;
13423|     89|          }
13424|       |
13425|       |          if constexpr (result_type_is_ada_url) {
13426|       |            // If host is "localhost", then set host to the empty string.
13427|       |            if (url.host.has_value() && url.host.value() == "localhost") {
13428|       |              url.host = "";
13429|       |            }
13430|  1.02k|          } else {
13431|  1.02k|            if (url.get_hostname() == "localhost") {
  ------------------
  |  Branch (13431:17): [True: 3, False: 1.02k]
  ------------------
13432|      3|              url.update_base_hostname("");
13433|      3|            }
13434|  1.02k|          }
13435|       |
13436|       |          // Set buffer to the empty string and state to path start state.
13437|  1.02k|          state = state::PATH_START;
13438|  1.02k|        }
13439|       |
13440|  1.34k|        break;
13441|  1.42k|      }
13442|  1.57k|      case state::FILE: {
  ------------------
  |  Branch (13442:7): [True: 1.57k, False: 1.76M]
  ------------------
13443|  1.57k|        ada_log("FILE ", helpers::substring(url_data, input_position));
13444|  1.57k|        std::string_view file_view = url_data.substr(input_position);
13445|       |
13446|  1.57k|        url.set_protocol_as_file();
13447|       |        if constexpr (result_type_is_ada_url) {
13448|       |          // Set url's host to the empty string.
13449|       |          url.host = "";
13450|  1.57k|        } else {
13451|  1.57k|          url.update_base_hostname("");
13452|  1.57k|        }
13453|       |        // If c is U+002F (/) or U+005C (\), then:
13454|  1.57k|        if (input_position != input_size &&
  ------------------
  |  Branch (13454:13): [True: 1.57k, False: 1]
  ------------------
13455|  1.57k|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (13455:14): [True: 1.44k, False: 132]
  ------------------
13456|  1.44k|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (13456:14): [True: 3, False: 129]
  ------------------
13457|  1.44k|          ada_log("FILE c is U+002F or U+005C");
13458|       |          // Set state to file slash state.
13459|  1.44k|          state = state::FILE_SLASH;
13460|  1.44k|        }
13461|       |        // Otherwise, if base is non-null and base's scheme is "file":
13462|    130|        else if (base_url != nullptr && base_url->type == scheme::type::FILE) {
  ------------------
  |  Branch (13462:18): [True: 0, False: 130]
  |  Branch (13462:41): [True: 0, False: 0]
  ------------------
13463|       |          // Set url's host to base's host, url's path to a clone of base's
13464|       |          // path, and url's query to base's query.
13465|      0|          ada_log("FILE base non-null");
13466|       |          if constexpr (result_type_is_ada_url) {
13467|       |            url.host = base_url->host;
13468|       |            url.path = base_url->path;
13469|       |            url.query = base_url->query;
13470|      0|          } else {
13471|      0|            url.update_host_to_base_host(base_url->get_hostname());
13472|      0|            url.update_base_pathname(base_url->get_pathname());
13473|      0|            if (base_url->has_search()) {
  ------------------
  |  Branch (13473:17): [True: 0, False: 0]
  ------------------
13474|       |              // get_search() returns "" for an empty query string (URL ends
13475|       |              // with '?'). update_base_search("") would incorrectly clear the
13476|       |              // query, so pass "?" to preserve the empty query distinction.
13477|      0|              auto s = base_url->get_search();
13478|      0|              url.update_base_search(s.empty() ? std::string_view("?") : s);
  ------------------
  |  Branch (13478:38): [True: 0, False: 0]
  ------------------
13479|      0|            }
13480|      0|          }
13481|      0|          url.has_opaque_path = base_url->has_opaque_path;
13482|       |
13483|       |          // If c is U+003F (?), then set url's query to the empty string and
13484|       |          // state to query state.
13485|      0|          if (input_position != input_size && url_data[input_position] == '?') {
  ------------------
  |  Branch (13485:15): [True: 0, False: 0]
  |  Branch (13485:47): [True: 0, False: 0]
  ------------------
13486|      0|            state = state::QUERY;
13487|      0|          }
13488|       |          // Otherwise, if c is not the EOF code point:
13489|      0|          else if (input_position != input_size) {
  ------------------
  |  Branch (13489:20): [True: 0, False: 0]
  ------------------
13490|       |            // Set url's query to null.
13491|      0|            url.clear_search();
13492|       |            // If the code point substring from pointer to the end of input does
13493|       |            // not start with a Windows drive letter, then shorten url's path.
13494|      0|            if (!checkers::is_windows_drive_letter(file_view)) {
  ------------------
  |  Branch (13494:17): [True: 0, False: 0]
  ------------------
13495|       |              if constexpr (result_type_is_ada_url) {
13496|       |                helpers::shorten_path(url.path, url.type);
13497|      0|              } else {
13498|      0|                std::string_view path = url.get_pathname();
13499|      0|                if (helpers::shorten_path(path, url.type)) {
  ------------------
  |  Branch (13499:21): [True: 0, False: 0]
  ------------------
13500|      0|                  url.update_base_pathname(std::move(std::string(path)));
13501|      0|                }
13502|      0|              }
13503|      0|            }
13504|       |            // Otherwise:
13505|      0|            else {
13506|       |              // Set url's path to an empty list.
13507|      0|              url.clear_pathname();
13508|      0|              url.has_opaque_path = true;
13509|      0|            }
13510|       |
13511|       |            // Set state to path state and decrease pointer by 1.
13512|      0|            state = state::PATH;
13513|      0|            break;
13514|      0|          }
13515|      0|        }
13516|       |        // Otherwise, set state to path state, and decrease pointer by 1.
13517|    130|        else {
13518|    130|          ada_log("FILE go to path");
13519|    130|          state = state::PATH;
13520|    130|          break;
13521|    130|        }
13522|       |
13523|  1.44k|        input_position++;
13524|  1.44k|        break;
13525|  1.57k|      }
13526|      0|      default:
  ------------------
  |  Branch (13526:7): [True: 0, False: 1.76M]
  ------------------
13527|      0|        unreachable();
13528|  1.76M|    }
13529|  1.76M|  }
13530|   543k|  if constexpr (store_values) {
13531|   543k|    if (fragment.has_value()) {
  ------------------
  |  Branch (13531:9): [True: 2.34k, False: 541k]
  ------------------
13532|  2.34k|      url.update_unencoded_base_hash(*fragment);
13533|  2.34k|    }
13534|   543k|  }
13535|   543k|  enforce_max_input_length();
13536|   543k|  return url;
13537|   604k|}
_ZN3ada14url_aggregator8set_hrefENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
14106|   194k|bool url_aggregator::set_href(const std::string_view input) {
14107|   194k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
14108|   194k|  ada_log("url_aggregator::set_href ", input, " [", input.size(), " bytes]");
14109|   194k|  ada::result<url_aggregator> out = ada::parse<url_aggregator>(input);
14110|   194k|  ada_log("url_aggregator::set_href, success :", out.has_value());
14111|       |
14112|   194k|  if (out) {
  ------------------
  |  Branch (14112:7): [True: 194k, False: 0]
  ------------------
14113|       |    // The parser enforces get_max_input_length() on both the input and the
14114|       |    // normalized result. This is a defense-in-depth check.
14115|   194k|    if (out->buffer.size() > ada::get_max_input_length()) {
  ------------------
  |  Branch (14115:9): [True: 0, False: 194k]
  ------------------
14116|      0|      return false;
14117|      0|    }
14118|   194k|    ada_log("url_aggregator::set_href, parsed ", out->to_string());
14119|       |    // TODO: Figure out why the following line puts test to never finish.
14120|   194k|    *this = *out;
14121|   194k|  }
14122|       |
14123|   194k|  return out.has_value();
14124|   194k|}
_ZNK3ada14url_aggregator12get_usernameEv:
14442|   194k|    ada_lifetime_bound {
14443|   194k|  ada_log("url_aggregator::get_username");
14444|   194k|  if (has_non_empty_username()) {
  ------------------
  |  Branch (14444:7): [True: 9.97k, False: 184k]
  ------------------
14445|  9.97k|    return helpers::substring(buffer, components.protocol_end + 2,
14446|  9.97k|                              components.username_end);
14447|  9.97k|  }
14448|   184k|  return "";
14449|   194k|}
_ZNK3ada14url_aggregator12get_passwordEv:
14452|   194k|    ada_lifetime_bound {
14453|   194k|  ada_log("url_aggregator::get_password");
14454|   194k|  if (has_non_empty_password()) {
  ------------------
  |  Branch (14454:7): [True: 9.63k, False: 184k]
  ------------------
14455|  9.63k|    return helpers::substring(buffer, components.username_end + 1,
14456|  9.63k|                              components.host_start);
14457|  9.63k|  }
14458|   184k|  return "";
14459|   194k|}
_ZNK3ada14url_aggregator8get_portEv:
14462|   194k|    ada_lifetime_bound {
14463|   194k|  ada_log("url_aggregator::get_port");
14464|   194k|  if (components.port == url_components::omitted) {
  ------------------
  |  Branch (14464:7): [True: 174k, False: 20.0k]
  ------------------
14465|   174k|    return "";
14466|   174k|  }
14467|  20.0k|  return helpers::substring(buffer, components.host_end + 1,
14468|  20.0k|                            components.pathname_start);
14469|   194k|}
_ZNK3ada14url_aggregator8get_hashEv:
14472|   194k|    ada_lifetime_bound {
14473|   194k|  ada_log("url_aggregator::get_hash");
14474|       |  // If this's URL's fragment is either null or the empty string, then return
14475|       |  // the empty string. Return U+0023 (#), followed by this's URL's fragment.
14476|   194k|  if (components.hash_start == url_components::omitted) {
  ------------------
  |  Branch (14476:7): [True: 170k, False: 23.8k]
  ------------------
14477|   170k|    return "";
14478|   170k|  }
14479|  23.8k|  if (buffer.size() - components.hash_start <= 1) {
  ------------------
  |  Branch (14479:7): [True: 1.49k, False: 22.3k]
  ------------------
14480|  1.49k|    return "";
14481|  1.49k|  }
14482|  22.3k|  return helpers::substring(buffer, components.hash_start);
14483|  23.8k|}
_ZNK3ada14url_aggregator8get_hostEv:
14486|   194k|    ada_lifetime_bound {
14487|   194k|  ada_log("url_aggregator::get_host");
14488|       |  // Technically, we should check if there is a hostname, but
14489|       |  // the code below works even if there isn't.
14490|       |  // if(!has_hostname()) { return ""; }
14491|   194k|  size_t start = components.host_start;
14492|   194k|  if (components.host_end > components.host_start &&
  ------------------
  |  Branch (14492:7): [True: 193k, False: 546]
  ------------------
14493|   193k|      buffer[components.host_start] == '@') {
  ------------------
  |  Branch (14493:7): [True: 10.0k, False: 183k]
  ------------------
14494|  10.0k|    start++;
14495|  10.0k|  }
14496|       |  // if we have an empty host, then the space between components.host_end and
14497|       |  // components.pathname_start may be occupied by /.
14498|   194k|  if (start == components.host_end) {
  ------------------
  |  Branch (14498:7): [True: 546, False: 193k]
  ------------------
14499|    546|    return {};
14500|    546|  }
14501|   193k|  return helpers::substring(buffer, start, components.pathname_start);
14502|   194k|}
_ZNK3ada14url_aggregator12get_hostnameEv:
14505|   258k|    ada_lifetime_bound {
14506|   258k|  ada_log("url_aggregator::get_hostname");
14507|       |  // Technically, we should check if there is a hostname, but
14508|       |  // the code below works even if there isn't.
14509|       |  // if(!has_hostname()) { return ""; }
14510|   258k|  size_t start = components.host_start;
14511|       |  // So host_start is not where the host begins.
14512|   258k|  if (components.host_end > components.host_start &&
  ------------------
  |  Branch (14512:7): [True: 195k, False: 63.1k]
  ------------------
14513|   195k|      buffer[components.host_start] == '@') {
  ------------------
  |  Branch (14513:7): [True: 10.2k, False: 185k]
  ------------------
14514|  10.2k|    start++;
14515|  10.2k|  }
14516|   258k|  return helpers::substring(buffer, start, components.host_end);
14517|   258k|}
_ZNK3ada14url_aggregator10get_searchEv:
14520|   194k|    ada_lifetime_bound {
14521|   194k|  ada_log("url_aggregator::get_search");
14522|       |  // If this's URL's query is either null or the empty string, then return the
14523|       |  // empty string. Return U+003F (?), followed by this's URL's query.
14524|   194k|  if (components.search_start == url_components::omitted) {
  ------------------
  |  Branch (14524:7): [True: 161k, False: 33.0k]
  ------------------
14525|   161k|    return "";
14526|   161k|  }
14527|  33.0k|  auto ending_index = uint32_t(buffer.size());
14528|  33.0k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (14528:7): [True: 13.1k, False: 19.8k]
  ------------------
14529|  13.1k|    ending_index = components.hash_start;
14530|  13.1k|  }
14531|  33.0k|  if (ending_index - components.search_start <= 1) {
  ------------------
  |  Branch (14531:7): [True: 1.10k, False: 31.9k]
  ------------------
14532|  1.10k|    return "";
14533|  1.10k|  }
14534|  31.9k|  return helpers::substring(buffer, components.search_start, ending_index);
14535|  33.0k|}
_ZNK3ada14url_aggregator12get_protocolEv:
14538|   194k|    ada_lifetime_bound {
14539|   194k|  ada_log("url_aggregator::get_protocol");
14540|   194k|  return helpers::substring(buffer, 0, components.protocol_end);
14541|   194k|}
_ZN3ada14url_aggregator10parse_ipv4ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEb:
14650|  57.0k|bool url_aggregator::parse_ipv4(std::string_view input, bool in_place) {
14651|  57.0k|  ada_log("parse_ipv4 ", input, " [", input.size(),
14652|  57.0k|          " bytes], overlaps with buffer: ",
14653|  57.0k|          helpers::overlaps(input, buffer) ? "yes" : "no");
14654|  57.0k|  ADA_ASSERT_TRUE(validate());
14655|  57.0k|  if (input.empty()) {
  ------------------
  |  Branch (14655:7): [True: 0, False: 57.0k]
  ------------------
14656|      0|    return is_valid = false;
14657|      0|  }
14658|  57.0k|  const bool trailing_dot = (input.back() == '.');
14659|  57.0k|  if (trailing_dot) {
  ------------------
  |  Branch (14659:7): [True: 27.5k, False: 29.5k]
  ------------------
14660|  27.5k|    input.remove_suffix(1);
14661|  27.5k|    if (input.empty()) {
  ------------------
  |  Branch (14661:9): [True: 0, False: 27.5k]
  ------------------
14662|      0|      return is_valid = false;
14663|      0|    }
14664|  27.5k|  }
14665|       |
14666|  57.0k|  const uint64_t fast = checkers::try_parse_ipv4_fast(input);
14667|  57.0k|  if (fast < checkers::ipv4_fast_fail) [[likely]] {
  ------------------
  |  Branch (14667:7): [True: 18.3k, False: 38.7k]
  ------------------
14668|       |    // Pure decimal: keep the buffer when it already holds the address.
14669|       |    // Otherwise write the (trailing-dot-stripped) input.
14670|  18.3k|    if (!(in_place && !trailing_dot)) {
  ------------------
  |  Branch (14670:11): [True: 18.3k, False: 6]
  |  Branch (14670:23): [True: 4, False: 18.3k]
  ------------------
14671|  18.3k|      if (helpers::overlaps(input, buffer)) {
  ------------------
  |  Branch (14671:11): [True: 0, False: 18.3k]
  ------------------
14672|      0|        update_base_hostname(std::string(input));
14673|  18.3k|      } else {
14674|  18.3k|        update_base_hostname(input);
14675|  18.3k|      }
14676|  18.3k|    }
14677|  18.3k|    host_type = IPV4;
14678|  18.3k|    ADA_ASSERT_TRUE(validate());
14679|  18.3k|    return true;
14680|  18.3k|  }
14681|       |
14682|  38.7k|  const char* p = input.data();
14683|  38.7k|  const char* end = p + input.size();
14684|  38.7k|  uint64_t ipv4 = 0;
14685|  38.7k|  int digit_count = 0;
14686|  38.7k|  int pure_decimal_count = 0;
14687|       |
14688|  48.8k|  for (; digit_count < 4 && p < end; ++digit_count) {
  ------------------
  |  Branch (14688:10): [True: 48.8k, False: 14]
  |  Branch (14688:29): [True: 48.8k, False: 0]
  ------------------
14689|  48.8k|    uint64_t segment = 0;
14690|  48.8k|    bool pure = false;
14691|  48.8k|    if (!detail::parse_ipv4_number(p, end, segment, pure)) {
  ------------------
  |  Branch (14691:9): [True: 18.6k, False: 30.1k]
  ------------------
14692|  18.6k|      return is_valid = false;
14693|  18.6k|    }
14694|  30.1k|    if (pure) {
  ------------------
  |  Branch (14694:9): [True: 11.2k, False: 18.9k]
  ------------------
14695|  11.2k|      ++pure_decimal_count;
14696|  11.2k|    }
14697|  30.1k|    if (p >= end) {
  ------------------
  |  Branch (14697:9): [True: 20.0k, False: 10.1k]
  ------------------
14698|  20.0k|      const unsigned shift = static_cast<unsigned>(32 - digit_count * 8);
14699|  20.0k|      if (segment >= (uint64_t{1} << shift)) {
  ------------------
  |  Branch (14699:11): [True: 23, False: 20.0k]
  ------------------
14700|     23|        return is_valid = false;
14701|     23|      }
14702|  20.0k|      ipv4 = (ipv4 << shift) | segment;
14703|  20.0k|      goto ipv4_done;
14704|  20.0k|    }
14705|  10.1k|    if (segment > 255 || *p != '.') {
  ------------------
  |  Branch (14705:9): [True: 47, False: 10.0k]
  |  Branch (14705:26): [True: 0, False: 10.0k]
  ------------------
14706|     47|      return is_valid = false;
14707|     47|    }
14708|  10.0k|    ipv4 = (ipv4 << 8) | segment;
14709|  10.0k|    ++p;
14710|  10.0k|  }
14711|     14|  if (digit_count != 4 || p != end) {
  ------------------
  |  Branch (14711:7): [True: 0, False: 14]
  |  Branch (14711:27): [True: 14, False: 0]
  ------------------
14712|     14|    return is_valid = false;
14713|     14|  }
14714|  20.0k|ipv4_done:
14715|  20.0k|  ada_log("url_aggregator::parse_ipv4 completed ", get_href(),
14716|  20.0k|          " host: ", get_host());
14717|  20.0k|  if (in_place && pure_decimal_count == 4 && !trailing_dot) {
  ------------------
  |  Branch (14717:7): [True: 19.9k, False: 54]
  |  Branch (14717:19): [True: 0, False: 19.9k]
  |  Branch (14717:46): [True: 0, False: 0]
  ------------------
14718|      0|    ada_log(
14719|      0|        "url_aggregator::parse_ipv4 completed and was already correct in the "
14720|      0|        "buffer");
14721|  20.0k|  } else {
14722|  20.0k|    update_base_hostname(ada::serializers::ipv4(ipv4));
14723|  20.0k|  }
14724|  20.0k|  host_type = IPV4;
14725|  20.0k|  ADA_ASSERT_TRUE(validate());
14726|  20.0k|  return true;
14727|     14|}
_ZN3ada14url_aggregator10parse_ipv6ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
14729|    604|bool url_aggregator::parse_ipv6(std::string_view input) {
14730|    604|  ada_log("parse_ipv6 ", input, " [", input.size(), " bytes]");
14731|    604|  ADA_ASSERT_TRUE(validate());
14732|    604|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
14733|    604|  if (input.empty() || input.size() > 45) [[unlikely]] {
  ------------------
  |  Branch (14733:7): [True: 19, False: 585]
  |  Branch (14733:24): [True: 13, False: 572]
  ------------------
14734|     32|    return is_valid = false;
14735|     32|  }
14736|    572|  std::array<uint16_t, 8> address{};
14737|       |#if defined(ADA_AVX512_IPV6)
14738|       |  if (bool simd_valid; detail::try_parse_ipv6_avx512(input.data(), input.size(),
14739|       |                                                     address, simd_valid)) {
14740|       |    if (!simd_valid) [[unlikely]] {
14741|       |      return is_valid = false;
14742|       |    }
14743|       |    const std::string serialized = ada::serializers::ipv6(address);
14744|       |    if (get_hostname() != serialized) {
14745|       |      update_base_hostname(serialized);
14746|       |    }
14747|       |    host_type = IPV6;
14748|       |    return true;
14749|       |  }
14750|       |  address = {};
14751|       |#endif
14752|    572|  const char* pointer = input.data();
14753|    572|  const char* const end = pointer + input.size();
14754|    572|  int piece_index = 0;
14755|    572|  int compress = -1;
14756|       |
14757|    572|  if (*pointer == ':') {
  ------------------
  |  Branch (14757:7): [True: 275, False: 297]
  ------------------
14758|    275|    if (input.size() == 1 || pointer[1] != ':') [[unlikely]] {
  ------------------
  |  Branch (14758:9): [True: 3, False: 272]
  |  Branch (14758:30): [True: 7, False: 265]
  ------------------
14759|     10|      return is_valid = false;
14760|     10|    }
14761|    265|    pointer += 2;
14762|    265|    compress = ++piece_index;
14763|    265|  }
14764|       |
14765|  1.60k|  while (pointer != end) {
  ------------------
  |  Branch (14765:10): [True: 1.15k, False: 447]
  ------------------
14766|  1.15k|    if (piece_index == 8) [[unlikely]] {
  ------------------
  |  Branch (14766:9): [True: 3, False: 1.15k]
  ------------------
14767|      3|      return is_valid = false;
14768|      3|    }
14769|  1.15k|    if (*pointer == ':') {
  ------------------
  |  Branch (14769:9): [True: 157, False: 993]
  ------------------
14770|    157|      if (compress != -1) [[unlikely]] {
  ------------------
  |  Branch (14770:11): [True: 3, False: 154]
  ------------------
14771|      3|        return is_valid = false;
14772|      3|      }
14773|    154|      ++pointer;
14774|    154|      compress = ++piece_index;
14775|    154|      continue;
14776|    157|    }
14777|       |
14778|    993|    uint16_t value = 0;
14779|    993|    const int length = detail::parse_hex_piece(pointer, end, value);
14780|       |
14781|    993|    if (pointer != end && *pointer == '.') {
  ------------------
  |  Branch (14781:9): [True: 763, False: 230]
  |  Branch (14781:27): [True: 77, False: 686]
  ------------------
14782|     77|      if (length == 0) [[unlikely]] {
  ------------------
  |  Branch (14782:11): [True: 3, False: 74]
  ------------------
14783|      3|        return is_valid = false;
14784|      3|      }
14785|     74|      pointer -= length;
14786|     74|      if (piece_index > 6) [[unlikely]] {
  ------------------
  |  Branch (14786:11): [True: 3, False: 71]
  ------------------
14787|      3|        return is_valid = false;
14788|      3|      }
14789|       |
14790|     71|      int numbers_seen = 0;
14791|    209|      while (pointer != end) {
  ------------------
  |  Branch (14791:14): [True: 191, False: 18]
  ------------------
14792|    191|        int ipv4_piece = -1;
14793|    191|        if (numbers_seen > 0) {
  ------------------
  |  Branch (14793:13): [True: 120, False: 71]
  ------------------
14794|    120|          if (*pointer == '.' && numbers_seen < 4) {
  ------------------
  |  Branch (14794:15): [True: 104, False: 16]
  |  Branch (14794:34): [True: 98, False: 6]
  ------------------
14795|     98|            ++pointer;
14796|     98|          } else {
14797|     22|            return is_valid = false;
14798|     22|          }
14799|    120|        }
14800|    169|        if (pointer == end || *pointer < '0' || *pointer > '9') [[unlikely]] {
  ------------------
  |  Branch (14800:13): [True: 14, False: 155]
  |  Branch (14800:31): [True: 6, False: 149]
  |  Branch (14800:49): [True: 3, False: 146]
  ------------------
14801|     23|          return is_valid = false;
14802|     23|        }
14803|    146|        ipv4_piece = *pointer - '0';
14804|    146|        ++pointer;
14805|    146|        if (pointer != end && *pointer >= '0' && *pointer <= '9') {
  ------------------
  |  Branch (14805:13): [True: 136, False: 10]
  |  Branch (14805:31): [True: 59, False: 77]
  |  Branch (14805:50): [True: 55, False: 4]
  ------------------
14806|     55|          if (ipv4_piece == 0) [[unlikely]] {
  ------------------
  |  Branch (14806:15): [True: 3, False: 52]
  ------------------
14807|      3|            return is_valid = false;
14808|      3|          }
14809|     52|          ipv4_piece = ipv4_piece * 10 + (*pointer - '0');
14810|     52|          ++pointer;
14811|     52|          if (pointer != end && *pointer >= '0' && *pointer <= '9') {
  ------------------
  |  Branch (14811:15): [True: 49, False: 3]
  |  Branch (14811:33): [True: 28, False: 21]
  |  Branch (14811:52): [True: 25, False: 3]
  ------------------
14812|     25|            ipv4_piece = ipv4_piece * 10 + (*pointer - '0');
14813|     25|            ++pointer;
14814|     25|            if (ipv4_piece > 255) [[unlikely]] {
  ------------------
  |  Branch (14814:17): [True: 5, False: 20]
  ------------------
14815|      5|              return is_valid = false;
14816|      5|            }
14817|     25|          }
14818|     52|        }
14819|    138|        address[static_cast<size_t>(piece_index)] = static_cast<uint16_t>(
14820|    138|            address[static_cast<size_t>(piece_index)] * 0x100 +
14821|    138|            static_cast<uint16_t>(ipv4_piece));
14822|    138|        ++numbers_seen;
14823|    138|        if (numbers_seen == 2 || numbers_seen == 4) {
  ------------------
  |  Branch (14823:13): [True: 42, False: 96]
  |  Branch (14823:34): [True: 14, False: 82]
  ------------------
14824|     56|          ++piece_index;
14825|     56|        }
14826|    138|      }
14827|     18|      if (numbers_seen != 4) [[unlikely]] {
  ------------------
  |  Branch (14827:11): [True: 12, False: 6]
  ------------------
14828|     12|        return is_valid = false;
14829|     12|      }
14830|      6|      break;
14831|     18|    }
14832|       |
14833|    916|    if (length == 0) [[unlikely]] {
  ------------------
  |  Branch (14833:9): [True: 18, False: 898]
  ------------------
14834|     18|      return is_valid = false;
14835|     18|    }
14836|       |
14837|    898|    if (pointer != end && *pointer == ':') {
  ------------------
  |  Branch (14837:9): [True: 668, False: 230]
  |  Branch (14837:27): [True: 657, False: 11]
  ------------------
14838|    657|      ++pointer;
14839|    657|      if (pointer == end) [[unlikely]] {
  ------------------
  |  Branch (14839:11): [True: 3, False: 654]
  ------------------
14840|      3|        return is_valid = false;
14841|      3|      }
14842|    657|    } else if (pointer != end) [[unlikely]] {
  ------------------
  |  Branch (14842:16): [True: 11, False: 230]
  ------------------
14843|     11|      return is_valid = false;
14844|     11|    }
14845|       |
14846|    884|    address[static_cast<size_t>(piece_index)] = value;
14847|    884|    ++piece_index;
14848|    884|  }
14849|       |
14850|    453|  if (compress != -1) {
  ------------------
  |  Branch (14850:7): [True: 408, False: 45]
  ------------------
14851|    408|    const int right = piece_index - compress;
14852|    408|    if (right > 0) {
  ------------------
  |  Branch (14852:9): [True: 191, False: 217]
  ------------------
14853|    191|      const size_t dest = static_cast<size_t>(8 - right);
14854|    191|      const size_t src = static_cast<size_t>(compress);
14855|    191|      if (dest != src) {
  ------------------
  |  Branch (14855:11): [True: 181, False: 10]
  ------------------
14856|    478|        for (size_t i = static_cast<size_t>(right); i-- > 0;) {
  ------------------
  |  Branch (14856:53): [True: 297, False: 181]
  ------------------
14857|    297|          address[dest + i] = address[src + i];
14858|    297|          address[src + i] = 0;
14859|    297|        }
14860|    181|      }
14861|    191|    }
14862|    408|  } else if (piece_index != 8) [[unlikely]] {
  ------------------
  |  Branch (14862:14): [True: 27, False: 18]
  ------------------
14863|     27|    return is_valid = false;
14864|     27|  }
14865|       |
14866|       |  // Serialize once; skip rewrite when hostname is already canonical.
14867|    426|  const std::string serialized = ada::serializers::ipv6(address);
14868|    426|  const std::string_view current = get_hostname();
14869|    426|  if (current.size() == serialized.size() &&
  ------------------
  |  Branch (14869:7): [True: 0, False: 426]
  ------------------
14870|      0|      std::memcmp(current.data(), serialized.data(), serialized.size()) == 0) {
  ------------------
  |  Branch (14870:7): [True: 0, False: 0]
  ------------------
14871|      0|    ada_log("parse_ipv6 in-place canonical match");
14872|    426|  } else {
14873|    426|    update_base_hostname(serialized);
14874|    426|  }
14875|    426|  ada_log("parse_ipv6 ", get_hostname());
14876|    426|  ADA_ASSERT_TRUE(validate());
14877|    426|  host_type = IPV6;
14878|    426|  return true;
14879|    453|}
_ZN3ada14url_aggregator17parse_opaque_hostENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
14881|    669|bool url_aggregator::parse_opaque_host(std::string_view input) {
14882|    669|  ada_log("parse_opaque_host ", input, " [", input.size(), " bytes]");
14883|    669|  ADA_ASSERT_TRUE(validate());
14884|    669|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
14885|    669|  if (std::ranges::any_of(input, ada::unicode::is_forbidden_host_code_point)) {
  ------------------
  |  Branch (14885:7): [True: 33, False: 636]
  ------------------
14886|     33|    return is_valid = false;
14887|     33|  }
14888|       |
14889|       |  // Return the result of running UTF-8 percent-encode on input using the C0
14890|       |  // control percent-encode set.
14891|    636|  size_t idx = ada::unicode::percent_encode_index(
14892|    636|      input, character_sets::C0_CONTROL_PERCENT_ENCODE);
14893|    636|  if (idx == input.size()) {
  ------------------
  |  Branch (14893:7): [True: 594, False: 42]
  ------------------
14894|    594|    update_base_hostname(input);
14895|    594|  } else {
14896|       |    // We only create a temporary string if we need to.
14897|     42|    update_base_hostname(ada::unicode::percent_encode(
14898|     42|        input, character_sets::C0_CONTROL_PERCENT_ENCODE, idx));
14899|     42|  }
14900|    636|  ADA_ASSERT_TRUE(validate());
14901|    636|  return true;
14902|    669|}
simple_absolute.cc:_ZZN3ada4idna22utf32_length_from_utf8EPKcmENK3$_0clEa:
  272|   255k|  return std::count_if(p, std::next(p, len), [](int8_t c) {
  273|       |    // -65 is 0b10111111, anything larger in two-complement's
  274|       |    // should start a new code point.
  275|   255k|    return c > -65;
  276|   255k|  });
_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|     16|  bool build(const uint8_t* lens, int n) {
  433|     16|    std::memset(counts, 0, sizeof(counts));
  434|     16|    std::memset(first_code, 0, sizeof(first_code));
  435|     16|    std::memset(base_idx, 0, sizeof(base_idx));
  436|     16|    nsymbols = n;
  437|     16|    max_bits = 0;
  438|  1.98k|    for (int i = 0; i < n; i++) {
  ------------------
  |  Branch (438:21): [True: 1.96k, False: 16]
  ------------------
  439|  1.96k|      lengths[i] = lens[i];
  440|  1.96k|      if (lens[i]) {
  ------------------
  |  Branch (440:11): [True: 1.91k, False: 49]
  ------------------
  441|  1.91k|        counts[lens[i]]++;
  442|  1.91k|        if (lens[i] > max_bits) max_bits = lens[i];
  ------------------
  |  Branch (442:13): [True: 46, False: 1.87k]
  ------------------
  443|  1.91k|      }
  444|  1.96k|    }
  445|       |    // Canonical first code for each bit length (RFC 1951).
  446|     16|    int code = 0;
  447|    256|    for (int bits = 1; bits <= MAXBITS; bits++) {
  ------------------
  |  Branch (447:24): [True: 240, False: 16]
  ------------------
  448|    240|      code = (code + counts[bits - 1]) << 1;
  449|    240|      first_code[bits] = code;
  450|    240|    }
  451|     16|    int idx = 0;
  452|    158|    for (int bits = 1; bits <= max_bits; bits++) {
  ------------------
  |  Branch (452:24): [True: 142, False: 16]
  ------------------
  453|    142|      base_idx[bits] = idx;
  454|       |      // assign symbols in symbol order for codes of this length
  455|  21.6k|      for (int sym = 0; sym < n; sym++) {
  ------------------
  |  Branch (455:25): [True: 21.5k, False: 142]
  ------------------
  456|  21.5k|        if (lengths[sym] == bits) {
  ------------------
  |  Branch (456:13): [True: 1.91k, False: 19.6k]
  ------------------
  457|  1.91k|          symbols[idx++] = static_cast<int16_t>(sym);
  458|  1.91k|        }
  459|  21.5k|      }
  460|    142|    }
  461|     16|    return true;
  462|     16|  }
_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|}
_ZN3ada4idna7deflate9BitReader6ensureEi:
  392|   457k|  bool ensure(int n) {
  393|   520k|    while (bits < n) {
  ------------------
  |  Branch (393:12): [True: 62.3k, False: 457k]
  ------------------
  394|  62.3k|      if (p >= end) return false;
  ------------------
  |  Branch (394:11): [True: 0, False: 62.3k]
  ------------------
  395|  62.3k|      acc |= uint32_t(*p++) << bits;
  396|  62.3k|      bits += 8;
  397|  62.3k|    }
  398|   457k|    return true;
  399|   457k|  }
simple_absolute.cc:_ZZN3ada4idna9ascii_mapEPcmENK3$_0clEh:
 5127|   358k|  auto broadcast = [](uint8_t v) -> uint64_t {
 5128|   358k|    return 0x101010101010101ull * v;
 5129|   358k|  };
_ZN3ada4idna13ensure_tablesEv:
 4878|  36.3k|[[nodiscard]] inline bool ensure_tables() noexcept {
 4879|  36.3k|  uint8_t state = tables_init_state.load(std::memory_order_acquire);
 4880|  36.3k|  if (state == kTablesReady) {
  ------------------
  |  Branch (4880:7): [True: 36.3k, False: 1]
  ------------------
 4881|  36.3k|    return true;
 4882|  36.3k|  }
 4883|      1|  if (state == kTablesFailed) {
  ------------------
  |  Branch (4883:7): [True: 0, False: 1]
  ------------------
 4884|      0|    return false;
 4885|      0|  }
 4886|       |
 4887|      1|  uint8_t expected = kTablesUninit;
 4888|      1|  if (tables_init_state.compare_exchange_strong(expected, kTablesInProgress,
  ------------------
  |  Branch (4888:7): [True: 1, False: 0]
  ------------------
 4889|      1|                                                std::memory_order_acq_rel,
 4890|      1|                                                std::memory_order_acquire)) {
 4891|      1|    uint8_t* buffer = new (std::nothrow) uint8_t[table_blob::uncompressed_size];
 4892|      1|    if (buffer == nullptr) {
  ------------------
  |  Branch (4892:9): [True: 0, False: 1]
  ------------------
 4893|      0|      tables_init_state.store(kTablesFailed, std::memory_order_release);
 4894|      0|      return false;
 4895|      0|    }
 4896|       |
 4897|      1|    const size_t n = deflate::inflate_raw(table_blob::compressed,
 4898|      1|                                          table_blob::compressed_size, buffer,
 4899|      1|                                          table_blob::uncompressed_size);
 4900|      1|    if (n != table_blob::uncompressed_size ||
  ------------------
  |  Branch (4900:9): [True: 0, False: 1]
  ------------------
 4901|      1|        crc32_ieee(buffer, n) != table_blob::uncompressed_crc32) {
  ------------------
  |  Branch (4901:9): [True: 0, False: 1]
  ------------------
 4902|      0|      delete[] buffer;
 4903|      0|      tables_init_state.store(kTablesFailed, std::memory_order_release);
 4904|      0|      return false;
 4905|      0|    }
 4906|       |
 4907|       |    // LE payload verified; convert multi-byte fields for big-endian hosts.
 4908|      1|    detail::convert_table_blob_to_host_endian(buffer);
 4909|       |
 4910|      1|    auto at = [&](size_t off) noexcept -> const uint8_t* {
 4911|      1|      return buffer + off;
 4912|      1|    };
 4913|       |
 4914|       |    // Publish all non-atomic pointers before READY. Waiters synchronize via
 4915|       |    // acquire on tables_init_state and then observe these writes.
 4916|      1|    idna_stage1 =
 4917|      1|        reinterpret_cast<const uint16_t*>(at(table_blob::off_idna_stage1));
 4918|      1|    idna_stage2 =
 4919|      1|        reinterpret_cast<const uint16_t*>(at(table_blob::off_idna_stage2));
 4920|      1|    idna_bool_blocks =
 4921|      1|        reinterpret_cast<const uint64_t*>(at(table_blob::off_idna_bool_blocks));
 4922|      1|    idna_utf8_mappings = at(table_blob::off_idna_utf8_mappings);
 4923|       |
 4924|      1|    decomposition_index = at(table_blob::off_decomposition_index);
 4925|      1|    decomposition_block_flat = reinterpret_cast<const uint16_t*>(
 4926|      1|        at(table_blob::off_decomposition_block));
 4927|      1|    decomposition_data = reinterpret_cast<const char32_t*>(
 4928|      1|        at(table_blob::off_decomposition_data));
 4929|      1|    ccc_index = at(table_blob::off_ccc_index);
 4930|      1|    ccc_block_flat = at(table_blob::off_ccc_block);
 4931|      1|    composition_index = at(table_blob::off_composition_index);
 4932|      1|    composition_block_flat = reinterpret_cast<const uint16_t*>(
 4933|      1|        at(table_blob::off_composition_block));
 4934|      1|    composition_data =
 4935|      1|        reinterpret_cast<const char32_t*>(at(table_blob::off_composition_data));
 4936|       |
 4937|      1|    id_continue =
 4938|      1|        reinterpret_cast<range_pair_ptr>(at(table_blob::off_id_continue_flat));
 4939|      1|    id_start =
 4940|      1|        reinterpret_cast<range_pair_ptr>(at(table_blob::off_id_start_flat));
 4941|       |
 4942|      1|    dir_start =
 4943|      1|        reinterpret_cast<const uint32_t*>(at(table_blob::off_dir_start));
 4944|      1|    dir_final =
 4945|      1|        reinterpret_cast<const uint32_t*>(at(table_blob::off_dir_final));
 4946|      1|    dir_value = at(table_blob::off_dir_value);
 4947|      1|    combining_ranges =
 4948|      1|        reinterpret_cast<range_pair_ptr>(at(table_blob::off_combining_flat));
 4949|       |
 4950|      1|    tables_buffer = buffer;
 4951|      1|    tables_init_state.store(kTablesReady, std::memory_order_release);
 4952|      1|    return true;
 4953|      1|  }
 4954|       |
 4955|       |  // Another thread owns init (or finished between our loads).
 4956|      0|  for (uint64_t spins = 0; spins < kTablesSpinLimit; ++spins) {
  ------------------
  |  Branch (4956:28): [True: 0, False: 0]
  ------------------
 4957|      0|    state = tables_init_state.load(std::memory_order_acquire);
 4958|      0|    if (state == kTablesReady) {
  ------------------
  |  Branch (4958:9): [True: 0, False: 0]
  ------------------
 4959|      0|      return true;
 4960|      0|    }
 4961|      0|    if (state == kTablesFailed) {
  ------------------
  |  Branch (4961:9): [True: 0, False: 0]
  ------------------
 4962|      0|      return false;
 4963|      0|    }
 4964|      0|#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || \
 4965|      0|    defined(_M_IX86)
 4966|      0|#if defined(__GNUC__) || defined(__clang__)
 4967|      0|    __builtin_ia32_pause();
 4968|      0|#endif
 4969|       |#elif defined(__aarch64__) || defined(_M_ARM64)
 4970|       |#if defined(__GNUC__) || defined(__clang__)
 4971|       |    asm volatile("yield" ::: "memory");
 4972|       |#endif
 4973|       |#endif
 4974|      0|  }
 4975|       |  // Timed out waiting for a peer - treat as failure rather than hang.
 4976|      0|  return false;
 4977|      0|}
_ZN3ada4idna7deflate11inflate_rawEPKhmPhm:
  528|      1|                          size_t dst_cap) {
  529|      1|  BitReader br(src, src_len);
  530|      1|  size_t out = 0;
  531|      4|  for (;;) {
  532|      4|    uint32_t bfinal = br.get(1);
  533|      4|    uint32_t btype = br.get(2);
  534|      4|    if (bfinal == UINT32_MAX || btype == UINT32_MAX) return 0;
  ------------------
  |  Branch (534:9): [True: 0, False: 4]
  |  Branch (534:33): [True: 0, False: 4]
  ------------------
  535|      4|    if (btype == 0) {
  ------------------
  |  Branch (535:9): [True: 0, False: 4]
  ------------------
  536|       |      // stored
  537|      0|      br.align_byte();
  538|      0|      if (!br.ensure(16)) return 0;
  ------------------
  |  Branch (538:11): [True: 0, False: 0]
  ------------------
  539|       |      // read 16+16 from bit buffer awkwardly - use byte path
  540|       |      // Align: bits is multiple of 8
  541|       |      // Get len from remaining bits then bytes
  542|      0|      uint32_t len = br.get(16);
  543|      0|      uint32_t nlen = br.get(16);
  544|      0|      if (len == UINT32_MAX || nlen == UINT32_MAX) return 0;
  ------------------
  |  Branch (544:11): [True: 0, False: 0]
  |  Branch (544:32): [True: 0, False: 0]
  ------------------
  545|      0|      if ((len ^ 0xFFFF) != nlen) return 0;
  ------------------
  |  Branch (545:11): [True: 0, False: 0]
  ------------------
  546|       |      // After get, may have bits in acc from previous - for stored, should be
  547|       |      // byte aligned Copy len bytes from p
  548|      0|      if (br.bits != 0) {
  ------------------
  |  Branch (548:11): [True: 0, False: 0]
  ------------------
  549|       |        // leftover bits should be 0 if aligned
  550|      0|      }
  551|      0|      if (size_t(br.end - br.p) < len) return 0;
  ------------------
  |  Branch (551:11): [True: 0, False: 0]
  ------------------
  552|      0|      if (out + len > dst_cap) return 0;
  ------------------
  |  Branch (552:11): [True: 0, False: 0]
  ------------------
  553|      0|      std::memcpy(dst + out, br.p, len);
  554|      0|      br.p += len;
  555|      0|      out += len;
  556|      4|    } else if (btype == 1 || btype == 2) {
  ------------------
  |  Branch (556:16): [True: 0, False: 4]
  |  Branch (556:30): [True: 4, False: 0]
  ------------------
  557|      4|      Huff lit, dist;
  558|      4|      if (btype == 1) {
  ------------------
  |  Branch (558:11): [True: 0, False: 4]
  ------------------
  559|       |        // use fixed via functions
  560|      4|      } else {
  561|       |        // dynamic
  562|      4|        uint32_t hlit = br.get(5);
  563|      4|        if (hlit == UINT32_MAX) return 0;
  ------------------
  |  Branch (563:13): [True: 0, False: 4]
  ------------------
  564|      4|        hlit += 257;
  565|      4|        uint32_t hdist = br.get(5);
  566|      4|        if (hdist == UINT32_MAX) return 0;
  ------------------
  |  Branch (566:13): [True: 0, False: 4]
  ------------------
  567|      4|        hdist += 1;
  568|      4|        uint32_t hclen = br.get(4);
  569|      4|        if (hclen == UINT32_MAX) return 0;
  ------------------
  |  Branch (569:13): [True: 0, False: 4]
  ------------------
  570|      4|        hclen += 4;
  571|      4|        static const int order[19] = {16, 17, 18, 0, 8,  7, 9,  6, 10, 5,
  572|      4|                                      11, 4,  12, 3, 13, 2, 14, 1, 15};
  573|      4|        uint8_t clen[19]{};
  574|     69|        for (uint32_t i = 0; i < hclen; i++) {
  ------------------
  |  Branch (574:30): [True: 65, False: 4]
  ------------------
  575|     65|          uint32_t v = br.get(3);
  576|     65|          if (v == UINT32_MAX) return 0;
  ------------------
  |  Branch (576:15): [True: 0, False: 65]
  ------------------
  577|     65|          clen[order[i]] = uint8_t(v);
  578|     65|        }
  579|      4|        Huff cl;
  580|      4|        if (!cl.build(clen, 19)) return 0;
  ------------------
  |  Branch (580:13): [True: 0, False: 4]
  ------------------
  581|      4|        uint8_t lens[288 + 32]{};
  582|      4|        uint32_t n = hlit + hdist;
  583|  1.09k|        for (uint32_t i = 0; i < n;) {
  ------------------
  |  Branch (583:30): [True: 1.08k, False: 4]
  ------------------
  584|  1.08k|          int sym = cl.decode(br);
  585|  1.08k|          if (sym < 0) return 0;
  ------------------
  |  Branch (585:15): [True: 0, False: 1.08k]
  ------------------
  586|  1.08k|          if (sym < 16) {
  ------------------
  |  Branch (586:15): [True: 1.03k, False: 49]
  ------------------
  587|  1.03k|            lens[i++] = uint8_t(sym);
  588|  1.03k|          } else if (sym == 16) {
  ------------------
  |  Branch (588:22): [True: 49, False: 0]
  ------------------
  589|     49|            uint32_t rep = br.get(2);
  590|     49|            if (rep == UINT32_MAX) return 0;
  ------------------
  |  Branch (590:17): [True: 0, False: 49]
  ------------------
  591|     49|            rep += 3;
  592|     49|            if (i == 0) return 0;
  ------------------
  |  Branch (592:17): [True: 0, False: 49]
  ------------------
  593|     49|            uint8_t v = lens[i - 1];
  594|    263|            while (rep--) lens[i++] = v;
  ------------------
  |  Branch (594:20): [True: 214, False: 49]
  ------------------
  595|     49|          } else if (sym == 17) {
  ------------------
  |  Branch (595:22): [True: 0, False: 0]
  ------------------
  596|      0|            uint32_t rep = br.get(3);
  597|      0|            if (rep == UINT32_MAX) return 0;
  ------------------
  |  Branch (597:17): [True: 0, False: 0]
  ------------------
  598|      0|            rep += 3;
  599|      0|            while (rep--) lens[i++] = 0;
  ------------------
  |  Branch (599:20): [True: 0, False: 0]
  ------------------
  600|      0|          } else if (sym == 18) {
  ------------------
  |  Branch (600:22): [True: 0, False: 0]
  ------------------
  601|      0|            uint32_t rep = br.get(7);
  602|      0|            if (rep == UINT32_MAX) return 0;
  ------------------
  |  Branch (602:17): [True: 0, False: 0]
  ------------------
  603|      0|            rep += 11;
  604|      0|            while (rep--) lens[i++] = 0;
  ------------------
  |  Branch (604:20): [True: 0, False: 0]
  ------------------
  605|      0|          } else
  606|      0|            return 0;
  607|  1.08k|        }
  608|      4|        if (!lit.build(lens, int(hlit))) return 0;
  ------------------
  |  Branch (608:13): [True: 0, False: 4]
  ------------------
  609|      4|        if (!dist.build(lens + hlit, int(hdist))) return 0;
  ------------------
  |  Branch (609:13): [True: 0, False: 4]
  ------------------
  610|      4|      }
  611|  52.2k|      for (;;) {
  612|  52.2k|        int sym;
  613|  52.2k|        if (btype == 1)
  ------------------
  |  Branch (613:13): [True: 0, False: 52.2k]
  ------------------
  614|      0|          sym = fixed_litlen(br);
  615|  52.2k|        else
  616|  52.2k|          sym = lit.decode(br);
  617|  52.2k|        if (sym < 0) return 0;
  ------------------
  |  Branch (617:13): [True: 0, False: 52.2k]
  ------------------
  618|  52.2k|        if (sym < 256) {
  ------------------
  |  Branch (618:13): [True: 37.2k, False: 14.9k]
  ------------------
  619|  37.2k|          if (out >= dst_cap) return 0;
  ------------------
  |  Branch (619:15): [True: 0, False: 37.2k]
  ------------------
  620|  37.2k|          dst[out++] = uint8_t(sym);
  621|  37.2k|        } else if (sym == 256) {
  ------------------
  |  Branch (621:20): [True: 4, False: 14.9k]
  ------------------
  622|      4|          break;
  623|  14.9k|        } else {
  624|  14.9k|          int len_code = sym - 257;
  625|  14.9k|          if (len_code < 0 || len_code > 28) return 0;
  ------------------
  |  Branch (625:15): [True: 0, False: 14.9k]
  |  Branch (625:31): [True: 0, False: 14.9k]
  ------------------
  626|  14.9k|          uint32_t extra = br.get(len_extra[len_code]);
  627|  14.9k|          if (len_extra[len_code] && extra == UINT32_MAX) return 0;
  ------------------
  |  Branch (627:15): [True: 2.03k, False: 12.9k]
  |  Branch (627:38): [True: 0, False: 2.03k]
  ------------------
  628|  14.9k|          uint32_t length =
  629|  14.9k|              len_base[len_code] + (len_extra[len_code] ? extra : 0);
  ------------------
  |  Branch (629:37): [True: 2.03k, False: 12.9k]
  ------------------
  630|  14.9k|          int dsym;
  631|  14.9k|          if (btype == 1)
  ------------------
  |  Branch (631:15): [True: 0, False: 14.9k]
  ------------------
  632|      0|            dsym = fixed_dist(br);
  633|  14.9k|          else
  634|  14.9k|            dsym = dist.decode(br);
  635|  14.9k|          if (dsym < 0 || dsym > 29) return 0;
  ------------------
  |  Branch (635:15): [True: 0, False: 14.9k]
  |  Branch (635:27): [True: 0, False: 14.9k]
  ------------------
  636|  14.9k|          uint32_t dextra = br.get(dist_extra[dsym]);
  637|  14.9k|          if (dist_extra[dsym] && dextra == UINT32_MAX) return 0;
  ------------------
  |  Branch (637:15): [True: 9.97k, False: 5.01k]
  |  Branch (637:35): [True: 0, False: 9.97k]
  ------------------
  638|  14.9k|          uint32_t distance = dist_base[dsym] + (dist_extra[dsym] ? dextra : 0);
  ------------------
  |  Branch (638:50): [True: 9.97k, False: 5.01k]
  ------------------
  639|  14.9k|          if (distance > out || out + length > dst_cap) return 0;
  ------------------
  |  Branch (639:15): [True: 0, False: 14.9k]
  |  Branch (639:33): [True: 0, False: 14.9k]
  ------------------
  640|   202k|          for (uint32_t k = 0; k < length; k++) {
  ------------------
  |  Branch (640:32): [True: 187k, False: 14.9k]
  ------------------
  641|   187k|            dst[out] = dst[out - distance];
  642|   187k|            out++;
  643|   187k|          }
  644|  14.9k|        }
  645|  52.2k|      }
  646|      4|    } else {
  647|      0|      return 0;  // reserved
  648|      0|    }
  649|      4|    if (bfinal) break;
  ------------------
  |  Branch (649:9): [True: 1, False: 3]
  ------------------
  650|      4|  }
  651|      1|  return out;
  652|      1|}
_ZN3ada4idna7deflate9BitReaderC2EPKhm:
  390|      1|      : p(data), end(data + len) {}
_ZNK3ada4idna7deflate4Huff6decodeERNS1_9BitReaderE:
  464|  68.3k|  int decode(BitReader& br) const {
  465|  68.3k|    if (max_bits == 0) return -1;
  ------------------
  |  Branch (465:9): [True: 0, False: 68.3k]
  ------------------
  466|  68.3k|    int code = 0;
  467|   427k|    for (int len = 1; len <= max_bits; len++) {
  ------------------
  |  Branch (467:23): [True: 427k, False: 0]
  ------------------
  468|   427k|      uint32_t b = br.get(1);
  469|   427k|      if (b == UINT32_MAX) return -1;
  ------------------
  |  Branch (469:11): [True: 0, False: 427k]
  ------------------
  470|   427k|      code = (code << 1) | int(b);
  471|   427k|      int first = first_code[len];
  472|   427k|      int cnt = counts[len];
  473|   427k|      if (cnt && code - first < cnt) {
  ------------------
  |  Branch (473:11): [True: 263k, False: 164k]
  |  Branch (473:18): [True: 68.3k, False: 195k]
  ------------------
  474|  68.3k|        return symbols[base_idx[len] + (code - first)];
  475|  68.3k|      }
  476|   427k|    }
  477|      0|    return -1;
  478|  68.3k|  }
_ZN3ada4idna10crc32_ieeeEPKhm:
 4861|      1|                                         size_t len) noexcept {
 4862|      1|  uint32_t c = 0xFFFFFFFFu;
 4863|   224k|  for (size_t i = 0; i < len; ++i) {
  ------------------
  |  Branch (4863:22): [True: 224k, False: 1]
  ------------------
 4864|   224k|    c ^= data[i];
 4865|  2.02M|    for (int k = 0; k < 8; ++k) {
  ------------------
  |  Branch (4865:21): [True: 1.79M, False: 224k]
  ------------------
 4866|  1.79M|      const uint32_t mask = 0u - (c & 1u);
 4867|  1.79M|      c = (c >> 1) ^ (0xEDB88320u & mask);
 4868|  1.79M|    }
 4869|   224k|  }
 4870|      1|  return ~c;
 4871|      1|}
_ZN3ada4idna6detail33convert_table_blob_to_host_endianEPh:
 4684|      1|inline void convert_table_blob_to_host_endian(uint8_t* buffer) noexcept {
 4685|      1|  if constexpr (std::endian::native == std::endian::little) {
 4686|      1|    (void)buffer;
 4687|      1|    return;
 4688|      1|  }
 4689|      0|  auto u16 = [&](size_t off, size_t count) {
 4690|      1|    bswap_inplace(reinterpret_cast<uint16_t*>(buffer + off), count);
 4691|      1|  };
 4692|      1|  auto u32 = [&](size_t off, size_t count) {
 4693|      1|    bswap_inplace(reinterpret_cast<uint32_t*>(buffer + off), count);
 4694|      1|  };
 4695|      1|  auto u64 = [&](size_t off, size_t count) {
 4696|      1|    bswap_inplace(reinterpret_cast<uint64_t*>(buffer + off), count);
 4697|      1|  };
 4698|       |
 4699|      1|  u16(table_blob::off_idna_stage1, table_blob::count_idna_stage1);
 4700|      1|  u16(table_blob::off_idna_stage2, table_blob::count_idna_stage2);
 4701|      1|  u64(table_blob::off_idna_bool_blocks, table_blob::count_idna_bool_blocks);
 4702|      1|  u16(table_blob::off_decomposition_block,
 4703|      1|      table_blob::count_decomposition_block);
 4704|      1|  u32(table_blob::off_decomposition_data, table_blob::count_decomposition_data);
 4705|      1|  u16(table_blob::off_composition_block, table_blob::count_composition_block);
 4706|      1|  u32(table_blob::off_composition_data, table_blob::count_composition_data);
 4707|      1|  u32(table_blob::off_id_continue_flat, table_blob::count_id_continue_flat);
 4708|      1|  u32(table_blob::off_id_start_flat, table_blob::count_id_start_flat);
 4709|      1|  u32(table_blob::off_dir_start, table_blob::count_dir_start);
 4710|      1|  u32(table_blob::off_dir_final, table_blob::count_dir_final);
 4711|      1|  u32(table_blob::off_combining_flat, table_blob::count_combining_flat);
 4712|      1|}
_ZZN3ada4idna13ensure_tablesEvENKUlmE_clEm:
 4910|     18|    auto at = [&](size_t off) noexcept -> const uint8_t* {
 4911|     18|      return buffer + off;
 4912|     18|    };
simple_absolute.cc:_ZN3ada4idnaL11idna_lookupEj:
 5065|   365k|static uint16_t idna_lookup(uint32_t cp) noexcept {
 5066|   365k|  if (cp < IDNA_LOW_RANGE_END) {
  ------------------
  |  Branch (5066:7): [True: 362k, False: 2.35k]
  ------------------
 5067|   362k|    uint16_t ref = idna_stage1[cp >> IDNA_BLOCK_BITS];
 5068|   362k|    if (ref & IDNA_BOOL_FLAG) {
  ------------------
  |  Branch (5068:9): [True: 150k, False: 212k]
  ------------------
 5069|   150k|      uint32_t bit_idx =
 5070|   150k|          static_cast<uint32_t>(ref & ~IDNA_BOOL_FLAG) * IDNA_BLOCK_SIZE +
 5071|   150k|          (cp & IDNA_BLOCK_MASK);
 5072|   150k|      bool is_valid = (idna_bool_blocks[bit_idx >> 6] >> (bit_idx & 63u)) & 1u;
 5073|   150k|      return is_valid ? IDNA_VALID : IDNA_DISALLOWED;
  ------------------
  |  Branch (5073:14): [True: 150k, False: 30]
  ------------------
 5074|   150k|    }
 5075|   212k|    return idna_stage2[ref + (cp & IDNA_BLOCK_MASK)];
 5076|   362k|  }
 5077|       |
 5078|  2.35k|  if (cp >= IDNA_HIGH_IGNORED_START && cp < IDNA_HIGH_IGNORED_END) {
  ------------------
  |  Branch (5078:7): [True: 2.30k, False: 48]
  |  Branch (5078:40): [True: 2.06k, False: 248]
  ------------------
 5079|  2.06k|    return IDNA_IGNORED;
 5080|  2.06k|  }
 5081|       |
 5082|    296|  return IDNA_DISALLOWED;
 5083|  2.35k|}
simple_absolute.cc:_ZN3ada4idnaL21utf8_count_codepointsEPKh:
 5108|  56.0k|static size_t utf8_count_codepoints(const uint8_t* ptr) noexcept {
 5109|  56.0k|  size_t n = 0;
 5110|   356k|  while (*ptr != 0) {
  ------------------
  |  Branch (5110:10): [True: 300k, False: 56.0k]
  ------------------
 5111|   300k|    ++n;
 5112|   300k|    if (*ptr < 0x80u) {
  ------------------
  |  Branch (5112:9): [True: 93.6k, False: 207k]
  ------------------
 5113|  93.6k|      ++ptr;
 5114|   207k|    } else if (*ptr < 0xE0u) {
  ------------------
  |  Branch (5114:16): [True: 167k, False: 39.9k]
  ------------------
 5115|   167k|      ptr += 2;
 5116|   167k|    } else if (*ptr < 0xF0u) {
  ------------------
  |  Branch (5116:16): [True: 38.9k, False: 994]
  ------------------
 5117|  38.9k|      ptr += 3;
 5118|  38.9k|    } else {
 5119|    994|      ptr += 4;
 5120|    994|    }
 5121|   300k|  }
 5122|  56.0k|  return n;
 5123|  56.0k|}
simple_absolute.cc:_ZN3ada4idnaL9utf8_nextERPKh:
 5086|   300k|static char32_t utf8_next(const uint8_t*& ptr) noexcept {
 5087|   300k|  uint8_t b0 = *ptr++;
 5088|   300k|  if (b0 < 0x80u) return static_cast<char32_t>(b0);
  ------------------
  |  Branch (5088:7): [True: 93.6k, False: 207k]
  ------------------
 5089|   207k|  if (b0 < 0xE0u) {
  ------------------
  |  Branch (5089:7): [True: 167k, False: 39.9k]
  ------------------
 5090|   167k|    uint32_t cp = (b0 & 0x1Fu) << 6;
 5091|   167k|    cp |= (*ptr++ & 0x3Fu);
 5092|   167k|    return static_cast<char32_t>(cp);
 5093|   167k|  }
 5094|  39.9k|  if (b0 < 0xF0u) {
  ------------------
  |  Branch (5094:7): [True: 38.9k, False: 964]
  ------------------
 5095|  38.9k|    uint32_t cp = (b0 & 0x0Fu) << 12;
 5096|  38.9k|    cp |= ((*ptr++ & 0x3Fu) << 6);
 5097|  38.9k|    cp |= (*ptr++ & 0x3Fu);
 5098|  38.9k|    return static_cast<char32_t>(cp);
 5099|  38.9k|  }
 5100|    964|  uint32_t cp = (b0 & 0x07u) << 18;
 5101|    964|  cp |= ((*ptr++ & 0x3Fu) << 12);
 5102|    964|  cp |= ((*ptr++ & 0x3Fu) << 6);
 5103|    964|  cp |= (*ptr++ & 0x3Fu);
 5104|    964|  return static_cast<char32_t>(cp);
 5105|  39.9k|}
_ZN3ada4idna23decomposition_block_rowEh:
 4982|   858k|inline const uint16_t* decomposition_block_row(uint8_t bi) noexcept {
 4983|   858k|  if (bi >= kDecompBlockRows) {
  ------------------
  |  Branch (4983:7): [True: 0, False: 858k]
  ------------------
 4984|      0|    bi = 0;
 4985|      0|  }
 4986|   858k|  return decomposition_block_flat + static_cast<size_t>(bi) * kDecompBlockCols;
 4987|   858k|}
_ZN3ada4idna13ccc_block_rowEh:
 4989|  1.30M|inline const uint8_t* ccc_block_row(uint8_t bi) noexcept {
 4990|  1.30M|  if (bi >= kCccBlockRows) {
  ------------------
  |  Branch (4990:7): [True: 0, False: 1.30M]
  ------------------
 4991|      0|    bi = 0;
 4992|      0|  }
 4993|  1.30M|  return ccc_block_flat + static_cast<size_t>(bi) * kCccBlockCols;
 4994|  1.30M|}
_ZN3ada4idna16tables_are_readyEv:
 4873|  7.94k|[[nodiscard]] inline bool tables_are_ready() noexcept {
 4874|  7.94k|  return tables_init_state.load(std::memory_order_acquire) == kTablesReady;
 4875|  7.94k|}
simple_absolute.cc:_ZN3ada4idnaL23canonical_decomp_lengthEDi:
 5265|   838k|static size_t canonical_decomp_length(char32_t current_character) noexcept {
 5266|   838k|  if (current_character >= hangul_sbase &&
  ------------------
  |  Branch (5266:7): [True: 88.4k, False: 749k]
  ------------------
 5267|  88.4k|      current_character < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (5267:7): [True: 82.1k, False: 6.31k]
  ------------------
 5268|       |    // Hangul precomposed syllables are NFC.
 5269|  82.1k|    return 0;
 5270|  82.1k|  }
 5271|   756k|  if (current_character >= 0x110000) {
  ------------------
  |  Branch (5271:7): [True: 0, False: 756k]
  ------------------
 5272|      0|    return 0;
 5273|      0|  }
 5274|   756k|  const uint8_t di = decomposition_index[current_character >> 8];
 5275|   756k|  const uint16_t* const decomposition =
 5276|   756k|      decomposition_block_row(di) + (current_character % 256);
 5277|   756k|  size_t decomposition_length =
 5278|   756k|      (decomposition[1] >> 2) - (decomposition[0] >> 2);
 5279|   756k|  if ((decomposition_length > 0) && (decomposition[0] & 1)) {
  ------------------
  |  Branch (5279:7): [True: 5.32k, False: 750k]
  |  Branch (5279:37): [True: 0, False: 5.32k]
  ------------------
 5280|      0|    decomposition_length = 0;  // compatibility-only: ignored for NFC
 5281|      0|  }
 5282|   756k|  return decomposition_length;
 5283|   756k|}
simple_absolute.cc:_ZN3ada4idnaL12trailing_cccEDi:
 5466|   417k|static uint8_t trailing_ccc(char32_t c) noexcept {
 5467|   417k|  const size_t length = canonical_decomp_length(c);
 5468|   417k|  if (length == 0) {
  ------------------
  |  Branch (5468:7): [True: 414k, False: 2.46k]
  ------------------
 5469|   414k|    return get_ccc(c);
 5470|   414k|  }
 5471|  2.46k|  const uint16_t* const decomposition =
 5472|  2.46k|      decomposition_block_row(decomposition_index[c >> 8]) + (c % 256);
 5473|  2.46k|  const size_t base = decomposition[0] >> 2;
 5474|  2.46k|  return get_ccc(decomposition_data[base + length - 1]);
 5475|   417k|}
simple_absolute.cc:_ZN3ada4idnaL13would_composeENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5397|  7.49k|static bool would_compose(std::u32string_view input) noexcept {
 5398|   392k|  for (size_t input_count = 0; input_count < input.size();) {
  ------------------
  |  Branch (5398:32): [True: 387k, False: 5.14k]
  ------------------
 5399|   387k|    const char32_t current = input[input_count];
 5400|   387k|    if (current >= hangul_lbase && current < hangul_lbase + hangul_lcount) {
  ------------------
  |  Branch (5400:9): [True: 49.5k, False: 338k]
  |  Branch (5400:36): [True: 1.40k, False: 48.1k]
  ------------------
 5401|  1.40k|      if (input_count + 1 < input.size() &&
  ------------------
  |  Branch (5401:11): [True: 1.33k, False: 68]
  ------------------
 5402|  1.33k|          input[input_count + 1] >= hangul_vbase &&
  ------------------
  |  Branch (5402:11): [True: 614, False: 722]
  ------------------
 5403|    614|          input[input_count + 1] < hangul_vbase + hangul_vcount) {
  ------------------
  |  Branch (5403:11): [True: 160, False: 454]
  ------------------
 5404|    160|        return true;
 5405|    160|      }
 5406|  1.24k|      ++input_count;
 5407|  1.24k|      continue;
 5408|  1.40k|    }
 5409|   386k|    if (current >= hangul_sbase && current < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (5409:9): [True: 40.7k, False: 345k]
  |  Branch (5409:36): [True: 39.6k, False: 1.14k]
  ------------------
 5410|  39.6k|      if ((current - hangul_sbase) % hangul_tcount &&
  ------------------
  |  Branch (5410:11): [True: 2.86k, False: 36.7k]
  ------------------
 5411|  2.86k|          input_count + 1 < input.size() &&
  ------------------
  |  Branch (5411:11): [True: 2.74k, False: 122]
  ------------------
 5412|  2.74k|          input[input_count + 1] > hangul_tbase &&
  ------------------
  |  Branch (5412:11): [True: 2.20k, False: 542]
  ------------------
 5413|  2.20k|          input[input_count + 1] < hangul_tbase + hangul_tcount) {
  ------------------
  |  Branch (5413:11): [True: 1.03k, False: 1.16k]
  ------------------
 5414|  1.03k|        return true;
 5415|  1.03k|      }
 5416|  38.5k|      ++input_count;
 5417|  38.5k|      continue;
 5418|  39.6k|    }
 5419|   346k|    if (current < 0x110000) {
  ------------------
  |  Branch (5419:9): [True: 346k, False: 0]
  ------------------
 5420|   346k|      const uint16_t* composition =
 5421|   346k|          composition_block_row(composition_index[current >> 8]) +
 5422|   346k|          (current % 256);
 5423|   346k|      int32_t previous_ccc = -1;
 5424|   346k|      size_t j = input_count;
 5425|   349k|      for (; j + 1 < input.size(); ++j) {
  ------------------
  |  Branch (5425:14): [True: 344k, False: 4.94k]
  ------------------
 5426|   344k|        uint8_t ccc = get_ccc(input[j + 1]);
 5427|   344k|        if (composition[1] != composition[0] && previous_ccc < ccc) {
  ------------------
  |  Branch (5427:13): [True: 84.7k, False: 259k]
  |  Branch (5427:49): [True: 83.5k, False: 1.23k]
  ------------------
 5428|  83.5k|          int left = composition[0];
 5429|  83.5k|          int right = composition[1];
 5430|  83.5k|          if (left < 0 || right < left ||
  ------------------
  |  Branch (5430:15): [True: 0, False: 83.5k]
  |  Branch (5430:27): [True: 0, False: 83.5k]
  ------------------
 5431|  83.5k|              static_cast<size_t>(right) > composition_data_size) {
  ------------------
  |  Branch (5431:15): [True: 0, False: 83.5k]
  ------------------
 5432|      0|            break;
 5433|      0|          }
 5434|   213k|          while (left + 2 < right) {
  ------------------
  |  Branch (5434:18): [True: 129k, False: 83.5k]
  ------------------
 5435|   129k|            int middle = left + (((right - left) >> 1) & ~1);
 5436|   129k|            if (composition_data[static_cast<size_t>(middle)] <= input[j + 1]) {
  ------------------
  |  Branch (5436:17): [True: 4.16k, False: 125k]
  ------------------
 5437|  4.16k|              left = middle;
 5438|  4.16k|            }
 5439|   129k|            if (composition_data[static_cast<size_t>(middle)] >= input[j + 1]) {
  ------------------
  |  Branch (5439:17): [True: 126k, False: 3.52k]
  ------------------
 5440|   126k|              right = middle;
 5441|   126k|            }
 5442|   129k|          }
 5443|  83.5k|          if (static_cast<size_t>(left + 1) < composition_data_size &&
  ------------------
  |  Branch (5443:15): [True: 83.5k, False: 0]
  ------------------
 5444|  83.5k|              composition_data[static_cast<size_t>(left)] == input[j + 1]) {
  ------------------
  |  Branch (5444:15): [True: 1.15k, False: 82.3k]
  ------------------
 5445|  1.15k|            return true;
 5446|  1.15k|          }
 5447|  83.5k|        }
 5448|   343k|        if (ccc == 0) {
  ------------------
  |  Branch (5448:13): [True: 340k, False: 2.62k]
  ------------------
 5449|   340k|          break;
 5450|   340k|        }
 5451|  2.62k|        previous_ccc = ccc;
 5452|  2.62k|      }
 5453|   345k|      input_count = j + 1;
 5454|   345k|      continue;
 5455|   346k|    }
 5456|      0|    ++input_count;
 5457|      0|  }
 5458|  5.14k|  return false;
 5459|  7.49k|}
_ZN3ada4idna21composition_block_rowEh:
 4996|   404k|inline const uint16_t* composition_block_row(uint8_t bi) noexcept {
 4997|   404k|  if (bi >= kCompBlockRows) {
  ------------------
  |  Branch (4997:7): [True: 0, False: 404k]
  ------------------
 4998|      0|    bi = 0;
 4999|      0|  }
 5000|   404k|  return composition_block_flat + static_cast<size_t>(bi) * kCompBlockCols;
 5001|   404k|}
simple_absolute.cc:_ZN3ada4idnaL19char_to_digit_valueEc:
 5643|  35.6k|static constexpr int32_t char_to_digit_value(char value) {
 5644|  35.6k|  if (value >= 'a' && value <= 'z') return value - 'a';
  ------------------
  |  Branch (5644:7): [True: 29.6k, False: 5.99k]
  |  Branch (5644:23): [True: 29.6k, False: 8]
  ------------------
 5645|  6.00k|  if (value >= '0' && value <= '9') return value - '0' + 26;
  ------------------
  |  Branch (5645:7): [True: 5.98k, False: 24]
  |  Branch (5645:23): [True: 5.96k, False: 18]
  ------------------
 5646|     42|  return -1;
 5647|  6.00k|}
simple_absolute.cc:_ZN3ada4idnaL5adaptEiib:
 5653|   166k|static constexpr int32_t adapt(int32_t d, int32_t n, bool firsttime) {
 5654|   166k|  if (firsttime) {
  ------------------
  |  Branch (5654:7): [True: 27.1k, False: 139k]
  ------------------
 5655|  27.1k|    d = d / damp;
 5656|   139k|  } else {
 5657|   139k|    d = d / 2;
 5658|   139k|  }
 5659|   166k|  d += d / n;
 5660|   166k|  int32_t k = 0;
 5661|   193k|  while (d > ((base - tmin) * tmax) / 2) {
  ------------------
  |  Branch (5661:10): [True: 27.4k, False: 166k]
  ------------------
 5662|  27.4k|    d /= base - tmin;
 5663|  27.4k|    k += base;
 5664|  27.4k|  }
 5665|   166k|  return k + (((base - tmin + 1) * d) / (d + skew));
 5666|   166k|}
simple_absolute.cc:_ZN3ada4idnaL13digit_to_charEi:
 5649|   278k|static constexpr char digit_to_char(int32_t digit) {
 5650|   278k|  return digit < 26 ? char(digit + 97) : char(digit + 22);
  ------------------
  |  Branch (5650:10): [True: 174k, False: 103k]
  ------------------
 5651|   278k|}
simple_absolute.cc:_ZZN3ada4idna14is_label_validENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEEENK3$_0clIA2_jEEDaRKT_:
 5988|   241k|      comb_span, label.front(), {}, [](const auto& range) { return range[1]; });
simple_absolute.cc:_ZZN3ada4idna14is_label_validENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEEENK3$_1clEj:
 6073|  2.15k|      auto is_l_or_d = [](uint32_t code) {
 6074|  2.15k|        return std::ranges::binary_search(L, code) ||
  ------------------
  |  Branch (6074:16): [True: 114, False: 2.04k]
  ------------------
 6075|  2.04k|               std::ranges::binary_search(D, code);
  ------------------
  |  Branch (6075:16): [True: 772, False: 1.27k]
  ------------------
 6076|  2.15k|      };
simple_absolute.cc:_ZZN3ada4idna14is_label_validENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEEENK3$_2clEj:
 6077|  2.99k|      auto is_r_or_d = [](uint32_t code) {
 6078|  2.99k|        return std::ranges::binary_search(R, code) ||
  ------------------
  |  Branch (6078:16): [True: 484, False: 2.51k]
  ------------------
 6079|  2.51k|               std::ranges::binary_search(D, code);
  ------------------
  |  Branch (6079:16): [True: 290, False: 2.22k]
  ------------------
 6080|  2.99k|      };
simple_absolute.cc:_ZN3ada4idnaL20find_last_not_of_nsmENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5935|  25.5k|    const std::u32string_view label) noexcept {
 5936|  26.5k|  for (int i = static_cast<int>(label.size() - 1); i >= 0; i--)
  ------------------
  |  Branch (5936:52): [True: 26.5k, False: 0]
  ------------------
 5937|  26.5k|    if (find_direction(label[i]) != direction::NSM) return i;
  ------------------
  |  Branch (5937:9): [True: 25.5k, False: 998]
  ------------------
 5938|       |
 5939|      0|  return std::u32string_view::npos;
 5940|  25.5k|}
simple_absolute.cc:_ZN3ada4idnaL12is_rtl_labelENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5944|  25.5k|inline static bool is_rtl_label(const std::u32string_view label) noexcept {
 5945|  25.5k|  const size_t mask =
 5946|  25.5k|      (1u << direction::R) | (1u << direction::AL) | (1u << direction::AN);
 5947|       |
 5948|  25.5k|  size_t directions = 0;
 5949|   152k|  for (size_t i = 0; i < label.size(); i++) {
  ------------------
  |  Branch (5949:22): [True: 126k, False: 25.5k]
  ------------------
 5950|   126k|    directions |= 1u << find_direction(label[i]);
 5951|   126k|  }
 5952|  25.5k|  return (directions & mask) != 0;
 5953|  25.5k|}
simple_absolute.cc:_ZN3ada4idnaL14find_directionEj:
 5916|   164k|inline static direction find_direction(uint32_t code_point) noexcept {
 5917|       |  // Binary search on dir_final (sorted upper bounds).
 5918|   164k|  size_t lo = 0, hi = dir_table_count;
 5919|  1.90M|  while (lo < hi) {
  ------------------
  |  Branch (5919:10): [True: 1.73M, False: 164k]
  ------------------
 5920|  1.73M|    size_t mid = lo + (hi - lo) / 2;
 5921|  1.73M|    if (dir_final[mid] < code_point) {
  ------------------
  |  Branch (5921:9): [True: 549k, False: 1.19M]
  ------------------
 5922|   549k|      lo = mid + 1;
 5923|  1.19M|    } else {
 5924|  1.19M|      hi = mid;
 5925|  1.19M|    }
 5926|  1.73M|  }
 5927|   164k|  if (lo == dir_table_count) {
  ------------------
  |  Branch (5927:7): [True: 0, False: 164k]
  ------------------
 5928|      0|    return direction::NONE;
 5929|      0|  }
 5930|   164k|  return code_point >= dir_start[lo] ? static_cast<direction>(dir_value[lo])
  ------------------
  |  Branch (5930:10): [True: 162k, False: 1.32k]
  ------------------
 5931|   164k|                                     : direction::NONE;
 5932|   164k|}
_ZN3ada4idna8is_asciiENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6301|   124k|bool constexpr is_ascii(std::string_view view) {
 6302|  1.92M|  for (uint8_t c : view) {
  ------------------
  |  Branch (6302:18): [True: 1.92M, False: 119k]
  ------------------
 6303|  1.92M|    if (c >= 0x80) {
  ------------------
  |  Branch (6303:9): [True: 5.38k, False: 1.92M]
  ------------------
 6304|  5.38k|      return false;
 6305|  5.38k|    }
 6306|  1.92M|  }
 6307|   119k|  return true;
 6308|   124k|}
simple_absolute.cc:_ZN3ada4idnaL19from_ascii_to_asciiENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEERNS1_12basic_stringIcS4_NS1_9allocatorIcEEEE:
 6338|   119k|static void from_ascii_to_ascii(std::string_view ut8_string, std::string& out) {
 6339|   119k|  out.assign(ut8_string);
 6340|   119k|  ascii_map(out.data(), out.size());
 6341|   119k|}
_ZN3ada4idna8is_asciiENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 6292|  37.1k|bool constexpr is_ascii(std::u32string_view view) {
 6293|   109k|  for (uint32_t c : view) {
  ------------------
  |  Branch (6293:19): [True: 109k, False: 2.81k]
  ------------------
 6294|   109k|    if (c >= 0x80) {
  ------------------
  |  Branch (6294:9): [True: 34.3k, False: 75.5k]
  ------------------
 6295|  34.3k|      return false;
 6296|  34.3k|    }
 6297|   109k|  }
 6298|  2.81k|  return true;
 6299|  37.1k|}
simple_absolute.cc:_ZN3ada4idnaL13is_ace_prefixENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 6354|  30.2k|static bool is_ace_prefix(std::u32string_view label) noexcept {
 6355|  30.2k|  return label.size() >= 4 && label[0] == U'x' && label[1] == U'n' &&
  ------------------
  |  Branch (6355:10): [True: 23.3k, False: 6.89k]
  |  Branch (6355:31): [True: 3.79k, False: 19.5k]
  |  Branch (6355:51): [True: 3.52k, False: 266]
  ------------------
 6356|  3.52k|         label[2] == U'-' && label[3] == U'-';
  ------------------
  |  Branch (6356:10): [True: 3.29k, False: 232]
  |  Branch (6356:30): [True: 3.09k, False: 200]
  ------------------
 6357|  30.2k|}
simple_absolute.cc:_ZN3ada4idnaL18append_ascii_labelERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS1_17basic_string_viewIDiNS3_IDiEEEE:
 6344|  5.15k|static void append_ascii_label(std::string& out, std::u32string_view label) {
 6345|  5.15k|  const size_t old = out.size();
 6346|  5.15k|  out.resize(old + label.size());
 6347|  5.15k|  char* dest = out.data() + old;
 6348|  79.4k|  for (char32_t c : label) {
  ------------------
  |  Branch (6348:19): [True: 79.4k, False: 5.15k]
  ------------------
 6349|  79.4k|    *dest++ = static_cast<char>(c);
 6350|  79.4k|  }
 6351|  5.15k|}
_ZZN3ada7unicode14percent_encodeILb1EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKhRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEEENKUlcE_clEc:
 7352|   241k|  auto pointer = std::ranges::find_if(input, [character_set](const char c) {
 7353|   241k|    return character_sets::bit_at(character_set, c);
 7354|   241k|  });
_ZZN3ada7unicode14percent_encodeILb0EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKhRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEEENKUlcE_clEc:
 7352|  48.9k|  auto pointer = std::ranges::find_if(input, [character_set](const char c) {
 7353|  48.9k|    return character_sets::bit_at(character_set, c);
 7354|  48.9k|  });
_ZN3ada7unicode18is_ascii_hex_digitEc:
 7086|  88.7k|ada_really_inline constexpr bool is_ascii_hex_digit(const char c) noexcept {
 7087|  88.7k|  return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') ||
  ------------------
  |  Branch (7087:11): [True: 85.2k, False: 3.47k]
  |  Branch (7087:23): [True: 43.2k, False: 42.0k]
  |  Branch (7087:37): [True: 41.9k, False: 3.49k]
  |  Branch (7087:49): [True: 40.0k, False: 1.95k]
  ------------------
 7088|  5.44k|         (c >= 'a' && c <= 'f');
  ------------------
  |  Branch (7088:11): [True: 1.90k, False: 3.54k]
  |  Branch (7088:23): [True: 1.74k, False: 164]
  ------------------
 7089|  88.7k|}
_ZN3ada7unicode21convert_hex_to_binaryEc:
 7176|  83.9k|unsigned constexpr convert_hex_to_binary(const char c) noexcept {
 7177|  83.9k|  return hex_to_binary_table[c - '0'];
 7178|  83.9k|}
simple_absolute.cc:_ZZN3ada7unicode14percent_encodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKhENK3$_0clEc:
 7320|  1.02M|  auto pointer = std::ranges::find_if(input, [character_set](const char c) {
 7321|  1.02M|    return character_sets::bit_at(character_set, c);
 7322|  1.02M|  });
_ZN3ada7unicode36contains_forbidden_domain_code_pointEPKcm:
 7013|   122k|    const char* input, size_t length) noexcept {
 7014|   122k|  size_t i = 0;
 7015|   122k|  uint8_t accumulator{};
 7016|   705k|  for (; i + 4 <= length; i += 4) {
  ------------------
  |  Branch (7016:10): [True: 582k, False: 122k]
  ------------------
 7017|   582k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i])];
 7018|   582k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 1])];
 7019|   582k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 2])];
 7020|   582k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 3])];
 7021|   582k|  }
 7022|   194k|  for (; i < length; i++) {
  ------------------
  |  Branch (7022:10): [True: 71.9k, False: 122k]
  ------------------
 7023|  71.9k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i])];
 7024|  71.9k|  }
 7025|   122k|  return accumulator;
 7026|   122k|}
simple_absolute.cc:_ZN3ada7unicode12_GLOBAL__N_122percent_encode_to_wideEPKcS3_PKhRNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEE:
 7702|    743|                            const uint8_t character_set[], std::string& out) {
 7703|       |  // Worst case every byte becomes %XX. Avoids realloc while walking windows.
 7704|    743|  out.reserve(out.size() + static_cast<size_t>(end - p) * 3);
 7705|    743|#if ADA_UNICODE_SSSE3
 7706|    743|  const ssse3_percent_tables tables = load_ssse3_percent_tables(character_set);
 7707|    743|  percent_encode_to_ssse3(p, end, character_set, tables, out);
 7708|       |#elif ADA_NEON
 7709|       |  percent_encode_to_neon(p, end, character_set,
 7710|       |                         load_neon_percent_table(character_set), out);
 7711|       |#elif ADA_RVV
 7712|       |  percent_encode_to_rvv(p, end, character_set, out);
 7713|       |#endif
 7714|    743|}
simple_absolute.cc:_ZN3ada7unicode12_GLOBAL__N_125load_ssse3_percent_tablesEPKh:
 7529|    743|load_ssse3_percent_tables(const uint8_t character_set[]) noexcept {
 7530|    743|  ssse3_percent_tables t{};
 7531|    743|  t.cs_lo = _mm_loadu_si128(reinterpret_cast<const __m128i*>(character_set));
 7532|    743|  t.cs_hi =
 7533|    743|      _mm_loadu_si128(reinterpret_cast<const __m128i*>(character_set + 16));
 7534|       |  // 1 << (0..7), duplicated so pshufb(index & 7) works for every lane.
 7535|    743|  t.pow2 =
 7536|    743|      _mm_setr_epi8(1, 2, 4, 8, 16, 32, 64, -128, 1, 2, 4, 8, 16, 32, 64, -128);
 7537|    743|  t.mask_0f = _mm_set1_epi8(0x0F);
 7538|    743|  t.mask_07 = _mm_set1_epi8(0x07);
 7539|    743|  t.zero = _mm_setzero_si128();
 7540|    743|  return t;
 7541|    743|}
simple_absolute.cc:_ZN3ada7unicode12_GLOBAL__N_123percent_encode_to_ssse3EPKcS3_PKhRKNS1_20ssse3_percent_tablesERNSt3__112basic_stringIcNS9_11char_traitsIcEENS9_9allocatorIcEEEE:
 7560|    743|    const ssse3_percent_tables& tables, std::string& out) {
 7561|       |  // Pair 16-byte windows so a fully clean 32-byte run is one append.
 7562|  2.93k|  while (p + 32 <= end) {
  ------------------
  |  Branch (7562:10): [True: 2.18k, False: 743]
  ------------------
 7563|  2.18k|    const __m128i word0 = _mm_loadu_si128(reinterpret_cast<const __m128i*>(p));
 7564|  2.18k|    const __m128i word1 =
 7565|  2.18k|        _mm_loadu_si128(reinterpret_cast<const __m128i*>(p + 16));
 7566|  2.18k|    const int mask0 = ssse3_percent_mask(word0, tables);
 7567|  2.18k|    const int mask1 = ssse3_percent_mask(word1, tables);
 7568|  2.18k|    if ((mask0 | mask1) == 0) {
  ------------------
  |  Branch (7568:9): [True: 204, False: 1.98k]
  ------------------
 7569|    204|      out.append(p, 32);
 7570|  1.98k|    } else {
 7571|  1.98k|      if (mask0 == 0) {
  ------------------
  |  Branch (7571:11): [True: 50, False: 1.93k]
  ------------------
 7572|     50|        out.append(p, 16);
 7573|  1.93k|      } else {
 7574|  1.93k|        encode_mask_window(p, static_cast<uint32_t>(mask0), 16, out);
 7575|  1.93k|      }
 7576|  1.98k|      if (mask1 == 0) {
  ------------------
  |  Branch (7576:11): [True: 229, False: 1.75k]
  ------------------
 7577|    229|        out.append(p + 16, 16);
 7578|  1.75k|      } else {
 7579|  1.75k|        encode_mask_window(p + 16, static_cast<uint32_t>(mask1), 16, out);
 7580|  1.75k|      }
 7581|  1.98k|    }
 7582|  2.18k|    p += 32;
 7583|  2.18k|  }
 7584|    743|  if (p + 16 <= end) {
  ------------------
  |  Branch (7584:7): [True: 481, False: 262]
  ------------------
 7585|    481|    const __m128i word = _mm_loadu_si128(reinterpret_cast<const __m128i*>(p));
 7586|    481|    const int mask = ssse3_percent_mask(word, tables);
 7587|    481|    if (mask == 0) {
  ------------------
  |  Branch (7587:9): [True: 135, False: 346]
  ------------------
 7588|    135|      out.append(p, 16);
 7589|    346|    } else {
 7590|    346|      encode_mask_window(p, static_cast<uint32_t>(mask), 16, out);
 7591|    346|    }
 7592|    481|    p += 16;
 7593|    481|  }
 7594|    743|  percent_encode_to_scalar(p, end, character_set, out);
 7595|    743|}
simple_absolute.cc:_ZN3ada7unicode12_GLOBAL__N_118ssse3_percent_maskEDv2_xRKNS1_20ssse3_percent_tablesE:
 7544|  4.85k|    __m128i word, const ssse3_percent_tables& tables) noexcept {
 7545|  4.85k|  const __m128i idx = _mm_and_si128(_mm_srli_epi16(word, 3), tables.mask_0f);
 7546|  4.85k|  const __m128i lo = _mm_shuffle_epi8(tables.cs_lo, idx);
 7547|  4.85k|  const __m128i hi = _mm_shuffle_epi8(tables.cs_hi, idx);
 7548|       |  // Bytes 0x80-0xFF are signed-negative; select the high half of the bitmap.
 7549|  4.85k|  const __m128i high_byte = _mm_cmpgt_epi8(tables.zero, word);
 7550|  4.85k|  const __m128i cs_byte = _mm_or_si128(_mm_and_si128(hi, high_byte),
 7551|  4.85k|                                       _mm_andnot_si128(high_byte, lo));
 7552|  4.85k|  const __m128i bits =
 7553|  4.85k|      _mm_shuffle_epi8(tables.pow2, _mm_and_si128(word, tables.mask_07));
 7554|  4.85k|  const __m128i hits = _mm_and_si128(cs_byte, bits);
 7555|  4.85k|  return _mm_movemask_epi8(_mm_cmpeq_epi8(hits, tables.zero)) ^ 0xFFFF;
 7556|  4.85k|}
simple_absolute.cc:_ZN3ada7unicode12_GLOBAL__N_118encode_mask_windowEPKcjmRNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEE:
 7484|  4.03k|                                          size_t width, std::string& out) {
 7485|  4.03k|  uint64_t bits = mask;
 7486|  4.03k|  size_t off = 0;
 7487|  58.2k|  while (bits != 0) {
  ------------------
  |  Branch (7487:10): [True: 54.2k, False: 4.03k]
  ------------------
 7488|  54.2k|    const int zero_run = trailing_zeroes32(static_cast<uint32_t>(bits));
 7489|  54.2k|    if (zero_run != 0) {
  ------------------
  |  Branch (7489:9): [True: 2.35k, False: 51.8k]
  ------------------
 7490|  2.35k|      out.append(p + off, static_cast<size_t>(zero_run));
 7491|  2.35k|    }
 7492|  54.2k|    off += static_cast<size_t>(zero_run);
 7493|  54.2k|    out.append(character_sets::hex + uint8_t(p[off]) * 4, 3);
 7494|  54.2k|    ++off;
 7495|  54.2k|    bits >>= static_cast<unsigned>(zero_run + 1);
 7496|  54.2k|  }
 7497|  4.03k|  if (off < width) {
  ------------------
  |  Branch (7497:7): [True: 851, False: 3.18k]
  ------------------
 7498|    851|    out.append(p + off, width - off);
 7499|    851|  }
 7500|  4.03k|}
simple_absolute.cc:_ZN3ada7unicode12_GLOBAL__N_117trailing_zeroes32Ej:
 7472|  54.2k|ada_really_inline int trailing_zeroes32(uint32_t input_num) noexcept {
 7473|       |#ifdef ADA_REGULAR_VISUAL_STUDIO
 7474|       |  unsigned long ret;
 7475|       |  _BitScanForward(&ret, input_num);
 7476|       |  return static_cast<int>(ret);
 7477|       |#else
 7478|  54.2k|  return __builtin_ctz(input_num);
 7479|  54.2k|#endif
 7480|  54.2k|}
simple_absolute.cc:_ZN3ada7unicode12_GLOBAL__N_124percent_encode_to_scalarEPKcS3_PKhRNSt3__112basic_stringIcNS6_11char_traitsIcEENS6_9allocatorIcEEEE:
 7505|    743|                                                std::string& out) {
 7506|  4.27k|  for (; p != end; ++p) {
  ------------------
  |  Branch (7506:10): [True: 3.53k, False: 743]
  ------------------
 7507|  3.53k|    if (character_sets::bit_at(character_set, *p)) {
  ------------------
  |  Branch (7507:9): [True: 1.99k, False: 1.53k]
  ------------------
 7508|  1.99k|      out.append(character_sets::hex + uint8_t(*p) * 4, 3);
 7509|  1.99k|    } else {
 7510|  1.53k|      out += *p;
 7511|  1.53k|    }
 7512|  3.53k|  }
 7513|    743|}
simple_absolute.cc:_ZN3ada11serializers12_GLOBAL__N_113write_hex_u16EPct:
 7769|  1.60k|ada_really_inline char* write_hex_u16(char* p, uint16_t v) noexcept {
 7770|  1.60k|  static constexpr char kHex[] = "0123456789abcdef";
 7771|  1.60k|  if (v >= 0x1000) {
  ------------------
  |  Branch (7771:7): [True: 122, False: 1.48k]
  ------------------
 7772|    122|    *p++ = kHex[(v >> 12) & 0xf];
 7773|    122|    *p++ = kHex[(v >> 8) & 0xf];
 7774|    122|    *p++ = kHex[(v >> 4) & 0xf];
 7775|    122|    *p++ = kHex[v & 0xf];
 7776|  1.48k|  } else if (v >= 0x100) {
  ------------------
  |  Branch (7776:14): [True: 224, False: 1.26k]
  ------------------
 7777|    224|    *p++ = kHex[(v >> 8) & 0xf];
 7778|    224|    *p++ = kHex[(v >> 4) & 0xf];
 7779|    224|    *p++ = kHex[v & 0xf];
 7780|  1.26k|  } else if (v >= 0x10) {
  ------------------
  |  Branch (7780:14): [True: 214, False: 1.04k]
  ------------------
 7781|    214|    *p++ = kHex[(v >> 4) & 0xf];
 7782|    214|    *p++ = kHex[v & 0xf];
 7783|  1.04k|  } else {
 7784|  1.04k|    *p++ = kHex[v & 0xf];
 7785|  1.04k|  }
 7786|  1.60k|  return p;
 7787|  1.60k|}
simple_absolute.cc:_ZN3ada11serializers12_GLOBAL__N_18write_u8EPch:
 7755|   160k|ada_really_inline char* write_u8(char* p, uint8_t v) noexcept {
 7756|   160k|  if (v < 10) {
  ------------------
  |  Branch (7756:7): [True: 65.5k, False: 94.7k]
  ------------------
 7757|  65.5k|    *p++ = static_cast<char>('0' + v);
 7758|  94.7k|  } else if (v < 100) {
  ------------------
  |  Branch (7758:14): [True: 394, False: 94.3k]
  ------------------
 7759|    394|    std::memcpy(p, &digit_pairs[static_cast<size_t>(v) * 2], 2);
 7760|    394|    p += 2;
 7761|  94.3k|  } else {
 7762|  94.3k|    *p++ = static_cast<char>('0' + v / 100);
 7763|  94.3k|    std::memcpy(p, &digit_pairs[static_cast<size_t>(v % 100) * 2], 2);
 7764|  94.3k|    p += 2;
 7765|  94.3k|  }
 7766|   160k|  return p;
 7767|   160k|}
_ZN3ada7unicode19has_tabs_or_newlineENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6862|   615k|    std::string_view user_input) noexcept {
 6863|       |  // first check for short strings in which case we do it naively.
 6864|   615k|  if (user_input.size() < 16) {  // slow path
  ------------------
  |  Branch (6864:7): [True: 121k, False: 494k]
  ------------------
 6865|   121k|    return std::ranges::any_of(user_input, is_tabs_or_newline);
 6866|   121k|  }
 6867|       |  // fast path for long strings (expected to be common)
 6868|   494k|  size_t i = 0;
 6869|   494k|  const __m128i mask1 = _mm_set1_epi8('\r');
 6870|   494k|  const __m128i mask2 = _mm_set1_epi8('\n');
 6871|   494k|  const __m128i mask3 = _mm_set1_epi8('\t');
 6872|       |  // If we supported SSSE3, we could use the algorithm that we use for NEON.
 6873|   494k|  __m128i running{0};
 6874|  1.19M|  for (; i + 15 < user_input.size(); i += 16) {
  ------------------
  |  Branch (6874:10): [True: 705k, False: 494k]
  ------------------
 6875|   705k|    __m128i word = _mm_loadu_si128((const __m128i*)(user_input.data() + i));
 6876|   705k|    running = _mm_or_si128(
 6877|   705k|        _mm_or_si128(running, _mm_or_si128(_mm_cmpeq_epi8(word, mask1),
 6878|   705k|                                           _mm_cmpeq_epi8(word, mask2))),
 6879|   705k|        _mm_cmpeq_epi8(word, mask3));
 6880|   705k|  }
 6881|   494k|  if (i < user_input.size()) {
  ------------------
  |  Branch (6881:7): [True: 490k, False: 4.50k]
  ------------------
 6882|   490k|    __m128i word = _mm_loadu_si128(
 6883|   490k|        (const __m128i*)(user_input.data() + user_input.length() - 16));
 6884|   490k|    running = _mm_or_si128(
 6885|   490k|        _mm_or_si128(running, _mm_or_si128(_mm_cmpeq_epi8(word, mask1),
 6886|   490k|                                           _mm_cmpeq_epi8(word, mask2))),
 6887|   490k|        _mm_cmpeq_epi8(word, mask3));
 6888|   490k|  }
 6889|   494k|  return _mm_movemask_epi8(running) != 0;
 6890|   615k|}
_ZN3ada7unicode18is_tabs_or_newlineEc:
 6753|  1.54M|constexpr bool is_tabs_or_newline(char c) noexcept {
 6754|  1.54M|  return c == '\r' || c == '\n' || c == '\t';
  ------------------
  |  Branch (6754:10): [True: 36, False: 1.54M]
  |  Branch (6754:23): [True: 34, False: 1.54M]
  |  Branch (6754:36): [True: 26, False: 1.54M]
  ------------------
 6755|  1.54M|}
_ZN3ada7helpers27remove_ascii_tab_or_newlineERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
 8558|    948|ada_really_inline void remove_ascii_tab_or_newline(std::string& input) {
 8559|       |  // if this ever becomes a performance issue, we could use an approach similar
 8560|       |  // to has_tabs_or_newline
 8561|    948|  std::erase_if(input, ada::unicode::is_ascii_tab_or_newline);
 8562|    948|}
_ZN3ada7unicode23is_ascii_tab_or_newlineEc:
 7107|  85.8k|    const char c) noexcept {
 7108|  85.8k|  return c == '\t' || c == '\n' || c == '\r';
  ------------------
  |  Branch (7108:10): [True: 1.89k, False: 83.9k]
  |  Branch (7108:23): [True: 422, False: 83.5k]
  |  Branch (7108:36): [True: 1.27k, False: 82.2k]
  ------------------
 7109|  85.8k|}
_ZN3ada7unicode22is_c0_control_or_spaceEc:
 7102|  1.09M|ada_really_inline constexpr bool is_c0_control_or_space(const char c) noexcept {
 7103|  1.09M|  return (unsigned char)c <= ' ';
 7104|  1.09M|}
_ZN3ada7helpers19parse_prepared_pathENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEENS_6scheme4typeERNS1_12basic_stringIcS4_NS1_9allocatorIcEEEE:
 9255|   232k|                                           std::string& path) {
 9256|   232k|  ada_log("parse_prepared_path ", input);
 9257|   232k|  uint8_t accumulator = checkers::path_signature(input);
 9258|       |  // Let us first detect a trivial case.
 9259|       |  // If it is special, we check that we have no dot, no %,  no \ and no
 9260|       |  // character needing percent encoding. Otherwise, we check that we have no %,
 9261|       |  // no dot, and no character needing percent encoding.
 9262|   232k|  constexpr uint8_t need_encoding = 1;
 9263|   232k|  constexpr uint8_t backslash_char = 2;
 9264|   232k|  constexpr uint8_t dot_char = 4;
 9265|   232k|  constexpr uint8_t percent_char = 8;
 9266|   232k|  bool special = type != ada::scheme::NOT_SPECIAL;
 9267|   232k|  bool may_need_slow_file_handling = (type == ada::scheme::type::FILE &&
  ------------------
  |  Branch (9267:39): [True: 1.45k, False: 231k]
  ------------------
 9268|  1.45k|                                      checkers::is_windows_drive_letter(input));
  ------------------
  |  Branch (9268:39): [True: 36, False: 1.41k]
  ------------------
 9269|   232k|  bool trivial_path =
 9270|   232k|      (special ? (accumulator == 0)
  ------------------
  |  Branch (9270:7): [True: 202k, False: 29.5k]
  |  Branch (9270:8): [True: 231k, False: 834]
  ------------------
 9271|   232k|               : ((accumulator & (need_encoding | dot_char | percent_char)) ==
 9272|    834|                  0)) &&
 9273|   202k|      (!may_need_slow_file_handling);
  ------------------
  |  Branch (9273:7): [True: 202k, False: 13]
  ------------------
 9274|   232k|  if (accumulator == dot_char && !may_need_slow_file_handling) {
  ------------------
  |  Branch (9274:7): [True: 12.7k, False: 219k]
  |  Branch (9274:34): [True: 12.7k, False: 15]
  ------------------
 9275|       |    // '4' means that we have at least one dot, but nothing that requires
 9276|       |    // percent encoding or decoding. The only part that is not trivial is
 9277|       |    // that we may have single dots and double dots path segments.
 9278|       |    // If we have such segments, then we either have a path that begins
 9279|       |    // with '.' (easy to check), or we have the sequence './'.
 9280|       |    // Note: input cannot be empty, it must at least contain one character ('.')
 9281|       |    // Note: we know that '\' is not present.
 9282|  12.7k|    if (input[0] != '.') {
  ------------------
  |  Branch (9282:9): [True: 11.3k, False: 1.33k]
  ------------------
 9283|  11.3k|      size_t slashdot = 0;
 9284|  11.3k|      bool dot_is_file = true;
 9285|  36.5k|      for (;;) {
 9286|  36.5k|        slashdot = input.find("/.", slashdot);
 9287|  36.5k|        if (slashdot == std::string_view::npos) {  // common case
  ------------------
  |  Branch (9287:13): [True: 11.3k, False: 25.1k]
  ------------------
 9288|  11.3k|          break;
 9289|  25.1k|        } else {  // uncommon
 9290|       |          // only three cases matter: /./, /.. or a final /
 9291|  25.1k|          slashdot += 2;
 9292|  25.1k|          dot_is_file &= !(slashdot == input.size() || input[slashdot] == '.' ||
  ------------------
  |  Branch (9292:28): [True: 75, False: 25.0k]
  |  Branch (9292:56): [True: 12.3k, False: 12.7k]
  ------------------
 9293|  12.7k|                           input[slashdot] == '/');
  ------------------
  |  Branch (9293:28): [True: 11.5k, False: 1.14k]
  ------------------
 9294|  25.1k|        }
 9295|  36.5k|      }
 9296|  11.3k|      trivial_path = dot_is_file;
 9297|  11.3k|    }
 9298|  12.7k|  }
 9299|   232k|  if (trivial_path) {
  ------------------
  |  Branch (9299:7): [True: 204k, False: 28.4k]
  ------------------
 9300|   204k|    ada_log("parse_path trivial");
 9301|   204k|    path += '/';
 9302|   204k|    path += input;
 9303|   204k|    return;
 9304|   204k|  }
 9305|       |  // We are going to need to look a bit at the path, but let us see if we can
 9306|       |  // ignore percent encoding *and* backslashes *and* percent characters.
 9307|       |  // Except for the trivial case, this is likely to capture 99% of paths out
 9308|       |  // there.
 9309|  28.4k|  bool fast_path =
 9310|  28.4k|      (special &&
  ------------------
  |  Branch (9310:8): [True: 27.9k, False: 473]
  ------------------
 9311|  27.9k|       (accumulator & (need_encoding | backslash_char | percent_char)) == 0) &&
  ------------------
  |  Branch (9311:8): [True: 11.4k, False: 16.4k]
  ------------------
 9312|  11.4k|      (type != ada::scheme::type::FILE);
  ------------------
  |  Branch (9312:7): [True: 11.3k, False: 89]
  ------------------
 9313|  28.4k|  if (fast_path) {
  ------------------
  |  Branch (9313:7): [True: 11.3k, False: 17.0k]
  ------------------
 9314|  11.3k|    ada_log("parse_prepared_path fast");
 9315|       |    // Here we don't need to worry about \ or percent encoding.
 9316|       |    // We also do not have a file protocol. We might have dots, however,
 9317|       |    // but dots must as appear as '.', and they cannot be encoded because
 9318|       |    // the symbol '%' is not present.
 9319|  11.3k|    size_t previous_location = 0;  // We start at 0.
 9320|  70.2k|    do {
 9321|  70.2k|      size_t new_location = input.find('/', previous_location);
 9322|       |      // std::string_view path_view = input;
 9323|       |      //  We process the last segment separately:
 9324|  70.2k|      if (new_location == std::string_view::npos) {
  ------------------
  |  Branch (9324:11): [True: 11.3k, False: 58.8k]
  ------------------
 9325|  11.3k|        std::string_view path_view = input.substr(previous_location);
 9326|  11.3k|        if (path_view == "..") {  // The path ends with ..
  ------------------
  |  Branch (9326:13): [True: 83, False: 11.3k]
  ------------------
 9327|       |          // e.g., if you receive ".." with an empty path, you go to "/".
 9328|     83|          if (path.empty()) {
  ------------------
  |  Branch (9328:15): [True: 18, False: 65]
  ------------------
 9329|     18|            path = '/';
 9330|     18|            return;
 9331|     18|          }
 9332|       |          // Fast case where we have nothing to do:
 9333|     65|          if (path.back() == '/') {
  ------------------
  |  Branch (9333:15): [True: 18, False: 47]
  ------------------
 9334|     18|            return;
 9335|     18|          }
 9336|       |          // If you have the path "/joe/myfriend",
 9337|       |          // then you delete 'myfriend'.
 9338|     47|          path.resize(path.rfind('/') + 1);
 9339|     47|          return;
 9340|     65|        }
 9341|  11.3k|        path += '/';
 9342|  11.3k|        if (path_view != ".") {
  ------------------
  |  Branch (9342:13): [True: 11.2k, False: 99]
  ------------------
 9343|  11.2k|          path.append(path_view);
 9344|  11.2k|        }
 9345|  11.3k|        return;
 9346|  58.8k|      } else {
 9347|       |        // This is a non-final segment.
 9348|  58.8k|        std::string_view path_view =
 9349|  58.8k|            input.substr(previous_location, new_location - previous_location);
 9350|  58.8k|        previous_location = new_location + 1;
 9351|  58.8k|        if (path_view == "..") {
  ------------------
  |  Branch (9351:13): [True: 13.0k, False: 45.8k]
  ------------------
 9352|  13.0k|          size_t last_delimiter = path.rfind('/');
 9353|  13.0k|          if (last_delimiter != std::string::npos) {
  ------------------
  |  Branch (9353:15): [True: 10.8k, False: 2.14k]
  ------------------
 9354|  10.8k|            path.erase(last_delimiter);
 9355|  10.8k|          }
 9356|  45.8k|        } else if (path_view != ".") {
  ------------------
  |  Branch (9356:20): [True: 33.2k, False: 12.5k]
  ------------------
 9357|  33.2k|          path += '/';
 9358|  33.2k|          path.append(path_view);
 9359|  33.2k|        }
 9360|  58.8k|      }
 9361|  70.2k|    } while (true);
  ------------------
  |  Branch (9361:14): [True: 58.8k, Folded]
  ------------------
 9362|  17.0k|  } else {
 9363|  17.0k|    ada_log("parse_path slow");
 9364|       |    // we have reached the general case
 9365|  17.0k|    bool needs_percent_encoding = (accumulator & 1);
 9366|  17.0k|    std::string path_buffer_tmp;
 9367|  62.1k|    do {
 9368|  62.1k|      size_t location = (special && (accumulator & 2))
  ------------------
  |  Branch (9368:26): [True: 60.2k, False: 1.97k]
  |  Branch (9368:37): [True: 6.29k, False: 53.9k]
  ------------------
 9369|  62.1k|                            ? input.find_first_of("/\\")
 9370|  62.1k|                            : input.find('/');
 9371|  62.1k|      std::string_view path_view = input;
 9372|  62.1k|      if (location != std::string_view::npos) {
  ------------------
  |  Branch (9372:11): [True: 45.1k, False: 17.0k]
  ------------------
 9373|  45.1k|        path_view.remove_suffix(path_view.size() - location);
 9374|  45.1k|        input.remove_prefix(location + 1);
 9375|  45.1k|      }
 9376|       |      // path_buffer is either path_view or it might point at a percent encoded
 9377|       |      // temporary file.
 9378|  62.1k|      std::string_view path_buffer =
 9379|  62.1k|          (needs_percent_encoding &&
  ------------------
  |  Branch (9379:12): [True: 13.2k, False: 48.9k]
  ------------------
 9380|  13.2k|           ada::unicode::percent_encode<false>(
  ------------------
  |  Branch (9380:12): [True: 4.56k, False: 8.67k]
  ------------------
 9381|  13.2k|               path_view, character_sets::PATH_PERCENT_ENCODE, path_buffer_tmp))
 9382|  62.1k|              ? path_buffer_tmp
 9383|  62.1k|              : path_view;
 9384|  62.1k|      if (unicode::is_double_dot_path_segment(path_buffer)) {
  ------------------
  |  Branch (9384:11): [True: 12.8k, False: 49.3k]
  ------------------
 9385|  12.8k|        helpers::shorten_path(path, type);
 9386|  12.8k|        if (location == std::string_view::npos) {
  ------------------
  |  Branch (9386:13): [True: 9.54k, False: 3.29k]
  ------------------
 9387|  9.54k|          path += '/';
 9388|  9.54k|        }
 9389|  49.3k|      } else if (unicode::is_single_dot_path_segment(path_buffer) &&
  ------------------
  |  Branch (9389:18): [True: 2.26k, False: 47.0k]
  ------------------
 9390|  2.26k|                 (location == std::string_view::npos)) {
  ------------------
  |  Branch (9390:18): [True: 450, False: 1.81k]
  ------------------
 9391|    450|        path += '/';
 9392|    450|      }
 9393|       |      // Otherwise, if path_buffer is not a single-dot path segment, then:
 9394|  48.8k|      else if (!unicode::is_single_dot_path_segment(path_buffer)) {
  ------------------
  |  Branch (9394:16): [True: 47.0k, False: 1.81k]
  ------------------
 9395|       |        // If url's scheme is "file", url's path is empty, and path_buffer is a
 9396|       |        // Windows drive letter, then replace the second code point in
 9397|       |        // path_buffer with U+003A (:).
 9398|  47.0k|        if (type == ada::scheme::type::FILE && path.empty() &&
  ------------------
  |  Branch (9398:13): [True: 2.06k, False: 45.0k]
  |  Branch (9398:48): [True: 581, False: 1.48k]
  ------------------
 9399|    581|            checkers::is_windows_drive_letter(path_buffer)) {
  ------------------
  |  Branch (9399:13): [True: 39, False: 542]
  ------------------
 9400|     39|          path += '/';
 9401|     39|          path += path_buffer[0];
 9402|     39|          path += ':';
 9403|     39|          path_buffer.remove_prefix(2);
 9404|     39|          path.append(path_buffer);
 9405|  47.0k|        } else {
 9406|       |          // Append path_buffer to url's path.
 9407|  47.0k|          path += '/';
 9408|  47.0k|          path.append(path_buffer);
 9409|  47.0k|        }
 9410|  47.0k|      }
 9411|  62.1k|      if (location == std::string_view::npos) {
  ------------------
  |  Branch (9411:11): [True: 17.0k, False: 45.1k]
  ------------------
 9412|  17.0k|        return;
 9413|  17.0k|      }
 9414|  62.1k|    } while (true);
  ------------------
  |  Branch (9414:14): [True: 45.1k, Folded]
  ------------------
 9415|  17.0k|  }
 9416|  28.4k|}
_ZN3ada8checkers14path_signatureENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
   75|   464k|    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|   464k|  size_t i = 0;
   82|   464k|  uint8_t accumulator{};
   83|   624k|  for (; i + 7 < input.size(); i += 8) {
  ------------------
  |  Branch (83:10): [True: 159k, False: 464k]
  ------------------
   84|   159k|    accumulator |= uint8_t(path_signature_table[uint8_t(input[i])] |
   85|   159k|                           path_signature_table[uint8_t(input[i + 1])] |
   86|   159k|                           path_signature_table[uint8_t(input[i + 2])] |
   87|   159k|                           path_signature_table[uint8_t(input[i + 3])] |
   88|   159k|                           path_signature_table[uint8_t(input[i + 4])] |
   89|   159k|                           path_signature_table[uint8_t(input[i + 5])] |
   90|   159k|                           path_signature_table[uint8_t(input[i + 6])] |
   91|   159k|                           path_signature_table[uint8_t(input[i + 7])]);
   92|   159k|  }
   93|   746k|  for (; i < input.size(); i++) {
  ------------------
  |  Branch (93:10): [True: 281k, False: 464k]
  ------------------
   94|   281k|    accumulator |= uint8_t(path_signature_table[uint8_t(input[i])]);
   95|   281k|  }
   96|   464k|  return accumulator;
   97|   464k|}
_ZN3ada7unicode26is_double_dot_path_segmentENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 7115|   124k|    std::string_view input) noexcept {
 7116|       |  // This will catch most cases:
 7117|       |  // The length must be 2,4 or 6.
 7118|       |  // We divide by two and require
 7119|       |  // that the result be between 1 and 3 inclusively.
 7120|   124k|  uint64_t half_length = uint64_t(input.size()) / 2;
 7121|   124k|  if (half_length - 1 > 2) {
  ------------------
  |  Branch (7121:7): [True: 47.2k, False: 77.0k]
  ------------------
 7122|  47.2k|    return false;
 7123|  47.2k|  }
 7124|       |  // We have a string of length 2, 4 or 6.
 7125|       |  // We now check the first character:
 7126|  77.0k|  if ((input[0] != '.') && (input[0] != '%')) {
  ------------------
  |  Branch (7126:7): [True: 66.0k, False: 11.0k]
  |  Branch (7126:28): [True: 25.7k, False: 40.2k]
  ------------------
 7127|  25.7k|    return false;
 7128|  25.7k|  }
 7129|       |  // We are unlikely the get beyond this point.
 7130|  51.3k|  int hash_value = (input.size() + (unsigned)(input[0])) & 3;
 7131|  51.3k|  const std::string_view target = table_is_double_dot_path_segment[hash_value];
 7132|  51.3k|  if (target.size() != input.size()) {
  ------------------
  |  Branch (7132:7): [True: 16.4k, False: 34.8k]
  ------------------
 7133|  16.4k|    return false;
 7134|  16.4k|  }
 7135|       |  // We almost never get here.
 7136|       |  // Optimizing the rest is relatively unimportant.
 7137|  34.8k|  auto prefix_equal_unsafe = [](std::string_view a, std::string_view b) {
 7138|  34.8k|    uint16_t A, B;
 7139|  34.8k|    memcpy(&A, a.data(), sizeof(A));
 7140|  34.8k|    memcpy(&B, b.data(), sizeof(B));
 7141|  34.8k|    return A == B;
 7142|  34.8k|  };
 7143|  34.8k|  if (!prefix_equal_unsafe(input, target)) {
  ------------------
  |  Branch (7143:7): [True: 2.55k, False: 32.3k]
  ------------------
 7144|  2.55k|    return false;
 7145|  2.55k|  }
 7146|   116k|  for (size_t i = 2; i < input.size(); i++) {
  ------------------
  |  Branch (7146:22): [True: 91.2k, False: 25.6k]
  ------------------
 7147|  91.2k|    char c = input[i];
 7148|  91.2k|    if ((uint8_t((c | 0x20) - 0x61) <= 25 ? (c | 0x20) : c) != target[i]) {
  ------------------
  |  Branch (7148:9): [True: 6.66k, False: 84.5k]
  |  Branch (7148:10): [True: 43.7k, False: 47.4k]
  ------------------
 7149|  6.66k|      return false;
 7150|  6.66k|    }
 7151|  91.2k|  }
 7152|  25.6k|  return true;
 7153|       |  // The above code might be a bit better than the code below. Compilers
 7154|       |  // are not stupid and may use the fact that these strings have length 2,4 and
 7155|       |  // 6 and other tricks.
 7156|       |  // return input == ".." ||
 7157|       |  //  input == ".%2e" || input == ".%2E" ||
 7158|       |  //  input == "%2e." || input == "%2E." ||
 7159|       |  //  input == "%2e%2e" || input == "%2E%2E" || input == "%2E%2e" || input ==
 7160|       |  //  "%2e%2E";
 7161|  32.3k|}
_ZZN3ada7unicode26is_double_dot_path_segmentENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlS5_S5_E_clES5_S5_:
 7137|  34.8k|  auto prefix_equal_unsafe = [](std::string_view a, std::string_view b) {
 7138|  34.8k|    uint16_t A, B;
 7139|  34.8k|    memcpy(&A, a.data(), sizeof(A));
 7140|  34.8k|    memcpy(&B, b.data(), sizeof(B));
 7141|  34.8k|    return A == B;
 7142|  34.8k|  };
_ZN3ada7unicode26is_single_dot_path_segmentENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 7164|   196k|    std::string_view input) noexcept {
 7165|   196k|  return input == "." || input == "%2e" || input == "%2E";
  ------------------
  |  Branch (7165:10): [True: 4.14k, False: 192k]
  |  Branch (7165:26): [True: 4.00k, False: 188k]
  |  Branch (7165:44): [True: 20, False: 188k]
  ------------------
 7166|   196k|}
_ZN3ada7unicode28is_forbidden_host_code_pointEc:
 6985|  16.7k|    const char c) noexcept {
 6986|  16.7k|  return is_forbidden_host_code_point_table[uint8_t(c)];
 6987|  16.7k|}
_ZN3ada6detail17parse_ipv4_numberERPKcS2_RmRb:
 9539|  97.6k|                              bool& is_pure_decimal) noexcept {
 9540|  97.6k|  is_pure_decimal = false;
 9541|  97.6k|  if (p >= end) [[unlikely]] {
  ------------------
  |  Branch (9541:7): [True: 0, False: 97.6k]
  ------------------
 9542|      0|    return false;
 9543|      0|  }
 9544|  97.6k|  if (end - p >= 2 && p[0] == '0' && ((p[1] | 0x20) == 'x')) {
  ------------------
  |  Branch (9544:7): [True: 76.9k, False: 20.6k]
  |  Branch (9544:23): [True: 38.1k, False: 38.7k]
  |  Branch (9544:38): [True: 37.7k, False: 372]
  ------------------
 9545|  37.7k|    p += 2;
 9546|  37.7k|    if (p == end || *p == '.') {
  ------------------
  |  Branch (9546:9): [True: 58, False: 37.7k]
  |  Branch (9546:21): [True: 34, False: 37.7k]
  ------------------
 9547|     92|      value = 0;
 9548|     92|      return true;
 9549|     92|    }
 9550|  37.7k|    uint64_t v = 0;
 9551|  37.7k|    int digits = 0;
 9552|   226k|    while (p < end && *p != '.') {
  ------------------
  |  Branch (9552:12): [True: 208k, False: 18.6k]
  |  Branch (9552:23): [True: 189k, False: 18.9k]
  ------------------
 9553|   189k|      const uint8_t nib = hex_nibble[static_cast<unsigned char>(*p)];
 9554|   189k|      if (nib == 0xff) [[unlikely]] {
  ------------------
  |  Branch (9554:11): [True: 12, False: 189k]
  ------------------
 9555|     12|        return false;
 9556|     12|      }
 9557|   189k|      if (v > (0xFFFFFFFFULL >> 4)) [[unlikely]] {
  ------------------
  |  Branch (9557:11): [True: 86, False: 188k]
  ------------------
 9558|     86|        return false;
 9559|     86|      }
 9560|   188k|      v = (v << 4) | nib;
 9561|   188k|      ++p;
 9562|   188k|      ++digits;
 9563|   188k|    }
 9564|  37.6k|    if (digits == 0) [[unlikely]] {
  ------------------
  |  Branch (9564:9): [True: 0, False: 37.6k]
  ------------------
 9565|      0|      return false;
 9566|      0|    }
 9567|  37.6k|    value = v;
 9568|  37.6k|    return true;
 9569|  37.6k|  }
 9570|  59.8k|  if (end - p >= 2 && p[0] == '0' && p[1] >= '0' && p[1] <= '9') {
  ------------------
  |  Branch (9570:7): [True: 39.1k, False: 20.6k]
  |  Branch (9570:23): [True: 372, False: 38.7k]
  |  Branch (9570:38): [True: 230, False: 142]
  |  Branch (9570:53): [True: 218, False: 12]
  ------------------
 9571|    218|    ++p;
 9572|    218|    uint64_t v = 0;
 9573|  4.80k|    while (p < end && *p != '.') {
  ------------------
  |  Branch (9573:12): [True: 4.69k, False: 104]
  |  Branch (9573:23): [True: 4.66k, False: 36]
  ------------------
 9574|  4.66k|      const char c = *p;
 9575|  4.66k|      if (c < '0' || c > '7') [[unlikely]] {
  ------------------
  |  Branch (9575:11): [True: 6, False: 4.65k]
  |  Branch (9575:22): [True: 18, False: 4.63k]
  ------------------
 9576|     24|        return false;
 9577|     24|      }
 9578|  4.63k|      if (v > (0xFFFFFFFFULL >> 3)) [[unlikely]] {
  ------------------
  |  Branch (9578:11): [True: 54, False: 4.58k]
  ------------------
 9579|     54|        return false;
 9580|     54|      }
 9581|  4.58k|      v = (v << 3) | static_cast<uint64_t>(c - '0');
 9582|  4.58k|      ++p;
 9583|  4.58k|    }
 9584|    140|    value = v;
 9585|    140|    return true;
 9586|    218|  }
 9587|  59.5k|  if (*p < '0' || *p > '9') [[unlikely]] {
  ------------------
  |  Branch (9587:7): [True: 76, False: 59.5k]
  |  Branch (9587:19): [True: 36.8k, False: 22.6k]
  ------------------
 9588|  36.9k|    return false;
 9589|  36.9k|  }
 9590|  22.6k|  is_pure_decimal = true;
 9591|  22.6k|  uint64_t v = static_cast<uint64_t>(*p - '0');
 9592|  22.6k|  ++p;
 9593|  30.4k|  while (p < end && *p != '.') {
  ------------------
  |  Branch (9593:10): [True: 9.09k, False: 21.3k]
  |  Branch (9593:21): [True: 7.89k, False: 1.20k]
  ------------------
 9594|  7.89k|    const char c = *p;
 9595|  7.89k|    if (c < '0' || c > '9') [[unlikely]] {
  ------------------
  |  Branch (9595:9): [True: 24, False: 7.87k]
  |  Branch (9595:20): [True: 38, False: 7.83k]
  ------------------
 9596|     62|      return false;
 9597|     62|    }
 9598|  7.83k|    if (v > 429496729ULL) [[unlikely]] {
  ------------------
  |  Branch (9598:9): [True: 78, False: 7.75k]
  ------------------
 9599|     78|      return false;
 9600|     78|    }
 9601|  7.75k|    v = v * 10u + static_cast<uint64_t>(c - '0');
 9602|  7.75k|    if (v > 0xFFFFFFFFULL) [[unlikely]] {
  ------------------
  |  Branch (9602:9): [True: 8, False: 7.75k]
  ------------------
 9603|      8|      return false;
 9604|      8|    }
 9605|  7.75k|    ++p;
 9606|  7.75k|  }
 9607|  22.5k|  value = v;
 9608|  22.5k|  return true;
 9609|  22.6k|}
_ZN3ada6detail15parse_hex_pieceERPKcS2_Rt:
 9613|  1.98k|                           uint16_t& value) noexcept {
 9614|  1.98k|  if (pointer == end) {
  ------------------
  |  Branch (9614:7): [True: 0, False: 1.98k]
  ------------------
 9615|      0|    return 0;
 9616|      0|  }
 9617|  1.98k|  const uint8_t n0 = hex_nibble[static_cast<unsigned char>(*pointer)];
 9618|  1.98k|  if (n0 == 0xff) {
  ------------------
  |  Branch (9618:7): [True: 42, False: 1.94k]
  ------------------
 9619|     42|    return 0;
 9620|     42|  }
 9621|  1.94k|  uint32_t v = n0;
 9622|  1.94k|  ++pointer;
 9623|  1.94k|  int length = 1;
 9624|  1.94k|  if (pointer != end) {
  ------------------
  |  Branch (9624:7): [True: 1.72k, False: 216]
  ------------------
 9625|  1.72k|    const uint8_t n1 = hex_nibble[static_cast<unsigned char>(*pointer)];
 9626|  1.72k|    if (n1 != 0xff) {
  ------------------
  |  Branch (9626:9): [True: 654, False: 1.07k]
  ------------------
 9627|    654|      v = (v << 4) | n1;
 9628|    654|      ++pointer;
 9629|    654|      ++length;
 9630|    654|      if (pointer != end) {
  ------------------
  |  Branch (9630:11): [True: 568, False: 86]
  ------------------
 9631|    568|        const uint8_t n2 = hex_nibble[static_cast<unsigned char>(*pointer)];
 9632|    568|        if (n2 != 0xff) {
  ------------------
  |  Branch (9632:13): [True: 402, False: 166]
  ------------------
 9633|    402|          v = (v << 4) | n2;
 9634|    402|          ++pointer;
 9635|    402|          ++length;
 9636|    402|          if (pointer != end) {
  ------------------
  |  Branch (9636:15): [True: 314, False: 88]
  ------------------
 9637|    314|            const uint8_t n3 = hex_nibble[static_cast<unsigned char>(*pointer)];
 9638|    314|            if (n3 != 0xff) {
  ------------------
  |  Branch (9638:17): [True: 138, False: 176]
  ------------------
 9639|    138|              v = (v << 4) | n3;
 9640|    138|              ++pointer;
 9641|    138|              ++length;
 9642|    138|            }
 9643|    314|          }
 9644|    402|        }
 9645|    568|      }
 9646|    654|    }
 9647|  1.72k|  }
 9648|  1.94k|  value = static_cast<uint16_t>(v);
 9649|  1.94k|  return length;
 9650|  1.98k|}
_ZN3ada3url10parse_pathENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
10222|  23.0k|ada_really_inline void url::parse_path(std::string_view input) {
10223|  23.0k|  ada_log("parse_path ", input);
10224|  23.0k|  std::string tmp_buffer;
10225|  23.0k|  std::string_view internal_input;
10226|  23.0k|  if (unicode::has_tabs_or_newline(input)) {
  ------------------
  |  Branch (10226:7): [True: 0, False: 23.0k]
  ------------------
10227|      0|    tmp_buffer = input;
10228|       |    // Optimization opportunity: Instead of copying and then pruning, we could
10229|       |    // just directly build the string from user_input.
10230|      0|    helpers::remove_ascii_tab_or_newline(tmp_buffer);
10231|      0|    internal_input = tmp_buffer;
10232|  23.0k|  } else {
10233|  23.0k|    internal_input = input;
10234|  23.0k|  }
10235|       |
10236|       |  // If url is special, then:
10237|  23.0k|  if (is_special()) {
  ------------------
  |  Branch (10237:7): [True: 23.0k, False: 0]
  ------------------
10238|  23.0k|    if (internal_input.empty()) {
  ------------------
  |  Branch (10238:9): [True: 196, False: 22.8k]
  ------------------
10239|    196|      path = "/";
10240|  22.8k|    } else if ((internal_input[0] == '/') || (internal_input[0] == '\\')) {
  ------------------
  |  Branch (10240:16): [True: 22.8k, False: 0]
  |  Branch (10240:46): [True: 0, False: 0]
  ------------------
10241|  22.8k|      helpers::parse_prepared_path(internal_input.substr(1), type, path);
10242|  22.8k|    } else {
10243|      0|      helpers::parse_prepared_path(internal_input, type, path);
10244|      0|    }
10245|  23.0k|  } else if (!internal_input.empty()) {
  ------------------
  |  Branch (10245:14): [True: 0, False: 0]
  ------------------
10246|      0|    if (internal_input[0] == '/') {
  ------------------
  |  Branch (10246:9): [True: 0, False: 0]
  ------------------
10247|      0|      helpers::parse_prepared_path(internal_input.substr(1), type, path);
10248|      0|    } else {
10249|      0|      helpers::parse_prepared_path(internal_input, type, path);
10250|      0|    }
10251|      0|  } else {
10252|      0|    if (!host.has_value()) {
  ------------------
  |  Branch (10252:9): [True: 0, False: 0]
  ------------------
10253|      0|      path = "/";
10254|      0|    }
10255|      0|  }
10256|  23.0k|}
_ZN3ada7unicode13is_alnum_plusEc:
 7079|  2.27M|ada_really_inline constexpr bool is_alnum_plus(const char c) noexcept {
 7080|  2.27M|  return is_alnum_plus_table[uint8_t(c)];
 7081|       |  // A table is almost surely much faster than the
 7082|       |  // following under most compilers: return
 7083|       |  // return (std::isalnum(c) || c == '+' || c == '-' || c == '.');
 7084|  2.27M|}
_ZN3ada7unicode14to_lower_asciiEPcm:
 6761|  50.4k|constexpr bool to_lower_ascii(char* input, size_t length) noexcept {
 6762|  50.4k|  uint64_t broadcast_80 = broadcast(0x80);
 6763|  50.4k|  uint64_t broadcast_Ap = broadcast(128 - 'A');
 6764|  50.4k|  uint64_t broadcast_Zp = broadcast(128 - 'Z' - 1);
 6765|  50.4k|  uint64_t non_ascii = 0;
 6766|  50.4k|  size_t i = 0;
 6767|       |
 6768|  95.6k|  for (; i + 7 < length; i += 8) {
  ------------------
  |  Branch (6768:10): [True: 45.1k, False: 50.4k]
  ------------------
 6769|  45.1k|    uint64_t word{};
 6770|  45.1k|    memcpy(&word, input + i, sizeof(word));
 6771|  45.1k|    non_ascii |= (word & broadcast_80);
 6772|  45.1k|    word ^=
 6773|  45.1k|        (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
 6774|  45.1k|    memcpy(input + i, &word, sizeof(word));
 6775|  45.1k|  }
 6776|  50.4k|  if (i < length) {
  ------------------
  |  Branch (6776:7): [True: 50.0k, False: 422]
  ------------------
 6777|  50.0k|    uint64_t word{};
 6778|  50.0k|    memcpy(&word, input + i, length - i);
 6779|  50.0k|    non_ascii |= (word & broadcast_80);
 6780|  50.0k|    word ^=
 6781|  50.0k|        (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
 6782|  50.0k|    memcpy(input + i, &word, length - i);
 6783|  50.0k|  }
 6784|  50.4k|  return non_ascii == 0;
 6785|  50.4k|}
_ZN3ada7unicode9broadcastEh:
 6757|   151k|constexpr uint64_t broadcast(uint8_t v) noexcept {
 6758|   151k|  return 0x101010101010101ull * v;
 6759|   151k|}
_ZZN3ada6parser25try_parse_simple_absoluteINS_3urlEEEbNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEERT_ENKUlvE_clEv:
12222|  21.3k|    auto apply_query_and_hash = [&]() {
12223|  21.3k|      if (query_start != std::string_view::npos) {
  ------------------
  |  Branch (12223:11): [True: 1.18k, False: 20.1k]
  ------------------
12224|  1.18k|        const size_t q_end =
12225|  1.18k|            (hash_start != std::string_view::npos) ? hash_start : len;
  ------------------
  |  Branch (12225:13): [True: 802, False: 382]
  ------------------
12226|  1.18k|        out.update_base_search(std::string_view(input.data() + query_start + 1,
12227|  1.18k|                                                q_end - query_start - 1),
12228|  1.18k|                               character_sets::SPECIAL_QUERY_PERCENT_ENCODE);
12229|  1.18k|      }
12230|  21.3k|      if (hash_start != std::string_view::npos) {
  ------------------
  |  Branch (12230:11): [True: 1.12k, False: 20.2k]
  ------------------
12231|  1.12k|        out.update_unencoded_base_hash(std::string_view(
12232|  1.12k|            input.data() + hash_start + 1, len - hash_start - 1));
12233|  1.12k|      }
12234|  21.3k|    };
_ZZN3ada6parser25try_parse_simple_absoluteINS_14url_aggregatorEEEbNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEERT_ENKUlvE_clEv:
12222|  21.3k|    auto apply_query_and_hash = [&]() {
12223|  21.3k|      if (query_start != std::string_view::npos) {
  ------------------
  |  Branch (12223:11): [True: 1.18k, False: 20.1k]
  ------------------
12224|  1.18k|        const size_t q_end =
12225|  1.18k|            (hash_start != std::string_view::npos) ? hash_start : len;
  ------------------
  |  Branch (12225:13): [True: 802, False: 382]
  ------------------
12226|  1.18k|        out.update_base_search(std::string_view(input.data() + query_start + 1,
12227|  1.18k|                                                q_end - query_start - 1),
12228|  1.18k|                               character_sets::SPECIAL_QUERY_PERCENT_ENCODE);
12229|  1.18k|      }
12230|  21.3k|      if (hash_start != std::string_view::npos) {
  ------------------
  |  Branch (12230:11): [True: 1.12k, False: 20.2k]
  ------------------
12231|  1.12k|        out.update_unencoded_base_hash(std::string_view(
12232|  1.12k|            input.data() + hash_start + 1, len - hash_start - 1));
12233|  1.12k|      }
12234|  21.3k|    };
_ZZN3ada6parser32finish_simple_absolute_with_portINS_3urlEEEbNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEERT_NS_6scheme4typeEjmmmbENKUlvE_clEv:
11822|  1.66k|    auto apply_query_and_hash = [&]() {
11823|  1.66k|      if (query_start != std::string_view::npos) {
  ------------------
  |  Branch (11823:11): [True: 752, False: 913]
  ------------------
11824|    752|        const size_t q_end =
11825|    752|            (hash_start != std::string_view::npos) ? hash_start : len;
  ------------------
  |  Branch (11825:13): [True: 508, False: 244]
  ------------------
11826|    752|        out.update_base_search(std::string_view(input.data() + query_start + 1,
11827|    752|                                                q_end - query_start - 1),
11828|    752|                               character_sets::SPECIAL_QUERY_PERCENT_ENCODE);
11829|    752|      }
11830|  1.66k|      if (hash_start != std::string_view::npos) {
  ------------------
  |  Branch (11830:11): [True: 752, False: 913]
  ------------------
11831|    752|        out.update_unencoded_base_hash(std::string_view(
11832|    752|            input.data() + hash_start + 1, len - hash_start - 1));
11833|    752|      }
11834|  1.66k|    };
_ZZN3ada6parser32finish_simple_absolute_with_portINS_14url_aggregatorEEEbNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEERT_NS_6scheme4typeEjmmmbENKUlvE_clEv:
11822|  1.66k|    auto apply_query_and_hash = [&]() {
11823|  1.66k|      if (query_start != std::string_view::npos) {
  ------------------
  |  Branch (11823:11): [True: 752, False: 913]
  ------------------
11824|    752|        const size_t q_end =
11825|    752|            (hash_start != std::string_view::npos) ? hash_start : len;
  ------------------
  |  Branch (11825:13): [True: 508, False: 244]
  ------------------
11826|    752|        out.update_base_search(std::string_view(input.data() + query_start + 1,
11827|    752|                                                q_end - query_start - 1),
11828|    752|                               character_sets::SPECIAL_QUERY_PERCENT_ENCODE);
11829|    752|      }
11830|  1.66k|      if (hash_start != std::string_view::npos) {
  ------------------
  |  Branch (11830:11): [True: 752, False: 913]
  ------------------
11831|    752|        out.update_unencoded_base_hash(std::string_view(
11832|    752|            input.data() + hash_start + 1, len - hash_start - 1));
11833|    752|      }
11834|  1.66k|    };
_ZN3ada7helpers10prune_hashERNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8498|   523k|    std::string_view& input) noexcept {
 8499|       |  // compiles down to 20--30 instructions including a class to memchr (C
 8500|       |  // function). this function should be quite fast.
 8501|   523k|  size_t location_of_first = input.find('#');
 8502|   523k|  if (location_of_first == std::string_view::npos) {
  ------------------
  |  Branch (8502:7): [True: 501k, False: 22.3k]
  ------------------
 8503|   501k|    return std::nullopt;
 8504|   501k|  }
 8505|  22.3k|  std::string_view hash = input;
 8506|  22.3k|  hash.remove_prefix(location_of_first + 1);
 8507|  22.3k|  input.remove_suffix(input.size() - location_of_first);
 8508|  22.3k|  return hash;
 8509|   523k|}
_ZZN3ada6parser14parse_url_implINS_3urlELb1EEET_NSt3__117basic_string_viewIcNS4_11char_traitsIcEEEEPKS3_ENKUlvE_clEv:
12545|   240k|  const auto enforce_max_input_length = [&]() {
12546|   240k|    if constexpr (store_values) {
12547|   240k|      if (url.is_valid) {
  ------------------
  |  Branch (12547:11): [True: 240k, False: 0]
  ------------------
12548|       |        if constexpr (result_type_is_ada_url_aggregator) {
12549|       |          if (url.buffer.size() > max_input_length) [[unlikely]] {
12550|       |            url.is_valid = false;
12551|       |          }
12552|   240k|        } else {
12553|   240k|          if (url.get_href_size() > max_input_length) [[unlikely]] {
  ------------------
  |  Branch (12553:15): [True: 0, False: 240k]
  ------------------
12554|      0|            url.is_valid = false;
12555|      0|          }
12556|   240k|        }
12557|   240k|      }
12558|   240k|    }
12559|   240k|  };
_ZN3ada7helpers32find_authority_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9451|   184k|find_authority_delimiter_special(std::string_view view) noexcept {
 9452|       |  // performance note: we might be able to gain further performance
 9453|       |  // with SIMD intrinsics.
 9454|  1.98M|  for (auto pos = view.begin(); pos != view.end(); ++pos) {
  ------------------
  |  Branch (9454:33): [True: 1.96M, False: 19.3k]
  ------------------
 9455|  1.96M|    if (authority_delimiter_special[(uint8_t)*pos]) {
  ------------------
  |  Branch (9455:9): [True: 165k, False: 1.80M]
  ------------------
 9456|   165k|      return pos - view.begin();
 9457|   165k|    }
 9458|  1.96M|  }
 9459|  19.3k|  return size_t(view.size());
 9460|   184k|}
_ZN3ada7helpers24find_authority_delimiterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9472|    412|find_authority_delimiter(std::string_view view) noexcept {
 9473|       |  // performance note: we might be able to gain further performance
 9474|       |  // with SIMD instrinsics.
 9475|  4.76k|  for (auto pos = view.begin(); pos != view.end(); ++pos) {
  ------------------
  |  Branch (9475:33): [True: 4.71k, False: 48]
  ------------------
 9476|  4.71k|    if (authority_delimiter[(uint8_t)*pos]) {
  ------------------
  |  Branch (9476:9): [True: 364, False: 4.34k]
  ------------------
 9477|    364|      return pos - view.begin();
 9478|    364|    }
 9479|  4.71k|  }
 9480|     48|  return size_t(view.size());
 9481|    412|}
_ZN3ada7helpers12shorten_pathERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS_6scheme4typeE:
 8511|  25.6k|ada_really_inline bool shorten_path(std::string& path, ada::scheme::type type) {
 8512|       |  // Let path be url's path.
 8513|       |  // If url's scheme is "file", path's size is 1, and path[0] is a normalized
 8514|       |  // Windows drive letter, then return.
 8515|  25.6k|  if (type == ada::scheme::type::FILE &&
  ------------------
  |  Branch (8515:7): [True: 328, False: 25.3k]
  ------------------
 8516|    328|      path.find('/', 1) == std::string_view::npos && !path.empty()) {
  ------------------
  |  Branch (8516:7): [True: 166, False: 162]
  |  Branch (8516:54): [True: 136, False: 30]
  ------------------
 8517|    136|    if (checkers::is_normalized_windows_drive_letter(
  ------------------
  |  Branch (8517:9): [True: 20, False: 116]
  ------------------
 8518|    136|            helpers::substring(path, 1))) {
 8519|     20|      return false;
 8520|     20|    }
 8521|    136|  }
 8522|       |
 8523|       |  // Remove path's last item, if any.
 8524|  25.6k|  size_t last_delimiter = path.rfind('/');
 8525|  25.6k|  if (last_delimiter != std::string::npos) {
  ------------------
  |  Branch (8525:7): [True: 21.5k, False: 4.06k]
  ------------------
 8526|  21.5k|    path.erase(last_delimiter);
 8527|  21.5k|    return true;
 8528|  21.5k|  }
 8529|       |
 8530|  4.06k|  return false;
 8531|  25.6k|}
_ZN3ada7helpers27get_host_delimiter_locationEbRNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9164|   517k|    const bool is_special, std::string_view& view) noexcept {
 9165|       |  /**
 9166|       |   * The spec at https://url.spec.whatwg.org/#hostname-state expects us to
 9167|       |   * compute a variable called insideBrackets but this variable is only used
 9168|       |   * once, to check whether a ':' character was found outside brackets. Exact
 9169|       |   * text: "Otherwise, if c is U+003A (:) and insideBrackets is false, then:".
 9170|       |   * It is conceptually simpler and arguably more efficient to just return a
 9171|       |   * Boolean indicating whether ':' was found outside brackets.
 9172|       |   */
 9173|   517k|  const size_t view_size = view.size();
 9174|   517k|  size_t location = 0;
 9175|   517k|  bool found_colon = false;
 9176|       |  /**
 9177|       |   * Performance analysis:
 9178|       |   *
 9179|       |   * We are basically seeking the end of the hostname which can be indicated
 9180|       |   * by the end of the view, or by one of the characters ':', '/', '?', '\\'
 9181|       |   * (where '\\' is only applicable for special URLs). However, these must
 9182|       |   * appear outside a bracket range. E.g., if you have [something?]fd: then the
 9183|       |   * '?' does not count.
 9184|       |   *
 9185|       |   * So we can skip ahead to the next delimiter, as long as we include '[' in
 9186|       |   * the set of delimiters, and that we handle it first.
 9187|       |   *
 9188|       |   * So the trick is to have a fast function that locates the next delimiter.
 9189|       |   * Unless we find '[', then it only needs to be called once! Ideally, such a
 9190|       |   * function would be provided by the C++ standard library, but it seems that
 9191|       |   * find_first_of is not very fast, so we are forced to roll our own.
 9192|       |   *
 9193|       |   * We do not break into two loops for speed, but for clarity.
 9194|       |   */
 9195|   517k|  if (is_special) {
  ------------------
  |  Branch (9195:7): [True: 515k, False: 1.54k]
  ------------------
 9196|       |    // We move to the next delimiter.
 9197|   515k|    location = find_next_host_delimiter_special(view, location);
 9198|       |    // Unless we find '[' then we are going only going to have to call
 9199|       |    // find_next_host_delimiter_special once.
 9200|   518k|    for (; location < view_size;
  ------------------
  |  Branch (9200:12): [True: 457k, False: 61.2k]
  ------------------
 9201|   515k|         location = find_next_host_delimiter_special(view, location)) {
 9202|   457k|      if (view[location] == '[') {
  ------------------
  |  Branch (9202:11): [True: 2.77k, False: 454k]
  ------------------
 9203|  2.77k|        location = view.find(']', location);
 9204|  2.77k|        if (location == std::string_view::npos) {
  ------------------
  |  Branch (9204:13): [True: 180, False: 2.59k]
  ------------------
 9205|       |          // performance: view.find might get translated to a memchr, which
 9206|       |          // has no notion of std::string_view::npos, so the code does not
 9207|       |          // reflect the assembly.
 9208|    180|          location = view_size;
 9209|    180|          break;
 9210|    180|        }
 9211|   454k|      } else {
 9212|   454k|        found_colon = view[location] == ':';
 9213|   454k|        break;
 9214|   454k|      }
 9215|   457k|    }
 9216|   515k|  } else {
 9217|       |    // We move to the next delimiter.
 9218|  1.54k|    location = find_next_host_delimiter(view, location);
 9219|       |    // Unless we find '[' then we are going only going to have to call
 9220|       |    // find_next_host_delimiter_special once.
 9221|  1.69k|    for (; location < view_size;
  ------------------
  |  Branch (9221:12): [True: 1.42k, False: 276]
  ------------------
 9222|  1.54k|         location = find_next_host_delimiter(view, location)) {
 9223|  1.42k|      if (view[location] == '[') {
  ------------------
  |  Branch (9223:11): [True: 164, False: 1.25k]
  ------------------
 9224|    164|        location = view.find(']', location);
 9225|    164|        if (location == std::string_view::npos) {
  ------------------
  |  Branch (9225:13): [True: 8, False: 156]
  ------------------
 9226|       |          // performance: view.find might get translated to a memchr, which
 9227|       |          // has no notion of std::string_view::npos, so the code does not
 9228|       |          // reflect the assembly.
 9229|      8|          location = view_size;
 9230|      8|          break;
 9231|      8|        }
 9232|  1.25k|      } else {
 9233|  1.25k|        found_colon = view[location] == ':';
 9234|  1.25k|        break;
 9235|  1.25k|      }
 9236|  1.42k|    }
 9237|  1.54k|  }
 9238|       |  // performance: remove_suffix may translate into a single instruction.
 9239|   517k|  view.remove_suffix(view_size - location);
 9240|   517k|  return {location, found_colon};
 9241|   517k|}
_ZN3ada7helpers32find_next_host_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEm:
 8754|   518k|    std::string_view view, size_t location) noexcept {
 8755|       |  // first check for short strings in which case we do it naively.
 8756|   518k|  if (view.size() - location < 16) {  // slow path
  ------------------
  |  Branch (8756:7): [True: 401k, False: 117k]
  ------------------
 8757|  4.26M|    for (size_t i = location; i < view.size(); i++) {
  ------------------
  |  Branch (8757:31): [True: 4.20M, False: 59.3k]
  ------------------
 8758|  4.20M|      if (view[i] == ':' || view[i] == '/' || view[i] == '\\' ||
  ------------------
  |  Branch (8758:11): [True: 1.39k, False: 4.20M]
  |  Branch (8758:29): [True: 338k, False: 3.86M]
  |  Branch (8758:47): [True: 198, False: 3.86M]
  ------------------
 8759|  3.86M|          view[i] == '?' || view[i] == '[') {
  ------------------
  |  Branch (8759:11): [True: 508, False: 3.86M]
  |  Branch (8759:29): [True: 1.10k, False: 3.86M]
  ------------------
 8760|   341k|        return i;
 8761|   341k|      }
 8762|  4.20M|    }
 8763|  59.3k|    return size_t(view.size());
 8764|   401k|  }
 8765|       |  // fast path for long strings (expected to be common)
 8766|   117k|  size_t i = location;
 8767|   117k|  const __m128i mask1 = _mm_set1_epi8(':');
 8768|   117k|  const __m128i mask2 = _mm_set1_epi8('/');
 8769|   117k|  const __m128i mask3 = _mm_set1_epi8('\\');
 8770|   117k|  const __m128i mask4 = _mm_set1_epi8('?');
 8771|   117k|  const __m128i mask5 = _mm_set1_epi8('[');
 8772|       |
 8773|   235k|  for (; i + 15 < view.size(); i += 16) {
  ------------------
  |  Branch (8773:10): [True: 174k, False: 60.5k]
  ------------------
 8774|   174k|    __m128i word = _mm_loadu_si128((const __m128i*)(view.data() + i));
 8775|   174k|    __m128i m1 = _mm_cmpeq_epi8(word, mask1);
 8776|   174k|    __m128i m2 = _mm_cmpeq_epi8(word, mask2);
 8777|   174k|    __m128i m3 = _mm_cmpeq_epi8(word, mask3);
 8778|   174k|    __m128i m4 = _mm_cmpeq_epi8(word, mask4);
 8779|   174k|    __m128i m5 = _mm_cmpeq_epi8(word, mask5);
 8780|   174k|    __m128i m = _mm_or_si128(
 8781|   174k|        _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m3, m4)), m5);
 8782|   174k|    int mask = _mm_movemask_epi8(m);
 8783|   174k|    if (mask != 0) {
  ------------------
  |  Branch (8783:9): [True: 56.8k, False: 117k]
  ------------------
 8784|  56.8k|      return i + trailing_zeroes(mask);
 8785|  56.8k|    }
 8786|   174k|  }
 8787|  60.5k|  if (i < view.size()) {
  ------------------
  |  Branch (8787:7): [True: 60.2k, False: 296]
  ------------------
 8788|  60.2k|    __m128i word =
 8789|  60.2k|        _mm_loadu_si128((const __m128i*)(view.data() + view.length() - 16));
 8790|  60.2k|    __m128i m1 = _mm_cmpeq_epi8(word, mask1);
 8791|  60.2k|    __m128i m2 = _mm_cmpeq_epi8(word, mask2);
 8792|  60.2k|    __m128i m3 = _mm_cmpeq_epi8(word, mask3);
 8793|  60.2k|    __m128i m4 = _mm_cmpeq_epi8(word, mask4);
 8794|  60.2k|    __m128i m5 = _mm_cmpeq_epi8(word, mask5);
 8795|  60.2k|    __m128i m = _mm_or_si128(
 8796|  60.2k|        _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m3, m4)), m5);
 8797|  60.2k|    int mask = _mm_movemask_epi8(m);
 8798|  60.2k|    if (mask != 0) {
  ------------------
  |  Branch (8798:9): [True: 58.6k, False: 1.58k]
  ------------------
 8799|  58.6k|      return view.length() - 16 + trailing_zeroes(mask);
 8800|  58.6k|    }
 8801|  60.2k|  }
 8802|  1.88k|  return size_t(view.length());
 8803|  60.5k|}
_ZN3ada7helpers15trailing_zeroesEj:
 8579|   116k|ada_really_inline int trailing_zeroes(uint32_t input_num) noexcept {
 8580|       |#ifdef ADA_REGULAR_VISUAL_STUDIO
 8581|       |  unsigned long ret;
 8582|       |  // Search the mask data from least significant bit (LSB)
 8583|       |  // to the most significant bit (MSB) for a set bit (1).
 8584|       |  _BitScanForward(&ret, input_num);
 8585|       |  return (int)ret;
 8586|       |#else   // ADA_REGULAR_VISUAL_STUDIO
 8587|   116k|  return __builtin_ctzl(input_num);
 8588|   116k|#endif  // ADA_REGULAR_VISUAL_STUDIO
 8589|   116k|}
_ZN3ada7helpers24find_next_host_delimiterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEm:
 9030|  1.69k|                                                  size_t location) noexcept {
 9031|       |  // first check for short strings in which case we do it naively.
 9032|  1.69k|  if (view.size() - location < 16) {  // slow path
  ------------------
  |  Branch (9032:7): [True: 554, False: 1.14k]
  ------------------
 9033|  3.44k|    for (size_t i = location; i < view.size(); i++) {
  ------------------
  |  Branch (9033:31): [True: 3.22k, False: 224]
  ------------------
 9034|  3.22k|      if (view[i] == ':' || view[i] == '/' || view[i] == '?' ||
  ------------------
  |  Branch (9034:11): [True: 58, False: 3.16k]
  |  Branch (9034:29): [True: 158, False: 3.00k]
  |  Branch (9034:47): [True: 56, False: 2.95k]
  ------------------
 9035|  2.95k|          view[i] == '[') {
  ------------------
  |  Branch (9035:11): [True: 58, False: 2.89k]
  ------------------
 9036|    330|        return i;
 9037|    330|      }
 9038|  3.22k|    }
 9039|    224|    return size_t(view.size());
 9040|    554|  }
 9041|       |  // fast path for long strings (expected to be common)
 9042|  1.14k|  size_t i = location;
 9043|  1.14k|  const __m128i mask1 = _mm_set1_epi8(':');
 9044|  1.14k|  const __m128i mask2 = _mm_set1_epi8('/');
 9045|  1.14k|  const __m128i mask4 = _mm_set1_epi8('?');
 9046|  1.14k|  const __m128i mask5 = _mm_set1_epi8('[');
 9047|       |
 9048|  1.62k|  for (; i + 15 < view.size(); i += 16) {
  ------------------
  |  Branch (9048:10): [True: 1.47k, False: 146]
  ------------------
 9049|  1.47k|    __m128i word = _mm_loadu_si128((const __m128i*)(view.data() + i));
 9050|  1.47k|    __m128i m1 = _mm_cmpeq_epi8(word, mask1);
 9051|  1.47k|    __m128i m2 = _mm_cmpeq_epi8(word, mask2);
 9052|  1.47k|    __m128i m4 = _mm_cmpeq_epi8(word, mask4);
 9053|  1.47k|    __m128i m5 = _mm_cmpeq_epi8(word, mask5);
 9054|  1.47k|    __m128i m = _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m4, m5));
 9055|  1.47k|    int mask = _mm_movemask_epi8(m);
 9056|  1.47k|    if (mask != 0) {
  ------------------
  |  Branch (9056:9): [True: 998, False: 478]
  ------------------
 9057|    998|      return i + trailing_zeroes(mask);
 9058|    998|    }
 9059|  1.47k|  }
 9060|    146|  if (i < view.size()) {
  ------------------
  |  Branch (9060:7): [True: 116, False: 30]
  ------------------
 9061|    116|    __m128i word =
 9062|    116|        _mm_loadu_si128((const __m128i*)(view.data() + view.length() - 16));
 9063|    116|    __m128i m1 = _mm_cmpeq_epi8(word, mask1);
 9064|    116|    __m128i m2 = _mm_cmpeq_epi8(word, mask2);
 9065|    116|    __m128i m4 = _mm_cmpeq_epi8(word, mask4);
 9066|    116|    __m128i m5 = _mm_cmpeq_epi8(word, mask5);
 9067|    116|    __m128i m = _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m4, m5));
 9068|    116|    int mask = _mm_movemask_epi8(m);
 9069|    116|    if (mask != 0) {
  ------------------
  |  Branch (9069:9): [True: 94, False: 22]
  ------------------
 9070|     94|      return view.length() - 16 + trailing_zeroes(mask);
 9071|     94|    }
 9072|    116|  }
 9073|     52|  return size_t(view.length());
 9074|    146|}
_ZN3ada3url10parse_hostENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
10113|   259k|ada_really_inline bool url::parse_host(std::string_view input) {
10114|   259k|  ada_log("parse_host ", input, " [", input.size(), " bytes]");
10115|   259k|  if (input.empty()) {
  ------------------
  |  Branch (10115:7): [True: 6, False: 259k]
  ------------------
10116|      6|    return is_valid = false;
10117|      6|  }  // technically unnecessary.
10118|       |  // If input starts with U+005B ([), then:
10119|   259k|  if (input[0] == '[') {
  ------------------
  |  Branch (10119:7): [True: 684, False: 258k]
  ------------------
10120|       |    // If input does not end with U+005D (]), validation error, return failure.
10121|    684|    if (input.back() != ']') {
  ------------------
  |  Branch (10121:9): [True: 80, False: 604]
  ------------------
10122|     80|      return is_valid = false;
10123|     80|    }
10124|    604|    ada_log("parse_host ipv6");
10125|       |
10126|       |    // Return the result of IPv6 parsing input with its leading U+005B ([) and
10127|       |    // trailing U+005D (]) removed.
10128|    604|    input.remove_prefix(1);
10129|    604|    input.remove_suffix(1);
10130|    604|    return parse_ipv6(input);
10131|    684|  }
10132|       |
10133|       |  // If isNotSpecial is true, then return the result of opaque-host parsing
10134|       |  // input.
10135|   258k|  if (!is_special()) {
  ------------------
  |  Branch (10135:7): [True: 669, False: 258k]
  ------------------
10136|    669|    return parse_opaque_host(input);
10137|    669|  }
10138|       |
10139|       |  // Fast path: try to parse as pure decimal IPv4 first.
10140|   258k|  const uint64_t fast_result = checkers::try_parse_ipv4_fast(input);
10141|   258k|  if (fast_result < checkers::ipv4_fast_fail) {
  ------------------
  |  Branch (10141:7): [True: 105k, False: 153k]
  ------------------
10142|   105k|    if (!input.empty() && input.back() == '.') {
  ------------------
  |  Branch (10142:9): [True: 105k, False: 0]
  |  Branch (10142:27): [True: 11, False: 105k]
  ------------------
10143|     11|      host = input.substr(0, input.size() - 1);
10144|   105k|    } else {
10145|   105k|      host = input;
10146|   105k|    }
10147|   105k|    host_type = IPV4;
10148|   105k|    is_valid = true;
10149|   105k|    ada_log("parse_host fast path decimal ipv4");
10150|   105k|    return true;
10151|   105k|  }
10152|       |  // Let domain be the result of running UTF-8 decode without BOM on the
10153|       |  // percent-decoding of input. Let asciiDomain be the result of running domain
10154|       |  // to ASCII with domain and false. The most common case is an ASCII input, in
10155|       |  // which case we do not need to call the expensive 'to_ascii' if a few
10156|       |  // conditions are met: no '%' and no 'xn-' subsequence.
10157|   153k|  const uint8_t forbidden_or_upper =
10158|   153k|      unicode::contains_forbidden_domain_code_point_or_upper(input.data(),
10159|   153k|                                                             input.size());
10160|   153k|  static constexpr std::string_view xn_dash{"xn-", 3};
10161|   153k|  if ((forbidden_or_upper & 1) == 0) {
  ------------------
  |  Branch (10161:7): [True: 131k, False: 21.6k]
  ------------------
10162|   131k|    host = std::string(input);
10163|   131k|    if ((forbidden_or_upper & 2) != 0) {
  ------------------
  |  Branch (10163:9): [True: 868, False: 130k]
  ------------------
10164|    868|      unicode::to_lower_ascii(host->data(), host->size());
10165|    868|    }
10166|   131k|    if (host->find('-') == std::string_view::npos ||
  ------------------
  |  Branch (10166:9): [True: 71.8k, False: 59.6k]
  ------------------
10167|  72.0k|        host->find(xn_dash) == std::string_view::npos) {
  ------------------
  |  Branch (10167:9): [True: 238, False: 59.4k]
  ------------------
10168|  72.0k|      if (checkers::is_ipv4(*host)) {
  ------------------
  |  Branch (10168:11): [True: 38.4k, False: 33.5k]
  ------------------
10169|  38.4k|        ada_log("parse_host fast path ipv4");
10170|  38.4k|        return parse_ipv4(*host);
10171|  38.4k|      }
10172|  33.5k|      ada_log("parse_host fast path ", *host);
10173|  33.5k|      is_valid = true;
10174|  33.5k|      return true;
10175|  72.0k|    }
10176|   131k|  } else if (const size_t first_percent = input.find('%');
10177|  21.6k|             first_percent != std::string_view::npos) {
  ------------------
  |  Branch (10177:14): [True: 19.0k, False: 2.58k]
  ------------------
10178|  19.0k|    std::string decoded = unicode::percent_decode(input, first_percent);
10179|  19.0k|    const uint8_t decoded_flags =
10180|  19.0k|        unicode::contains_forbidden_domain_code_point_or_upper(decoded.data(),
10181|  19.0k|                                                               decoded.size());
10182|  19.0k|    if ((decoded_flags & 1) == 0) {
  ------------------
  |  Branch (10182:9): [True: 18.6k, False: 354]
  ------------------
10183|  18.6k|      if ((decoded_flags & 2) != 0) {
  ------------------
  |  Branch (10183:11): [True: 131, False: 18.5k]
  ------------------
10184|    131|        unicode::to_lower_ascii(decoded.data(), decoded.size());
10185|    131|      }
10186|  18.6k|      if (decoded.find('-') == std::string_view::npos ||
  ------------------
  |  Branch (10186:11): [True: 18.6k, False: 53]
  ------------------
10187|  18.6k|          decoded.find(xn_dash) == std::string_view::npos) {
  ------------------
  |  Branch (10187:11): [True: 21, False: 32]
  ------------------
10188|  18.6k|        host = std::move(decoded);
10189|  18.6k|        if (checkers::is_ipv4(*host)) {
  ------------------
  |  Branch (10189:13): [True: 18.4k, False: 204]
  ------------------
10190|  18.4k|          return parse_ipv4(*host);
10191|  18.4k|        }
10192|    204|        is_valid = true;
10193|    204|        return true;
10194|  18.6k|      }
10195|  18.6k|    }
10196|  19.0k|  }
10197|  62.4k|  ada_log("parse_host calling to_ascii");
10198|  62.4k|  is_valid = ada::unicode::to_ascii(host, input, input.find('%'));
10199|  62.4k|  if (!is_valid || !host.has_value()) {
  ------------------
  |  Branch (10199:7): [True: 1.59k, False: 60.8k]
  |  Branch (10199:20): [True: 0, False: 60.8k]
  ------------------
10200|  1.59k|    ada_log("parse_host to_ascii returns false");
10201|  1.59k|    return is_valid = false;
10202|  1.59k|  }
10203|  60.8k|  ada_log("parse_host to_ascii succeeded ", *host, " [", host->size(),
10204|  60.8k|          " bytes]");
10205|       |
10206|  60.8k|  if (std::any_of(host->begin(), host->end(),
  ------------------
  |  Branch (10206:7): [True: 0, False: 60.8k]
  ------------------
10207|  60.8k|                  ada::unicode::is_forbidden_domain_code_point)) {
10208|      0|    host = std::nullopt;
10209|      0|    return is_valid = false;
10210|      0|  }
10211|       |
10212|       |  // If asciiDomain ends in a number, then return the result of IPv4 parsing
10213|       |  // asciiDomain.
10214|  60.8k|  if (checkers::is_ipv4(*host)) {
  ------------------
  |  Branch (10214:7): [True: 126, False: 60.6k]
  ------------------
10215|    126|    ada_log("parse_host got ipv4 ", *host);
10216|    126|    return parse_ipv4(*host);
10217|    126|  }
10218|       |
10219|  60.6k|  return true;
10220|  60.8k|}
_ZN3ada7unicode45contains_forbidden_domain_code_point_or_upperEPKcm:
 7049|   344k|                                              size_t length) noexcept {
 7050|   344k|  size_t i = 0;
 7051|   344k|  uint8_t accumulator{};
 7052|  1.36M|  for (; i + 4 <= length; i += 4) {
  ------------------
  |  Branch (7052:10): [True: 1.02M, False: 344k]
  ------------------
 7053|  1.02M|    accumulator |=
 7054|  1.02M|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i])];
 7055|  1.02M|    accumulator |=
 7056|  1.02M|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 1])];
 7057|  1.02M|    accumulator |=
 7058|  1.02M|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 2])];
 7059|  1.02M|    accumulator |=
 7060|  1.02M|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 3])];
 7061|  1.02M|  }
 7062|   930k|  for (; i < length; i++) {
  ------------------
  |  Branch (7062:10): [True: 586k, False: 344k]
  ------------------
 7063|   586k|    accumulator |=
 7064|   586k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i])];
 7065|   586k|  }
 7066|   344k|  return accumulator;
 7067|   344k|}
_ZN3ada7unicode30is_forbidden_domain_code_pointEc:
 7008|  2.25M|    const char c) noexcept {
 7009|  2.25M|  return is_forbidden_domain_code_point_table[uint8_t(c)];
 7010|  2.25M|}
_ZZN3ada6parser14parse_url_implINS_14url_aggregatorELb1EEET_NSt3__117basic_string_viewIcNS4_11char_traitsIcEEEEPKS3_ENKUlvE_clEv:
12545|   240k|  const auto enforce_max_input_length = [&]() {
12546|   240k|    if constexpr (store_values) {
12547|   240k|      if (url.is_valid) {
  ------------------
  |  Branch (12547:11): [True: 240k, False: 0]
  ------------------
12548|   240k|        if constexpr (result_type_is_ada_url_aggregator) {
12549|   240k|          if (url.buffer.size() > max_input_length) [[unlikely]] {
  ------------------
  |  Branch (12549:15): [True: 0, False: 240k]
  ------------------
12550|      0|            url.is_valid = false;
12551|      0|          }
12552|       |        } else {
12553|       |          if (url.get_href_size() > max_input_length) [[unlikely]] {
12554|       |            url.is_valid = false;
12555|       |          }
12556|       |        }
12557|   240k|      }
12558|   240k|    }
12559|   240k|  };
simple_absolute.cc:_ZN3ada6parser12_GLOBAL__N_124port_decimal_digit_countEj:
10875|   116k|ada_really_inline uint32_t port_decimal_digit_count(uint32_t port) noexcept {
10876|   116k|  uint32_t digits = 1;
10877|   351k|  while (port >= 10) {
  ------------------
  |  Branch (10877:10): [True: 234k, False: 116k]
  ------------------
10878|   234k|    port /= 10;
10879|   234k|    ++digits;
10880|   234k|  }
10881|   116k|  return digits;
10882|   116k|}
simple_absolute.cc:_ZN3ada6parser12_GLOBAL__N_121append_canonical_portERNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEj:
10885|  10.5k|                                             uint32_t port) {
10886|  10.5k|  buffer += ':';
10887|  10.5k|  char port_buf[5];
10888|  10.5k|  auto [ptr, ec] = std::to_chars(port_buf, port_buf + 5, port);
10889|  10.5k|  (void)ec;
10890|  10.5k|  buffer.append(port_buf, static_cast<size_t>(ptr - port_buf));
10891|  10.5k|}
simple_absolute.cc:_ZN3ada6parser12_GLOBAL__N_116authority_has_atEPKhmm:
11033|  1.20M|                                        size_t n) noexcept {
11034|  1.20M|  const size_t rem = n - host_start;
11035|  1.20M|  if (rem == 0) {
  ------------------
  |  Branch (11035:7): [True: 0, False: 1.20M]
  ------------------
11036|      0|    return false;
11037|      0|  }
11038|       |#if ADA_NEON
11039|       |  if (rem >= 16) {
11040|       |    const uint8x16_t w = vld1q_u8(p + host_start);
11041|       |    const uint64_t at = neon_nibble_bits(vceqq_u8(w, vdupq_n_u8('@')));
11042|       |    if (at == 0) {
11043|       |      return false;
11044|       |    }
11045|       |    const uint64_t delim = neon_nibble_bits(vceqq_u8(w, vdupq_n_u8('/'))) |
11046|       |                           neon_nibble_bits(vceqq_u8(w, vdupq_n_u8('?'))) |
11047|       |                           neon_nibble_bits(vceqq_u8(w, vdupq_n_u8('#')));
11048|       |    return delim == 0 || std::countr_zero(at) < std::countr_zero(delim);
11049|       |  }
11050|       |#elif ADA_SSE2
11051|  1.20M|  if (rem >= 16) {
  ------------------
  |  Branch (11051:7): [True: 652k, False: 549k]
  ------------------
11052|   652k|    const __m128i w =
11053|   652k|        _mm_loadu_si128(reinterpret_cast<const __m128i*>(p + host_start));
11054|   652k|    const uint16_t at = static_cast<uint16_t>(
11055|   652k|        _mm_movemask_epi8(_mm_cmpeq_epi8(w, _mm_set1_epi8('@'))));
11056|   652k|    if (at == 0) {
  ------------------
  |  Branch (11056:9): [True: 594k, False: 58.6k]
  ------------------
11057|   594k|      return false;
11058|   594k|    }
11059|  58.6k|    const uint16_t delim = static_cast<uint16_t>(
11060|  58.6k|        _mm_movemask_epi8(_mm_cmpeq_epi8(w, _mm_set1_epi8('/'))) |
11061|  58.6k|        _mm_movemask_epi8(_mm_cmpeq_epi8(w, _mm_set1_epi8('?'))) |
11062|  58.6k|        _mm_movemask_epi8(_mm_cmpeq_epi8(w, _mm_set1_epi8('#'))));
11063|  58.6k|    return delim == 0 || std::countr_zero(at) < std::countr_zero(delim);
  ------------------
  |  Branch (11063:12): [True: 58.1k, False: 504]
  |  Branch (11063:26): [True: 138, False: 366]
  ------------------
11064|   652k|  }
11065|   549k|#endif
11066|   549k|  const size_t lim = host_start + rem;
11067|  5.79M|  for (size_t i = host_start; i < lim; ++i) {
  ------------------
  |  Branch (11067:31): [True: 5.73M, False: 59.3k]
  ------------------
11068|  5.73M|    const uint8_t c = p[i];
11069|  5.73M|    if (c == '@') {
  ------------------
  |  Branch (11069:9): [True: 18.7k, False: 5.72M]
  ------------------
11070|  18.7k|      return true;
11071|  18.7k|    }
11072|  5.72M|    if (c == '/' || c == '?' || c == '#') {
  ------------------
  |  Branch (11072:9): [True: 452k, False: 5.26M]
  |  Branch (11072:21): [True: 18.8k, False: 5.24M]
  |  Branch (11072:33): [True: 326, False: 5.24M]
  ------------------
11073|   471k|      return false;
11074|   471k|    }
11075|  5.72M|  }
11076|  59.3k|  return false;
11077|   549k|}
simple_absolute.cc:_ZN3ada6parser12_GLOBAL__N_115scan_plain_hostEPKhmmRmRbS5_:
11084|   847k|                                     bool& has_x) noexcept {
11085|   847k|  has_upper = false;
11086|   847k|  has_x = false;
11087|   847k|  size_t i = start;
11088|   847k|#if ADA_PARSER_SSSE3
11089|   847k|  if (len - start >= 16) {
  ------------------
  |  Branch (11089:7): [True: 542k, False: 305k]
  ------------------
11090|   542k|    const __m128i lo_tbl = nibble_load(k_host_nibbles.low);
11091|   542k|    const __m128i hi_tbl = nibble_load(k_host_nibbles.high);
11092|   542k|    const __m128i x_splat = _mm_set1_epi8('x');
11093|   542k|    auto visit = [&](size_t at) noexcept -> bool {
11094|   542k|      const __m128i w =
11095|   542k|          _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + at));
11096|   542k|      const int up = sse2_uppercase(w);
11097|   542k|      const int xs = _mm_movemask_epi8(_mm_cmpeq_epi8(w, x_splat));
11098|   542k|      const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl);
11099|   542k|      if (mask == 0) {
11100|   542k|        if (up != 0) {
11101|   542k|          has_upper = true;
11102|   542k|        }
11103|   542k|        if (xs != 0) {
11104|   542k|          has_x = true;
11105|   542k|        }
11106|   542k|        return false;
11107|   542k|      }
11108|   542k|      const int hit = trailing_zeroes32(static_cast<uint32_t>(mask));
11109|   542k|      const int valid = (1 << hit) - 1;
11110|   542k|      if ((up & valid) != 0) {
11111|   542k|        has_upper = true;
11112|   542k|      }
11113|   542k|      if ((xs & valid) != 0) {
11114|   542k|        has_x = true;
11115|   542k|      }
11116|   542k|      end = at + static_cast<size_t>(hit);
11117|   542k|      return true;
11118|   542k|    };
11119|   561k|    for (; i + 32 <= len; i += 32) {
  ------------------
  |  Branch (11119:12): [True: 90.4k, False: 470k]
  ------------------
11120|  90.4k|      if (visit(i) || visit(i + 16)) {
  ------------------
  |  Branch (11120:11): [True: 69.7k, False: 20.6k]
  |  Branch (11120:23): [True: 1.53k, False: 19.1k]
  ------------------
11121|  71.3k|        return k_host_class[b[end]] == 1;
11122|  71.3k|      }
11123|  90.4k|    }
11124|   528k|    for (; i + 16 <= len; i += 16) {
  ------------------
  |  Branch (11124:12): [True: 470k, False: 58.0k]
  ------------------
11125|   470k|      if (visit(i)) {
  ------------------
  |  Branch (11125:11): [True: 412k, False: 57.2k]
  ------------------
11126|   412k|        return k_host_class[b[end]] == 1;
11127|   412k|      }
11128|   470k|    }
11129|       |    // Overlapping tail only after a full 16-byte step so the window cannot
11130|       |    // start before `start` (a prior '/' would otherwise look like a host stop).
11131|  58.0k|    if (i > start && i < len) {
  ------------------
  |  Branch (11131:9): [True: 58.0k, False: 0]
  |  Branch (11131:22): [True: 57.9k, False: 34]
  ------------------
11132|  57.9k|      if (visit(len - 16) && end >= i) {
  ------------------
  |  Branch (11132:11): [True: 57.8k, False: 116]
  |  Branch (11132:30): [True: 57.8k, False: 0]
  ------------------
11133|  57.8k|        return k_host_class[b[end]] == 1;
11134|  57.8k|      }
11135|    116|      end = len;
11136|    116|      return true;
11137|  57.9k|    }
11138|  58.0k|  }
11139|       |#elif ADA_SSE2
11140|       |  const __m128i x_splat = _mm_set1_epi8('x');
11141|       |  for (; i + 32 <= len; i += 32) {
11142|       |    for (size_t off = 0; off < 32; off += 16) {
11143|       |      const __m128i w =
11144|       |          _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i + off));
11145|       |      const int up = sse2_uppercase(w);
11146|       |      const int xs = _mm_movemask_epi8(_mm_cmpeq_epi8(w, x_splat));
11147|       |      const int mask = sse2_host_stop(w);
11148|       |      if (mask != 0) {
11149|       |        const int hit = trailing_zeroes32(static_cast<uint32_t>(mask));
11150|       |        const int valid = (1 << hit) - 1;
11151|       |        if ((up & valid) != 0) {
11152|       |          has_upper = true;
11153|       |        }
11154|       |        if ((xs & valid) != 0) {
11155|       |          has_x = true;
11156|       |        }
11157|       |        end = i + off + static_cast<size_t>(hit);
11158|       |        return k_host_class[b[end]] == 1;
11159|       |      }
11160|       |      if (up != 0) {
11161|       |        has_upper = true;
11162|       |      }
11163|       |      if (xs != 0) {
11164|       |        has_x = true;
11165|       |      }
11166|       |    }
11167|       |  }
11168|       |  for (; i + 16 <= len; i += 16) {
11169|       |    const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i));
11170|       |    const int up = sse2_uppercase(w);
11171|       |    const int xs = _mm_movemask_epi8(_mm_cmpeq_epi8(w, x_splat));
11172|       |    const int mask = sse2_host_stop(w);
11173|       |    if (mask != 0) {
11174|       |      const int hit = trailing_zeroes32(static_cast<uint32_t>(mask));
11175|       |      const int valid = (1 << hit) - 1;
11176|       |      if ((up & valid) != 0) {
11177|       |        has_upper = true;
11178|       |      }
11179|       |      if ((xs & valid) != 0) {
11180|       |        has_x = true;
11181|       |      }
11182|       |      end = i + static_cast<size_t>(hit);
11183|       |      return k_host_class[b[end]] == 1;
11184|       |    }
11185|       |    if (up != 0) {
11186|       |      has_upper = true;
11187|       |    }
11188|       |    if (xs != 0) {
11189|       |      has_x = true;
11190|       |    }
11191|       |  }
11192|       |#elif ADA_NEON
11193|       |  if (len - start >= 16) {
11194|       |    const uint8x16_t lo_tbl = vld1q_u8(k_host_nibbles.low);
11195|       |    const uint8x16_t hi_tbl = vld1q_u8(k_host_nibbles.high);
11196|       |    const uint8x16_t x_splat = vdupq_n_u8('x');
11197|       |    auto visit = [&](size_t at) noexcept -> bool {
11198|       |      const uint8x16_t w = vld1q_u8(b + at);
11199|       |      const uint64_t up = neon_uppercase(w);
11200|       |      const uint64_t xs = neon_nibble_bits(vceqq_u8(w, x_splat));
11201|       |      const uint64_t bits = neon_table_stop(w, lo_tbl, hi_tbl);
11202|       |      if (bits == 0) {
11203|       |        if (up != 0) {
11204|       |          has_upper = true;
11205|       |        }
11206|       |        if (xs != 0) {
11207|       |          has_x = true;
11208|       |        }
11209|       |        return false;
11210|       |      }
11211|       |      const size_t hit = static_cast<size_t>(trailing_zeroes64(bits)) >> 2;
11212|       |      const uint64_t valid = (hit == 0) ? 0 : (uint64_t{1} << (hit * 4)) - 1;
11213|       |      if ((up & valid) != 0) {
11214|       |        has_upper = true;
11215|       |      }
11216|       |      if ((xs & valid) != 0) {
11217|       |        has_x = true;
11218|       |      }
11219|       |      end = at + hit;
11220|       |      return true;
11221|       |    };
11222|       |    for (; i + 32 <= len; i += 32) {
11223|       |      if (visit(i) || visit(i + 16)) {
11224|       |        return k_host_class[b[end]] == 1;
11225|       |      }
11226|       |    }
11227|       |    for (; i + 16 <= len; i += 16) {
11228|       |      if (visit(i)) {
11229|       |        return k_host_class[b[end]] == 1;
11230|       |      }
11231|       |    }
11232|       |    if (i > start && i < len) {
11233|       |      if (visit(len - 16) && end >= i) {
11234|       |        return k_host_class[b[end]] == 1;
11235|       |      }
11236|       |      end = len;
11237|       |      return true;
11238|       |    }
11239|       |  }
11240|       |#endif
11241|  3.28M|  for (; i < len; ++i) {
  ------------------
  |  Branch (11241:10): [True: 3.26M, False: 18.6k]
  ------------------
11242|  3.26M|    const uint8_t c = b[i];
11243|  3.26M|    const uint8_t cls = k_host_class[c];
11244|  3.26M|    if (cls == 1) {
  ------------------
  |  Branch (11244:9): [True: 284k, False: 2.97M]
  ------------------
11245|   284k|      end = i;
11246|   284k|      return true;
11247|   284k|    }
11248|  2.97M|    if (cls == 2) {
  ------------------
  |  Branch (11248:9): [True: 2.54k, False: 2.97M]
  ------------------
11249|  2.54k|      return false;
11250|  2.54k|    }
11251|  2.97M|    if (c >= 'A' && c <= 'Z') {
  ------------------
  |  Branch (11251:9): [True: 2.57M, False: 398k]
  |  Branch (11251:21): [True: 726, False: 2.57M]
  ------------------
11252|    726|      has_upper = true;
11253|  2.97M|    } else if (c == 'x') {
  ------------------
  |  Branch (11253:16): [True: 316k, False: 2.65M]
  ------------------
11254|   316k|      has_x = true;
11255|   316k|    }
11256|  2.97M|  }
11257|  18.6k|  end = len;
11258|  18.6k|  return true;
11259|   305k|}
simple_absolute.cc:_ZN3ada6parser12_GLOBAL__N_111nibble_loadEPKh:
10914|  1.23M|ADA_PARSER_SIMD __m128i nibble_load(const uint8_t* t) noexcept {
10915|  1.23M|  return _mm_load_si128(reinterpret_cast<const __m128i*>(t));
10916|  1.23M|}
simple_absolute.cc:_ZZN3ada6parser12_GLOBAL__N_115scan_plain_hostEPKhmmRmRbS5_ENK3$_0clEm:
11093|   639k|    auto visit = [&](size_t at) noexcept -> bool {
11094|   639k|      const __m128i w =
11095|   639k|          _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + at));
11096|   639k|      const int up = sse2_uppercase(w);
11097|   639k|      const int xs = _mm_movemask_epi8(_mm_cmpeq_epi8(w, x_splat));
11098|   639k|      const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl);
11099|   639k|      if (mask == 0) {
  ------------------
  |  Branch (11099:11): [True: 97.2k, False: 542k]
  ------------------
11100|  97.2k|        if (up != 0) {
  ------------------
  |  Branch (11100:13): [True: 1.20k, False: 95.9k]
  ------------------
11101|  1.20k|          has_upper = true;
11102|  1.20k|        }
11103|  97.2k|        if (xs != 0) {
  ------------------
  |  Branch (11103:13): [True: 92.9k, False: 4.27k]
  ------------------
11104|  92.9k|          has_x = true;
11105|  92.9k|        }
11106|  97.2k|        return false;
11107|  97.2k|      }
11108|   542k|      const int hit = trailing_zeroes32(static_cast<uint32_t>(mask));
11109|   542k|      const int valid = (1 << hit) - 1;
11110|   542k|      if ((up & valid) != 0) {
  ------------------
  |  Branch (11110:11): [True: 19.4k, False: 522k]
  ------------------
11111|  19.4k|        has_upper = true;
11112|  19.4k|      }
11113|   542k|      if ((xs & valid) != 0) {
  ------------------
  |  Branch (11113:11): [True: 472k, False: 69.6k]
  ------------------
11114|   472k|        has_x = true;
11115|   472k|      }
11116|   542k|      end = at + static_cast<size_t>(hit);
11117|   542k|      return true;
11118|   639k|    };
simple_absolute.cc:_ZN3ada6parser12_GLOBAL__N_114sse2_uppercaseEDv2_x:
11001|   639k|ada_really_inline int sse2_uppercase(__m128i w) noexcept {
11002|   639k|  return _mm_movemask_epi8(_mm_and_si128(
11003|   639k|      _mm_cmpgt_epi8(w, _mm_set1_epi8(static_cast<char>('A' - 1))),
11004|   639k|      _mm_cmplt_epi8(w, _mm_set1_epi8(static_cast<char>('Z' + 1)))));
11005|   639k|}
simple_absolute.cc:_ZN3ada6parser12_GLOBAL__N_117ssse3_nibble_maskEDv2_xS2_S2_:
10921|   745k|                                      __m128i hi_tbl) noexcept {
10922|   745k|  const __m128i nibble = _mm_set1_epi8(0x0F);
10923|   745k|  const __m128i lo = _mm_and_si128(w, nibble);
10924|   745k|  const __m128i hi = _mm_and_si128(_mm_srli_epi16(w, 4), nibble);
10925|   745k|  const __m128i hit =
10926|   745k|      _mm_and_si128(_mm_shuffle_epi8(lo_tbl, lo), _mm_shuffle_epi8(hi_tbl, hi));
10927|   745k|  return _mm_movemask_epi8(_mm_cmpeq_epi8(hit, _mm_setzero_si128())) ^ 0xFFFF;
10928|   745k|}
simple_absolute.cc:_ZN3ada6parser12_GLOBAL__N_117trailing_zeroes32Ej:
10893|   612k|ada_really_inline int trailing_zeroes32(uint32_t input_num) noexcept {
10894|       |#ifdef ADA_REGULAR_VISUAL_STUDIO
10895|       |  unsigned long ret;
10896|       |  _BitScanForward(&ret, input_num);
10897|       |  return static_cast<int>(ret);
10898|       |#else
10899|   612k|  return __builtin_ctz(input_num);
10900|   612k|#endif
10901|   612k|}
simple_absolute.cc:_ZN3ada6parser12_GLOBAL__N_113scan_path_runEPKhRmmRb:
11319|   630k|                                   bool& maybe_dot_segment) noexcept {
11320|   630k|  const size_t run_start = i;
11321|   630k|#if ADA_PARSER_SSSE3
11322|   630k|  if (i + 16 <= len) {
  ------------------
  |  Branch (11322:7): [True: 67.8k, False: 562k]
  ------------------
11323|  67.8k|    const __m128i lo_tbl = nibble_load(k_path_nibbles.low);
11324|  67.8k|    const __m128i hi_tbl = nibble_load(k_path_nibbles.high);
11325|  72.4k|    for (; i + 32 <= len; i += 32) {
  ------------------
  |  Branch (11325:12): [True: 11.8k, False: 60.5k]
  ------------------
11326|  11.8k|      const __m128i w0 =
11327|  11.8k|          _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i));
11328|  11.8k|      const int m0 = ssse3_nibble_mask(w0, lo_tbl, hi_tbl);
11329|  11.8k|      if (m0 != 0) {
  ------------------
  |  Branch (11329:11): [True: 6.64k, False: 5.23k]
  ------------------
11330|  6.64k|        const int hit_bit = trailing_zeroes32(static_cast<uint32_t>(m0));
11331|  6.64k|        note_dots_in_window(b, i, run_start, w0, (1 << hit_bit) - 1,
11332|  6.64k|                            maybe_dot_segment);
11333|  6.64k|        i += static_cast<size_t>(hit_bit);
11334|  6.64k|        return;
11335|  6.64k|      }
11336|  5.23k|      note_dots_in_window(b, i, run_start, w0, 0xFFFF, maybe_dot_segment);
11337|  5.23k|      const __m128i w1 =
11338|  5.23k|          _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i + 16));
11339|  5.23k|      const int m1 = ssse3_nibble_mask(w1, lo_tbl, hi_tbl);
11340|  5.23k|      if (m1 != 0) {
  ------------------
  |  Branch (11340:11): [True: 650, False: 4.58k]
  ------------------
11341|    650|        const int hit_bit = trailing_zeroes32(static_cast<uint32_t>(m1));
11342|    650|        note_dots_in_window(b, i + 16, run_start, w1, (1 << hit_bit) - 1,
11343|    650|                            maybe_dot_segment);
11344|    650|        i += 16 + static_cast<size_t>(hit_bit);
11345|    650|        return;
11346|    650|      }
11347|  4.58k|      note_dots_in_window(b, i + 16, run_start, w1, 0xFFFF, maybe_dot_segment);
11348|  4.58k|    }
11349|  61.6k|    for (; i + 16 <= len; i += 16) {
  ------------------
  |  Branch (11349:12): [True: 59.9k, False: 1.67k]
  ------------------
11350|  59.9k|      const __m128i w =
11351|  59.9k|          _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i));
11352|  59.9k|      const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl);
11353|  59.9k|      if (mask != 0) {
  ------------------
  |  Branch (11353:11): [True: 58.8k, False: 1.10k]
  ------------------
11354|  58.8k|        const int hit_bit = trailing_zeroes32(static_cast<uint32_t>(mask));
11355|  58.8k|        note_dots_in_window(b, i, run_start, w, (1 << hit_bit) - 1,
11356|  58.8k|                            maybe_dot_segment);
11357|  58.8k|        i += static_cast<size_t>(hit_bit);
11358|  58.8k|        return;
11359|  58.8k|      }
11360|  1.10k|      note_dots_in_window(b, i, run_start, w, 0xFFFF, maybe_dot_segment);
11361|  1.10k|    }
11362|  1.67k|    if (i > run_start && i < len) {
  ------------------
  |  Branch (11362:9): [True: 1.67k, False: 0]
  |  Branch (11362:26): [True: 1.34k, False: 330]
  ------------------
11363|  1.34k|      const __m128i w =
11364|  1.34k|          _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + len - 16));
11365|  1.34k|      const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl);
11366|  1.34k|      if (mask != 0) {
  ------------------
  |  Branch (11366:11): [True: 594, False: 752]
  ------------------
11367|    594|        const size_t hit =
11368|    594|            len - 16 +
11369|    594|            static_cast<size_t>(trailing_zeroes32(static_cast<uint32_t>(mask)));
11370|    594|        if (hit >= i) {
  ------------------
  |  Branch (11370:13): [True: 594, False: 0]
  ------------------
11371|  3.09k|          for (size_t j = i; j < hit; ++j) {
  ------------------
  |  Branch (11371:30): [True: 2.50k, False: 594]
  ------------------
11372|  2.50k|            if (b[j] == '.') {
  ------------------
  |  Branch (11372:17): [True: 508, False: 1.99k]
  ------------------
11373|    508|              note_possible_dot_segment(b, j, run_start, maybe_dot_segment);
11374|    508|            }
11375|  2.50k|          }
11376|    594|          i = hit;
11377|    594|          return;
11378|    594|        }
11379|    594|      }
11380|  6.22k|      for (size_t j = i; j < len; ++j) {
  ------------------
  |  Branch (11380:26): [True: 5.47k, False: 752]
  ------------------
11381|  5.47k|        if (b[j] == '.') {
  ------------------
  |  Branch (11381:13): [True: 1.36k, False: 4.11k]
  ------------------
11382|  1.36k|          note_possible_dot_segment(b, j, run_start, maybe_dot_segment);
11383|  1.36k|        }
11384|  5.47k|      }
11385|    752|      i = len;
11386|    752|      return;
11387|  1.34k|    }
11388|  1.67k|  }
11389|       |#elif ADA_SSE2
11390|       |  for (; i + 16 <= len; i += 16) {
11391|       |    const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i));
11392|       |    const int mask = sse2_path_stop(w);
11393|       |    if (mask != 0) {
11394|       |      const int hit_bit = trailing_zeroes32(static_cast<uint32_t>(mask));
11395|       |      note_dots_in_window(b, i, run_start, w, (1 << hit_bit) - 1,
11396|       |                          maybe_dot_segment);
11397|       |      i += static_cast<size_t>(hit_bit);
11398|       |      return;
11399|       |    }
11400|       |    note_dots_in_window(b, i, run_start, w, 0xFFFF, maybe_dot_segment);
11401|       |  }
11402|       |#elif ADA_NEON
11403|       |  if (i + 16 <= len) {
11404|       |    const uint8x16_t lo_tbl = vld1q_u8(k_path_nibbles.low);
11405|       |    const uint8x16_t hi_tbl = vld1q_u8(k_path_nibbles.high);
11406|       |    for (; i + 32 <= len; i += 32) {
11407|       |      const uint8x16_t w0 = vld1q_u8(b + i);
11408|       |      const uint64_t bits0 = neon_table_stop(w0, lo_tbl, hi_tbl);
11409|       |      if (bits0 != 0) {
11410|       |        const size_t hit_off =
11411|       |            static_cast<size_t>(trailing_zeroes64(bits0)) >> 2;
11412|       |        const uint64_t valid =
11413|       |            (hit_off == 0) ? 0 : (uint64_t{1} << (hit_off * 4)) - 1;
11414|       |        note_dots_in_window_neon(b, i, run_start, w0, valid, maybe_dot_segment);
11415|       |        i += hit_off;
11416|       |        return;
11417|       |      }
11418|       |      note_dots_in_window_neon(b, i, run_start, w0, ~uint64_t{0},
11419|       |                               maybe_dot_segment);
11420|       |      const uint8x16_t w1 = vld1q_u8(b + i + 16);
11421|       |      const uint64_t bits1 = neon_table_stop(w1, lo_tbl, hi_tbl);
11422|       |      if (bits1 != 0) {
11423|       |        const size_t hit_off =
11424|       |            static_cast<size_t>(trailing_zeroes64(bits1)) >> 2;
11425|       |        const uint64_t valid =
11426|       |            (hit_off == 0) ? 0 : (uint64_t{1} << (hit_off * 4)) - 1;
11427|       |        note_dots_in_window_neon(b, i + 16, run_start, w1, valid,
11428|       |                                 maybe_dot_segment);
11429|       |        i += 16 + hit_off;
11430|       |        return;
11431|       |      }
11432|       |      note_dots_in_window_neon(b, i + 16, run_start, w1, ~uint64_t{0},
11433|       |                               maybe_dot_segment);
11434|       |    }
11435|       |    for (; i + 16 <= len; i += 16) {
11436|       |      const uint8x16_t w = vld1q_u8(b + i);
11437|       |      const uint64_t bits = neon_table_stop(w, lo_tbl, hi_tbl);
11438|       |      if (bits != 0) {
11439|       |        const size_t hit_off =
11440|       |            static_cast<size_t>(trailing_zeroes64(bits)) >> 2;
11441|       |        const uint64_t valid =
11442|       |            (hit_off == 0) ? 0 : (uint64_t{1} << (hit_off * 4)) - 1;
11443|       |        note_dots_in_window_neon(b, i, run_start, w, valid, maybe_dot_segment);
11444|       |        i += hit_off;
11445|       |        return;
11446|       |      }
11447|       |      note_dots_in_window_neon(b, i, run_start, w, ~uint64_t{0},
11448|       |                               maybe_dot_segment);
11449|       |    }
11450|       |    if (i > run_start && i < len) {
11451|       |      const uint8x16_t w = vld1q_u8(b + len - 16);
11452|       |      const uint64_t bits = neon_table_stop(w, lo_tbl, hi_tbl);
11453|       |      if (bits != 0) {
11454|       |        const size_t hit =
11455|       |            len - 16 + (static_cast<size_t>(trailing_zeroes64(bits)) >> 2);
11456|       |        if (hit >= i) {
11457|       |          for (size_t j = i; j < hit; ++j) {
11458|       |            if (b[j] == '.') {
11459|       |              note_possible_dot_segment(b, j, run_start, maybe_dot_segment);
11460|       |            }
11461|       |          }
11462|       |          i = hit;
11463|       |          return;
11464|       |        }
11465|       |      }
11466|       |      for (size_t j = i; j < len; ++j) {
11467|       |        if (b[j] == '.') {
11468|       |          note_possible_dot_segment(b, j, run_start, maybe_dot_segment);
11469|       |        }
11470|       |      }
11471|       |      i = len;
11472|       |      return;
11473|       |    }
11474|       |  }
11475|       |#endif
11476|  2.10M|  for (; i < len; ++i) {
  ------------------
  |  Branch (11476:10): [True: 1.69M, False: 408k]
  ------------------
11477|  1.69M|    const uint8_t c = b[i];
11478|  1.69M|    const uint8_t cls = k_path[c];
11479|  1.69M|    if (cls != 0) {
  ------------------
  |  Branch (11479:9): [True: 154k, False: 1.54M]
  ------------------
11480|   154k|      return;
11481|   154k|    }
11482|  1.54M|    if (c == '.') {
  ------------------
  |  Branch (11482:9): [True: 167k, False: 1.37M]
  ------------------
11483|   167k|      note_possible_dot_segment(b, i, run_start, maybe_dot_segment);
11484|   167k|    }
11485|  1.54M|  }
11486|   562k|}
simple_absolute.cc:_ZN3ada6parser12_GLOBAL__N_119note_dots_in_windowEPKhmmDv2_xiRb:
11276|  77.1k|                                           bool& maybe_dot_segment) noexcept {
11277|  77.1k|  if (maybe_dot_segment || valid_mask == 0) {
  ------------------
  |  Branch (11277:7): [True: 4.80k, False: 72.2k]
  |  Branch (11277:28): [True: 4.45k, False: 67.8k]
  ------------------
11278|  9.26k|    return;
11279|  9.26k|  }
11280|  67.8k|  const int dots =
11281|  67.8k|      _mm_movemask_epi8(_mm_cmpeq_epi8(w, _mm_set1_epi8('.'))) & valid_mask;
11282|  67.8k|  if (dots == 0) {
  ------------------
  |  Branch (11282:7): [True: 62.8k, False: 4.99k]
  ------------------
11283|  62.8k|    return;
11284|  62.8k|  }
11285|  4.99k|  const int slashes =
11286|  4.99k|      _mm_movemask_epi8(_mm_cmpeq_epi8(w, _mm_set1_epi8('/'))) & valid_mask;
11287|  4.99k|  if (((dots & 1) != 0 && (i == run_start || b[i - 1] == '/')) ||
  ------------------
  |  Branch (11287:8): [True: 1.70k, False: 3.28k]
  |  Branch (11287:28): [True: 920, False: 784]
  |  Branch (11287:46): [True: 102, False: 682]
  ------------------
11288|  3.97k|      (dots & (slashes << 1)) != 0) {
  ------------------
  |  Branch (11288:7): [True: 1.13k, False: 2.83k]
  ------------------
11289|  2.15k|    maybe_dot_segment = true;
11290|  2.15k|  }
11291|  4.99k|}
simple_absolute.cc:_ZN3ada6parser12_GLOBAL__N_125note_possible_dot_segmentEPKhmmRb:
11263|   168k|    bool& maybe_dot_segment) noexcept {
11264|   168k|  if (pos == run_start || b[pos - 1] == '/') {
  ------------------
  |  Branch (11264:7): [True: 556, False: 168k]
  |  Branch (11264:27): [True: 38.1k, False: 130k]
  ------------------
11265|  38.7k|    maybe_dot_segment = true;
11266|  38.7k|  }
11267|   168k|}
simple_absolute.cc:_ZN3ada6parser12_GLOBAL__N_114scan_query_runEPKhRmm:
11629|   175k|                                    size_t len) noexcept {
11630|   175k|  ADA_SCAN_STOP_RUN(k_query_nibbles, k_query, sse2_query_stop);
  ------------------
  |  |11492|   175k|  do {                                                                       \
  |  |11493|   175k|    const size_t scan_start = i;                                             \
  |  |11494|   175k|    if (i + 16 <= len) {                                                     \
  |  |  ------------------
  |  |  |  Branch (11494:9): [True: 4.53k, False: 170k]
  |  |  ------------------
  |  |11495|  4.53k|      const __m128i lo_tbl = nibble_load((nibbles).low);                     \
  |  |11496|  4.53k|      const __m128i hi_tbl = nibble_load((nibbles).high);                    \
  |  |11497|  12.2k|      for (; i + 32 <= len; i += 32) {                                       \
  |  |  ------------------
  |  |  |  Branch (11497:14): [True: 8.17k, False: 4.04k]
  |  |  ------------------
  |  |11498|  8.17k|        const __m128i w0 =                                                   \
  |  |11499|  8.17k|            _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i));        \
  |  |11500|  8.17k|        const int m0 = ssse3_nibble_mask(w0, lo_tbl, hi_tbl);                \
  |  |11501|  8.17k|        if (m0 != 0) {                                                       \
  |  |  ------------------
  |  |  |  Branch (11501:13): [True: 300, False: 7.87k]
  |  |  ------------------
  |  |11502|    300|          i += static_cast<size_t>(                                          \
  |  |11503|    300|              trailing_zeroes32(static_cast<uint32_t>(m0)));                 \
  |  |11504|    300|          return;                                                            \
  |  |11505|    300|        }                                                                    \
  |  |11506|  8.17k|        const __m128i w1 =                                                   \
  |  |11507|  7.87k|            _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i + 16));   \
  |  |11508|  7.87k|        const int m1 = ssse3_nibble_mask(w1, lo_tbl, hi_tbl);                \
  |  |11509|  7.87k|        if (m1 != 0) {                                                       \
  |  |  ------------------
  |  |  |  Branch (11509:13): [True: 192, False: 7.68k]
  |  |  ------------------
  |  |11510|    192|          i += 16 + static_cast<size_t>(                                     \
  |  |11511|    192|                        trailing_zeroes32(static_cast<uint32_t>(m1)));       \
  |  |11512|    192|          return;                                                            \
  |  |11513|    192|        }                                                                    \
  |  |11514|  7.87k|      }                                                                      \
  |  |11515|  4.53k|      for (; i + 16 <= len; i += 16) {                                       \
  |  |  ------------------
  |  |  |  Branch (11515:14): [True: 1.34k, False: 3.01k]
  |  |  ------------------
  |  |11516|  1.34k|        const __m128i w =                                                    \
  |  |11517|  1.34k|            _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i));        \
  |  |11518|  1.34k|        const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl);               \
  |  |11519|  1.34k|        if (mask != 0) {                                                     \
  |  |  ------------------
  |  |  |  Branch (11519:13): [True: 1.02k, False: 314]
  |  |  ------------------
  |  |11520|  1.02k|          i += static_cast<size_t>(                                          \
  |  |11521|  1.02k|              trailing_zeroes32(static_cast<uint32_t>(mask)));               \
  |  |11522|  1.02k|          return;                                                            \
  |  |11523|  1.02k|        }                                                                    \
  |  |11524|  1.34k|      }                                                                      \
  |  |11525|  4.04k|      if (i > scan_start && i < len) {                                       \
  |  |  ------------------
  |  |  |  Branch (11525:11): [True: 3.01k, False: 0]
  |  |  |  Branch (11525:29): [True: 2.96k, False: 48]
  |  |  ------------------
  |  |11526|  2.96k|        const __m128i w =                                                    \
  |  |11527|  2.96k|            _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + len - 16)); \
  |  |11528|  2.96k|        const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl);               \
  |  |11529|  2.96k|        if (mask != 0) {                                                     \
  |  |  ------------------
  |  |  |  Branch (11529:13): [True: 2.14k, False: 818]
  |  |  ------------------
  |  |11530|  2.14k|          const size_t hit = len - 16 +                                      \
  |  |11531|  2.14k|                             static_cast<size_t>(trailing_zeroes32(          \
  |  |11532|  2.14k|                                 static_cast<uint32_t>(mask)));              \
  |  |11533|  2.14k|          if (hit >= i) {                                                    \
  |  |  ------------------
  |  |  |  Branch (11533:15): [True: 2.14k, False: 0]
  |  |  ------------------
  |  |11534|  2.14k|            i = hit;                                                         \
  |  |11535|  2.14k|            return;                                                          \
  |  |11536|  2.14k|          }                                                                  \
  |  |11537|  2.14k|        }                                                                    \
  |  |11538|  2.96k|        i = len;                                                             \
  |  |11539|    818|        return;                                                              \
  |  |11540|  2.96k|      }                                                                      \
  |  |11541|  3.01k|    }                                                                        \
  |  |11542|  1.18M|    for (; i < len; ++i) {                                                   \
  |  |  ------------------
  |  |  |  Branch (11542:12): [True: 1.07M, False: 111k]
  |  |  ------------------
  |  |11543|  1.07M|      if ((cls)[b[i]] != 0) {                                                \
  |  |  ------------------
  |  |  |  Branch (11543:11): [True: 58.6k, False: 1.01M]
  |  |  ------------------
  |  |11544|  58.6k|        return;                                                              \
  |  |11545|  58.6k|      }                                                                      \
  |  |11546|  1.07M|    }                                                                        \
  |  |11547|   170k|  } while (0)
  |  |  ------------------
  |  |  |  Branch (11547:12): [Folded, False: 111k]
  |  |  ------------------
  ------------------
11631|   175k|}
simple_absolute.cc:_ZN3ada6parser12_GLOBAL__N_113scan_hash_runEPKhRmm:
11634|   119k|                                   size_t len) noexcept {
11635|   119k|  ADA_SCAN_STOP_RUN(k_hash_nibbles, k_hash, sse2_hash_stop);
  ------------------
  |  |11492|   119k|  do {                                                                       \
  |  |11493|   119k|    const size_t scan_start = i;                                             \
  |  |11494|   119k|    if (i + 16 <= len) {                                                     \
  |  |  ------------------
  |  |  |  Branch (11494:9): [True: 902, False: 118k]
  |  |  ------------------
  |  |11495|    902|      const __m128i lo_tbl = nibble_load((nibbles).low);                     \
  |  |11496|    902|      const __m128i hi_tbl = nibble_load((nibbles).high);                    \
  |  |11497|  4.06k|      for (; i + 32 <= len; i += 32) {                                       \
  |  |  ------------------
  |  |  |  Branch (11497:14): [True: 3.30k, False: 758]
  |  |  ------------------
  |  |11498|  3.30k|        const __m128i w0 =                                                   \
  |  |11499|  3.30k|            _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i));        \
  |  |11500|  3.30k|        const int m0 = ssse3_nibble_mask(w0, lo_tbl, hi_tbl);                \
  |  |11501|  3.30k|        if (m0 != 0) {                                                       \
  |  |  ------------------
  |  |  |  Branch (11501:13): [True: 104, False: 3.19k]
  |  |  ------------------
  |  |11502|    104|          i += static_cast<size_t>(                                          \
  |  |11503|    104|              trailing_zeroes32(static_cast<uint32_t>(m0)));                 \
  |  |11504|    104|          return;                                                            \
  |  |11505|    104|        }                                                                    \
  |  |11506|  3.30k|        const __m128i w1 =                                                   \
  |  |11507|  3.19k|            _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i + 16));   \
  |  |11508|  3.19k|        const int m1 = ssse3_nibble_mask(w1, lo_tbl, hi_tbl);                \
  |  |11509|  3.19k|        if (m1 != 0) {                                                       \
  |  |  ------------------
  |  |  |  Branch (11509:13): [True: 40, False: 3.15k]
  |  |  ------------------
  |  |11510|     40|          i += 16 + static_cast<size_t>(                                     \
  |  |11511|     40|                        trailing_zeroes32(static_cast<uint32_t>(m1)));       \
  |  |11512|     40|          return;                                                            \
  |  |11513|     40|        }                                                                    \
  |  |11514|  3.19k|      }                                                                      \
  |  |11515|  1.21k|      for (; i + 16 <= len; i += 16) {                                       \
  |  |  ------------------
  |  |  |  Branch (11515:14): [True: 474, False: 738]
  |  |  ------------------
  |  |11516|    474|        const __m128i w =                                                    \
  |  |11517|    474|            _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + i));        \
  |  |11518|    474|        const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl);               \
  |  |11519|    474|        if (mask != 0) {                                                     \
  |  |  ------------------
  |  |  |  Branch (11519:13): [True: 20, False: 454]
  |  |  ------------------
  |  |11520|     20|          i += static_cast<size_t>(                                          \
  |  |11521|     20|              trailing_zeroes32(static_cast<uint32_t>(mask)));               \
  |  |11522|     20|          return;                                                            \
  |  |11523|     20|        }                                                                    \
  |  |11524|    474|      }                                                                      \
  |  |11525|    758|      if (i > scan_start && i < len) {                                       \
  |  |  ------------------
  |  |  |  Branch (11525:11): [True: 738, False: 0]
  |  |  |  Branch (11525:29): [True: 666, False: 72]
  |  |  ------------------
  |  |11526|    666|        const __m128i w =                                                    \
  |  |11527|    666|            _mm_loadu_si128(reinterpret_cast<const __m128i*>(b + len - 16)); \
  |  |11528|    666|        const int mask = ssse3_nibble_mask(w, lo_tbl, hi_tbl);               \
  |  |11529|    666|        if (mask != 0) {                                                     \
  |  |  ------------------
  |  |  |  Branch (11529:13): [True: 32, False: 634]
  |  |  ------------------
  |  |11530|     32|          const size_t hit = len - 16 +                                      \
  |  |11531|     32|                             static_cast<size_t>(trailing_zeroes32(          \
  |  |11532|     32|                                 static_cast<uint32_t>(mask)));              \
  |  |11533|     32|          if (hit >= i) {                                                    \
  |  |  ------------------
  |  |  |  Branch (11533:15): [True: 32, False: 0]
  |  |  ------------------
  |  |11534|     32|            i = hit;                                                         \
  |  |11535|     32|            return;                                                          \
  |  |11536|     32|          }                                                                  \
  |  |11537|     32|        }                                                                    \
  |  |11538|    666|        i = len;                                                             \
  |  |11539|    634|        return;                                                              \
  |  |11540|    666|      }                                                                      \
  |  |11541|    738|    }                                                                        \
  |  |11542|   581k|    for (; i < len; ++i) {                                                   \
  |  |  ------------------
  |  |  |  Branch (11542:12): [True: 463k, False: 118k]
  |  |  ------------------
  |  |11543|   463k|      if ((cls)[b[i]] != 0) {                                                \
  |  |  ------------------
  |  |  |  Branch (11543:11): [True: 104, False: 462k]
  |  |  ------------------
  |  |11544|    104|        return;                                                              \
  |  |11545|    104|      }                                                                      \
  |  |11546|   463k|    }                                                                        \
  |  |11547|   118k|  } while (0)
  |  |  ------------------
  |  |  |  Branch (11547:12): [Folded, False: 118k]
  |  |  ------------------
  ------------------
11636|   119k|}
simple_absolute.cc:_ZN3ada6parser12_GLOBAL__N_120path_has_dot_segmentENSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE:
11640|  20.4k|bool path_has_dot_segment(std::string_view path) noexcept {
11641|  20.4k|  if (path.empty()) {
  ------------------
  |  Branch (11641:7): [True: 0, False: 20.4k]
  ------------------
11642|      0|    return false;
11643|      0|  }
11644|       |  // "." / ".." at the start, with or without a leading '/'.
11645|  20.4k|  const size_t i = (path[0] == '/') ? 1 : 0;
  ------------------
  |  Branch (11645:20): [True: 20.4k, False: 0]
  ------------------
11646|  20.4k|  if (i < path.size() && path[i] == '.') {
  ------------------
  |  Branch (11646:7): [True: 20.4k, False: 0]
  |  Branch (11646:26): [True: 796, False: 19.6k]
  ------------------
11647|    796|    const size_t after = i + 1;
11648|    796|    if (after == path.size() || path[after] == '/' ||
  ------------------
  |  Branch (11648:9): [True: 32, False: 764]
  |  Branch (11648:33): [True: 188, False: 576]
  ------------------
11649|    576|        (after < path.size() && path[after] == '.' &&
  ------------------
  |  Branch (11649:10): [True: 576, False: 0]
  |  Branch (11649:33): [True: 354, False: 222]
  ------------------
11650|    438|         (after + 1 == path.size() || path[after + 1] == '/'))) {
  ------------------
  |  Branch (11650:11): [True: 14, False: 340]
  |  Branch (11650:39): [True: 204, False: 136]
  ------------------
11651|    438|      return true;
11652|    438|    }
11653|    796|  }
11654|  20.0k|  static constexpr std::string_view slash_dot{"/.", 2};
11655|  20.0k|  size_t p = i;
11656|  22.7k|  while ((p = path.find(slash_dot, p)) != std::string_view::npos) {
  ------------------
  |  Branch (11656:10): [True: 21.8k, False: 832]
  ------------------
11657|  21.8k|    const size_t after = p + 2;
11658|  21.8k|    if (after == path.size() || path[after] == '/' ||
  ------------------
  |  Branch (11658:9): [True: 100, False: 21.7k]
  |  Branch (11658:33): [True: 18.8k, False: 2.94k]
  ------------------
11659|  2.94k|        (after < path.size() && path[after] == '.' &&
  ------------------
  |  Branch (11659:10): [True: 2.94k, False: 0]
  |  Branch (11659:33): [True: 850, False: 2.09k]
  ------------------
11660|  19.2k|         (after + 1 == path.size() || path[after + 1] == '/'))) {
  ------------------
  |  Branch (11660:11): [True: 70, False: 780]
  |  Branch (11660:39): [True: 200, False: 580]
  ------------------
11661|  19.2k|      return true;
11662|  19.2k|    }
11663|  2.67k|    p = after;
11664|  2.67k|  }
11665|    832|  return false;
11666|  20.0k|}
simple_absolute.cc:_ZN12_GLOBAL__N_132apply_shifted_non_scheme_offsetsERN3ada14url_componentsEj:
13637|   261k|    ada::url_components& components, uint32_t new_difference) {
13638|   261k|  components.username_end += new_difference;
13639|   261k|  components.host_start += new_difference;
13640|   261k|  components.host_end += new_difference;
13641|   261k|  components.pathname_start += new_difference;
13642|   261k|  if (components.search_start != ada::url_components::omitted) {
  ------------------
  |  Branch (13642:7): [True: 0, False: 261k]
  ------------------
13643|      0|    components.search_start += new_difference;
13644|      0|  }
13645|   261k|  if (components.hash_start != ada::url_components::omitted) {
  ------------------
  |  Branch (13645:7): [True: 0, False: 261k]
  ------------------
13646|      0|    components.hash_start += new_difference;
13647|      0|  }
13648|   261k|}
_ZN3ada14url_aggregator10parse_pathENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
14007|  23.0k|ada_really_inline void url_aggregator::parse_path(std::string_view input) {
14008|  23.0k|  ada_log("url_aggregator::parse_path ", input);
14009|  23.0k|  ADA_ASSERT_TRUE(validate());
14010|  23.0k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
14011|  23.0k|  std::string tmp_buffer;
14012|  23.0k|  std::string_view internal_input;
14013|  23.0k|  if (unicode::has_tabs_or_newline(input)) {
  ------------------
  |  Branch (14013:7): [True: 0, False: 23.0k]
  ------------------
14014|      0|    tmp_buffer = input;
14015|       |    // Optimization opportunity: Instead of copying and then pruning, we could
14016|       |    // just directly build the string from user_input.
14017|      0|    helpers::remove_ascii_tab_or_newline(tmp_buffer);
14018|      0|    internal_input = tmp_buffer;
14019|  23.0k|  } else {
14020|  23.0k|    internal_input = input;
14021|  23.0k|  }
14022|       |
14023|       |  // If url is special, then:
14024|  23.0k|  if (is_special()) {
  ------------------
  |  Branch (14024:7): [True: 23.0k, False: 0]
  ------------------
14025|  23.0k|    if (internal_input.empty()) {
  ------------------
  |  Branch (14025:9): [True: 196, False: 22.8k]
  ------------------
14026|    196|      update_base_pathname("/");
14027|  22.8k|    } else if ((internal_input[0] == '/') || (internal_input[0] == '\\')) {
  ------------------
  |  Branch (14027:16): [True: 22.8k, False: 0]
  |  Branch (14027:46): [True: 0, False: 0]
  ------------------
14028|  22.8k|      consume_prepared_path(internal_input.substr(1));
14029|  22.8k|    } else {
14030|      0|      consume_prepared_path(internal_input);
14031|      0|    }
14032|  23.0k|  } else if (!internal_input.empty()) {
  ------------------
  |  Branch (14032:14): [True: 0, False: 0]
  ------------------
14033|      0|    if (internal_input[0] == '/') {
  ------------------
  |  Branch (14033:9): [True: 0, False: 0]
  ------------------
14034|      0|      consume_prepared_path(internal_input.substr(1));
14035|      0|    } else {
14036|      0|      consume_prepared_path(internal_input);
14037|      0|    }
14038|      0|  } else {
14039|       |    // Non-special URLs with an empty host can have their paths erased
14040|       |    // Path-only URLs cannot have their paths erased
14041|      0|    if (components.host_start == components.host_end && !has_authority()) {
  ------------------
  |  Branch (14041:9): [True: 0, False: 0]
  |  Branch (14041:57): [True: 0, False: 0]
  ------------------
14042|      0|      update_base_pathname("/");
14043|      0|    }
14044|      0|  }
14045|  23.0k|  ADA_ASSERT_TRUE(validate());
14046|  23.0k|}
_ZN3ada14url_aggregator10parse_hostENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
14126|   259k|ada_really_inline bool url_aggregator::parse_host(std::string_view input) {
14127|   259k|  ada_log("url_aggregator:parse_host \"", input, "\" [", input.size(),
14128|   259k|          " bytes]");
14129|   259k|  ADA_ASSERT_TRUE(validate());
14130|   259k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
14131|   259k|  if (input.empty()) {
  ------------------
  |  Branch (14131:7): [True: 6, False: 259k]
  ------------------
14132|      6|    return is_valid = false;
14133|      6|  }  // technically unnecessary.
14134|       |  // If input starts with U+005B ([), then:
14135|   259k|  if (input[0] == '[') {
  ------------------
  |  Branch (14135:7): [True: 684, False: 258k]
  ------------------
14136|       |    // If input does not end with U+005D (]), validation error, return failure.
14137|    684|    if (input.back() != ']') {
  ------------------
  |  Branch (14137:9): [True: 80, False: 604]
  ------------------
14138|     80|      return is_valid = false;
14139|     80|    }
14140|    604|    ada_log("parse_host ipv6");
14141|       |
14142|       |    // Return the result of IPv6 parsing input with its leading U+005B ([) and
14143|       |    // trailing U+005D (]) removed.
14144|    604|    input.remove_prefix(1);
14145|    604|    input.remove_suffix(1);
14146|    604|    return parse_ipv6(input);
14147|    684|  }
14148|       |
14149|       |  // If isNotSpecial is true, then return the result of opaque-host parsing
14150|       |  // input.
14151|   258k|  if (!is_special()) {
  ------------------
  |  Branch (14151:7): [True: 669, False: 258k]
  ------------------
14152|    669|    return parse_opaque_host(input);
14153|    669|  }
14154|       |  // Let domain be the result of running UTF-8 decode without BOM on the
14155|       |  // percent-decoding of input. Let asciiDomain be the result of running domain
14156|       |  // to ASCII with domain and false. The most common case is an ASCII input, in
14157|       |  // which case we do not need to call the expensive 'to_ascii' if a few
14158|       |  // conditions are met: no '%' and no 'xn-' subsequence.
14159|       |
14160|       |  // Often, the input does not contain any forbidden code points, and no upper
14161|       |  // case ASCII letter, then we can just copy it to the buffer. We want to
14162|       |  // optimize for such a common case.
14163|       |
14164|       |  // Fast path: try to parse as pure decimal IPv4 first.
14165|   258k|  const uint64_t fast_result = checkers::try_parse_ipv4_fast(input);
14166|   258k|  if (fast_result < checkers::ipv4_fast_fail) {
  ------------------
  |  Branch (14166:7): [True: 105k, False: 153k]
  ------------------
14167|   105k|    if (!input.empty() && input.back() == '.') {
  ------------------
  |  Branch (14167:9): [True: 105k, False: 0]
  |  Branch (14167:27): [True: 11, False: 105k]
  ------------------
14168|     11|      update_base_hostname(input.substr(0, input.size() - 1));
14169|   105k|    } else {
14170|   105k|      update_base_hostname(input);
14171|   105k|    }
14172|   105k|    host_type = IPV4;
14173|   105k|    is_valid = true;
14174|   105k|    ada_log("parse_host fast path decimal ipv4");
14175|   105k|    ADA_ASSERT_TRUE(validate());
14176|   105k|    return true;
14177|   105k|  }
14178|   153k|  uint8_t is_forbidden_or_upper =
14179|   153k|      unicode::contains_forbidden_domain_code_point_or_upper(input.data(),
14180|   153k|                                                             input.size());
14181|   153k|  static constexpr std::string_view xn_dash{"xn-", 3};
14182|   153k|  if ((is_forbidden_or_upper & 1) == 0) {
  ------------------
  |  Branch (14182:7): [True: 131k, False: 21.6k]
  ------------------
14183|   131k|    if ((is_forbidden_or_upper & 2) != 0) {
  ------------------
  |  Branch (14183:9): [True: 868, False: 130k]
  ------------------
14184|    868|      std::string lowered(input);
14185|    868|      unicode::to_lower_ascii(lowered.data(), lowered.size());
14186|    868|      if (lowered.find('-') == std::string_view::npos ||
  ------------------
  |  Branch (14186:11): [True: 628, False: 240]
  ------------------
14187|    670|          lowered.find(xn_dash) == std::string_view::npos) {
  ------------------
  |  Branch (14187:11): [True: 42, False: 198]
  ------------------
14188|    670|        update_base_hostname(lowered);
14189|    670|        if (checkers::is_ipv4(lowered)) {
  ------------------
  |  Branch (14189:13): [True: 143, False: 527]
  ------------------
14190|    143|          ada_log("parse_host fast path ipv4");
14191|    143|          return parse_ipv4(lowered, true);
14192|    143|        }
14193|    527|        ada_log("parse_host fast path ", get_hostname());
14194|    527|        is_valid = true;
14195|    527|        return true;
14196|    670|      }
14197|   130k|    } else if (input.find('-') == std::string_view::npos ||
  ------------------
  |  Branch (14197:16): [True: 71.1k, False: 59.4k]
  ------------------
14198|  71.3k|               input.find(xn_dash) == std::string_view::npos) {
  ------------------
  |  Branch (14198:16): [True: 196, False: 59.2k]
  ------------------
14199|  71.3k|      update_base_hostname(input);
14200|  71.3k|      if (checkers::is_ipv4(input)) {
  ------------------
  |  Branch (14200:11): [True: 38.3k, False: 33.0k]
  ------------------
14201|  38.3k|        ada_log("parse_host fast path ipv4");
14202|  38.3k|        return parse_ipv4(input, true);
14203|  38.3k|      }
14204|  33.0k|      ada_log("parse_host fast path ", get_hostname());
14205|  33.0k|      is_valid = true;
14206|  33.0k|      return true;
14207|  71.3k|    }
14208|   131k|  } else if (const size_t first_percent = input.find('%');
14209|  21.6k|             first_percent != std::string_view::npos) {
  ------------------
  |  Branch (14209:14): [True: 19.0k, False: 2.58k]
  ------------------
14210|  19.0k|    std::string decoded = unicode::percent_decode(input, first_percent);
14211|  19.0k|    const uint8_t decoded_flags =
14212|  19.0k|        unicode::contains_forbidden_domain_code_point_or_upper(decoded.data(),
14213|  19.0k|                                                               decoded.size());
14214|  19.0k|    if ((decoded_flags & 1) == 0) {
  ------------------
  |  Branch (14214:9): [True: 18.6k, False: 354]
  ------------------
14215|  18.6k|      if ((decoded_flags & 2) != 0) {
  ------------------
  |  Branch (14215:11): [True: 131, False: 18.5k]
  ------------------
14216|    131|        unicode::to_lower_ascii(decoded.data(), decoded.size());
14217|    131|      }
14218|  18.6k|      if (decoded.find('-') == std::string_view::npos ||
  ------------------
  |  Branch (14218:11): [True: 18.6k, False: 53]
  ------------------
14219|  18.6k|          decoded.find(xn_dash) == std::string_view::npos) {
  ------------------
  |  Branch (14219:11): [True: 21, False: 32]
  ------------------
14220|  18.6k|        update_base_hostname(decoded);
14221|  18.6k|        if (checkers::is_ipv4(decoded)) {
  ------------------
  |  Branch (14221:13): [True: 18.4k, False: 204]
  ------------------
14222|  18.4k|          return parse_ipv4(decoded, true);
14223|  18.4k|        }
14224|    204|        is_valid = true;
14225|    204|        return true;
14226|  18.6k|      }
14227|  18.6k|    }
14228|  19.0k|  }
14229|       |  // We have encountered at least one forbidden code point or the input contains
14230|       |  // 'xn-' (case insensitive), so we need to call 'to_ascii' to perform the full
14231|       |  // conversion.
14232|       |
14233|  62.4k|  ada_log("parse_host calling to_ascii");
14234|  62.4k|  std::optional<std::string> host = std::string(get_hostname());
14235|  62.4k|  is_valid = ada::unicode::to_ascii(host, input, input.find('%'));
14236|  62.4k|  if (!is_valid) {
  ------------------
  |  Branch (14236:7): [True: 1.59k, False: 60.8k]
  ------------------
14237|  1.59k|    ada_log("parse_host to_ascii returns false");
14238|  1.59k|    return is_valid = false;
14239|  1.59k|  }
14240|  60.8k|  ada_log("parse_host to_ascii succeeded ", *host, " [", host->size(),
14241|  60.8k|          " bytes]");
14242|       |
14243|  60.8k|  if (std::ranges::any_of(host.value(),
  ------------------
  |  Branch (14243:7): [True: 0, False: 60.8k]
  ------------------
14244|  60.8k|                          ada::unicode::is_forbidden_domain_code_point)) {
14245|      0|    return is_valid = false;
14246|      0|  }
14247|       |
14248|       |  // If asciiDomain ends in a number, then return the result of IPv4 parsing
14249|       |  // asciiDomain.
14250|  60.8k|  if (checkers::is_ipv4(host.value())) {
  ------------------
  |  Branch (14250:7): [True: 126, False: 60.6k]
  ------------------
14251|    126|    ada_log("parse_host got ipv4 ", *host);
14252|    126|    return parse_ipv4(host.value(), false);
14253|    126|  }
14254|       |
14255|  60.6k|  update_base_hostname(host.value());
14256|  60.6k|  ADA_ASSERT_TRUE(validate());
14257|  60.6k|  return true;
14258|  60.8k|}
_ZN3ada7helpers9substringENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEm:
 8565|  22.4k|                                                       size_t pos) {
 8566|  22.4k|  ADA_ASSERT_TRUE(pos <= input.size());
 8567|       |  // The following is safer but unneeded if we have the above line:
 8568|       |  // return pos > input.size() ? std::string_view() : input.substr(pos);
 8569|  22.4k|  return input.substr(pos);
 8570|  22.4k|}
_ZN3ada14url_aggregator21consume_prepared_pathENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
15077|   232k|inline void url_aggregator::consume_prepared_path(std::string_view input) {
15078|   232k|  ada_log("url_aggregator::consume_prepared_path ", input);
15079|       |  /***
15080|       |   * This is largely duplicated code from helpers::parse_prepared_path, which is
15081|       |   * unfortunate. This particular function is nearly identical, except that it
15082|       |   * is a method on url_aggregator. The idea is that the trivial path (which is
15083|       |   * very common) merely appends to the buffer. This is the same trivial path as
15084|       |   * with helpers::parse_prepared_path, except that we have the additional check
15085|       |   * for is_at_path(). Otherwise, we grab a copy of the current path and we
15086|       |   * modify it, and then insert it back into the buffer.
15087|       |   */
15088|   232k|  uint8_t accumulator = checkers::path_signature(input);
15089|       |  // Let us first detect a trivial case.
15090|       |  // If it is special, we check that we have no dot, no %,  no \ and no
15091|       |  // character needing percent encoding. Otherwise, we check that we have no %,
15092|       |  // no dot, and no character needing percent encoding.
15093|   232k|  constexpr uint8_t need_encoding = 1;
15094|   232k|  constexpr uint8_t backslash_char = 2;
15095|   232k|  constexpr uint8_t dot_char = 4;
15096|   232k|  constexpr uint8_t percent_char = 8;
15097|   232k|  bool special = type != ada::scheme::NOT_SPECIAL;
15098|   232k|  bool may_need_slow_file_handling = (type == ada::scheme::type::FILE &&
  ------------------
  |  Branch (15098:39): [True: 1.45k, False: 231k]
  ------------------
15099|  1.45k|                                      checkers::is_windows_drive_letter(input));
  ------------------
  |  Branch (15099:39): [True: 36, False: 1.41k]
  ------------------
15100|   232k|  bool trivial_path =
15101|   232k|      (special ? (accumulator == 0)
  ------------------
  |  Branch (15101:7): [True: 202k, False: 29.5k]
  |  Branch (15101:8): [True: 231k, False: 834]
  ------------------
15102|   232k|               : ((accumulator & (need_encoding | dot_char | percent_char)) ==
15103|    834|                  0)) &&
15104|   202k|      (!may_need_slow_file_handling);
  ------------------
  |  Branch (15104:7): [True: 202k, False: 13]
  ------------------
15105|   232k|  if (accumulator == dot_char && !may_need_slow_file_handling) {
  ------------------
  |  Branch (15105:7): [True: 12.7k, False: 219k]
  |  Branch (15105:34): [True: 12.7k, False: 15]
  ------------------
15106|       |    // '4' means that we have at least one dot, but nothing that requires
15107|       |    // percent encoding or decoding. The only part that is not trivial is
15108|       |    // that we may have single dots and double dots path segments.
15109|       |    // If we have such segments, then we either have a path that begins
15110|       |    // with '.' (easy to check), or we have the sequence './'.
15111|       |    // Note: input cannot be empty, it must at least contain one character ('.')
15112|       |    // Note: we know that '\' is not present.
15113|  12.7k|    if (input[0] != '.') {
  ------------------
  |  Branch (15113:9): [True: 11.3k, False: 1.33k]
  ------------------
15114|  11.3k|      size_t slashdot = 0;
15115|  11.3k|      bool dot_is_file = true;
15116|  36.5k|      for (;;) {
15117|  36.5k|        slashdot = input.find("/.", slashdot);
15118|  36.5k|        if (slashdot == std::string_view::npos) {  // common case
  ------------------
  |  Branch (15118:13): [True: 11.3k, False: 25.1k]
  ------------------
15119|  11.3k|          break;
15120|  25.1k|        } else {  // uncommon
15121|       |          // only three cases matter: /./, /.. or a final /
15122|  25.1k|          slashdot += 2;
15123|  25.1k|          dot_is_file &= !(slashdot == input.size() || input[slashdot] == '.' ||
  ------------------
  |  Branch (15123:28): [True: 75, False: 25.0k]
  |  Branch (15123:56): [True: 12.3k, False: 12.7k]
  ------------------
15124|  12.7k|                           input[slashdot] == '/');
  ------------------
  |  Branch (15124:28): [True: 11.5k, False: 1.14k]
  ------------------
15125|  25.1k|        }
15126|  36.5k|      }
15127|  11.3k|      trivial_path = dot_is_file;
15128|  11.3k|    }
15129|  12.7k|  }
15130|   232k|  if (trivial_path && is_at_path()) {
  ------------------
  |  Branch (15130:7): [True: 204k, False: 28.4k]
  |  Branch (15130:23): [True: 204k, False: 0]
  ------------------
15131|   204k|    ada_log("parse_path trivial");
15132|   204k|    buffer += '/';
15133|   204k|    buffer += input;
15134|   204k|    return;
15135|   204k|  }
15136|  28.4k|  std::string path = std::string(get_pathname());
15137|       |  // We are going to need to look a bit at the path, but let us see if we can
15138|       |  // ignore percent encoding *and* backslashes *and* percent characters.
15139|       |  // Except for the trivial case, this is likely to capture 99% of paths out
15140|       |  // there.
15141|  28.4k|  bool fast_path =
15142|  28.4k|      (special &&
  ------------------
  |  Branch (15142:8): [True: 27.9k, False: 473]
  ------------------
15143|  27.9k|       (accumulator & (need_encoding | backslash_char | percent_char)) == 0) &&
  ------------------
  |  Branch (15143:8): [True: 11.4k, False: 16.4k]
  ------------------
15144|  11.4k|      (type != ada::scheme::type::FILE);
  ------------------
  |  Branch (15144:7): [True: 11.3k, False: 89]
  ------------------
15145|  28.4k|  if (fast_path) {
  ------------------
  |  Branch (15145:7): [True: 11.3k, False: 17.0k]
  ------------------
15146|  11.3k|    ada_log("parse_prepared_path fast");
15147|       |    // Here we don't need to worry about \ or percent encoding.
15148|       |    // We also do not have a file protocol. We might have dots, however,
15149|       |    // but dots must as appear as '.', and they cannot be encoded because
15150|       |    // the symbol '%' is not present.
15151|  11.3k|    size_t previous_location = 0;  // We start at 0.
15152|  70.2k|    do {
15153|  70.2k|      size_t new_location = input.find('/', previous_location);
15154|       |      // std::string_view path_view = input;
15155|       |      //  We process the last segment separately:
15156|  70.2k|      if (new_location == std::string_view::npos) {
  ------------------
  |  Branch (15156:11): [True: 11.3k, False: 58.8k]
  ------------------
15157|  11.3k|        std::string_view path_view = input.substr(previous_location);
15158|  11.3k|        if (path_view == "..") {  // The path ends with ..
  ------------------
  |  Branch (15158:13): [True: 83, False: 11.3k]
  ------------------
15159|       |          // e.g., if you receive ".." with an empty path, you go to "/".
15160|     83|          if (path.empty()) {
  ------------------
  |  Branch (15160:15): [True: 18, False: 65]
  ------------------
15161|     18|            path = '/';
15162|     18|            update_base_pathname(path);
15163|     18|            return;
15164|     18|          }
15165|       |          // Fast case where we have nothing to do:
15166|     65|          if (path.back() == '/') {
  ------------------
  |  Branch (15166:15): [True: 18, False: 47]
  ------------------
15167|     18|            update_base_pathname(path);
15168|     18|            return;
15169|     18|          }
15170|       |          // If you have the path "/joe/myfriend",
15171|       |          // then you delete 'myfriend'.
15172|     47|          path.resize(path.rfind('/') + 1);
15173|     47|          update_base_pathname(path);
15174|     47|          return;
15175|     65|        }
15176|  11.3k|        path += '/';
15177|  11.3k|        if (path_view != ".") {
  ------------------
  |  Branch (15177:13): [True: 11.2k, False: 99]
  ------------------
15178|  11.2k|          path.append(path_view);
15179|  11.2k|        }
15180|  11.3k|        update_base_pathname(path);
15181|  11.3k|        return;
15182|  58.8k|      } else {
15183|       |        // This is a non-final segment.
15184|  58.8k|        std::string_view path_view =
15185|  58.8k|            input.substr(previous_location, new_location - previous_location);
15186|  58.8k|        previous_location = new_location + 1;
15187|  58.8k|        if (path_view == "..") {
  ------------------
  |  Branch (15187:13): [True: 13.0k, False: 45.8k]
  ------------------
15188|  13.0k|          size_t last_delimiter = path.rfind('/');
15189|  13.0k|          if (last_delimiter != std::string::npos) {
  ------------------
  |  Branch (15189:15): [True: 10.8k, False: 2.14k]
  ------------------
15190|  10.8k|            path.erase(last_delimiter);
15191|  10.8k|          }
15192|  45.8k|        } else if (path_view != ".") {
  ------------------
  |  Branch (15192:20): [True: 33.2k, False: 12.5k]
  ------------------
15193|  33.2k|          path += '/';
15194|  33.2k|          path.append(path_view);
15195|  33.2k|        }
15196|  58.8k|      }
15197|  70.2k|    } while (true);
  ------------------
  |  Branch (15197:14): [True: 58.8k, Folded]
  ------------------
15198|  17.0k|  } else {
15199|  17.0k|    ada_log("parse_path slow");
15200|       |    // we have reached the general case
15201|  17.0k|    bool needs_percent_encoding = (accumulator & 1);
15202|  17.0k|    std::string path_buffer_tmp;
15203|  62.1k|    do {
15204|  62.1k|      size_t location = (special && (accumulator & 2))
  ------------------
  |  Branch (15204:26): [True: 60.2k, False: 1.97k]
  |  Branch (15204:37): [True: 6.29k, False: 53.9k]
  ------------------
15205|  62.1k|                            ? input.find_first_of("/\\")
15206|  62.1k|                            : input.find('/');
15207|  62.1k|      std::string_view path_view = input;
15208|  62.1k|      if (location != std::string_view::npos) {
  ------------------
  |  Branch (15208:11): [True: 45.1k, False: 17.0k]
  ------------------
15209|  45.1k|        path_view.remove_suffix(path_view.size() - location);
15210|  45.1k|        input.remove_prefix(location + 1);
15211|  45.1k|      }
15212|       |      // path_buffer is either path_view or it might point at a percent encoded
15213|       |      // temporary string.
15214|  62.1k|      std::string_view path_buffer =
15215|  62.1k|          (needs_percent_encoding &&
  ------------------
  |  Branch (15215:12): [True: 13.2k, False: 48.9k]
  ------------------
15216|  13.2k|           ada::unicode::percent_encode<false>(
  ------------------
  |  Branch (15216:12): [True: 4.56k, False: 8.67k]
  ------------------
15217|  13.2k|               path_view, character_sets::PATH_PERCENT_ENCODE, path_buffer_tmp))
15218|  62.1k|              ? path_buffer_tmp
15219|  62.1k|              : path_view;
15220|  62.1k|      if (unicode::is_double_dot_path_segment(path_buffer)) {
  ------------------
  |  Branch (15220:11): [True: 12.8k, False: 49.3k]
  ------------------
15221|  12.8k|        helpers::shorten_path(path, type);
15222|  12.8k|        if (location == std::string_view::npos) {
  ------------------
  |  Branch (15222:13): [True: 9.54k, False: 3.29k]
  ------------------
15223|  9.54k|          path += '/';
15224|  9.54k|        }
15225|  49.3k|      } else if (unicode::is_single_dot_path_segment(path_buffer) &&
  ------------------
  |  Branch (15225:18): [True: 2.26k, False: 47.0k]
  ------------------
15226|  2.26k|                 (location == std::string_view::npos)) {
  ------------------
  |  Branch (15226:18): [True: 450, False: 1.81k]
  ------------------
15227|    450|        path += '/';
15228|    450|      }
15229|       |      // Otherwise, if path_buffer is not a single-dot path segment, then:
15230|  48.8k|      else if (!unicode::is_single_dot_path_segment(path_buffer)) {
  ------------------
  |  Branch (15230:16): [True: 47.0k, False: 1.81k]
  ------------------
15231|       |        // If url's scheme is "file", url's path is empty, and path_buffer is a
15232|       |        // Windows drive letter, then replace the second code point in
15233|       |        // path_buffer with U+003A (:).
15234|  47.0k|        if (type == ada::scheme::type::FILE && path.empty() &&
  ------------------
  |  Branch (15234:13): [True: 2.06k, False: 45.0k]
  |  Branch (15234:48): [True: 581, False: 1.48k]
  ------------------
15235|    581|            checkers::is_windows_drive_letter(path_buffer)) {
  ------------------
  |  Branch (15235:13): [True: 39, False: 542]
  ------------------
15236|     39|          path += '/';
15237|     39|          path += path_buffer[0];
15238|     39|          path += ':';
15239|     39|          path_buffer.remove_prefix(2);
15240|     39|          path.append(path_buffer);
15241|  47.0k|        } else {
15242|       |          // Append path_buffer to url's path.
15243|  47.0k|          path += '/';
15244|  47.0k|          path.append(path_buffer);
15245|  47.0k|        }
15246|  47.0k|      }
15247|  62.1k|      if (location == std::string_view::npos) {
  ------------------
  |  Branch (15247:11): [True: 17.0k, False: 45.1k]
  ------------------
15248|  17.0k|        update_base_pathname(path);
15249|  17.0k|        return;
15250|  17.0k|      }
15251|  62.1k|    } while (true);
  ------------------
  |  Branch (15251:14): [True: 45.1k, Folded]
  ------------------
15252|  17.0k|  }
15253|  28.4k|}
_ZN3ada8checkers7is_ipv4ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
   12|   303k|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|   303k|  if (!last_label_may_be_a_number(view)) {
  ------------------
  |  Branch (14:7): [True: 186k, False: 116k]
  ------------------
   15|   186k|    return false;
   16|   186k|  }
   17|       |  // If the address ends with a dot, we need to prune it (special case).
   18|   116k|  if (view.ends_with('.')) {
  ------------------
  |  Branch (18:7): [True: 55.2k, False: 61.1k]
  ------------------
   19|  55.2k|    view.remove_suffix(1);
   20|  55.2k|  }
   21|       |  // From the last character, find the last dot.
   22|   116k|  size_t last_dot = view.rfind('.');
   23|   116k|  if (last_dot != std::string_view::npos) {
  ------------------
  |  Branch (23:7): [True: 94.1k, False: 22.2k]
  ------------------
   24|       |    // We have at least one dot.
   25|  94.1k|    view.remove_prefix(last_dot + 1);
   26|  94.1k|  }
   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|   116k|  if (std::ranges::all_of(view, ada::checkers::is_digit)) {
  ------------------
  |  Branch (30:7): [True: 58.6k, False: 57.7k]
  ------------------
   31|  58.6k|    return true;
   32|  58.6k|  }
   33|       |  // It could be hex (0x), but not if there is a single character.
   34|  57.7k|  if (view.size() == 1) {
  ------------------
  |  Branch (34:7): [True: 0, False: 57.7k]
  ------------------
   35|      0|    return false;
   36|      0|  }
   37|       |  // It must start with 0x.
   38|  57.7k|  if (!view.starts_with("0x")) {
  ------------------
  |  Branch (38:7): [True: 1.38k, False: 56.3k]
  ------------------
   39|  1.38k|    return false;
   40|  1.38k|  }
   41|       |  // We must allow "0x".
   42|  56.3k|  if (view.size() == 2) {
  ------------------
  |  Branch (42:7): [True: 18.4k, False: 37.9k]
  ------------------
   43|  18.4k|    return true;
   44|  18.4k|  }
   45|       |  // We have 0x followed by some characters, we need to check that they are
   46|       |  // hexadecimals.
   47|  37.9k|  view.remove_prefix(2);
   48|  37.9k|  return std::ranges::all_of(view, ada::unicode::is_lowercase_hex);
   49|  56.3k|}
_ZN3ada7unicode16is_lowercase_hexEc:
 7168|   328k|ada_really_inline constexpr bool is_lowercase_hex(const char c) noexcept {
 7169|   328k|  return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f');
  ------------------
  |  Branch (7169:11): [True: 328k, False: 0]
  |  Branch (7169:23): [True: 13.9k, False: 314k]
  |  Branch (7169:37): [True: 314k, False: 0]
  |  Branch (7169:49): [True: 313k, False: 866]
  ------------------
 7170|   328k|}
_ZN3ada3url12parse_schemeILb0EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE:
10015|   261k|ada_really_inline bool url::parse_scheme(const std::string_view input) {
10016|   261k|  auto parsed_type = ada::scheme::get_scheme_type(input);
10017|   261k|  bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL);
10018|       |  /**
10019|       |   * In the common case, we will immediately recognize a special scheme (e.g.,
10020|       |   *http, https), in which case, we can go really fast.
10021|       |   **/
10022|   261k|  if (is_input_special) {  // fast path!!!
  ------------------
  |  Branch (10022:7): [True: 256k, False: 4.87k]
  ------------------
10023|       |    if constexpr (has_state_override) {
10024|       |      // If url's scheme is not a special scheme and buffer is a special scheme,
10025|       |      // then return.
10026|       |      if (is_special() != is_input_special) {
10027|       |        return false;
10028|       |      }
10029|       |
10030|       |      // If url includes credentials or has a non-null port, and buffer is
10031|       |      // "file", then return.
10032|       |      if ((has_credentials() || port.has_value()) &&
10033|       |          parsed_type == ada::scheme::type::FILE) {
10034|       |        return false;
10035|       |      }
10036|       |
10037|       |      // If url's scheme is "file" and its host is an empty host, then return.
10038|       |      // An empty host is the empty string.
10039|       |      if (type == ada::scheme::type::FILE && host.has_value() &&
10040|       |          host->empty()) {
10041|       |        return false;
10042|       |      }
10043|       |    }
10044|       |
10045|   256k|    type = parsed_type;
10046|       |
10047|       |    if constexpr (has_state_override) {
10048|       |      // This is uncommon.
10049|       |      uint16_t urls_scheme_port = get_special_port();
10050|       |
10051|       |      if (urls_scheme_port) {
10052|       |        // If url's port is url's scheme's default port, then set url's port to
10053|       |        // null.
10054|       |        if (port.has_value() && *port == urls_scheme_port) {
10055|       |          port = std::nullopt;
10056|       |        }
10057|       |      }
10058|       |    }
10059|   256k|  } else {  // slow path
10060|  4.87k|    std::string _buffer(input);
10061|       |    // Next function is only valid if the input is ASCII and returns false
10062|       |    // otherwise, but it seems that we always have ascii content so we do not
10063|       |    // need to check the return value.
10064|       |    // bool is_ascii =
10065|  4.87k|    unicode::to_lower_ascii(_buffer.data(), _buffer.size());
10066|       |
10067|       |    if constexpr (has_state_override) {
10068|       |      // The state-override validation errors below ("return" in the WHATWG URL
10069|       |      // parser) leave the URL unchanged. The setter contract is
10070|       |      // "true on success, false if the scheme is invalid" -- the fast path
10071|       |      // above already returns false here, so the slow path must agree.
10072|       |
10073|       |      // If url's scheme is a special scheme and buffer is not a special scheme,
10074|       |      // then return. If url's scheme is not a special scheme and buffer is a
10075|       |      // special scheme, then return.
10076|       |      if (is_special() != ada::scheme::is_special(_buffer)) {
10077|       |        return false;
10078|       |      }
10079|       |
10080|       |      // If url includes credentials or has a non-null port, and buffer is
10081|       |      // "file", then return.
10082|       |      if ((has_credentials() || port.has_value()) && _buffer == "file") {
10083|       |        return false;
10084|       |      }
10085|       |
10086|       |      // If url's scheme is "file" and its host is an empty host, then return.
10087|       |      // An empty host is the empty string.
10088|       |      if (type == ada::scheme::type::FILE && host.has_value() &&
10089|       |          host->empty()) {
10090|       |        return false;
10091|       |      }
10092|       |    }
10093|       |
10094|  4.87k|    set_scheme(std::move(_buffer));
10095|       |
10096|       |    if constexpr (has_state_override) {
10097|       |      // This is uncommon.
10098|       |      uint16_t urls_scheme_port = get_special_port();
10099|       |
10100|       |      if (urls_scheme_port) {
10101|       |        // If url's port is url's scheme's default port, then set url's port to
10102|       |        // null.
10103|       |        if (port.has_value() && *port == urls_scheme_port) {
10104|       |          port = std::nullopt;
10105|       |        }
10106|       |      }
10107|       |    }
10108|  4.87k|  }
10109|       |
10110|   261k|  return true;
10111|   261k|}
_ZN3ada14url_aggregator23parse_scheme_with_colonILb0EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE:
13655|   261k|    const std::string_view input_with_colon) {
13656|   261k|  ada_log("url_aggregator::parse_scheme_with_colon ", input_with_colon);
13657|   261k|  ADA_ASSERT_TRUE(validate());
13658|   261k|  ADA_ASSERT_TRUE(!helpers::overlaps(input_with_colon, buffer));
13659|   261k|  std::string_view input{input_with_colon};
13660|   261k|  input.remove_suffix(1);
13661|   261k|  auto parsed_type = ada::scheme::get_scheme_type(input);
13662|   261k|  const bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL);
13663|       |  /**
13664|       |   * In the common case, we will immediately recognize a special scheme (e.g.,
13665|       |   *http, https), in which case, we can go really fast.
13666|       |   **/
13667|   261k|  if (is_input_special) {  // fast path!!!
  ------------------
  |  Branch (13667:7): [True: 256k, False: 4.87k]
  ------------------
13668|       |    if constexpr (has_state_override) {
13669|       |      // If url's scheme is not a special scheme and buffer is a special scheme,
13670|       |      // then return.
13671|       |      if (is_special() != is_input_special) {
13672|       |        return false;
13673|       |      }
13674|       |
13675|       |      // If url includes credentials or has a non-null port, and buffer is
13676|       |      // "file", then return.
13677|       |      if ((has_credentials() || components.port != url_components::omitted) &&
13678|       |          parsed_type == ada::scheme::type::FILE) {
13679|       |        return false;
13680|       |      }
13681|       |
13682|       |      // If url's scheme is "file" and its host is an empty host, then return.
13683|       |      // An empty host is the empty string.
13684|       |      if (type == ada::scheme::type::FILE &&
13685|       |          components.host_start == components.host_end) {
13686|       |        return false;
13687|       |      }
13688|       |    }
13689|       |
13690|   256k|    type = parsed_type;
13691|   256k|    set_scheme_from_view_with_colon(input_with_colon);
13692|       |
13693|       |    if constexpr (has_state_override) {
13694|       |      // This is uncommon.
13695|       |      uint16_t urls_scheme_port = get_special_port();
13696|       |
13697|       |      if (urls_scheme_port) {
13698|       |        // If url's port is url's scheme's default port, then set url's port to
13699|       |        // null.
13700|       |        if (components.port == urls_scheme_port) {
13701|       |          clear_port();
13702|       |        }
13703|       |      }
13704|       |    }
13705|   256k|  } else {  // slow path
13706|  4.87k|    std::string _buffer(input);
13707|       |    // Next function is only valid if the input is ASCII and returns false
13708|       |    // otherwise, but it seems that we always have ascii content so we do not
13709|       |    // need to check the return value.
13710|  4.87k|    unicode::to_lower_ascii(_buffer.data(), _buffer.size());
13711|       |
13712|       |    if constexpr (has_state_override) {
13713|       |      // The state-override validation errors below ("return" in the WHATWG URL
13714|       |      // parser) leave the URL unchanged. The setter contract is
13715|       |      // "true on success, false if the scheme is invalid" -- the fast path
13716|       |      // above already returns false here, so the slow path must agree.
13717|       |
13718|       |      // If url's scheme is a special scheme and buffer is not a special scheme,
13719|       |      // then return. If url's scheme is not a special scheme and buffer is a
13720|       |      // special scheme, then return.
13721|       |      if (is_special() != ada::scheme::is_special(_buffer)) {
13722|       |        return false;
13723|       |      }
13724|       |
13725|       |      // If url includes credentials or has a non-null port, and buffer is
13726|       |      // "file", then return.
13727|       |      if ((has_credentials() || components.port != url_components::omitted) &&
13728|       |          _buffer == "file") {
13729|       |        return false;
13730|       |      }
13731|       |
13732|       |      // If url's scheme is "file" and its host is an empty host, then return.
13733|       |      // An empty host is the empty string.
13734|       |      if (type == ada::scheme::type::FILE &&
13735|       |          components.host_start == components.host_end) {
13736|       |        return false;
13737|       |      }
13738|       |    }
13739|       |
13740|  4.87k|    set_scheme(_buffer);
13741|       |
13742|       |    if constexpr (has_state_override) {
13743|       |      // This is uncommon.
13744|       |      uint16_t urls_scheme_port = get_special_port();
13745|       |
13746|       |      if (urls_scheme_port) {
13747|       |        // If url's port is url's scheme's default port, then set url's port to
13748|       |        // null.
13749|       |        if (components.port == urls_scheme_port) {
13750|       |          clear_port();
13751|       |        }
13752|       |      }
13753|       |    }
13754|  4.87k|  }
13755|   261k|  ADA_ASSERT_TRUE(validate());
13756|   261k|  return true;
13757|   261k|}
_ZN3ada14url_aggregator31set_scheme_from_view_with_colonENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13781|   256k|    std::string_view new_scheme_with_colon) {
13782|   256k|  ada_log("url_aggregator::set_scheme_from_view_with_colon ",
13783|   256k|          new_scheme_with_colon);
13784|   256k|  ADA_ASSERT_TRUE(validate());
13785|   256k|  ADA_ASSERT_TRUE(!new_scheme_with_colon.empty() &&
13786|   256k|                  new_scheme_with_colon.back() == ':');
13787|       |  // next line could overflow but unsigned arithmetic has well-defined
13788|       |  // overflows.
13789|   256k|  uint32_t new_difference =
13790|   256k|      uint32_t(new_scheme_with_colon.size()) - components.protocol_end;
13791|       |
13792|   256k|  if (buffer.empty()) {
  ------------------
  |  Branch (13792:7): [True: 256k, False: 0]
  ------------------
13793|   256k|    buffer.append(new_scheme_with_colon);
13794|   256k|  } else {
13795|      0|    buffer.erase(0, components.protocol_end);
13796|      0|    buffer.insert(0, new_scheme_with_colon);
13797|      0|  }
13798|   256k|  components.protocol_end += new_difference;
13799|       |
13800|   256k|  apply_shifted_non_scheme_offsets(components, new_difference);
13801|   256k|  ADA_ASSERT_TRUE(validate());
13802|   256k|}
_ZN3ada14url_aggregator10set_schemeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13804|  4.87k|inline void url_aggregator::set_scheme(std::string_view new_scheme) {
13805|  4.87k|  ada_log("url_aggregator::set_scheme ", new_scheme);
13806|  4.87k|  ADA_ASSERT_TRUE(validate());
13807|  4.87k|  ADA_ASSERT_TRUE(new_scheme.empty() || new_scheme.back() != ':');
13808|       |  // next line could overflow but unsigned arithmetic has well-defined
13809|       |  // overflows.
13810|  4.87k|  uint32_t new_difference =
13811|  4.87k|      uint32_t(new_scheme.size()) - components.protocol_end + 1;
13812|       |
13813|  4.87k|  type = ada::scheme::get_scheme_type(new_scheme);
13814|  4.87k|  if (buffer.empty()) {
  ------------------
  |  Branch (13814:7): [True: 4.87k, False: 0]
  ------------------
13815|  4.87k|    buffer.append(helpers::concat(new_scheme, ":"));
13816|  4.87k|  } else {
13817|      0|    buffer.erase(0, components.protocol_end);
13818|      0|    buffer.insert(0, helpers::concat(new_scheme, ":"));
13819|      0|  }
13820|  4.87k|  components.protocol_end = uint32_t(new_scheme.size() + 1);
13821|       |
13822|  4.87k|  apply_shifted_non_scheme_offsets(components, new_difference);
13823|  4.87k|  ADA_ASSERT_TRUE(validate());
13824|  4.87k|}

_ZN3ada37url_pattern_compile_component_optionsC2ENSt3__18optionalIcEES3_:
 5755|      6|      : delimiter(new_delimiter), prefix(new_prefix) {}
_ZN3ada14character_sets6bit_atEPKhh:
 1074|  1.46M|ada_really_inline constexpr bool bit_at(const uint8_t a[], const uint8_t i) {
 1075|  1.46M|  return !!(a[i >> 3] & (1 << (i & 7)));
 1076|  1.46M|}
_ZN2tl10unexpectedIN3ada6errorsEEC2EOS2_:
 2189|  85.4k|  constexpr explicit unexpected(E&& e) : m_val(std::move(e)) {}
_ZN2tl8expectedIN3ada3urlENS1_6errorsEEC2IS3_TnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_OT_EE5valueEvE4typeELPv0ETnPNS7_IXsr3std14is_convertibleIS9_S3_EE5valueEvE4typeELSD_0EEEONS_10unexpectedIS8_EE:
 3675|  21.3k|      : impl_base(unexpect, std::move(e.value())),
 3676|  21.3k|        ctor_base(detail::default_constructor_tag{}) {}
_ZNR2tl10unexpectedIN3ada6errorsEE5valueEv:
 2203|  42.7k|  TL_EXPECTED_11_CONSTEXPR E& value() & { return m_val; }
_ZN2tl6detail21expected_storage_baseIN3ada3urlENS2_6errorsELb0ELb1EEC2IJS4_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS4_DpOT_EE5valueEvE4typeELPv0EEENS_10unexpect_tESB_:
 2661|  21.3k|      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
_ZN2tl6detail26expected_default_ctor_baseIN3ada3urlENS2_6errorsELb1EEC2ENS0_23default_constructor_tagE:
 3279|   604k|  constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
_ZN2tl8expectedIN3ada3urlENS1_6errorsEEC2IS2_TnPNSt3__19enable_ifIXsr3std14is_convertibleIOT_S2_EE5valueEvE4typeELPv0ETnPNS7_IXaaaaaasr3std16is_constructibleIS2_S9_EE5valuentsr3std7is_sameINS6_5decayIS8_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameIS4_SG_EE5valuentsr3std7is_sameINS_10unexpectedIS3_EESG_EE5valueEvE4typeELSD_0EEES9_:
 3761|   583k|      : expected(in_place, std::forward<U>(v)) {}
_ZN2tl8expectedIN3ada3urlENS1_6errorsEEC2IJS2_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS2_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESA_:
 3634|   583k|      : impl_base(in_place, std::forward<Args>(args)...),
 3635|   583k|        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl6detail21expected_storage_baseIN3ada3urlENS2_6errorsELb0ELb1EEC2IJS3_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESB_:
 2649|   583k|      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
_ZN3ada3urlC2EOS0_:
 5043|   583k|  url(url&& u) noexcept = default;
_ZN3ada8url_baseD2Ev:
 1693|  2.37M|  virtual ~url_base() = default;
_ZN3ada3urlD2Ev:
 5046|  1.18M|  ~url() override = default;
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEC2IS3_TnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_OT_EE5valueEvE4typeELPv0ETnPNS7_IXsr3std14is_convertibleIS9_S3_EE5valueEvE4typeELSD_0EEEONS_10unexpectedIS8_EE:
 3675|  21.3k|      : impl_base(unexpect, std::move(e.value())),
 3676|  21.3k|        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl6detail21expected_storage_baseIN3ada14url_aggregatorENS2_6errorsELb0ELb1EEC2IJS4_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS4_DpOT_EE5valueEvE4typeELPv0EEENS_10unexpect_tESB_:
 2661|  21.3k|      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
_ZN2tl6detail26expected_default_ctor_baseIN3ada14url_aggregatorENS2_6errorsELb1EEC2ENS0_23default_constructor_tagE:
 3279|   604k|  constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEC2IS2_TnPNSt3__19enable_ifIXsr3std14is_convertibleIOT_S2_EE5valueEvE4typeELPv0ETnPNS7_IXaaaaaasr3std16is_constructibleIS2_S9_EE5valuentsr3std7is_sameINS6_5decayIS8_E4typeENS_10in_place_tEEE5valuentsr3std7is_sameIS4_SG_EE5valuentsr3std7is_sameINS_10unexpectedIS3_EESG_EE5valueEvE4typeELSD_0EEES9_:
 3761|   583k|      : expected(in_place, std::forward<U>(v)) {}
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEC2IJS2_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS2_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESA_:
 3634|   583k|      : impl_base(in_place, std::forward<Args>(args)...),
 3635|   583k|        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl6detail21expected_storage_baseIN3ada14url_aggregatorENS2_6errorsELb0ELb1EEC2IJS3_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESB_:
 2649|   583k|      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
_ZN3ada14url_aggregatorC2EOS0_:
 7774|   583k|  url_aggregator(url_aggregator&& u) noexcept = default;
_ZN3ada14url_aggregatorD2Ev:
 7777|  1.18M|  ~url_aggregator() override = default;
_ZN3ada6scheme15get_scheme_typeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6789|   532k|constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept {
 6790|   532k|  if (scheme.empty()) {
  ------------------
  |  Branch (6790:7): [True: 0, False: 532k]
  ------------------
 6791|      0|    return ada::scheme::NOT_SPECIAL;
 6792|      0|  }
 6793|   532k|  int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
 6794|   532k|  const std::string_view target = details::is_special_list[hash_value];
 6795|   532k|  if (scheme.size() == target.size() &&
  ------------------
  |  Branch (6795:7): [True: 527k, False: 5.14k]
  ------------------
 6796|   527k|      details::branchless_load5(scheme.data(), scheme.size()) ==
  ------------------
  |  Branch (6796:7): [True: 519k, False: 8.38k]
  ------------------
 6797|   527k|          details::scheme_keys[hash_value]) {
 6798|   519k|    return ada::scheme::type(hash_value);
 6799|   519k|  } else {
 6800|  13.5k|    return ada::scheme::NOT_SPECIAL;
 6801|  13.5k|  }
 6802|   532k|}
_ZN3ada6scheme7details16branchless_load5EPKcm:
 6730|   527k|inline uint64_t branchless_load5(const char* p, size_t n) {
 6731|   527k|  uint64_t input = (uint8_t)p[0];
 6732|   527k|  input |= ((uint64_t)(uint8_t)p[n > 1] << 8) & (0 - (uint64_t)(n > 1));
 6733|   527k|  input |= ((uint64_t)(uint8_t)p[(n > 2) * 2] << 16) & (0 - (uint64_t)(n > 2));
 6734|   527k|  input |= ((uint64_t)(uint8_t)p[(n > 3) * 3] << 24) & (0 - (uint64_t)(n > 3));
 6735|   527k|  input |= ((uint64_t)(uint8_t)p[(n > 4) * 4] << 32) & (0 - (uint64_t)(n > 4));
 6736|   527k|  return input;
 6737|   527k|}
_ZN3ada14url_aggregatorC2Ev:
 7772|   604k|  url_aggregator() = default;
_ZN3ada14url_componentsC2Ev:
 4952|   604k|  url_components() = default;
_ZN3ada8checkers19try_parse_ipv4_fastENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 1446|   630k|try_parse_ipv4_fast(std::string_view input) noexcept {
 1447|   630k|  const size_t len = input.size();
 1448|       |  // Shortest pure decimal: "0.0.0.0" (7). Longest + trailing dot: 16.
 1449|   630k|  if (len < 7 || len > 16) [[unlikely]] {
  ------------------
  |  Branch (1449:7): [True: 106k, False: 524k]
  |  Branch (1449:18): [True: 6.74k, False: 517k]
  ------------------
 1450|   112k|    return ipv4_fast_fail;
 1451|   112k|  }
 1452|   517k|  const char* data = input.data();
 1453|       |
 1454|       |#if defined(ADA_AVX512) && defined(__AVX512VBMI2__)
 1455|       |  return detail::try_parse_ipv4_avx512(data, len);
 1456|       |#else
 1457|   517k|  return detail::parse_ipv4_decimal_scalar(data, data + len);
 1458|   630k|#endif
 1459|   630k|}
_ZN3ada8checkers6detail25parse_ipv4_decimal_scalarEPKcS3_:
 1287|   517k|parse_ipv4_decimal_scalar(const char* p, const char* pend) noexcept {
 1288|   517k|  uint32_t ipv4 = 0;
 1289|  1.50M|  for (int i = 0; i < 4; ++i) {
  ------------------
  |  Branch (1289:19): [True: 1.26M, False: 247k]
  ------------------
 1290|  1.26M|    if (p == pend) [[unlikely]] {
  ------------------
  |  Branch (1290:9): [True: 18, False: 1.26M]
  ------------------
 1291|     18|      return ipv4_fast_fail;
 1292|     18|    }
 1293|  1.26M|    uint32_t val;
 1294|  1.26M|    char c = *p;
 1295|  1.26M|    if (c >= '0' && c <= '9') [[likely]] {
  ------------------
  |  Branch (1295:9): [True: 1.25M, False: 1.01k]
  |  Branch (1295:21): [True: 1.06M, False: 193k]
  ------------------
 1296|  1.06M|      val = static_cast<uint32_t>(c - '0');
 1297|  1.06M|      ++p;
 1298|  1.06M|    } else {
 1299|   194k|      return ipv4_fast_fail;
 1300|   194k|    }
 1301|  1.06M|    if (p < pend) {
  ------------------
  |  Branch (1301:9): [True: 966k, False: 99.6k]
  ------------------
 1302|   966k|      c = *p;
 1303|   966k|      if (c >= '0' && c <= '9') {
  ------------------
  |  Branch (1303:11): [True: 710k, False: 255k]
  |  Branch (1303:23): [True: 672k, False: 37.4k]
  ------------------
 1304|   672k|        if (val == 0) [[unlikely]] {
  ------------------
  |  Branch (1304:13): [True: 294, False: 672k]
  ------------------
 1305|    294|          return ipv4_fast_fail;
 1306|    294|        }
 1307|   672k|        val = val * 10u + static_cast<uint32_t>(c - '0');
 1308|   672k|        ++p;
 1309|   672k|        if (p < pend) {
  ------------------
  |  Branch (1309:13): [True: 562k, False: 110k]
  ------------------
 1310|   562k|          c = *p;
 1311|   562k|          if (c >= '0' && c <= '9') {
  ------------------
  |  Branch (1311:15): [True: 305k, False: 257k]
  |  Branch (1311:27): [True: 304k, False: 128]
  ------------------
 1312|   304k|            val = val * 10u + static_cast<uint32_t>(c - '0');
 1313|   304k|            ++p;
 1314|   304k|            if (val > 255u) [[unlikely]] {
  ------------------
  |  Branch (1314:17): [True: 1.37k, False: 303k]
  ------------------
 1315|  1.37k|              return ipv4_fast_fail;
 1316|  1.37k|            }
 1317|   304k|          }
 1318|   562k|        }
 1319|   672k|      }
 1320|   966k|    }
 1321|  1.06M|    ipv4 = (ipv4 << 8) | val;
 1322|  1.06M|    if (i < 3) {
  ------------------
  |  Branch (1322:9): [True: 816k, False: 247k]
  ------------------
 1323|   816k|      if (p == pend || *p != '.') [[unlikely]] {
  ------------------
  |  Branch (1323:11): [True: 96, False: 816k]
  |  Branch (1323:24): [True: 74.3k, False: 742k]
  ------------------
 1324|  74.4k|        return ipv4_fast_fail;
 1325|  74.4k|      }
 1326|   742k|      ++p;
 1327|   742k|    }
 1328|  1.06M|  }
 1329|   247k|  if (p != pend) {
  ------------------
  |  Branch (1329:7): [True: 298, False: 246k]
  ------------------
 1330|    298|    if (p == pend - 1 && *p == '.') {
  ------------------
  |  Branch (1330:9): [True: 142, False: 156]
  |  Branch (1330:26): [True: 22, False: 120]
  ------------------
 1331|     22|      return ipv4;
 1332|     22|    }
 1333|    276|    return ipv4_fast_fail;
 1334|    298|  }
 1335|   246k|  return ipv4;
 1336|   247k|}
_ZNK3ada3url15has_credentialsEv:
 7307|  1.24M|[[nodiscard]] ada_really_inline bool url::has_credentials() const noexcept {
 7308|  1.24M|  return !username.empty() || !password.empty();
  ------------------
  |  Branch (7308:10): [True: 199k, False: 1.04M]
  |  Branch (7308:31): [True: 840, False: 1.04M]
  ------------------
 7309|  1.24M|}
_ZNK3ada8url_base10is_specialEv:
 7272|  5.61M|    const noexcept {
 7273|  5.61M|  return type != ada::scheme::NOT_SPECIAL;
 7274|  5.61M|}
_ZNK2tl8expectedIN3ada3urlENS1_6errorsEEcvbEv:
 4074|   604k|  constexpr explicit operator bool() const noexcept { return this->m_has_val; }
_ZN2tl8expectedIN3ada3urlENS1_6errorsEEptEv:
 4043|   972k|  TL_EXPECTED_11_CONSTEXPR T* operator->() {
 4044|   972k|    TL_ASSERT(has_value());
  ------------------
  |  | 2096|   972k|#define TL_ASSERT(x) assert(x)
  ------------------
  |  Branch (4044:5): [True: 972k, False: 0]
  ------------------
 4045|   972k|    return valptr();
 4046|   972k|  }
_ZN2tl8expectedIN3ada3urlENS1_6errorsEE6valptrEv:
 3339|   972k|  T* valptr() { return std::addressof(this->m_val); }
_ZN2tl6detail21expected_storage_baseIN3ada3urlENS2_6errorsELb0ELb1EED2Ev:
 2671|   604k|  ~expected_storage_base() {
 2672|   604k|    if (m_has_val) {
  ------------------
  |  Branch (2672:9): [True: 583k, False: 21.3k]
  ------------------
 2673|   583k|      m_val.~T();
 2674|   583k|    }
 2675|   604k|  }
_ZNK3ada3url13get_href_sizeEv:
 7565|  1.03M|[[nodiscard]] inline size_t url::get_href_size() const noexcept {
 7566|  1.03M|  size_t size = 0;
 7567|  1.03M|  if (is_special()) {
  ------------------
  |  Branch (7567:7): [True: 1.02M, False: 7.86k]
  ------------------
 7568|  1.02M|    size += ada::scheme::details::is_special_list[type].size() + 1;
 7569|  1.02M|  } else {
 7570|  7.86k|    size += non_special_scheme.size() + 1;
 7571|  7.86k|  }
 7572|  1.03M|  if (host.has_value()) {
  ------------------
  |  Branch (7572:7): [True: 1.03M, False: 4.82k]
  ------------------
 7573|  1.03M|    size += host->size();
 7574|  1.03M|    size += 2;
 7575|  1.03M|    if (has_credentials()) {
  ------------------
  |  Branch (7575:9): [True: 130k, False: 902k]
  ------------------
 7576|   130k|      size += username.size();
 7577|   130k|      if (!password.empty()) {
  ------------------
  |  Branch (7577:11): [True: 125k, False: 4.96k]
  ------------------
 7578|   125k|        size += 1 + password.size();
 7579|   125k|      }
 7580|   130k|      size += 1;
 7581|   130k|    }
 7582|  1.03M|    if (port.has_value()) {
  ------------------
  |  Branch (7582:9): [True: 201k, False: 831k]
  ------------------
 7583|   201k|      size += 1;
 7584|   201k|      uint16_t p = *port;
 7585|   201k|      size += (p >= 10000)  ? 5
  ------------------
  |  Branch (7585:15): [True: 5.80k, False: 196k]
  ------------------
 7586|   201k|              : (p >= 1000) ? 4
  ------------------
  |  Branch (7586:17): [True: 95.9k, False: 100k]
  ------------------
 7587|   196k|              : (p >= 100)  ? 3
  ------------------
  |  Branch (7587:17): [True: 274, False: 99.8k]
  ------------------
 7588|   100k|              : (p >= 10)   ? 2
  ------------------
  |  Branch (7588:17): [True: 91.9k, False: 7.87k]
  ------------------
 7589|  99.8k|                            : 1;
 7590|   201k|    }
 7591|  1.03M|  } else if (!has_opaque_path && path.starts_with("//")) {
  ------------------
  |  Branch (7591:14): [True: 1.69k, False: 3.13k]
  |  Branch (7591:34): [True: 182, False: 1.50k]
  ------------------
 7592|    182|    size += 2;
 7593|    182|  }
 7594|  1.03M|  size += path.size();
 7595|  1.03M|  if (query.has_value()) {
  ------------------
  |  Branch (7595:7): [True: 121k, False: 916k]
  ------------------
 7596|   121k|    size += 1 + query->size();
 7597|   121k|  }
 7598|  1.03M|  if (hash.has_value()) {
  ------------------
  |  Branch (7598:7): [True: 93.8k, False: 943k]
  ------------------
 7599|  93.8k|    size += 1 + hash->size();
 7600|  93.8k|  }
 7601|  1.03M|  return size;
 7602|  1.03M|}
_ZN3ada8checkers8is_alphaEc:
 1267|   529k|constexpr bool is_alpha(char x) noexcept {
 1268|   529k|  return (to_lower(x) >= 'a') && (to_lower(x) <= 'z');
  ------------------
  |  Branch (1268:10): [True: 526k, False: 2.05k]
  |  Branch (1268:34): [True: 526k, False: 58]
  ------------------
 1269|   529k|}
_ZN3ada8checkers8to_lowerEc:
 1265|  1.05M|constexpr char to_lower(char x) noexcept { return (x | 0x20); }
_ZNR2tl8expectedIN3ada3urlENS1_6errorsEEdeIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v:
 4056|   972k|  TL_EXPECTED_11_CONSTEXPR U& operator*() & {
 4057|   972k|    TL_ASSERT(has_value());
  ------------------
  |  | 2096|   972k|#define TL_ASSERT(x) assert(x)
  ------------------
  |  Branch (4057:5): [True: 972k, False: 0]
  ------------------
 4058|   972k|    return val();
 4059|   972k|  }
_ZN2tl8expectedIN3ada3urlENS1_6errorsEE3valIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v:
 3348|   972k|  TL_EXPECTED_11_CONSTEXPR U& val() {
 3349|   972k|    return this->m_val;
 3350|   972k|  }
_ZN3ada3urlaSERKS0_:
 5045|   194k|  url& operator=(const url& u) = default;
_ZNK2tl8expectedIN3ada3urlENS1_6errorsEE9has_valueEv:
 4073|  2.35M|  constexpr bool has_value() const noexcept { return this->m_has_val; }
_ZN3ada8checkers26last_label_may_be_a_numberENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 1240|  1.14M|constexpr bool last_label_may_be_a_number(std::string_view view) noexcept {
 1241|  1.14M|  if (view.empty()) {
  ------------------
  |  Branch (1241:7): [True: 0, False: 1.14M]
  ------------------
 1242|      0|    return false;
 1243|      0|  }
 1244|  1.14M|  const char* start = view.data();
 1245|  1.14M|  const char* end = start + view.size();
 1246|  1.14M|  if (end[-1] == '.') {
  ------------------
  |  Branch (1246:7): [True: 58.3k, False: 1.08M]
  ------------------
 1247|  58.3k|    --end;
 1248|  58.3k|    if (end == start) {
  ------------------
  |  Branch (1248:9): [True: 2.04k, False: 56.3k]
  ------------------
 1249|  2.04k|      return false;
 1250|  2.04k|    }
 1251|  58.3k|  }
 1252|  1.14M|  if (!is_ipv4_number_char(end[-1])) {
  ------------------
  |  Branch (1252:7): [True: 858k, False: 283k]
  ------------------
 1253|   858k|    return false;
 1254|   858k|  }
 1255|   283k|  const char* label = end;
 1256|  1.29M|  while (label != start && is_ipv4_number_char(label[-1])) {
  ------------------
  |  Branch (1256:10): [True: 1.27M, False: 27.5k]
  |  Branch (1256:28): [True: 1.01M, False: 255k]
  ------------------
 1257|  1.01M|    --label;
 1258|  1.01M|  }
 1259|   283k|  if (label != start && label[-1] != '.') {
  ------------------
  |  Branch (1259:7): [True: 255k, False: 27.5k]
  |  Branch (1259:25): [True: 122k, False: 133k]
  ------------------
 1260|   122k|    return false;
 1261|   122k|  }
 1262|   160k|  return label != end && is_digit(*label);
  ------------------
  |  Branch (1262:10): [True: 160k, False: 0]
  |  Branch (1262:26): [True: 153k, False: 7.57k]
  ------------------
 1263|   283k|}
_ZN3ada8checkers19is_ipv4_number_charEc:
 1234|  2.41M|constexpr bool is_ipv4_number_char(char x) noexcept {
 1235|  2.41M|  const unsigned char c = static_cast<unsigned char>(x);
 1236|  2.41M|  return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') ||
  ------------------
  |  Branch (1236:11): [True: 2.16M, False: 251k]
  |  Branch (1236:23): [True: 315k, False: 1.84M]
  |  Branch (1236:37): [True: 1.84M, False: 252k]
  |  Branch (1236:49): [True: 824k, False: 1.02M]
  ------------------
 1237|  1.27M|         (c >= 'A' && c <= 'F') || c == 'x' || c == 'X';
  ------------------
  |  Branch (1237:11): [True: 1.02M, False: 251k]
  |  Branch (1237:23): [True: 0, False: 1.02M]
  |  Branch (1237:36): [True: 160k, False: 1.11M]
  |  Branch (1237:48): [True: 0, False: 1.11M]
  ------------------
 1238|  2.41M|}
_ZN3ada8checkers8is_digitEc:
 1232|   391k|constexpr bool is_digit(char x) noexcept { return (x >= '0') & (x <= '9'); }
_ZN3ada6scheme16get_special_portENS0_4typeE:
 6786|   121k|constexpr uint16_t get_special_port(ada::scheme::type type) noexcept {
 6787|   121k|  return details::special_ports[int(type)];
 6788|   121k|}
_ZN3ada14url_aggregatoraSERKS0_:
 7776|   194k|  url_aggregator& operator=(const url_aggregator& u) = default;
_ZN3ada14url_aggregator20update_base_pathnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8497|  59.1k|inline void url_aggregator::update_base_pathname(const std::string_view input) {
 8498|  59.1k|  ada_log("url_aggregator::update_base_pathname '", input, "' [", input.size(),
 8499|  59.1k|          " bytes] \n", to_diagram());
 8500|  59.1k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 8501|  59.1k|  ADA_ASSERT_TRUE(validate());
 8502|       |
 8503|  59.1k|  const bool begins_with_dashdash = input.starts_with("//");
 8504|  59.1k|  if (!begins_with_dashdash && has_dash_dot()) {
  ------------------
  |  Branch (8504:7): [True: 58.3k, False: 825]
  |  Branch (8504:32): [True: 0, False: 58.3k]
  ------------------
 8505|       |    // We must delete the ./
 8506|      0|    delete_dash_dot();
 8507|      0|  }
 8508|       |
 8509|  59.1k|  if (begins_with_dashdash && !has_opaque_path && !has_authority() &&
  ------------------
  |  Branch (8509:7): [True: 825, False: 58.3k]
  |  Branch (8509:31): [True: 825, False: 0]
  |  Branch (8509:51): [True: 42, False: 783]
  ------------------
 8510|     42|      !has_dash_dot()) {
  ------------------
  |  Branch (8510:7): [True: 42, False: 0]
  ------------------
 8511|       |    // If url's host is null, url does not have an opaque path, url's path's
 8512|       |    // size is greater than 1, then append U+002F (/) followed by U+002E (.) to
 8513|       |    // output.
 8514|     42|    buffer.insert(components.pathname_start, "/.");
 8515|     42|    components.pathname_start += 2;
 8516|     42|    if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (8516:9): [True: 0, False: 42]
  ------------------
 8517|      0|      components.search_start += 2;
 8518|      0|    }
 8519|     42|    if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8519:9): [True: 0, False: 42]
  ------------------
 8520|      0|      components.hash_start += 2;
 8521|      0|    }
 8522|     42|  }
 8523|       |
 8524|  59.1k|  uint32_t difference = replace_and_resize(
 8525|  59.1k|      components.pathname_start,
 8526|  59.1k|      components.pathname_start + get_pathname_length(), input);
 8527|  59.1k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (8527:7): [True: 0, False: 59.1k]
  ------------------
 8528|      0|    components.search_start += difference;
 8529|      0|  }
 8530|  59.1k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8530:7): [True: 0, False: 59.1k]
  ------------------
 8531|      0|    components.hash_start += difference;
 8532|      0|  }
 8533|  59.1k|  ADA_ASSERT_TRUE(validate());
 8534|  59.1k|}
_ZN3ada14url_aggregator18replace_and_resizeEjjNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8339|   357k|    uint32_t start, uint32_t end, std::string_view input) {
 8340|   357k|  uint32_t current_length = end - start;
 8341|   357k|  uint32_t input_size = uint32_t(input.size());
 8342|   357k|  uint32_t new_difference = input_size - current_length;
 8343|       |
 8344|   357k|  if (current_length == 0) {
  ------------------
  |  Branch (8344:7): [True: 288k, False: 68.3k]
  ------------------
 8345|   288k|    buffer.insert(start, input);
 8346|   288k|  } else if (input_size == current_length) {
  ------------------
  |  Branch (8346:14): [True: 628, False: 67.7k]
  ------------------
 8347|    628|    if (input_size != 0) {
  ------------------
  |  Branch (8347:9): [True: 628, False: 0]
  ------------------
 8348|    628|      std::memmove(buffer.data() + start, input.data(), input_size);
 8349|    628|    }
 8350|  67.7k|  } else if (input_size < current_length) {
  ------------------
  |  Branch (8350:14): [True: 18.3k, False: 49.3k]
  ------------------
 8351|  18.3k|    buffer.erase(start, current_length - input_size);
 8352|  18.3k|    buffer.replace(start, input_size, input);
 8353|  49.3k|  } else {
 8354|  49.3k|    buffer.replace(start, current_length, input.substr(0, current_length));
 8355|  49.3k|    buffer.insert(start + current_length, input.substr(current_length));
 8356|  49.3k|  }
 8357|       |
 8358|   357k|  return new_difference;
 8359|   357k|}
_ZNK3ada14url_aggregator19get_pathname_lengthEv:
 8390|  59.1k|url_aggregator::get_pathname_length() const noexcept {
 8391|  59.1k|  ada_log("url_aggregator::get_pathname_length");
 8392|  59.1k|  uint32_t ending_index = uint32_t(buffer.size());
 8393|  59.1k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (8393:7): [True: 0, False: 59.1k]
  ------------------
 8394|      0|    ending_index = components.search_start;
 8395|  59.1k|  } else if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8395:14): [True: 0, False: 59.1k]
  ------------------
 8396|      0|    ending_index = components.hash_start;
 8397|      0|  }
 8398|  59.1k|  return ending_index - components.pathname_start;
 8399|  59.1k|}
_ZNK3ada14url_aggregator12get_pathnameEv:
 9332|   222k|    ada_lifetime_bound {
 9333|   222k|  ada_log("url_aggregator::get_pathname pathname_start = ",
 9334|   222k|          components.pathname_start, " buffer.size() = ", buffer.size(),
 9335|   222k|          " components.search_start = ", components.search_start,
 9336|   222k|          " components.hash_start = ", components.hash_start);
 9337|   222k|  auto ending_index = uint32_t(buffer.size());
 9338|   222k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (9338:7): [True: 33.0k, False: 189k]
  ------------------
 9339|  33.0k|    ending_index = components.search_start;
 9340|   189k|  } else if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (9340:14): [True: 10.6k, False: 179k]
  ------------------
 9341|  10.6k|    ending_index = components.hash_start;
 9342|  10.6k|  }
 9343|   222k|  return helpers::substring(buffer, components.pathname_start, ending_index);
 9344|   222k|}
_ZN3ada14url_aggregator26update_unencoded_base_hashENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8315|  11.9k|inline void url_aggregator::update_unencoded_base_hash(std::string_view input) {
 8316|  11.9k|  ada_log("url_aggregator::update_unencoded_base_hash ", input, " [",
 8317|  11.9k|          input.size(), " bytes], buffer is '", buffer, "' [", buffer.size(),
 8318|  11.9k|          " bytes] components.hash_start = ", components.hash_start);
 8319|  11.9k|  ADA_ASSERT_TRUE(validate());
 8320|  11.9k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 8321|  11.9k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8321:7): [True: 0, False: 11.9k]
  ------------------
 8322|      0|    buffer.resize(components.hash_start);
 8323|      0|  }
 8324|  11.9k|  components.hash_start = uint32_t(buffer.size());
 8325|  11.9k|  buffer += "#";
 8326|  11.9k|  bool encoding_required = unicode::percent_encode<true>(
 8327|  11.9k|      input, ada::character_sets::FRAGMENT_PERCENT_ENCODE, buffer);
 8328|       |  // When encoding_required is false, then buffer is left unchanged, and percent
 8329|       |  // encoding was not deemed required.
 8330|  11.9k|  if (!encoding_required) {
  ------------------
  |  Branch (8330:7): [True: 11.7k, False: 250]
  ------------------
 8331|  11.7k|    buffer.append(input);
 8332|  11.7k|  }
 8333|  11.9k|  ada_log("url_aggregator::update_unencoded_base_hash final buffer is '",
 8334|  11.9k|          buffer, "' [", buffer.size(), " bytes]");
 8335|  11.9k|  ADA_ASSERT_TRUE(validate());
 8336|  11.9k|}
_ZN3ada3urlC2Ev:
 5041|   604k|  url() = default;
_ZN3ada3url26update_unencoded_base_hashENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 7415|  11.9k|inline void url::update_unencoded_base_hash(std::string_view input) {
 7416|       |  // We do the percent encoding
 7417|  11.9k|  hash = unicode::percent_encode(input,
 7418|  11.9k|                                 ada::character_sets::FRAGMENT_PERCENT_ENCODE);
 7419|  11.9k|}
_ZN3ada3url18update_base_searchENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKh:
 7422|  12.1k|                                    const uint8_t query_percent_encode_set[]) {
 7423|  12.1k|  query = ada::unicode::percent_encode(input, query_percent_encode_set);
 7424|  12.1k|}
_ZN3ada3url20update_base_hostnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 7413|     66|inline void url::update_base_hostname(std::string_view input) { host = input; }
_ZN3ada3url20update_base_pathnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 7430|  30.5k|inline void url::update_base_pathname(const std::string_view input) {
 7431|  30.5k|  path = input;
 7432|  30.5k|}
_ZN3ada3url10parse_portENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEb:
 7605|  2.29k|                                         bool check_trailing_content) noexcept {
 7606|  2.29k|  ada_log("parse_port('", view, "') ", view.size());
 7607|  2.29k|  if (!view.empty() && view[0] == '-') {
  ------------------
  |  Branch (7607:7): [True: 2.08k, False: 211]
  |  Branch (7607:24): [True: 9, False: 2.07k]
  ------------------
 7608|      9|    ada_log("parse_port: view[0] == '0' && view.size() > 1");
 7609|      9|    is_valid = false;
 7610|      9|    return 0;
 7611|      9|  }
 7612|  2.28k|  uint16_t parsed_port{};
 7613|  2.28k|  auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port);
 7614|  2.28k|  if (r.ec == std::errc::result_out_of_range) {
  ------------------
  |  Branch (7614:7): [True: 29, False: 2.25k]
  ------------------
 7615|     29|    ada_log("parse_port: r.ec == std::errc::result_out_of_range");
 7616|     29|    is_valid = false;
 7617|     29|    return 0;
 7618|     29|  }
 7619|  2.25k|  ada_log("parse_port: ", parsed_port);
 7620|  2.25k|  const auto consumed = size_t(r.ptr - view.data());
 7621|  2.25k|  ada_log("parse_port: consumed ", consumed);
 7622|  2.25k|  if (check_trailing_content) {
  ------------------
  |  Branch (7622:7): [True: 2.25k, False: 0]
  ------------------
 7623|  2.25k|    is_valid &=
 7624|  2.25k|        (consumed == view.size() || view[consumed] == '/' ||
  ------------------
  |  Branch (7624:10): [True: 461, False: 1.79k]
  |  Branch (7624:37): [True: 1.43k, False: 354]
  ------------------
 7625|    354|         view[consumed] == '?' || (is_special() && view[consumed] == '\\'));
  ------------------
  |  Branch (7625:10): [True: 108, False: 246]
  |  Branch (7625:36): [True: 235, False: 11]
  |  Branch (7625:52): [True: 53, False: 182]
  ------------------
 7626|  2.25k|  }
 7627|  2.25k|  ada_log("parse_port: is_valid = ", is_valid);
 7628|  2.25k|  if (is_valid) {
  ------------------
  |  Branch (7628:7): [True: 2.06k, False: 193]
  ------------------
 7629|       |    // scheme_default_port can return 0, and we should allow 0 as a base port.
 7630|  2.06k|    auto default_port = scheme_default_port();
 7631|  2.06k|    bool is_port_valid = (default_port == 0 && parsed_port == 0) ||
  ------------------
  |  Branch (7631:27): [True: 183, False: 1.87k]
  |  Branch (7631:48): [True: 78, False: 105]
  ------------------
 7632|  1.98k|                         (default_port != parsed_port);
  ------------------
  |  Branch (7632:26): [True: 1.97k, False: 3]
  ------------------
 7633|  2.06k|    port = (r.ec == std::errc() && is_port_valid) ? std::optional(parsed_port)
  ------------------
  |  Branch (7633:13): [True: 1.71k, False: 350]
  |  Branch (7633:36): [True: 1.70k, False: 3]
  ------------------
 7634|  2.06k|                                                  : std::nullopt;
 7635|  2.06k|  }
 7636|  2.25k|  return consumed;
 7637|  2.28k|}
_ZNK3ada8url_base19scheme_default_portEv:
 7281|  4.12k|url_base::scheme_default_port() const noexcept {
 7282|  4.12k|  return scheme::get_special_port(type);
 7283|  4.12k|}
_ZNK3ada3url12get_pathnameEv:
 7333|   194k|[[nodiscard]] constexpr std::string_view url::get_pathname() const noexcept {
 7334|   194k|  return path;
 7335|   194k|}
_ZN3ada8checkers23is_windows_drive_letterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 1271|  6.92k|constexpr bool is_windows_drive_letter(std::string_view input) noexcept {
 1272|  6.92k|  return input.size() >= 2 &&
  ------------------
  |  Branch (1272:10): [True: 5.37k, False: 1.55k]
  ------------------
 1273|  5.37k|         (is_alpha(input[0]) && ((input[1] == ':') || (input[1] == '|'))) &&
  ------------------
  |  Branch (1273:11): [True: 3.53k, False: 1.84k]
  |  Branch (1273:34): [True: 356, False: 3.17k]
  |  Branch (1273:55): [True: 74, False: 3.10k]
  ------------------
 1274|    430|         ((input.size() == 2) || (input[2] == '/' || input[2] == '\\' ||
  ------------------
  |  Branch (1274:11): [True: 98, False: 332]
  |  Branch (1274:35): [True: 50, False: 282]
  |  Branch (1274:54): [True: 4, False: 278]
  ------------------
 1275|    278|                                  input[2] == '?' || input[2] == '#'));
  ------------------
  |  Branch (1275:35): [True: 0, False: 278]
  |  Branch (1275:54): [True: 0, False: 278]
  ------------------
 1276|  6.92k|}
_ZN3ada8checkers34is_normalized_windows_drive_letterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 1279|    136|    std::string_view input) noexcept {
 1280|    136|  return input.size() == 2 && (is_alpha(input[0]) && (input[1] == ':'));
  ------------------
  |  Branch (1280:10): [True: 42, False: 94]
  |  Branch (1280:32): [True: 30, False: 12]
  |  Branch (1280:54): [True: 20, False: 10]
  ------------------
 1281|    136|}
_ZN3ada3url20set_protocol_as_fileEv:
 7458|  1.57k|constexpr void url::set_protocol_as_file() { type = ada::scheme::type::FILE; }
_ZN3ada7helpers14leading_zeroesEj:
 1978|   281k|inline int leading_zeroes(uint32_t input_num) noexcept {
 1979|       |#if ADA_REGULAR_VISUAL_STUDIO
 1980|       |  unsigned long leading_zero(0);
 1981|       |  unsigned long in(input_num);
 1982|       |  return _BitScanReverse(&leading_zero, in) ? int(31 - leading_zero) : 32;
 1983|       |#else
 1984|   281k|  return __builtin_clz(input_num);
 1985|   281k|#endif  // ADA_REGULAR_VISUAL_STUDIO
 1986|   281k|}
_ZN3ada14url_aggregator7reserveEj:
 9005|   261k|constexpr void ada::url_aggregator::reserve(uint32_t capacity) {
 9006|   261k|  buffer.reserve(capacity);
 9007|   261k|}
_ZN3ada14url_aggregator20append_base_passwordENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8723|  36.7k|inline void url_aggregator::append_base_password(const std::string_view input) {
 8724|  36.7k|  ada_log("url_aggregator::append_base_password ", input, " ", to_string(),
 8725|  36.7k|          "\n", to_diagram());
 8726|  36.7k|  ADA_ASSERT_TRUE(validate());
 8727|  36.7k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 8728|       |#if ADA_DEVELOPMENT_CHECKS
 8729|       |  // computing the expected password.
 8730|       |  std::string password_expected = std::string(get_password());
 8731|       |  password_expected.append(input);
 8732|       |#endif  // ADA_DEVELOPMENT_CHECKS
 8733|  36.7k|  add_authority_slashes_if_needed();
 8734|       |
 8735|       |  // If input is empty, do nothing.
 8736|  36.7k|  if (input.empty()) {
  ------------------
  |  Branch (8736:7): [True: 3.30k, False: 33.4k]
  ------------------
 8737|  3.30k|    return;
 8738|  3.30k|  }
 8739|       |
 8740|  33.4k|  uint32_t difference = uint32_t(input.size());
 8741|  33.4k|  if (has_password()) {
  ------------------
  |  Branch (8741:7): [True: 4.42k, False: 28.9k]
  ------------------
 8742|  4.42k|    buffer.insert(components.host_start, input);
 8743|  28.9k|  } else {
 8744|  28.9k|    difference++;  // Increment for ":"
 8745|  28.9k|    buffer.insert(components.username_end, ":");
 8746|  28.9k|    buffer.insert(components.username_end + 1, input);
 8747|  28.9k|  }
 8748|  33.4k|  components.host_start += difference;
 8749|       |
 8750|       |  // The following line is required to add "@" to hostname. When updating
 8751|       |  // password if hostname does not start with "@", it is "append_base_password"s
 8752|       |  // responsibility to set it.
 8753|  33.4k|  if (buffer[components.host_start] != '@') {
  ------------------
  |  Branch (8753:7): [True: 185, False: 33.2k]
  ------------------
 8754|    185|    buffer.insert(components.host_start, "@");
 8755|    185|    difference++;
 8756|    185|  }
 8757|       |
 8758|  33.4k|  components.host_end += difference;
 8759|  33.4k|  components.pathname_start += difference;
 8760|  33.4k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (8760:7): [True: 0, False: 33.4k]
  ------------------
 8761|      0|    components.search_start += difference;
 8762|      0|  }
 8763|  33.4k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8763:7): [True: 0, False: 33.4k]
  ------------------
 8764|      0|    components.hash_start += difference;
 8765|      0|  }
 8766|       |#if ADA_DEVELOPMENT_CHECKS
 8767|       |  std::string password_after(get_password());
 8768|       |  ADA_ASSERT_EQUAL(
 8769|       |      password_expected, password_after,
 8770|       |      "append_base_password problem after inserting " + std::string(input));
 8771|       |#endif  // ADA_DEVELOPMENT_CHECKS
 8772|  33.4k|  ADA_ASSERT_TRUE(validate());
 8773|  33.4k|}
_ZN3ada14url_aggregator31add_authority_slashes_if_neededEv:
 8979|   393k|inline void ada::url_aggregator::add_authority_slashes_if_needed() {
 8980|   393k|  ada_log("url_aggregator::add_authority_slashes_if_needed");
 8981|   393k|  ADA_ASSERT_TRUE(validate());
 8982|       |  // Protocol setter will insert `http:` to the URL. It is up to hostname setter
 8983|       |  // to insert
 8984|       |  // `//` initially to the buffer, since it depends on the hostname existence.
 8985|   393k|  if (has_authority()) {
  ------------------
  |  Branch (8985:7): [True: 134k, False: 258k]
  ------------------
 8986|   134k|    return;
 8987|   134k|  }
 8988|       |  // Performance: the common case is components.protocol_end == buffer.size()
 8989|       |  // Optimization opportunity: in many cases, the "//" is part of the input and
 8990|       |  // the insert could be fused with another insert.
 8991|   258k|  buffer.insert(components.protocol_end, "//");
 8992|   258k|  components.username_end += 2;
 8993|   258k|  components.host_start += 2;
 8994|   258k|  components.host_end += 2;
 8995|   258k|  components.pathname_start += 2;
 8996|   258k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (8996:7): [True: 0, False: 258k]
  ------------------
 8997|      0|    components.search_start += 2;
 8998|      0|  }
 8999|   258k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8999:7): [True: 0, False: 258k]
  ------------------
 9000|      0|    components.hash_start += 2;
 9001|      0|  }
 9002|   258k|  ADA_ASSERT_TRUE(validate());
 9003|   258k|}
_ZN3ada14url_aggregator20append_base_usernameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8607|  58.6k|inline void url_aggregator::append_base_username(const std::string_view input) {
 8608|  58.6k|  ada_log("url_aggregator::append_base_username ", input);
 8609|  58.6k|  ADA_ASSERT_TRUE(validate());
 8610|  58.6k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 8611|       |#if ADA_DEVELOPMENT_CHECKS
 8612|       |  // computing the expected password.
 8613|       |  std::string username_expected(get_username());
 8614|       |  username_expected.append(input);
 8615|       |#endif  // ADA_DEVELOPMENT_CHECKS
 8616|  58.6k|  add_authority_slashes_if_needed();
 8617|       |
 8618|       |  // If input is empty, do nothing.
 8619|  58.6k|  if (input.empty()) {
  ------------------
  |  Branch (8619:7): [True: 17.8k, False: 40.7k]
  ------------------
 8620|  17.8k|    return;
 8621|  17.8k|  }
 8622|       |
 8623|  40.7k|  uint32_t difference = uint32_t(input.size());
 8624|  40.7k|  buffer.insert(components.username_end, input);
 8625|  40.7k|  components.username_end += difference;
 8626|  40.7k|  components.host_start += difference;
 8627|       |
 8628|  40.7k|  if (buffer[components.host_start] != '@' &&
  ------------------
  |  Branch (8628:7): [True: 30.1k, False: 10.6k]
  ------------------
 8629|  30.1k|      components.host_start != components.host_end) {
  ------------------
  |  Branch (8629:7): [True: 30.1k, False: 0]
  ------------------
 8630|  30.1k|    buffer.insert(components.host_start, "@");
 8631|  30.1k|    difference++;
 8632|  30.1k|  }
 8633|       |
 8634|  40.7k|  components.host_end += difference;
 8635|  40.7k|  components.pathname_start += difference;
 8636|  40.7k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (8636:7): [True: 0, False: 40.7k]
  ------------------
 8637|      0|    components.search_start += difference;
 8638|      0|  }
 8639|  40.7k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8639:7): [True: 0, False: 40.7k]
  ------------------
 8640|      0|    components.hash_start += difference;
 8641|      0|  }
 8642|       |#if ADA_DEVELOPMENT_CHECKS
 8643|       |  std::string username_after(get_username());
 8644|       |  ADA_ASSERT_EQUAL(
 8645|       |      username_expected, username_after,
 8646|       |      "append_base_username problem after inserting " + std::string(input));
 8647|       |#endif  // ADA_DEVELOPMENT_CHECKS
 8648|  40.7k|  ADA_ASSERT_TRUE(validate());
 8649|  40.7k|}
_ZNK3ada14url_aggregator8get_hrefEv:
 9083|  1.16M|    const noexcept ada_lifetime_bound {
 9084|  1.16M|  ada_log("url_aggregator::get_href");
 9085|  1.16M|  return buffer;
 9086|  1.16M|}
_ZN3ada14url_aggregator16update_base_portEj:
 8775|  1.70k|inline void url_aggregator::update_base_port(uint32_t input) {
 8776|  1.70k|  ada_log("url_aggregator::update_base_port");
 8777|  1.70k|  ADA_ASSERT_TRUE(validate());
 8778|  1.70k|  if (input == url_components::omitted) {
  ------------------
  |  Branch (8778:7): [True: 0, False: 1.70k]
  ------------------
 8779|      0|    clear_port();
 8780|      0|    return;
 8781|      0|  }
 8782|       |  // calling std::to_string(input.value()) is unfortunate given that the port
 8783|       |  // value is probably already available as a string.
 8784|  1.70k|  std::string value = helpers::concat(":", std::to_string(input));
 8785|  1.70k|  uint32_t difference = uint32_t(value.size());
 8786|       |
 8787|  1.70k|  if (components.port != url_components::omitted) {
  ------------------
  |  Branch (8787:7): [True: 0, False: 1.70k]
  ------------------
 8788|      0|    difference -= components.pathname_start - components.host_end;
 8789|      0|    buffer.erase(components.host_end,
 8790|      0|                 components.pathname_start - components.host_end);
 8791|      0|  }
 8792|       |
 8793|  1.70k|  buffer.insert(components.host_end, value);
 8794|  1.70k|  components.pathname_start += difference;
 8795|  1.70k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (8795:7): [True: 0, False: 1.70k]
  ------------------
 8796|      0|    components.search_start += difference;
 8797|      0|  }
 8798|  1.70k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8798:7): [True: 0, False: 1.70k]
  ------------------
 8799|      0|    components.hash_start += difference;
 8800|      0|  }
 8801|  1.70k|  components.port = input;
 8802|  1.70k|  ADA_ASSERT_TRUE(validate());
 8803|  1.70k|}
_ZN3ada7helpers6concatIJPKcNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEEEESA_DpT_:
 1968|  1.70k|std::string concat(Args... args) {
 1969|  1.70k|  std::string answer;
 1970|  1.70k|  inner_concat(answer, args...);
 1971|  1.70k|  return answer;
 1972|  1.70k|}
_ZN3ada7helpers12inner_concatIPKcJNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEEEEvRSA_T_DpT0_:
 1957|  1.70k|inline void inner_concat(std::string& buffer, T t, Args... args) {
 1958|  1.70k|  buffer.append(t);
 1959|  1.70k|  return inner_concat(buffer, args...);
 1960|  1.70k|}
_ZN3ada7helpers12inner_concatINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEJEEEvRS8_T_:
 1949|  1.70k|inline void inner_concat(std::string& buffer, T t) {
 1950|  1.70k|  buffer.append(t);
 1951|  1.70k|}
_ZN3ada14url_aggregator18update_base_searchENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKh:
 8446|  12.1k|    std::string_view input, const uint8_t query_percent_encode_set[]) {
 8447|  12.1k|  ada_log("url_aggregator::update_base_search ", input,
 8448|  12.1k|          " with encoding parameter ", to_string(), "\n", to_diagram());
 8449|  12.1k|  ADA_ASSERT_TRUE(validate());
 8450|  12.1k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 8451|       |
 8452|  12.1k|  if (components.hash_start == url_components::omitted) {
  ------------------
  |  Branch (8452:7): [True: 12.1k, False: 0]
  ------------------
 8453|  12.1k|    if (components.search_start == url_components::omitted) {
  ------------------
  |  Branch (8453:9): [True: 12.1k, False: 0]
  ------------------
 8454|  12.1k|      components.search_start = uint32_t(buffer.size());
 8455|  12.1k|      buffer += "?";
 8456|  12.1k|    } else {
 8457|      0|      buffer.resize(components.search_start + 1);
 8458|      0|    }
 8459|       |
 8460|  12.1k|    bool encoding_required =
 8461|  12.1k|        unicode::percent_encode<true>(input, query_percent_encode_set, buffer);
 8462|       |    // When encoding_required is false, then buffer is left unchanged, and
 8463|       |    // percent encoding was not deemed required.
 8464|  12.1k|    if (!encoding_required) {
  ------------------
  |  Branch (8464:9): [True: 11.8k, False: 338]
  ------------------
 8465|  11.8k|      buffer.append(input);
 8466|  11.8k|    }
 8467|  12.1k|  } else {
 8468|      0|    const size_t idx =
 8469|      0|        ada::unicode::percent_encode_index(input, query_percent_encode_set);
 8470|      0|    std::string encoded;
 8471|      0|    std::string_view replacement = input;
 8472|      0|    if (idx != input.size()) {
  ------------------
  |  Branch (8472:9): [True: 0, False: 0]
  ------------------
 8473|      0|      encoded =
 8474|      0|          ada::unicode::percent_encode(input, query_percent_encode_set, idx);
 8475|      0|      replacement = encoded;
 8476|      0|    }
 8477|       |
 8478|      0|    if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (8478:9): [True: 0, False: 0]
  ------------------
 8479|      0|      const uint32_t difference = replace_and_resize(
 8480|      0|          components.search_start + 1, components.hash_start, replacement);
 8481|      0|      components.hash_start += difference;
 8482|      0|    } else {
 8483|      0|      components.search_start = components.hash_start;
 8484|      0|      buffer.insert(components.search_start, replacement.size() + 1, '?');
 8485|      0|      if (!replacement.empty()) {
  ------------------
  |  Branch (8485:11): [True: 0, False: 0]
  ------------------
 8486|      0|        std::memmove(buffer.data() + components.search_start + 1,
 8487|      0|                     replacement.data(), replacement.size());
 8488|      0|      }
 8489|      0|      components.hash_start +=
 8490|      0|          uint32_t(replacement.size() + 1);  // Do not forget `?`
 8491|      0|    }
 8492|      0|  }
 8493|       |
 8494|  12.1k|  ADA_ASSERT_TRUE(validate());
 8495|  12.1k|}
_ZN3ada14url_aggregator20update_base_hostnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8361|   297k|inline void url_aggregator::update_base_hostname(const std::string_view input) {
 8362|   297k|  ada_log("url_aggregator::update_base_hostname ", input, " [", input.size(),
 8363|   297k|          " bytes], buffer is '", buffer, "' [", buffer.size(), " bytes]");
 8364|   297k|  ADA_ASSERT_TRUE(validate());
 8365|   297k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 8366|       |
 8367|       |  // This next line is required for when parsing a URL like `foo://`
 8368|   297k|  add_authority_slashes_if_needed();
 8369|       |
 8370|   297k|  bool has_credentials = components.protocol_end + 2 < components.host_start;
 8371|   297k|  uint32_t new_difference =
 8372|   297k|      replace_and_resize(components.host_start, components.host_end, input);
 8373|       |
 8374|   297k|  if (has_credentials) {
  ------------------
  |  Branch (8374:7): [True: 30.1k, False: 267k]
  ------------------
 8375|  30.1k|    buffer.insert(components.host_start, "@");
 8376|  30.1k|    new_difference++;
 8377|  30.1k|  }
 8378|   297k|  components.host_end += new_difference;
 8379|   297k|  components.pathname_start += new_difference;
 8380|   297k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (8380:7): [True: 0, False: 297k]
  ------------------
 8381|      0|    components.search_start += new_difference;
 8382|      0|  }
 8383|   297k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8383:7): [True: 0, False: 297k]
  ------------------
 8384|      0|    components.hash_start += new_difference;
 8385|      0|  }
 8386|   297k|  ADA_ASSERT_TRUE(validate());
 8387|   297k|}
_ZN3ada14url_aggregator10parse_portENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEb:
 9093|  2.29k|url_aggregator::parse_port(std::string_view view, bool check_trailing_content) {
 9094|  2.29k|  ada_log("url_aggregator::parse_port('", view, "') ", view.size());
 9095|  2.29k|  if (!view.empty() && view[0] == '-') {
  ------------------
  |  Branch (9095:7): [True: 2.08k, False: 211]
  |  Branch (9095:24): [True: 9, False: 2.07k]
  ------------------
 9096|      9|    ada_log("parse_port: view[0] == '0' && view.size() > 1");
 9097|      9|    is_valid = false;
 9098|      9|    return 0;
 9099|      9|  }
 9100|  2.28k|  uint16_t parsed_port{};
 9101|  2.28k|  auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port);
 9102|  2.28k|  if (r.ec == std::errc::result_out_of_range) {
  ------------------
  |  Branch (9102:7): [True: 29, False: 2.25k]
  ------------------
 9103|     29|    ada_log("parse_port: r.ec == std::errc::result_out_of_range");
 9104|     29|    is_valid = false;
 9105|     29|    return 0;
 9106|     29|  }
 9107|  2.25k|  ada_log("parse_port: ", parsed_port);
 9108|  2.25k|  const size_t consumed = size_t(r.ptr - view.data());
 9109|  2.25k|  ada_log("parse_port: consumed ", consumed);
 9110|  2.25k|  if (check_trailing_content) {
  ------------------
  |  Branch (9110:7): [True: 2.25k, False: 0]
  ------------------
 9111|  2.25k|    is_valid &=
 9112|  2.25k|        (consumed == view.size() || view[consumed] == '/' ||
  ------------------
  |  Branch (9112:10): [True: 461, False: 1.79k]
  |  Branch (9112:37): [True: 1.43k, False: 354]
  ------------------
 9113|    354|         view[consumed] == '?' || (is_special() && view[consumed] == '\\'));
  ------------------
  |  Branch (9113:10): [True: 108, False: 246]
  |  Branch (9113:36): [True: 235, False: 11]
  |  Branch (9113:52): [True: 53, False: 182]
  ------------------
 9114|  2.25k|  }
 9115|  2.25k|  ada_log("parse_port: is_valid = ", is_valid);
 9116|  2.25k|  if (is_valid) {
  ------------------
  |  Branch (9116:7): [True: 2.06k, False: 193]
  ------------------
 9117|  2.06k|    ada_log("parse_port", r.ec == std::errc());
 9118|       |    // scheme_default_port can return 0, and we should allow 0 as a base port.
 9119|  2.06k|    auto default_port = scheme_default_port();
 9120|  2.06k|    bool is_port_valid = (default_port == 0 && parsed_port == 0) ||
  ------------------
  |  Branch (9120:27): [True: 183, False: 1.87k]
  |  Branch (9120:48): [True: 78, False: 105]
  ------------------
 9121|  1.98k|                         (default_port != parsed_port);
  ------------------
  |  Branch (9121:26): [True: 1.97k, False: 3]
  ------------------
 9122|  2.06k|    if (r.ec == std::errc() && is_port_valid) {
  ------------------
  |  Branch (9122:9): [True: 1.71k, False: 350]
  |  Branch (9122:32): [True: 1.70k, False: 3]
  ------------------
 9123|  1.70k|      update_base_port(parsed_port);
 9124|  1.70k|    } else {
 9125|    353|      clear_port();
 9126|    353|    }
 9127|  2.06k|  }
 9128|  2.25k|  return consumed;
 9129|  2.28k|}
_ZN3ada14url_aggregator20set_protocol_as_fileEv:
 9131|  1.57k|constexpr void url_aggregator::set_protocol_as_file() {
 9132|  1.57k|  ada_log("url_aggregator::set_protocol_as_file ");
 9133|  1.57k|  ADA_ASSERT_TRUE(validate());
 9134|  1.57k|  type = ada::scheme::type::FILE;
 9135|       |  // next line could overflow but unsigned arithmetic has well-defined
 9136|       |  // overflows.
 9137|  1.57k|  uint32_t new_difference = 5 - components.protocol_end;
 9138|       |
 9139|  1.57k|  if (buffer.empty()) {
  ------------------
  |  Branch (9139:7): [True: 0, False: 1.57k]
  ------------------
 9140|      0|    buffer.append("file:");
 9141|  1.57k|  } else {
 9142|  1.57k|    buffer.erase(0, components.protocol_end);
 9143|  1.57k|    buffer.insert(0, "file:");
 9144|  1.57k|  }
 9145|  1.57k|  components.protocol_end = 5;
 9146|       |
 9147|       |  // Update the rest of the components.
 9148|  1.57k|  components.username_end += new_difference;
 9149|  1.57k|  components.host_start += new_difference;
 9150|  1.57k|  components.host_end += new_difference;
 9151|  1.57k|  components.pathname_start += new_difference;
 9152|  1.57k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (9152:7): [True: 0, False: 1.57k]
  ------------------
 9153|      0|    components.search_start += new_difference;
 9154|      0|  }
 9155|  1.57k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (9155:7): [True: 0, False: 1.57k]
  ------------------
 9156|      0|    components.hash_start += new_difference;
 9157|      0|  }
 9158|  1.57k|  ADA_ASSERT_TRUE(validate());
 9159|  1.57k|}
_ZN3ada7unicode20percent_encode_indexENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKh:
 8216|    636|                                              const uint8_t character_set[]) {
 8217|    636|  const char* data = input.data();
 8218|    636|  const size_t size = input.size();
 8219|       |
 8220|       |  // Process 8 bytes at a time using unrolled loop
 8221|    636|  size_t i = 0;
 8222|  1.31k|  for (; i + 8 <= size; i += 8) {
  ------------------
  |  Branch (8222:10): [True: 709, False: 601]
  ------------------
 8223|    709|    unsigned char chunk[8];
 8224|    709|    std::memcpy(&chunk, data + i,
 8225|    709|                8);  // entices compiler to unconditionally process 8 characters
 8226|       |
 8227|       |    // Check 8 characters at once
 8228|  6.22k|    for (size_t j = 0; j < 8; j++) {
  ------------------
  |  Branch (8228:24): [True: 5.54k, False: 674]
  ------------------
 8229|  5.54k|      if (character_sets::bit_at(character_set, chunk[j])) {
  ------------------
  |  Branch (8229:11): [True: 35, False: 5.51k]
  ------------------
 8230|     35|        return i + j;
 8231|     35|      }
 8232|  5.54k|    }
 8233|    709|  }
 8234|       |
 8235|       |  // Handle remaining bytes
 8236|  2.50k|  for (; i < size; i++) {
  ------------------
  |  Branch (8236:10): [True: 1.91k, False: 594]
  ------------------
 8237|  1.91k|    if (character_sets::bit_at(character_set, data[i])) {
  ------------------
  |  Branch (8237:9): [True: 7, False: 1.90k]
  ------------------
 8238|      7|      return i;
 8239|      7|    }
 8240|  1.91k|  }
 8241|       |
 8242|    594|  return size;
 8243|    601|}
_ZN3ada14url_aggregator10clear_portEv:
 8805|    353|inline void url_aggregator::clear_port() {
 8806|    353|  ada_log("url_aggregator::clear_port");
 8807|    353|  ADA_ASSERT_TRUE(validate());
 8808|    353|  if (components.port == url_components::omitted) {
  ------------------
  |  Branch (8808:7): [True: 353, False: 0]
  ------------------
 8809|    353|    return;
 8810|    353|  }
 8811|      0|  uint32_t length = components.pathname_start - components.host_end;
 8812|      0|  buffer.erase(components.host_end, length);
 8813|      0|  components.pathname_start -= length;
 8814|      0|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (8814:7): [True: 0, False: 0]
  ------------------
 8815|      0|    components.search_start -= length;
 8816|      0|  }
 8817|      0|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8817:7): [True: 0, False: 0]
  ------------------
 8818|      0|    components.hash_start -= length;
 8819|      0|  }
 8820|      0|  components.port = url_components::omitted;
 8821|      0|  ADA_ASSERT_TRUE(validate());
 8822|      0|}
_ZNK3ada14url_aggregator13has_authorityEv:
 8970|   394k|    const noexcept {
 8971|   394k|  ada_log("url_aggregator::has_authority");
 8972|       |  // Performance: instead of doing this potentially expensive check, we could
 8973|       |  // have a boolean in the struct.
 8974|   394k|  return components.protocol_end + 2 <= components.host_start &&
  ------------------
  |  Branch (8974:10): [True: 135k, False: 258k]
  ------------------
 8975|   135k|         buffer[components.protocol_end] == '/' &&
  ------------------
  |  Branch (8975:10): [True: 135k, False: 0]
  ------------------
 8976|   135k|         buffer[components.protocol_end + 1] == '/';
  ------------------
  |  Branch (8976:10): [True: 135k, False: 0]
  ------------------
 8977|   394k|}
_ZNK3ada14url_aggregator12has_dash_dotEv:
 9050|  58.3k|[[nodiscard]] constexpr bool url_aggregator::has_dash_dot() const noexcept {
 9051|       |  // If url's host is null, url does not have an opaque path, url's path's size
 9052|       |  // is greater than 1, and url's path[0] is the empty string, then append
 9053|       |  // U+002F (/) followed by U+002E (.) to output.
 9054|  58.3k|  ada_log("url_aggregator::has_dash_dot");
 9055|       |#if ADA_DEVELOPMENT_CHECKS
 9056|       |  // If pathname_start and host_end are exactly two characters apart, then we
 9057|       |  // either have a one-digit port such as http://test.com:5?param=1 or else we
 9058|       |  // have a /.: sequence such as "non-spec:/.//". We test that this is the case.
 9059|       |  if (components.pathname_start == components.host_end + 2) {
 9060|       |    ADA_ASSERT_TRUE((buffer[components.host_end] == '/' &&
 9061|       |                     buffer[components.host_end + 1] == '.') ||
 9062|       |                    (buffer[components.host_end] == ':' &&
 9063|       |                     checkers::is_digit(buffer[components.host_end + 1])));
 9064|       |  }
 9065|       |  if (components.pathname_start == components.host_end + 2 &&
 9066|       |      buffer[components.host_end] == '/' &&
 9067|       |      buffer[components.host_end + 1] == '.') {
 9068|       |    ADA_ASSERT_TRUE(components.pathname_start + 1 < buffer.size());
 9069|       |    ADA_ASSERT_TRUE(buffer[components.pathname_start] == '/');
 9070|       |    ADA_ASSERT_TRUE(buffer[components.pathname_start + 1] == '/');
 9071|       |  }
 9072|       |#endif
 9073|       |  // Performance: it should be uncommon for components.pathname_start ==
 9074|       |  // components.host_end + 2 to be true. So we put this check first in the
 9075|       |  // sequence. Most times, we do not have an opaque path. Checking for '/.' is
 9076|       |  // more expensive, but should be uncommon.
 9077|  58.3k|  return components.pathname_start == components.host_end + 2 &&
  ------------------
  |  Branch (9077:10): [True: 926, False: 57.4k]
  ------------------
 9078|    926|         !has_opaque_path && buffer[components.host_end] == '/' &&
  ------------------
  |  Branch (9078:10): [True: 926, False: 0]
  |  Branch (9078:30): [True: 0, False: 926]
  ------------------
 9079|      0|         buffer[components.host_end + 1] == '.';
  ------------------
  |  Branch (9079:10): [True: 0, False: 0]
  ------------------
 9080|  58.3k|}
_ZNK2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEcvbEv:
 4074|   389k|  constexpr explicit operator bool() const noexcept { return this->m_has_val; }
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEptEv:
 4043|   972k|  TL_EXPECTED_11_CONSTEXPR T* operator->() {
 4044|   972k|    TL_ASSERT(has_value());
  ------------------
  |  | 2096|   972k|#define TL_ASSERT(x) assert(x)
  ------------------
  |  Branch (4044:5): [True: 972k, False: 0]
  ------------------
 4045|   972k|    return valptr();
 4046|   972k|  }
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEE6valptrEv:
 3339|   972k|  T* valptr() { return std::addressof(this->m_val); }
_ZNR2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEdeIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v:
 4056|   972k|  TL_EXPECTED_11_CONSTEXPR U& operator*() & {
 4057|   972k|    TL_ASSERT(has_value());
  ------------------
  |  | 2096|   972k|#define TL_ASSERT(x) assert(x)
  ------------------
  |  Branch (4057:5): [True: 972k, False: 0]
  ------------------
 4058|   972k|    return val();
 4059|   972k|  }
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEE3valIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v:
 3348|   972k|  TL_EXPECTED_11_CONSTEXPR U& val() {
 3349|   972k|    return this->m_val;
 3350|   972k|  }
_ZNK2tl8expectedIN3ada14url_aggregatorENS1_6errorsEE9has_valueEv:
 4073|  2.35M|  constexpr bool has_value() const noexcept { return this->m_has_val; }
_ZN2tl6detail21expected_storage_baseIN3ada14url_aggregatorENS2_6errorsELb0ELb1EED2Ev:
 2671|   604k|  ~expected_storage_base() {
 2672|   604k|    if (m_has_val) {
  ------------------
  |  Branch (2672:9): [True: 583k, False: 21.3k]
  ------------------
 2673|   583k|      m_val.~T();
 2674|   583k|    }
 2675|   604k|  }
_ZNK3ada14url_aggregator22has_non_empty_usernameEv:
 9009|   194k|constexpr bool url_aggregator::has_non_empty_username() const noexcept {
 9010|   194k|  ada_log("url_aggregator::has_non_empty_username");
 9011|   194k|  return components.protocol_end + 2 < components.username_end;
 9012|   194k|}
_ZN3ada7helpers9substringENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEmm:
 1890|   941k|                                                       size_t pos2) {
 1891|       |#if ADA_DEVELOPMENT_CHECKS
 1892|       |  if (pos2 < pos1) {
 1893|       |    std::cerr << "Negative-length substring: [" << pos1 << " to " << pos2 << ")"
 1894|       |              << std::endl;
 1895|       |    abort();
 1896|       |  }
 1897|       |#endif
 1898|   941k|  return input.substr(pos1, pos2 - pos1);
 1899|   941k|}
_ZNK3ada14url_aggregator22has_non_empty_passwordEv:
 9014|   194k|constexpr bool url_aggregator::has_non_empty_password() const noexcept {
 9015|   194k|  ada_log("url_aggregator::has_non_empty_password");
 9016|   194k|  return components.host_start > components.username_end;
 9017|   194k|}
_ZNK3ada14url_aggregator10is_at_pathEv:
 8402|   204k|    const noexcept {
 8403|   204k|  return buffer.size() == components.pathname_start;
 8404|   204k|}
_ZNK3ada14url_aggregator12has_passwordEv:
 9019|  33.4k|constexpr bool url_aggregator::has_password() const noexcept {
 9020|  33.4k|  ada_log("url_aggregator::has_password");
 9021|       |  // This function does not care about the length of the password
 9022|  33.4k|  return components.host_start > components.username_end &&
  ------------------
  |  Branch (9022:10): [True: 4.42k, False: 28.9k]
  ------------------
 9023|  4.42k|         buffer[components.username_end] == ':';
  ------------------
  |  Branch (9023:10): [True: 4.42k, False: 0]
  ------------------
 9024|  33.4k|}
_ZNK3ada14url_aggregator13get_href_sizeEv:
 9088|   389k|[[nodiscard]] constexpr size_t url_aggregator::get_href_size() const noexcept {
 9089|   389k|  return buffer.size();
 9090|   389k|}
_ZNK3ada3url8get_hrefEv:
 7478|  1.36M|[[nodiscard]] ada_really_inline std::string url::get_href() const {
 7479|  1.36M|  if (is_special() && host.has_value() && username.empty() &&
  ------------------
  |  Branch (7479:7): [True: 1.35M, False: 4.23k]
  |  Branch (7479:23): [True: 1.35M, False: 0]
  |  Branch (7479:43): [True: 1.28M, False: 69.6k]
  ------------------
 7480|  1.28M|      password.empty() && !port.has_value()) [[likely]] {
  ------------------
  |  Branch (7480:7): [True: 1.28M, False: 294]
  |  Branch (7480:27): [True: 1.14M, False: 139k]
  ------------------
 7481|  1.14M|    const std::string_view scheme = ada::scheme::details::is_special_list[type];
 7482|  1.14M|    const size_t host_size = host->size();
 7483|  1.14M|    const size_t path_size = path.size();
 7484|  1.14M|    const size_t query_size = query.has_value() ? query->size() : 0;
  ------------------
  |  Branch (7484:31): [True: 219k, False: 928k]
  ------------------
 7485|  1.14M|    const size_t hash_size = hash.has_value() ? hash->size() : 0;
  ------------------
  |  Branch (7485:30): [True: 154k, False: 993k]
  ------------------
 7486|  1.14M|    const size_t total = scheme.size() + 3 + host_size + path_size +
 7487|  1.14M|                         (query.has_value() ? query_size + 1 : 0) +
  ------------------
  |  Branch (7487:27): [True: 219k, False: 928k]
  ------------------
 7488|  1.14M|                         (hash.has_value() ? hash_size + 1 : 0);
  ------------------
  |  Branch (7488:27): [True: 154k, False: 993k]
  ------------------
 7489|  1.14M|    std::string output(total, '\0');
 7490|  1.14M|    char* p = output.data();
 7491|  1.14M|    std::memcpy(p, scheme.data(), scheme.size());
 7492|  1.14M|    p += scheme.size();
 7493|  1.14M|    p[0] = ':';
 7494|  1.14M|    p[1] = '/';
 7495|  1.14M|    p[2] = '/';
 7496|  1.14M|    p += 3;
 7497|       |    // NOLINTNEXTLINE(bugprone-not-null-terminated-result)
 7498|  1.14M|    std::memcpy(p, host->data(), host_size);
 7499|  1.14M|    p += host_size;
 7500|  1.14M|    std::memcpy(p, path.data(), path_size);
 7501|  1.14M|    p += path_size;
 7502|  1.14M|    if (query.has_value()) {
  ------------------
  |  Branch (7502:9): [True: 219k, False: 928k]
  ------------------
 7503|   219k|      *p++ = '?';
 7504|       |      // NOLINTNEXTLINE(bugprone-not-null-terminated-result)
 7505|   219k|      std::memcpy(p, query->data(), query_size);
 7506|   219k|      p += query_size;
 7507|   219k|    }
 7508|  1.14M|    if (hash.has_value()) {
  ------------------
  |  Branch (7508:9): [True: 154k, False: 993k]
  ------------------
 7509|   154k|      *p++ = '#';
 7510|       |      // NOLINTNEXTLINE(bugprone-not-null-terminated-result)
 7511|   154k|      std::memcpy(p, hash->data(), hash_size);
 7512|   154k|    }
 7513|  1.14M|    return output;
 7514|  1.14M|  }
 7515|       |
 7516|   213k|  std::string output;
 7517|   213k|  output.reserve(get_href_size());
 7518|       |
 7519|   213k|  if (is_special()) {
  ------------------
  |  Branch (7519:7): [True: 209k, False: 4.23k]
  ------------------
 7520|   209k|    output.append(ada::scheme::details::is_special_list[type]);
 7521|   209k|    output += ':';
 7522|   209k|  } else {
 7523|  4.23k|    output.append(non_special_scheme);
 7524|  4.23k|    output += ':';
 7525|  4.23k|  }
 7526|       |
 7527|   213k|  if (host.has_value()) {
  ------------------
  |  Branch (7527:7): [True: 211k, False: 2.59k]
  ------------------
 7528|   211k|    output += '/';
 7529|   211k|    output += '/';
 7530|   211k|    if (has_credentials()) {
  ------------------
  |  Branch (7530:9): [True: 70.1k, False: 141k]
  ------------------
 7531|  70.1k|      output.append(username);
 7532|  70.1k|      if (!password.empty()) {
  ------------------
  |  Branch (7532:11): [True: 67.4k, False: 2.67k]
  ------------------
 7533|  67.4k|        output += ':';
 7534|  67.4k|        output.append(password);
 7535|  67.4k|      }
 7536|  70.1k|      output += '@';
 7537|  70.1k|    }
 7538|   211k|    output.append(*host);
 7539|   211k|    if (port.has_value()) {
  ------------------
  |  Branch (7539:9): [True: 140k, False: 71.0k]
  ------------------
 7540|   140k|      output += ':';
 7541|   140k|      char port_buf[5];
 7542|   140k|      auto [ptr, ec] = std::to_chars(port_buf, port_buf + 5, *port);
 7543|   140k|      (void)ec;
 7544|   140k|      output.append(port_buf, static_cast<size_t>(ptr - port_buf));
 7545|   140k|    }
 7546|   211k|  } else if (!has_opaque_path && path.starts_with("//")) {
  ------------------
  |  Branch (7546:14): [True: 910, False: 1.68k]
  |  Branch (7546:34): [True: 98, False: 812]
  ------------------
 7547|       |    // If url's host is null, url does not have an opaque path, url's path's
 7548|       |    // size is greater than 1, and url's path[0] is the empty string, then
 7549|       |    // append U+002F (/) followed by U+002E (.) to output.
 7550|     98|    output += '/';
 7551|     98|    output += '.';
 7552|     98|  }
 7553|   213k|  output.append(path);
 7554|   213k|  if (query.has_value()) {
  ------------------
  |  Branch (7554:7): [True: 12.2k, False: 201k]
  ------------------
 7555|  12.2k|    output += '?';
 7556|  12.2k|    output.append(*query);
 7557|  12.2k|  }
 7558|   213k|  if (hash.has_value()) {
  ------------------
  |  Branch (7558:7): [True: 12.2k, False: 201k]
  ------------------
 7559|  12.2k|    output += '#';
 7560|  12.2k|    output.append(*hash);
 7561|  12.2k|  }
 7562|   213k|  return output;
 7563|  1.36M|}
_ZNK3ada14url_aggregator8validateEv:
 9161|   194k|[[nodiscard]] constexpr bool url_aggregator::validate() const noexcept {
 9162|   194k|  if (!is_valid) {
  ------------------
  |  Branch (9162:7): [True: 0, False: 194k]
  ------------------
 9163|      0|    return true;
 9164|      0|  }
 9165|   194k|  if (!components.check_offset_consistency()) {
  ------------------
  |  Branch (9165:7): [True: 0, False: 194k]
  ------------------
 9166|      0|    ada_log("url_aggregator::validate inconsistent components \n",
 9167|      0|            to_diagram());
 9168|      0|    return false;
 9169|      0|  }
 9170|       |  // We have a credible components struct, but let us investivate more
 9171|       |  // carefully:
 9172|       |  /**
 9173|       |   * https://user:pass@example.com:1234/foo/bar?baz#quux
 9174|       |   *       |     |    |          | ^^^^|       |   |
 9175|       |   *       |     |    |          | |   |       |   `----- hash_start
 9176|       |   *       |     |    |          | |   |       `--------- search_start
 9177|       |   *       |     |    |          | |   `----------------- pathname_start
 9178|       |   *       |     |    |          | `--------------------- port
 9179|       |   *       |     |    |          `----------------------- host_end
 9180|       |   *       |     |    `---------------------------------- host_start
 9181|       |   *       |     `--------------------------------------- username_end
 9182|       |   *       `--------------------------------------------- protocol_end
 9183|       |   */
 9184|   194k|  if (components.protocol_end == url_components::omitted) {
  ------------------
  |  Branch (9184:7): [True: 0, False: 194k]
  ------------------
 9185|      0|    ada_log("url_aggregator::validate omitted protocol_end \n", to_diagram());
 9186|      0|    return false;
 9187|      0|  }
 9188|   194k|  if (components.username_end == url_components::omitted) {
  ------------------
  |  Branch (9188:7): [True: 0, False: 194k]
  ------------------
 9189|      0|    ada_log("url_aggregator::validate omitted username_end \n", to_diagram());
 9190|      0|    return false;
 9191|      0|  }
 9192|   194k|  if (components.host_start == url_components::omitted) {
  ------------------
  |  Branch (9192:7): [True: 0, False: 194k]
  ------------------
 9193|      0|    ada_log("url_aggregator::validate omitted host_start \n", to_diagram());
 9194|      0|    return false;
 9195|      0|  }
 9196|   194k|  if (components.host_end == url_components::omitted) {
  ------------------
  |  Branch (9196:7): [True: 0, False: 194k]
  ------------------
 9197|      0|    ada_log("url_aggregator::validate omitted host_end \n", to_diagram());
 9198|      0|    return false;
 9199|      0|  }
 9200|   194k|  if (components.pathname_start == url_components::omitted) {
  ------------------
  |  Branch (9200:7): [True: 0, False: 194k]
  ------------------
 9201|      0|    ada_log("url_aggregator::validate omitted pathname_start \n", to_diagram());
 9202|      0|    return false;
 9203|      0|  }
 9204|       |
 9205|   194k|  if (components.protocol_end > buffer.size()) {
  ------------------
  |  Branch (9205:7): [True: 0, False: 194k]
  ------------------
 9206|      0|    ada_log("url_aggregator::validate protocol_end overflow \n", to_diagram());
 9207|      0|    return false;
 9208|      0|  }
 9209|   194k|  if (components.username_end > buffer.size()) {
  ------------------
  |  Branch (9209:7): [True: 0, False: 194k]
  ------------------
 9210|      0|    ada_log("url_aggregator::validate username_end overflow \n", to_diagram());
 9211|      0|    return false;
 9212|      0|  }
 9213|   194k|  if (components.host_start > buffer.size()) {
  ------------------
  |  Branch (9213:7): [True: 0, False: 194k]
  ------------------
 9214|      0|    ada_log("url_aggregator::validate host_start overflow \n", to_diagram());
 9215|      0|    return false;
 9216|      0|  }
 9217|   194k|  if (components.host_end > buffer.size()) {
  ------------------
  |  Branch (9217:7): [True: 0, False: 194k]
  ------------------
 9218|      0|    ada_log("url_aggregator::validate host_end overflow \n", to_diagram());
 9219|      0|    return false;
 9220|      0|  }
 9221|   194k|  if (components.pathname_start > buffer.size()) {
  ------------------
  |  Branch (9221:7): [True: 0, False: 194k]
  ------------------
 9222|      0|    ada_log("url_aggregator::validate pathname_start overflow \n",
 9223|      0|            to_diagram());
 9224|      0|    return false;
 9225|      0|  }
 9226|       |
 9227|   194k|  if (components.protocol_end > 0) {
  ------------------
  |  Branch (9227:7): [True: 194k, False: 0]
  ------------------
 9228|   194k|    if (buffer[components.protocol_end - 1] != ':') {
  ------------------
  |  Branch (9228:9): [True: 0, False: 194k]
  ------------------
 9229|      0|      ada_log(
 9230|      0|          "url_aggregator::validate missing : at the end of the protocol \n",
 9231|      0|          to_diagram());
 9232|      0|      return false;
 9233|      0|    }
 9234|   194k|  }
 9235|       |
 9236|   194k|  if (components.username_end != buffer.size() &&
  ------------------
  |  Branch (9236:7): [True: 194k, False: 18]
  ------------------
 9237|   194k|      components.username_end > components.protocol_end + 2) {
  ------------------
  |  Branch (9237:7): [True: 9.97k, False: 184k]
  ------------------
 9238|  9.97k|    if (buffer[components.username_end] != ':' &&
  ------------------
  |  Branch (9238:9): [True: 382, False: 9.59k]
  ------------------
 9239|    382|        buffer[components.username_end] != '@') {
  ------------------
  |  Branch (9239:9): [True: 0, False: 382]
  ------------------
 9240|      0|      ada_log(
 9241|      0|          "url_aggregator::validate missing : or @ at the end of the username "
 9242|      0|          "\n",
 9243|      0|          to_diagram());
 9244|      0|      return false;
 9245|      0|    }
 9246|  9.97k|  }
 9247|       |
 9248|   194k|  if (components.host_start != buffer.size()) {
  ------------------
  |  Branch (9248:7): [True: 194k, False: 18]
  ------------------
 9249|   194k|    if (components.host_start > components.username_end) {
  ------------------
  |  Branch (9249:9): [True: 9.63k, False: 184k]
  ------------------
 9250|  9.63k|      if (buffer[components.host_start] != '@') {
  ------------------
  |  Branch (9250:11): [True: 0, False: 9.63k]
  ------------------
 9251|      0|        ada_log(
 9252|      0|            "url_aggregator::validate missing @ at the end of the password \n",
 9253|      0|            to_diagram());
 9254|      0|        return false;
 9255|      0|      }
 9256|   184k|    } else if (components.host_start == components.username_end &&
  ------------------
  |  Branch (9256:16): [True: 184k, False: 0]
  ------------------
 9257|   184k|               components.host_end > components.host_start) {
  ------------------
  |  Branch (9257:16): [True: 184k, False: 528]
  ------------------
 9258|   184k|      if (components.host_start == components.protocol_end + 2) {
  ------------------
  |  Branch (9258:11): [True: 183k, False: 382]
  ------------------
 9259|   183k|        if (buffer[components.protocol_end] != '/' ||
  ------------------
  |  Branch (9259:13): [True: 0, False: 183k]
  ------------------
 9260|   183k|            buffer[components.protocol_end + 1] != '/') {
  ------------------
  |  Branch (9260:13): [True: 0, False: 183k]
  ------------------
 9261|      0|          ada_log(
 9262|      0|              "url_aggregator::validate missing // between protocol and host "
 9263|      0|              "\n",
 9264|      0|              to_diagram());
 9265|      0|          return false;
 9266|      0|        }
 9267|   183k|      } else {
 9268|    382|        if (components.host_start > components.protocol_end &&
  ------------------
  |  Branch (9268:13): [True: 382, False: 0]
  ------------------
 9269|    382|            buffer[components.host_start] != '@') {
  ------------------
  |  Branch (9269:13): [True: 0, False: 382]
  ------------------
 9270|      0|          ada_log(
 9271|      0|              "url_aggregator::validate missing @ at the end of the username "
 9272|      0|              "\n",
 9273|      0|              to_diagram());
 9274|      0|          return false;
 9275|      0|        }
 9276|    382|      }
 9277|   184k|    } else {
 9278|    528|      if (components.host_end != components.host_start) {
  ------------------
  |  Branch (9278:11): [True: 0, False: 528]
  ------------------
 9279|      0|        ada_log("url_aggregator::validate expected omitted host \n",
 9280|      0|                to_diagram());
 9281|      0|        return false;
 9282|      0|      }
 9283|    528|    }
 9284|   194k|  }
 9285|   194k|  if (components.host_end != buffer.size() &&
  ------------------
  |  Branch (9285:7): [True: 194k, False: 36]
  ------------------
 9286|   194k|      components.pathname_start > components.host_end) {
  ------------------
  |  Branch (9286:7): [True: 20.0k, False: 174k]
  ------------------
 9287|  20.0k|    if (components.pathname_start == components.host_end + 2 &&
  ------------------
  |  Branch (9287:9): [True: 717, False: 19.3k]
  ------------------
 9288|    717|        buffer[components.host_end] == '/' &&
  ------------------
  |  Branch (9288:9): [True: 14, False: 703]
  ------------------
 9289|     14|        buffer[components.host_end + 1] == '.') {
  ------------------
  |  Branch (9289:9): [True: 14, False: 0]
  ------------------
 9290|     14|      if (components.pathname_start + 1 >= buffer.size() ||
  ------------------
  |  Branch (9290:11): [True: 0, False: 14]
  ------------------
 9291|     14|          buffer[components.pathname_start] != '/' ||
  ------------------
  |  Branch (9291:11): [True: 0, False: 14]
  ------------------
 9292|     14|          buffer[components.pathname_start + 1] != '/') {
  ------------------
  |  Branch (9292:11): [True: 0, False: 14]
  ------------------
 9293|      0|        ada_log(
 9294|      0|            "url_aggregator::validate expected the path to begin with // \n",
 9295|      0|            to_diagram());
 9296|      0|        return false;
 9297|      0|      }
 9298|  20.0k|    } else if (buffer[components.host_end] != ':') {
  ------------------
  |  Branch (9298:16): [True: 0, False: 20.0k]
  ------------------
 9299|      0|      ada_log("url_aggregator::validate missing : at the port \n",
 9300|      0|              to_diagram());
 9301|      0|      return false;
 9302|      0|    }
 9303|  20.0k|  }
 9304|   194k|  if (components.pathname_start != buffer.size() &&
  ------------------
  |  Branch (9304:7): [True: 194k, False: 40]
  ------------------
 9305|   194k|      components.pathname_start < components.search_start &&
  ------------------
  |  Branch (9305:7): [True: 194k, False: 53]
  ------------------
 9306|   194k|      components.pathname_start < components.hash_start && !has_opaque_path) {
  ------------------
  |  Branch (9306:7): [True: 194k, False: 65]
  |  Branch (9306:60): [True: 194k, False: 169]
  ------------------
 9307|   194k|    if (buffer[components.pathname_start] != '/') {
  ------------------
  |  Branch (9307:9): [True: 0, False: 194k]
  ------------------
 9308|      0|      ada_log("url_aggregator::validate missing / at the path \n",
 9309|      0|              to_diagram());
 9310|      0|      return false;
 9311|      0|    }
 9312|   194k|  }
 9313|   194k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (9313:7): [True: 33.0k, False: 161k]
  ------------------
 9314|  33.0k|    if (buffer[components.search_start] != '?') {
  ------------------
  |  Branch (9314:9): [True: 0, False: 33.0k]
  ------------------
 9315|      0|      ada_log("url_aggregator::validate missing ? at the search \n",
 9316|      0|              to_diagram());
 9317|      0|      return false;
 9318|      0|    }
 9319|  33.0k|  }
 9320|   194k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (9320:7): [True: 23.8k, False: 170k]
  ------------------
 9321|  23.8k|    if (buffer[components.hash_start] != '#') {
  ------------------
  |  Branch (9321:9): [True: 0, False: 23.8k]
  ------------------
 9322|      0|      ada_log("url_aggregator::validate missing # at the hash \n",
 9323|      0|              to_diagram());
 9324|      0|      return false;
 9325|      0|    }
 9326|  23.8k|  }
 9327|       |
 9328|   194k|  return true;
 9329|   194k|}
_ZNK3ada14url_components24check_offset_consistencyEv:
 7655|   194k|    const noexcept {
 7656|       |  /**
 7657|       |   * https://user:pass@example.com:1234/foo/bar?baz#quux
 7658|       |   *       |     |    |          | ^^^^|       |   |
 7659|       |   *       |     |    |          | |   |       |   `----- hash_start
 7660|       |   *       |     |    |          | |   |       `--------- search_start
 7661|       |   *       |     |    |          | |   `----------------- pathname_start
 7662|       |   *       |     |    |          | `--------------------- port
 7663|       |   *       |     |    |          `----------------------- host_end
 7664|       |   *       |     |    `---------------------------------- host_start
 7665|       |   *       |     `--------------------------------------- username_end
 7666|       |   *       `--------------------------------------------- protocol_end
 7667|       |   */
 7668|       |  // These conditions can be made more strict.
 7669|   194k|  if (protocol_end == url_components::omitted) {
  ------------------
  |  Branch (7669:7): [True: 0, False: 194k]
  ------------------
 7670|      0|    return false;
 7671|      0|  }
 7672|   194k|  uint32_t index = protocol_end;
 7673|       |
 7674|   194k|  if (username_end == url_components::omitted) {
  ------------------
  |  Branch (7674:7): [True: 0, False: 194k]
  ------------------
 7675|      0|    return false;
 7676|      0|  }
 7677|   194k|  if (username_end < index) {
  ------------------
  |  Branch (7677:7): [True: 0, False: 194k]
  ------------------
 7678|      0|    return false;
 7679|      0|  }
 7680|   194k|  index = username_end;
 7681|       |
 7682|   194k|  if (host_start == url_components::omitted) {
  ------------------
  |  Branch (7682:7): [True: 0, False: 194k]
  ------------------
 7683|      0|    return false;
 7684|      0|  }
 7685|   194k|  if (host_start < index) {
  ------------------
  |  Branch (7685:7): [True: 0, False: 194k]
  ------------------
 7686|      0|    return false;
 7687|      0|  }
 7688|   194k|  index = host_start;
 7689|       |
 7690|   194k|  if (port != url_components::omitted) {
  ------------------
  |  Branch (7690:7): [True: 20.0k, False: 174k]
  ------------------
 7691|  20.0k|    if (port > 0xffff) {
  ------------------
  |  Branch (7691:9): [True: 0, False: 20.0k]
  ------------------
 7692|      0|      return false;
 7693|      0|    }
 7694|  20.0k|    uint32_t port_length = helpers::fast_digit_count(port) + 1;
 7695|  20.0k|    if (index + port_length < index) {
  ------------------
  |  Branch (7695:9): [True: 0, False: 20.0k]
  ------------------
 7696|      0|      return false;
 7697|      0|    }
 7698|  20.0k|    index += port_length;
 7699|  20.0k|  }
 7700|       |
 7701|   194k|  if (pathname_start == url_components::omitted) {
  ------------------
  |  Branch (7701:7): [True: 0, False: 194k]
  ------------------
 7702|      0|    return false;
 7703|      0|  }
 7704|   194k|  if (pathname_start < index) {
  ------------------
  |  Branch (7704:7): [True: 0, False: 194k]
  ------------------
 7705|      0|    return false;
 7706|      0|  }
 7707|   194k|  index = pathname_start;
 7708|       |
 7709|   194k|  if (search_start != url_components::omitted) {
  ------------------
  |  Branch (7709:7): [True: 33.0k, False: 161k]
  ------------------
 7710|  33.0k|    if (search_start < index) {
  ------------------
  |  Branch (7710:9): [True: 0, False: 33.0k]
  ------------------
 7711|      0|      return false;
 7712|      0|    }
 7713|  33.0k|    index = search_start;
 7714|  33.0k|  }
 7715|       |
 7716|   194k|  if (hash_start != url_components::omitted) {
  ------------------
  |  Branch (7716:7): [True: 23.8k, False: 170k]
  ------------------
 7717|  23.8k|    if (hash_start < index) {
  ------------------
  |  Branch (7717:9): [True: 0, False: 23.8k]
  ------------------
 7718|      0|      return false;
 7719|      0|    }
 7720|  23.8k|  }
 7721|       |
 7722|   194k|  return true;
 7723|   194k|}
_ZN3ada7helpers16fast_digit_countEj:
 1994|  20.0k|inline int fast_digit_count(uint32_t x) noexcept {
 1995|  20.0k|  auto int_log2 = [](uint32_t z) -> int {
 1996|  20.0k|    return 31 - ada::helpers::leading_zeroes(z | 1);
 1997|  20.0k|  };
 1998|       |  // Compiles to very few instructions. Note that the
 1999|       |  // table is static and thus effectively a constant.
 2000|       |  // We leave it inside the function because it is meaningless
 2001|       |  // outside of it (this comes at no performance cost).
 2002|  20.0k|  const static uint64_t table[] = {
 2003|  20.0k|      4294967296,  8589934582,  8589934582,  8589934582,  12884901788,
 2004|  20.0k|      12884901788, 12884901788, 17179868184, 17179868184, 17179868184,
 2005|  20.0k|      21474826480, 21474826480, 21474826480, 21474826480, 25769703776,
 2006|  20.0k|      25769703776, 25769703776, 30063771072, 30063771072, 30063771072,
 2007|  20.0k|      34349738368, 34349738368, 34349738368, 34349738368, 38554705664,
 2008|  20.0k|      38554705664, 38554705664, 41949672960, 41949672960, 41949672960,
 2009|  20.0k|      42949672960, 42949672960};
 2010|  20.0k|  return int((x + table[int_log2(x)]) >> 32);
 2011|  20.0k|}
_ZZN3ada7helpers16fast_digit_countEjENKUljE_clEj:
 1995|  20.0k|  auto int_log2 = [](uint32_t z) -> int {
 1996|  20.0k|    return 31 - ada::helpers::leading_zeroes(z | 1);
 1997|  20.0k|  };
_ZN3ada7helpers6concatIJNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKcEEENS2_12basic_stringIcS5_NS2_9allocatorIcEEEEDpT_:
 1968|   198k|std::string concat(Args... args) {
 1969|   198k|  std::string answer;
 1970|   198k|  inner_concat(answer, args...);
 1971|   198k|  return answer;
 1972|   198k|}
_ZN3ada7helpers12inner_concatINSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEJPKcEEEvRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEET_DpT0_:
 1957|   198k|inline void inner_concat(std::string& buffer, T t, Args... args) {
 1958|   198k|  buffer.append(t);
 1959|   198k|  return inner_concat(buffer, args...);
 1960|   198k|}
_ZN3ada7helpers12inner_concatIPKcJEEEvRNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEET_:
 1949|   199k|inline void inner_concat(std::string& buffer, T t) {
 1950|   199k|  buffer.append(t);
 1951|   199k|}
_ZN3ada7helpers6concatIJNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPKcEEES8_DpT_:
 1968|    605|std::string concat(Args... args) {
 1969|    605|  std::string answer;
 1970|    605|  inner_concat(answer, args...);
 1971|    605|  return answer;
 1972|    605|}
_ZN3ada7helpers12inner_concatINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEJPKcEEEvRS8_T_DpT0_:
 1957|    605|inline void inner_concat(std::string& buffer, T t, Args... args) {
 1958|    605|  buffer.append(t);
 1959|    605|  return inner_concat(buffer, args...);
 1960|    605|}
_ZN3ada3url10set_schemeEONSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
 7460|  4.87k|inline void url::set_scheme(std::string&& new_scheme) noexcept {
 7461|  4.87k|  type = ada::scheme::get_scheme_type(new_scheme);
 7462|       |  // We only move the 'scheme' if it is non-special.
 7463|  4.87k|  if (!is_special()) {
  ------------------
  |  Branch (7463:7): [True: 1.88k, False: 2.99k]
  ------------------
 7464|  1.88k|    non_special_scheme = std::move(new_scheme);
 7465|  1.88k|  }
 7466|  4.87k|}

LLVMFuzzerTestOneInput:
  212|  9.16k|extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  213|  9.16k|  FuzzedDataProvider fdp(data, size);
  214|       |
  215|  9.16k|  fuzz_one_input(make_candidate(fdp));
  216|       |
  217|  9.16k|  if (fdp.remaining_bytes() > 0) {
  ------------------
  |  Branch (217:7): [True: 5.22k, False: 3.94k]
  ------------------
  218|  5.22k|    std::string raw = fdp.ConsumeRemainingBytesAsString();
  219|  5.22k|    if (raw.size() > 512) {
  ------------------
  |  Branch (219:9): [True: 41, False: 5.17k]
  ------------------
  220|     41|      raw.resize(512);
  221|     41|    }
  222|  5.22k|    if (!raw.empty() && (static_cast<unsigned char>(raw[0]) & 1u)) {
  ------------------
  |  Branch (222:9): [True: 5.22k, False: 0]
  |  Branch (222:25): [True: 2.31k, False: 2.90k]
  ------------------
  223|  2.31k|      raw = std::string("https://") + raw;
  224|  2.90k|    } else if (!raw.empty()) {
  ------------------
  |  Branch (224:16): [True: 2.90k, False: 0]
  ------------------
  225|  2.90k|      raw = std::string("http://") + raw;
  226|  2.90k|    }
  227|  5.22k|    fuzz_one_input(raw);
  228|  5.22k|  }
  229|       |
  230|  9.16k|  static constexpr const char* kAnchors[] = {
  231|  9.16k|      "https://example.com",
  232|  9.16k|      "https://example.com/",
  233|  9.16k|      "https://example.com?q=1",
  234|  9.16k|      "https://example.com#frag",
  235|  9.16k|      "https://example.com/?q=1#frag",
  236|  9.16k|      "http://www.example.com/path/file.js",
  237|  9.16k|      "http://WWW.Example.COM/file.js",
  238|  9.16k|      "https://www.google.com/imghp?hl=en&tab=wi",
  239|  9.16k|      "http://192.168.0.1/x",
  240|  9.16k|      "http://0x7f.1/",
  241|  9.16k|      "https://user:pass@example.com/x",
  242|  9.16k|      "https://example.com:8080/x",
  243|  9.16k|      "https://example.com/a/./b/../c",
  244|  9.16k|      "https://example.com/foo/%2e%2e",
  245|  9.16k|      "https://xn--nxasmq6b.com/",
  246|  9.16k|      "https://xn--a/",
  247|  9.16k|      "http://foo.0xffffffff/",
  248|  9.16k|      "http://example.0x/",
  249|  9.16k|      "https://example.com:0080/x",
  250|  9.16k|      "http://@19%2E68.1.10.",
  251|  9.16k|      "http://19%2E68.1.10.",
  252|  9.16k|      "http://0xffffffff.",
  253|  9.16k|  };
  254|   201k|  for (const char* seed : kAnchors) {
  ------------------
  |  Branch (254:25): [True: 201k, False: 9.16k]
  ------------------
  255|   201k|    fuzz_one_input(seed);
  256|   201k|  }
  257|       |
  258|  9.16k|  return 0;
  259|  9.16k|}
simple_absolute.cc:_ZL14fuzz_one_inputNSt3__117basic_string_viewIcNS_11char_traitsIcEEEE:
  171|   215k|static void fuzz_one_input(std::string_view input) {
  172|   215k|  auto url = ada::parse<ada::url>(input);
  173|   215k|  auto agg = ada::parse<ada::url_aggregator>(input);
  174|       |
  175|   215k|  if (url.has_value() != agg.has_value()) {
  ------------------
  |  Branch (175:7): [True: 0, False: 215k]
  ------------------
  176|      0|    printf(
  177|      0|        "parse agreement failure\n"
  178|      0|        "  input: %.*s\n"
  179|      0|        "  url: %d aggregator: %d\n",
  180|      0|        static_cast<int>(input.size()), input.data(), url.has_value(),
  181|      0|        agg.has_value());
  182|      0|    abort();
  183|      0|  }
  184|       |
  185|   215k|  if (!url) {
  ------------------
  |  Branch (185:7): [True: 21.3k, False: 194k]
  ------------------
  186|  21.3k|    return;
  187|  21.3k|  }
  188|       |
  189|   194k|  check_components_agree(*url, *agg, input);
  190|   194k|  check_href_size(*url, input);
  191|   194k|  check_href_size(*agg, input);
  192|   194k|  check_reparse_idempotent(*url, input);
  193|   194k|  check_reparse_idempotent(*agg, input);
  194|       |
  195|   194k|  const std::string href = url->get_href();
  196|   194k|  url->set_href(href);
  197|   194k|  agg->set_href(href);
  198|   194k|  if (url->get_href() != std::string(agg->get_href())) {
  ------------------
  |  Branch (198:7): [True: 0, False: 194k]
  ------------------
  199|      0|    printf(
  200|      0|        "set_href agreement failure\n"
  201|      0|        "  href: %s\n",
  202|      0|        href.c_str());
  203|      0|    abort();
  204|      0|  }
  205|   194k|  check_href_size(*url, href);
  206|   194k|  check_href_size(*agg, href);
  207|       |
  208|   194k|  volatile bool valid = agg->validate();
  209|   194k|  (void)valid;
  210|   194k|}
simple_absolute.cc:_ZL22check_components_agreeRKN3ada3urlERKNS_14url_aggregatorENSt3__117basic_string_viewIcNS6_11char_traitsIcEEEE:
  148|   194k|                                   std::string_view input) {
  149|   194k|  if (u.get_protocol() != a.get_protocol() ||
  ------------------
  |  Branch (149:7): [True: 0, False: 194k]
  |  Branch (149:7): [True: 0, False: 194k]
  ------------------
  150|   194k|      u.get_href() != std::string(a.get_href()) ||
  ------------------
  |  Branch (150:7): [True: 0, False: 194k]
  ------------------
  151|   194k|      std::string(u.get_hostname()) != std::string(a.get_hostname()) ||
  ------------------
  |  Branch (151:7): [True: 0, False: 194k]
  ------------------
  152|   194k|      std::string(u.get_pathname()) != std::string(a.get_pathname()) ||
  ------------------
  |  Branch (152:7): [True: 0, False: 194k]
  ------------------
  153|   194k|      std::string(u.get_search()) != std::string(a.get_search()) ||
  ------------------
  |  Branch (153:7): [True: 0, False: 194k]
  ------------------
  154|   194k|      std::string(u.get_hash()) != std::string(a.get_hash()) ||
  ------------------
  |  Branch (154:7): [True: 0, False: 194k]
  ------------------
  155|   194k|      std::string(u.get_port()) != std::string(a.get_port()) ||
  ------------------
  |  Branch (155:7): [True: 0, False: 194k]
  ------------------
  156|   194k|      u.get_username() != std::string(a.get_username()) ||
  ------------------
  |  Branch (156:7): [True: 0, False: 194k]
  ------------------
  157|   194k|      u.get_password() != std::string(a.get_password()) ||
  ------------------
  |  Branch (157:7): [True: 0, False: 194k]
  ------------------
  158|   194k|      std::string(u.get_host()) != std::string(a.get_host())) {
  ------------------
  |  Branch (158:7): [True: 0, False: 194k]
  ------------------
  159|      0|    printf(
  160|      0|        "url vs aggregator component mismatch\n"
  161|      0|        "  input: %.*s\n"
  162|      0|        "  url href: %s\n"
  163|      0|        "  agg href: %s\n",
  164|      0|        static_cast<int>(input.size()), input.data(), u.get_href().c_str(),
  165|      0|        std::string(a.get_href()).c_str());
  166|       |    fflush(stdout);
  167|      0|    abort();
  168|      0|  }
  169|   194k|}
simple_absolute.cc:_ZL15check_href_sizeRKN3ada3urlENSt3__117basic_string_viewIcNS3_11char_traitsIcEEEE:
   94|   389k|static void check_href_size(const ada::url& u, std::string_view input) {
   95|   389k|  if (u.get_href_size() != u.get_href().size()) {
  ------------------
  |  Branch (95:7): [True: 0, False: 389k]
  ------------------
   96|      0|    printf(
   97|      0|        "get_href_size mismatch (url)\n"
   98|      0|        "  input: %.*s\n"
   99|      0|        "  size:  %zu href.size: %zu\n"
  100|      0|        "  href:  %s\n",
  101|      0|        static_cast<int>(input.size()), input.data(), u.get_href_size(),
  102|      0|        u.get_href().size(), u.get_href().c_str());
  103|      0|    abort();
  104|      0|  }
  105|   389k|}
simple_absolute.cc:_ZL15check_href_sizeRKN3ada14url_aggregatorENSt3__117basic_string_viewIcNS3_11char_traitsIcEEEE:
  108|   389k|                            std::string_view input) {
  109|   389k|  if (u.get_href_size() != u.get_href().size()) {
  ------------------
  |  Branch (109:7): [True: 0, False: 389k]
  ------------------
  110|      0|    printf(
  111|      0|        "get_href_size mismatch (aggregator)\n"
  112|      0|        "  input: %.*s\n"
  113|      0|        "  size:  %zu href.size: %zu\n"
  114|      0|        "  href:  %s\n",
  115|      0|        static_cast<int>(input.size()), input.data(), u.get_href_size(),
  116|      0|        u.get_href().size(), std::string(u.get_href()).c_str());
  117|      0|    abort();
  118|      0|  }
  119|   389k|}
simple_absolute.cc:_ZL24check_reparse_idempotentIN3ada3urlEEvRKT_NSt3__117basic_string_viewIcNS5_11char_traitsIcEEEE:
  123|   194k|                                     std::string_view input) {
  124|   194k|  const std::string href = std::string(parsed.get_href());
  125|   194k|  auto again = ada::parse<Result>(href);
  126|   194k|  if (!again) {
  ------------------
  |  Branch (126:7): [True: 0, False: 194k]
  ------------------
  127|      0|    printf(
  128|      0|        "re-parse of href failed\n"
  129|      0|        "  input: %.*s\n"
  130|      0|        "  href:  %s\n",
  131|      0|        static_cast<int>(input.size()), input.data(), href.c_str());
  132|      0|    abort();
  133|      0|  }
  134|   194k|  if (std::string(again->get_href()) != href) {
  ------------------
  |  Branch (134:7): [True: 0, False: 194k]
  ------------------
  135|      0|    printf(
  136|      0|        "href not idempotent\n"
  137|      0|        "  input: %.*s\n"
  138|      0|        "  href1: %s\n"
  139|      0|        "  href2: %s\n",
  140|      0|        static_cast<int>(input.size()), input.data(), href.c_str(),
  141|      0|        std::string(again->get_href()).c_str());
  142|      0|    abort();
  143|      0|  }
  144|   194k|}
simple_absolute.cc:_ZL24check_reparse_idempotentIN3ada14url_aggregatorEEvRKT_NSt3__117basic_string_viewIcNS5_11char_traitsIcEEEE:
  123|   194k|                                     std::string_view input) {
  124|   194k|  const std::string href = std::string(parsed.get_href());
  125|   194k|  auto again = ada::parse<Result>(href);
  126|   194k|  if (!again) {
  ------------------
  |  Branch (126:7): [True: 0, False: 194k]
  ------------------
  127|      0|    printf(
  128|      0|        "re-parse of href failed\n"
  129|      0|        "  input: %.*s\n"
  130|      0|        "  href:  %s\n",
  131|      0|        static_cast<int>(input.size()), input.data(), href.c_str());
  132|      0|    abort();
  133|      0|  }
  134|   194k|  if (std::string(again->get_href()) != href) {
  ------------------
  |  Branch (134:7): [True: 0, False: 194k]
  ------------------
  135|      0|    printf(
  136|      0|        "href not idempotent\n"
  137|      0|        "  input: %.*s\n"
  138|      0|        "  href1: %s\n"
  139|      0|        "  href2: %s\n",
  140|      0|        static_cast<int>(input.size()), input.data(), href.c_str(),
  141|      0|        std::string(again->get_href()).c_str());
  142|      0|    abort();
  143|      0|  }
  144|   194k|}
simple_absolute.cc:_ZL14make_candidateR18FuzzedDataProvider:
   74|  9.16k|static std::string make_candidate(FuzzedDataProvider& fdp) {
   75|  9.16k|  std::string out;
   76|  9.16k|  out += pick(fdp, kSchemes);
   77|  9.16k|  out += pick(fdp, kHosts);
   78|  9.16k|  out += pick(fdp, kPaths);
   79|  9.16k|  out += pick(fdp, kQueries);
   80|  9.16k|  out += pick(fdp, kFrags);
   81|       |
   82|  9.16k|  if (fdp.ConsumeBool() && !out.empty()) {
  ------------------
  |  Branch (82:7): [True: 3.13k, False: 6.02k]
  |  Branch (82:28): [True: 3.13k, False: 0]
  ------------------
   83|  3.13k|    std::string mid = fdp.ConsumeRandomLengthString(24);
   84|  3.13k|    size_t pos = fdp.ConsumeIntegralInRange<size_t>(0, out.size());
   85|  3.13k|    out.insert(pos, mid);
   86|  3.13k|  }
   87|  9.16k|  if (fdp.ConsumeBool() && !out.empty()) {
  ------------------
  |  Branch (87:7): [True: 1.96k, False: 7.19k]
  |  Branch (87:28): [True: 1.96k, False: 0]
  ------------------
   88|  1.96k|    size_t i = fdp.ConsumeIntegralInRange<size_t>(0, out.size() - 1);
   89|  1.96k|    out[i] = static_cast<char>(fdp.ConsumeIntegral<uint8_t>());
   90|  1.96k|  }
   91|  9.16k|  return out;
   92|  9.16k|}
simple_absolute.cc:_ZL4pickILm8EEPKcR18FuzzedDataProviderRAT__KS1_:
   70|  9.16k|static const char* pick(FuzzedDataProvider& fdp, const char* const (&arr)[N]) {
   71|  9.16k|  return arr[fdp.ConsumeIntegralInRange<size_t>(0, N - 1)];
   72|  9.16k|}
simple_absolute.cc:_ZL4pickILm20EEPKcR18FuzzedDataProviderRAT__KS1_:
   70|  9.16k|static const char* pick(FuzzedDataProvider& fdp, const char* const (&arr)[N]) {
   71|  9.16k|  return arr[fdp.ConsumeIntegralInRange<size_t>(0, N - 1)];
   72|  9.16k|}
simple_absolute.cc:_ZL4pickILm16EEPKcR18FuzzedDataProviderRAT__KS1_:
   70|  9.16k|static const char* pick(FuzzedDataProvider& fdp, const char* const (&arr)[N]) {
   71|  9.16k|  return arr[fdp.ConsumeIntegralInRange<size_t>(0, N - 1)];
   72|  9.16k|}
simple_absolute.cc:_ZL4pickILm6EEPKcR18FuzzedDataProviderRAT__KS1_:
   70|  9.16k|static const char* pick(FuzzedDataProvider& fdp, const char* const (&arr)[N]) {
   71|  9.16k|  return arr[fdp.ConsumeIntegralInRange<size_t>(0, N - 1)];
   72|  9.16k|}
simple_absolute.cc:_ZL4pickILm5EEPKcR18FuzzedDataProviderRAT__KS1_:
   70|  9.16k|static const char* pick(FuzzedDataProvider& fdp, const char* const (&arr)[N]) {
   71|  9.16k|  return arr[fdp.ConsumeIntegralInRange<size_t>(0, N - 1)];
   72|  9.16k|}

