_ZN3ada4idna13utf8_to_utf32EPKcmPDi:
  172|  5.14k|size_t utf8_to_utf32(const char* buf, size_t len, char32_t* utf32_output) {
  173|  5.14k|  const uint8_t* data = reinterpret_cast<const uint8_t*>(buf);
  174|  5.14k|  size_t pos = 0;
  175|  5.14k|  const char32_t* start{utf32_output};
  176|  87.6k|  while (pos < len) {
  ------------------
  |  Branch (176:10): [True: 82.9k, False: 4.67k]
  ------------------
  177|       |    // try to convert the next block of 16 ASCII bytes
  178|  82.9k|    if (pos + 16 <= len) {  // if it is safe to read 16 more
  ------------------
  |  Branch (178:9): [True: 53.7k, False: 29.2k]
  ------------------
  179|       |                            // bytes, check that they are ascii
  180|  53.7k|      uint64_t v1;
  181|  53.7k|      std::memcpy(&v1, data + pos, sizeof(uint64_t));
  182|  53.7k|      uint64_t v2;
  183|  53.7k|      std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t));
  184|  53.7k|      uint64_t v{v1 | v2};
  185|  53.7k|      if ((v & 0x8080808080808080) == 0) {
  ------------------
  |  Branch (185:11): [True: 7.79k, False: 45.9k]
  ------------------
  186|  7.79k|        size_t final_pos = pos + 16;
  187|   132k|        while (pos < final_pos) {
  ------------------
  |  Branch (187:16): [True: 124k, False: 7.79k]
  ------------------
  188|   124k|          *utf32_output++ = char32_t(buf[pos]);
  189|   124k|          pos++;
  190|   124k|        }
  191|  7.79k|        continue;
  192|  7.79k|      }
  193|  53.7k|    }
  194|  75.1k|    uint8_t leading_byte = data[pos];  // leading byte
  195|  75.1k|    if (leading_byte < 0b10000000) {
  ------------------
  |  Branch (195:9): [True: 53.0k, False: 22.1k]
  ------------------
  196|       |      // converting one ASCII byte !!!
  197|  53.0k|      *utf32_output++ = char32_t(leading_byte);
  198|  53.0k|      pos++;
  199|  53.0k|    } else if ((leading_byte & 0b11100000) == 0b11000000) {
  ------------------
  |  Branch (199:16): [True: 16.5k, False: 5.56k]
  ------------------
  200|       |      // We have a two-byte UTF-8
  201|  16.5k|      if (pos + 1 >= len) {
  ------------------
  |  Branch (201:11): [True: 64, False: 16.5k]
  ------------------
  202|     64|        return 0;
  203|     64|      }  // minimal bound checking
  204|  16.5k|      if ((data[pos + 1] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (204:11): [True: 104, False: 16.4k]
  ------------------
  205|    104|        return 0;
  206|    104|      }
  207|       |      // range check
  208|  16.4k|      uint32_t code_point =
  209|  16.4k|          (leading_byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111);
  210|  16.4k|      if (code_point < 0x80 || 0x7ff < code_point) {
  ------------------
  |  Branch (210:11): [True: 8, False: 16.4k]
  |  Branch (210:32): [True: 0, False: 16.4k]
  ------------------
  211|      8|        return 0;
  212|      8|      }
  213|  16.4k|      *utf32_output++ = char32_t(code_point);
  214|  16.4k|      pos += 2;
  215|  16.4k|    } else if ((leading_byte & 0b11110000) == 0b11100000) {
  ------------------
  |  Branch (215:16): [True: 3.80k, False: 1.76k]
  ------------------
  216|       |      // We have a three-byte UTF-8
  217|  3.80k|      if (pos + 2 >= len) {
  ------------------
  |  Branch (217:11): [True: 14, False: 3.79k]
  ------------------
  218|     14|        return 0;
  219|     14|      }  // minimal bound checking
  220|       |
  221|  3.79k|      if ((data[pos + 1] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (221:11): [True: 20, False: 3.77k]
  ------------------
  222|     20|        return 0;
  223|     20|      }
  224|  3.77k|      if ((data[pos + 2] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (224:11): [True: 8, False: 3.76k]
  ------------------
  225|      8|        return 0;
  226|      8|      }
  227|       |      // range check
  228|  3.76k|      uint32_t code_point = (leading_byte & 0b00001111) << 12 |
  229|  3.76k|                            (data[pos + 1] & 0b00111111) << 6 |
  230|  3.76k|                            (data[pos + 2] & 0b00111111);
  231|  3.76k|      if (code_point < 0x800 || 0xffff < code_point ||
  ------------------
  |  Branch (231:11): [True: 16, False: 3.74k]
  |  Branch (231:33): [True: 0, False: 3.74k]
  ------------------
  232|  3.74k|          (0xd7ff < code_point && code_point < 0xe000)) {
  ------------------
  |  Branch (232:12): [True: 618, False: 3.13k]
  |  Branch (232:35): [True: 6, False: 612]
  ------------------
  233|     22|        return 0;
  234|     22|      }
  235|  3.74k|      *utf32_output++ = char32_t(code_point);
  236|  3.74k|      pos += 3;
  237|  3.74k|    } else if ((leading_byte & 0b11111000) == 0b11110000) {  // 0b11110000
  ------------------
  |  Branch (237:16): [True: 1.63k, False: 130]
  ------------------
  238|       |      // we have a 4-byte UTF-8 word.
  239|  1.63k|      if (pos + 3 >= len) {
  ------------------
  |  Branch (239:11): [True: 26, False: 1.60k]
  ------------------
  240|     26|        return 0;
  241|     26|      }  // minimal bound checking
  242|  1.60k|      if ((data[pos + 1] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (242:11): [True: 22, False: 1.58k]
  ------------------
  243|     22|        return 0;
  244|     22|      }
  245|  1.58k|      if ((data[pos + 2] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (245:11): [True: 12, False: 1.57k]
  ------------------
  246|     12|        return 0;
  247|     12|      }
  248|  1.57k|      if ((data[pos + 3] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (248:11): [True: 10, False: 1.56k]
  ------------------
  249|     10|        return 0;
  250|     10|      }
  251|       |
  252|       |      // range check
  253|  1.56k|      uint32_t code_point = (leading_byte & 0b00000111) << 18 |
  254|  1.56k|                            (data[pos + 1] & 0b00111111) << 12 |
  255|  1.56k|                            (data[pos + 2] & 0b00111111) << 6 |
  256|  1.56k|                            (data[pos + 3] & 0b00111111);
  257|  1.56k|      if (code_point <= 0xffff || 0x10ffff < code_point) {
  ------------------
  |  Branch (257:11): [True: 14, False: 1.54k]
  |  Branch (257:35): [True: 8, False: 1.54k]
  ------------------
  258|     22|        return 0;
  259|     22|      }
  260|  1.54k|      *utf32_output++ = char32_t(code_point);
  261|  1.54k|      pos += 4;
  262|  1.54k|    } else {
  263|    130|      return 0;
  264|    130|    }
  265|  75.1k|  }
  266|  4.67k|  return utf32_output - start;
  267|  5.14k|}
_ZN3ada4idna22utf32_length_from_utf8EPKcm:
  282|  5.17k|size_t utf32_length_from_utf8(const char* buf, size_t len) {
  283|  5.17k|  const int8_t* p = reinterpret_cast<const int8_t*>(buf);
  284|  5.17k|  return std::count_if(p, std::next(p, len), [](int8_t c) {
  285|       |    // -65 is 0b10111111, anything larger in two-complement's
  286|       |    // should start a new code point.
  287|  5.17k|    return c > -65;
  288|  5.17k|  });
  289|  5.17k|}
_ZN3ada4idna9ascii_mapEPcm:
 5133|  91.1k|void ascii_map(char* input, size_t length) {
 5134|  91.1k|  auto broadcast = [](uint8_t v) -> uint64_t {
 5135|  91.1k|    return 0x101010101010101ull * v;
 5136|  91.1k|  };
 5137|  91.1k|  uint64_t broadcast_80 = broadcast(0x80);
 5138|  91.1k|  uint64_t broadcast_Ap = broadcast(128 - 'A');
 5139|  91.1k|  uint64_t broadcast_Zp = broadcast(128 - 'Z' - 1);
 5140|  91.1k|  size_t i = 0;
 5141|       |
 5142|   210k|  for (; i + 7 < length; i += 8) {
  ------------------
  |  Branch (5142:10): [True: 119k, False: 91.1k]
  ------------------
 5143|   119k|    uint64_t word{};
 5144|   119k|    std::memcpy(&word, input + i, sizeof(word));
 5145|   119k|    word ^=
 5146|   119k|        (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
 5147|   119k|    std::memcpy(input + i, &word, sizeof(word));
 5148|   119k|  }
 5149|  91.1k|  if (i < length) {
  ------------------
  |  Branch (5149:7): [True: 48.1k, False: 43.0k]
  ------------------
 5150|  48.1k|    uint64_t word{};
 5151|  48.1k|    std::memcpy(&word, input + i, length - i);
 5152|  48.1k|    word ^=
 5153|  48.1k|        (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
 5154|  48.1k|    std::memcpy(input + i, &word, length - i);
 5155|  48.1k|  }
 5156|  91.1k|}
_ZN3ada4idna3mapENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEERNS1_12basic_stringIDiS4_NS1_9allocatorIDiEEEE:
 5160|  7.70k|bool map(std::u32string_view input, std::u32string& out) {
 5161|       |  //  [Map](https://www.unicode.org/reports/tr46/#ProcessingStepMap).
 5162|  7.70k|  out.clear();
 5163|  7.70k|  if (!ensure_tables()) {
  ------------------
  |  Branch (5163:7): [True: 0, False: 7.70k]
  ------------------
 5164|      0|    return false;
 5165|      0|  }
 5166|       |
 5167|       |  // Pass 1: validate and compute exact output length.
 5168|  7.70k|  size_t out_size = 0;
 5169|   239k|  for (char32_t x : input) {
  ------------------
  |  Branch (5169:19): [True: 239k, False: 7.32k]
  ------------------
 5170|   239k|    uint16_t status = idna_lookup(static_cast<uint32_t>(x));
 5171|   239k|    if (status == IDNA_DISALLOWED) {
  ------------------
  |  Branch (5171:9): [True: 382, False: 239k]
  ------------------
 5172|    382|      return false;
 5173|    382|    }
 5174|   239k|    if (status == IDNA_VALID) {
  ------------------
  |  Branch (5174:9): [True: 187k, False: 52.3k]
  ------------------
 5175|   187k|      ++out_size;
 5176|   187k|      continue;
 5177|   187k|    }
 5178|  52.3k|    if (static_cast<size_t>(status) >= idna_utf8_mappings_size) {
  ------------------
  |  Branch (5178:9): [True: 0, False: 52.3k]
  ------------------
 5179|      0|      return false;
 5180|      0|    }
 5181|  52.3k|    out_size += utf8_count_codepoints(idna_utf8_mappings + status);
 5182|  52.3k|  }
 5183|       |
 5184|       |  // Pass 2: write into a single allocation.
 5185|  7.32k|  out.resize(out_size);
 5186|  7.32k|  size_t w = 0;
 5187|   238k|  for (char32_t x : input) {
  ------------------
  |  Branch (5187:19): [True: 238k, False: 7.32k]
  ------------------
 5188|   238k|    uint16_t status = idna_lookup(static_cast<uint32_t>(x));
 5189|   238k|    if (status == IDNA_VALID) {
  ------------------
  |  Branch (5189:9): [True: 186k, False: 52.3k]
  ------------------
 5190|   186k|      out[w++] = x;
 5191|   186k|      continue;
 5192|   186k|    }
 5193|       |    // IGNORED or mapped (status already validated in pass 1).
 5194|  52.3k|    const uint8_t* ptr = idna_utf8_mappings + status;
 5195|   112k|    while (*ptr != 0) {
  ------------------
  |  Branch (5195:12): [True: 59.7k, False: 52.3k]
  ------------------
 5196|  59.7k|      out[w++] = utf8_next(ptr);
 5197|  59.7k|    }
 5198|  52.3k|  }
 5199|  7.32k|  return true;
 5200|  7.70k|}
_ZN3ada4idna28compute_decomposition_lengthENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5293|  1.06k|    const std::u32string_view input) noexcept {
 5294|  1.06k|  bool decomposition_needed{false};
 5295|  1.06k|  size_t additional_elements{0};
 5296|  36.6k|  for (char32_t current_character : input) {
  ------------------
  |  Branch (5296:35): [True: 36.6k, False: 1.06k]
  ------------------
 5297|  36.6k|    size_t decomposition_length{0};
 5298|       |
 5299|  36.6k|    if (current_character >= hangul_sbase &&
  ------------------
  |  Branch (5299:9): [True: 10.7k, False: 25.8k]
  ------------------
 5300|  10.7k|        current_character < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (5300:9): [True: 8.91k, False: 1.84k]
  ------------------
 5301|       |      // Full NFD-style Hangul decomp for the decompose() step.
 5302|  8.91k|      decomposition_length = 2;
 5303|  8.91k|      if ((current_character - hangul_sbase) % hangul_tcount) {
  ------------------
  |  Branch (5303:11): [True: 8.31k, False: 604]
  ------------------
 5304|  8.31k|        decomposition_length = 3;
 5305|  8.31k|      }
 5306|  27.7k|    } else if (current_character < 0x110000) {
  ------------------
  |  Branch (5306:16): [True: 27.7k, False: 0]
  ------------------
 5307|  27.7k|      const uint8_t di = decomposition_index[current_character >> 8];
 5308|  27.7k|      const uint16_t* const decomposition =
 5309|  27.7k|          decomposition_block_row(di) + (current_character % 256);
 5310|  27.7k|      decomposition_length = (decomposition[1] >> 2) - (decomposition[0] >> 2);
 5311|  27.7k|      if ((decomposition_length > 0) && (decomposition[0] & 1)) {
  ------------------
  |  Branch (5311:11): [True: 1.14k, False: 26.5k]
  |  Branch (5311:41): [True: 0, False: 1.14k]
  ------------------
 5312|      0|        decomposition_length = 0;
 5313|      0|      }
 5314|  27.7k|    }
 5315|  36.6k|    if (decomposition_length != 0) {
  ------------------
  |  Branch (5315:9): [True: 10.0k, False: 26.5k]
  ------------------
 5316|  10.0k|      decomposition_needed = true;
 5317|  10.0k|      additional_elements += decomposition_length - 1;
 5318|  10.0k|    }
 5319|  36.6k|  }
 5320|  1.06k|  return {decomposition_needed, additional_elements};
 5321|  1.06k|}
_ZN3ada4idna9decomposeERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEEm:
 5323|    504|void decompose(std::u32string& input, size_t additional_elements) {
 5324|    504|  input.resize(input.size() + additional_elements);
 5325|    504|  for (size_t descending_idx = input.size(),
 5326|    504|              input_count = descending_idx - additional_elements;
 5327|  24.3k|       input_count--;) {
  ------------------
  |  Branch (5327:8): [True: 23.8k, False: 504]
  ------------------
 5328|  23.8k|    if (input[input_count] >= hangul_sbase &&
  ------------------
  |  Branch (5328:9): [True: 9.66k, False: 14.2k]
  ------------------
 5329|  9.66k|        input[input_count] < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (5329:9): [True: 8.91k, False: 746]
  ------------------
 5330|       |      // Hangul decomposition.
 5331|  8.91k|      char32_t s_index = input[input_count] - hangul_sbase;
 5332|  8.91k|      if (s_index % hangul_tcount != 0) {
  ------------------
  |  Branch (5332:11): [True: 8.31k, False: 604]
  ------------------
 5333|  8.31k|        input[--descending_idx] = hangul_tbase + s_index % hangul_tcount;
 5334|  8.31k|      }
 5335|  8.91k|      input[--descending_idx] =
 5336|  8.91k|          hangul_vbase + (s_index % hangul_ncount) / hangul_tcount;
 5337|  8.91k|      input[--descending_idx] = hangul_lbase + s_index / hangul_ncount;
 5338|  14.9k|    } else if (input[input_count] < 0x110000) {
  ------------------
  |  Branch (5338:16): [True: 14.9k, False: 0]
  ------------------
 5339|  14.9k|      const uint16_t* decomposition =
 5340|  14.9k|          decomposition_block_row(
 5341|  14.9k|              decomposition_index[input[input_count] >> 8]) +
 5342|  14.9k|          (input[input_count] % 256);
 5343|  14.9k|      uint16_t decomposition_length =
 5344|  14.9k|          (decomposition[1] >> 2) - (decomposition[0] >> 2);
 5345|  14.9k|      if (decomposition_length > 0 && (decomposition[0] & 1)) {
  ------------------
  |  Branch (5345:11): [True: 1.14k, False: 13.8k]
  |  Branch (5345:39): [True: 0, False: 1.14k]
  ------------------
 5346|      0|        decomposition_length = 0;
 5347|      0|      }
 5348|  14.9k|      if (decomposition_length > 0) {
  ------------------
  |  Branch (5348:11): [True: 1.14k, False: 13.8k]
  ------------------
 5349|  1.14k|        const size_t base = static_cast<size_t>(decomposition[0] >> 2);
 5350|  1.14k|        if (base + decomposition_length > decomposition_data_size) {
  ------------------
  |  Branch (5350:13): [True: 0, False: 1.14k]
  ------------------
 5351|      0|          input[--descending_idx] = input[input_count];
 5352|  1.14k|        } else {
 5353|  3.69k|          while (decomposition_length-- > 0) {
  ------------------
  |  Branch (5353:18): [True: 2.55k, False: 1.14k]
  ------------------
 5354|  2.55k|            input[--descending_idx] =
 5355|  2.55k|                decomposition_data[base + decomposition_length];
 5356|  2.55k|          }
 5357|  1.14k|        }
 5358|  13.8k|      } else {
 5359|  13.8k|        input[--descending_idx] = input[input_count];
 5360|  13.8k|      }
 5361|  14.9k|    } else {
 5362|      0|      input[--descending_idx] = input[input_count];
 5363|      0|    }
 5364|  23.8k|  }
 5365|    504|}
_ZN3ada4idna7get_cccEDi:
 5367|   564k|uint8_t get_ccc(char32_t c) noexcept {
 5368|   564k|  if (c >= 0x110000) {
  ------------------
  |  Branch (5368:7): [True: 0, False: 564k]
  ------------------
 5369|      0|    return 0;
 5370|      0|  }
 5371|   564k|  return ccc_block_row(ccc_index[c >> 8])[c % 256];
 5372|   564k|}
_ZN3ada4idna10sort_marksERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEE:
 5374|  1.06k|void sort_marks(std::u32string& input) {
 5375|  55.2k|  for (size_t idx = 1; idx < input.size(); idx++) {
  ------------------
  |  Branch (5375:24): [True: 54.2k, False: 1.06k]
  ------------------
 5376|  54.2k|    uint8_t ccc = get_ccc(input[idx]);
 5377|  54.2k|    if (ccc == 0) {
  ------------------
  |  Branch (5377:9): [True: 47.5k, False: 6.71k]
  ------------------
 5378|  47.5k|      continue;
 5379|  47.5k|    }
 5380|  6.71k|    auto current_character = input[idx];
 5381|  6.71k|    size_t back_idx = idx;
 5382|  38.9k|    while (back_idx != 0 && get_ccc(input[back_idx - 1]) > ccc) {
  ------------------
  |  Branch (5382:12): [True: 38.8k, False: 112]
  |  Branch (5382:29): [True: 32.2k, False: 6.60k]
  ------------------
 5383|  32.2k|      input[back_idx] = input[back_idx - 1];
 5384|  32.2k|      back_idx--;
 5385|  32.2k|    }
 5386|  6.71k|    input[back_idx] = current_character;
 5387|  6.71k|  }
 5388|  1.06k|}
_ZN3ada4idna13decompose_nfcERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEE:
 5390|  1.06k|void decompose_nfc(std::u32string& input) {
 5391|       |  /**
 5392|       |   * Decompose the domain_name string to Unicode Normalization Form C.
 5393|       |   * @see https://www.unicode.org/reports/tr46/#ProcessingStepDecompose
 5394|       |   */
 5395|  1.06k|  auto [decomposition_needed, additional_elements] =
 5396|  1.06k|      compute_decomposition_length(input);
 5397|  1.06k|  if (decomposition_needed) {
  ------------------
  |  Branch (5397:7): [True: 504, False: 558]
  ------------------
 5398|    504|    decompose(input, additional_elements);
 5399|    504|  }
 5400|  1.06k|  sort_marks(input);
 5401|  1.06k|}
_ZN3ada4idna14is_already_nfcENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5468|  8.20k|bool is_already_nfc(std::u32string_view input) noexcept {
 5469|  8.20k|  if (input.empty()) {
  ------------------
  |  Branch (5469:7): [True: 0, False: 8.20k]
  ------------------
 5470|      0|    return true;
 5471|      0|  }
 5472|  8.20k|  if (!tables_are_ready() && !ensure_tables()) {
  ------------------
  |  Branch (5472:7): [True: 0, False: 8.20k]
  |  Branch (5472:30): [True: 0, False: 0]
  ------------------
 5473|      0|    return false;
 5474|      0|  }
 5475|       |  // 1) Singleton decompositions are never NFC (e.g. U+212B ANGSTROM SIGN).
 5476|       |  //    Multi-code-point decomps are primary composites that are NFC as-is.
 5477|   269k|  for (char32_t c : input) {
  ------------------
  |  Branch (5477:19): [True: 269k, False: 8.20k]
  ------------------
 5478|   269k|    if (canonical_decomp_length(c) == 1) {
  ------------------
  |  Branch (5478:9): [True: 0, False: 269k]
  ------------------
 5479|      0|      return false;
 5480|      0|    }
 5481|   269k|  }
 5482|       |  // 2) Combining marks already in canonical order.
 5483|  8.20k|  uint8_t prev_ccc = 0;
 5484|   246k|  for (char32_t c : input) {
  ------------------
  |  Branch (5484:19): [True: 246k, False: 7.51k]
  ------------------
 5485|   246k|    uint8_t ccc = get_ccc(c);
 5486|   246k|    if (ccc != 0 && prev_ccc > ccc) {
  ------------------
  |  Branch (5486:9): [True: 7.64k, False: 238k]
  |  Branch (5486:21): [True: 688, False: 6.95k]
  ------------------
 5487|    688|      return false;
 5488|    688|    }
 5489|   245k|    prev_ccc = ccc;
 5490|   245k|  }
 5491|       |  // 3) No pairwise composition would apply (including Hangul L+V / LV+T).
 5492|  7.51k|  return !would_compose(input);
 5493|  8.20k|}
_ZN3ada4idna7composeERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEE:
 5495|  1.06k|void compose(std::u32string& input) {
 5496|       |  /**
 5497|       |   * Compose the domain_name string to Unicode Normalization Form C.
 5498|       |   * @see https://www.unicode.org/reports/tr46/#ProcessingStepCompose
 5499|       |   */
 5500|  1.06k|  size_t input_count{0};
 5501|  1.06k|  size_t composition_count{0};
 5502|  32.8k|  for (; input_count < input.size(); input_count++, composition_count++) {
  ------------------
  |  Branch (5502:10): [True: 31.8k, False: 1.06k]
  ------------------
 5503|  31.8k|    input[composition_count] = input[input_count];
 5504|  31.8k|    if (input[input_count] >= hangul_lbase &&
  ------------------
  |  Branch (5504:9): [True: 14.8k, False: 16.9k]
  ------------------
 5505|  14.8k|        input[input_count] < hangul_lbase + hangul_lcount) {
  ------------------
  |  Branch (5505:9): [True: 10.5k, False: 4.30k]
  ------------------
 5506|  10.5k|      if (input_count + 1 < input.size() &&
  ------------------
  |  Branch (5506:11): [True: 10.4k, False: 52]
  ------------------
 5507|  10.4k|          input[input_count + 1] >= hangul_vbase &&
  ------------------
  |  Branch (5507:11): [True: 9.53k, False: 916]
  ------------------
 5508|  9.53k|          input[input_count + 1] < hangul_vbase + hangul_vcount) {
  ------------------
  |  Branch (5508:11): [True: 9.04k, False: 494]
  ------------------
 5509|  9.04k|        input[composition_count] =
 5510|  9.04k|            hangul_sbase +
 5511|  9.04k|            ((input[input_count] - hangul_lbase) * hangul_vcount +
 5512|  9.04k|             input[input_count + 1] - hangul_vbase) *
 5513|  9.04k|                hangul_tcount;
 5514|  9.04k|        input_count++;
 5515|  9.04k|        if (input_count + 1 < input.size() &&
  ------------------
  |  Branch (5515:13): [True: 9.00k, False: 42]
  ------------------
 5516|  9.00k|            input[input_count + 1] > hangul_tbase &&
  ------------------
  |  Branch (5516:13): [True: 8.41k, False: 584]
  ------------------
 5517|  8.41k|            input[input_count + 1] < hangul_tbase + hangul_tcount) {
  ------------------
  |  Branch (5517:13): [True: 8.31k, False: 104]
  ------------------
 5518|  8.31k|          input[composition_count] += input[++input_count] - hangul_tbase;
 5519|  8.31k|        }
 5520|  9.04k|      }
 5521|  21.2k|    } else if (input[input_count] >= hangul_sbase &&
  ------------------
  |  Branch (5521:16): [True: 1.53k, False: 19.7k]
  ------------------
 5522|  1.53k|               input[input_count] < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (5522:16): [True: 0, False: 1.53k]
  ------------------
 5523|      0|      if ((input[input_count] - hangul_sbase) % hangul_tcount &&
  ------------------
  |  Branch (5523:11): [True: 0, False: 0]
  ------------------
 5524|      0|          input_count + 1 < input.size() &&
  ------------------
  |  Branch (5524:11): [True: 0, False: 0]
  ------------------
 5525|      0|          input[input_count + 1] > hangul_tbase &&
  ------------------
  |  Branch (5525:11): [True: 0, False: 0]
  ------------------
 5526|      0|          input[input_count + 1] < hangul_tbase + hangul_tcount) {
  ------------------
  |  Branch (5526:11): [True: 0, False: 0]
  ------------------
 5527|      0|        input[composition_count] += input[++input_count] - hangul_tbase;
 5528|      0|      }
 5529|  21.2k|    } else if (input[input_count] < 0x110000) {
  ------------------
  |  Branch (5529:16): [True: 21.2k, False: 0]
  ------------------
 5530|  21.2k|      const uint16_t* composition =
 5531|  21.2k|          composition_block_row(composition_index[input[input_count] >> 8]) +
 5532|  21.2k|          (input[input_count] % 256);
 5533|  21.2k|      size_t initial_composition_count = composition_count;
 5534|  27.4k|      for (int32_t previous_ccc = -1; input_count + 1 < input.size();
  ------------------
  |  Branch (5534:39): [True: 26.5k, False: 902]
  ------------------
 5535|  26.5k|           input_count++) {
 5536|  26.5k|        uint8_t ccc = get_ccc(input[input_count + 1]);
 5537|       |
 5538|  26.5k|        if (composition[1] != composition[0] && previous_ccc < ccc) {
  ------------------
  |  Branch (5538:13): [True: 9.31k, False: 17.2k]
  |  Branch (5538:49): [True: 8.51k, False: 802]
  ------------------
 5539|  8.51k|          int left = composition[0];
 5540|  8.51k|          int right = composition[1];
 5541|  8.51k|          if (left < 0 || right < left ||
  ------------------
  |  Branch (5541:15): [True: 0, False: 8.51k]
  |  Branch (5541:27): [True: 0, False: 8.51k]
  ------------------
 5542|  8.51k|              static_cast<size_t>(right) > composition_data_size) {
  ------------------
  |  Branch (5542:15): [True: 0, False: 8.51k]
  ------------------
 5543|      0|            break;
 5544|      0|          }
 5545|  25.9k|          while (left + 2 < right) {
  ------------------
  |  Branch (5545:18): [True: 17.4k, False: 8.51k]
  ------------------
 5546|  17.4k|            int middle = left + (((right - left) >> 1) & ~1);
 5547|  17.4k|            if (composition_data[static_cast<size_t>(middle)] <=
  ------------------
  |  Branch (5547:17): [True: 4.00k, False: 13.4k]
  ------------------
 5548|  17.4k|                input[input_count + 1]) {
 5549|  4.00k|              left = middle;
 5550|  4.00k|            }
 5551|  17.4k|            if (composition_data[static_cast<size_t>(middle)] >=
  ------------------
  |  Branch (5551:17): [True: 14.4k, False: 2.99k]
  ------------------
 5552|  17.4k|                input[input_count + 1]) {
 5553|  14.4k|              right = middle;
 5554|  14.4k|            }
 5555|  17.4k|          }
 5556|  8.51k|          if (static_cast<size_t>(left + 1) < composition_data_size &&
  ------------------
  |  Branch (5556:15): [True: 8.51k, False: 0]
  ------------------
 5557|  8.51k|              composition_data[static_cast<size_t>(left)] ==
  ------------------
  |  Branch (5557:15): [True: 1.87k, False: 6.64k]
  ------------------
 5558|  8.51k|                  input[input_count + 1]) {
 5559|  1.87k|            char32_t composed = composition_data[static_cast<size_t>(left + 1)];
 5560|  1.87k|            input[initial_composition_count] = composed;
 5561|  1.87k|            composition =
 5562|  1.87k|                composition_block_row(composition_index[composed >> 8]) +
 5563|  1.87k|                (composed % 256);
 5564|  1.87k|            continue;
 5565|  1.87k|          }
 5566|  8.51k|        }
 5567|       |
 5568|  24.6k|        if (ccc == 0) {
  ------------------
  |  Branch (5568:13): [True: 20.3k, False: 4.25k]
  ------------------
 5569|  20.3k|          break;
 5570|  20.3k|        }
 5571|  4.25k|        previous_ccc = ccc;
 5572|  4.25k|        input[++composition_count] = input[input_count + 1];
 5573|  4.25k|      }
 5574|  21.2k|    }
 5575|  31.8k|  }
 5576|       |
 5577|  1.06k|  if (composition_count < input_count) {
  ------------------
  |  Branch (5577:7): [True: 850, False: 212]
  ------------------
 5578|    850|    input.resize(composition_count);
 5579|    850|  }
 5580|  1.06k|}
_ZN3ada4idna9normalizeERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEE:
 5582|  1.06k|bool normalize(std::u32string& input) {
 5583|       |  /**
 5584|       |   * Normalize the characters according to IDNA (Unicode Normalization Form C).
 5585|       |   * @see https://www.unicode.org/reports/tr46/#ProcessingStepNormalize
 5586|       |   */
 5587|  1.06k|  if (!ensure_tables() || decomposition_index == nullptr ||
  ------------------
  |  Branch (5587:7): [True: 0, False: 1.06k]
  |  Branch (5587:27): [True: 0, False: 1.06k]
  ------------------
 5588|  1.06k|      composition_index == nullptr) {
  ------------------
  |  Branch (5588:7): [True: 0, False: 1.06k]
  ------------------
 5589|      0|    return false;
 5590|      0|  }
 5591|  1.06k|  if (is_already_nfc(input)) {
  ------------------
  |  Branch (5591:7): [True: 0, False: 1.06k]
  ------------------
 5592|      0|    return true;
 5593|      0|  }
 5594|  1.06k|  decompose_nfc(input);
 5595|  1.06k|  compose(input);
 5596|  1.06k|  return true;
 5597|  1.06k|}
_ZN3ada4idna17punycode_to_utf32ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEERNS1_12basic_stringIDiNS3_IDiEENS1_9allocatorIDiEEEE:
 5657|  3.32k|bool punycode_to_utf32(std::string_view input, std::u32string &out) {
 5658|  3.32k|  int32_t written_out{0};
 5659|  3.32k|  out.reserve(out.size() + input.size());
 5660|  3.32k|  uint32_t n = initial_n;
 5661|  3.32k|  int32_t i = 0;
 5662|  3.32k|  int32_t bias = initial_bias;
 5663|       |  // grab ascii content
 5664|  3.32k|  size_t end_of_ascii = input.find_last_of('-');
 5665|  3.32k|  if (end_of_ascii != std::string_view::npos) {
  ------------------
  |  Branch (5665:7): [True: 936, False: 2.38k]
  ------------------
 5666|  10.9k|    for (uint8_t c : input.substr(0, end_of_ascii)) {
  ------------------
  |  Branch (5666:20): [True: 10.9k, False: 936]
  ------------------
 5667|  10.9k|      if (c >= 0x80) {
  ------------------
  |  Branch (5667:11): [True: 0, False: 10.9k]
  ------------------
 5668|      0|        return false;
 5669|      0|      }
 5670|  10.9k|      out.push_back(c);
 5671|  10.9k|      written_out++;
 5672|  10.9k|    }
 5673|    936|    input.remove_prefix(end_of_ascii + 1);
 5674|    936|  }
 5675|  42.8k|  while (!input.empty()) {
  ------------------
  |  Branch (5675:10): [True: 39.7k, False: 3.12k]
  ------------------
 5676|  39.7k|    int32_t oldi = i;
 5677|  39.7k|    int32_t w = 1;
 5678|  58.7k|    for (int32_t k = base;; k += base) {
 5679|  58.7k|      if (input.empty()) {
  ------------------
  |  Branch (5679:11): [True: 78, False: 58.6k]
  ------------------
 5680|     78|        return false;
 5681|     78|      }
 5682|  58.6k|      uint8_t code_point = input.front();
 5683|  58.6k|      input.remove_prefix(1);
 5684|  58.6k|      int32_t digit = char_to_digit_value(code_point);
 5685|  58.6k|      if (digit < 0) {
  ------------------
  |  Branch (5685:11): [True: 38, False: 58.6k]
  ------------------
 5686|     38|        return false;
 5687|     38|      }
 5688|  58.6k|      if (digit > (0x7fffffff - i) / w) {
  ------------------
  |  Branch (5688:11): [True: 26, False: 58.6k]
  ------------------
 5689|     26|        return false;
 5690|     26|      }
 5691|  58.6k|      i = i + digit * w;
 5692|  58.6k|      int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias;
  ------------------
  |  Branch (5692:19): [True: 11.9k, False: 46.6k]
  |  Branch (5692:38): [True: 42.9k, False: 3.72k]
  ------------------
 5693|  58.6k|      if (digit < t) {
  ------------------
  |  Branch (5693:11): [True: 39.5k, False: 19.0k]
  ------------------
 5694|  39.5k|        break;
 5695|  39.5k|      }
 5696|  19.0k|      if (w > 0x7fffffff / (base - t)) {
  ------------------
  |  Branch (5696:11): [True: 0, False: 19.0k]
  ------------------
 5697|      0|        return false;
 5698|      0|      }
 5699|  19.0k|      w = w * (base - t);
 5700|  19.0k|    }
 5701|  39.5k|    bias = adapt(i - oldi, written_out + 1, oldi == 0);
 5702|  39.5k|    if (i / (written_out + 1) > int32_t(0x7fffffff - n)) {
  ------------------
  |  Branch (5702:9): [True: 56, False: 39.5k]
  ------------------
 5703|     56|      return false;
 5704|     56|    }
 5705|  39.5k|    n = n + i / (written_out + 1);
 5706|  39.5k|    i = i % (written_out + 1);
 5707|  39.5k|    if (n < 0x80) {
  ------------------
  |  Branch (5707:9): [True: 0, False: 39.5k]
  ------------------
 5708|      0|      return false;
 5709|      0|    }
 5710|  39.5k|    out.insert(out.begin() + i, n);
 5711|  39.5k|    written_out++;
 5712|  39.5k|    ++i;
 5713|  39.5k|  }
 5714|       |  // See https://github.com/whatwg/url/issues/803
 5715|       |  // Reject labels whose decoded form begins with "xn--" (double-encoded ACE).
 5716|  3.12k|  if (out.size() >= 4 && out[0] == U'x' && out[1] == U'n' && out[2] == U'-' &&
  ------------------
  |  Branch (5716:7): [True: 1.44k, False: 1.68k]
  |  Branch (5716:26): [True: 362, False: 1.08k]
  |  Branch (5716:44): [True: 226, False: 136]
  |  Branch (5716:62): [True: 112, False: 114]
  ------------------
 5717|    112|      out[3] == U'-') {
  ------------------
  |  Branch (5717:7): [True: 8, False: 104]
  ------------------
 5718|      8|    return false;
 5719|      8|  }
 5720|  3.11k|  return true;
 5721|  3.12k|}
_ZN3ada4idna17utf32_to_punycodeENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEERNS1_12basic_stringIcNS3_IcEENS1_9allocatorIcEEEE:
 5801|  14.7k|bool utf32_to_punycode(std::u32string_view input, std::string &out) {
 5802|  14.7k|  out.reserve(input.size() + out.size());
 5803|  14.7k|  uint32_t n = initial_n;
 5804|  14.7k|  int32_t d = 0;
 5805|  14.7k|  int32_t bias = initial_bias;
 5806|  14.7k|  size_t h = 0;
 5807|       |  // first push the ascii content
 5808|  57.5k|  for (uint32_t c : input) {
  ------------------
  |  Branch (5808:19): [True: 57.5k, False: 14.7k]
  ------------------
 5809|  57.5k|    if (c < 0x80) {
  ------------------
  |  Branch (5809:9): [True: 37.4k, False: 20.0k]
  ------------------
 5810|  37.4k|      ++h;
 5811|  37.4k|      out.push_back(char(c));
 5812|  37.4k|    }
 5813|  57.5k|    if (c > 0x10ffff || (c >= 0xd800 && c < 0xe000)) {
  ------------------
  |  Branch (5813:9): [True: 0, False: 57.5k]
  |  Branch (5813:26): [True: 1.25k, False: 56.2k]
  |  Branch (5813:41): [True: 0, False: 1.25k]
  ------------------
 5814|      0|      return false;
 5815|      0|    }
 5816|  57.5k|  }
 5817|  14.7k|  size_t b = h;
 5818|  14.7k|  if (b > 0) {
  ------------------
  |  Branch (5818:7): [True: 4.29k, False: 10.4k]
  ------------------
 5819|  4.29k|    out.push_back('-');
 5820|  4.29k|  }
 5821|  32.2k|  while (h < input.size()) {
  ------------------
  |  Branch (5821:10): [True: 17.5k, False: 14.7k]
  ------------------
 5822|  17.5k|    uint32_t m = 0x10FFFF;
 5823|   112k|    for (auto code_point : input) {
  ------------------
  |  Branch (5823:26): [True: 112k, False: 17.5k]
  ------------------
 5824|   112k|      if (code_point >= n && code_point < m) m = code_point;
  ------------------
  |  Branch (5824:11): [True: 29.1k, False: 83.0k]
  |  Branch (5824:30): [True: 19.2k, False: 9.82k]
  ------------------
 5825|   112k|    }
 5826|       |
 5827|  17.5k|    if ((m - n) > (0x7fffffff - d) / (h + 1)) {
  ------------------
  |  Branch (5827:9): [True: 0, False: 17.5k]
  ------------------
 5828|      0|      return false;
 5829|      0|    }
 5830|  17.5k|    d = d + int32_t((m - n) * (h + 1));
 5831|  17.5k|    n = m;
 5832|   112k|    for (auto c : input) {
  ------------------
  |  Branch (5832:17): [True: 112k, False: 17.5k]
  ------------------
 5833|   112k|      if (c < n) {
  ------------------
  |  Branch (5833:11): [True: 83.0k, False: 29.1k]
  ------------------
 5834|  83.0k|        if (d == 0x7fffffff) {
  ------------------
  |  Branch (5834:13): [True: 0, False: 83.0k]
  ------------------
 5835|      0|          return false;
 5836|      0|        }
 5837|  83.0k|        ++d;
 5838|  83.0k|      }
 5839|   112k|      if (c == n) {
  ------------------
  |  Branch (5839:11): [True: 20.0k, False: 92.0k]
  ------------------
 5840|  20.0k|        int32_t q = d;
 5841|  58.6k|        for (int32_t k = base;; k += base) {
 5842|  58.6k|          int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias;
  ------------------
  |  Branch (5842:23): [True: 30.0k, False: 28.6k]
  |  Branch (5842:42): [True: 27.1k, False: 1.45k]
  ------------------
 5843|       |
 5844|  58.6k|          if (q < t) {
  ------------------
  |  Branch (5844:15): [True: 20.0k, False: 38.6k]
  ------------------
 5845|  20.0k|            break;
 5846|  20.0k|          }
 5847|  38.6k|          out.push_back(digit_to_char(t + ((q - t) % (base - t))));
 5848|  38.6k|          q = (q - t) / (base - t);
 5849|  38.6k|        }
 5850|  20.0k|        out.push_back(digit_to_char(q));
 5851|  20.0k|        bias = adapt(d, int32_t(h + 1), h == b);
 5852|  20.0k|        d = 0;
 5853|  20.0k|        ++h;
 5854|  20.0k|      }
 5855|   112k|    }
 5856|  17.5k|    ++d;
 5857|  17.5k|    ++n;
 5858|  17.5k|  }
 5859|  14.7k|  return true;
 5860|  14.7k|}
_ZN3ada4idna14is_label_validENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5944|  17.9k|bool is_label_valid(const std::u32string_view label) {
 5945|  17.9k|  if (label.empty()) {
  ------------------
  |  Branch (5945:7): [True: 0, False: 17.9k]
  ------------------
 5946|      0|    return true;
 5947|      0|  }
 5948|  17.9k|  if (!ensure_tables() || combining_ranges == nullptr || dir_start == nullptr ||
  ------------------
  |  Branch (5948:7): [True: 0, False: 17.9k]
  |  Branch (5948:27): [True: 0, False: 17.9k]
  |  Branch (5948:58): [True: 0, False: 17.9k]
  ------------------
 5949|  17.9k|      dir_final == nullptr || dir_value == nullptr) {
  ------------------
  |  Branch (5949:7): [True: 0, False: 17.9k]
  |  Branch (5949:31): [True: 0, False: 17.9k]
  ------------------
 5950|      0|    return false;
 5951|      0|  }
 5952|       |
 5953|       |  ///////////////
 5954|       |  // We have a normalization step which ensures that we are in NFC.
 5955|       |  // If we receive punycode, we normalize and check that the normalized
 5956|       |  // version matches the original.
 5957|       |  // --------------------------------------
 5958|       |  // The label must be in Unicode Normalization Form NFC.
 5959|       |
 5960|       |  // Current URL standard indicatest that CheckHyphens is set to false.
 5961|       |  // ---------------------------------------
 5962|       |  // If CheckHyphens, the label must not contain a U+002D HYPHEN-MINUS character
 5963|       |  // in both the third and fourth positions. If CheckHyphens, the label must
 5964|       |  // neither begin nor end with a U+002D HYPHEN-MINUS character.
 5965|       |
 5966|       |  // This is not necessary because we segment the
 5967|       |  // labels by '.'.
 5968|       |  // ---------------------------------------
 5969|       |  // The label must not contain a U+002E ( . ) FULL STOP.
 5970|       |  // if (label.find('.') != std::string_view::npos) return false;
 5971|       |
 5972|       |  // The label must not begin with a combining mark.
 5973|       |  // Range membership via lower_bound on range end.
 5974|  17.9k|  const std::span<const uint32_t[2]> comb_span{combining_ranges,
 5975|  17.9k|                                               combining_range_count};
 5976|  17.9k|  const auto comb_it = std::ranges::lower_bound(
 5977|  17.9k|      comb_span, label.front(), {}, [](const auto& range) { return range[1]; });
 5978|  17.9k|  if (comb_it != comb_span.end() && label.front() >= (*comb_it)[0]) {
  ------------------
  |  Branch (5978:7): [True: 17.9k, False: 0]
  |  Branch (5978:7): [True: 90, False: 17.8k]
  |  Branch (5978:37): [True: 90, False: 17.8k]
  ------------------
 5979|     90|    return false;
 5980|     90|  }
 5981|       |  // We verify this next step as part of the mapping:
 5982|       |  // ---------------------------------------------
 5983|       |  // Each code point in the label must only have certain status values
 5984|       |  // according to Section 5, IDNA Mapping Table:
 5985|       |  // - For Transitional Processing, each value must be valid.
 5986|       |  // - For Nontransitional Processing, each value must be either valid or
 5987|       |  // deviation.
 5988|       |
 5989|       |  // If CheckJoiners, the label must satisfy the ContextJ rules from Appendix
 5990|       |  // A, in The Unicode Code Points and Internationalized Domain Names for
 5991|       |  // Applications (IDNA) [IDNA2008].
 5992|  17.8k|  constexpr static uint32_t virama[] = {
 5993|  17.8k|      0x094D,  0x09CD,  0x0A4D,  0x0ACD,  0x0B4D,  0x0BCD,  0x0C4D,  0x0CCD,
 5994|  17.8k|      0x0D3B,  0x0D3C,  0x0D4D,  0x0DCA,  0x0E3A,  0x0EBA,  0x0F84,  0x1039,
 5995|  17.8k|      0x103A,  0x1714,  0x1734,  0x17D2,  0x1A60,  0x1B44,  0x1BAA,  0x1BAB,
 5996|  17.8k|      0x1BF2,  0x1BF3,  0x2D7F,  0xA806,  0xA82C,  0xA8C4,  0xA953,  0xA9C0,
 5997|  17.8k|      0xAAF6,  0xABED,  0x10A3F, 0x11046, 0x1107F, 0x110B9, 0x11133, 0x11134,
 5998|  17.8k|      0x111C0, 0x11235, 0x112EA, 0x1134D, 0x11442, 0x114C2, 0x115BF, 0x1163F,
 5999|  17.8k|      0x116B6, 0x1172B, 0x11839, 0x1193D, 0x1193E, 0x119E0, 0x11A34, 0x11A47,
 6000|  17.8k|      0x11A99, 0x11C3F, 0x11D44, 0x11D45, 0x11D97};
 6001|  17.8k|  constexpr static uint32_t R[] = {
 6002|  17.8k|      0x622, 0x623, 0x624, 0x625, 0x627, 0x629, 0x62f, 0x630, 0x631,
 6003|  17.8k|      0x632, 0x648, 0x671, 0x672, 0x673, 0x675, 0x676, 0x677, 0x688,
 6004|  17.8k|      0x689, 0x68a, 0x68b, 0x68c, 0x68d, 0x68e, 0x68f, 0x690, 0x691,
 6005|  17.8k|      0x692, 0x693, 0x694, 0x695, 0x696, 0x697, 0x698, 0x699, 0x6c0,
 6006|  17.8k|      0x6c3, 0x6c4, 0x6c5, 0x6c6, 0x6c7, 0x6c8, 0x6c9, 0x6ca, 0x6cb,
 6007|  17.8k|      0x6cd, 0x6cf, 0x6d2, 0x6d3, 0x6d5, 0x6ee, 0x6ef, 0x710, 0x715,
 6008|  17.8k|      0x716, 0x717, 0x718, 0x719, 0x71e, 0x728, 0x72a, 0x72c, 0x72f,
 6009|  17.8k|      0x74d, 0x759, 0x75a, 0x75b, 0x854, 0x8aa, 0x8ab, 0x8ac};
 6010|  17.8k|  constexpr static uint32_t L[] = {0xa872};
 6011|  17.8k|  constexpr static uint32_t D[] = {
 6012|  17.8k|      0x620,  0x626,  0x628,  0x62a,  0x62b,  0x62c,  0x62d,  0x62e,  0x633,
 6013|  17.8k|      0x634,  0x635,  0x636,  0x637,  0x638,  0x639,  0x63a,  0x63b,  0x63c,
 6014|  17.8k|      0x63d,  0x63e,  0x63f,  0x641,  0x642,  0x643,  0x644,  0x645,  0x646,
 6015|  17.8k|      0x647,  0x649,  0x64a,  0x66e,  0x66f,  0x678,  0x679,  0x67a,  0x67b,
 6016|  17.8k|      0x67c,  0x67d,  0x67e,  0x67f,  0x680,  0x681,  0x682,  0x683,  0x684,
 6017|  17.8k|      0x685,  0x686,  0x687,  0x69a,  0x69b,  0x69c,  0x69d,  0x69e,  0x69f,
 6018|  17.8k|      0x6a0,  0x6a1,  0x6a2,  0x6a3,  0x6a4,  0x6a5,  0x6a6,  0x6a7,  0x6a8,
 6019|  17.8k|      0x6a9,  0x6aa,  0x6ab,  0x6ac,  0x6ad,  0x6ae,  0x6af,  0x6b0,  0x6b1,
 6020|  17.8k|      0x6b2,  0x6b3,  0x6b4,  0x6b5,  0x6b6,  0x6b7,  0x6b8,  0x6b9,  0x6ba,
 6021|  17.8k|      0x6bb,  0x6bc,  0x6bd,  0x6be,  0x6bf,  0x6c1,  0x6c2,  0x6cc,  0x6ce,
 6022|  17.8k|      0x6d0,  0x6d1,  0x6fa,  0x6fb,  0x6fc,  0x6ff,  0x712,  0x713,  0x714,
 6023|  17.8k|      0x71a,  0x71b,  0x71c,  0x71d,  0x71f,  0x720,  0x721,  0x722,  0x723,
 6024|  17.8k|      0x724,  0x725,  0x726,  0x727,  0x729,  0x72b,  0x72d,  0x72e,  0x74e,
 6025|  17.8k|      0x74f,  0x750,  0x751,  0x752,  0x753,  0x754,  0x755,  0x756,  0x757,
 6026|  17.8k|      0x758,  0x75c,  0x75d,  0x75e,  0x75f,  0x760,  0x761,  0x762,  0x763,
 6027|  17.8k|      0x764,  0x765,  0x766,  0x850,  0x851,  0x852,  0x853,  0x855,  0x8a0,
 6028|  17.8k|      0x8a2,  0x8a3,  0x8a4,  0x8a5,  0x8a6,  0x8a7,  0x8a8,  0x8a9,  0x1807,
 6029|  17.8k|      0x1820, 0x1821, 0x1822, 0x1823, 0x1824, 0x1825, 0x1826, 0x1827, 0x1828,
 6030|  17.8k|      0x1829, 0x182a, 0x182b, 0x182c, 0x182d, 0x182e, 0x182f, 0x1830, 0x1831,
 6031|  17.8k|      0x1832, 0x1833, 0x1834, 0x1835, 0x1836, 0x1837, 0x1838, 0x1839, 0x183a,
 6032|  17.8k|      0x183b, 0x183c, 0x183d, 0x183e, 0x183f, 0x1840, 0x1841, 0x1842, 0x1843,
 6033|  17.8k|      0x1844, 0x1845, 0x1846, 0x1847, 0x1848, 0x1849, 0x184a, 0x184b, 0x184c,
 6034|  17.8k|      0x184d, 0x184e, 0x184f, 0x1850, 0x1851, 0x1852, 0x1853, 0x1854, 0x1855,
 6035|  17.8k|      0x1856, 0x1857, 0x1858, 0x1859, 0x185a, 0x185b, 0x185c, 0x185d, 0x185e,
 6036|  17.8k|      0x185f, 0x1860, 0x1861, 0x1862, 0x1863, 0x1864, 0x1865, 0x1866, 0x1867,
 6037|  17.8k|      0x1868, 0x1869, 0x186a, 0x186b, 0x186c, 0x186d, 0x186e, 0x186f, 0x1870,
 6038|  17.8k|      0x1871, 0x1872, 0x1873, 0x1874, 0x1875, 0x1876, 0x1877, 0x1887, 0x1888,
 6039|  17.8k|      0x1889, 0x188a, 0x188b, 0x188c, 0x188d, 0x188e, 0x188f, 0x1890, 0x1891,
 6040|  17.8k|      0x1892, 0x1893, 0x1894, 0x1895, 0x1896, 0x1897, 0x1898, 0x1899, 0x189a,
 6041|  17.8k|      0x189b, 0x189c, 0x189d, 0x189e, 0x189f, 0x18a0, 0x18a1, 0x18a2, 0x18a3,
 6042|  17.8k|      0x18a4, 0x18a5, 0x18a6, 0x18a7, 0x18a8, 0x18aa, 0xa840, 0xa841, 0xa842,
 6043|  17.8k|      0xa843, 0xa844, 0xa845, 0xa846, 0xa847, 0xa848, 0xa849, 0xa84a, 0xa84b,
 6044|  17.8k|      0xa84c, 0xa84d, 0xa84e, 0xa84f, 0xa850, 0xa851, 0xa852, 0xa853, 0xa854,
 6045|  17.8k|      0xa855, 0xa856, 0xa857, 0xa858, 0xa859, 0xa85a, 0xa85b, 0xa85c, 0xa85d,
 6046|  17.8k|      0xa85e, 0xa85f, 0xa860, 0xa861, 0xa862, 0xa863, 0xa864, 0xa865, 0xa866,
 6047|  17.8k|      0xa867, 0xa868, 0xa869, 0xa86a, 0xa86b, 0xa86c, 0xa86d, 0xa86e, 0xa86f,
 6048|  17.8k|      0xa870, 0xa871};
 6049|       |
 6050|   105k|  for (size_t i = 0; i < label.size(); i++) {
  ------------------
  |  Branch (6050:22): [True: 89.0k, False: 16.8k]
  ------------------
 6051|  89.0k|    uint32_t c = label[i];
 6052|  89.0k|    if (c == 0x200c) {
  ------------------
  |  Branch (6052:9): [True: 654, False: 88.4k]
  ------------------
 6053|    654|      if (i > 0) {
  ------------------
  |  Branch (6053:11): [True: 640, False: 14]
  ------------------
 6054|    640|        if (std::ranges::binary_search(virama, label[i - 1])) {
  ------------------
  |  Branch (6054:13): [True: 128, False: 512]
  ------------------
 6055|    128|          return true;
 6056|    128|        }
 6057|    640|      }
 6058|    526|      if ((i == 0) || (i + 1 >= label.size())) {
  ------------------
  |  Branch (6058:11): [True: 14, False: 512]
  |  Branch (6058:23): [True: 70, False: 442]
  ------------------
 6059|     84|        return false;
 6060|     84|      }
 6061|       |      // we go backward looking for L or D
 6062|    442|      auto is_l_or_d = [](uint32_t code) {
 6063|    442|        return std::ranges::binary_search(L, code) ||
 6064|    442|               std::ranges::binary_search(D, code);
 6065|    442|      };
 6066|    442|      auto is_r_or_d = [](uint32_t code) {
 6067|    442|        return std::ranges::binary_search(R, code) ||
 6068|    442|               std::ranges::binary_search(D, code);
 6069|    442|      };
 6070|    442|      std::u32string_view before = label.substr(0, i);
 6071|    442|      std::u32string_view after = label.substr(i + 1);
 6072|    442|      return (std::find_if(before.begin(), before.end(), is_l_or_d) !=
  ------------------
  |  Branch (6072:14): [True: 340, False: 102]
  ------------------
 6073|    442|              before.end()) &&
 6074|    340|             (std::find_if(after.begin(), after.end(), is_r_or_d) !=
  ------------------
  |  Branch (6074:14): [True: 210, False: 130]
  ------------------
 6075|    340|              after.end());
 6076|  88.4k|    } else if (c == 0x200d) {
  ------------------
  |  Branch (6076:16): [True: 400, False: 88.0k]
  ------------------
 6077|    400|      if (i > 0) {
  ------------------
  |  Branch (6077:11): [True: 394, False: 6]
  ------------------
 6078|    394|        if (std::ranges::binary_search(virama, label[i - 1])) {
  ------------------
  |  Branch (6078:13): [True: 336, False: 58]
  ------------------
 6079|    336|          return true;
 6080|    336|        }
 6081|    394|      }
 6082|     64|      return false;
 6083|    400|    }
 6084|  89.0k|  }
 6085|       |
 6086|       |  // If CheckBidi, and if the domain name is a  Bidi domain name, then the label
 6087|       |  // must satisfy all six of the numbered conditions in [IDNA2008] RFC 5893,
 6088|       |  // Section 2.
 6089|       |
 6090|       |  // The following rule, consisting of six conditions, applies to labels
 6091|       |  // in Bidi domain names.  The requirements that this rule satisfies are
 6092|       |  // described in Section 3.  All of the conditions must be satisfied for
 6093|       |  // the rule to be satisfied.
 6094|       |  //
 6095|       |  //  1.  The first character must be a character with Bidi property L, R,
 6096|       |  //     or AL.  If it has the R or AL property, it is an RTL label; if it
 6097|       |  //     has the L property, it is an LTR label.
 6098|       |  //
 6099|       |  //  2.  In an RTL label, only characters with the Bidi properties R, AL,
 6100|       |  //      AN, EN, ES, CS, ET, ON, BN, or NSM are allowed.
 6101|       |  //
 6102|       |  //   3.  In an RTL label, the end of the label must be a character with
 6103|       |  //       Bidi property R, AL, EN, or AN, followed by zero or more
 6104|       |  //       characters with Bidi property NSM.
 6105|       |  //
 6106|       |  //   4.  In an RTL label, if an EN is present, no AN may be present, and
 6107|       |  //       vice versa.
 6108|       |  //
 6109|       |  //  5.  In an LTR label, only characters with the Bidi properties L, EN,
 6110|       |  //       ES, CS, ET, ON, BN, or NSM are allowed.
 6111|       |  //
 6112|       |  //   6.  In an LTR label, the end of the label must be a character with
 6113|       |  //       Bidi property L or EN, followed by zero or more characters with
 6114|       |  //       Bidi property NSM.
 6115|       |
 6116|  16.8k|  size_t last_non_nsm_char = find_last_not_of_nsm(label);
 6117|  16.8k|  if (last_non_nsm_char == std::u32string_view::npos) {
  ------------------
  |  Branch (6117:7): [True: 0, False: 16.8k]
  ------------------
 6118|      0|    return false;
 6119|      0|  }
 6120|       |
 6121|       |  // A "Bidi domain name" is a domain name that contains at least one RTL label.
 6122|       |  // The following rule, consisting of six conditions, applies to labels in Bidi
 6123|       |  // domain names.
 6124|  16.8k|  if (is_rtl_label(label)) {
  ------------------
  |  Branch (6124:7): [True: 3.13k, False: 13.6k]
  ------------------
 6125|       |    // The first character must be a character with Bidi property L, R,
 6126|       |    // or AL. If it has the R or AL property, it is an RTL label; if it
 6127|       |    // has the L property, it is an LTR label.
 6128|       |
 6129|  3.13k|    if (find_direction(label[0]) == direction::L) {
  ------------------
  |  Branch (6129:9): [True: 256, False: 2.87k]
  ------------------
 6130|       |      // Eval as LTR
 6131|       |
 6132|       |      // In an LTR label, only characters with the Bidi properties L, EN,
 6133|       |      // ES, CS, ET, ON, BN, or NSM are allowed.
 6134|  4.44k|      for (size_t i = 0; i <= last_non_nsm_char; i++) {
  ------------------
  |  Branch (6134:26): [True: 4.44k, False: 0]
  ------------------
 6135|  4.44k|        const direction d = find_direction(label[i]);
 6136|  4.44k|        if (!(d == direction::L || d == direction::EN || d == direction::ES ||
  ------------------
  |  Branch (6136:15): [True: 890, False: 3.55k]
  |  Branch (6136:36): [True: 314, False: 3.24k]
  |  Branch (6136:58): [True: 284, False: 2.95k]
  ------------------
 6137|  2.95k|              d == direction::CS || d == direction::ET || d == direction::ON ||
  ------------------
  |  Branch (6137:15): [True: 574, False: 2.38k]
  |  Branch (6137:37): [True: 340, False: 2.04k]
  |  Branch (6137:59): [True: 390, False: 1.65k]
  ------------------
 6138|  1.65k|              d == direction::BN || d == direction::NSM)) {
  ------------------
  |  Branch (6138:15): [True: 984, False: 668]
  |  Branch (6138:37): [True: 412, False: 256]
  ------------------
 6139|    256|          return false;
 6140|    256|        }
 6141|  4.44k|      }
 6142|       |
 6143|      0|      const direction last_dir = find_direction(label[last_non_nsm_char]);
 6144|      0|      if (!(last_dir == direction::L || last_dir == direction::EN)) {
  ------------------
  |  Branch (6144:13): [True: 0, False: 0]
  |  Branch (6144:41): [True: 0, False: 0]
  ------------------
 6145|      0|        return false;
 6146|      0|      }
 6147|       |
 6148|      0|      return true;
 6149|       |
 6150|  2.87k|    } else {
 6151|       |      // Eval as RTL
 6152|       |
 6153|       |      // The first character must be R or AL; a leading AN (or any other
 6154|       |      // direction) does not start a valid RTL label.
 6155|  2.87k|      const direction first_dir = find_direction(label[0]);
 6156|  2.87k|      if (first_dir != direction::R && first_dir != direction::AL) {
  ------------------
  |  Branch (6156:11): [True: 1.88k, False: 998]
  |  Branch (6156:40): [True: 38, False: 1.84k]
  ------------------
 6157|     38|        return false;
 6158|     38|      }
 6159|       |
 6160|  2.84k|      bool has_an = false;
 6161|  2.84k|      bool has_en = false;
 6162|  12.2k|      for (size_t i = 0; i <= last_non_nsm_char; i++) {
  ------------------
  |  Branch (6162:26): [True: 9.51k, False: 2.68k]
  ------------------
 6163|  9.51k|        const direction d = find_direction(label[i]);
 6164|       |
 6165|       |        // In an RTL label, if an EN is present, no AN may be present, and vice
 6166|       |        // versa.
 6167|  9.51k|        if ((d == direction::EN && ((has_en = true) && has_an)) ||
  ------------------
  |  Branch (6167:14): [True: 996, False: 8.52k]
  |  Branch (6167:37): [True: 996, False: 0]
  |  Branch (6167:56): [True: 6, False: 990]
  ------------------
 6168|  9.51k|            (d == direction::AN && ((has_an = true) && has_en))) {
  ------------------
  |  Branch (6168:14): [True: 870, False: 8.64k]
  |  Branch (6168:37): [True: 870, False: 0]
  |  Branch (6168:56): [True: 6, False: 864]
  ------------------
 6169|     12|          return false;
 6170|     12|        }
 6171|       |
 6172|  9.50k|        if (!(d == direction::R || d == direction::AL || d == direction::AN ||
  ------------------
  |  Branch (6172:15): [True: 1.31k, False: 8.19k]
  |  Branch (6172:36): [True: 3.11k, False: 5.07k]
  |  Branch (6172:58): [True: 864, False: 4.21k]
  ------------------
 6173|  4.21k|              d == direction::EN || d == direction::ES || d == direction::CS ||
  ------------------
  |  Branch (6173:15): [True: 990, False: 3.22k]
  |  Branch (6173:37): [True: 250, False: 2.97k]
  |  Branch (6173:59): [True: 458, False: 2.51k]
  ------------------
 6174|  2.51k|              d == direction::ET || d == direction::ON || d == direction::BN ||
  ------------------
  |  Branch (6174:15): [True: 294, False: 2.22k]
  |  Branch (6174:37): [True: 470, False: 1.75k]
  |  Branch (6174:59): [True: 1.19k, False: 562]
  ------------------
 6175|    562|              d == direction::NSM)) {
  ------------------
  |  Branch (6175:15): [True: 496, False: 66]
  ------------------
 6176|     66|          return false;
 6177|     66|        }
 6178|       |
 6179|  9.44k|        if (i == last_non_nsm_char &&
  ------------------
  |  Branch (6179:13): [True: 2.76k, False: 6.67k]
  ------------------
 6180|  2.76k|            !(d == direction::R || d == direction::AL || d == direction::AN ||
  ------------------
  |  Branch (6180:15): [True: 618, False: 2.14k]
  |  Branch (6180:36): [True: 1.41k, False: 728]
  |  Branch (6180:58): [True: 218, False: 510]
  ------------------
 6181|    510|              d == direction::EN)) {
  ------------------
  |  Branch (6181:15): [True: 432, False: 78]
  ------------------
 6182|     78|          return false;
 6183|     78|        }
 6184|  9.44k|      }
 6185|       |
 6186|  2.68k|      return true;
 6187|  2.84k|    }
 6188|  3.13k|  }
 6189|       |
 6190|  13.6k|  return true;
 6191|  16.8k|}
_ZN3ada4idna8to_asciiENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEERNS1_12basic_stringIcS4_NS1_9allocatorIcEEEE:
 6348|  96.3k|[[nodiscard]] bool to_ascii(std::string_view ut8_string, std::string& out) {
 6349|  96.3k|  out.clear();
 6350|  96.3k|  if (ut8_string.size() > max_domain_input_bytes) {
  ------------------
  |  Branch (6350:7): [True: 0, False: 96.3k]
  ------------------
 6351|      0|    return false;
 6352|      0|  }
 6353|  96.3k|  if (is_ascii(ut8_string)) {
  ------------------
  |  Branch (6353:7): [True: 91.1k, False: 5.17k]
  ------------------
 6354|  91.1k|    from_ascii_to_ascii(ut8_string, out);
 6355|  91.1k|    return true;
 6356|  91.1k|  }
 6357|       |
 6358|       |#ifdef ADA_USE_SIMDUTF
 6359|       |  size_t utf32_length =
 6360|       |      simdutf::utf32_length_from_utf8(ut8_string.data(), ut8_string.size());
 6361|       |  if (utf32_length == 0 && !ut8_string.empty()) {
 6362|       |    return false;
 6363|       |  }
 6364|       |  std::u32string working(utf32_length, U'\0');
 6365|       |  size_t actual_utf32_length = simdutf::convert_utf8_to_utf32(
 6366|       |      ut8_string.data(), ut8_string.size(), working.data());
 6367|       |#else
 6368|  5.17k|  size_t utf32_length =
 6369|  5.17k|      ada::idna::utf32_length_from_utf8(ut8_string.data(), ut8_string.size());
 6370|  5.17k|  if (utf32_length == 0 && !ut8_string.empty()) {
  ------------------
  |  Branch (6370:7): [True: 34, False: 5.14k]
  |  Branch (6370:28): [True: 34, False: 0]
  ------------------
 6371|     34|    return false;
 6372|     34|  }
 6373|  5.14k|  std::u32string working(utf32_length, U'\0');
 6374|  5.14k|  size_t actual_utf32_length = ada::idna::utf8_to_utf32(
 6375|  5.14k|      ut8_string.data(), ut8_string.size(), working.data());
 6376|  5.14k|#endif
 6377|  5.14k|  if (actual_utf32_length == 0 || actual_utf32_length != utf32_length) {
  ------------------
  |  Branch (6377:7): [True: 462, False: 4.67k]
  |  Branch (6377:35): [True: 0, False: 4.67k]
  ------------------
 6378|    462|    return false;
 6379|    462|  }
 6380|  4.67k|  working.resize(actual_utf32_length);
 6381|       |
 6382|       |  // Map into a second buffer with exact sizing (no growth reallocs).
 6383|  4.67k|  std::u32string mapped;
 6384|  4.67k|  if (!ada::idna::map(working, mapped)) {
  ------------------
  |  Branch (6384:7): [True: 96, False: 4.58k]
  ------------------
 6385|     96|    return false;
 6386|     96|  }
 6387|       |  // Drop UTF-32 input; reuse `working` as scratch for ACE validation below.
 6388|  4.58k|  working.clear();
 6389|       |
 6390|       |  // Skip NFC when already normalized (ASCII is a fast subset of this check).
 6391|  4.58k|  if (!is_ascii(mapped) && !is_already_nfc(mapped)) {
  ------------------
  |  Branch (6391:7): [True: 4.50k, False: 82]
  |  Branch (6391:28): [True: 614, False: 3.88k]
  ------------------
 6392|    614|    if (!normalize(mapped)) {
  ------------------
  |  Branch (6392:9): [True: 0, False: 614]
  ------------------
 6393|      0|      return false;
 6394|      0|    }
 6395|    614|  }
 6396|       |
 6397|       |  // Estimate ASCII output size (punycode may expand non-ASCII labels).
 6398|  4.58k|  out.reserve(mapped.size() + 8);
 6399|       |
 6400|       |  // Walk labels with a single pointer scan (no repeated string::find).
 6401|  4.58k|  const char32_t* p = mapped.data();
 6402|  4.58k|  const char32_t* const end = p + mapped.size();
 6403|  4.58k|  std::u32string post_map;
 6404|       |
 6405|  26.6k|  while (p < end) {
  ------------------
  |  Branch (6405:10): [True: 24.0k, False: 2.65k]
  ------------------
 6406|  24.0k|    const char32_t* label_begin = p;
 6407|   197k|    while (p < end && *p != U'.') {
  ------------------
  |  Branch (6407:12): [True: 193k, False: 4.17k]
  |  Branch (6407:23): [True: 173k, False: 19.8k]
  ------------------
 6408|   173k|      ++p;
 6409|   173k|    }
 6410|  24.0k|    const size_t label_size = static_cast<size_t>(p - label_begin);
 6411|  24.0k|    std::u32string_view label_view(label_begin, label_size);
 6412|  24.0k|    const bool is_last_label = (p == end);
 6413|  24.0k|    if (p < end) {
  ------------------
  |  Branch (6413:9): [True: 19.8k, False: 4.17k]
  ------------------
 6414|  19.8k|      ++p;  // skip dot
 6415|  19.8k|    }
 6416|       |
 6417|  24.0k|    if (label_size == 0) {
  ------------------
  |  Branch (6417:9): [True: 2.45k, False: 21.5k]
  ------------------
 6418|       |      // empty label
 6419|  21.5k|    } else if (is_ace_prefix(label_view)) {
  ------------------
  |  Branch (6419:16): [True: 3.37k, False: 18.2k]
  ------------------
 6420|  86.8k|      for (char32_t c : label_view) {
  ------------------
  |  Branch (6420:23): [True: 86.8k, False: 3.32k]
  ------------------
 6421|  86.8k|        if (c >= 0x80) {
  ------------------
  |  Branch (6421:13): [True: 52, False: 86.8k]
  ------------------
 6422|     52|          out.clear();
 6423|     52|          return false;
 6424|     52|        }
 6425|  86.8k|      }
 6426|  3.32k|      append_ascii_label(out, label_view);
 6427|  3.32k|      std::string_view puny_segment_ascii(
 6428|  3.32k|          out.data() + (out.size() - label_size) + 4, label_size - 4);
 6429|  3.32k|      working.clear();
 6430|  3.32k|      if (!ada::idna::punycode_to_utf32(puny_segment_ascii, working)) {
  ------------------
  |  Branch (6430:11): [True: 206, False: 3.11k]
  ------------------
 6431|    206|        out.clear();
 6432|    206|        return false;
 6433|    206|      }
 6434|  3.11k|      if (is_ascii(working)) {
  ------------------
  |  Branch (6434:11): [True: 88, False: 3.03k]
  ------------------
 6435|     88|        out.clear();
 6436|     88|        return false;
 6437|     88|      }
 6438|  3.03k|      if (!ada::idna::map(working, post_map) || working != post_map) {
  ------------------
  |  Branch (6438:11): [True: 286, False: 2.74k]
  |  Branch (6438:49): [True: 100, False: 2.64k]
  ------------------
 6439|    386|        out.clear();
 6440|    386|        return false;
 6441|    386|      }
 6442|       |      // Mapping must be stable; NFC must not change the mapped form either.
 6443|  2.64k|      if (!is_ascii(post_map) && !is_already_nfc(post_map)) {
  ------------------
  |  Branch (6443:11): [True: 2.64k, False: 0]
  |  Branch (6443:34): [True: 448, False: 2.19k]
  ------------------
 6444|    448|        if (!normalize(post_map) || post_map != working) {
  ------------------
  |  Branch (6444:13): [True: 0, False: 448]
  |  Branch (6444:37): [True: 272, False: 176]
  ------------------
 6445|    272|          out.clear();
 6446|    272|          return false;
 6447|    272|        }
 6448|    448|      }
 6449|  2.37k|      if (post_map.empty() || !is_label_valid(post_map)) {
  ------------------
  |  Branch (6449:11): [True: 0, False: 2.37k]
  |  Branch (6449:31): [True: 42, False: 2.33k]
  ------------------
 6450|     42|        out.clear();
 6451|     42|        return false;
 6452|     42|      }
 6453|  18.2k|    } else if (is_ascii(label_view)) {
  ------------------
  |  Branch (6453:16): [True: 2.60k, False: 15.6k]
  ------------------
 6454|  2.60k|      append_ascii_label(out, label_view);
 6455|  15.6k|    } else {
 6456|  15.6k|      if (!is_label_valid(label_view)) {
  ------------------
  |  Branch (6456:11): [True: 878, False: 14.7k]
  ------------------
 6457|    878|        out.clear();
 6458|    878|        return false;
 6459|    878|      }
 6460|  14.7k|      out.append("xn--");
 6461|  14.7k|      if (!ada::idna::utf32_to_punycode(label_view, out)) {
  ------------------
  |  Branch (6461:11): [True: 0, False: 14.7k]
  ------------------
 6462|      0|        out.clear();
 6463|      0|        return false;
 6464|      0|      }
 6465|  14.7k|    }
 6466|  22.1k|    if (!is_last_label) {
  ------------------
  |  Branch (6466:9): [True: 19.5k, False: 2.52k]
  ------------------
 6467|  19.5k|      out.push_back('.');
 6468|  19.5k|    }
 6469|  22.1k|  }
 6470|  2.65k|  return true;
 6471|  4.58k|}
_ZN3ada4idna8to_asciiENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6473|  96.3k|std::string to_ascii(std::string_view ut8_string) {
 6474|  96.3k|  std::string out;
 6475|  96.3k|  if (!to_ascii(ut8_string, out)) {
  ------------------
  |  Branch (6475:7): [True: 2.51k, False: 93.8k]
  ------------------
 6476|  2.51k|    return {};
 6477|  2.51k|  }
 6478|  93.8k|  return out;
 6479|  96.3k|}
_ZN3ada7unicode14percent_decodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEm:
 7165|    874|std::string percent_decode(const std::string_view input, size_t first_percent) {
 7166|       |  // next line is for safety only, we expect users to avoid calling
 7167|       |  // percent_decode when first_percent is outside the range.
 7168|    874|  if (first_percent == std::string_view::npos) {
  ------------------
  |  Branch (7168:7): [True: 0, False: 874]
  ------------------
 7169|      0|    return std::string(input);
 7170|      0|  }
 7171|    874|  std::string dest;
 7172|    874|  dest.reserve(input.length());
 7173|    874|  dest.append(input.substr(0, first_percent));
 7174|    874|  const char* pointer = input.data() + first_percent;
 7175|    874|  const char* end = input.data() + input.size();
 7176|       |  // Optimization opportunity: if the following code gets
 7177|       |  // called often, it can be optimized quite a bit.
 7178|  37.5k|  while (pointer < end) {
  ------------------
  |  Branch (7178:10): [True: 36.6k, False: 874]
  ------------------
 7179|  36.6k|    const char ch = pointer[0];
 7180|  36.6k|    size_t remaining = end - pointer - 1;
 7181|  36.6k|    if (ch != '%' || remaining < 2 ||
  ------------------
  |  Branch (7181:9): [True: 32.7k, False: 3.91k]
  |  Branch (7181:22): [True: 104, False: 3.80k]
  ------------------
 7182|  3.80k|        (  // ch == '%' && // It is unnecessary to check that ch == '%'.
 7183|  3.80k|            (!is_ascii_hex_digit(pointer[1]) ||
  ------------------
  |  Branch (7183:14): [True: 1.08k, False: 2.72k]
  ------------------
 7184|  34.5k|             !is_ascii_hex_digit(pointer[2])))) {
  ------------------
  |  Branch (7184:14): [True: 556, False: 2.16k]
  ------------------
 7185|  34.5k|      dest += ch;
 7186|  34.5k|      pointer++;
 7187|  34.5k|    } else {
 7188|  2.16k|      unsigned a = convert_hex_to_binary(pointer[1]);
 7189|  2.16k|      unsigned b = convert_hex_to_binary(pointer[2]);
 7190|  2.16k|      char c = static_cast<char>(a * 16 + b);
 7191|  2.16k|      dest += c;
 7192|  2.16k|      pointer += 3;
 7193|  2.16k|    }
 7194|  36.6k|  }
 7195|    874|  return dest;
 7196|    874|}
_ZN3ada7unicode14percent_encodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKh:
 7281|   137k|                           const uint8_t character_set[]) {
 7282|   137k|  auto pointer = std::ranges::find_if(input, [character_set](const char c) {
 7283|   137k|    return character_sets::bit_at(character_set, c);
 7284|   137k|  });
 7285|       |  // Optimization: Don't iterate if percent encode is not required
 7286|   137k|  if (pointer == input.end()) {
  ------------------
  |  Branch (7286:7): [True: 133k, False: 4.31k]
  ------------------
 7287|   133k|    return std::string(input);
 7288|   133k|  }
 7289|       |
 7290|  4.31k|  std::string result;
 7291|  4.31k|  result.reserve(input.length());  // in the worst case, percent encoding might
 7292|       |                                   // produce 3 characters.
 7293|  4.31k|  result.append(input.substr(0, std::distance(input.begin(), pointer)));
 7294|       |
 7295|  77.6k|  for (; pointer != input.end(); pointer++) {
  ------------------
  |  Branch (7295:10): [True: 73.3k, False: 4.31k]
  ------------------
 7296|  73.3k|    if (character_sets::bit_at(character_set, *pointer)) {
  ------------------
  |  Branch (7296:9): [True: 60.8k, False: 12.4k]
  ------------------
 7297|  60.8k|      result.append(character_sets::hex + uint8_t(*pointer) * 4, 3);
 7298|  60.8k|    } else {
 7299|  12.4k|      result += *pointer;
 7300|  12.4k|    }
 7301|  73.3k|  }
 7302|       |
 7303|  4.31k|  return result;
 7304|   137k|}
_ZN3ada7unicode8to_asciiERNSt3__18optionalINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEENS1_17basic_string_viewIcS5_EEm:
 7342|  96.3k|              size_t first_percent) {
 7343|  96.3k|  std::string percent_decoded_buffer;
 7344|  96.3k|  std::string_view input = plain;
 7345|  96.3k|  if (first_percent != std::string_view::npos) {
  ------------------
  |  Branch (7345:7): [True: 874, False: 95.4k]
  ------------------
 7346|    874|    percent_decoded_buffer = unicode::percent_decode(plain, first_percent);
 7347|    874|    input = percent_decoded_buffer;
 7348|    874|  }
 7349|       |  // input is a non-empty UTF-8 string, must be percent decoded
 7350|  96.3k|  std::string idna_ascii = ada::idna::to_ascii(input);
 7351|  96.3k|  if (idna_ascii.empty() || contains_forbidden_domain_code_point(
  ------------------
  |  Branch (7351:7): [True: 2.53k, False: 93.8k]
  |  Branch (7351:29): [True: 984, False: 92.8k]
  ------------------
 7352|  93.8k|                                idna_ascii.data(), idna_ascii.size())) {
 7353|  3.51k|    return false;
 7354|  3.51k|  }
 7355|  92.8k|  out = std::move(idna_ascii);
 7356|  92.8k|  return true;
 7357|  96.3k|}
_ZN3ada7unicode14percent_encodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKhm:
 7360|     59|                           const uint8_t character_set[], size_t index) {
 7361|     59|  std::string out;
 7362|       |  // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage)
 7363|     59|  out.append(input.data(), index);
 7364|     59|  auto pointer = input.begin() + index;
 7365|    754|  for (; pointer != input.end(); pointer++) {
  ------------------
  |  Branch (7365:10): [True: 695, False: 59]
  ------------------
 7366|    695|    if (character_sets::bit_at(character_set, *pointer)) {
  ------------------
  |  Branch (7366:9): [True: 313, False: 382]
  ------------------
 7367|    313|      out.append(character_sets::hex + uint8_t(*pointer) * 4, 3);
 7368|    382|    } else {
 7369|    382|      out += *pointer;
 7370|    382|    }
 7371|    695|  }
 7372|     59|  return out;
 7373|     59|}
_ZN3ada11serializers36find_longest_sequence_of_ipv6_piecesERKNSt3__15arrayItLm8EEERmS6_:
 7437|    848|    size_t& compress_length) noexcept {
 7438|    848|  compress = 0;
 7439|    848|  compress_length = 0;
 7440|    848|  size_t i = 0;
 7441|  3.41k|  while (i < 8) {
  ------------------
  |  Branch (7441:10): [True: 2.56k, False: 848]
  ------------------
 7442|  2.56k|    if (address[i] != 0) {
  ------------------
  |  Branch (7442:9): [True: 1.51k, False: 1.05k]
  ------------------
 7443|  1.51k|      ++i;
 7444|  1.51k|      continue;
 7445|  1.51k|    }
 7446|  1.05k|    size_t next = i + 1;
 7447|  5.27k|    while (next < 8 && address[next] == 0) {
  ------------------
  |  Branch (7447:12): [True: 4.84k, False: 426]
  |  Branch (7447:24): [True: 4.21k, False: 630]
  ------------------
 7448|  4.21k|      ++next;
 7449|  4.21k|    }
 7450|  1.05k|    const size_t count = next - i;
 7451|  1.05k|    if (count > compress_length) {
  ------------------
  |  Branch (7451:9): [True: 910, False: 146]
  ------------------
 7452|    910|      compress_length = count;
 7453|    910|      compress = i;
 7454|    910|    }
 7455|  1.05k|    i = next;
 7456|  1.05k|  }
 7457|    848|}
_ZN3ada11serializers4ipv6ERKNSt3__15arrayItLm8EEE:
 7459|    848|std::string ipv6(const std::array<uint16_t, 8>& address) {
 7460|    848|  size_t compress = 0;
 7461|    848|  size_t compress_length = 0;
 7462|    848|  find_longest_sequence_of_ipv6_pieces(address, compress, compress_length);
 7463|       |
 7464|       |  // Skip compression when the longest zero run is a single piece.
 7465|    848|  if (compress_length <= 1) {
  ------------------
  |  Branch (7465:7): [True: 62, False: 786]
  ------------------
 7466|     62|    compress = compress_length = 8;
 7467|     62|  }
 7468|       |
 7469|       |  // Max: '[' + 8*4 hex + 7 ':' + ']' = 41
 7470|    848|  std::string output(4 * 8 + 7 + 2, '\0');
 7471|    848|  char* point = output.data();
 7472|    848|  *point++ = '[';
 7473|    848|  size_t piece_index = 0;
 7474|  2.20k|  while (true) {
  ------------------
  |  Branch (7474:10): [True: 2.20k, Folded]
  ------------------
 7475|  2.20k|    if (piece_index == compress) {
  ------------------
  |  Branch (7475:9): [True: 786, False: 1.41k]
  ------------------
 7476|    786|      *point++ = ':';
 7477|       |      // If we skip a value initially, we need to write '::'.
 7478|    786|      if (piece_index == 0) {
  ------------------
  |  Branch (7478:11): [True: 448, False: 338]
  ------------------
 7479|    448|        *point++ = ':';
 7480|    448|      }
 7481|    786|      piece_index += compress_length;
 7482|    786|      if (piece_index == 8) {
  ------------------
  |  Branch (7482:11): [True: 382, False: 404]
  ------------------
 7483|    382|        break;
 7484|    382|      }
 7485|    786|    }
 7486|  1.82k|    point = write_hex_u16(point, address[piece_index]);
 7487|  1.82k|    ++piece_index;
 7488|  1.82k|    if (piece_index == 8) {
  ------------------
  |  Branch (7488:9): [True: 466, False: 1.35k]
  ------------------
 7489|    466|      break;
 7490|    466|    }
 7491|  1.35k|    *point++ = ':';
 7492|  1.35k|  }
 7493|    848|  *point++ = ']';
 7494|    848|  output.resize(static_cast<size_t>(point - output.data()));
 7495|    848|  return output;
 7496|    848|}
_ZN3ada11serializers4ipv4Em:
 7498|  16.7k|std::string ipv4(const uint64_t address) {
 7499|  16.7k|  std::string output(15, '\0');
 7500|  16.7k|  char* point = output.data();
 7501|  16.7k|  point = write_u8(point, static_cast<uint8_t>(address >> 24));
 7502|  16.7k|  *point++ = '.';
 7503|  16.7k|  point = write_u8(point, static_cast<uint8_t>(address >> 16));
 7504|  16.7k|  *point++ = '.';
 7505|  16.7k|  point = write_u8(point, static_cast<uint8_t>(address >> 8));
 7506|  16.7k|  *point++ = '.';
 7507|  16.7k|  point = write_u8(point, static_cast<uint8_t>(address));
 7508|  16.7k|  output.resize(static_cast<size_t>(point - output.data()));
 7509|  16.7k|  return output;
 7510|  16.7k|}
_ZN3ada5parseINS_3urlEEEN2tl8expectedIT_NS_6errorsEEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEPKS4_:
 7782|   357k|    std::string_view input, const result_type* base_url) {
 7783|   357k|  result_type u = ada::parser::parse_url_impl<result_type>(input, base_url);
 7784|   357k|  if (!u.is_valid) {
  ------------------
  |  Branch (7784:7): [True: 2.88k, False: 354k]
  ------------------
 7785|  2.88k|    return tl::unexpected(errors::type_error);
 7786|  2.88k|  }
 7787|   354k|  return u;
 7788|   357k|}
_ZN3ada5parseINS_14url_aggregatorEEEN2tl8expectedIT_NS_6errorsEEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEPKS4_:
 7782|   357k|    std::string_view input, const result_type* base_url) {
 7783|   357k|  result_type u = ada::parser::parse_url_impl<result_type>(input, base_url);
 7784|   357k|  if (!u.is_valid) {
  ------------------
  |  Branch (7784:7): [True: 2.88k, False: 354k]
  ------------------
 7785|  2.88k|    return tl::unexpected(errors::type_error);
 7786|  2.88k|  }
 7787|   354k|  return u;
 7788|   357k|}
_ZN3ada20get_max_input_lengthEv:
 7531|   952k|uint32_t get_max_input_length() {
 7532|   952k|  return max_input_length_.load(std::memory_order_relaxed);
 7533|   952k|}
_ZN3ada7helpers18trim_c0_whitespaceERNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8724|   321k|void trim_c0_whitespace(std::string_view& input) noexcept {
 8725|   322k|  while (!input.empty() &&
  ------------------
  |  Branch (8725:10): [True: 322k, False: 0]
  ------------------
 8726|   322k|         ada::unicode::is_c0_control_or_space(input.front())) {
  ------------------
  |  Branch (8726:10): [True: 462, False: 321k]
  ------------------
 8727|    462|    input.remove_prefix(1);
 8728|    462|  }
 8729|   325k|  while (!input.empty() && ada::unicode::is_c0_control_or_space(input.back())) {
  ------------------
  |  Branch (8729:10): [True: 325k, False: 0]
  |  Branch (8729:28): [True: 3.48k, False: 321k]
  ------------------
 8730|  3.48k|    input.remove_suffix(1);
 8731|  3.48k|  }
 8732|   321k|}
_ZN3ada3url17parse_opaque_hostENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9179|    600|bool url::parse_opaque_host(std::string_view input) {
 9180|    600|  ada_log("parse_opaque_host ", input, " [", input.size(), " bytes]");
 9181|    600|  if (std::ranges::any_of(input, ada::unicode::is_forbidden_host_code_point)) {
  ------------------
  |  Branch (9181:7): [True: 34, False: 566]
  ------------------
 9182|     34|    return is_valid = false;
 9183|     34|  }
 9184|       |
 9185|       |  // Return the result of running UTF-8 percent-encode on input using the C0
 9186|       |  // control percent-encode set.
 9187|    566|  host = ada::unicode::percent_encode(
 9188|    566|      input, ada::character_sets::C0_CONTROL_PERCENT_ENCODE);
 9189|    566|  return true;
 9190|    600|}
_ZN3ada3url10parse_ipv4ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9192|  8.63k|bool url::parse_ipv4(std::string_view input) {
 9193|  8.63k|  ada_log("parse_ipv4 ", input, " [", input.size(), " bytes]");
 9194|  8.63k|  if (input.empty()) {
  ------------------
  |  Branch (9194:7): [True: 0, False: 8.63k]
  ------------------
 9195|      0|    return is_valid = false;
 9196|      0|  }
 9197|  8.63k|  std::string_view original_input = input;
 9198|  8.63k|  if (original_input.back() == '.') {
  ------------------
  |  Branch (9198:7): [True: 46, False: 8.58k]
  ------------------
 9199|     46|    original_input.remove_suffix(1);
 9200|     46|  }
 9201|  8.63k|  if (input.back() == '.') {
  ------------------
  |  Branch (9201:7): [True: 46, False: 8.58k]
  ------------------
 9202|     46|    input.remove_suffix(1);
 9203|     46|    if (input.empty()) {
  ------------------
  |  Branch (9203:9): [True: 0, False: 46]
  ------------------
 9204|      0|      return is_valid = false;
 9205|      0|    }
 9206|     46|  }
 9207|       |
 9208|  8.63k|  const uint64_t fast = checkers::try_parse_ipv4_fast(input);
 9209|  8.63k|  if (fast < checkers::ipv4_fast_fail) [[likely]] {
  ------------------
  |  Branch (9209:7): [True: 5, False: 8.62k]
  ------------------
 9210|      5|    host = original_input;
 9211|      5|    host_type = IPV4;
 9212|      5|    return true;
 9213|      5|  }
 9214|       |
 9215|  8.62k|  const char* p = input.data();
 9216|  8.62k|  const char* end = p + input.size();
 9217|  8.62k|  uint64_t ipv4 = 0;
 9218|  8.62k|  int digit_count = 0;
 9219|  8.62k|  int pure_decimal_count = 0;
 9220|       |
 9221|  16.3k|  for (; digit_count < 4 && p < end; ++digit_count) {
  ------------------
  |  Branch (9221:10): [True: 16.3k, False: 20]
  |  Branch (9221:29): [True: 16.3k, False: 0]
  ------------------
 9222|  16.3k|    uint64_t segment = 0;
 9223|  16.3k|    bool pure = false;
 9224|  16.3k|    if (!detail::parse_ipv4_number(p, end, segment, pure)) {
  ------------------
  |  Branch (9224:9): [True: 191, False: 16.1k]
  ------------------
 9225|    191|      return is_valid = false;
 9226|    191|    }
 9227|  16.1k|    if (pure) {
  ------------------
  |  Branch (9227:9): [True: 8.81k, False: 7.31k]
  ------------------
 9228|  8.81k|      ++pure_decimal_count;
 9229|  8.81k|    }
 9230|  16.1k|    if (p >= end) {
  ------------------
  |  Branch (9230:9): [True: 8.39k, False: 7.73k]
  ------------------
 9231|  8.39k|      const unsigned shift = static_cast<unsigned>(32 - digit_count * 8);
 9232|  8.39k|      if (segment >= (uint64_t{1} << shift)) {
  ------------------
  |  Branch (9232:11): [True: 30, False: 8.36k]
  ------------------
 9233|     30|        return is_valid = false;
 9234|     30|      }
 9235|  8.36k|      ipv4 = (ipv4 << shift) | segment;
 9236|  8.36k|      host = (pure_decimal_count == 4) ? std::string(original_input)
  ------------------
  |  Branch (9236:14): [True: 0, False: 8.36k]
  ------------------
 9237|  8.36k|                                       : ada::serializers::ipv4(ipv4);
 9238|  8.36k|      host_type = IPV4;
 9239|  8.36k|      return true;
 9240|  8.39k|    }
 9241|  7.73k|    if (segment > 255 || *p != '.') {
  ------------------
  |  Branch (9241:9): [True: 16, False: 7.71k]
  |  Branch (9241:26): [True: 0, False: 7.71k]
  ------------------
 9242|     16|      return is_valid = false;
 9243|     16|    }
 9244|  7.71k|    ipv4 = (ipv4 << 8) | segment;
 9245|  7.71k|    ++p;
 9246|  7.71k|  }
 9247|     20|  if (digit_count != 4 || p != end) {
  ------------------
  |  Branch (9247:7): [True: 0, False: 20]
  |  Branch (9247:27): [True: 20, False: 0]
  ------------------
 9248|     20|    return is_valid = false;
 9249|     20|  }
 9250|      0|  host = (pure_decimal_count == 4) ? std::string(original_input)
  ------------------
  |  Branch (9250:10): [True: 0, False: 0]
  ------------------
 9251|      0|                                   : ada::serializers::ipv4(ipv4);
 9252|      0|  host_type = IPV4;
 9253|      0|  return true;
 9254|     20|}
_ZN3ada3url10parse_ipv6ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9256|    615|bool url::parse_ipv6(std::string_view input) {
 9257|    615|  ada_log("parse_ipv6 ", input, " [", input.size(), " bytes]");
 9258|    615|  if (input.empty() || input.size() > 45) [[unlikely]] {
  ------------------
  |  Branch (9258:7): [True: 16, False: 599]
  |  Branch (9258:24): [True: 8, False: 591]
  ------------------
 9259|     24|    return is_valid = false;
 9260|     24|  }
 9261|       |#if defined(ADA_AVX512)
 9262|       |  // One masked load classifies colon/dot shape; rejects impossible inputs
 9263|       |  // before the piece parser (free on AVX-512BW+VL builds).
 9264|       |  if (!detail::ipv6_structure_plausible(input.data(), input.size()))
 9265|       |      [[unlikely]] {
 9266|       |    return is_valid = false;
 9267|       |  }
 9268|       |#endif
 9269|       |
 9270|    591|  std::array<uint16_t, 8> address{};
 9271|    591|  const char* pointer = input.data();
 9272|    591|  const char* const end = pointer + input.size();
 9273|    591|  int piece_index = 0;
 9274|    591|  int compress = -1;
 9275|       |
 9276|    591|  if (*pointer == ':') {
  ------------------
  |  Branch (9276:7): [True: 251, False: 340]
  ------------------
 9277|    251|    if (input.size() == 1 || pointer[1] != ':') [[unlikely]] {
  ------------------
  |  Branch (9277:9): [True: 5, False: 246]
  |  Branch (9277:30): [True: 11, False: 235]
  ------------------
 9278|     16|      return is_valid = false;
 9279|     16|    }
 9280|    235|    pointer += 2;
 9281|    235|    compress = ++piece_index;
 9282|    235|  }
 9283|       |
 9284|  1.75k|  while (pointer != end) {
  ------------------
  |  Branch (9284:10): [True: 1.31k, False: 442]
  ------------------
 9285|  1.31k|    if (piece_index == 8) [[unlikely]] {
  ------------------
  |  Branch (9285:9): [True: 3, False: 1.30k]
  ------------------
 9286|      3|      return is_valid = false;
 9287|      3|    }
 9288|  1.30k|    if (*pointer == ':') {
  ------------------
  |  Branch (9288:9): [True: 179, False: 1.12k]
  ------------------
 9289|    179|      if (compress != -1) [[unlikely]] {
  ------------------
  |  Branch (9289:11): [True: 3, False: 176]
  ------------------
 9290|      3|        return is_valid = false;
 9291|      3|      }
 9292|    176|      ++pointer;
 9293|    176|      compress = ++piece_index;
 9294|    176|      continue;
 9295|    179|    }
 9296|       |
 9297|  1.12k|    uint16_t value = 0;
 9298|  1.12k|    const int length = detail::parse_hex_piece(pointer, end, value);
 9299|       |
 9300|  1.12k|    if (pointer != end && *pointer == '.') {
  ------------------
  |  Branch (9300:9): [True: 867, False: 262]
  |  Branch (9300:27): [True: 95, False: 772]
  ------------------
 9301|     95|      if (length == 0) [[unlikely]] {
  ------------------
  |  Branch (9301:11): [True: 3, False: 92]
  ------------------
 9302|      3|        return is_valid = false;
 9303|      3|      }
 9304|     92|      pointer -= length;
 9305|     92|      if (piece_index > 6) [[unlikely]] {
  ------------------
  |  Branch (9305:11): [True: 3, False: 89]
  ------------------
 9306|      3|        return is_valid = false;
 9307|      3|      }
 9308|       |
 9309|     89|      int numbers_seen = 0;
 9310|    246|      while (pointer != end) {
  ------------------
  |  Branch (9310:14): [True: 227, False: 19]
  ------------------
 9311|    227|        int ipv4_piece = -1;
 9312|    227|        if (numbers_seen > 0) {
  ------------------
  |  Branch (9312:13): [True: 138, False: 89]
  ------------------
 9313|    138|          if (*pointer == '.' && numbers_seen < 4) {
  ------------------
  |  Branch (9313:15): [True: 119, False: 19]
  |  Branch (9313:34): [True: 112, False: 7]
  ------------------
 9314|    112|            ++pointer;
 9315|    112|          } else {
 9316|     26|            return is_valid = false;
 9317|     26|          }
 9318|    138|        }
 9319|    201|        if (pointer == end || *pointer < '0' || *pointer > '9') [[unlikely]] {
  ------------------
  |  Branch (9319:13): [True: 16, False: 185]
  |  Branch (9319:31): [True: 9, False: 176]
  |  Branch (9319:49): [True: 9, False: 167]
  ------------------
 9320|     34|          return is_valid = false;
 9321|     34|        }
 9322|    167|        ipv4_piece = *pointer - '0';
 9323|    167|        ++pointer;
 9324|    167|        if (pointer != end && *pointer >= '0' && *pointer <= '9') {
  ------------------
  |  Branch (9324:13): [True: 157, False: 10]
  |  Branch (9324:31): [True: 75, False: 82]
  |  Branch (9324:50): [True: 72, False: 3]
  ------------------
 9325|     72|          if (ipv4_piece == 0) [[unlikely]] {
  ------------------
  |  Branch (9325:15): [True: 3, False: 69]
  ------------------
 9326|      3|            return is_valid = false;
 9327|      3|          }
 9328|     69|          ipv4_piece = ipv4_piece * 10 + (*pointer - '0');
 9329|     69|          ++pointer;
 9330|     69|          if (pointer != end && *pointer >= '0' && *pointer <= '9') {
  ------------------
  |  Branch (9330:15): [True: 66, False: 3]
  |  Branch (9330:33): [True: 37, False: 29]
  |  Branch (9330:52): [True: 34, False: 3]
  ------------------
 9331|     34|            ipv4_piece = ipv4_piece * 10 + (*pointer - '0');
 9332|     34|            ++pointer;
 9333|     34|            if (ipv4_piece > 255) [[unlikely]] {
  ------------------
  |  Branch (9333:17): [True: 7, False: 27]
  ------------------
 9334|      7|              return is_valid = false;
 9335|      7|            }
 9336|     34|          }
 9337|     69|        }
 9338|    157|        address[static_cast<size_t>(piece_index)] = static_cast<uint16_t>(
 9339|    157|            address[static_cast<size_t>(piece_index)] * 0x100 +
 9340|    157|            static_cast<uint16_t>(ipv4_piece));
 9341|    157|        ++numbers_seen;
 9342|    157|        if (numbers_seen == 2 || numbers_seen == 4) {
  ------------------
  |  Branch (9342:13): [True: 45, False: 112]
  |  Branch (9342:34): [True: 14, False: 98]
  ------------------
 9343|     59|          ++piece_index;
 9344|     59|        }
 9345|    157|      }
 9346|     19|      if (numbers_seen != 4) [[unlikely]] {
  ------------------
  |  Branch (9346:11): [True: 12, False: 7]
  ------------------
 9347|     12|        return is_valid = false;
 9348|     12|      }
 9349|      7|      break;
 9350|     19|    }
 9351|       |
 9352|  1.03k|    if (length == 0) [[unlikely]] {
  ------------------
  |  Branch (9352:9): [True: 22, False: 1.01k]
  ------------------
 9353|     22|      return is_valid = false;
 9354|     22|    }
 9355|       |
 9356|  1.01k|    if (pointer != end && *pointer == ':') {
  ------------------
  |  Branch (9356:9): [True: 750, False: 262]
  |  Branch (9356:27): [True: 744, False: 6]
  ------------------
 9357|    744|      ++pointer;
 9358|    744|      if (pointer == end) [[unlikely]] {
  ------------------
  |  Branch (9358:11): [True: 4, False: 740]
  ------------------
 9359|      4|        return is_valid = false;
 9360|      4|      }
 9361|    744|    } else if (pointer != end) [[unlikely]] {
  ------------------
  |  Branch (9361:16): [True: 6, False: 262]
  ------------------
 9362|      6|      return is_valid = false;
 9363|      6|    }
 9364|       |
 9365|  1.00k|    address[static_cast<size_t>(piece_index)] = value;
 9366|  1.00k|    ++piece_index;
 9367|  1.00k|  }
 9368|       |
 9369|    449|  if (compress != -1) {
  ------------------
  |  Branch (9369:7): [True: 400, False: 49]
  ------------------
 9370|    400|    const int right = piece_index - compress;
 9371|    400|    if (right > 0) {
  ------------------
  |  Branch (9371:9): [True: 220, False: 180]
  ------------------
 9372|    220|      const size_t dest = static_cast<size_t>(8 - right);
 9373|    220|      const size_t src = static_cast<size_t>(compress);
 9374|    220|      if (dest != src) {
  ------------------
  |  Branch (9374:11): [True: 207, False: 13]
  ------------------
 9375|    561|        for (size_t i = static_cast<size_t>(right); i-- > 0;) {
  ------------------
  |  Branch (9375:53): [True: 354, False: 207]
  ------------------
 9376|    354|          address[dest + i] = address[src + i];
 9377|    354|          address[src + i] = 0;
 9378|    354|        }
 9379|    207|      }
 9380|    220|    }
 9381|    400|  } else if (piece_index != 8) [[unlikely]] {
  ------------------
  |  Branch (9381:14): [True: 25, False: 24]
  ------------------
 9382|     25|    return is_valid = false;
 9383|     25|  }
 9384|       |
 9385|    424|  host = ada::serializers::ipv6(address);
 9386|    424|  ada_log("parse_ipv6 ", *host);
 9387|    424|  host_type = IPV6;
 9388|    424|  return true;
 9389|    449|}
_ZNK3ada3url12get_protocolEv:
 9700|   118k|[[nodiscard]] std::string url::get_protocol() const {
 9701|   118k|  if (is_special()) {
  ------------------
  |  Branch (9701:7): [True: 117k, False: 486]
  ------------------
 9702|   117k|    return helpers::concat(ada::scheme::details::is_special_list[type], ":");
 9703|   117k|  }
 9704|       |  // We only move the 'scheme' if it is non-special.
 9705|    486|  return helpers::concat(non_special_scheme, ":");
 9706|   118k|}
_ZNK3ada3url8get_hostEv:
 9708|   118k|[[nodiscard]] std::string url::get_host() const {
 9709|       |  // If url's host is null, then return the empty string.
 9710|       |  // If url's port is null, return url's host, serialized.
 9711|       |  // Return url's host, serialized, followed by U+003A (:) and url's port,
 9712|       |  // serialized.
 9713|   118k|  if (!host.has_value()) {
  ------------------
  |  Branch (9713:7): [True: 283, False: 118k]
  ------------------
 9714|    283|    return "";
 9715|    283|  }
 9716|   118k|  if (port.has_value()) {
  ------------------
  |  Branch (9716:7): [True: 7.79k, False: 110k]
  ------------------
 9717|  7.79k|    return host.value() + ":" + get_port();
 9718|  7.79k|  }
 9719|   110k|  return host.value();
 9720|   118k|}
_ZNK3ada3url12get_hostnameEv:
 9722|   118k|[[nodiscard]] std::string url::get_hostname() const {
 9723|   118k|  return host.value_or("");
 9724|   118k|}
_ZNK3ada3url10get_searchEv:
 9726|   118k|[[nodiscard]] std::string url::get_search() const {
 9727|       |  // If this's URL's query is either null or the empty string, then return the
 9728|       |  // empty string. Return U+003F (?), followed by this's URL's query.
 9729|   118k|  return (!query.has_value() || (query->empty())) ? "" : "?" + query.value();
  ------------------
  |  Branch (9729:11): [True: 93.6k, False: 24.7k]
  |  Branch (9729:33): [True: 770, False: 23.9k]
  ------------------
 9730|   118k|}
_ZNK3ada3url12get_usernameEv:
 9732|   118k|[[nodiscard]] const std::string& url::get_username() const noexcept {
 9733|   118k|  return username;
 9734|   118k|}
_ZNK3ada3url12get_passwordEv:
 9736|   118k|[[nodiscard]] const std::string& url::get_password() const noexcept {
 9737|   118k|  return password;
 9738|   118k|}
_ZNK3ada3url8get_portEv:
 9740|   126k|[[nodiscard]] std::string url::get_port() const {
 9741|   126k|  return port.has_value() ? std::to_string(port.value()) : "";
  ------------------
  |  Branch (9741:10): [True: 15.5k, False: 110k]
  ------------------
 9742|   126k|}
_ZNK3ada3url8get_hashEv:
 9744|   118k|[[nodiscard]] std::string url::get_hash() const {
 9745|       |  // If this's URL's fragment is either null or the empty string, then return
 9746|       |  // the empty string. Return U+0023 (#), followed by this's URL's fragment.
 9747|   118k|  return (!hash.has_value() || (hash->empty())) ? "" : "#" + hash.value();
  ------------------
  |  Branch (9747:11): [True: 100k, False: 17.8k]
  |  Branch (9747:32): [True: 1.08k, False: 16.7k]
  ------------------
 9748|   118k|}
_ZN3ada3url8set_hrefENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
10031|   118k|bool url::set_href(const std::string_view input) {
10032|   118k|  ada::result<ada::url> out = ada::parse<ada::url>(input);
10033|       |
10034|   118k|  if (out) {
  ------------------
  |  Branch (10034:7): [True: 118k, False: 0]
  ------------------
10035|       |    // The parser enforces get_max_input_length() on both the input and the
10036|       |    // normalized result. This is a defense-in-depth check.
10037|   118k|    if (out->get_href_size() > ada::get_max_input_length()) {
  ------------------
  |  Branch (10037:9): [True: 0, False: 118k]
  ------------------
10038|      0|      return false;
10039|      0|    }
10040|   118k|    *this = *out;
10041|   118k|  }
10042|       |
10043|   118k|  return out.has_value();
10044|   118k|}
_ZN3ada6parser14parse_url_implINS_3urlELb1EEET_NSt3__117basic_string_viewIcNS4_11char_traitsIcEEEEPKS3_:
10361|   357k|                           const result_type* base_url) {
10362|       |  // We can specialize the implementation per type.
10363|       |  // Important: result_type_is_ada_url is evaluated at *compile time*. This
10364|       |  // means that doing if constexpr(result_type_is_ada_url) { something } else {
10365|       |  // something else } is free (at runtime). This means that ada::url_aggregator
10366|       |  // and ada::url **do not have to support the exact same API**.
10367|   357k|  constexpr bool result_type_is_ada_url = std::is_same_v<url, result_type>;
10368|   357k|  constexpr bool result_type_is_ada_url_aggregator =
10369|   357k|      std::is_same_v<url_aggregator, result_type>;
10370|   357k|  static_assert(result_type_is_ada_url ||
10371|   357k|                result_type_is_ada_url_aggregator);  // We don't support
10372|       |                                                     // anything else for now.
10373|       |
10374|   357k|  ada_log("ada::parser::parse_url('", user_input, "' [", user_input.size(),
10375|   357k|          " bytes],", (base_url != nullptr ? base_url->to_string() : "null"),
10376|   357k|          ")");
10377|       |
10378|   357k|  state state = state::SCHEME_START;
10379|   357k|  result_type url{};
10380|       |
10381|   357k|  const uint32_t max_input_length = ada::get_max_input_length();
10382|       |
10383|       |  // We refuse to parse URL strings that exceed the maximum input length.
10384|       |  // By default, this is 4GB but can be configured via
10385|       |  // ada::set_max_input_length().
10386|   357k|  if (user_input.size() > max_input_length) [[unlikely]] {
  ------------------
  |  Branch (10386:7): [True: 0, False: 357k]
  ------------------
10387|      0|    url.is_valid = false;
10388|      0|  }
10389|       |  // Going forward, user_input.size() is in [0,
10390|       |  // std::numeric_limits<uint32_t>::max). If we are provided with an invalid
10391|       |  // base, or the optional_url was invalid, we must return.
10392|   357k|  if (base_url != nullptr) {
  ------------------
  |  Branch (10392:7): [True: 0, False: 357k]
  ------------------
10393|      0|    url.is_valid &= base_url->is_valid;
10394|      0|  }
10395|   357k|  if (!url.is_valid) {
  ------------------
  |  Branch (10395:7): [True: 0, False: 357k]
  ------------------
10396|      0|    return url;
10397|      0|  }
10398|       |
10399|       |  // Simple absolute http(s) fast path (before tabs/newline scan).
10400|       |  // Skip digit-led hosts (IPv4) with a cheap peek.
10401|   357k|  if constexpr (store_values) {
10402|   357k|    if (base_url == nullptr) {
  ------------------
  |  Branch (10402:9): [True: 357k, False: 0]
  ------------------
10403|   357k|      const auto* p = reinterpret_cast<const uint8_t*>(user_input.data());
10404|   357k|      const size_t n = user_input.size();
10405|   357k|      const bool digit_led_host = (n >= 8 && p[4] == ':' && p[5] == '/' &&
  ------------------
  |  Branch (10405:36): [True: 357k, False: 45]
  |  Branch (10405:46): [True: 99.1k, False: 258k]
  |  Branch (10405:61): [True: 98.3k, False: 799]
  ------------------
10406|  98.3k|                                   p[6] == '/' && p[7] >= '0' && p[7] <= '9') ||
  ------------------
  |  Branch (10406:36): [True: 98.2k, False: 139]
  |  Branch (10406:51): [True: 96.3k, False: 1.86k]
  |  Branch (10406:66): [True: 45.2k, False: 51.0k]
  ------------------
10407|   312k|                                  (n >= 9 && p[5] == ':' && p[6] == '/' &&
  ------------------
  |  Branch (10407:36): [True: 312k, False: 124]
  |  Branch (10407:46): [True: 257k, False: 54.8k]
  |  Branch (10407:61): [True: 256k, False: 737]
  ------------------
10408|   256k|                                   p[7] == '/' && p[8] >= '0' && p[8] <= '9');
  ------------------
  |  Branch (10408:36): [True: 256k, False: 69]
  |  Branch (10408:51): [True: 256k, False: 645]
  |  Branch (10408:66): [True: 2.20k, False: 253k]
  ------------------
10409|   357k|      if (!digit_led_host && try_parse_simple_absolute(user_input, url)) {
  ------------------
  |  Branch (10409:11): [True: 310k, False: 47.4k]
  |  Branch (10409:30): [True: 196k, False: 113k]
  ------------------
10410|       |        if constexpr (result_type_is_ada_url_aggregator) {
10411|       |          if (url.buffer.size() > max_input_length) [[unlikely]] {
10412|       |            url.is_valid = false;
10413|       |          }
10414|   196k|        } else {
10415|   196k|          if (url.get_href_size() > max_input_length) [[unlikely]] {
  ------------------
  |  Branch (10415:15): [True: 0, False: 196k]
  ------------------
10416|      0|            url.is_valid = false;
10417|      0|          }
10418|   196k|        }
10419|   196k|        return url;
10420|   196k|      }
10421|   357k|    }
10422|   357k|  }
10423|       |
10424|   160k|  std::string tmp_buffer;
10425|   357k|  std::string_view url_data;
10426|   357k|  if (unicode::has_tabs_or_newline(user_input)) [[unlikely]] {
  ------------------
  |  Branch (10426:7): [True: 442, False: 357k]
  ------------------
10427|    442|    tmp_buffer = user_input;
10428|       |    // Optimization opportunity: Instead of copying and then pruning, we could
10429|       |    // just directly build the string from user_input.
10430|    442|    helpers::remove_ascii_tab_or_newline(tmp_buffer);
10431|    442|    url_data = tmp_buffer;
10432|   357k|  } else [[likely]] {
10433|   357k|    url_data = user_input;
10434|   357k|  }
10435|       |
10436|       |  // Leading and trailing control characters are uncommon and easy to deal with
10437|       |  // (no performance concern).
10438|   357k|  helpers::trim_c0_whitespace(url_data);
10439|       |
10440|       |  if constexpr (result_type_is_ada_url_aggregator && store_values) {
10441|       |    // Most of the time, we just need user_input.size().
10442|       |    // In some instances, we may need a bit more.
10443|       |    ///////////////////////////
10444|       |    // This is *very* important. This line should *not* be removed
10445|       |    // hastily. There are principled reasons why reserve is important
10446|       |    // for performance. If you have a benchmark with small inputs,
10447|       |    // it may not matter, but in other instances, it could.
10448|       |    ////
10449|       |    // This rounds up to the next power of two.
10450|       |    // We know that user_input.size() is in [0,
10451|       |    // std::numeric_limits<uint32_t>::max).
10452|       |    uint32_t reserve_capacity =
10453|       |        (0xFFFFFFFF >>
10454|       |         helpers::leading_zeroes(uint32_t(1 | user_input.size()))) +
10455|       |        1;
10456|       |    url.reserve(reserve_capacity);
10457|       |  }
10458|       |
10459|       |  // Optimization opportunity. Most websites do not have fragment.
10460|   357k|  std::optional<std::string_view> fragment = helpers::prune_hash(url_data);
10461|       |  // We add it last so that an implementation like ada::url_aggregator
10462|       |  // can append it last to its internal buffer, thus improving performance.
10463|       |
10464|       |  // Here url_data no longer has its fragment.
10465|       |  // We are going to access the data from url_data (it is immutable).
10466|       |  // At any given time, we are pointing at byte 'input_position' in url_data.
10467|       |  // The input_position variable should range from 0 to input_size.
10468|       |  // It is illegal to access url_data at input_size.
10469|   357k|  size_t input_position = 0;
10470|   357k|  const size_t input_size = url_data.size();
10471|       |  // Keep running the following state machine by switching on state.
10472|       |  // If after a run pointer points to the EOF code point, go to the next step.
10473|       |  // Otherwise, increase pointer by 1 and continue with the state machine.
10474|       |  // We never decrement input_position.
10475|  1.46M|  while (input_position <= input_size) {
  ------------------
  |  Branch (10475:10): [True: 1.12M, False: 342k]
  ------------------
10476|  1.12M|    ada_log("In parsing at ", input_position, " out of ", input_size,
10477|  1.12M|            " in state ", ada::to_string(state));
10478|  1.12M|    switch (state) {
10479|   160k|      case state::SCHEME_START: {
  ------------------
  |  Branch (10479:7): [True: 160k, False: 963k]
  ------------------
10480|   160k|        ada_log("SCHEME_START ", helpers::substring(url_data, input_position));
10481|       |        // If c is an ASCII alpha, append c, lowercased, to buffer, and set
10482|       |        // state to scheme state.
10483|   160k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (10483:13): [True: 160k, False: 1]
  ------------------
10484|   160k|            checkers::is_alpha(url_data[input_position])) {
  ------------------
  |  Branch (10484:13): [True: 160k, False: 45]
  ------------------
10485|   160k|          state = state::SCHEME;
10486|   160k|          input_position++;
10487|   160k|        } else {
10488|       |          // Otherwise, if state override is not given, set state to no scheme
10489|       |          // state and decrease pointer by 1.
10490|     46|          state = state::NO_SCHEME;
10491|     46|        }
10492|   160k|        break;
10493|      0|      }
10494|   160k|      case state::SCHEME: {
  ------------------
  |  Branch (10494:7): [True: 160k, False: 963k]
  ------------------
10495|   160k|        ada_log("SCHEME ", helpers::substring(url_data, input_position));
10496|       |        // If c is an ASCII alphanumeric, U+002B (+), U+002D (-), or U+002E (.),
10497|       |        // append c, lowercased, to buffer.
10498|   746k|        while ((input_position != input_size) &&
  ------------------
  |  Branch (10498:16): [True: 746k, False: 1]
  ------------------
10499|   746k|               (unicode::is_alnum_plus(url_data[input_position]))) {
  ------------------
  |  Branch (10499:16): [True: 586k, False: 160k]
  ------------------
10500|   586k|          input_position++;
10501|   586k|        }
10502|       |        // Otherwise, if c is U+003A (:), then:
10503|   160k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (10503:13): [True: 160k, False: 1]
  ------------------
10504|   160k|            (url_data[input_position] == ':')) {
  ------------------
  |  Branch (10504:13): [True: 160k, False: 57]
  ------------------
10505|   160k|          ada_log("SCHEME the scheme should be ",
10506|   160k|                  url_data.substr(0, input_position));
10507|   160k|          if constexpr (result_type_is_ada_url) {
10508|   160k|            if (!url.parse_scheme(url_data.substr(0, input_position))) {
  ------------------
  |  Branch (10508:17): [True: 0, False: 160k]
  ------------------
10509|      0|              return url;
10510|      0|            }
10511|       |          } else {
10512|       |            // we pass the colon along instead of painfully adding it back.
10513|       |            if (!url.parse_scheme_with_colon(
10514|       |                    url_data.substr(0, input_position + 1))) {
10515|       |              return url;
10516|       |            }
10517|       |          }
10518|   160k|          ada_log("SCHEME the scheme is ", url.get_protocol());
10519|       |
10520|       |          // If url's scheme is "file", then:
10521|       |          // NOLINTNEXTLINE(bugprone-branch-clone)
10522|   160k|          if (url.type == scheme::type::FILE) {
  ------------------
  |  Branch (10522:15): [True: 1.28k, False: 159k]
  ------------------
10523|       |            // Set state to file state.
10524|  1.28k|            state = state::FILE;
10525|  1.28k|          }
10526|       |          // Otherwise, if url is special, base is non-null, and base's scheme
10527|       |          // is url's scheme: Note: Doing base_url->scheme is unsafe if base_url
10528|       |          // != nullptr is false.
10529|   159k|          else if (url.is_special() && base_url != nullptr &&
  ------------------
  |  Branch (10529:20): [True: 157k, False: 1.54k]
  |  Branch (10529:40): [True: 0, False: 157k]
  ------------------
10530|      0|                   base_url->type == url.type) {
  ------------------
  |  Branch (10530:20): [True: 0, False: 0]
  ------------------
10531|       |            // Set state to special relative or authority state.
10532|      0|            state = state::SPECIAL_RELATIVE_OR_AUTHORITY;
10533|      0|          }
10534|       |          // Otherwise, if url is special, set state to special authority
10535|       |          // slashes state.
10536|   159k|          else if (url.is_special()) {
  ------------------
  |  Branch (10536:20): [True: 157k, False: 1.54k]
  ------------------
10537|   157k|            state = state::SPECIAL_AUTHORITY_SLASHES;
10538|   157k|          }
10539|       |          // Otherwise, if remaining starts with an U+002F (/), set state to
10540|       |          // path or authority state and increase pointer by 1.
10541|  1.54k|          else if (input_position + 1 < input_size &&
  ------------------
  |  Branch (10541:20): [True: 1.50k, False: 33]
  ------------------
10542|  1.50k|                   url_data[input_position + 1] == '/') {
  ------------------
  |  Branch (10542:20): [True: 1.02k, False: 486]
  ------------------
10543|  1.02k|            state = state::PATH_OR_AUTHORITY;
10544|  1.02k|            input_position++;
10545|  1.02k|          }
10546|       |          // Otherwise, set url's path to the empty string and set state to
10547|       |          // opaque path state.
10548|    519|          else {
10549|    519|            state = state::OPAQUE_PATH;
10550|    519|          }
10551|   160k|        }
10552|       |        // Otherwise, if state override is not given, set buffer to the empty
10553|       |        // string, state to no scheme state, and start over (from the first code
10554|       |        // point in input).
10555|     58|        else {
10556|     58|          state = state::NO_SCHEME;
10557|     58|          input_position = 0;
10558|     58|          break;
10559|     58|        }
10560|   160k|        input_position++;
10561|   160k|        break;
10562|   160k|      }
10563|    104|      case state::NO_SCHEME: {
  ------------------
  |  Branch (10563:7): [True: 104, False: 1.12M]
  ------------------
10564|    104|        ada_log("NO_SCHEME ", helpers::substring(url_data, input_position));
10565|       |        // If base is null, or base has an opaque path and c is not U+0023 (#),
10566|       |        // validation error, return failure.
10567|    104|        if (base_url == nullptr ||
  ------------------
  |  Branch (10567:13): [True: 104, False: 0]
  ------------------
10568|    104|            (base_url->has_opaque_path && !fragment.has_value())) {
  ------------------
  |  Branch (10568:14): [True: 0, False: 0]
  |  Branch (10568:43): [True: 0, False: 0]
  ------------------
10569|    104|          ada_log("NO_SCHEME validation error");
10570|    104|          url.is_valid = false;
10571|    104|          return url;
10572|    104|        }
10573|       |        // Otherwise, if base has an opaque path and c is U+0023 (#),
10574|       |        // set url's scheme to base's scheme, url's path to base's path, url's
10575|       |        // query to base's query, and set state to fragment state.
10576|      0|        else if (base_url->has_opaque_path && fragment.has_value() &&
  ------------------
  |  Branch (10576:18): [True: 0, False: 0]
  |  Branch (10576:47): [True: 0, False: 0]
  ------------------
10577|      0|                 input_position == input_size) {
  ------------------
  |  Branch (10577:18): [True: 0, False: 0]
  ------------------
10578|      0|          ada_log("NO_SCHEME opaque base with fragment");
10579|      0|          url.copy_scheme(*base_url);
10580|      0|          url.has_opaque_path = base_url->has_opaque_path;
10581|       |
10582|      0|          if constexpr (result_type_is_ada_url) {
10583|      0|            url.path = base_url->path;
10584|      0|            url.query = base_url->query;
10585|       |          } else {
10586|       |            url.update_base_pathname(base_url->get_pathname());
10587|       |            if (base_url->has_search()) {
10588|       |              // get_search() returns "" for an empty query string (URL ends
10589|       |              // with '?'). update_base_search("") would incorrectly clear the
10590|       |              // query, so pass "?" to preserve the empty query distinction.
10591|       |              auto s = base_url->get_search();
10592|       |              url.update_base_search(s.empty() ? std::string_view("?") : s);
10593|       |            }
10594|       |          }
10595|      0|          url.update_unencoded_base_hash(*fragment);
10596|      0|          return url;
10597|      0|        }
10598|       |        // Otherwise, if base's scheme is not "file", set state to relative
10599|       |        // state and decrease pointer by 1.
10600|       |        // NOLINTNEXTLINE(bugprone-branch-clone)
10601|      0|        else if (base_url->type != scheme::type::FILE) {
  ------------------
  |  Branch (10601:18): [True: 0, False: 0]
  ------------------
10602|      0|          ada_log("NO_SCHEME non-file relative path");
10603|      0|          state = state::RELATIVE_SCHEME;
10604|      0|        }
10605|       |        // Otherwise, set state to file state and decrease pointer by 1.
10606|      0|        else {
10607|      0|          ada_log("NO_SCHEME file base type");
10608|      0|          state = state::FILE;
10609|      0|        }
10610|      0|        break;
10611|    104|      }
10612|   158k|      case state::AUTHORITY: {
  ------------------
  |  Branch (10612:7): [True: 158k, False: 965k]
  ------------------
10613|   158k|        ada_log("AUTHORITY ", helpers::substring(url_data, input_position));
10614|       |        // most URLs have no @. Having no @ tells us that we don't have to worry
10615|       |        // about AUTHORITY. Of course, we could have @ and still not have to
10616|       |        // worry about AUTHORITY.
10617|       |        // TODO: Instead of just collecting a bool, collect the location of the
10618|       |        // '@' and do something useful with it.
10619|       |        // TODO: We could do various processing early on, using a single pass
10620|       |        // over the string to collect information about it, e.g., telling us
10621|       |        // whether there is a @ and if so, where (or how many).
10622|       |
10623|       |        // Check if url data contains an @.
10624|   158k|        if (url_data.find('@', input_position) == std::string_view::npos) {
  ------------------
  |  Branch (10624:13): [True: 135k, False: 23.4k]
  ------------------
10625|   135k|          state = state::HOST;
10626|   135k|          break;
10627|   135k|        }
10628|  23.4k|        bool at_sign_seen{false};
10629|  23.4k|        bool password_token_seen{false};
10630|       |        /**
10631|       |         * We expect something of the sort...
10632|       |         * https://user:pass@example.com:1234/foo/bar?baz#quux
10633|       |         * --------^
10634|       |         */
10635|  59.3k|        do {
10636|  59.3k|          std::string_view view = url_data.substr(input_position);
10637|       |          // The delimiters are @, /, ? \\.
10638|  59.3k|          size_t location =
10639|  59.3k|              url.is_special() ? helpers::find_authority_delimiter_special(view)
  ------------------
  |  Branch (10639:15): [True: 59.0k, False: 302]
  ------------------
10640|  59.3k|                               : helpers::find_authority_delimiter(view);
10641|  59.3k|          std::string_view authority_view = view.substr(0, location);
10642|  59.3k|          size_t end_of_authority = input_position + authority_view.size();
10643|       |          // If c is U+0040 (@), then:
10644|  59.3k|          if ((end_of_authority != input_size) &&
  ------------------
  |  Branch (10644:15): [True: 58.9k, False: 452]
  ------------------
10645|  58.9k|              (url_data[end_of_authority] == '@')) {
  ------------------
  |  Branch (10645:15): [True: 35.8k, False: 23.0k]
  ------------------
10646|       |            // If atSignSeen is true, then prepend "%40" to buffer.
10647|  35.8k|            if (at_sign_seen) {
  ------------------
  |  Branch (10647:17): [True: 12.6k, False: 23.2k]
  ------------------
10648|  12.6k|              if (password_token_seen) {
  ------------------
  |  Branch (10648:19): [True: 4.28k, False: 8.36k]
  ------------------
10649|  4.28k|                if constexpr (result_type_is_ada_url) {
10650|  4.28k|                  url.password += "%40";
10651|       |                } else {
10652|       |                  url.append_base_password("%40");
10653|       |                }
10654|  8.36k|              } else {
10655|  8.36k|                if constexpr (result_type_is_ada_url) {
10656|  8.36k|                  url.username += "%40";
10657|       |                } else {
10658|       |                  url.append_base_username("%40");
10659|       |                }
10660|  8.36k|              }
10661|  12.6k|            }
10662|       |
10663|  35.8k|            at_sign_seen = true;
10664|       |
10665|  35.8k|            if (!password_token_seen) {
  ------------------
  |  Branch (10665:17): [True: 31.5k, False: 4.28k]
  ------------------
10666|  31.5k|              size_t password_token_location = authority_view.find(':');
10667|  31.5k|              password_token_seen =
10668|  31.5k|                  password_token_location != std::string_view::npos;
10669|       |
10670|  31.5k|              if constexpr (store_values) {
10671|  31.5k|                if (!password_token_seen) {
  ------------------
  |  Branch (10671:21): [True: 9.39k, False: 22.2k]
  ------------------
10672|  9.39k|                  if constexpr (result_type_is_ada_url) {
10673|  9.39k|                    url.username += unicode::percent_encode(
10674|  9.39k|                        authority_view,
10675|  9.39k|                        character_sets::USERINFO_PERCENT_ENCODE);
10676|       |                  } else {
10677|       |                    url.append_base_username(unicode::percent_encode(
10678|       |                        authority_view,
10679|       |                        character_sets::USERINFO_PERCENT_ENCODE));
10680|       |                  }
10681|  22.2k|                } else {
10682|  22.2k|                  if constexpr (result_type_is_ada_url) {
10683|  22.2k|                    url.username += unicode::percent_encode(
10684|  22.2k|                        authority_view.substr(0, password_token_location),
10685|  22.2k|                        character_sets::USERINFO_PERCENT_ENCODE);
10686|  22.2k|                    url.password += unicode::percent_encode(
10687|  22.2k|                        authority_view.substr(password_token_location + 1),
10688|  22.2k|                        character_sets::USERINFO_PERCENT_ENCODE);
10689|       |                  } else {
10690|       |                    url.append_base_username(unicode::percent_encode(
10691|       |                        authority_view.substr(0, password_token_location),
10692|       |                        character_sets::USERINFO_PERCENT_ENCODE));
10693|       |                    url.append_base_password(unicode::percent_encode(
10694|       |                        authority_view.substr(password_token_location + 1),
10695|       |                        character_sets::USERINFO_PERCENT_ENCODE));
10696|       |                  }
10697|  22.2k|                }
10698|  31.5k|              }
10699|  31.5k|            } else if constexpr (store_values) {
10700|  4.28k|              if constexpr (result_type_is_ada_url) {
10701|  4.28k|                url.password += unicode::percent_encode(
10702|  4.28k|                    authority_view, character_sets::USERINFO_PERCENT_ENCODE);
10703|       |              } else {
10704|       |                url.append_base_password(unicode::percent_encode(
10705|       |                    authority_view, character_sets::USERINFO_PERCENT_ENCODE));
10706|       |              }
10707|  4.28k|            }
10708|  35.8k|          }
10709|       |          // Otherwise, if one of the following is true:
10710|       |          // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
10711|       |          // - url is special and c is U+005C (\)
10712|  23.4k|          else if (end_of_authority == input_size ||
  ------------------
  |  Branch (10712:20): [True: 452, False: 23.0k]
  ------------------
10713|  23.0k|                   url_data[end_of_authority] == '/' ||
  ------------------
  |  Branch (10713:20): [True: 22.8k, False: 184]
  ------------------
10714|    184|                   url_data[end_of_authority] == '?' ||
  ------------------
  |  Branch (10714:20): [True: 138, False: 46]
  ------------------
10715|  23.4k|                   (url.is_special() && url_data[end_of_authority] == '\\')) {
  ------------------
  |  Branch (10715:21): [True: 46, False: 0]
  |  Branch (10715:41): [True: 46, False: 0]
  ------------------
10716|       |            // If atSignSeen is true and authority_view is the empty string,
10717|       |            // validation error, return failure.
10718|  23.4k|            if (at_sign_seen && authority_view.empty()) {
  ------------------
  |  Branch (10718:17): [True: 23.2k, False: 248]
  |  Branch (10718:33): [True: 189, False: 23.0k]
  ------------------
10719|    189|              url.is_valid = false;
10720|    189|              return url;
10721|    189|            }
10722|  23.2k|            state = state::HOST;
10723|  23.2k|            break;
10724|  23.4k|          }
10725|  35.8k|          if (end_of_authority == input_size) {
  ------------------
  |  Branch (10725:15): [True: 0, False: 35.8k]
  ------------------
10726|      0|            if constexpr (store_values) {
10727|      0|              if (fragment.has_value()) {
  ------------------
  |  Branch (10727:19): [True: 0, False: 0]
  ------------------
10728|      0|                url.update_unencoded_base_hash(*fragment);
10729|      0|              }
10730|      0|            }
10731|      0|            return url;
10732|      0|          }
10733|  35.8k|          input_position = end_of_authority + 1;
10734|  35.8k|        } while (true);
  ------------------
  |  Branch (10734:18): [True: 35.8k, Folded]
  ------------------
10735|       |
10736|  23.2k|        break;
10737|  23.4k|      }
10738|  23.2k|      case state::SPECIAL_RELATIVE_OR_AUTHORITY: {
  ------------------
  |  Branch (10738:7): [True: 0, False: 1.12M]
  ------------------
10739|      0|        ada_log("SPECIAL_RELATIVE_OR_AUTHORITY ",
10740|      0|                helpers::substring(url_data, input_position));
10741|       |
10742|       |        // If c is U+002F (/) and remaining starts with U+002F (/),
10743|       |        // then set state to special authority ignore slashes state and increase
10744|       |        // pointer by 1.
10745|      0|        if (url_data.substr(input_position, 2) == "//") {
  ------------------
  |  Branch (10745:13): [True: 0, False: 0]
  ------------------
10746|      0|          state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES;
10747|      0|          input_position += 2;
10748|      0|        } else {
10749|       |          // Otherwise, validation error, set state to relative state and
10750|       |          // decrease pointer by 1.
10751|      0|          state = state::RELATIVE_SCHEME;
10752|      0|        }
10753|       |
10754|      0|        break;
10755|  23.4k|      }
10756|  1.02k|      case state::PATH_OR_AUTHORITY: {
  ------------------
  |  Branch (10756:7): [True: 1.02k, False: 1.12M]
  ------------------
10757|  1.02k|        ada_log("PATH_OR_AUTHORITY ",
10758|  1.02k|                helpers::substring(url_data, input_position));
10759|       |
10760|       |        // If c is U+002F (/), then set state to authority state.
10761|  1.02k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (10761:13): [True: 1.00k, False: 21]
  ------------------
10762|  1.00k|            (url_data[input_position] == '/')) {
  ------------------
  |  Branch (10762:13): [True: 691, False: 309]
  ------------------
10763|    691|          state = state::AUTHORITY;
10764|    691|          input_position++;
10765|    691|        } else {
10766|       |          // Otherwise, set state to path state, and decrease pointer by 1.
10767|    330|          state = state::PATH;
10768|    330|        }
10769|       |
10770|  1.02k|        break;
10771|  23.4k|      }
10772|      0|      case state::RELATIVE_SCHEME: {
  ------------------
  |  Branch (10772:7): [True: 0, False: 1.12M]
  ------------------
10773|      0|        ada_log("RELATIVE_SCHEME ",
10774|      0|                helpers::substring(url_data, input_position));
10775|       |
10776|       |        // Set url's scheme to base's scheme.
10777|      0|        url.copy_scheme(*base_url);
10778|       |
10779|       |        // If c is U+002F (/), then set state to relative slash state.
10780|      0|        if ((input_position != input_size) &&
  ------------------
  |  Branch (10780:13): [True: 0, False: 0]
  ------------------
10781|       |            // NOLINTNEXTLINE(bugprone-branch-clone)
10782|      0|            (url_data[input_position] == '/')) {
  ------------------
  |  Branch (10782:13): [True: 0, False: 0]
  ------------------
10783|      0|          ada_log(
10784|      0|              "RELATIVE_SCHEME if c is U+002F (/), then set state to relative "
10785|      0|              "slash state");
10786|      0|          state = state::RELATIVE_SLASH;
10787|      0|        } else if (url.is_special() && (input_position != input_size) &&
  ------------------
  |  Branch (10787:20): [True: 0, False: 0]
  |  Branch (10787:40): [True: 0, False: 0]
  ------------------
10788|      0|                   (url_data[input_position] == '\\')) {
  ------------------
  |  Branch (10788:20): [True: 0, False: 0]
  ------------------
10789|       |          // Otherwise, if url is special and c is U+005C (\), validation error,
10790|       |          // set state to relative slash state.
10791|      0|          ada_log(
10792|      0|              "RELATIVE_SCHEME  if url is special and c is U+005C, validation "
10793|      0|              "error, set state to relative slash state");
10794|      0|          state = state::RELATIVE_SLASH;
10795|      0|        } else {
10796|      0|          ada_log("RELATIVE_SCHEME otherwise");
10797|       |          // Set url's username to base's username, url's password to base's
10798|       |          // password, url's host to base's host, url's port to base's port,
10799|       |          // url's path to a clone of base's path, and url's query to base's
10800|       |          // query.
10801|      0|          if constexpr (result_type_is_ada_url) {
10802|      0|            url.username = base_url->username;
10803|      0|            url.password = base_url->password;
10804|      0|            url.host = base_url->host;
10805|      0|            url.port = base_url->port;
10806|       |            // cloning the base path includes cloning the has_opaque_path flag
10807|      0|            url.has_opaque_path = base_url->has_opaque_path;
10808|      0|            url.path = base_url->path;
10809|      0|            url.query = base_url->query;
10810|       |          } else {
10811|       |            url.update_base_authority(base_url->get_href(),
10812|       |                                      base_url->get_components());
10813|       |            url.update_host_to_base_host(base_url->get_hostname());
10814|       |            url.update_base_port(base_url->retrieve_base_port());
10815|       |            // cloning the base path includes cloning the has_opaque_path flag
10816|       |            url.has_opaque_path = base_url->has_opaque_path;
10817|       |            url.update_base_pathname(base_url->get_pathname());
10818|       |            if (base_url->has_search()) {
10819|       |              // get_search() returns "" for an empty query string (URL ends
10820|       |              // with '?'). update_base_search("") would incorrectly clear the
10821|       |              // query, so pass "?" to preserve the empty query distinction.
10822|       |              auto s = base_url->get_search();
10823|       |              url.update_base_search(s.empty() ? std::string_view("?") : s);
10824|       |            }
10825|       |          }
10826|       |
10827|      0|          url.has_opaque_path = base_url->has_opaque_path;
10828|       |
10829|       |          // If c is U+003F (?), then set url's query to the empty string, and
10830|       |          // state to query state.
10831|      0|          if ((input_position != input_size) &&
  ------------------
  |  Branch (10831:15): [True: 0, False: 0]
  ------------------
10832|      0|              (url_data[input_position] == '?')) {
  ------------------
  |  Branch (10832:15): [True: 0, False: 0]
  ------------------
10833|      0|            state = state::QUERY;
10834|      0|          }
10835|       |          // Otherwise, if c is not the EOF code point:
10836|      0|          else if (input_position != input_size) {
  ------------------
  |  Branch (10836:20): [True: 0, False: 0]
  ------------------
10837|       |            // Set url's query to null.
10838|      0|            url.clear_search();
10839|      0|            if constexpr (result_type_is_ada_url) {
10840|       |              // Shorten url's path.
10841|      0|              helpers::shorten_path(url.path, url.type);
10842|       |            } else {
10843|       |              std::string_view path = url.get_pathname();
10844|       |              if (helpers::shorten_path(path, url.type)) {
10845|       |                url.update_base_pathname(std::move(std::string(path)));
10846|       |              }
10847|       |            }
10848|       |            // Set state to path state and decrease pointer by 1.
10849|      0|            state = state::PATH;
10850|      0|            break;
10851|      0|          }
10852|      0|        }
10853|      0|        input_position++;
10854|      0|        break;
10855|      0|      }
10856|      0|      case state::RELATIVE_SLASH: {
  ------------------
  |  Branch (10856:7): [True: 0, False: 1.12M]
  ------------------
10857|      0|        ada_log("RELATIVE_SLASH ",
10858|      0|                helpers::substring(url_data, input_position));
10859|       |
10860|       |        // If url is special and c is U+002F (/) or U+005C (\), then:
10861|       |        // NOLINTNEXTLINE(bugprone-branch-clone)
10862|      0|        if (url.is_special() && (input_position != input_size) &&
  ------------------
  |  Branch (10862:13): [True: 0, False: 0]
  |  Branch (10862:33): [True: 0, False: 0]
  ------------------
10863|      0|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (10863:14): [True: 0, False: 0]
  ------------------
10864|      0|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (10864:14): [True: 0, False: 0]
  ------------------
10865|       |          // Set state to special authority ignore slashes state.
10866|      0|          state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES;
10867|      0|        }
10868|       |        // Otherwise, if c is U+002F (/), then set state to authority state.
10869|      0|        else if ((input_position != input_size) &&
  ------------------
  |  Branch (10869:18): [True: 0, False: 0]
  ------------------
10870|      0|                 (url_data[input_position] == '/')) {
  ------------------
  |  Branch (10870:18): [True: 0, False: 0]
  ------------------
10871|      0|          state = state::AUTHORITY;
10872|      0|        }
10873|       |        // Otherwise, set
10874|       |        // - url's username to base's username,
10875|       |        // - url's password to base's password,
10876|       |        // - url's host to base's host,
10877|       |        // - url's port to base's port,
10878|       |        // - state to path state, and then, decrease pointer by 1.
10879|      0|        else {
10880|      0|          if constexpr (result_type_is_ada_url) {
10881|      0|            url.username = base_url->username;
10882|      0|            url.password = base_url->password;
10883|      0|            url.host = base_url->host;
10884|      0|            url.port = base_url->port;
10885|       |          } else {
10886|       |            url.update_base_authority(base_url->get_href(),
10887|       |                                      base_url->get_components());
10888|       |            url.update_host_to_base_host(base_url->get_hostname());
10889|       |            url.update_base_port(base_url->retrieve_base_port());
10890|       |          }
10891|      0|          state = state::PATH;
10892|      0|          break;
10893|      0|        }
10894|       |
10895|      0|        input_position++;
10896|      0|        break;
10897|      0|      }
10898|   157k|      case state::SPECIAL_AUTHORITY_SLASHES: {
  ------------------
  |  Branch (10898:7): [True: 157k, False: 966k]
  ------------------
10899|   157k|        ada_log("SPECIAL_AUTHORITY_SLASHES ",
10900|   157k|                helpers::substring(url_data, input_position));
10901|       |
10902|       |        // If c is U+002F (/) and remaining starts with U+002F (/),
10903|       |        // then set state to special authority ignore slashes state and increase
10904|       |        // pointer by 1.
10905|   157k|        if (url_data.substr(input_position, 2) == "//") {
  ------------------
  |  Branch (10905:13): [True: 156k, False: 1.35k]
  ------------------
10906|   156k|          input_position += 2;
10907|   156k|        }
10908|       |
10909|   157k|        [[fallthrough]];
10910|   157k|      }
10911|   157k|      case state::SPECIAL_AUTHORITY_IGNORE_SLASHES: {
  ------------------
  |  Branch (10911:7): [True: 0, False: 1.12M]
  ------------------
10912|   157k|        ada_log("SPECIAL_AUTHORITY_IGNORE_SLASHES ",
10913|   157k|                helpers::substring(url_data, input_position));
10914|       |
10915|       |        // If c is neither U+002F (/) nor U+005C (\), then set state to
10916|       |        // authority state and decrease pointer by 1.
10917|   159k|        while ((input_position != input_size) &&
  ------------------
  |  Branch (10917:16): [True: 159k, False: 73]
  ------------------
10918|   159k|               ((url_data[input_position] == '/') ||
  ------------------
  |  Branch (10918:17): [True: 521, False: 159k]
  ------------------
10919|   159k|                (url_data[input_position] == '\\'))) {
  ------------------
  |  Branch (10919:17): [True: 1.49k, False: 157k]
  ------------------
10920|  2.01k|          input_position++;
10921|  2.01k|        }
10922|   157k|        state = state::AUTHORITY;
10923|       |
10924|   157k|        break;
10925|   157k|      }
10926|  10.0k|      case state::QUERY: {
  ------------------
  |  Branch (10926:7): [True: 10.0k, False: 1.11M]
  ------------------
10927|  10.0k|        ada_log("QUERY ", helpers::substring(url_data, input_position));
10928|  10.0k|        if constexpr (store_values) {
10929|       |          // Let queryPercentEncodeSet be the special-query percent-encode set
10930|       |          // if url is special; otherwise the query percent-encode set.
10931|  10.0k|          const uint8_t* query_percent_encode_set =
10932|  10.0k|              url.is_special() ? character_sets::SPECIAL_QUERY_PERCENT_ENCODE
  ------------------
  |  Branch (10932:15): [True: 9.07k, False: 1.00k]
  ------------------
10933|  10.0k|                               : character_sets::QUERY_PERCENT_ENCODE;
10934|       |
10935|       |          // Percent-encode after encoding, with encoding, buffer, and
10936|       |          // queryPercentEncodeSet, and append the result to url's query.
10937|  10.0k|          url.update_base_search(url_data.substr(input_position),
10938|  10.0k|                                 query_percent_encode_set);
10939|  10.0k|          ada_log("QUERY update_base_search completed ");
10940|  10.0k|          if (fragment.has_value()) {
  ------------------
  |  Branch (10940:15): [True: 7.36k, False: 2.71k]
  ------------------
10941|  7.36k|            url.update_unencoded_base_hash(*fragment);
10942|  7.36k|          }
10943|  10.0k|        }
10944|  10.0k|        return url;
10945|   157k|      }
10946|   158k|      case state::HOST: {
  ------------------
  |  Branch (10946:7): [True: 158k, False: 965k]
  ------------------
10947|   158k|        ada_log("HOST ", helpers::substring(url_data, input_position));
10948|       |
10949|   158k|        std::string_view host_view = url_data.substr(input_position);
10950|   158k|        auto [location, found_colon] =
10951|   158k|            helpers::get_host_delimiter_location(url.is_special(), host_view);
10952|   158k|        input_position = (location != std::string_view::npos)
  ------------------
  |  Branch (10952:26): [True: 158k, False: 0]
  ------------------
10953|   158k|                             ? input_position + location
10954|   158k|                             : input_size;
10955|       |        // Otherwise, if c is U+003A (:) and insideBrackets is false, then:
10956|       |        // Note: the 'found_colon' value is true if and only if a colon was
10957|       |        // encountered while not inside brackets.
10958|   158k|        if (found_colon) {
  ------------------
  |  Branch (10958:13): [True: 23.9k, False: 134k]
  ------------------
10959|       |          // If buffer is the empty string, validation error, return failure.
10960|       |          // Let host be the result of host parsing buffer with url is not
10961|       |          // special.
10962|  23.9k|          ada_log("HOST parsing ", host_view);
10963|  23.9k|          if (!url.parse_host(host_view)) {
  ------------------
  |  Branch (10963:15): [True: 161, False: 23.8k]
  ------------------
10964|    161|            return url;
10965|    161|          }
10966|  23.8k|          ada_log("HOST parsing results in ", url.get_hostname());
10967|       |          // Set url's host to host, buffer to the empty string, and state to
10968|       |          // port state.
10969|  23.8k|          state = state::PORT;
10970|  23.8k|          input_position++;
10971|  23.8k|        }
10972|       |        // Otherwise, if one of the following is true:
10973|       |        // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
10974|       |        // - url is special and c is U+005C (\)
10975|       |        // The get_host_delimiter_location function either brings us to
10976|       |        // the colon outside of the bracket, or to one of those characters.
10977|   134k|        else {
10978|       |          // If url is special and host_view is the empty string, validation
10979|       |          // error, return failure.
10980|   134k|          if (host_view.empty() && url.is_special()) {
  ------------------
  |  Branch (10980:15): [True: 125, False: 134k]
  |  Branch (10980:36): [True: 86, False: 39]
  ------------------
10981|     86|            url.is_valid = false;
10982|     86|            return url;
10983|     86|          }
10984|   134k|          ada_log("HOST parsing ", host_view, " href=", url.get_href());
10985|       |          // Let host be the result of host parsing host_view with url is not
10986|       |          // special.
10987|   134k|          if (host_view.empty()) {
  ------------------
  |  Branch (10987:15): [True: 39, False: 134k]
  ------------------
10988|     39|            url.update_base_hostname("");
10989|   134k|          } else if (!url.parse_host(host_view)) {
  ------------------
  |  Branch (10989:22): [True: 2.11k, False: 132k]
  ------------------
10990|  2.11k|            return url;
10991|  2.11k|          }
10992|   132k|          ada_log("HOST parsing results in ", url.get_hostname(),
10993|   132k|                  " href=", url.get_href());
10994|       |
10995|       |          // Set url's host to host, and state to path start state.
10996|   132k|          state = state::PATH_START;
10997|   132k|        }
10998|       |
10999|   156k|        break;
11000|   158k|      }
11001|   156k|      case state::OPAQUE_PATH: {
  ------------------
  |  Branch (11001:7): [True: 519, False: 1.12M]
  ------------------
11002|    519|        ada_log("OPAQUE_PATH ", helpers::substring(url_data, input_position));
11003|       |        // Opaque path, query, and fragment are structurally always valid:
11004|       |        // the parser would just percent-encode whatever is there. When we
11005|       |        // are not storing values (can_parse), we can return immediately.
11006|       |        // We must set has_opaque_path = true before returning so that when
11007|       |        // this URL is used as an internal base inside can_parse, NO_SCHEME
11008|       |        // correctly rejects relative inputs against an opaque-path base
11009|       |        // (e.g. can_parse("", &"W:") must return false).
11010|       |        if constexpr (!store_values) {
11011|       |          url.has_opaque_path = true;
11012|       |          return url;
11013|       |        }
11014|    519|        std::string_view view = url_data.substr(input_position);
11015|       |        // If c is U+003F (?), then set url's query to the empty string and
11016|       |        // state to query state.
11017|    519|        size_t location = view.find('?');
11018|    519|        if (location != std::string_view::npos) {
  ------------------
  |  Branch (11018:13): [True: 345, False: 174]
  ------------------
11019|    345|          view.remove_suffix(view.size() - location);
11020|    345|          state = state::QUERY;
11021|    345|          input_position += location + 1;
11022|    345|        } else {
11023|    174|          input_position = input_size + 1;
11024|    174|        }
11025|    519|        url.has_opaque_path = true;
11026|       |
11027|       |        // This is a really unlikely scenario in real world. We should not seek
11028|       |        // to optimize it.
11029|    519|        if (view.ends_with(' ')) {
  ------------------
  |  Branch (11029:13): [True: 13, False: 506]
  ------------------
11030|     13|          std::string modified_view =
11031|     13|              std::string(view.substr(0, view.size() - 1)) + "%20";
11032|     13|          url.update_base_pathname(unicode::percent_encode(
11033|     13|              modified_view, character_sets::C0_CONTROL_PERCENT_ENCODE));
11034|    506|        } else {
11035|    506|          url.update_base_pathname(unicode::percent_encode(
11036|    506|              view, character_sets::C0_CONTROL_PERCENT_ENCODE));
11037|    506|        }
11038|    519|        break;
11039|   158k|      }
11040|  23.8k|      case state::PORT: {
  ------------------
  |  Branch (11040:7): [True: 23.8k, False: 1.10M]
  ------------------
11041|  23.8k|        ada_log("PORT ", helpers::substring(url_data, input_position));
11042|  23.8k|        std::string_view port_view = url_data.substr(input_position);
11043|  23.8k|        input_position += url.parse_port(port_view, true);
11044|  23.8k|        if (!url.is_valid) {
  ------------------
  |  Branch (11044:13): [True: 148, False: 23.6k]
  ------------------
11045|    148|          return url;
11046|    148|        }
11047|  23.6k|        state = state::PATH_START;
11048|  23.6k|        [[fallthrough]];
11049|  23.6k|      }
11050|   156k|      case state::PATH_START: {
  ------------------
  |  Branch (11050:7): [True: 133k, False: 990k]
  ------------------
11051|   156k|        ada_log("PATH_START ", helpers::substring(url_data, input_position));
11052|       |        // Path, query, and fragment are structurally always valid: the
11053|       |        // parser would just percent-encode whatever is there. When we are
11054|       |        // not storing values (can_parse), we can return immediately since
11055|       |        // no subsequent state can invalidate the URL.
11056|       |        if constexpr (!store_values) {
11057|       |          return url;
11058|       |        }
11059|       |
11060|       |        // If url is special, then:
11061|   156k|        if (url.is_special()) {
  ------------------
  |  Branch (11061:13): [True: 156k, False: 609]
  ------------------
11062|       |          // Set state to path state.
11063|   156k|          state = state::PATH;
11064|       |
11065|       |          // Optimization: Avoiding going into PATH state improves the
11066|       |          // performance of urls ending with /.
11067|   156k|          if (input_position == input_size) {
  ------------------
  |  Branch (11067:15): [True: 2.18k, False: 154k]
  ------------------
11068|  2.18k|            if constexpr (store_values) {
11069|  2.18k|              url.update_base_pathname("/");
11070|  2.18k|              if (fragment.has_value()) {
  ------------------
  |  Branch (11070:19): [True: 282, False: 1.89k]
  ------------------
11071|    282|                url.update_unencoded_base_hash(*fragment);
11072|    282|              }
11073|  2.18k|            }
11074|  2.18k|            return url;
11075|  2.18k|          }
11076|       |          // If c is neither U+002F (/) nor U+005C (\), then decrease pointer
11077|       |          // by 1. We know that (input_position == input_size) is impossible
11078|       |          // here, because of the previous if-check.
11079|   154k|          if ((url_data[input_position] != '/') &&
  ------------------
  |  Branch (11079:15): [True: 1.03k, False: 153k]
  ------------------
11080|  1.03k|              (url_data[input_position] != '\\')) {
  ------------------
  |  Branch (11080:15): [True: 615, False: 416]
  ------------------
11081|    615|            break;
11082|    615|          }
11083|   154k|        }
11084|       |        // Otherwise, if state override is not given and c is U+003F (?),
11085|       |        // set url's query to the empty string and state to query state.
11086|    609|        else if ((input_position != input_size) &&
  ------------------
  |  Branch (11086:18): [True: 507, False: 102]
  ------------------
11087|    507|                 (url_data[input_position] == '?')) {
  ------------------
  |  Branch (11087:18): [True: 105, False: 402]
  ------------------
11088|    105|          state = state::QUERY;
11089|    105|        }
11090|       |        // Otherwise, if c is not the EOF code point:
11091|    504|        else if (input_position != input_size) {
  ------------------
  |  Branch (11091:18): [True: 402, False: 102]
  ------------------
11092|       |          // Set state to path state.
11093|    402|          state = state::PATH;
11094|       |
11095|       |          // If c is not U+002F (/), then decrease pointer by 1.
11096|    402|          if (url_data[input_position] != '/') {
  ------------------
  |  Branch (11096:15): [True: 0, False: 402]
  ------------------
11097|      0|            break;
11098|      0|          }
11099|    402|        }
11100|       |
11101|   154k|        input_position++;
11102|   154k|        break;
11103|   156k|      }
11104|   155k|      case state::PATH: {
  ------------------
  |  Branch (11104:7): [True: 155k, False: 969k]
  ------------------
11105|   155k|        ada_log("PATH ", helpers::substring(url_data, input_position));
11106|       |        // Path, query, and fragment are structurally always valid: the
11107|       |        // parser would just percent-encode whatever is there. When we are
11108|       |        // not storing values (can_parse), we can return immediately since
11109|       |        // no subsequent state can invalidate the URL.
11110|       |        if constexpr (!store_values) {
11111|       |          return url;
11112|       |        }
11113|   155k|        std::string_view view = url_data.substr(input_position);
11114|       |
11115|       |        // Most time, we do not need percent encoding.
11116|       |        // Furthermore, we can immediately locate the '?'.
11117|   155k|        size_t locofquestionmark = view.find('?');
11118|   155k|        if (locofquestionmark != std::string_view::npos) {
  ------------------
  |  Branch (11118:13): [True: 9.63k, False: 145k]
  ------------------
11119|  9.63k|          state = state::QUERY;
11120|  9.63k|          view.remove_suffix(view.size() - locofquestionmark);
11121|  9.63k|          input_position += locofquestionmark + 1;
11122|   145k|        } else {
11123|   145k|          input_position = input_size + 1;
11124|   145k|        }
11125|   155k|        if constexpr (store_values) {
11126|   155k|          if constexpr (result_type_is_ada_url) {
11127|   155k|            helpers::parse_prepared_path(view, url.type, url.path);
11128|       |          } else {
11129|       |            url.consume_prepared_path(view);
11130|       |            ADA_ASSERT_TRUE(url.validate());
11131|       |          }
11132|   155k|        }
11133|   155k|        break;
11134|   156k|      }
11135|  1.13k|      case state::FILE_SLASH: {
  ------------------
  |  Branch (11135:7): [True: 1.13k, False: 1.12M]
  ------------------
11136|  1.13k|        ada_log("FILE_SLASH ", helpers::substring(url_data, input_position));
11137|       |
11138|       |        // If c is U+002F (/) or U+005C (\), then:
11139|  1.13k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (11139:13): [True: 1.13k, False: 1]
  ------------------
11140|  1.13k|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (11140:14): [True: 1.12k, False: 17]
  ------------------
11141|  1.12k|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (11141:14): [True: 1, False: 16]
  ------------------
11142|  1.12k|          ada_log("FILE_SLASH c is U+002F or U+005C");
11143|       |          // Set state to file host state.
11144|  1.12k|          state = state::FILE_HOST;
11145|  1.12k|          input_position++;
11146|  1.12k|        } else {
11147|     17|          ada_log("FILE_SLASH otherwise");
11148|       |          // If base is non-null and base's scheme is "file", then:
11149|       |          // Note: it is unsafe to do base_url->scheme unless you know that
11150|       |          // base_url_has_value() is true.
11151|     17|          if (base_url != nullptr && base_url->type == scheme::type::FILE) {
  ------------------
  |  Branch (11151:15): [True: 0, False: 17]
  |  Branch (11151:38): [True: 0, False: 0]
  ------------------
11152|       |            // Set url's host to base's host.
11153|      0|            if constexpr (result_type_is_ada_url) {
11154|      0|              url.host = base_url->host;
11155|       |            } else {
11156|       |              url.update_host_to_base_host(base_url->get_host());
11157|       |            }
11158|       |            // If the code point substring from pointer to the end of input does
11159|       |            // not start with a Windows drive letter and base's path[0] is a
11160|       |            // normalized Windows drive letter, then append base's path[0] to
11161|       |            // url's path.
11162|      0|            if (!base_url->get_pathname().empty()) {
  ------------------
  |  Branch (11162:17): [True: 0, False: 0]
  ------------------
11163|      0|              if (!checkers::is_windows_drive_letter(
  ------------------
  |  Branch (11163:19): [True: 0, False: 0]
  ------------------
11164|      0|                      url_data.substr(input_position))) {
11165|      0|                std::string_view first_base_url_path =
11166|      0|                    base_url->get_pathname().substr(1);
11167|      0|                size_t loc = first_base_url_path.find('/');
11168|      0|                if (loc != std::string_view::npos) {
  ------------------
  |  Branch (11168:21): [True: 0, False: 0]
  ------------------
11169|      0|                  helpers::resize(first_base_url_path, loc);
11170|      0|                }
11171|      0|                if (checkers::is_normalized_windows_drive_letter(
  ------------------
  |  Branch (11171:21): [True: 0, False: 0]
  ------------------
11172|      0|                        first_base_url_path)) {
11173|      0|                  if constexpr (result_type_is_ada_url) {
11174|      0|                    url.path += '/';
11175|      0|                    url.path += first_base_url_path;
11176|       |                  } else {
11177|       |                    url.append_base_pathname(
11178|       |                        helpers::concat("/", first_base_url_path));
11179|       |                  }
11180|      0|                }
11181|      0|              }
11182|      0|            }
11183|      0|          }
11184|       |
11185|       |          // Set state to path state, and decrease pointer by 1.
11186|     17|          state = state::PATH;
11187|     17|        }
11188|       |
11189|  1.13k|        break;
11190|   156k|      }
11191|  1.12k|      case state::FILE_HOST: {
  ------------------
  |  Branch (11191:7): [True: 1.12k, False: 1.12M]
  ------------------
11192|  1.12k|        ada_log("FILE_HOST ", helpers::substring(url_data, input_position));
11193|  1.12k|        std::string_view view = url_data.substr(input_position);
11194|       |
11195|  1.12k|        size_t location = view.find_first_of("/\\?");
11196|  1.12k|        std::string_view file_host_buffer = view.substr(
11197|  1.12k|            0, (location != std::string_view::npos) ? location : view.size());
  ------------------
  |  Branch (11197:16): [True: 1.09k, False: 27]
  ------------------
11198|       |
11199|  1.12k|        if (checkers::is_windows_drive_letter(file_host_buffer)) {
  ------------------
  |  Branch (11199:13): [True: 1, False: 1.12k]
  ------------------
11200|      1|          state = state::PATH;
11201|  1.12k|        } else if (file_host_buffer.empty()) {
  ------------------
  |  Branch (11201:20): [True: 355, False: 765]
  ------------------
11202|       |          // Set url's host to the empty string.
11203|    355|          if constexpr (result_type_is_ada_url) {
11204|    355|            url.host = "";
11205|       |          } else {
11206|       |            url.update_base_hostname("");
11207|       |          }
11208|       |          // Set state to path start state.
11209|    355|          state = state::PATH_START;
11210|    765|        } else {
11211|    765|          size_t consumed_bytes = file_host_buffer.size();
11212|    765|          input_position += consumed_bytes;
11213|       |          // Let host be the result of host parsing buffer with url is not
11214|       |          // special.
11215|    765|          if (!url.parse_host(file_host_buffer)) {
  ------------------
  |  Branch (11215:15): [True: 82, False: 683]
  ------------------
11216|     82|            return url;
11217|     82|          }
11218|       |
11219|    683|          if constexpr (result_type_is_ada_url) {
11220|       |            // If host is "localhost", then set host to the empty string.
11221|    683|            if (url.host.has_value() && url.host.value() == "localhost") {
  ------------------
  |  Branch (11221:17): [True: 683, False: 0]
  |  Branch (11221:41): [True: 2, False: 681]
  ------------------
11222|      2|              url.host = "";
11223|      2|            }
11224|       |          } else {
11225|       |            if (url.get_hostname() == "localhost") {
11226|       |              url.update_base_hostname("");
11227|       |            }
11228|       |          }
11229|       |
11230|       |          // Set buffer to the empty string and state to path start state.
11231|    683|          state = state::PATH_START;
11232|    683|        }
11233|       |
11234|  1.03k|        break;
11235|  1.12k|      }
11236|  1.28k|      case state::FILE: {
  ------------------
  |  Branch (11236:7): [True: 1.28k, False: 1.12M]
  ------------------
11237|  1.28k|        ada_log("FILE ", helpers::substring(url_data, input_position));
11238|  1.28k|        std::string_view file_view = url_data.substr(input_position);
11239|       |
11240|  1.28k|        url.set_protocol_as_file();
11241|  1.28k|        if constexpr (result_type_is_ada_url) {
11242|       |          // Set url's host to the empty string.
11243|  1.28k|          url.host = "";
11244|       |        } else {
11245|       |          url.update_base_hostname("");
11246|       |        }
11247|       |        // If c is U+002F (/) or U+005C (\), then:
11248|  1.28k|        if (input_position != input_size &&
  ------------------
  |  Branch (11248:13): [True: 1.28k, False: 1]
  ------------------
11249|  1.28k|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (11249:14): [True: 1.13k, False: 150]
  ------------------
11250|  1.13k|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (11250:14): [True: 1, False: 149]
  ------------------
11251|  1.13k|          ada_log("FILE c is U+002F or U+005C");
11252|       |          // Set state to file slash state.
11253|  1.13k|          state = state::FILE_SLASH;
11254|  1.13k|        }
11255|       |        // Otherwise, if base is non-null and base's scheme is "file":
11256|    150|        else if (base_url != nullptr && base_url->type == scheme::type::FILE) {
  ------------------
  |  Branch (11256:18): [True: 0, False: 150]
  |  Branch (11256:41): [True: 0, False: 0]
  ------------------
11257|       |          // Set url's host to base's host, url's path to a clone of base's
11258|       |          // path, and url's query to base's query.
11259|      0|          ada_log("FILE base non-null");
11260|      0|          if constexpr (result_type_is_ada_url) {
11261|      0|            url.host = base_url->host;
11262|      0|            url.path = base_url->path;
11263|      0|            url.query = base_url->query;
11264|       |          } else {
11265|       |            url.update_host_to_base_host(base_url->get_hostname());
11266|       |            url.update_base_pathname(base_url->get_pathname());
11267|       |            if (base_url->has_search()) {
11268|       |              // get_search() returns "" for an empty query string (URL ends
11269|       |              // with '?'). update_base_search("") would incorrectly clear the
11270|       |              // query, so pass "?" to preserve the empty query distinction.
11271|       |              auto s = base_url->get_search();
11272|       |              url.update_base_search(s.empty() ? std::string_view("?") : s);
11273|       |            }
11274|       |          }
11275|      0|          url.has_opaque_path = base_url->has_opaque_path;
11276|       |
11277|       |          // If c is U+003F (?), then set url's query to the empty string and
11278|       |          // state to query state.
11279|      0|          if (input_position != input_size && url_data[input_position] == '?') {
  ------------------
  |  Branch (11279:15): [True: 0, False: 0]
  |  Branch (11279:47): [True: 0, False: 0]
  ------------------
11280|      0|            state = state::QUERY;
11281|      0|          }
11282|       |          // Otherwise, if c is not the EOF code point:
11283|      0|          else if (input_position != input_size) {
  ------------------
  |  Branch (11283:20): [True: 0, False: 0]
  ------------------
11284|       |            // Set url's query to null.
11285|      0|            url.clear_search();
11286|       |            // If the code point substring from pointer to the end of input does
11287|       |            // not start with a Windows drive letter, then shorten url's path.
11288|      0|            if (!checkers::is_windows_drive_letter(file_view)) {
  ------------------
  |  Branch (11288:17): [True: 0, False: 0]
  ------------------
11289|      0|              if constexpr (result_type_is_ada_url) {
11290|      0|                helpers::shorten_path(url.path, url.type);
11291|       |              } else {
11292|       |                std::string_view path = url.get_pathname();
11293|       |                if (helpers::shorten_path(path, url.type)) {
11294|       |                  url.update_base_pathname(std::move(std::string(path)));
11295|       |                }
11296|       |              }
11297|      0|            }
11298|       |            // Otherwise:
11299|      0|            else {
11300|       |              // Set url's path to an empty list.
11301|      0|              url.clear_pathname();
11302|      0|              url.has_opaque_path = true;
11303|      0|            }
11304|       |
11305|       |            // Set state to path state and decrease pointer by 1.
11306|      0|            state = state::PATH;
11307|      0|            break;
11308|      0|          }
11309|      0|        }
11310|       |        // Otherwise, set state to path state, and decrease pointer by 1.
11311|    150|        else {
11312|    150|          ada_log("FILE go to path");
11313|    150|          state = state::PATH;
11314|    150|          break;
11315|    150|        }
11316|       |
11317|  1.13k|        input_position++;
11318|  1.13k|        break;
11319|  1.28k|      }
11320|      0|      default:
  ------------------
  |  Branch (11320:7): [True: 0, False: 1.12M]
  ------------------
11321|      0|        unreachable();
11322|  1.12M|    }
11323|  1.12M|  }
11324|   342k|  if constexpr (store_values) {
11325|   342k|    if (fragment.has_value()) {
  ------------------
  |  Branch (11325:9): [True: 2.41k, False: 340k]
  ------------------
11326|  2.41k|      url.update_unencoded_base_hash(*fragment);
11327|  2.41k|    }
11328|   342k|  }
11329|       |  // Check the resulting (normalized) URL size against the maximum input length.
11330|       |  // Normalization (percent-encoding, IDNA, etc.) can expand the URL beyond the
11331|       |  // original input size.
11332|   342k|  if constexpr (store_values) {
11333|   342k|    if (url.is_valid) {
  ------------------
  |  Branch (11333:9): [True: 145k, False: 196k]
  ------------------
11334|       |      if constexpr (result_type_is_ada_url_aggregator) {
11335|       |        if (url.buffer.size() > max_input_length) {
11336|       |          url.is_valid = false;
11337|       |        }
11338|   145k|      } else {
11339|   145k|        if (url.get_href_size() > max_input_length) {
  ------------------
  |  Branch (11339:13): [True: 0, False: 145k]
  ------------------
11340|      0|          url.is_valid = false;
11341|      0|        }
11342|   145k|      }
11343|   145k|    }
11344|   342k|  }
11345|   342k|  return url;
11346|   357k|}
_ZN3ada6parser14parse_url_implINS_14url_aggregatorELb1EEET_NSt3__117basic_string_viewIcNS4_11char_traitsIcEEEEPKS3_:
10361|   357k|                           const result_type* base_url) {
10362|       |  // We can specialize the implementation per type.
10363|       |  // Important: result_type_is_ada_url is evaluated at *compile time*. This
10364|       |  // means that doing if constexpr(result_type_is_ada_url) { something } else {
10365|       |  // something else } is free (at runtime). This means that ada::url_aggregator
10366|       |  // and ada::url **do not have to support the exact same API**.
10367|   357k|  constexpr bool result_type_is_ada_url = std::is_same_v<url, result_type>;
10368|   357k|  constexpr bool result_type_is_ada_url_aggregator =
10369|   357k|      std::is_same_v<url_aggregator, result_type>;
10370|   357k|  static_assert(result_type_is_ada_url ||
10371|   357k|                result_type_is_ada_url_aggregator);  // We don't support
10372|       |                                                     // anything else for now.
10373|       |
10374|   357k|  ada_log("ada::parser::parse_url('", user_input, "' [", user_input.size(),
10375|   357k|          " bytes],", (base_url != nullptr ? base_url->to_string() : "null"),
10376|   357k|          ")");
10377|       |
10378|   357k|  state state = state::SCHEME_START;
10379|   357k|  result_type url{};
10380|       |
10381|   357k|  const uint32_t max_input_length = ada::get_max_input_length();
10382|       |
10383|       |  // We refuse to parse URL strings that exceed the maximum input length.
10384|       |  // By default, this is 4GB but can be configured via
10385|       |  // ada::set_max_input_length().
10386|   357k|  if (user_input.size() > max_input_length) [[unlikely]] {
  ------------------
  |  Branch (10386:7): [True: 0, False: 357k]
  ------------------
10387|      0|    url.is_valid = false;
10388|      0|  }
10389|       |  // Going forward, user_input.size() is in [0,
10390|       |  // std::numeric_limits<uint32_t>::max). If we are provided with an invalid
10391|       |  // base, or the optional_url was invalid, we must return.
10392|   357k|  if (base_url != nullptr) {
  ------------------
  |  Branch (10392:7): [True: 0, False: 357k]
  ------------------
10393|      0|    url.is_valid &= base_url->is_valid;
10394|      0|  }
10395|   357k|  if (!url.is_valid) {
  ------------------
  |  Branch (10395:7): [True: 0, False: 357k]
  ------------------
10396|      0|    return url;
10397|      0|  }
10398|       |
10399|       |  // Simple absolute http(s) fast path (before tabs/newline scan).
10400|       |  // Skip digit-led hosts (IPv4) with a cheap peek.
10401|   357k|  if constexpr (store_values) {
10402|   357k|    if (base_url == nullptr) {
  ------------------
  |  Branch (10402:9): [True: 357k, False: 0]
  ------------------
10403|   357k|      const auto* p = reinterpret_cast<const uint8_t*>(user_input.data());
10404|   357k|      const size_t n = user_input.size();
10405|   357k|      const bool digit_led_host = (n >= 8 && p[4] == ':' && p[5] == '/' &&
  ------------------
  |  Branch (10405:36): [True: 357k, False: 45]
  |  Branch (10405:46): [True: 99.1k, False: 258k]
  |  Branch (10405:61): [True: 98.3k, False: 799]
  ------------------
10406|  98.3k|                                   p[6] == '/' && p[7] >= '0' && p[7] <= '9') ||
  ------------------
  |  Branch (10406:36): [True: 98.2k, False: 139]
  |  Branch (10406:51): [True: 96.3k, False: 1.86k]
  |  Branch (10406:66): [True: 45.2k, False: 51.0k]
  ------------------
10407|   312k|                                  (n >= 9 && p[5] == ':' && p[6] == '/' &&
  ------------------
  |  Branch (10407:36): [True: 312k, False: 124]
  |  Branch (10407:46): [True: 257k, False: 54.8k]
  |  Branch (10407:61): [True: 256k, False: 737]
  ------------------
10408|   256k|                                   p[7] == '/' && p[8] >= '0' && p[8] <= '9');
  ------------------
  |  Branch (10408:36): [True: 256k, False: 69]
  |  Branch (10408:51): [True: 256k, False: 645]
  |  Branch (10408:66): [True: 2.20k, False: 253k]
  ------------------
10409|   357k|      if (!digit_led_host && try_parse_simple_absolute(user_input, url)) {
  ------------------
  |  Branch (10409:11): [True: 310k, False: 47.4k]
  |  Branch (10409:30): [True: 196k, False: 113k]
  ------------------
10410|   196k|        if constexpr (result_type_is_ada_url_aggregator) {
10411|   196k|          if (url.buffer.size() > max_input_length) [[unlikely]] {
  ------------------
  |  Branch (10411:15): [True: 0, False: 196k]
  ------------------
10412|      0|            url.is_valid = false;
10413|      0|          }
10414|       |        } else {
10415|       |          if (url.get_href_size() > max_input_length) [[unlikely]] {
10416|       |            url.is_valid = false;
10417|       |          }
10418|       |        }
10419|   196k|        return url;
10420|   196k|      }
10421|   357k|    }
10422|   357k|  }
10423|       |
10424|   160k|  std::string tmp_buffer;
10425|   357k|  std::string_view url_data;
10426|   357k|  if (unicode::has_tabs_or_newline(user_input)) [[unlikely]] {
  ------------------
  |  Branch (10426:7): [True: 442, False: 357k]
  ------------------
10427|    442|    tmp_buffer = user_input;
10428|       |    // Optimization opportunity: Instead of copying and then pruning, we could
10429|       |    // just directly build the string from user_input.
10430|    442|    helpers::remove_ascii_tab_or_newline(tmp_buffer);
10431|    442|    url_data = tmp_buffer;
10432|   357k|  } else [[likely]] {
10433|   357k|    url_data = user_input;
10434|   357k|  }
10435|       |
10436|       |  // Leading and trailing control characters are uncommon and easy to deal with
10437|       |  // (no performance concern).
10438|   357k|  helpers::trim_c0_whitespace(url_data);
10439|       |
10440|   357k|  if constexpr (result_type_is_ada_url_aggregator && store_values) {
10441|       |    // Most of the time, we just need user_input.size().
10442|       |    // In some instances, we may need a bit more.
10443|       |    ///////////////////////////
10444|       |    // This is *very* important. This line should *not* be removed
10445|       |    // hastily. There are principled reasons why reserve is important
10446|       |    // for performance. If you have a benchmark with small inputs,
10447|       |    // it may not matter, but in other instances, it could.
10448|       |    ////
10449|       |    // This rounds up to the next power of two.
10450|       |    // We know that user_input.size() is in [0,
10451|       |    // std::numeric_limits<uint32_t>::max).
10452|   357k|    uint32_t reserve_capacity =
10453|   357k|        (0xFFFFFFFF >>
10454|   357k|         helpers::leading_zeroes(uint32_t(1 | user_input.size()))) +
10455|   357k|        1;
10456|   357k|    url.reserve(reserve_capacity);
10457|   357k|  }
10458|       |
10459|       |  // Optimization opportunity. Most websites do not have fragment.
10460|   357k|  std::optional<std::string_view> fragment = helpers::prune_hash(url_data);
10461|       |  // We add it last so that an implementation like ada::url_aggregator
10462|       |  // can append it last to its internal buffer, thus improving performance.
10463|       |
10464|       |  // Here url_data no longer has its fragment.
10465|       |  // We are going to access the data from url_data (it is immutable).
10466|       |  // At any given time, we are pointing at byte 'input_position' in url_data.
10467|       |  // The input_position variable should range from 0 to input_size.
10468|       |  // It is illegal to access url_data at input_size.
10469|   357k|  size_t input_position = 0;
10470|   357k|  const size_t input_size = url_data.size();
10471|       |  // Keep running the following state machine by switching on state.
10472|       |  // If after a run pointer points to the EOF code point, go to the next step.
10473|       |  // Otherwise, increase pointer by 1 and continue with the state machine.
10474|       |  // We never decrement input_position.
10475|  1.46M|  while (input_position <= input_size) {
  ------------------
  |  Branch (10475:10): [True: 1.12M, False: 342k]
  ------------------
10476|  1.12M|    ada_log("In parsing at ", input_position, " out of ", input_size,
10477|  1.12M|            " in state ", ada::to_string(state));
10478|  1.12M|    switch (state) {
10479|   160k|      case state::SCHEME_START: {
  ------------------
  |  Branch (10479:7): [True: 160k, False: 963k]
  ------------------
10480|   160k|        ada_log("SCHEME_START ", helpers::substring(url_data, input_position));
10481|       |        // If c is an ASCII alpha, append c, lowercased, to buffer, and set
10482|       |        // state to scheme state.
10483|   160k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (10483:13): [True: 160k, False: 1]
  ------------------
10484|   160k|            checkers::is_alpha(url_data[input_position])) {
  ------------------
  |  Branch (10484:13): [True: 160k, False: 45]
  ------------------
10485|   160k|          state = state::SCHEME;
10486|   160k|          input_position++;
10487|   160k|        } else {
10488|       |          // Otherwise, if state override is not given, set state to no scheme
10489|       |          // state and decrease pointer by 1.
10490|     46|          state = state::NO_SCHEME;
10491|     46|        }
10492|   160k|        break;
10493|      0|      }
10494|   160k|      case state::SCHEME: {
  ------------------
  |  Branch (10494:7): [True: 160k, False: 963k]
  ------------------
10495|   160k|        ada_log("SCHEME ", helpers::substring(url_data, input_position));
10496|       |        // If c is an ASCII alphanumeric, U+002B (+), U+002D (-), or U+002E (.),
10497|       |        // append c, lowercased, to buffer.
10498|   746k|        while ((input_position != input_size) &&
  ------------------
  |  Branch (10498:16): [True: 746k, False: 1]
  ------------------
10499|   746k|               (unicode::is_alnum_plus(url_data[input_position]))) {
  ------------------
  |  Branch (10499:16): [True: 586k, False: 160k]
  ------------------
10500|   586k|          input_position++;
10501|   586k|        }
10502|       |        // Otherwise, if c is U+003A (:), then:
10503|   160k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (10503:13): [True: 160k, False: 1]
  ------------------
10504|   160k|            (url_data[input_position] == ':')) {
  ------------------
  |  Branch (10504:13): [True: 160k, False: 57]
  ------------------
10505|   160k|          ada_log("SCHEME the scheme should be ",
10506|   160k|                  url_data.substr(0, input_position));
10507|       |          if constexpr (result_type_is_ada_url) {
10508|       |            if (!url.parse_scheme(url_data.substr(0, input_position))) {
10509|       |              return url;
10510|       |            }
10511|   160k|          } else {
10512|       |            // we pass the colon along instead of painfully adding it back.
10513|   160k|            if (!url.parse_scheme_with_colon(
  ------------------
  |  Branch (10513:17): [True: 0, False: 160k]
  ------------------
10514|   160k|                    url_data.substr(0, input_position + 1))) {
10515|      0|              return url;
10516|      0|            }
10517|   160k|          }
10518|   160k|          ada_log("SCHEME the scheme is ", url.get_protocol());
10519|       |
10520|       |          // If url's scheme is "file", then:
10521|       |          // NOLINTNEXTLINE(bugprone-branch-clone)
10522|   160k|          if (url.type == scheme::type::FILE) {
  ------------------
  |  Branch (10522:15): [True: 1.28k, False: 159k]
  ------------------
10523|       |            // Set state to file state.
10524|  1.28k|            state = state::FILE;
10525|  1.28k|          }
10526|       |          // Otherwise, if url is special, base is non-null, and base's scheme
10527|       |          // is url's scheme: Note: Doing base_url->scheme is unsafe if base_url
10528|       |          // != nullptr is false.
10529|   159k|          else if (url.is_special() && base_url != nullptr &&
  ------------------
  |  Branch (10529:20): [True: 157k, False: 1.54k]
  |  Branch (10529:40): [True: 0, False: 157k]
  ------------------
10530|      0|                   base_url->type == url.type) {
  ------------------
  |  Branch (10530:20): [True: 0, False: 0]
  ------------------
10531|       |            // Set state to special relative or authority state.
10532|      0|            state = state::SPECIAL_RELATIVE_OR_AUTHORITY;
10533|      0|          }
10534|       |          // Otherwise, if url is special, set state to special authority
10535|       |          // slashes state.
10536|   159k|          else if (url.is_special()) {
  ------------------
  |  Branch (10536:20): [True: 157k, False: 1.54k]
  ------------------
10537|   157k|            state = state::SPECIAL_AUTHORITY_SLASHES;
10538|   157k|          }
10539|       |          // Otherwise, if remaining starts with an U+002F (/), set state to
10540|       |          // path or authority state and increase pointer by 1.
10541|  1.54k|          else if (input_position + 1 < input_size &&
  ------------------
  |  Branch (10541:20): [True: 1.50k, False: 33]
  ------------------
10542|  1.50k|                   url_data[input_position + 1] == '/') {
  ------------------
  |  Branch (10542:20): [True: 1.02k, False: 486]
  ------------------
10543|  1.02k|            state = state::PATH_OR_AUTHORITY;
10544|  1.02k|            input_position++;
10545|  1.02k|          }
10546|       |          // Otherwise, set url's path to the empty string and set state to
10547|       |          // opaque path state.
10548|    519|          else {
10549|    519|            state = state::OPAQUE_PATH;
10550|    519|          }
10551|   160k|        }
10552|       |        // Otherwise, if state override is not given, set buffer to the empty
10553|       |        // string, state to no scheme state, and start over (from the first code
10554|       |        // point in input).
10555|     58|        else {
10556|     58|          state = state::NO_SCHEME;
10557|     58|          input_position = 0;
10558|     58|          break;
10559|     58|        }
10560|   160k|        input_position++;
10561|   160k|        break;
10562|   160k|      }
10563|    104|      case state::NO_SCHEME: {
  ------------------
  |  Branch (10563:7): [True: 104, False: 1.12M]
  ------------------
10564|    104|        ada_log("NO_SCHEME ", helpers::substring(url_data, input_position));
10565|       |        // If base is null, or base has an opaque path and c is not U+0023 (#),
10566|       |        // validation error, return failure.
10567|    104|        if (base_url == nullptr ||
  ------------------
  |  Branch (10567:13): [True: 104, False: 0]
  ------------------
10568|    104|            (base_url->has_opaque_path && !fragment.has_value())) {
  ------------------
  |  Branch (10568:14): [True: 0, False: 0]
  |  Branch (10568:43): [True: 0, False: 0]
  ------------------
10569|    104|          ada_log("NO_SCHEME validation error");
10570|    104|          url.is_valid = false;
10571|    104|          return url;
10572|    104|        }
10573|       |        // Otherwise, if base has an opaque path and c is U+0023 (#),
10574|       |        // set url's scheme to base's scheme, url's path to base's path, url's
10575|       |        // query to base's query, and set state to fragment state.
10576|      0|        else if (base_url->has_opaque_path && fragment.has_value() &&
  ------------------
  |  Branch (10576:18): [True: 0, False: 0]
  |  Branch (10576:47): [True: 0, False: 0]
  ------------------
10577|      0|                 input_position == input_size) {
  ------------------
  |  Branch (10577:18): [True: 0, False: 0]
  ------------------
10578|      0|          ada_log("NO_SCHEME opaque base with fragment");
10579|      0|          url.copy_scheme(*base_url);
10580|      0|          url.has_opaque_path = base_url->has_opaque_path;
10581|       |
10582|       |          if constexpr (result_type_is_ada_url) {
10583|       |            url.path = base_url->path;
10584|       |            url.query = base_url->query;
10585|      0|          } else {
10586|      0|            url.update_base_pathname(base_url->get_pathname());
10587|      0|            if (base_url->has_search()) {
  ------------------
  |  Branch (10587:17): [True: 0, False: 0]
  ------------------
10588|       |              // get_search() returns "" for an empty query string (URL ends
10589|       |              // with '?'). update_base_search("") would incorrectly clear the
10590|       |              // query, so pass "?" to preserve the empty query distinction.
10591|      0|              auto s = base_url->get_search();
10592|      0|              url.update_base_search(s.empty() ? std::string_view("?") : s);
  ------------------
  |  Branch (10592:38): [True: 0, False: 0]
  ------------------
10593|      0|            }
10594|      0|          }
10595|      0|          url.update_unencoded_base_hash(*fragment);
10596|      0|          return url;
10597|      0|        }
10598|       |        // Otherwise, if base's scheme is not "file", set state to relative
10599|       |        // state and decrease pointer by 1.
10600|       |        // NOLINTNEXTLINE(bugprone-branch-clone)
10601|      0|        else if (base_url->type != scheme::type::FILE) {
  ------------------
  |  Branch (10601:18): [True: 0, False: 0]
  ------------------
10602|      0|          ada_log("NO_SCHEME non-file relative path");
10603|      0|          state = state::RELATIVE_SCHEME;
10604|      0|        }
10605|       |        // Otherwise, set state to file state and decrease pointer by 1.
10606|      0|        else {
10607|      0|          ada_log("NO_SCHEME file base type");
10608|      0|          state = state::FILE;
10609|      0|        }
10610|      0|        break;
10611|    104|      }
10612|   158k|      case state::AUTHORITY: {
  ------------------
  |  Branch (10612:7): [True: 158k, False: 965k]
  ------------------
10613|   158k|        ada_log("AUTHORITY ", helpers::substring(url_data, input_position));
10614|       |        // most URLs have no @. Having no @ tells us that we don't have to worry
10615|       |        // about AUTHORITY. Of course, we could have @ and still not have to
10616|       |        // worry about AUTHORITY.
10617|       |        // TODO: Instead of just collecting a bool, collect the location of the
10618|       |        // '@' and do something useful with it.
10619|       |        // TODO: We could do various processing early on, using a single pass
10620|       |        // over the string to collect information about it, e.g., telling us
10621|       |        // whether there is a @ and if so, where (or how many).
10622|       |
10623|       |        // Check if url data contains an @.
10624|   158k|        if (url_data.find('@', input_position) == std::string_view::npos) {
  ------------------
  |  Branch (10624:13): [True: 135k, False: 23.4k]
  ------------------
10625|   135k|          state = state::HOST;
10626|   135k|          break;
10627|   135k|        }
10628|  23.4k|        bool at_sign_seen{false};
10629|  23.4k|        bool password_token_seen{false};
10630|       |        /**
10631|       |         * We expect something of the sort...
10632|       |         * https://user:pass@example.com:1234/foo/bar?baz#quux
10633|       |         * --------^
10634|       |         */
10635|  59.3k|        do {
10636|  59.3k|          std::string_view view = url_data.substr(input_position);
10637|       |          // The delimiters are @, /, ? \\.
10638|  59.3k|          size_t location =
10639|  59.3k|              url.is_special() ? helpers::find_authority_delimiter_special(view)
  ------------------
  |  Branch (10639:15): [True: 59.0k, False: 302]
  ------------------
10640|  59.3k|                               : helpers::find_authority_delimiter(view);
10641|  59.3k|          std::string_view authority_view = view.substr(0, location);
10642|  59.3k|          size_t end_of_authority = input_position + authority_view.size();
10643|       |          // If c is U+0040 (@), then:
10644|  59.3k|          if ((end_of_authority != input_size) &&
  ------------------
  |  Branch (10644:15): [True: 58.9k, False: 452]
  ------------------
10645|  58.9k|              (url_data[end_of_authority] == '@')) {
  ------------------
  |  Branch (10645:15): [True: 35.8k, False: 23.0k]
  ------------------
10646|       |            // If atSignSeen is true, then prepend "%40" to buffer.
10647|  35.8k|            if (at_sign_seen) {
  ------------------
  |  Branch (10647:17): [True: 12.6k, False: 23.2k]
  ------------------
10648|  12.6k|              if (password_token_seen) {
  ------------------
  |  Branch (10648:19): [True: 4.28k, False: 8.36k]
  ------------------
10649|       |                if constexpr (result_type_is_ada_url) {
10650|       |                  url.password += "%40";
10651|  4.28k|                } else {
10652|  4.28k|                  url.append_base_password("%40");
10653|  4.28k|                }
10654|  8.36k|              } else {
10655|       |                if constexpr (result_type_is_ada_url) {
10656|       |                  url.username += "%40";
10657|  8.36k|                } else {
10658|  8.36k|                  url.append_base_username("%40");
10659|  8.36k|                }
10660|  8.36k|              }
10661|  12.6k|            }
10662|       |
10663|  35.8k|            at_sign_seen = true;
10664|       |
10665|  35.8k|            if (!password_token_seen) {
  ------------------
  |  Branch (10665:17): [True: 31.5k, False: 4.28k]
  ------------------
10666|  31.5k|              size_t password_token_location = authority_view.find(':');
10667|  31.5k|              password_token_seen =
10668|  31.5k|                  password_token_location != std::string_view::npos;
10669|       |
10670|  31.5k|              if constexpr (store_values) {
10671|  31.5k|                if (!password_token_seen) {
  ------------------
  |  Branch (10671:21): [True: 9.39k, False: 22.2k]
  ------------------
10672|       |                  if constexpr (result_type_is_ada_url) {
10673|       |                    url.username += unicode::percent_encode(
10674|       |                        authority_view,
10675|       |                        character_sets::USERINFO_PERCENT_ENCODE);
10676|  9.39k|                  } else {
10677|  9.39k|                    url.append_base_username(unicode::percent_encode(
10678|  9.39k|                        authority_view,
10679|  9.39k|                        character_sets::USERINFO_PERCENT_ENCODE));
10680|  9.39k|                  }
10681|  22.2k|                } else {
10682|       |                  if constexpr (result_type_is_ada_url) {
10683|       |                    url.username += unicode::percent_encode(
10684|       |                        authority_view.substr(0, password_token_location),
10685|       |                        character_sets::USERINFO_PERCENT_ENCODE);
10686|       |                    url.password += unicode::percent_encode(
10687|       |                        authority_view.substr(password_token_location + 1),
10688|       |                        character_sets::USERINFO_PERCENT_ENCODE);
10689|  22.2k|                  } else {
10690|  22.2k|                    url.append_base_username(unicode::percent_encode(
10691|  22.2k|                        authority_view.substr(0, password_token_location),
10692|  22.2k|                        character_sets::USERINFO_PERCENT_ENCODE));
10693|  22.2k|                    url.append_base_password(unicode::percent_encode(
10694|  22.2k|                        authority_view.substr(password_token_location + 1),
10695|  22.2k|                        character_sets::USERINFO_PERCENT_ENCODE));
10696|  22.2k|                  }
10697|  22.2k|                }
10698|  31.5k|              }
10699|  31.5k|            } else if constexpr (store_values) {
10700|       |              if constexpr (result_type_is_ada_url) {
10701|       |                url.password += unicode::percent_encode(
10702|       |                    authority_view, character_sets::USERINFO_PERCENT_ENCODE);
10703|  4.28k|              } else {
10704|  4.28k|                url.append_base_password(unicode::percent_encode(
10705|  4.28k|                    authority_view, character_sets::USERINFO_PERCENT_ENCODE));
10706|  4.28k|              }
10707|  4.28k|            }
10708|  35.8k|          }
10709|       |          // Otherwise, if one of the following is true:
10710|       |          // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
10711|       |          // - url is special and c is U+005C (\)
10712|  23.4k|          else if (end_of_authority == input_size ||
  ------------------
  |  Branch (10712:20): [True: 452, False: 23.0k]
  ------------------
10713|  23.0k|                   url_data[end_of_authority] == '/' ||
  ------------------
  |  Branch (10713:20): [True: 22.8k, False: 184]
  ------------------
10714|    184|                   url_data[end_of_authority] == '?' ||
  ------------------
  |  Branch (10714:20): [True: 138, False: 46]
  ------------------
10715|  23.4k|                   (url.is_special() && url_data[end_of_authority] == '\\')) {
  ------------------
  |  Branch (10715:21): [True: 46, False: 0]
  |  Branch (10715:41): [True: 46, False: 0]
  ------------------
10716|       |            // If atSignSeen is true and authority_view is the empty string,
10717|       |            // validation error, return failure.
10718|  23.4k|            if (at_sign_seen && authority_view.empty()) {
  ------------------
  |  Branch (10718:17): [True: 23.2k, False: 248]
  |  Branch (10718:33): [True: 189, False: 23.0k]
  ------------------
10719|    189|              url.is_valid = false;
10720|    189|              return url;
10721|    189|            }
10722|  23.2k|            state = state::HOST;
10723|  23.2k|            break;
10724|  23.4k|          }
10725|  35.8k|          if (end_of_authority == input_size) {
  ------------------
  |  Branch (10725:15): [True: 0, False: 35.8k]
  ------------------
10726|      0|            if constexpr (store_values) {
10727|      0|              if (fragment.has_value()) {
  ------------------
  |  Branch (10727:19): [True: 0, False: 0]
  ------------------
10728|      0|                url.update_unencoded_base_hash(*fragment);
10729|      0|              }
10730|      0|            }
10731|      0|            return url;
10732|      0|          }
10733|  35.8k|          input_position = end_of_authority + 1;
10734|  35.8k|        } while (true);
  ------------------
  |  Branch (10734:18): [True: 35.8k, Folded]
  ------------------
10735|       |
10736|  23.2k|        break;
10737|  23.4k|      }
10738|  23.2k|      case state::SPECIAL_RELATIVE_OR_AUTHORITY: {
  ------------------
  |  Branch (10738:7): [True: 0, False: 1.12M]
  ------------------
10739|      0|        ada_log("SPECIAL_RELATIVE_OR_AUTHORITY ",
10740|      0|                helpers::substring(url_data, input_position));
10741|       |
10742|       |        // If c is U+002F (/) and remaining starts with U+002F (/),
10743|       |        // then set state to special authority ignore slashes state and increase
10744|       |        // pointer by 1.
10745|      0|        if (url_data.substr(input_position, 2) == "//") {
  ------------------
  |  Branch (10745:13): [True: 0, False: 0]
  ------------------
10746|      0|          state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES;
10747|      0|          input_position += 2;
10748|      0|        } else {
10749|       |          // Otherwise, validation error, set state to relative state and
10750|       |          // decrease pointer by 1.
10751|      0|          state = state::RELATIVE_SCHEME;
10752|      0|        }
10753|       |
10754|      0|        break;
10755|  23.4k|      }
10756|  1.02k|      case state::PATH_OR_AUTHORITY: {
  ------------------
  |  Branch (10756:7): [True: 1.02k, False: 1.12M]
  ------------------
10757|  1.02k|        ada_log("PATH_OR_AUTHORITY ",
10758|  1.02k|                helpers::substring(url_data, input_position));
10759|       |
10760|       |        // If c is U+002F (/), then set state to authority state.
10761|  1.02k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (10761:13): [True: 1.00k, False: 21]
  ------------------
10762|  1.00k|            (url_data[input_position] == '/')) {
  ------------------
  |  Branch (10762:13): [True: 691, False: 309]
  ------------------
10763|    691|          state = state::AUTHORITY;
10764|    691|          input_position++;
10765|    691|        } else {
10766|       |          // Otherwise, set state to path state, and decrease pointer by 1.
10767|    330|          state = state::PATH;
10768|    330|        }
10769|       |
10770|  1.02k|        break;
10771|  23.4k|      }
10772|      0|      case state::RELATIVE_SCHEME: {
  ------------------
  |  Branch (10772:7): [True: 0, False: 1.12M]
  ------------------
10773|      0|        ada_log("RELATIVE_SCHEME ",
10774|      0|                helpers::substring(url_data, input_position));
10775|       |
10776|       |        // Set url's scheme to base's scheme.
10777|      0|        url.copy_scheme(*base_url);
10778|       |
10779|       |        // If c is U+002F (/), then set state to relative slash state.
10780|      0|        if ((input_position != input_size) &&
  ------------------
  |  Branch (10780:13): [True: 0, False: 0]
  ------------------
10781|       |            // NOLINTNEXTLINE(bugprone-branch-clone)
10782|      0|            (url_data[input_position] == '/')) {
  ------------------
  |  Branch (10782:13): [True: 0, False: 0]
  ------------------
10783|      0|          ada_log(
10784|      0|              "RELATIVE_SCHEME if c is U+002F (/), then set state to relative "
10785|      0|              "slash state");
10786|      0|          state = state::RELATIVE_SLASH;
10787|      0|        } else if (url.is_special() && (input_position != input_size) &&
  ------------------
  |  Branch (10787:20): [True: 0, False: 0]
  |  Branch (10787:40): [True: 0, False: 0]
  ------------------
10788|      0|                   (url_data[input_position] == '\\')) {
  ------------------
  |  Branch (10788:20): [True: 0, False: 0]
  ------------------
10789|       |          // Otherwise, if url is special and c is U+005C (\), validation error,
10790|       |          // set state to relative slash state.
10791|      0|          ada_log(
10792|      0|              "RELATIVE_SCHEME  if url is special and c is U+005C, validation "
10793|      0|              "error, set state to relative slash state");
10794|      0|          state = state::RELATIVE_SLASH;
10795|      0|        } else {
10796|      0|          ada_log("RELATIVE_SCHEME otherwise");
10797|       |          // Set url's username to base's username, url's password to base's
10798|       |          // password, url's host to base's host, url's port to base's port,
10799|       |          // url's path to a clone of base's path, and url's query to base's
10800|       |          // query.
10801|       |          if constexpr (result_type_is_ada_url) {
10802|       |            url.username = base_url->username;
10803|       |            url.password = base_url->password;
10804|       |            url.host = base_url->host;
10805|       |            url.port = base_url->port;
10806|       |            // cloning the base path includes cloning the has_opaque_path flag
10807|       |            url.has_opaque_path = base_url->has_opaque_path;
10808|       |            url.path = base_url->path;
10809|       |            url.query = base_url->query;
10810|      0|          } else {
10811|      0|            url.update_base_authority(base_url->get_href(),
10812|      0|                                      base_url->get_components());
10813|      0|            url.update_host_to_base_host(base_url->get_hostname());
10814|      0|            url.update_base_port(base_url->retrieve_base_port());
10815|       |            // cloning the base path includes cloning the has_opaque_path flag
10816|      0|            url.has_opaque_path = base_url->has_opaque_path;
10817|      0|            url.update_base_pathname(base_url->get_pathname());
10818|      0|            if (base_url->has_search()) {
  ------------------
  |  Branch (10818:17): [True: 0, False: 0]
  ------------------
10819|       |              // get_search() returns "" for an empty query string (URL ends
10820|       |              // with '?'). update_base_search("") would incorrectly clear the
10821|       |              // query, so pass "?" to preserve the empty query distinction.
10822|      0|              auto s = base_url->get_search();
10823|      0|              url.update_base_search(s.empty() ? std::string_view("?") : s);
  ------------------
  |  Branch (10823:38): [True: 0, False: 0]
  ------------------
10824|      0|            }
10825|      0|          }
10826|       |
10827|      0|          url.has_opaque_path = base_url->has_opaque_path;
10828|       |
10829|       |          // If c is U+003F (?), then set url's query to the empty string, and
10830|       |          // state to query state.
10831|      0|          if ((input_position != input_size) &&
  ------------------
  |  Branch (10831:15): [True: 0, False: 0]
  ------------------
10832|      0|              (url_data[input_position] == '?')) {
  ------------------
  |  Branch (10832:15): [True: 0, False: 0]
  ------------------
10833|      0|            state = state::QUERY;
10834|      0|          }
10835|       |          // Otherwise, if c is not the EOF code point:
10836|      0|          else if (input_position != input_size) {
  ------------------
  |  Branch (10836:20): [True: 0, False: 0]
  ------------------
10837|       |            // Set url's query to null.
10838|      0|            url.clear_search();
10839|       |            if constexpr (result_type_is_ada_url) {
10840|       |              // Shorten url's path.
10841|       |              helpers::shorten_path(url.path, url.type);
10842|      0|            } else {
10843|      0|              std::string_view path = url.get_pathname();
10844|      0|              if (helpers::shorten_path(path, url.type)) {
  ------------------
  |  Branch (10844:19): [True: 0, False: 0]
  ------------------
10845|      0|                url.update_base_pathname(std::move(std::string(path)));
10846|      0|              }
10847|      0|            }
10848|       |            // Set state to path state and decrease pointer by 1.
10849|      0|            state = state::PATH;
10850|      0|            break;
10851|      0|          }
10852|      0|        }
10853|      0|        input_position++;
10854|      0|        break;
10855|      0|      }
10856|      0|      case state::RELATIVE_SLASH: {
  ------------------
  |  Branch (10856:7): [True: 0, False: 1.12M]
  ------------------
10857|      0|        ada_log("RELATIVE_SLASH ",
10858|      0|                helpers::substring(url_data, input_position));
10859|       |
10860|       |        // If url is special and c is U+002F (/) or U+005C (\), then:
10861|       |        // NOLINTNEXTLINE(bugprone-branch-clone)
10862|      0|        if (url.is_special() && (input_position != input_size) &&
  ------------------
  |  Branch (10862:13): [True: 0, False: 0]
  |  Branch (10862:33): [True: 0, False: 0]
  ------------------
10863|      0|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (10863:14): [True: 0, False: 0]
  ------------------
10864|      0|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (10864:14): [True: 0, False: 0]
  ------------------
10865|       |          // Set state to special authority ignore slashes state.
10866|      0|          state = state::SPECIAL_AUTHORITY_IGNORE_SLASHES;
10867|      0|        }
10868|       |        // Otherwise, if c is U+002F (/), then set state to authority state.
10869|      0|        else if ((input_position != input_size) &&
  ------------------
  |  Branch (10869:18): [True: 0, False: 0]
  ------------------
10870|      0|                 (url_data[input_position] == '/')) {
  ------------------
  |  Branch (10870:18): [True: 0, False: 0]
  ------------------
10871|      0|          state = state::AUTHORITY;
10872|      0|        }
10873|       |        // Otherwise, set
10874|       |        // - url's username to base's username,
10875|       |        // - url's password to base's password,
10876|       |        // - url's host to base's host,
10877|       |        // - url's port to base's port,
10878|       |        // - state to path state, and then, decrease pointer by 1.
10879|      0|        else {
10880|       |          if constexpr (result_type_is_ada_url) {
10881|       |            url.username = base_url->username;
10882|       |            url.password = base_url->password;
10883|       |            url.host = base_url->host;
10884|       |            url.port = base_url->port;
10885|      0|          } else {
10886|      0|            url.update_base_authority(base_url->get_href(),
10887|      0|                                      base_url->get_components());
10888|      0|            url.update_host_to_base_host(base_url->get_hostname());
10889|      0|            url.update_base_port(base_url->retrieve_base_port());
10890|      0|          }
10891|      0|          state = state::PATH;
10892|      0|          break;
10893|      0|        }
10894|       |
10895|      0|        input_position++;
10896|      0|        break;
10897|      0|      }
10898|   157k|      case state::SPECIAL_AUTHORITY_SLASHES: {
  ------------------
  |  Branch (10898:7): [True: 157k, False: 966k]
  ------------------
10899|   157k|        ada_log("SPECIAL_AUTHORITY_SLASHES ",
10900|   157k|                helpers::substring(url_data, input_position));
10901|       |
10902|       |        // If c is U+002F (/) and remaining starts with U+002F (/),
10903|       |        // then set state to special authority ignore slashes state and increase
10904|       |        // pointer by 1.
10905|   157k|        if (url_data.substr(input_position, 2) == "//") {
  ------------------
  |  Branch (10905:13): [True: 156k, False: 1.35k]
  ------------------
10906|   156k|          input_position += 2;
10907|   156k|        }
10908|       |
10909|   157k|        [[fallthrough]];
10910|   157k|      }
10911|   157k|      case state::SPECIAL_AUTHORITY_IGNORE_SLASHES: {
  ------------------
  |  Branch (10911:7): [True: 0, False: 1.12M]
  ------------------
10912|   157k|        ada_log("SPECIAL_AUTHORITY_IGNORE_SLASHES ",
10913|   157k|                helpers::substring(url_data, input_position));
10914|       |
10915|       |        // If c is neither U+002F (/) nor U+005C (\), then set state to
10916|       |        // authority state and decrease pointer by 1.
10917|   159k|        while ((input_position != input_size) &&
  ------------------
  |  Branch (10917:16): [True: 159k, False: 73]
  ------------------
10918|   159k|               ((url_data[input_position] == '/') ||
  ------------------
  |  Branch (10918:17): [True: 521, False: 159k]
  ------------------
10919|   159k|                (url_data[input_position] == '\\'))) {
  ------------------
  |  Branch (10919:17): [True: 1.49k, False: 157k]
  ------------------
10920|  2.01k|          input_position++;
10921|  2.01k|        }
10922|   157k|        state = state::AUTHORITY;
10923|       |
10924|   157k|        break;
10925|   157k|      }
10926|  10.0k|      case state::QUERY: {
  ------------------
  |  Branch (10926:7): [True: 10.0k, False: 1.11M]
  ------------------
10927|  10.0k|        ada_log("QUERY ", helpers::substring(url_data, input_position));
10928|  10.0k|        if constexpr (store_values) {
10929|       |          // Let queryPercentEncodeSet be the special-query percent-encode set
10930|       |          // if url is special; otherwise the query percent-encode set.
10931|  10.0k|          const uint8_t* query_percent_encode_set =
10932|  10.0k|              url.is_special() ? character_sets::SPECIAL_QUERY_PERCENT_ENCODE
  ------------------
  |  Branch (10932:15): [True: 9.07k, False: 1.00k]
  ------------------
10933|  10.0k|                               : character_sets::QUERY_PERCENT_ENCODE;
10934|       |
10935|       |          // Percent-encode after encoding, with encoding, buffer, and
10936|       |          // queryPercentEncodeSet, and append the result to url's query.
10937|  10.0k|          url.update_base_search(url_data.substr(input_position),
10938|  10.0k|                                 query_percent_encode_set);
10939|  10.0k|          ada_log("QUERY update_base_search completed ");
10940|  10.0k|          if (fragment.has_value()) {
  ------------------
  |  Branch (10940:15): [True: 7.36k, False: 2.71k]
  ------------------
10941|  7.36k|            url.update_unencoded_base_hash(*fragment);
10942|  7.36k|          }
10943|  10.0k|        }
10944|  10.0k|        return url;
10945|   157k|      }
10946|   158k|      case state::HOST: {
  ------------------
  |  Branch (10946:7): [True: 158k, False: 965k]
  ------------------
10947|   158k|        ada_log("HOST ", helpers::substring(url_data, input_position));
10948|       |
10949|   158k|        std::string_view host_view = url_data.substr(input_position);
10950|   158k|        auto [location, found_colon] =
10951|   158k|            helpers::get_host_delimiter_location(url.is_special(), host_view);
10952|   158k|        input_position = (location != std::string_view::npos)
  ------------------
  |  Branch (10952:26): [True: 158k, False: 0]
  ------------------
10953|   158k|                             ? input_position + location
10954|   158k|                             : input_size;
10955|       |        // Otherwise, if c is U+003A (:) and insideBrackets is false, then:
10956|       |        // Note: the 'found_colon' value is true if and only if a colon was
10957|       |        // encountered while not inside brackets.
10958|   158k|        if (found_colon) {
  ------------------
  |  Branch (10958:13): [True: 23.9k, False: 134k]
  ------------------
10959|       |          // If buffer is the empty string, validation error, return failure.
10960|       |          // Let host be the result of host parsing buffer with url is not
10961|       |          // special.
10962|  23.9k|          ada_log("HOST parsing ", host_view);
10963|  23.9k|          if (!url.parse_host(host_view)) {
  ------------------
  |  Branch (10963:15): [True: 161, False: 23.8k]
  ------------------
10964|    161|            return url;
10965|    161|          }
10966|  23.8k|          ada_log("HOST parsing results in ", url.get_hostname());
10967|       |          // Set url's host to host, buffer to the empty string, and state to
10968|       |          // port state.
10969|  23.8k|          state = state::PORT;
10970|  23.8k|          input_position++;
10971|  23.8k|        }
10972|       |        // Otherwise, if one of the following is true:
10973|       |        // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
10974|       |        // - url is special and c is U+005C (\)
10975|       |        // The get_host_delimiter_location function either brings us to
10976|       |        // the colon outside of the bracket, or to one of those characters.
10977|   134k|        else {
10978|       |          // If url is special and host_view is the empty string, validation
10979|       |          // error, return failure.
10980|   134k|          if (host_view.empty() && url.is_special()) {
  ------------------
  |  Branch (10980:15): [True: 125, False: 134k]
  |  Branch (10980:36): [True: 86, False: 39]
  ------------------
10981|     86|            url.is_valid = false;
10982|     86|            return url;
10983|     86|          }
10984|   134k|          ada_log("HOST parsing ", host_view, " href=", url.get_href());
10985|       |          // Let host be the result of host parsing host_view with url is not
10986|       |          // special.
10987|   134k|          if (host_view.empty()) {
  ------------------
  |  Branch (10987:15): [True: 39, False: 134k]
  ------------------
10988|     39|            url.update_base_hostname("");
10989|   134k|          } else if (!url.parse_host(host_view)) {
  ------------------
  |  Branch (10989:22): [True: 2.11k, False: 132k]
  ------------------
10990|  2.11k|            return url;
10991|  2.11k|          }
10992|   132k|          ada_log("HOST parsing results in ", url.get_hostname(),
10993|   132k|                  " href=", url.get_href());
10994|       |
10995|       |          // Set url's host to host, and state to path start state.
10996|   132k|          state = state::PATH_START;
10997|   132k|        }
10998|       |
10999|   156k|        break;
11000|   158k|      }
11001|   156k|      case state::OPAQUE_PATH: {
  ------------------
  |  Branch (11001:7): [True: 519, False: 1.12M]
  ------------------
11002|    519|        ada_log("OPAQUE_PATH ", helpers::substring(url_data, input_position));
11003|       |        // Opaque path, query, and fragment are structurally always valid:
11004|       |        // the parser would just percent-encode whatever is there. When we
11005|       |        // are not storing values (can_parse), we can return immediately.
11006|       |        // We must set has_opaque_path = true before returning so that when
11007|       |        // this URL is used as an internal base inside can_parse, NO_SCHEME
11008|       |        // correctly rejects relative inputs against an opaque-path base
11009|       |        // (e.g. can_parse("", &"W:") must return false).
11010|       |        if constexpr (!store_values) {
11011|       |          url.has_opaque_path = true;
11012|       |          return url;
11013|       |        }
11014|    519|        std::string_view view = url_data.substr(input_position);
11015|       |        // If c is U+003F (?), then set url's query to the empty string and
11016|       |        // state to query state.
11017|    519|        size_t location = view.find('?');
11018|    519|        if (location != std::string_view::npos) {
  ------------------
  |  Branch (11018:13): [True: 345, False: 174]
  ------------------
11019|    345|          view.remove_suffix(view.size() - location);
11020|    345|          state = state::QUERY;
11021|    345|          input_position += location + 1;
11022|    345|        } else {
11023|    174|          input_position = input_size + 1;
11024|    174|        }
11025|    519|        url.has_opaque_path = true;
11026|       |
11027|       |        // This is a really unlikely scenario in real world. We should not seek
11028|       |        // to optimize it.
11029|    519|        if (view.ends_with(' ')) {
  ------------------
  |  Branch (11029:13): [True: 13, False: 506]
  ------------------
11030|     13|          std::string modified_view =
11031|     13|              std::string(view.substr(0, view.size() - 1)) + "%20";
11032|     13|          url.update_base_pathname(unicode::percent_encode(
11033|     13|              modified_view, character_sets::C0_CONTROL_PERCENT_ENCODE));
11034|    506|        } else {
11035|    506|          url.update_base_pathname(unicode::percent_encode(
11036|    506|              view, character_sets::C0_CONTROL_PERCENT_ENCODE));
11037|    506|        }
11038|    519|        break;
11039|   158k|      }
11040|  23.8k|      case state::PORT: {
  ------------------
  |  Branch (11040:7): [True: 23.8k, False: 1.10M]
  ------------------
11041|  23.8k|        ada_log("PORT ", helpers::substring(url_data, input_position));
11042|  23.8k|        std::string_view port_view = url_data.substr(input_position);
11043|  23.8k|        input_position += url.parse_port(port_view, true);
11044|  23.8k|        if (!url.is_valid) {
  ------------------
  |  Branch (11044:13): [True: 148, False: 23.6k]
  ------------------
11045|    148|          return url;
11046|    148|        }
11047|  23.6k|        state = state::PATH_START;
11048|  23.6k|        [[fallthrough]];
11049|  23.6k|      }
11050|   156k|      case state::PATH_START: {
  ------------------
  |  Branch (11050:7): [True: 133k, False: 990k]
  ------------------
11051|   156k|        ada_log("PATH_START ", helpers::substring(url_data, input_position));
11052|       |        // Path, query, and fragment are structurally always valid: the
11053|       |        // parser would just percent-encode whatever is there. When we are
11054|       |        // not storing values (can_parse), we can return immediately since
11055|       |        // no subsequent state can invalidate the URL.
11056|       |        if constexpr (!store_values) {
11057|       |          return url;
11058|       |        }
11059|       |
11060|       |        // If url is special, then:
11061|   156k|        if (url.is_special()) {
  ------------------
  |  Branch (11061:13): [True: 156k, False: 609]
  ------------------
11062|       |          // Set state to path state.
11063|   156k|          state = state::PATH;
11064|       |
11065|       |          // Optimization: Avoiding going into PATH state improves the
11066|       |          // performance of urls ending with /.
11067|   156k|          if (input_position == input_size) {
  ------------------
  |  Branch (11067:15): [True: 2.18k, False: 154k]
  ------------------
11068|  2.18k|            if constexpr (store_values) {
11069|  2.18k|              url.update_base_pathname("/");
11070|  2.18k|              if (fragment.has_value()) {
  ------------------
  |  Branch (11070:19): [True: 282, False: 1.89k]
  ------------------
11071|    282|                url.update_unencoded_base_hash(*fragment);
11072|    282|              }
11073|  2.18k|            }
11074|  2.18k|            return url;
11075|  2.18k|          }
11076|       |          // If c is neither U+002F (/) nor U+005C (\), then decrease pointer
11077|       |          // by 1. We know that (input_position == input_size) is impossible
11078|       |          // here, because of the previous if-check.
11079|   154k|          if ((url_data[input_position] != '/') &&
  ------------------
  |  Branch (11079:15): [True: 1.03k, False: 153k]
  ------------------
11080|  1.03k|              (url_data[input_position] != '\\')) {
  ------------------
  |  Branch (11080:15): [True: 615, False: 416]
  ------------------
11081|    615|            break;
11082|    615|          }
11083|   154k|        }
11084|       |        // Otherwise, if state override is not given and c is U+003F (?),
11085|       |        // set url's query to the empty string and state to query state.
11086|    609|        else if ((input_position != input_size) &&
  ------------------
  |  Branch (11086:18): [True: 507, False: 102]
  ------------------
11087|    507|                 (url_data[input_position] == '?')) {
  ------------------
  |  Branch (11087:18): [True: 105, False: 402]
  ------------------
11088|    105|          state = state::QUERY;
11089|    105|        }
11090|       |        // Otherwise, if c is not the EOF code point:
11091|    504|        else if (input_position != input_size) {
  ------------------
  |  Branch (11091:18): [True: 402, False: 102]
  ------------------
11092|       |          // Set state to path state.
11093|    402|          state = state::PATH;
11094|       |
11095|       |          // If c is not U+002F (/), then decrease pointer by 1.
11096|    402|          if (url_data[input_position] != '/') {
  ------------------
  |  Branch (11096:15): [True: 0, False: 402]
  ------------------
11097|      0|            break;
11098|      0|          }
11099|    402|        }
11100|       |
11101|   154k|        input_position++;
11102|   154k|        break;
11103|   156k|      }
11104|   155k|      case state::PATH: {
  ------------------
  |  Branch (11104:7): [True: 155k, False: 969k]
  ------------------
11105|   155k|        ada_log("PATH ", helpers::substring(url_data, input_position));
11106|       |        // Path, query, and fragment are structurally always valid: the
11107|       |        // parser would just percent-encode whatever is there. When we are
11108|       |        // not storing values (can_parse), we can return immediately since
11109|       |        // no subsequent state can invalidate the URL.
11110|       |        if constexpr (!store_values) {
11111|       |          return url;
11112|       |        }
11113|   155k|        std::string_view view = url_data.substr(input_position);
11114|       |
11115|       |        // Most time, we do not need percent encoding.
11116|       |        // Furthermore, we can immediately locate the '?'.
11117|   155k|        size_t locofquestionmark = view.find('?');
11118|   155k|        if (locofquestionmark != std::string_view::npos) {
  ------------------
  |  Branch (11118:13): [True: 9.63k, False: 145k]
  ------------------
11119|  9.63k|          state = state::QUERY;
11120|  9.63k|          view.remove_suffix(view.size() - locofquestionmark);
11121|  9.63k|          input_position += locofquestionmark + 1;
11122|   145k|        } else {
11123|   145k|          input_position = input_size + 1;
11124|   145k|        }
11125|   155k|        if constexpr (store_values) {
11126|       |          if constexpr (result_type_is_ada_url) {
11127|       |            helpers::parse_prepared_path(view, url.type, url.path);
11128|   155k|          } else {
11129|   155k|            url.consume_prepared_path(view);
11130|   155k|            ADA_ASSERT_TRUE(url.validate());
11131|   155k|          }
11132|   155k|        }
11133|   155k|        break;
11134|   156k|      }
11135|  1.13k|      case state::FILE_SLASH: {
  ------------------
  |  Branch (11135:7): [True: 1.13k, False: 1.12M]
  ------------------
11136|  1.13k|        ada_log("FILE_SLASH ", helpers::substring(url_data, input_position));
11137|       |
11138|       |        // If c is U+002F (/) or U+005C (\), then:
11139|  1.13k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (11139:13): [True: 1.13k, False: 1]
  ------------------
11140|  1.13k|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (11140:14): [True: 1.12k, False: 17]
  ------------------
11141|  1.12k|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (11141:14): [True: 1, False: 16]
  ------------------
11142|  1.12k|          ada_log("FILE_SLASH c is U+002F or U+005C");
11143|       |          // Set state to file host state.
11144|  1.12k|          state = state::FILE_HOST;
11145|  1.12k|          input_position++;
11146|  1.12k|        } else {
11147|     17|          ada_log("FILE_SLASH otherwise");
11148|       |          // If base is non-null and base's scheme is "file", then:
11149|       |          // Note: it is unsafe to do base_url->scheme unless you know that
11150|       |          // base_url_has_value() is true.
11151|     17|          if (base_url != nullptr && base_url->type == scheme::type::FILE) {
  ------------------
  |  Branch (11151:15): [True: 0, False: 17]
  |  Branch (11151:38): [True: 0, False: 0]
  ------------------
11152|       |            // Set url's host to base's host.
11153|       |            if constexpr (result_type_is_ada_url) {
11154|       |              url.host = base_url->host;
11155|      0|            } else {
11156|      0|              url.update_host_to_base_host(base_url->get_host());
11157|      0|            }
11158|       |            // If the code point substring from pointer to the end of input does
11159|       |            // not start with a Windows drive letter and base's path[0] is a
11160|       |            // normalized Windows drive letter, then append base's path[0] to
11161|       |            // url's path.
11162|      0|            if (!base_url->get_pathname().empty()) {
  ------------------
  |  Branch (11162:17): [True: 0, False: 0]
  ------------------
11163|      0|              if (!checkers::is_windows_drive_letter(
  ------------------
  |  Branch (11163:19): [True: 0, False: 0]
  ------------------
11164|      0|                      url_data.substr(input_position))) {
11165|      0|                std::string_view first_base_url_path =
11166|      0|                    base_url->get_pathname().substr(1);
11167|      0|                size_t loc = first_base_url_path.find('/');
11168|      0|                if (loc != std::string_view::npos) {
  ------------------
  |  Branch (11168:21): [True: 0, False: 0]
  ------------------
11169|      0|                  helpers::resize(first_base_url_path, loc);
11170|      0|                }
11171|      0|                if (checkers::is_normalized_windows_drive_letter(
  ------------------
  |  Branch (11171:21): [True: 0, False: 0]
  ------------------
11172|      0|                        first_base_url_path)) {
11173|       |                  if constexpr (result_type_is_ada_url) {
11174|       |                    url.path += '/';
11175|       |                    url.path += first_base_url_path;
11176|      0|                  } else {
11177|      0|                    url.append_base_pathname(
11178|      0|                        helpers::concat("/", first_base_url_path));
11179|      0|                  }
11180|      0|                }
11181|      0|              }
11182|      0|            }
11183|      0|          }
11184|       |
11185|       |          // Set state to path state, and decrease pointer by 1.
11186|     17|          state = state::PATH;
11187|     17|        }
11188|       |
11189|  1.13k|        break;
11190|   156k|      }
11191|  1.12k|      case state::FILE_HOST: {
  ------------------
  |  Branch (11191:7): [True: 1.12k, False: 1.12M]
  ------------------
11192|  1.12k|        ada_log("FILE_HOST ", helpers::substring(url_data, input_position));
11193|  1.12k|        std::string_view view = url_data.substr(input_position);
11194|       |
11195|  1.12k|        size_t location = view.find_first_of("/\\?");
11196|  1.12k|        std::string_view file_host_buffer = view.substr(
11197|  1.12k|            0, (location != std::string_view::npos) ? location : view.size());
  ------------------
  |  Branch (11197:16): [True: 1.09k, False: 27]
  ------------------
11198|       |
11199|  1.12k|        if (checkers::is_windows_drive_letter(file_host_buffer)) {
  ------------------
  |  Branch (11199:13): [True: 1, False: 1.12k]
  ------------------
11200|      1|          state = state::PATH;
11201|  1.12k|        } else if (file_host_buffer.empty()) {
  ------------------
  |  Branch (11201:20): [True: 355, False: 765]
  ------------------
11202|       |          // Set url's host to the empty string.
11203|       |          if constexpr (result_type_is_ada_url) {
11204|       |            url.host = "";
11205|    355|          } else {
11206|    355|            url.update_base_hostname("");
11207|    355|          }
11208|       |          // Set state to path start state.
11209|    355|          state = state::PATH_START;
11210|    765|        } else {
11211|    765|          size_t consumed_bytes = file_host_buffer.size();
11212|    765|          input_position += consumed_bytes;
11213|       |          // Let host be the result of host parsing buffer with url is not
11214|       |          // special.
11215|    765|          if (!url.parse_host(file_host_buffer)) {
  ------------------
  |  Branch (11215:15): [True: 82, False: 683]
  ------------------
11216|     82|            return url;
11217|     82|          }
11218|       |
11219|       |          if constexpr (result_type_is_ada_url) {
11220|       |            // If host is "localhost", then set host to the empty string.
11221|       |            if (url.host.has_value() && url.host.value() == "localhost") {
11222|       |              url.host = "";
11223|       |            }
11224|    683|          } else {
11225|    683|            if (url.get_hostname() == "localhost") {
  ------------------
  |  Branch (11225:17): [True: 2, False: 681]
  ------------------
11226|      2|              url.update_base_hostname("");
11227|      2|            }
11228|    683|          }
11229|       |
11230|       |          // Set buffer to the empty string and state to path start state.
11231|    683|          state = state::PATH_START;
11232|    683|        }
11233|       |
11234|  1.03k|        break;
11235|  1.12k|      }
11236|  1.28k|      case state::FILE: {
  ------------------
  |  Branch (11236:7): [True: 1.28k, False: 1.12M]
  ------------------
11237|  1.28k|        ada_log("FILE ", helpers::substring(url_data, input_position));
11238|  1.28k|        std::string_view file_view = url_data.substr(input_position);
11239|       |
11240|  1.28k|        url.set_protocol_as_file();
11241|       |        if constexpr (result_type_is_ada_url) {
11242|       |          // Set url's host to the empty string.
11243|       |          url.host = "";
11244|  1.28k|        } else {
11245|  1.28k|          url.update_base_hostname("");
11246|  1.28k|        }
11247|       |        // If c is U+002F (/) or U+005C (\), then:
11248|  1.28k|        if (input_position != input_size &&
  ------------------
  |  Branch (11248:13): [True: 1.28k, False: 1]
  ------------------
11249|  1.28k|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (11249:14): [True: 1.13k, False: 150]
  ------------------
11250|  1.13k|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (11250:14): [True: 1, False: 149]
  ------------------
11251|  1.13k|          ada_log("FILE c is U+002F or U+005C");
11252|       |          // Set state to file slash state.
11253|  1.13k|          state = state::FILE_SLASH;
11254|  1.13k|        }
11255|       |        // Otherwise, if base is non-null and base's scheme is "file":
11256|    150|        else if (base_url != nullptr && base_url->type == scheme::type::FILE) {
  ------------------
  |  Branch (11256:18): [True: 0, False: 150]
  |  Branch (11256:41): [True: 0, False: 0]
  ------------------
11257|       |          // Set url's host to base's host, url's path to a clone of base's
11258|       |          // path, and url's query to base's query.
11259|      0|          ada_log("FILE base non-null");
11260|       |          if constexpr (result_type_is_ada_url) {
11261|       |            url.host = base_url->host;
11262|       |            url.path = base_url->path;
11263|       |            url.query = base_url->query;
11264|      0|          } else {
11265|      0|            url.update_host_to_base_host(base_url->get_hostname());
11266|      0|            url.update_base_pathname(base_url->get_pathname());
11267|      0|            if (base_url->has_search()) {
  ------------------
  |  Branch (11267:17): [True: 0, False: 0]
  ------------------
11268|       |              // get_search() returns "" for an empty query string (URL ends
11269|       |              // with '?'). update_base_search("") would incorrectly clear the
11270|       |              // query, so pass "?" to preserve the empty query distinction.
11271|      0|              auto s = base_url->get_search();
11272|      0|              url.update_base_search(s.empty() ? std::string_view("?") : s);
  ------------------
  |  Branch (11272:38): [True: 0, False: 0]
  ------------------
11273|      0|            }
11274|      0|          }
11275|      0|          url.has_opaque_path = base_url->has_opaque_path;
11276|       |
11277|       |          // If c is U+003F (?), then set url's query to the empty string and
11278|       |          // state to query state.
11279|      0|          if (input_position != input_size && url_data[input_position] == '?') {
  ------------------
  |  Branch (11279:15): [True: 0, False: 0]
  |  Branch (11279:47): [True: 0, False: 0]
  ------------------
11280|      0|            state = state::QUERY;
11281|      0|          }
11282|       |          // Otherwise, if c is not the EOF code point:
11283|      0|          else if (input_position != input_size) {
  ------------------
  |  Branch (11283:20): [True: 0, False: 0]
  ------------------
11284|       |            // Set url's query to null.
11285|      0|            url.clear_search();
11286|       |            // If the code point substring from pointer to the end of input does
11287|       |            // not start with a Windows drive letter, then shorten url's path.
11288|      0|            if (!checkers::is_windows_drive_letter(file_view)) {
  ------------------
  |  Branch (11288:17): [True: 0, False: 0]
  ------------------
11289|       |              if constexpr (result_type_is_ada_url) {
11290|       |                helpers::shorten_path(url.path, url.type);
11291|      0|              } else {
11292|      0|                std::string_view path = url.get_pathname();
11293|      0|                if (helpers::shorten_path(path, url.type)) {
  ------------------
  |  Branch (11293:21): [True: 0, False: 0]
  ------------------
11294|      0|                  url.update_base_pathname(std::move(std::string(path)));
11295|      0|                }
11296|      0|              }
11297|      0|            }
11298|       |            // Otherwise:
11299|      0|            else {
11300|       |              // Set url's path to an empty list.
11301|      0|              url.clear_pathname();
11302|      0|              url.has_opaque_path = true;
11303|      0|            }
11304|       |
11305|       |            // Set state to path state and decrease pointer by 1.
11306|      0|            state = state::PATH;
11307|      0|            break;
11308|      0|          }
11309|      0|        }
11310|       |        // Otherwise, set state to path state, and decrease pointer by 1.
11311|    150|        else {
11312|    150|          ada_log("FILE go to path");
11313|    150|          state = state::PATH;
11314|    150|          break;
11315|    150|        }
11316|       |
11317|  1.13k|        input_position++;
11318|  1.13k|        break;
11319|  1.28k|      }
11320|      0|      default:
  ------------------
  |  Branch (11320:7): [True: 0, False: 1.12M]
  ------------------
11321|      0|        unreachable();
11322|  1.12M|    }
11323|  1.12M|  }
11324|   342k|  if constexpr (store_values) {
11325|   342k|    if (fragment.has_value()) {
  ------------------
  |  Branch (11325:9): [True: 2.41k, False: 340k]
  ------------------
11326|  2.41k|      url.update_unencoded_base_hash(*fragment);
11327|  2.41k|    }
11328|   342k|  }
11329|       |  // Check the resulting (normalized) URL size against the maximum input length.
11330|       |  // Normalization (percent-encoding, IDNA, etc.) can expand the URL beyond the
11331|       |  // original input size.
11332|   342k|  if constexpr (store_values) {
11333|   342k|    if (url.is_valid) {
  ------------------
  |  Branch (11333:9): [True: 145k, False: 196k]
  ------------------
11334|   145k|      if constexpr (result_type_is_ada_url_aggregator) {
11335|   145k|        if (url.buffer.size() > max_input_length) {
  ------------------
  |  Branch (11335:13): [True: 0, False: 145k]
  ------------------
11336|      0|          url.is_valid = false;
11337|      0|        }
11338|       |      } else {
11339|       |        if (url.get_href_size() > max_input_length) {
11340|       |          url.is_valid = false;
11341|       |        }
11342|       |      }
11343|   145k|    }
11344|   342k|  }
11345|   342k|  return url;
11346|   357k|}
_ZN3ada14url_aggregator8set_hrefENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11870|   118k|bool url_aggregator::set_href(const std::string_view input) {
11871|   118k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
11872|   118k|  ada_log("url_aggregator::set_href ", input, " [", input.size(), " bytes]");
11873|   118k|  ada::result<url_aggregator> out = ada::parse<url_aggregator>(input);
11874|   118k|  ada_log("url_aggregator::set_href, success :", out.has_value());
11875|       |
11876|   118k|  if (out) {
  ------------------
  |  Branch (11876:7): [True: 118k, False: 0]
  ------------------
11877|       |    // The parser enforces get_max_input_length() on both the input and the
11878|       |    // normalized result. This is a defense-in-depth check.
11879|   118k|    if (out->buffer.size() > ada::get_max_input_length()) {
  ------------------
  |  Branch (11879:9): [True: 0, False: 118k]
  ------------------
11880|      0|      return false;
11881|      0|    }
11882|   118k|    ada_log("url_aggregator::set_href, parsed ", out->to_string());
11883|       |    // TODO: Figure out why the following line puts test to never finish.
11884|   118k|    *this = *out;
11885|   118k|  }
11886|       |
11887|   118k|  return out.has_value();
11888|   118k|}
_ZNK3ada14url_aggregator12get_usernameEv:
12180|   118k|    ada_lifetime_bound {
12181|   118k|  ada_log("url_aggregator::get_username");
12182|   118k|  if (has_non_empty_username()) {
  ------------------
  |  Branch (12182:7): [True: 7.61k, False: 110k]
  ------------------
12183|  7.61k|    return helpers::substring(buffer, components.protocol_end + 2,
12184|  7.61k|                              components.username_end);
12185|  7.61k|  }
12186|   110k|  return "";
12187|   118k|}
_ZNK3ada14url_aggregator12get_passwordEv:
12190|   118k|    ada_lifetime_bound {
12191|   118k|  ada_log("url_aggregator::get_password");
12192|   118k|  if (has_non_empty_password()) {
  ------------------
  |  Branch (12192:7): [True: 7.35k, False: 110k]
  ------------------
12193|  7.35k|    return helpers::substring(buffer, components.username_end + 1,
12194|  7.35k|                              components.host_start);
12195|  7.35k|  }
12196|   110k|  return "";
12197|   118k|}
_ZNK3ada14url_aggregator8get_portEv:
12200|   118k|    ada_lifetime_bound {
12201|   118k|  ada_log("url_aggregator::get_port");
12202|   118k|  if (components.port == url_components::omitted) {
  ------------------
  |  Branch (12202:7): [True: 110k, False: 7.79k]
  ------------------
12203|   110k|    return "";
12204|   110k|  }
12205|  7.79k|  return helpers::substring(buffer, components.host_end + 1,
12206|  7.79k|                            components.pathname_start);
12207|   118k|}
_ZNK3ada14url_aggregator8get_hashEv:
12210|   118k|    ada_lifetime_bound {
12211|   118k|  ada_log("url_aggregator::get_hash");
12212|       |  // If this's URL's fragment is either null or the empty string, then return
12213|       |  // the empty string. Return U+0023 (#), followed by this's URL's fragment.
12214|   118k|  if (components.hash_start == url_components::omitted) {
  ------------------
  |  Branch (12214:7): [True: 100k, False: 17.8k]
  ------------------
12215|   100k|    return "";
12216|   100k|  }
12217|  17.8k|  if (buffer.size() - components.hash_start <= 1) {
  ------------------
  |  Branch (12217:7): [True: 1.08k, False: 16.7k]
  ------------------
12218|  1.08k|    return "";
12219|  1.08k|  }
12220|  16.7k|  return helpers::substring(buffer, components.hash_start);
12221|  17.8k|}
_ZNK3ada14url_aggregator8get_hostEv:
12224|   118k|    ada_lifetime_bound {
12225|   118k|  ada_log("url_aggregator::get_host");
12226|       |  // Technically, we should check if there is a hostname, but
12227|       |  // the code below works even if there isn't.
12228|       |  // if(!has_hostname()) { return ""; }
12229|   118k|  size_t start = components.host_start;
12230|   118k|  if (components.host_end > components.host_start &&
  ------------------
  |  Branch (12230:7): [True: 117k, False: 471]
  ------------------
12231|   117k|      buffer[components.host_start] == '@') {
  ------------------
  |  Branch (12231:7): [True: 7.65k, False: 110k]
  ------------------
12232|  7.65k|    start++;
12233|  7.65k|  }
12234|       |  // if we have an empty host, then the space between components.host_end and
12235|       |  // components.pathname_start may be occupied by /.
12236|   118k|  if (start == components.host_end) {
  ------------------
  |  Branch (12236:7): [True: 471, False: 117k]
  ------------------
12237|    471|    return {};
12238|    471|  }
12239|   117k|  return helpers::substring(buffer, start, components.pathname_start);
12240|   118k|}
_ZNK3ada14url_aggregator12get_hostnameEv:
12243|   247k|    ada_lifetime_bound {
12244|   247k|  ada_log("url_aggregator::get_hostname");
12245|       |  // Technically, we should check if there is a hostname, but
12246|       |  // the code below works even if there isn't.
12247|       |  // if(!has_hostname()) { return ""; }
12248|   247k|  size_t start = components.host_start;
12249|       |  // So host_start is not where the host begins.
12250|   247k|  if (components.host_end > components.host_start &&
  ------------------
  |  Branch (12250:7): [True: 198k, False: 49.1k]
  ------------------
12251|   198k|      buffer[components.host_start] == '@') {
  ------------------
  |  Branch (12251:7): [True: 30.4k, False: 167k]
  ------------------
12252|  30.4k|    start++;
12253|  30.4k|  }
12254|   247k|  return helpers::substring(buffer, start, components.host_end);
12255|   247k|}
_ZNK3ada14url_aggregator10get_searchEv:
12258|   118k|    ada_lifetime_bound {
12259|   118k|  ada_log("url_aggregator::get_search");
12260|       |  // If this's URL's query is either null or the empty string, then return the
12261|       |  // empty string. Return U+003F (?), followed by this's URL's query.
12262|   118k|  if (components.search_start == url_components::omitted) {
  ------------------
  |  Branch (12262:7): [True: 93.6k, False: 24.7k]
  ------------------
12263|  93.6k|    return "";
12264|  93.6k|  }
12265|  24.7k|  auto ending_index = uint32_t(buffer.size());
12266|  24.7k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (12266:7): [True: 9.82k, False: 14.8k]
  ------------------
12267|  9.82k|    ending_index = components.hash_start;
12268|  9.82k|  }
12269|  24.7k|  if (ending_index - components.search_start <= 1) {
  ------------------
  |  Branch (12269:7): [True: 770, False: 23.9k]
  ------------------
12270|    770|    return "";
12271|    770|  }
12272|  23.9k|  return helpers::substring(buffer, components.search_start, ending_index);
12273|  24.7k|}
_ZNK3ada14url_aggregator12get_protocolEv:
12276|   118k|    ada_lifetime_bound {
12277|   118k|  ada_log("url_aggregator::get_protocol");
12278|   118k|  return helpers::substring(buffer, 0, components.protocol_end);
12279|   118k|}
_ZN3ada14url_aggregator10parse_ipv4ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEb:
12388|  8.63k|bool url_aggregator::parse_ipv4(std::string_view input, bool in_place) {
12389|  8.63k|  ada_log("parse_ipv4 ", input, " [", input.size(),
12390|  8.63k|          " bytes], overlaps with buffer: ",
12391|  8.63k|          helpers::overlaps(input, buffer) ? "yes" : "no");
12392|  8.63k|  ADA_ASSERT_TRUE(validate());
12393|  8.63k|  if (input.empty()) {
  ------------------
  |  Branch (12393:7): [True: 0, False: 8.63k]
  ------------------
12394|      0|    return is_valid = false;
12395|      0|  }
12396|  8.63k|  const bool trailing_dot = (input.back() == '.');
12397|  8.63k|  if (trailing_dot) {
  ------------------
  |  Branch (12397:7): [True: 46, False: 8.58k]
  ------------------
12398|     46|    input.remove_suffix(1);
12399|     46|    if (input.empty()) {
  ------------------
  |  Branch (12399:9): [True: 0, False: 46]
  ------------------
12400|      0|      return is_valid = false;
12401|      0|    }
12402|     46|  }
12403|       |
12404|  8.63k|  const uint64_t fast = checkers::try_parse_ipv4_fast(input);
12405|  8.63k|  if (fast < checkers::ipv4_fast_fail) [[likely]] {
  ------------------
  |  Branch (12405:7): [True: 5, False: 8.62k]
  ------------------
12406|       |    // Pure decimal: keep the buffer when it already holds the address.
12407|       |    // Otherwise write the (trailing-dot-stripped) input.
12408|      5|    if (!(in_place && !trailing_dot)) {
  ------------------
  |  Branch (12408:11): [True: 0, False: 5]
  |  Branch (12408:23): [True: 0, False: 0]
  ------------------
12409|      5|      update_base_hostname(input);
12410|      5|    }
12411|      5|    host_type = IPV4;
12412|      5|    ADA_ASSERT_TRUE(validate());
12413|      5|    return true;
12414|      5|  }
12415|       |
12416|  8.62k|  const char* p = input.data();
12417|  8.62k|  const char* end = p + input.size();
12418|  8.62k|  uint64_t ipv4 = 0;
12419|  8.62k|  int digit_count = 0;
12420|  8.62k|  int pure_decimal_count = 0;
12421|       |
12422|  16.3k|  for (; digit_count < 4 && p < end; ++digit_count) {
  ------------------
  |  Branch (12422:10): [True: 16.3k, False: 20]
  |  Branch (12422:29): [True: 16.3k, False: 0]
  ------------------
12423|  16.3k|    uint64_t segment = 0;
12424|  16.3k|    bool pure = false;
12425|  16.3k|    if (!detail::parse_ipv4_number(p, end, segment, pure)) {
  ------------------
  |  Branch (12425:9): [True: 191, False: 16.1k]
  ------------------
12426|    191|      return is_valid = false;
12427|    191|    }
12428|  16.1k|    if (pure) {
  ------------------
  |  Branch (12428:9): [True: 8.81k, False: 7.31k]
  ------------------
12429|  8.81k|      ++pure_decimal_count;
12430|  8.81k|    }
12431|  16.1k|    if (p >= end) {
  ------------------
  |  Branch (12431:9): [True: 8.39k, False: 7.73k]
  ------------------
12432|  8.39k|      const unsigned shift = static_cast<unsigned>(32 - digit_count * 8);
12433|  8.39k|      if (segment >= (uint64_t{1} << shift)) {
  ------------------
  |  Branch (12433:11): [True: 30, False: 8.36k]
  ------------------
12434|     30|        return is_valid = false;
12435|     30|      }
12436|  8.36k|      ipv4 = (ipv4 << shift) | segment;
12437|  8.36k|      goto ipv4_done;
12438|  8.39k|    }
12439|  7.73k|    if (segment > 255 || *p != '.') {
  ------------------
  |  Branch (12439:9): [True: 16, False: 7.71k]
  |  Branch (12439:26): [True: 0, False: 7.71k]
  ------------------
12440|     16|      return is_valid = false;
12441|     16|    }
12442|  7.71k|    ipv4 = (ipv4 << 8) | segment;
12443|  7.71k|    ++p;
12444|  7.71k|  }
12445|     20|  if (digit_count != 4 || p != end) {
  ------------------
  |  Branch (12445:7): [True: 0, False: 20]
  |  Branch (12445:27): [True: 20, False: 0]
  ------------------
12446|     20|    return is_valid = false;
12447|     20|  }
12448|  8.36k|ipv4_done:
12449|  8.36k|  ada_log("url_aggregator::parse_ipv4 completed ", get_href(),
12450|  8.36k|          " host: ", get_host());
12451|  8.36k|  if (in_place && pure_decimal_count == 4 && !trailing_dot) {
  ------------------
  |  Branch (12451:7): [True: 8.29k, False: 73]
  |  Branch (12451:19): [True: 0, False: 8.29k]
  |  Branch (12451:46): [True: 0, False: 0]
  ------------------
12452|      0|    ada_log(
12453|      0|        "url_aggregator::parse_ipv4 completed and was already correct in the "
12454|      0|        "buffer");
12455|  8.36k|  } else {
12456|  8.36k|    update_base_hostname(ada::serializers::ipv4(ipv4));
12457|  8.36k|  }
12458|  8.36k|  host_type = IPV4;
12459|  8.36k|  ADA_ASSERT_TRUE(validate());
12460|  8.36k|  return true;
12461|     20|}
_ZN3ada14url_aggregator10parse_ipv6ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
12463|    615|bool url_aggregator::parse_ipv6(std::string_view input) {
12464|    615|  ada_log("parse_ipv6 ", input, " [", input.size(), " bytes]");
12465|    615|  ADA_ASSERT_TRUE(validate());
12466|    615|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
12467|    615|  if (input.empty() || input.size() > 45) [[unlikely]] {
  ------------------
  |  Branch (12467:7): [True: 16, False: 599]
  |  Branch (12467:24): [True: 8, False: 591]
  ------------------
12468|     24|    return is_valid = false;
12469|     24|  }
12470|       |#if defined(ADA_AVX512)
12471|       |  if (!detail::ipv6_structure_plausible(input.data(), input.size()))
12472|       |      [[unlikely]] {
12473|       |    return is_valid = false;
12474|       |  }
12475|       |#endif
12476|       |
12477|    591|  std::array<uint16_t, 8> address{};
12478|    591|  const char* pointer = input.data();
12479|    591|  const char* const end = pointer + input.size();
12480|    591|  int piece_index = 0;
12481|    591|  int compress = -1;
12482|       |
12483|    591|  if (*pointer == ':') {
  ------------------
  |  Branch (12483:7): [True: 251, False: 340]
  ------------------
12484|    251|    if (input.size() == 1 || pointer[1] != ':') [[unlikely]] {
  ------------------
  |  Branch (12484:9): [True: 5, False: 246]
  |  Branch (12484:30): [True: 11, False: 235]
  ------------------
12485|     16|      return is_valid = false;
12486|     16|    }
12487|    235|    pointer += 2;
12488|    235|    compress = ++piece_index;
12489|    235|  }
12490|       |
12491|  1.75k|  while (pointer != end) {
  ------------------
  |  Branch (12491:10): [True: 1.31k, False: 442]
  ------------------
12492|  1.31k|    if (piece_index == 8) [[unlikely]] {
  ------------------
  |  Branch (12492:9): [True: 3, False: 1.30k]
  ------------------
12493|      3|      return is_valid = false;
12494|      3|    }
12495|  1.30k|    if (*pointer == ':') {
  ------------------
  |  Branch (12495:9): [True: 179, False: 1.12k]
  ------------------
12496|    179|      if (compress != -1) [[unlikely]] {
  ------------------
  |  Branch (12496:11): [True: 3, False: 176]
  ------------------
12497|      3|        return is_valid = false;
12498|      3|      }
12499|    176|      ++pointer;
12500|    176|      compress = ++piece_index;
12501|    176|      continue;
12502|    179|    }
12503|       |
12504|  1.12k|    uint16_t value = 0;
12505|  1.12k|    const int length = detail::parse_hex_piece(pointer, end, value);
12506|       |
12507|  1.12k|    if (pointer != end && *pointer == '.') {
  ------------------
  |  Branch (12507:9): [True: 867, False: 262]
  |  Branch (12507:27): [True: 95, False: 772]
  ------------------
12508|     95|      if (length == 0) [[unlikely]] {
  ------------------
  |  Branch (12508:11): [True: 3, False: 92]
  ------------------
12509|      3|        return is_valid = false;
12510|      3|      }
12511|     92|      pointer -= length;
12512|     92|      if (piece_index > 6) [[unlikely]] {
  ------------------
  |  Branch (12512:11): [True: 3, False: 89]
  ------------------
12513|      3|        return is_valid = false;
12514|      3|      }
12515|       |
12516|     89|      int numbers_seen = 0;
12517|    246|      while (pointer != end) {
  ------------------
  |  Branch (12517:14): [True: 227, False: 19]
  ------------------
12518|    227|        int ipv4_piece = -1;
12519|    227|        if (numbers_seen > 0) {
  ------------------
  |  Branch (12519:13): [True: 138, False: 89]
  ------------------
12520|    138|          if (*pointer == '.' && numbers_seen < 4) {
  ------------------
  |  Branch (12520:15): [True: 119, False: 19]
  |  Branch (12520:34): [True: 112, False: 7]
  ------------------
12521|    112|            ++pointer;
12522|    112|          } else {
12523|     26|            return is_valid = false;
12524|     26|          }
12525|    138|        }
12526|    201|        if (pointer == end || *pointer < '0' || *pointer > '9') [[unlikely]] {
  ------------------
  |  Branch (12526:13): [True: 16, False: 185]
  |  Branch (12526:31): [True: 9, False: 176]
  |  Branch (12526:49): [True: 9, False: 167]
  ------------------
12527|     34|          return is_valid = false;
12528|     34|        }
12529|    167|        ipv4_piece = *pointer - '0';
12530|    167|        ++pointer;
12531|    167|        if (pointer != end && *pointer >= '0' && *pointer <= '9') {
  ------------------
  |  Branch (12531:13): [True: 157, False: 10]
  |  Branch (12531:31): [True: 75, False: 82]
  |  Branch (12531:50): [True: 72, False: 3]
  ------------------
12532|     72|          if (ipv4_piece == 0) [[unlikely]] {
  ------------------
  |  Branch (12532:15): [True: 3, False: 69]
  ------------------
12533|      3|            return is_valid = false;
12534|      3|          }
12535|     69|          ipv4_piece = ipv4_piece * 10 + (*pointer - '0');
12536|     69|          ++pointer;
12537|     69|          if (pointer != end && *pointer >= '0' && *pointer <= '9') {
  ------------------
  |  Branch (12537:15): [True: 66, False: 3]
  |  Branch (12537:33): [True: 37, False: 29]
  |  Branch (12537:52): [True: 34, False: 3]
  ------------------
12538|     34|            ipv4_piece = ipv4_piece * 10 + (*pointer - '0');
12539|     34|            ++pointer;
12540|     34|            if (ipv4_piece > 255) [[unlikely]] {
  ------------------
  |  Branch (12540:17): [True: 7, False: 27]
  ------------------
12541|      7|              return is_valid = false;
12542|      7|            }
12543|     34|          }
12544|     69|        }
12545|    157|        address[static_cast<size_t>(piece_index)] = static_cast<uint16_t>(
12546|    157|            address[static_cast<size_t>(piece_index)] * 0x100 +
12547|    157|            static_cast<uint16_t>(ipv4_piece));
12548|    157|        ++numbers_seen;
12549|    157|        if (numbers_seen == 2 || numbers_seen == 4) {
  ------------------
  |  Branch (12549:13): [True: 45, False: 112]
  |  Branch (12549:34): [True: 14, False: 98]
  ------------------
12550|     59|          ++piece_index;
12551|     59|        }
12552|    157|      }
12553|     19|      if (numbers_seen != 4) [[unlikely]] {
  ------------------
  |  Branch (12553:11): [True: 12, False: 7]
  ------------------
12554|     12|        return is_valid = false;
12555|     12|      }
12556|      7|      break;
12557|     19|    }
12558|       |
12559|  1.03k|    if (length == 0) [[unlikely]] {
  ------------------
  |  Branch (12559:9): [True: 22, False: 1.01k]
  ------------------
12560|     22|      return is_valid = false;
12561|     22|    }
12562|       |
12563|  1.01k|    if (pointer != end && *pointer == ':') {
  ------------------
  |  Branch (12563:9): [True: 750, False: 262]
  |  Branch (12563:27): [True: 744, False: 6]
  ------------------
12564|    744|      ++pointer;
12565|    744|      if (pointer == end) [[unlikely]] {
  ------------------
  |  Branch (12565:11): [True: 4, False: 740]
  ------------------
12566|      4|        return is_valid = false;
12567|      4|      }
12568|    744|    } else if (pointer != end) [[unlikely]] {
  ------------------
  |  Branch (12568:16): [True: 6, False: 262]
  ------------------
12569|      6|      return is_valid = false;
12570|      6|    }
12571|       |
12572|  1.00k|    address[static_cast<size_t>(piece_index)] = value;
12573|  1.00k|    ++piece_index;
12574|  1.00k|  }
12575|       |
12576|    449|  if (compress != -1) {
  ------------------
  |  Branch (12576:7): [True: 400, False: 49]
  ------------------
12577|    400|    const int right = piece_index - compress;
12578|    400|    if (right > 0) {
  ------------------
  |  Branch (12578:9): [True: 220, False: 180]
  ------------------
12579|    220|      const size_t dest = static_cast<size_t>(8 - right);
12580|    220|      const size_t src = static_cast<size_t>(compress);
12581|    220|      if (dest != src) {
  ------------------
  |  Branch (12581:11): [True: 207, False: 13]
  ------------------
12582|    561|        for (size_t i = static_cast<size_t>(right); i-- > 0;) {
  ------------------
  |  Branch (12582:53): [True: 354, False: 207]
  ------------------
12583|    354|          address[dest + i] = address[src + i];
12584|    354|          address[src + i] = 0;
12585|    354|        }
12586|    207|      }
12587|    220|    }
12588|    400|  } else if (piece_index != 8) [[unlikely]] {
  ------------------
  |  Branch (12588:14): [True: 25, False: 24]
  ------------------
12589|     25|    return is_valid = false;
12590|     25|  }
12591|       |
12592|       |  // Serialize once; skip rewrite when hostname is already canonical.
12593|    424|  const std::string serialized = ada::serializers::ipv6(address);
12594|    424|  const std::string_view current = get_hostname();
12595|    424|  if (current.size() == serialized.size() &&
  ------------------
  |  Branch (12595:7): [True: 0, False: 424]
  ------------------
12596|      0|      std::memcmp(current.data(), serialized.data(), serialized.size()) == 0) {
  ------------------
  |  Branch (12596:7): [True: 0, False: 0]
  ------------------
12597|      0|    ada_log("parse_ipv6 in-place canonical match");
12598|    424|  } else {
12599|    424|    update_base_hostname(serialized);
12600|    424|  }
12601|    424|  ada_log("parse_ipv6 ", get_hostname());
12602|    424|  ADA_ASSERT_TRUE(validate());
12603|    424|  host_type = IPV6;
12604|    424|  return true;
12605|    449|}
_ZN3ada14url_aggregator17parse_opaque_hostENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
12607|    600|bool url_aggregator::parse_opaque_host(std::string_view input) {
12608|    600|  ada_log("parse_opaque_host ", input, " [", input.size(), " bytes]");
12609|    600|  ADA_ASSERT_TRUE(validate());
12610|    600|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
12611|    600|  if (std::ranges::any_of(input, ada::unicode::is_forbidden_host_code_point)) {
  ------------------
  |  Branch (12611:7): [True: 34, False: 566]
  ------------------
12612|     34|    return is_valid = false;
12613|     34|  }
12614|       |
12615|       |  // Return the result of running UTF-8 percent-encode on input using the C0
12616|       |  // control percent-encode set.
12617|    566|  size_t idx = ada::unicode::percent_encode_index(
12618|    566|      input, character_sets::C0_CONTROL_PERCENT_ENCODE);
12619|    566|  if (idx == input.size()) {
  ------------------
  |  Branch (12619:7): [True: 507, False: 59]
  ------------------
12620|    507|    update_base_hostname(input);
12621|    507|  } else {
12622|       |    // We only create a temporary string if we need to.
12623|     59|    update_base_hostname(ada::unicode::percent_encode(
12624|     59|        input, character_sets::C0_CONTROL_PERCENT_ENCODE, idx));
12625|     59|  }
12626|    566|  ADA_ASSERT_TRUE(validate());
12627|    566|  return true;
12628|    600|}
simple_absolute.cc:_ZZN3ada4idna22utf32_length_from_utf8EPKcmENK3$_0clEa:
  284|   239k|  return std::count_if(p, std::next(p, len), [](int8_t c) {
  285|       |    // -65 is 0b10111111, anything larger in two-complement's
  286|       |    // should start a new code point.
  287|   239k|    return c > -65;
  288|   239k|  });
_ZN3ada4idna7deflate22make_fixed_litlen_huffEv:
  490|      2|inline Huff make_fixed_litlen_huff() {
  491|      2|  Huff h;
  492|      2|  uint8_t lens[288];
  493|       |  // Fixed Huffman: 0-143:8, 144-255:9, 256-279:7, 280-287:8
  494|    290|  for (int i = 0; i <= 143; i++) lens[i] = 8;
  ------------------
  |  Branch (494:19): [True: 288, False: 2]
  ------------------
  495|    226|  for (int i = 144; i <= 255; i++) lens[i] = 9;
  ------------------
  |  Branch (495:21): [True: 224, False: 2]
  ------------------
  496|     50|  for (int i = 256; i <= 279; i++) lens[i] = 7;
  ------------------
  |  Branch (496:21): [True: 48, False: 2]
  ------------------
  497|     18|  for (int i = 280; i <= 287; i++) lens[i] = 8;
  ------------------
  |  Branch (497:21): [True: 16, False: 2]
  ------------------
  498|      2|  h.build(lens, 288);
  499|      2|  return h;
  500|      2|}
_ZN3ada4idna7deflate4Huff5buildEPKhi:
  439|     16|  bool build(const uint8_t* lens, int n) {
  440|     16|    std::memset(counts, 0, sizeof(counts));
  441|     16|    std::memset(first_code, 0, sizeof(first_code));
  442|     16|    std::memset(base_idx, 0, sizeof(base_idx));
  443|     16|    nsymbols = n;
  444|     16|    max_bits = 0;
  445|  1.98k|    for (int i = 0; i < n; i++) {
  ------------------
  |  Branch (445:21): [True: 1.96k, False: 16]
  ------------------
  446|  1.96k|      lengths[i] = lens[i];
  447|  1.96k|      if (lens[i]) {
  ------------------
  |  Branch (447:11): [True: 1.91k, False: 49]
  ------------------
  448|  1.91k|        counts[lens[i]]++;
  449|  1.91k|        if (lens[i] > max_bits) max_bits = lens[i];
  ------------------
  |  Branch (449:13): [True: 46, False: 1.87k]
  ------------------
  450|  1.91k|      }
  451|  1.96k|    }
  452|       |    // Canonical first code for each bit length (RFC 1951).
  453|     16|    int code = 0;
  454|    256|    for (int bits = 1; bits <= MAXBITS; bits++) {
  ------------------
  |  Branch (454:24): [True: 240, False: 16]
  ------------------
  455|    240|      code = (code + counts[bits - 1]) << 1;
  456|    240|      first_code[bits] = code;
  457|    240|    }
  458|     16|    int idx = 0;
  459|    158|    for (int bits = 1; bits <= max_bits; bits++) {
  ------------------
  |  Branch (459:24): [True: 142, False: 16]
  ------------------
  460|    142|      base_idx[bits] = idx;
  461|       |      // assign symbols in symbol order for codes of this length
  462|  21.6k|      for (int sym = 0; sym < n; sym++) {
  ------------------
  |  Branch (462:25): [True: 21.5k, False: 142]
  ------------------
  463|  21.5k|        if (lengths[sym] == bits) {
  ------------------
  |  Branch (463:13): [True: 1.91k, False: 19.6k]
  ------------------
  464|  1.91k|          symbols[idx++] = static_cast<int16_t>(sym);
  465|  1.91k|        }
  466|  21.5k|      }
  467|    142|    }
  468|     16|    return true;
  469|     16|  }
_ZN3ada4idna7deflate20make_fixed_dist_huffEv:
  502|      2|inline Huff make_fixed_dist_huff() {
  503|      2|  Huff h;
  504|      2|  uint8_t lens[32];
  505|     66|  for (int i = 0; i < 32; i++) lens[i] = 5;
  ------------------
  |  Branch (505:19): [True: 64, False: 2]
  ------------------
  506|      2|  h.build(lens, 32);
  507|      2|  return h;
  508|      2|}
simple_absolute.cc:_ZZN3ada4idna9ascii_mapEPcmENK3$_0clEh:
 5134|   273k|  auto broadcast = [](uint8_t v) -> uint64_t {
 5135|   273k|    return 0x101010101010101ull * v;
 5136|   273k|  };
_ZN3ada4idna13ensure_tablesEv:
 4885|  26.7k|[[nodiscard]] inline bool ensure_tables() noexcept {
 4886|  26.7k|  uint8_t state = tables_init_state.load(std::memory_order_acquire);
 4887|  26.7k|  if (state == kTablesReady) {
  ------------------
  |  Branch (4887:7): [True: 26.7k, False: 1]
  ------------------
 4888|  26.7k|    return true;
 4889|  26.7k|  }
 4890|      1|  if (state == kTablesFailed) {
  ------------------
  |  Branch (4890:7): [True: 0, False: 1]
  ------------------
 4891|      0|    return false;
 4892|      0|  }
 4893|       |
 4894|      1|  uint8_t expected = kTablesUninit;
 4895|      1|  if (tables_init_state.compare_exchange_strong(expected, kTablesInProgress,
  ------------------
  |  Branch (4895:7): [True: 1, False: 0]
  ------------------
 4896|      1|                                                std::memory_order_acq_rel,
 4897|      1|                                                std::memory_order_acquire)) {
 4898|      1|    uint8_t* buffer = new (std::nothrow) uint8_t[table_blob::uncompressed_size];
 4899|      1|    if (buffer == nullptr) {
  ------------------
  |  Branch (4899:9): [True: 0, False: 1]
  ------------------
 4900|      0|      tables_init_state.store(kTablesFailed, std::memory_order_release);
 4901|      0|      return false;
 4902|      0|    }
 4903|       |
 4904|      1|    const size_t n = deflate::inflate_raw(table_blob::compressed,
 4905|      1|                                          table_blob::compressed_size, buffer,
 4906|      1|                                          table_blob::uncompressed_size);
 4907|      1|    if (n != table_blob::uncompressed_size ||
  ------------------
  |  Branch (4907:9): [True: 0, False: 1]
  ------------------
 4908|      1|        crc32_ieee(buffer, n) != table_blob::uncompressed_crc32) {
  ------------------
  |  Branch (4908:9): [True: 0, False: 1]
  ------------------
 4909|      0|      delete[] buffer;
 4910|      0|      tables_init_state.store(kTablesFailed, std::memory_order_release);
 4911|      0|      return false;
 4912|      0|    }
 4913|       |
 4914|       |    // LE payload verified; convert multi-byte fields for big-endian hosts.
 4915|      1|    detail::convert_table_blob_to_host_endian(buffer);
 4916|       |
 4917|      1|    auto at = [&](size_t off) noexcept -> const uint8_t* {
 4918|      1|      return buffer + off;
 4919|      1|    };
 4920|       |
 4921|       |    // Publish all non-atomic pointers before READY. Waiters synchronize via
 4922|       |    // acquire on tables_init_state and then observe these writes.
 4923|      1|    idna_stage1 =
 4924|      1|        reinterpret_cast<const uint16_t*>(at(table_blob::off_idna_stage1));
 4925|      1|    idna_stage2 =
 4926|      1|        reinterpret_cast<const uint16_t*>(at(table_blob::off_idna_stage2));
 4927|      1|    idna_bool_blocks =
 4928|      1|        reinterpret_cast<const uint64_t*>(at(table_blob::off_idna_bool_blocks));
 4929|      1|    idna_utf8_mappings = at(table_blob::off_idna_utf8_mappings);
 4930|       |
 4931|      1|    decomposition_index = at(table_blob::off_decomposition_index);
 4932|      1|    decomposition_block_flat = reinterpret_cast<const uint16_t*>(
 4933|      1|        at(table_blob::off_decomposition_block));
 4934|      1|    decomposition_data = reinterpret_cast<const char32_t*>(
 4935|      1|        at(table_blob::off_decomposition_data));
 4936|      1|    ccc_index = at(table_blob::off_ccc_index);
 4937|      1|    ccc_block_flat = at(table_blob::off_ccc_block);
 4938|      1|    composition_index = at(table_blob::off_composition_index);
 4939|      1|    composition_block_flat = reinterpret_cast<const uint16_t*>(
 4940|      1|        at(table_blob::off_composition_block));
 4941|      1|    composition_data =
 4942|      1|        reinterpret_cast<const char32_t*>(at(table_blob::off_composition_data));
 4943|       |
 4944|      1|    id_continue =
 4945|      1|        reinterpret_cast<range_pair_ptr>(at(table_blob::off_id_continue_flat));
 4946|      1|    id_start =
 4947|      1|        reinterpret_cast<range_pair_ptr>(at(table_blob::off_id_start_flat));
 4948|       |
 4949|      1|    dir_start =
 4950|      1|        reinterpret_cast<const uint32_t*>(at(table_blob::off_dir_start));
 4951|      1|    dir_final =
 4952|      1|        reinterpret_cast<const uint32_t*>(at(table_blob::off_dir_final));
 4953|      1|    dir_value = at(table_blob::off_dir_value);
 4954|      1|    combining_ranges =
 4955|      1|        reinterpret_cast<range_pair_ptr>(at(table_blob::off_combining_flat));
 4956|       |
 4957|      1|    tables_buffer = buffer;
 4958|      1|    tables_init_state.store(kTablesReady, std::memory_order_release);
 4959|      1|    return true;
 4960|      1|  }
 4961|       |
 4962|       |  // Another thread owns init (or finished between our loads).
 4963|      0|  for (uint64_t spins = 0; spins < kTablesSpinLimit; ++spins) {
  ------------------
  |  Branch (4963:28): [True: 0, False: 0]
  ------------------
 4964|      0|    state = tables_init_state.load(std::memory_order_acquire);
 4965|      0|    if (state == kTablesReady) {
  ------------------
  |  Branch (4965:9): [True: 0, False: 0]
  ------------------
 4966|      0|      return true;
 4967|      0|    }
 4968|      0|    if (state == kTablesFailed) {
  ------------------
  |  Branch (4968:9): [True: 0, False: 0]
  ------------------
 4969|      0|      return false;
 4970|      0|    }
 4971|      0|#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || \
 4972|      0|    defined(_M_IX86)
 4973|      0|#if defined(__GNUC__) || defined(__clang__)
 4974|      0|    __builtin_ia32_pause();
 4975|      0|#endif
 4976|       |#elif defined(__aarch64__) || defined(_M_ARM64)
 4977|       |#if defined(__GNUC__) || defined(__clang__)
 4978|       |    asm volatile("yield" ::: "memory");
 4979|       |#endif
 4980|       |#endif
 4981|      0|  }
 4982|       |  // Timed out waiting for a peer - treat as failure rather than hang.
 4983|      0|  return false;
 4984|      0|}
_ZN3ada4idna7deflate11inflate_rawEPKhmPhm:
  535|      1|                          size_t dst_cap) {
  536|      1|  BitReader br(src, src_len);
  537|      1|  size_t out = 0;
  538|      4|  for (;;) {
  539|      4|    uint32_t bfinal = br.get(1);
  540|      4|    uint32_t btype = br.get(2);
  541|      4|    if (bfinal == UINT32_MAX || btype == UINT32_MAX) return 0;
  ------------------
  |  Branch (541:9): [True: 0, False: 4]
  |  Branch (541:33): [True: 0, False: 4]
  ------------------
  542|      4|    if (btype == 0) {
  ------------------
  |  Branch (542:9): [True: 0, False: 4]
  ------------------
  543|       |      // stored
  544|      0|      br.align_byte();
  545|      0|      if (!br.ensure(16)) return 0;
  ------------------
  |  Branch (545:11): [True: 0, False: 0]
  ------------------
  546|       |      // read 16+16 from bit buffer awkwardly - use byte path
  547|       |      // Align: bits is multiple of 8
  548|       |      // Get len from remaining bits then bytes
  549|      0|      uint32_t len = br.get(16);
  550|      0|      uint32_t nlen = br.get(16);
  551|      0|      if (len == UINT32_MAX || nlen == UINT32_MAX) return 0;
  ------------------
  |  Branch (551:11): [True: 0, False: 0]
  |  Branch (551:32): [True: 0, False: 0]
  ------------------
  552|      0|      if ((len ^ 0xFFFF) != nlen) return 0;
  ------------------
  |  Branch (552:11): [True: 0, False: 0]
  ------------------
  553|       |      // After get, may have bits in acc from previous - for stored, should be
  554|       |      // byte aligned Copy len bytes from p
  555|      0|      if (br.bits != 0) {
  ------------------
  |  Branch (555:11): [True: 0, False: 0]
  ------------------
  556|       |        // leftover bits should be 0 if aligned
  557|      0|      }
  558|      0|      if (size_t(br.end - br.p) < len) return 0;
  ------------------
  |  Branch (558:11): [True: 0, False: 0]
  ------------------
  559|      0|      if (out + len > dst_cap) return 0;
  ------------------
  |  Branch (559:11): [True: 0, False: 0]
  ------------------
  560|      0|      std::memcpy(dst + out, br.p, len);
  561|      0|      br.p += len;
  562|      0|      out += len;
  563|      4|    } else if (btype == 1 || btype == 2) {
  ------------------
  |  Branch (563:16): [True: 0, False: 4]
  |  Branch (563:30): [True: 4, False: 0]
  ------------------
  564|      4|      Huff lit, dist;
  565|      4|      if (btype == 1) {
  ------------------
  |  Branch (565:11): [True: 0, False: 4]
  ------------------
  566|       |        // use fixed via functions
  567|      4|      } else {
  568|       |        // dynamic
  569|      4|        uint32_t hlit = br.get(5);
  570|      4|        if (hlit == UINT32_MAX) return 0;
  ------------------
  |  Branch (570:13): [True: 0, False: 4]
  ------------------
  571|      4|        hlit += 257;
  572|      4|        uint32_t hdist = br.get(5);
  573|      4|        if (hdist == UINT32_MAX) return 0;
  ------------------
  |  Branch (573:13): [True: 0, False: 4]
  ------------------
  574|      4|        hdist += 1;
  575|      4|        uint32_t hclen = br.get(4);
  576|      4|        if (hclen == UINT32_MAX) return 0;
  ------------------
  |  Branch (576:13): [True: 0, False: 4]
  ------------------
  577|      4|        hclen += 4;
  578|      4|        static const int order[19] = {16, 17, 18, 0, 8,  7, 9,  6, 10, 5,
  579|      4|                                      11, 4,  12, 3, 13, 2, 14, 1, 15};
  580|      4|        uint8_t clen[19]{};
  581|     69|        for (uint32_t i = 0; i < hclen; i++) {
  ------------------
  |  Branch (581:30): [True: 65, False: 4]
  ------------------
  582|     65|          uint32_t v = br.get(3);
  583|     65|          if (v == UINT32_MAX) return 0;
  ------------------
  |  Branch (583:15): [True: 0, False: 65]
  ------------------
  584|     65|          clen[order[i]] = uint8_t(v);
  585|     65|        }
  586|      4|        Huff cl;
  587|      4|        if (!cl.build(clen, 19)) return 0;
  ------------------
  |  Branch (587:13): [True: 0, False: 4]
  ------------------
  588|      4|        uint8_t lens[288 + 32]{};
  589|      4|        uint32_t n = hlit + hdist;
  590|  1.09k|        for (uint32_t i = 0; i < n;) {
  ------------------
  |  Branch (590:30): [True: 1.08k, False: 4]
  ------------------
  591|  1.08k|          int sym = cl.decode(br);
  592|  1.08k|          if (sym < 0) return 0;
  ------------------
  |  Branch (592:15): [True: 0, False: 1.08k]
  ------------------
  593|  1.08k|          if (sym < 16) {
  ------------------
  |  Branch (593:15): [True: 1.03k, False: 49]
  ------------------
  594|  1.03k|            lens[i++] = uint8_t(sym);
  595|  1.03k|          } else if (sym == 16) {
  ------------------
  |  Branch (595:22): [True: 49, False: 0]
  ------------------
  596|     49|            uint32_t rep = br.get(2);
  597|     49|            if (rep == UINT32_MAX) return 0;
  ------------------
  |  Branch (597:17): [True: 0, False: 49]
  ------------------
  598|     49|            rep += 3;
  599|     49|            if (i == 0) return 0;
  ------------------
  |  Branch (599:17): [True: 0, False: 49]
  ------------------
  600|     49|            uint8_t v = lens[i - 1];
  601|    263|            while (rep--) lens[i++] = v;
  ------------------
  |  Branch (601:20): [True: 214, False: 49]
  ------------------
  602|     49|          } else if (sym == 17) {
  ------------------
  |  Branch (602:22): [True: 0, False: 0]
  ------------------
  603|      0|            uint32_t rep = br.get(3);
  604|      0|            if (rep == UINT32_MAX) return 0;
  ------------------
  |  Branch (604:17): [True: 0, False: 0]
  ------------------
  605|      0|            rep += 3;
  606|      0|            while (rep--) lens[i++] = 0;
  ------------------
  |  Branch (606:20): [True: 0, False: 0]
  ------------------
  607|      0|          } else if (sym == 18) {
  ------------------
  |  Branch (607:22): [True: 0, False: 0]
  ------------------
  608|      0|            uint32_t rep = br.get(7);
  609|      0|            if (rep == UINT32_MAX) return 0;
  ------------------
  |  Branch (609:17): [True: 0, False: 0]
  ------------------
  610|      0|            rep += 11;
  611|      0|            while (rep--) lens[i++] = 0;
  ------------------
  |  Branch (611:20): [True: 0, False: 0]
  ------------------
  612|      0|          } else
  613|      0|            return 0;
  614|  1.08k|        }
  615|      4|        if (!lit.build(lens, int(hlit))) return 0;
  ------------------
  |  Branch (615:13): [True: 0, False: 4]
  ------------------
  616|      4|        if (!dist.build(lens + hlit, int(hdist))) return 0;
  ------------------
  |  Branch (616:13): [True: 0, False: 4]
  ------------------
  617|      4|      }
  618|  52.2k|      for (;;) {
  619|  52.2k|        int sym;
  620|  52.2k|        if (btype == 1)
  ------------------
  |  Branch (620:13): [True: 0, False: 52.2k]
  ------------------
  621|      0|          sym = fixed_litlen(br);
  622|  52.2k|        else
  623|  52.2k|          sym = lit.decode(br);
  624|  52.2k|        if (sym < 0) return 0;
  ------------------
  |  Branch (624:13): [True: 0, False: 52.2k]
  ------------------
  625|  52.2k|        if (sym < 256) {
  ------------------
  |  Branch (625:13): [True: 37.2k, False: 14.9k]
  ------------------
  626|  37.2k|          if (out >= dst_cap) return 0;
  ------------------
  |  Branch (626:15): [True: 0, False: 37.2k]
  ------------------
  627|  37.2k|          dst[out++] = uint8_t(sym);
  628|  37.2k|        } else if (sym == 256) {
  ------------------
  |  Branch (628:20): [True: 4, False: 14.9k]
  ------------------
  629|      4|          break;
  630|  14.9k|        } else {
  631|  14.9k|          int len_code = sym - 257;
  632|  14.9k|          if (len_code < 0 || len_code > 28) return 0;
  ------------------
  |  Branch (632:15): [True: 0, False: 14.9k]
  |  Branch (632:31): [True: 0, False: 14.9k]
  ------------------
  633|  14.9k|          uint32_t extra = br.get(len_extra[len_code]);
  634|  14.9k|          if (len_extra[len_code] && extra == UINT32_MAX) return 0;
  ------------------
  |  Branch (634:15): [True: 2.03k, False: 12.9k]
  |  Branch (634:38): [True: 0, False: 2.03k]
  ------------------
  635|  14.9k|          uint32_t length =
  636|  14.9k|              len_base[len_code] + (len_extra[len_code] ? extra : 0);
  ------------------
  |  Branch (636:37): [True: 2.03k, False: 12.9k]
  ------------------
  637|  14.9k|          int dsym;
  638|  14.9k|          if (btype == 1)
  ------------------
  |  Branch (638:15): [True: 0, False: 14.9k]
  ------------------
  639|      0|            dsym = fixed_dist(br);
  640|  14.9k|          else
  641|  14.9k|            dsym = dist.decode(br);
  642|  14.9k|          if (dsym < 0 || dsym > 29) return 0;
  ------------------
  |  Branch (642:15): [True: 0, False: 14.9k]
  |  Branch (642:27): [True: 0, False: 14.9k]
  ------------------
  643|  14.9k|          uint32_t dextra = br.get(dist_extra[dsym]);
  644|  14.9k|          if (dist_extra[dsym] && dextra == UINT32_MAX) return 0;
  ------------------
  |  Branch (644:15): [True: 9.97k, False: 5.01k]
  |  Branch (644:35): [True: 0, False: 9.97k]
  ------------------
  645|  14.9k|          uint32_t distance = dist_base[dsym] + (dist_extra[dsym] ? dextra : 0);
  ------------------
  |  Branch (645:50): [True: 9.97k, False: 5.01k]
  ------------------
  646|  14.9k|          if (distance > out || out + length > dst_cap) return 0;
  ------------------
  |  Branch (646:15): [True: 0, False: 14.9k]
  |  Branch (646:33): [True: 0, False: 14.9k]
  ------------------
  647|   202k|          for (uint32_t k = 0; k < length; k++) {
  ------------------
  |  Branch (647:32): [True: 187k, False: 14.9k]
  ------------------
  648|   187k|            dst[out] = dst[out - distance];
  649|   187k|            out++;
  650|   187k|          }
  651|  14.9k|        }
  652|  52.2k|      }
  653|      4|    } else {
  654|      0|      return 0;  // reserved
  655|      0|    }
  656|      4|    if (bfinal) break;
  ------------------
  |  Branch (656:9): [True: 1, False: 3]
  ------------------
  657|      4|  }
  658|      1|  return out;
  659|      1|}
_ZN3ada4idna7deflate9BitReaderC2EPKhm:
  402|      1|      : p(data), end(data + len) {}
_ZN3ada4idna7deflate9BitReader3getEi:
  412|   457k|  uint32_t get(int n) {
  413|   457k|    if (!ensure(n)) return UINT32_MAX;
  ------------------
  |  Branch (413:9): [True: 0, False: 457k]
  ------------------
  414|   457k|    uint32_t v = acc & ((1u << n) - 1);
  415|   457k|    acc >>= n;
  416|   457k|    bits -= n;
  417|   457k|    return v;
  418|   457k|  }
_ZN3ada4idna7deflate9BitReader6ensureEi:
  404|   457k|  bool ensure(int n) {
  405|   520k|    while (bits < n) {
  ------------------
  |  Branch (405:12): [True: 62.3k, False: 457k]
  ------------------
  406|  62.3k|      if (p >= end) return false;
  ------------------
  |  Branch (406:11): [True: 0, False: 62.3k]
  ------------------
  407|  62.3k|      acc |= uint32_t(*p++) << bits;
  408|  62.3k|      bits += 8;
  409|  62.3k|    }
  410|   457k|    return true;
  411|   457k|  }
_ZNK3ada4idna7deflate4Huff6decodeERNS1_9BitReaderE:
  471|  68.3k|  int decode(BitReader& br) const {
  472|  68.3k|    if (max_bits == 0) return -1;
  ------------------
  |  Branch (472:9): [True: 0, False: 68.3k]
  ------------------
  473|  68.3k|    int code = 0;
  474|   427k|    for (int len = 1; len <= max_bits; len++) {
  ------------------
  |  Branch (474:23): [True: 427k, False: 0]
  ------------------
  475|   427k|      uint32_t b = br.get(1);
  476|   427k|      if (b == UINT32_MAX) return -1;
  ------------------
  |  Branch (476:11): [True: 0, False: 427k]
  ------------------
  477|   427k|      code = (code << 1) | int(b);
  478|   427k|      int first = first_code[len];
  479|   427k|      int cnt = counts[len];
  480|   427k|      if (cnt && code - first < cnt) {
  ------------------
  |  Branch (480:11): [True: 263k, False: 164k]
  |  Branch (480:18): [True: 68.3k, False: 195k]
  ------------------
  481|  68.3k|        return symbols[base_idx[len] + (code - first)];
  482|  68.3k|      }
  483|   427k|    }
  484|      0|    return -1;
  485|  68.3k|  }
_ZN3ada4idna10crc32_ieeeEPKhm:
 4868|      1|                                         size_t len) noexcept {
 4869|      1|  uint32_t c = 0xFFFFFFFFu;
 4870|   224k|  for (size_t i = 0; i < len; ++i) {
  ------------------
  |  Branch (4870:22): [True: 224k, False: 1]
  ------------------
 4871|   224k|    c ^= data[i];
 4872|  2.02M|    for (int k = 0; k < 8; ++k) {
  ------------------
  |  Branch (4872:21): [True: 1.79M, False: 224k]
  ------------------
 4873|  1.79M|      const uint32_t mask = 0u - (c & 1u);
 4874|  1.79M|      c = (c >> 1) ^ (0xEDB88320u & mask);
 4875|  1.79M|    }
 4876|   224k|  }
 4877|      1|  return ~c;
 4878|      1|}
_ZN3ada4idna6detail33convert_table_blob_to_host_endianEPh:
 4691|      1|inline void convert_table_blob_to_host_endian(uint8_t* buffer) noexcept {
 4692|      1|  if constexpr (std::endian::native == std::endian::little) {
 4693|      1|    (void)buffer;
 4694|      1|    return;
 4695|      1|  }
 4696|      0|  auto u16 = [&](size_t off, size_t count) {
 4697|      1|    bswap_inplace(reinterpret_cast<uint16_t*>(buffer + off), count);
 4698|      1|  };
 4699|      1|  auto u32 = [&](size_t off, size_t count) {
 4700|      1|    bswap_inplace(reinterpret_cast<uint32_t*>(buffer + off), count);
 4701|      1|  };
 4702|      1|  auto u64 = [&](size_t off, size_t count) {
 4703|      1|    bswap_inplace(reinterpret_cast<uint64_t*>(buffer + off), count);
 4704|      1|  };
 4705|       |
 4706|      1|  u16(table_blob::off_idna_stage1, table_blob::count_idna_stage1);
 4707|      1|  u16(table_blob::off_idna_stage2, table_blob::count_idna_stage2);
 4708|      1|  u64(table_blob::off_idna_bool_blocks, table_blob::count_idna_bool_blocks);
 4709|      1|  u16(table_blob::off_decomposition_block,
 4710|      1|      table_blob::count_decomposition_block);
 4711|      1|  u32(table_blob::off_decomposition_data, table_blob::count_decomposition_data);
 4712|      1|  u16(table_blob::off_composition_block, table_blob::count_composition_block);
 4713|      1|  u32(table_blob::off_composition_data, table_blob::count_composition_data);
 4714|      1|  u32(table_blob::off_id_continue_flat, table_blob::count_id_continue_flat);
 4715|      1|  u32(table_blob::off_id_start_flat, table_blob::count_id_start_flat);
 4716|      1|  u32(table_blob::off_dir_start, table_blob::count_dir_start);
 4717|      1|  u32(table_blob::off_dir_final, table_blob::count_dir_final);
 4718|      1|  u32(table_blob::off_combining_flat, table_blob::count_combining_flat);
 4719|      1|}
_ZZN3ada4idna13ensure_tablesEvENKUlmE_clEm:
 4917|     18|    auto at = [&](size_t off) noexcept -> const uint8_t* {
 4918|     18|      return buffer + off;
 4919|     18|    };
simple_absolute.cc:_ZN3ada4idnaL11idna_lookupEj:
 5072|   478k|static uint16_t idna_lookup(uint32_t cp) noexcept {
 5073|   478k|  if (cp < IDNA_LOW_RANGE_END) {
  ------------------
  |  Branch (5073:7): [True: 478k, False: 496]
  ------------------
 5074|   478k|    uint16_t ref = idna_stage1[cp >> IDNA_BLOCK_BITS];
 5075|   478k|    if (ref & IDNA_BOOL_FLAG) {
  ------------------
  |  Branch (5075:9): [True: 219k, False: 258k]
  ------------------
 5076|   219k|      uint32_t bit_idx =
 5077|   219k|          static_cast<uint32_t>(ref & ~IDNA_BOOL_FLAG) * IDNA_BLOCK_SIZE +
 5078|   219k|          (cp & IDNA_BLOCK_MASK);
 5079|   219k|      bool is_valid = (idna_bool_blocks[bit_idx >> 6] >> (bit_idx & 63u)) & 1u;
 5080|   219k|      return is_valid ? IDNA_VALID : IDNA_DISALLOWED;
  ------------------
  |  Branch (5080:14): [True: 219k, False: 24]
  ------------------
 5081|   219k|    }
 5082|   258k|    return idna_stage2[ref + (cp & IDNA_BLOCK_MASK)];
 5083|   478k|  }
 5084|       |
 5085|    496|  if (cp >= IDNA_HIGH_IGNORED_START && cp < IDNA_HIGH_IGNORED_END) {
  ------------------
  |  Branch (5085:7): [True: 424, False: 72]
  |  Branch (5085:40): [True: 172, False: 252]
  ------------------
 5086|    172|    return IDNA_IGNORED;
 5087|    172|  }
 5088|       |
 5089|    324|  return IDNA_DISALLOWED;
 5090|    496|}
simple_absolute.cc:_ZN3ada4idnaL21utf8_count_codepointsEPKh:
 5115|  52.3k|static size_t utf8_count_codepoints(const uint8_t* ptr) noexcept {
 5116|  52.3k|  size_t n = 0;
 5117|   112k|  while (*ptr != 0) {
  ------------------
  |  Branch (5117:10): [True: 59.8k, False: 52.3k]
  ------------------
 5118|  59.8k|    ++n;
 5119|  59.8k|    if (*ptr < 0x80u) {
  ------------------
  |  Branch (5119:9): [True: 39.7k, False: 20.0k]
  ------------------
 5120|  39.7k|      ++ptr;
 5121|  39.7k|    } else if (*ptr < 0xE0u) {
  ------------------
  |  Branch (5121:16): [True: 13.4k, False: 6.63k]
  ------------------
 5122|  13.4k|      ptr += 2;
 5123|  13.4k|    } else if (*ptr < 0xF0u) {
  ------------------
  |  Branch (5123:16): [True: 5.03k, False: 1.60k]
  ------------------
 5124|  5.03k|      ptr += 3;
 5125|  5.03k|    } else {
 5126|  1.60k|      ptr += 4;
 5127|  1.60k|    }
 5128|  59.8k|  }
 5129|  52.3k|  return n;
 5130|  52.3k|}
simple_absolute.cc:_ZN3ada4idnaL9utf8_nextERPKh:
 5093|  59.7k|static char32_t utf8_next(const uint8_t*& ptr) noexcept {
 5094|  59.7k|  uint8_t b0 = *ptr++;
 5095|  59.7k|  if (b0 < 0x80u) return static_cast<char32_t>(b0);
  ------------------
  |  Branch (5095:7): [True: 39.7k, False: 20.0k]
  ------------------
 5096|  20.0k|  if (b0 < 0xE0u) {
  ------------------
  |  Branch (5096:7): [True: 13.4k, False: 6.57k]
  ------------------
 5097|  13.4k|    uint32_t cp = (b0 & 0x1Fu) << 6;
 5098|  13.4k|    cp |= (*ptr++ & 0x3Fu);
 5099|  13.4k|    return static_cast<char32_t>(cp);
 5100|  13.4k|  }
 5101|  6.57k|  if (b0 < 0xF0u) {
  ------------------
  |  Branch (5101:7): [True: 5.00k, False: 1.57k]
  ------------------
 5102|  5.00k|    uint32_t cp = (b0 & 0x0Fu) << 12;
 5103|  5.00k|    cp |= ((*ptr++ & 0x3Fu) << 6);
 5104|  5.00k|    cp |= (*ptr++ & 0x3Fu);
 5105|  5.00k|    return static_cast<char32_t>(cp);
 5106|  5.00k|  }
 5107|  1.57k|  uint32_t cp = (b0 & 0x07u) << 18;
 5108|  1.57k|  cp |= ((*ptr++ & 0x3Fu) << 12);
 5109|  1.57k|  cp |= ((*ptr++ & 0x3Fu) << 6);
 5110|  1.57k|  cp |= (*ptr++ & 0x3Fu);
 5111|  1.57k|  return static_cast<char32_t>(cp);
 5112|  6.57k|}
_ZN3ada4idna23decomposition_block_rowEh:
 4989|   290k|inline const uint16_t* decomposition_block_row(uint8_t bi) noexcept {
 4990|   290k|  if (bi >= kDecompBlockRows) {
  ------------------
  |  Branch (4990:7): [True: 0, False: 290k]
  ------------------
 4991|      0|    bi = 0;
 4992|      0|  }
 4993|   290k|  return decomposition_block_flat + static_cast<size_t>(bi) * kDecompBlockCols;
 4994|   290k|}
_ZN3ada4idna13ccc_block_rowEh:
 4996|   564k|inline const uint8_t* ccc_block_row(uint8_t bi) noexcept {
 4997|   564k|  if (bi >= kCccBlockRows) {
  ------------------
  |  Branch (4997:7): [True: 0, False: 564k]
  ------------------
 4998|      0|    bi = 0;
 4999|      0|  }
 5000|   564k|  return ccc_block_flat + static_cast<size_t>(bi) * kCccBlockCols;
 5001|   564k|}
_ZN3ada4idna16tables_are_readyEv:
 4880|  8.20k|[[nodiscard]] inline bool tables_are_ready() noexcept {
 4881|  8.20k|  return tables_init_state.load(std::memory_order_acquire) == kTablesReady;
 4882|  8.20k|}
simple_absolute.cc:_ZN3ada4idnaL23canonical_decomp_lengthEDi:
 5272|   269k|static size_t canonical_decomp_length(char32_t current_character) noexcept {
 5273|   269k|  if (current_character >= hangul_sbase &&
  ------------------
  |  Branch (5273:7): [True: 26.7k, False: 242k]
  ------------------
 5274|  26.7k|      current_character < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (5274:7): [True: 20.7k, False: 6.04k]
  ------------------
 5275|       |    // Hangul precomposed syllables are NFC.
 5276|  20.7k|    return 0;
 5277|  20.7k|  }
 5278|   248k|  if (current_character >= 0x110000) {
  ------------------
  |  Branch (5278:7): [True: 0, False: 248k]
  ------------------
 5279|      0|    return 0;
 5280|      0|  }
 5281|   248k|  const uint8_t di = decomposition_index[current_character >> 8];
 5282|   248k|  const uint16_t* const decomposition =
 5283|   248k|      decomposition_block_row(di) + (current_character % 256);
 5284|   248k|  size_t decomposition_length =
 5285|   248k|      (decomposition[1] >> 2) - (decomposition[0] >> 2);
 5286|   248k|  if ((decomposition_length > 0) && (decomposition[0] & 1)) {
  ------------------
  |  Branch (5286:7): [True: 10.2k, False: 237k]
  |  Branch (5286:37): [True: 0, False: 10.2k]
  ------------------
 5287|      0|    decomposition_length = 0;  // compatibility-only: ignored for NFC
 5288|      0|  }
 5289|   248k|  return decomposition_length;
 5290|   248k|}
simple_absolute.cc:_ZN3ada4idnaL13would_composeENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5404|  7.51k|static bool would_compose(std::u32string_view input) noexcept {
 5405|   218k|  for (size_t input_count = 0; input_count < input.size();) {
  ------------------
  |  Branch (5405:32): [True: 212k, False: 6.08k]
  ------------------
 5406|   212k|    const char32_t current = input[input_count];
 5407|   212k|    if (current >= hangul_lbase && current < hangul_lbase + hangul_lcount) {
  ------------------
  |  Branch (5407:9): [True: 20.1k, False: 191k]
  |  Branch (5407:36): [True: 2.32k, False: 17.8k]
  ------------------
 5408|  2.32k|      if (input_count + 1 < input.size() &&
  ------------------
  |  Branch (5408:11): [True: 2.24k, False: 80]
  ------------------
 5409|  2.24k|          input[input_count + 1] >= hangul_vbase &&
  ------------------
  |  Branch (5409:11): [True: 1.08k, False: 1.15k]
  ------------------
 5410|  1.08k|          input[input_count + 1] < hangul_vbase + hangul_vcount) {
  ------------------
  |  Branch (5410:11): [True: 208, False: 878]
  ------------------
 5411|    208|        return true;
 5412|    208|      }
 5413|  2.11k|      ++input_count;
 5414|  2.11k|      continue;
 5415|  2.32k|    }
 5416|   209k|    if (current >= hangul_sbase && current < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (5416:9): [True: 10.6k, False: 199k]
  |  Branch (5416:36): [True: 8.34k, False: 2.32k]
  ------------------
 5417|  8.34k|      if ((current - hangul_sbase) % hangul_tcount &&
  ------------------
  |  Branch (5417:11): [True: 7.47k, False: 870]
  ------------------
 5418|  7.47k|          input_count + 1 < input.size() &&
  ------------------
  |  Branch (5418:11): [True: 7.13k, False: 336]
  ------------------
 5419|  7.13k|          input[input_count + 1] > hangul_tbase &&
  ------------------
  |  Branch (5419:11): [True: 6.25k, False: 888]
  ------------------
 5420|  6.25k|          input[input_count + 1] < hangul_tbase + hangul_tcount) {
  ------------------
  |  Branch (5420:11): [True: 356, False: 5.89k]
  ------------------
 5421|    356|        return true;
 5422|    356|      }
 5423|  7.98k|      ++input_count;
 5424|  7.98k|      continue;
 5425|  8.34k|    }
 5426|   201k|    if (current < 0x110000) {
  ------------------
  |  Branch (5426:9): [True: 201k, False: 0]
  ------------------
 5427|   201k|      const uint16_t* composition =
 5428|   201k|          composition_block_row(composition_index[current >> 8]) +
 5429|   201k|          (current % 256);
 5430|   201k|      int32_t previous_ccc = -1;
 5431|   201k|      size_t j = input_count;
 5432|   204k|      for (; j + 1 < input.size(); ++j) {
  ------------------
  |  Branch (5432:14): [True: 199k, False: 5.65k]
  ------------------
 5433|   199k|        uint8_t ccc = get_ccc(input[j + 1]);
 5434|   199k|        if (composition[1] != composition[0] && previous_ccc < ccc) {
  ------------------
  |  Branch (5434:13): [True: 96.8k, False: 102k]
  |  Branch (5434:49): [True: 96.2k, False: 604]
  ------------------
 5435|  96.2k|          int left = composition[0];
 5436|  96.2k|          int right = composition[1];
 5437|  96.2k|          if (left < 0 || right < left ||
  ------------------
  |  Branch (5437:15): [True: 0, False: 96.2k]
  |  Branch (5437:27): [True: 0, False: 96.2k]
  ------------------
 5438|  96.2k|              static_cast<size_t>(right) > composition_data_size) {
  ------------------
  |  Branch (5438:15): [True: 0, False: 96.2k]
  ------------------
 5439|      0|            break;
 5440|      0|          }
 5441|   312k|          while (left + 2 < right) {
  ------------------
  |  Branch (5441:18): [True: 215k, False: 96.2k]
  ------------------
 5442|   215k|            int middle = left + (((right - left) >> 1) & ~1);
 5443|   215k|            if (composition_data[static_cast<size_t>(middle)] <= input[j + 1]) {
  ------------------
  |  Branch (5443:17): [True: 5.95k, False: 210k]
  ------------------
 5444|  5.95k|              left = middle;
 5445|  5.95k|            }
 5446|   215k|            if (composition_data[static_cast<size_t>(middle)] >= input[j + 1]) {
  ------------------
  |  Branch (5446:17): [True: 210k, False: 5.44k]
  ------------------
 5447|   210k|              right = middle;
 5448|   210k|            }
 5449|   215k|          }
 5450|  96.2k|          if (static_cast<size_t>(left + 1) < composition_data_size &&
  ------------------
  |  Branch (5450:15): [True: 96.2k, False: 0]
  ------------------
 5451|  96.2k|              composition_data[static_cast<size_t>(left)] == input[j + 1]) {
  ------------------
  |  Branch (5451:15): [True: 872, False: 95.3k]
  ------------------
 5452|    872|            return true;
 5453|    872|          }
 5454|  96.2k|        }
 5455|   198k|        if (ccc == 0) {
  ------------------
  |  Branch (5455:13): [True: 194k, False: 3.34k]
  ------------------
 5456|   194k|          break;
 5457|   194k|        }
 5458|  3.34k|        previous_ccc = ccc;
 5459|  3.34k|      }
 5460|   200k|      input_count = j + 1;
 5461|   200k|      continue;
 5462|   201k|    }
 5463|      0|    ++input_count;
 5464|      0|  }
 5465|  6.08k|  return false;
 5466|  7.51k|}
_ZN3ada4idna21composition_block_rowEh:
 5003|   224k|inline const uint16_t* composition_block_row(uint8_t bi) noexcept {
 5004|   224k|  if (bi >= kCompBlockRows) {
  ------------------
  |  Branch (5004:7): [True: 0, False: 224k]
  ------------------
 5005|      0|    bi = 0;
 5006|      0|  }
 5007|   224k|  return composition_block_flat + static_cast<size_t>(bi) * kCompBlockCols;
 5008|   224k|}
simple_absolute.cc:_ZN3ada4idnaL19char_to_digit_valueEc:
 5632|  58.6k|static constexpr int32_t char_to_digit_value(char value) {
 5633|  58.6k|  if (value >= 'a' && value <= 'z') return value - 'a';
  ------------------
  |  Branch (5633:7): [True: 51.0k, False: 7.64k]
  |  Branch (5633:23): [True: 51.0k, False: 8]
  ------------------
 5634|  7.65k|  if (value >= '0' && value <= '9') return value - '0' + 26;
  ------------------
  |  Branch (5634:7): [True: 7.63k, False: 16]
  |  Branch (5634:23): [True: 7.61k, False: 22]
  ------------------
 5635|     38|  return -1;
 5636|  7.65k|}
simple_absolute.cc:_ZN3ada4idnaL5adaptEiib:
 5642|  59.6k|static constexpr int32_t adapt(int32_t d, int32_t n, bool firsttime) {
 5643|  59.6k|  if (firsttime) {
  ------------------
  |  Branch (5643:7): [True: 17.8k, False: 41.7k]
  ------------------
 5644|  17.8k|    d = d / damp;
 5645|  41.7k|  } else {
 5646|  41.7k|    d = d / 2;
 5647|  41.7k|  }
 5648|  59.6k|  d += d / n;
 5649|  59.6k|  int32_t k = 0;
 5650|  69.7k|  while (d > ((base - tmin) * tmax) / 2) {
  ------------------
  |  Branch (5650:10): [True: 10.1k, False: 59.6k]
  ------------------
 5651|  10.1k|    d /= base - tmin;
 5652|  10.1k|    k += base;
 5653|  10.1k|  }
 5654|  59.6k|  return k + (((base - tmin + 1) * d) / (d + skew));
 5655|  59.6k|}
simple_absolute.cc:_ZN3ada4idnaL13digit_to_charEi:
 5638|  58.6k|static constexpr char digit_to_char(int32_t digit) {
 5639|  58.6k|  return digit < 26 ? char(digit + 97) : char(digit + 22);
  ------------------
  |  Branch (5639:10): [True: 39.6k, False: 19.0k]
  ------------------
 5640|  58.6k|}
simple_absolute.cc:_ZZN3ada4idna14is_label_validENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEEENK3$_0clIA2_jEEDaRKT_:
 5977|   157k|      comb_span, label.front(), {}, [](const auto& range) { return range[1]; });
simple_absolute.cc:_ZZN3ada4idna14is_label_validENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEEENK3$_1clEj:
 6062|  3.12k|      auto is_l_or_d = [](uint32_t code) {
 6063|  3.12k|        return std::ranges::binary_search(L, code) ||
  ------------------
  |  Branch (6063:16): [True: 8, False: 3.12k]
  ------------------
 6064|  3.12k|               std::ranges::binary_search(D, code);
  ------------------
  |  Branch (6064:16): [True: 332, False: 2.78k]
  ------------------
 6065|  3.12k|      };
simple_absolute.cc:_ZZN3ada4idna14is_label_validENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEEENK3$_2clEj:
 6066|  2.91k|      auto is_r_or_d = [](uint32_t code) {
 6067|  2.91k|        return std::ranges::binary_search(R, code) ||
  ------------------
  |  Branch (6067:16): [True: 170, False: 2.74k]
  ------------------
 6068|  2.74k|               std::ranges::binary_search(D, code);
  ------------------
  |  Branch (6068:16): [True: 40, False: 2.70k]
  ------------------
 6069|  2.91k|      };
simple_absolute.cc:_ZN3ada4idnaL20find_last_not_of_nsmENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5924|  16.8k|    const std::u32string_view label) noexcept {
 5925|  17.9k|  for (int i = static_cast<int>(label.size() - 1); i >= 0; i--)
  ------------------
  |  Branch (5925:52): [True: 17.9k, False: 0]
  ------------------
 5926|  17.9k|    if (find_direction(label[i]) != direction::NSM) return i;
  ------------------
  |  Branch (5926:9): [True: 16.8k, False: 1.08k]
  ------------------
 5927|       |
 5928|      0|  return std::u32string_view::npos;
 5929|  16.8k|}
simple_absolute.cc:_ZN3ada4idnaL12is_rtl_labelENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5933|  16.8k|inline static bool is_rtl_label(const std::u32string_view label) noexcept {
 5934|  16.8k|  const size_t mask =
 5935|  16.8k|      (1u << direction::R) | (1u << direction::AL) | (1u << direction::AN);
 5936|       |
 5937|  16.8k|  size_t directions = 0;
 5938|  99.2k|  for (size_t i = 0; i < label.size(); i++) {
  ------------------
  |  Branch (5938:22): [True: 82.4k, False: 16.8k]
  ------------------
 5939|  82.4k|    directions |= 1u << find_direction(label[i]);
 5940|  82.4k|  }
 5941|  16.8k|  return (directions & mask) != 0;
 5942|  16.8k|}
simple_absolute.cc:_ZN3ada4idnaL14find_directionEj:
 5905|   120k|inline static direction find_direction(uint32_t code_point) noexcept {
 5906|       |  // Binary search on dir_final (sorted upper bounds).
 5907|   120k|  size_t lo = 0, hi = dir_table_count;
 5908|  1.37M|  while (lo < hi) {
  ------------------
  |  Branch (5908:10): [True: 1.25M, False: 120k]
  ------------------
 5909|  1.25M|    size_t mid = lo + (hi - lo) / 2;
 5910|  1.25M|    if (dir_final[mid] < code_point) {
  ------------------
  |  Branch (5910:9): [True: 403k, False: 854k]
  ------------------
 5911|   403k|      lo = mid + 1;
 5912|   854k|    } else {
 5913|   854k|      hi = mid;
 5914|   854k|    }
 5915|  1.25M|  }
 5916|   120k|  if (lo == dir_table_count) {
  ------------------
  |  Branch (5916:7): [True: 0, False: 120k]
  ------------------
 5917|      0|    return direction::NONE;
 5918|      0|  }
 5919|   120k|  return code_point >= dir_start[lo] ? static_cast<direction>(dir_value[lo])
  ------------------
  |  Branch (5919:10): [True: 115k, False: 4.38k]
  ------------------
 5920|   120k|                                     : direction::NONE;
 5921|   120k|}
_ZN3ada4idna8is_asciiENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6290|  96.3k|bool constexpr is_ascii(std::string_view view) {
 6291|  1.22M|  for (uint8_t c : view) {
  ------------------
  |  Branch (6291:18): [True: 1.22M, False: 91.1k]
  ------------------
 6292|  1.22M|    if (c >= 0x80) {
  ------------------
  |  Branch (6292:9): [True: 5.17k, False: 1.22M]
  ------------------
 6293|  5.17k|      return false;
 6294|  5.17k|    }
 6295|  1.22M|  }
 6296|  91.1k|  return true;
 6297|  96.3k|}
simple_absolute.cc:_ZN3ada4idnaL19from_ascii_to_asciiENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEERNS1_12basic_stringIcS4_NS1_9allocatorIcEEEE:
 6327|  91.1k|static void from_ascii_to_ascii(std::string_view ut8_string, std::string& out) {
 6328|  91.1k|  out.assign(ut8_string);
 6329|  91.1k|  ascii_map(out.data(), out.size());
 6330|  91.1k|}
_ZN3ada4idna8is_asciiENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 6281|  28.5k|bool constexpr is_ascii(std::u32string_view view) {
 6282|  96.1k|  for (uint32_t c : view) {
  ------------------
  |  Branch (6282:19): [True: 96.1k, False: 2.77k]
  ------------------
 6283|  96.1k|    if (c >= 0x80) {
  ------------------
  |  Branch (6283:9): [True: 25.7k, False: 70.3k]
  ------------------
 6284|  25.7k|      return false;
 6285|  25.7k|    }
 6286|  96.1k|  }
 6287|  2.77k|  return true;
 6288|  28.5k|}
simple_absolute.cc:_ZN3ada4idnaL13is_ace_prefixENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 6343|  21.5k|static bool is_ace_prefix(std::u32string_view label) noexcept {
 6344|  21.5k|  return label.size() >= 4 && label[0] == U'x' && label[1] == U'n' &&
  ------------------
  |  Branch (6344:10): [True: 7.59k, False: 13.9k]
  |  Branch (6344:31): [True: 4.66k, False: 2.93k]
  |  Branch (6344:51): [True: 4.28k, False: 374]
  ------------------
 6345|  4.28k|         label[2] == U'-' && label[3] == U'-';
  ------------------
  |  Branch (6345:10): [True: 3.45k, False: 832]
  |  Branch (6345:30): [True: 3.37k, False: 80]
  ------------------
 6346|  21.5k|}
simple_absolute.cc:_ZN3ada4idnaL18append_ascii_labelERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS1_17basic_string_viewIDiNS3_IDiEEEE:
 6333|  5.93k|static void append_ascii_label(std::string& out, std::u32string_view label) {
 6334|  5.93k|  const size_t old = out.size();
 6335|  5.93k|  out.resize(old + label.size());
 6336|  5.93k|  char* dest = out.data() + old;
 6337|   100k|  for (char32_t c : label) {
  ------------------
  |  Branch (6337:19): [True: 100k, False: 5.93k]
  ------------------
 6338|   100k|    *dest++ = static_cast<char>(c);
 6339|   100k|  }
 6340|  5.93k|}
_ZN3ada7unicode18is_ascii_hex_digitEc:
 7071|  6.52k|ada_really_inline constexpr bool is_ascii_hex_digit(const char c) noexcept {
 7072|  6.52k|  return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') ||
  ------------------
  |  Branch (7072:11): [True: 5.02k, False: 1.50k]
  |  Branch (7072:23): [True: 2.45k, False: 2.57k]
  |  Branch (7072:37): [True: 2.55k, False: 1.52k]
  |  Branch (7072:49): [True: 1.38k, False: 1.16k]
  ------------------
 7073|  2.68k|         (c >= 'a' && c <= 'f');
  ------------------
  |  Branch (7073:11): [True: 1.12k, False: 1.56k]
  |  Branch (7073:23): [True: 1.04k, False: 72]
  ------------------
 7074|  6.52k|}
_ZN3ada7unicode21convert_hex_to_binaryEc:
 7161|  4.33k|unsigned constexpr convert_hex_to_binary(const char c) noexcept {
 7162|  4.33k|  return hex_to_binary_table[c - '0'];
 7163|  4.33k|}
simple_absolute.cc:_ZZN3ada7unicode14percent_encodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKhENK3$_0clEc:
 7282|   911k|  auto pointer = std::ranges::find_if(input, [character_set](const char c) {
 7283|   911k|    return character_sets::bit_at(character_set, c);
 7284|   911k|  });
_ZN3ada7unicode36contains_forbidden_domain_code_pointEPKcm:
 6998|   213k|    const char* input, size_t length) noexcept {
 6999|   213k|  size_t i = 0;
 7000|   213k|  uint8_t accumulator{};
 7001|   855k|  for (; i + 4 <= length; i += 4) {
  ------------------
  |  Branch (7001:10): [True: 642k, False: 213k]
  ------------------
 7002|   642k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i])];
 7003|   642k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 1])];
 7004|   642k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 2])];
 7005|   642k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 3])];
 7006|   642k|  }
 7007|   498k|  for (; i < length; i++) {
  ------------------
  |  Branch (7007:10): [True: 285k, False: 213k]
  ------------------
 7008|   285k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i])];
 7009|   285k|  }
 7010|   213k|  return accumulator;
 7011|   213k|}
simple_absolute.cc:_ZN3ada11serializers12_GLOBAL__N_113write_hex_u16EPct:
 7413|  1.82k|ada_really_inline char* write_hex_u16(char* p, uint16_t v) noexcept {
 7414|  1.82k|  static constexpr char kHex[] = "0123456789abcdef";
 7415|  1.82k|  if (v >= 0x1000) {
  ------------------
  |  Branch (7415:7): [True: 140, False: 1.68k]
  ------------------
 7416|    140|    *p++ = kHex[(v >> 12) & 0xf];
 7417|    140|    *p++ = kHex[(v >> 8) & 0xf];
 7418|    140|    *p++ = kHex[(v >> 4) & 0xf];
 7419|    140|    *p++ = kHex[v & 0xf];
 7420|  1.68k|  } else if (v >= 0x100) {
  ------------------
  |  Branch (7420:14): [True: 278, False: 1.40k]
  ------------------
 7421|    278|    *p++ = kHex[(v >> 8) & 0xf];
 7422|    278|    *p++ = kHex[(v >> 4) & 0xf];
 7423|    278|    *p++ = kHex[v & 0xf];
 7424|  1.40k|  } else if (v >= 0x10) {
  ------------------
  |  Branch (7424:14): [True: 308, False: 1.09k]
  ------------------
 7425|    308|    *p++ = kHex[(v >> 4) & 0xf];
 7426|    308|    *p++ = kHex[v & 0xf];
 7427|  1.09k|  } else {
 7428|  1.09k|    *p++ = kHex[v & 0xf];
 7429|  1.09k|  }
 7430|  1.82k|  return p;
 7431|  1.82k|}
simple_absolute.cc:_ZN3ada11serializers12_GLOBAL__N_18write_u8EPch:
 7399|  66.9k|ada_really_inline char* write_u8(char* p, uint8_t v) noexcept {
 7400|  66.9k|  if (v < 10) {
  ------------------
  |  Branch (7400:7): [True: 49.9k, False: 16.9k]
  ------------------
 7401|  49.9k|    *p++ = static_cast<char>('0' + v);
 7402|  49.9k|  } else if (v < 100) {
  ------------------
  |  Branch (7402:14): [True: 406, False: 16.5k]
  ------------------
 7403|    406|    std::memcpy(p, &digit_pairs[static_cast<size_t>(v) * 2], 2);
 7404|    406|    p += 2;
 7405|  16.5k|  } else {
 7406|  16.5k|    *p++ = static_cast<char>('0' + v / 100);
 7407|  16.5k|    std::memcpy(p, &digit_pairs[static_cast<size_t>(v % 100) * 2], 2);
 7408|  16.5k|    p += 2;
 7409|  16.5k|  }
 7410|  66.9k|  return p;
 7411|  66.9k|}
_ZN3ada7unicode19has_tabs_or_newlineENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6847|   321k|    std::string_view user_input) noexcept {
 6848|       |  // first check for short strings in which case we do it naively.
 6849|   321k|  if (user_input.size() < 16) {  // slow path
  ------------------
  |  Branch (6849:7): [True: 61.0k, False: 260k]
  ------------------
 6850|  61.0k|    return std::ranges::any_of(user_input, is_tabs_or_newline);
 6851|  61.0k|  }
 6852|       |  // fast path for long strings (expected to be common)
 6853|   260k|  size_t i = 0;
 6854|   260k|  const __m128i mask1 = _mm_set1_epi8('\r');
 6855|   260k|  const __m128i mask2 = _mm_set1_epi8('\n');
 6856|   260k|  const __m128i mask3 = _mm_set1_epi8('\t');
 6857|       |  // If we supported SSSE3, we could use the algorithm that we use for NEON.
 6858|   260k|  __m128i running{0};
 6859|   649k|  for (; i + 15 < user_input.size(); i += 16) {
  ------------------
  |  Branch (6859:10): [True: 388k, False: 260k]
  ------------------
 6860|   388k|    __m128i word = _mm_loadu_si128((const __m128i*)(user_input.data() + i));
 6861|   388k|    running = _mm_or_si128(
 6862|   388k|        _mm_or_si128(running, _mm_or_si128(_mm_cmpeq_epi8(word, mask1),
 6863|   388k|                                           _mm_cmpeq_epi8(word, mask2))),
 6864|   388k|        _mm_cmpeq_epi8(word, mask3));
 6865|   388k|  }
 6866|   260k|  if (i < user_input.size()) {
  ------------------
  |  Branch (6866:7): [True: 257k, False: 3.19k]
  ------------------
 6867|   257k|    __m128i word = _mm_loadu_si128(
 6868|   257k|        (const __m128i*)(user_input.data() + user_input.length() - 16));
 6869|   257k|    running = _mm_or_si128(
 6870|   257k|        _mm_or_si128(running, _mm_or_si128(_mm_cmpeq_epi8(word, mask1),
 6871|   257k|                                           _mm_cmpeq_epi8(word, mask2))),
 6872|   257k|        _mm_cmpeq_epi8(word, mask3));
 6873|   257k|  }
 6874|   260k|  return _mm_movemask_epi8(running) != 0;
 6875|   321k|}
_ZN3ada7unicode18is_tabs_or_newlineEc:
 6742|   844k|constexpr bool is_tabs_or_newline(char c) noexcept {
 6743|   844k|  return c == '\r' || c == '\n' || c == '\t';
  ------------------
  |  Branch (6743:10): [True: 8, False: 844k]
  |  Branch (6743:23): [True: 16, False: 844k]
  |  Branch (6743:36): [True: 10, False: 844k]
  ------------------
 6744|   844k|}
_ZN3ada7helpers27remove_ascii_tab_or_newlineERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
 8054|    884|ada_really_inline void remove_ascii_tab_or_newline(std::string& input) {
 8055|       |  // if this ever becomes a performance issue, we could use an approach similar
 8056|       |  // to has_tabs_or_newline
 8057|    884|  std::erase_if(input, ada::unicode::is_ascii_tab_or_newline);
 8058|    884|}
_ZN3ada7unicode23is_ascii_tab_or_newlineEc:
 7092|  77.9k|    const char c) noexcept {
 7093|  77.9k|  return c == '\t' || c == '\n' || c == '\r';
  ------------------
  |  Branch (7093:10): [True: 1.62k, False: 76.2k]
  |  Branch (7093:23): [True: 1.11k, False: 75.1k]
  |  Branch (7093:36): [True: 1.46k, False: 73.7k]
  ------------------
 7094|  77.9k|}
_ZN3ada7unicode22is_c0_control_or_spaceEc:
 7087|   647k|ada_really_inline constexpr bool is_c0_control_or_space(const char c) noexcept {
 7088|   647k|  return (unsigned char)c <= ' ';
 7089|   647k|}
_ZN3ada7helpers19parse_prepared_pathENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEENS_6scheme4typeERNS1_12basic_stringIcS4_NS1_9allocatorIcEEEE:
 8736|   155k|                                           std::string& path) {
 8737|   155k|  ada_log("parse_prepared_path ", input);
 8738|   155k|  uint8_t accumulator = checkers::path_signature(input);
 8739|       |  // Let us first detect a trivial case.
 8740|       |  // If it is special, we check that we have no dot, no %,  no \ and no
 8741|       |  // character needing percent encoding. Otherwise, we check that we have no %,
 8742|       |  // no dot, and no character needing percent encoding.
 8743|   155k|  constexpr uint8_t need_encoding = 1;
 8744|   155k|  constexpr uint8_t backslash_char = 2;
 8745|   155k|  constexpr uint8_t dot_char = 4;
 8746|   155k|  constexpr uint8_t percent_char = 8;
 8747|   155k|  bool special = type != ada::scheme::NOT_SPECIAL;
 8748|   155k|  bool may_need_slow_file_handling = (type == ada::scheme::type::FILE &&
  ------------------
  |  Branch (8748:39): [True: 1.18k, False: 153k]
  ------------------
 8749|  1.18k|                                      checkers::is_windows_drive_letter(input));
  ------------------
  |  Branch (8749:39): [True: 40, False: 1.14k]
  ------------------
 8750|   155k|  bool trivial_path =
 8751|   155k|      (special ? (accumulator == 0)
  ------------------
  |  Branch (8751:7): [True: 133k, False: 21.3k]
  |  Branch (8751:8): [True: 154k, False: 732]
  ------------------
 8752|   155k|               : ((accumulator & (need_encoding | dot_char | percent_char)) ==
 8753|    732|                  0)) &&
 8754|   133k|      (!may_need_slow_file_handling);
  ------------------
  |  Branch (8754:7): [True: 133k, False: 13]
  ------------------
 8755|   155k|  if (accumulator == dot_char && !may_need_slow_file_handling) {
  ------------------
  |  Branch (8755:7): [True: 9.53k, False: 145k]
  |  Branch (8755:34): [True: 9.51k, False: 17]
  ------------------
 8756|       |    // '4' means that we have at least one dot, but nothing that requires
 8757|       |    // percent encoding or decoding. The only part that is not trivial is
 8758|       |    // that we may have single dots and double dots path segments.
 8759|       |    // If we have such segments, then we either have a path that begins
 8760|       |    // with '.' (easy to check), or we have the sequence './'.
 8761|       |    // Note: input cannot be empty, it must at least contain one character ('.')
 8762|       |    // Note: we know that '\' is not present.
 8763|  9.51k|    if (input[0] != '.') {
  ------------------
  |  Branch (8763:9): [True: 8.53k, False: 980]
  ------------------
 8764|  8.53k|      size_t slashdot = 0;
 8765|  8.53k|      bool dot_is_file = true;
 8766|  25.5k|      for (;;) {
 8767|  25.5k|        slashdot = input.find("/.", slashdot);
 8768|  25.5k|        if (slashdot == std::string_view::npos) {  // common case
  ------------------
  |  Branch (8768:13): [True: 8.53k, False: 16.9k]
  ------------------
 8769|  8.53k|          break;
 8770|  16.9k|        } else {  // uncommon
 8771|       |          // only three cases matter: /./, /.. or a final /
 8772|  16.9k|          slashdot += 2;
 8773|  16.9k|          dot_is_file &= !(slashdot == input.size() || input[slashdot] == '.' ||
  ------------------
  |  Branch (8773:28): [True: 30, False: 16.9k]
  |  Branch (8773:56): [True: 8.41k, False: 8.52k]
  ------------------
 8774|  8.52k|                           input[slashdot] == '/');
  ------------------
  |  Branch (8774:28): [True: 7.31k, False: 1.21k]
  ------------------
 8775|  16.9k|        }
 8776|  25.5k|      }
 8777|  8.53k|      trivial_path = dot_is_file;
 8778|  8.53k|    }
 8779|  9.51k|  }
 8780|   155k|  if (trivial_path) {
  ------------------
  |  Branch (8780:7): [True: 134k, False: 20.3k]
  ------------------
 8781|   134k|    ada_log("parse_path trivial");
 8782|   134k|    path += '/';
 8783|   134k|    path += input;
 8784|   134k|    return;
 8785|   134k|  }
 8786|       |  // We are going to need to look a bit at the path, but let us see if we can
 8787|       |  // ignore percent encoding *and* backslashes *and* percent characters.
 8788|       |  // Except for the trivial case, this is likely to capture 99% of paths out
 8789|       |  // there.
 8790|  20.3k|  bool fast_path =
 8791|  20.3k|      (special &&
  ------------------
  |  Branch (8791:8): [True: 19.9k, False: 387]
  ------------------
 8792|  19.9k|       (accumulator & (need_encoding | backslash_char | percent_char)) == 0) &&
  ------------------
  |  Branch (8792:8): [True: 8.46k, False: 11.5k]
  ------------------
 8793|  8.46k|      (type != ada::scheme::type::FILE);
  ------------------
  |  Branch (8793:7): [True: 8.36k, False: 103]
  ------------------
 8794|  20.3k|  if (fast_path) {
  ------------------
  |  Branch (8794:7): [True: 8.36k, False: 12.0k]
  ------------------
 8795|  8.36k|    ada_log("parse_prepared_path fast");
 8796|       |    // Here we don't need to worry about \ or percent encoding.
 8797|       |    // We also do not have a file protocol. We might have dots, however,
 8798|       |    // but dots must as appear as '.', and they cannot be encoded because
 8799|       |    // the symbol '%' is not present.
 8800|  8.36k|    size_t previous_location = 0;  // We start at 0.
 8801|  49.2k|    do {
 8802|  49.2k|      size_t new_location = input.find('/', previous_location);
 8803|       |      // std::string_view path_view = input;
 8804|       |      //  We process the last segment separately:
 8805|  49.2k|      if (new_location == std::string_view::npos) {
  ------------------
  |  Branch (8805:11): [True: 8.36k, False: 40.8k]
  ------------------
 8806|  8.36k|        std::string_view path_view = input.substr(previous_location);
 8807|  8.36k|        if (path_view == "..") {  // The path ends with ..
  ------------------
  |  Branch (8807:13): [True: 34, False: 8.33k]
  ------------------
 8808|       |          // e.g., if you receive ".." with an empty path, you go to "/".
 8809|     34|          if (path.empty()) {
  ------------------
  |  Branch (8809:15): [True: 6, False: 28]
  ------------------
 8810|      6|            path = '/';
 8811|      6|            return;
 8812|      6|          }
 8813|       |          // Fast case where we have nothing to do:
 8814|     28|          if (path.back() == '/') {
  ------------------
  |  Branch (8814:15): [True: 9, False: 19]
  ------------------
 8815|      9|            return;
 8816|      9|          }
 8817|       |          // If you have the path "/joe/myfriend",
 8818|       |          // then you delete 'myfriend'.
 8819|     19|          path.resize(path.rfind('/') + 1);
 8820|     19|          return;
 8821|     28|        }
 8822|  8.33k|        path += '/';
 8823|  8.33k|        if (path_view != ".") {
  ------------------
  |  Branch (8823:13): [True: 8.28k, False: 46]
  ------------------
 8824|  8.28k|          path.append(path_view);
 8825|  8.28k|        }
 8826|  8.33k|        return;
 8827|  40.8k|      } else {
 8828|       |        // This is a non-final segment.
 8829|  40.8k|        std::string_view path_view =
 8830|  40.8k|            input.substr(previous_location, new_location - previous_location);
 8831|  40.8k|        previous_location = new_location + 1;
 8832|  40.8k|        if (path_view == "..") {
  ------------------
  |  Branch (8832:13): [True: 8.24k, False: 32.5k]
  ------------------
 8833|  8.24k|          size_t last_delimiter = path.rfind('/');
 8834|  8.24k|          if (last_delimiter != std::string::npos) {
  ------------------
  |  Branch (8834:15): [True: 7.38k, False: 863]
  ------------------
 8835|  7.38k|            path.erase(last_delimiter);
 8836|  7.38k|          }
 8837|  32.5k|        } else if (path_view != ".") {
  ------------------
  |  Branch (8837:20): [True: 24.4k, False: 8.18k]
  ------------------
 8838|  24.4k|          path += '/';
 8839|  24.4k|          path.append(path_view);
 8840|  24.4k|        }
 8841|  40.8k|      }
 8842|  49.2k|    } while (true);
  ------------------
  |  Branch (8842:14): [True: 40.8k, Folded]
  ------------------
 8843|  12.0k|  } else {
 8844|  12.0k|    ada_log("parse_path slow");
 8845|       |    // we have reached the general case
 8846|  12.0k|    bool needs_percent_encoding = (accumulator & 1);
 8847|  12.0k|    std::string path_buffer_tmp;
 8848|  37.0k|    do {
 8849|  37.0k|      size_t location = (special && (accumulator & 2))
  ------------------
  |  Branch (8849:26): [True: 35.5k, False: 1.49k]
  |  Branch (8849:37): [True: 2.48k, False: 33.0k]
  ------------------
 8850|  37.0k|                            ? input.find_first_of("/\\")
 8851|  37.0k|                            : input.find('/');
 8852|  37.0k|      std::string_view path_view = input;
 8853|  37.0k|      if (location != std::string_view::npos) {
  ------------------
  |  Branch (8853:11): [True: 25.0k, False: 12.0k]
  ------------------
 8854|  25.0k|        path_view.remove_suffix(path_view.size() - location);
 8855|  25.0k|        input.remove_prefix(location + 1);
 8856|  25.0k|      }
 8857|       |      // path_buffer is either path_view or it might point at a percent encoded
 8858|       |      // temporary file.
 8859|  37.0k|      std::string_view path_buffer =
 8860|  37.0k|          (needs_percent_encoding &&
  ------------------
  |  Branch (8860:12): [True: 6.39k, False: 30.6k]
  ------------------
 8861|  6.39k|           ada::unicode::percent_encode<false>(
  ------------------
  |  Branch (8861:12): [True: 2.44k, False: 3.94k]
  ------------------
 8862|  6.39k|               path_view, character_sets::PATH_PERCENT_ENCODE, path_buffer_tmp))
 8863|  37.0k|              ? path_buffer_tmp
 8864|  37.0k|              : path_view;
 8865|  37.0k|      if (unicode::is_double_dot_path_segment(path_buffer)) {
  ------------------
  |  Branch (8865:11): [True: 8.42k, False: 28.6k]
  ------------------
 8866|  8.42k|        helpers::shorten_path(path, type);
 8867|  8.42k|        if (location == std::string_view::npos) {
  ------------------
  |  Branch (8867:13): [True: 7.12k, False: 1.29k]
  ------------------
 8868|  7.12k|          path += '/';
 8869|  7.12k|        }
 8870|  28.6k|      } else if (unicode::is_single_dot_path_segment(path_buffer) &&
  ------------------
  |  Branch (8870:18): [True: 1.07k, False: 27.5k]
  ------------------
 8871|  1.07k|                 (location == std::string_view::npos)) {
  ------------------
  |  Branch (8871:18): [True: 374, False: 701]
  ------------------
 8872|    374|        path += '/';
 8873|    374|      }
 8874|       |      // Otherwise, if path_buffer is not a single-dot path segment, then:
 8875|  28.2k|      else if (!unicode::is_single_dot_path_segment(path_buffer)) {
  ------------------
  |  Branch (8875:16): [True: 27.5k, False: 701]
  ------------------
 8876|       |        // If url's scheme is "file", url's path is empty, and path_buffer is a
 8877|       |        // Windows drive letter, then replace the second code point in
 8878|       |        // path_buffer with U+003A (:).
 8879|  27.5k|        if (type == ada::scheme::type::FILE && path.empty() &&
  ------------------
  |  Branch (8879:13): [True: 1.80k, False: 25.7k]
  |  Branch (8879:48): [True: 524, False: 1.27k]
  ------------------
 8880|    524|            checkers::is_windows_drive_letter(path_buffer)) {
  ------------------
  |  Branch (8880:13): [True: 42, False: 482]
  ------------------
 8881|     42|          path += '/';
 8882|     42|          path += path_buffer[0];
 8883|     42|          path += ':';
 8884|     42|          path_buffer.remove_prefix(2);
 8885|     42|          path.append(path_buffer);
 8886|  27.4k|        } else {
 8887|       |          // Append path_buffer to url's path.
 8888|  27.4k|          path += '/';
 8889|  27.4k|          path.append(path_buffer);
 8890|  27.4k|        }
 8891|  27.5k|      }
 8892|  37.0k|      if (location == std::string_view::npos) {
  ------------------
  |  Branch (8892:11): [True: 12.0k, False: 25.0k]
  ------------------
 8893|  12.0k|        return;
 8894|  12.0k|      }
 8895|  37.0k|    } while (true);
  ------------------
  |  Branch (8895:14): [True: 25.0k, Folded]
  ------------------
 8896|  12.0k|  }
 8897|  20.3k|}
_ZN3ada8checkers14path_signatureENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
   87|   310k|    std::string_view input) noexcept {
   88|       |  // The path percent-encode set is the query percent-encode set and U+003F (?),
   89|       |  // U+0060 (`), U+007B ({), and U+007D (}). The query percent-encode set is the
   90|       |  // C0 control percent-encode set and U+0020 SPACE, U+0022 ("), U+0023 (#),
   91|       |  // U+003C (<), and U+003E (>). The C0 control percent-encode set are the C0
   92|       |  // controls and all code points greater than U+007E (~).
   93|   310k|  size_t i = 0;
   94|   310k|  uint8_t accumulator{};
   95|   428k|  for (; i + 7 < input.size(); i += 8) {
  ------------------
  |  Branch (95:10): [True: 118k, False: 310k]
  ------------------
   96|   118k|    accumulator |= uint8_t(path_signature_table[uint8_t(input[i])] |
   97|   118k|                           path_signature_table[uint8_t(input[i + 1])] |
   98|   118k|                           path_signature_table[uint8_t(input[i + 2])] |
   99|   118k|                           path_signature_table[uint8_t(input[i + 3])] |
  100|   118k|                           path_signature_table[uint8_t(input[i + 4])] |
  101|   118k|                           path_signature_table[uint8_t(input[i + 5])] |
  102|   118k|                           path_signature_table[uint8_t(input[i + 6])] |
  103|   118k|                           path_signature_table[uint8_t(input[i + 7])]);
  104|   118k|  }
  105|   563k|  for (; i < input.size(); i++) {
  ------------------
  |  Branch (105:10): [True: 253k, False: 310k]
  ------------------
  106|   253k|    accumulator |= uint8_t(path_signature_table[uint8_t(input[i])]);
  107|   253k|  }
  108|   310k|  return accumulator;
  109|   310k|}
_ZN3ada7unicode14percent_encodeILb0EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKhRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEE:
 7308|  12.7k|                    std::string& out) {
 7309|  12.7k|  ada_log("percent_encode ", input, " to output string while ",
 7310|  12.7k|          append ? "appending" : "overwriting");
 7311|  12.7k|  auto pointer = std::ranges::find_if(input, [character_set](const char c) {
 7312|  12.7k|    return character_sets::bit_at(character_set, c);
 7313|  12.7k|  });
 7314|  12.7k|  ada_log("percent_encode done checking, moved to ",
 7315|  12.7k|          std::distance(input.begin(), pointer));
 7316|       |
 7317|       |  // Optimization: Don't iterate if percent encode is not required
 7318|  12.7k|  if (pointer == input.end()) {
  ------------------
  |  Branch (7318:7): [True: 7.89k, False: 4.89k]
  ------------------
 7319|  7.89k|    ada_log("percent_encode encoding not needed.");
 7320|  7.89k|    return false;
 7321|  7.89k|  }
 7322|  4.89k|  if constexpr (!append) {
 7323|  4.89k|    out.clear();
 7324|  4.89k|  }
 7325|  4.89k|  ada_log("percent_encode appending ", std::distance(input.begin(), pointer),
 7326|  4.89k|          " bytes");
 7327|       |  // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage)
 7328|  4.89k|  out.append(input.data(), std::distance(input.begin(), pointer));
 7329|  4.89k|  ada_log("percent_encode processing ", std::distance(pointer, input.end()),
 7330|  4.89k|          " bytes");
 7331|  78.3k|  for (; pointer != input.end(); pointer++) {
  ------------------
  |  Branch (7331:10): [True: 73.4k, False: 4.89k]
  ------------------
 7332|  73.4k|    if (character_sets::bit_at(character_set, *pointer)) {
  ------------------
  |  Branch (7332:9): [True: 61.6k, False: 11.8k]
  ------------------
 7333|  61.6k|      out.append(character_sets::hex + uint8_t(*pointer) * 4, 3);
 7334|  61.6k|    } else {
 7335|  11.8k|      out += *pointer;
 7336|  11.8k|    }
 7337|  73.4k|  }
 7338|  4.89k|  return true;
 7339|  12.7k|}
_ZZN3ada7unicode14percent_encodeILb0EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKhRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEEENKUlcE_clEc:
 7311|  24.0k|  auto pointer = std::ranges::find_if(input, [character_set](const char c) {
 7312|  24.0k|    return character_sets::bit_at(character_set, c);
 7313|  24.0k|  });
_ZN3ada7unicode26is_double_dot_path_segmentENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 7100|  74.0k|    std::string_view input) noexcept {
 7101|       |  // This will catch most cases:
 7102|       |  // The length must be 2,4 or 6.
 7103|       |  // We divide by two and require
 7104|       |  // that the result be between 1 and 3 inclusively.
 7105|  74.0k|  uint64_t half_length = uint64_t(input.size()) / 2;
 7106|  74.0k|  if (half_length - 1 > 2) {
  ------------------
  |  Branch (7106:7): [True: 26.8k, False: 47.2k]
  ------------------
 7107|  26.8k|    return false;
 7108|  26.8k|  }
 7109|       |  // We have a string of length 2, 4 or 6.
 7110|       |  // We now check the first character:
 7111|  47.2k|  if ((input[0] != '.') && (input[0] != '%')) {
  ------------------
  |  Branch (7111:7): [True: 41.9k, False: 5.29k]
  |  Branch (7111:28): [True: 18.4k, False: 23.5k]
  ------------------
 7112|  18.4k|    return false;
 7113|  18.4k|  }
 7114|       |  // We are unlikely the get beyond this point.
 7115|  28.7k|  int hash_value = (input.size() + (unsigned)(input[0])) & 3;
 7116|  28.7k|  const std::string_view target = table_is_double_dot_path_segment[hash_value];
 7117|  28.7k|  if (target.size() != input.size()) {
  ------------------
  |  Branch (7117:7): [True: 5.76k, False: 23.0k]
  ------------------
 7118|  5.76k|    return false;
 7119|  5.76k|  }
 7120|       |  // We almost never get here.
 7121|       |  // Optimizing the rest is relatively unimportant.
 7122|  23.0k|  auto prefix_equal_unsafe = [](std::string_view a, std::string_view b) {
 7123|  23.0k|    uint16_t A, B;
 7124|  23.0k|    memcpy(&A, a.data(), sizeof(A));
 7125|  23.0k|    memcpy(&B, b.data(), sizeof(B));
 7126|  23.0k|    return A == B;
 7127|  23.0k|  };
 7128|  23.0k|  if (!prefix_equal_unsafe(input, target)) {
  ------------------
  |  Branch (7128:7): [True: 2.99k, False: 20.0k]
  ------------------
 7129|  2.99k|    return false;
 7130|  2.99k|  }
 7131|  80.1k|  for (size_t i = 2; i < input.size(); i++) {
  ------------------
  |  Branch (7131:22): [True: 63.2k, False: 16.8k]
  ------------------
 7132|  63.2k|    char c = input[i];
 7133|  63.2k|    if ((uint8_t((c | 0x20) - 0x61) <= 25 ? (c | 0x20) : c) != target[i]) {
  ------------------
  |  Branch (7133:9): [True: 3.19k, False: 60.0k]
  |  Branch (7133:10): [True: 30.9k, False: 32.2k]
  ------------------
 7134|  3.19k|      return false;
 7135|  3.19k|    }
 7136|  63.2k|  }
 7137|  16.8k|  return true;
 7138|       |  // The above code might be a bit better than the code below. Compilers
 7139|       |  // are not stupid and may use the fact that these strings have length 2,4 and
 7140|       |  // 6 and other tricks.
 7141|       |  // return input == ".." ||
 7142|       |  //  input == ".%2e" || input == ".%2E" ||
 7143|       |  //  input == "%2e." || input == "%2E." ||
 7144|       |  //  input == "%2e%2e" || input == "%2E%2E" || input == "%2E%2e" || input ==
 7145|       |  //  "%2e%2E";
 7146|  20.0k|}
_ZZN3ada7unicode26is_double_dot_path_segmentENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlS5_S5_E_clES5_S5_:
 7122|  23.0k|  auto prefix_equal_unsafe = [](std::string_view a, std::string_view b) {
 7123|  23.0k|    uint16_t A, B;
 7124|  23.0k|    memcpy(&A, a.data(), sizeof(A));
 7125|  23.0k|    memcpy(&B, b.data(), sizeof(B));
 7126|  23.0k|    return A == B;
 7127|  23.0k|  };
_ZN3ada7unicode26is_single_dot_path_segmentENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 7149|   113k|    std::string_view input) noexcept {
 7150|   113k|  return input == "." || input == "%2e" || input == "%2E";
  ------------------
  |  Branch (7150:10): [True: 1.54k, False: 112k]
  |  Branch (7150:26): [True: 1.99k, False: 110k]
  |  Branch (7150:44): [True: 16, False: 110k]
  ------------------
 7151|   113k|}
_ZN3ada7unicode28is_forbidden_host_code_pointEc:
 6970|  17.3k|    const char c) noexcept {
 6971|  17.3k|  return is_forbidden_host_code_point_table[uint8_t(c)];
 6972|  17.3k|}
_ZN3ada6detail17parse_ipv4_numberERPKcS2_RmRb:
 9014|  32.6k|                              bool& is_pure_decimal) noexcept {
 9015|  32.6k|  is_pure_decimal = false;
 9016|  32.6k|  if (p >= end) [[unlikely]] {
  ------------------
  |  Branch (9016:7): [True: 0, False: 32.6k]
  ------------------
 9017|      0|    return false;
 9018|      0|  }
 9019|  32.6k|  if (end - p >= 2 && p[0] == '0' && ((p[1] | 0x20) == 'x')) {
  ------------------
  |  Branch (9019:7): [True: 17.0k, False: 15.6k]
  |  Branch (9019:23): [True: 14.8k, False: 2.13k]
  |  Branch (9019:38): [True: 14.4k, False: 378]
  ------------------
 9020|  14.4k|    p += 2;
 9021|  14.4k|    if (p == end || *p == '.') {
  ------------------
  |  Branch (9021:9): [True: 58, False: 14.4k]
  |  Branch (9021:21): [True: 22, False: 14.4k]
  ------------------
 9022|     80|      value = 0;
 9023|     80|      return true;
 9024|     80|    }
 9025|  14.4k|    uint64_t v = 0;
 9026|  14.4k|    int digits = 0;
 9027|  43.6k|    while (p < end && *p != '.') {
  ------------------
  |  Branch (9027:12): [True: 43.4k, False: 190]
  |  Branch (9027:23): [True: 29.2k, False: 14.1k]
  ------------------
 9028|  29.2k|      const uint8_t nib = hex_nibble[static_cast<unsigned char>(*p)];
 9029|  29.2k|      if (nib == 0xff) [[unlikely]] {
  ------------------
  |  Branch (9029:11): [True: 26, False: 29.2k]
  ------------------
 9030|     26|        return false;
 9031|     26|      }
 9032|  29.2k|      if (v > (0xFFFFFFFFULL >> 4)) [[unlikely]] {
  ------------------
  |  Branch (9032:11): [True: 12, False: 29.2k]
  ------------------
 9033|     12|        return false;
 9034|     12|      }
 9035|  29.2k|      v = (v << 4) | nib;
 9036|  29.2k|      ++p;
 9037|  29.2k|      ++digits;
 9038|  29.2k|    }
 9039|  14.3k|    if (digits == 0) [[unlikely]] {
  ------------------
  |  Branch (9039:9): [True: 0, False: 14.3k]
  ------------------
 9040|      0|      return false;
 9041|      0|    }
 9042|  14.3k|    value = v;
 9043|  14.3k|    return true;
 9044|  14.3k|  }
 9045|  18.1k|  if (end - p >= 2 && p[0] == '0' && p[1] >= '0' && p[1] <= '9') {
  ------------------
  |  Branch (9045:7): [True: 2.51k, False: 15.6k]
  |  Branch (9045:23): [True: 378, False: 2.13k]
  |  Branch (9045:38): [True: 240, False: 138]
  |  Branch (9045:53): [True: 226, False: 14]
  ------------------
 9046|    226|    ++p;
 9047|    226|    uint64_t v = 0;
 9048|  3.36k|    while (p < end && *p != '.') {
  ------------------
  |  Branch (9048:12): [True: 3.23k, False: 132]
  |  Branch (9048:23): [True: 3.18k, False: 48]
  ------------------
 9049|  3.18k|      const char c = *p;
 9050|  3.18k|      if (c < '0' || c > '7') [[unlikely]] {
  ------------------
  |  Branch (9050:11): [True: 10, False: 3.17k]
  |  Branch (9050:22): [True: 18, False: 3.15k]
  ------------------
 9051|     28|        return false;
 9052|     28|      }
 9053|  3.15k|      if (v > (0xFFFFFFFFULL >> 3)) [[unlikely]] {
  ------------------
  |  Branch (9053:11): [True: 18, False: 3.14k]
  ------------------
 9054|     18|        return false;
 9055|     18|      }
 9056|  3.14k|      v = (v << 3) | static_cast<uint64_t>(c - '0');
 9057|  3.14k|      ++p;
 9058|  3.14k|    }
 9059|    180|    value = v;
 9060|    180|    return true;
 9061|    226|  }
 9062|  17.9k|  if (*p < '0' || *p > '9') [[unlikely]] {
  ------------------
  |  Branch (9062:7): [True: 84, False: 17.8k]
  |  Branch (9062:19): [True: 116, False: 17.7k]
  ------------------
 9063|    200|    return false;
 9064|    200|  }
 9065|  17.7k|  is_pure_decimal = true;
 9066|  17.7k|  uint64_t v = static_cast<uint64_t>(*p - '0');
 9067|  17.7k|  ++p;
 9068|  25.7k|  while (p < end && *p != '.') {
  ------------------
  |  Branch (9068:10): [True: 9.36k, False: 16.4k]
  |  Branch (9068:21): [True: 8.15k, False: 1.20k]
  ------------------
 9069|  8.15k|    const char c = *p;
 9070|  8.15k|    if (c < '0' || c > '9') [[unlikely]] {
  ------------------
  |  Branch (9070:9): [True: 24, False: 8.13k]
  |  Branch (9070:20): [True: 58, False: 8.07k]
  ------------------
 9071|     82|      return false;
 9072|     82|    }
 9073|  8.07k|    if (v > 429496729ULL) [[unlikely]] {
  ------------------
  |  Branch (9073:9): [True: 8, False: 8.06k]
  ------------------
 9074|      8|      return false;
 9075|      8|    }
 9076|  8.06k|    v = v * 10u + static_cast<uint64_t>(c - '0');
 9077|  8.06k|    if (v > 0xFFFFFFFFULL) [[unlikely]] {
  ------------------
  |  Branch (9077:9): [True: 8, False: 8.05k]
  ------------------
 9078|      8|      return false;
 9079|      8|    }
 9080|  8.05k|    ++p;
 9081|  8.05k|  }
 9082|  17.6k|  value = v;
 9083|  17.6k|  return true;
 9084|  17.7k|}
_ZN3ada6detail15parse_hex_pieceERPKcS2_Rt:
 9088|  2.25k|                           uint16_t& value) noexcept {
 9089|  2.25k|  if (pointer == end) {
  ------------------
  |  Branch (9089:7): [True: 0, False: 2.25k]
  ------------------
 9090|      0|    return 0;
 9091|      0|  }
 9092|  2.25k|  const uint8_t n0 = hex_nibble[static_cast<unsigned char>(*pointer)];
 9093|  2.25k|  if (n0 == 0xff) {
  ------------------
  |  Branch (9093:7): [True: 50, False: 2.20k]
  ------------------
 9094|     50|    return 0;
 9095|     50|  }
 9096|  2.20k|  uint32_t v = n0;
 9097|  2.20k|  ++pointer;
 9098|  2.20k|  int length = 1;
 9099|  2.20k|  if (pointer != end) {
  ------------------
  |  Branch (9099:7): [True: 1.97k, False: 236]
  ------------------
 9100|  1.97k|    const uint8_t n1 = hex_nibble[static_cast<unsigned char>(*pointer)];
 9101|  1.97k|    if (n1 != 0xff) {
  ------------------
  |  Branch (9101:9): [True: 828, False: 1.14k]
  ------------------
 9102|    828|      v = (v << 4) | n1;
 9103|    828|      ++pointer;
 9104|    828|      ++length;
 9105|    828|      if (pointer != end) {
  ------------------
  |  Branch (9105:11): [True: 714, False: 114]
  ------------------
 9106|    714|        const uint8_t n2 = hex_nibble[static_cast<unsigned char>(*pointer)];
 9107|    714|        if (n2 != 0xff) {
  ------------------
  |  Branch (9107:13): [True: 484, False: 230]
  ------------------
 9108|    484|          v = (v << 4) | n2;
 9109|    484|          ++pointer;
 9110|    484|          ++length;
 9111|    484|          if (pointer != end) {
  ------------------
  |  Branch (9111:15): [True: 386, False: 98]
  ------------------
 9112|    386|            const uint8_t n3 = hex_nibble[static_cast<unsigned char>(*pointer)];
 9113|    386|            if (n3 != 0xff) {
  ------------------
  |  Branch (9113:17): [True: 156, False: 230]
  ------------------
 9114|    156|              v = (v << 4) | n3;
 9115|    156|              ++pointer;
 9116|    156|              ++length;
 9117|    156|            }
 9118|    386|          }
 9119|    484|        }
 9120|    714|      }
 9121|    828|    }
 9122|  1.97k|  }
 9123|  2.20k|  value = static_cast<uint16_t>(v);
 9124|  2.20k|  return length;
 9125|  2.25k|}
_ZN3ada7unicode13is_alnum_plusEc:
 7064|  1.49M|ada_really_inline constexpr bool is_alnum_plus(const char c) noexcept {
 7065|  1.49M|  return is_alnum_plus_table[uint8_t(c)];
 7066|       |  // A table is almost surely much faster than the
 7067|       |  // following under most compilers: return
 7068|       |  // return (std::isalnum(c) || c == '+' || c == '-' || c == '.');
 7069|  1.49M|}
_ZN3ada7helpers10prune_hashERNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 7994|   321k|    std::string_view& input) noexcept {
 7995|       |  // compiles down to 20--30 instructions including a class to memchr (C
 7996|       |  // function). this function should be quite fast.
 7997|   321k|  size_t location_of_first = input.find('#');
 7998|   321k|  if (location_of_first == std::string_view::npos) {
  ------------------
  |  Branch (7998:7): [True: 300k, False: 21.5k]
  ------------------
 7999|   300k|    return std::nullopt;
 8000|   300k|  }
 8001|  21.5k|  std::string_view hash = input;
 8002|  21.5k|  hash.remove_prefix(location_of_first + 1);
 8003|  21.5k|  input.remove_suffix(input.size() - location_of_first);
 8004|  21.5k|  return hash;
 8005|   321k|}
_ZN3ada7helpers32find_authority_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8932|   118k|find_authority_delimiter_special(std::string_view view) noexcept {
 8933|       |  // performance note: we might be able to gain further performance
 8934|       |  // with SIMD intrinsics.
 8935|  1.40M|  for (auto pos = view.begin(); pos != view.end(); ++pos) {
  ------------------
  |  Branch (8935:33): [True: 1.40M, False: 878]
  ------------------
 8936|  1.40M|    if (authority_delimiter_special[(uint8_t)*pos]) {
  ------------------
  |  Branch (8936:9): [True: 117k, False: 1.28M]
  ------------------
 8937|   117k|      return pos - view.begin();
 8938|   117k|    }
 8939|  1.40M|  }
 8940|    878|  return size_t(view.size());
 8941|   118k|}
_ZN3ada7helpers24find_authority_delimiterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8953|    604|find_authority_delimiter(std::string_view view) noexcept {
 8954|       |  // performance note: we might be able to gain further performance
 8955|       |  // with SIMD instrinsics.
 8956|  7.36k|  for (auto pos = view.begin(); pos != view.end(); ++pos) {
  ------------------
  |  Branch (8956:33): [True: 7.33k, False: 26]
  ------------------
 8957|  7.33k|    if (authority_delimiter[(uint8_t)*pos]) {
  ------------------
  |  Branch (8957:9): [True: 578, False: 6.75k]
  ------------------
 8958|    578|      return pos - view.begin();
 8959|    578|    }
 8960|  7.33k|  }
 8961|     26|  return size_t(view.size());
 8962|    604|}
_ZN3ada7helpers12shorten_pathERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS_6scheme4typeE:
 8007|  16.8k|ada_really_inline bool shorten_path(std::string& path, ada::scheme::type type) {
 8008|       |  // Let path be url's path.
 8009|       |  // If url's scheme is "file", path's size is 1, and path[0] is a normalized
 8010|       |  // Windows drive letter, then return.
 8011|  16.8k|  if (type == ada::scheme::type::FILE &&
  ------------------
  |  Branch (8011:7): [True: 370, False: 16.4k]
  ------------------
 8012|    370|      path.find('/', 1) == std::string_view::npos && !path.empty()) {
  ------------------
  |  Branch (8012:7): [True: 190, False: 180]
  |  Branch (8012:54): [True: 146, False: 44]
  ------------------
 8013|    146|    if (checkers::is_normalized_windows_drive_letter(
  ------------------
  |  Branch (8013:9): [True: 24, False: 122]
  ------------------
 8014|    146|            helpers::substring(path, 1))) {
 8015|     24|      return false;
 8016|     24|    }
 8017|    146|  }
 8018|       |
 8019|       |  // Remove path's last item, if any.
 8020|  16.8k|  size_t last_delimiter = path.rfind('/');
 8021|  16.8k|  if (last_delimiter != std::string::npos) {
  ------------------
  |  Branch (8021:7): [True: 15.3k, False: 1.46k]
  ------------------
 8022|  15.3k|    path.erase(last_delimiter);
 8023|  15.3k|    return true;
 8024|  15.3k|  }
 8025|       |
 8026|  1.46k|  return false;
 8027|  16.8k|}
_ZN3ada7helpers27get_host_delimiter_locationEbRNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8645|   316k|    const bool is_special, std::string_view& view) noexcept {
 8646|       |  /**
 8647|       |   * The spec at https://url.spec.whatwg.org/#hostname-state expects us to
 8648|       |   * compute a variable called insideBrackets but this variable is only used
 8649|       |   * once, to check whether a ':' character was found outside brackets. Exact
 8650|       |   * text: "Otherwise, if c is U+003A (:) and insideBrackets is false, then:".
 8651|       |   * It is conceptually simpler and arguably more efficient to just return a
 8652|       |   * Boolean indicating whether ':' was found outside brackets.
 8653|       |   */
 8654|   316k|  const size_t view_size = view.size();
 8655|   316k|  size_t location = 0;
 8656|   316k|  bool found_colon = false;
 8657|       |  /**
 8658|       |   * Performance analysis:
 8659|       |   *
 8660|       |   * We are basically seeking the end of the hostname which can be indicated
 8661|       |   * by the end of the view, or by one of the characters ':', '/', '?', '\\'
 8662|       |   * (where '\\' is only applicable for special URLs). However, these must
 8663|       |   * appear outside a bracket range. E.g., if you have [something?]fd: then the
 8664|       |   * '?' does not count.
 8665|       |   *
 8666|       |   * So we can skip ahead to the next delimiter, as long as we include '[' in
 8667|       |   * the set of delimiters, and that we handle it first.
 8668|       |   *
 8669|       |   * So the trick is to have a fast function that locates the next delimiter.
 8670|       |   * Unless we find '[', then it only needs to be called once! Ideally, such a
 8671|       |   * function would be provided by the C++ standard library, but it seems that
 8672|       |   * find_first_of is not very fast, so we are forced to roll our own.
 8673|       |   *
 8674|       |   * We do not break into two loops for speed, but for clarity.
 8675|       |   */
 8676|   316k|  if (is_special) {
  ------------------
  |  Branch (8676:7): [True: 315k, False: 1.37k]
  ------------------
 8677|       |    // We move to the next delimiter.
 8678|   315k|    location = find_next_host_delimiter_special(view, location);
 8679|       |    // Unless we find '[' then we are going only going to have to call
 8680|       |    // find_next_host_delimiter_special once.
 8681|   317k|    for (; location < view_size;
  ------------------
  |  Branch (8681:12): [True: 311k, False: 6.69k]
  ------------------
 8682|   315k|         location = find_next_host_delimiter_special(view, location)) {
 8683|   311k|      if (view[location] == '[') {
  ------------------
  |  Branch (8683:11): [True: 2.45k, False: 308k]
  ------------------
 8684|  2.45k|        location = view.find(']', location);
 8685|  2.45k|        if (location == std::string_view::npos) {
  ------------------
  |  Branch (8685:13): [True: 258, False: 2.19k]
  ------------------
 8686|       |          // performance: view.find might get translated to a memchr, which
 8687|       |          // has no notion of std::string_view::npos, so the code does not
 8688|       |          // reflect the assembly.
 8689|    258|          location = view_size;
 8690|    258|          break;
 8691|    258|        }
 8692|   308k|      } else {
 8693|   308k|        found_colon = view[location] == ':';
 8694|   308k|        break;
 8695|   308k|      }
 8696|   311k|    }
 8697|   315k|  } else {
 8698|       |    // We move to the next delimiter.
 8699|  1.37k|    location = find_next_host_delimiter(view, location);
 8700|       |    // Unless we find '[' then we are going only going to have to call
 8701|       |    // find_next_host_delimiter_special once.
 8702|  1.53k|    for (; location < view_size;
  ------------------
  |  Branch (8702:12): [True: 1.38k, False: 152]
  ------------------
 8703|  1.38k|         location = find_next_host_delimiter(view, location)) {
 8704|  1.38k|      if (view[location] == '[') {
  ------------------
  |  Branch (8704:11): [True: 194, False: 1.19k]
  ------------------
 8705|    194|        location = view.find(']', location);
 8706|    194|        if (location == std::string_view::npos) {
  ------------------
  |  Branch (8706:13): [True: 36, False: 158]
  ------------------
 8707|       |          // performance: view.find might get translated to a memchr, which
 8708|       |          // has no notion of std::string_view::npos, so the code does not
 8709|       |          // reflect the assembly.
 8710|     36|          location = view_size;
 8711|     36|          break;
 8712|     36|        }
 8713|  1.19k|      } else {
 8714|  1.19k|        found_colon = view[location] == ':';
 8715|  1.19k|        break;
 8716|  1.19k|      }
 8717|  1.38k|    }
 8718|  1.37k|  }
 8719|       |  // performance: remove_suffix may translate into a single instruction.
 8720|   316k|  view.remove_suffix(view_size - location);
 8721|   316k|  return {location, found_colon};
 8722|   316k|}
_ZN3ada7helpers32find_next_host_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEm:
 8222|   317k|    std::string_view view, size_t location) noexcept {
 8223|       |  // first check for short strings in which case we do it naively.
 8224|   317k|  if (view.size() - location < 16) {  // slow path
  ------------------
  |  Branch (8224:7): [True: 181k, False: 136k]
  ------------------
 8225|  1.71M|    for (size_t i = location; i < view.size(); i++) {
  ------------------
  |  Branch (8225:31): [True: 1.71M, False: 4.94k]
  ------------------
 8226|  1.71M|      if (view[i] == ':' || view[i] == '/' || view[i] == '\\' ||
  ------------------
  |  Branch (8226:11): [True: 1.52k, False: 1.71M]
  |  Branch (8226:29): [True: 173k, False: 1.54M]
  |  Branch (8226:47): [True: 190, False: 1.53M]
  ------------------
 8227|  1.53M|          view[i] == '?' || view[i] == '[') {
  ------------------
  |  Branch (8227:11): [True: 400, False: 1.53M]
  |  Branch (8227:29): [True: 1.09k, False: 1.53M]
  ------------------
 8228|   176k|        return i;
 8229|   176k|      }
 8230|  1.71M|    }
 8231|  4.94k|    return size_t(view.size());
 8232|   181k|  }
 8233|       |  // fast path for long strings (expected to be common)
 8234|   136k|  size_t i = location;
 8235|   136k|  const __m128i mask1 = _mm_set1_epi8(':');
 8236|   136k|  const __m128i mask2 = _mm_set1_epi8('/');
 8237|   136k|  const __m128i mask3 = _mm_set1_epi8('\\');
 8238|   136k|  const __m128i mask4 = _mm_set1_epi8('?');
 8239|   136k|  const __m128i mask5 = _mm_set1_epi8('[');
 8240|       |
 8241|   208k|  for (; i + 15 < view.size(); i += 16) {
  ------------------
  |  Branch (8241:10): [True: 163k, False: 45.5k]
  ------------------
 8242|   163k|    __m128i word = _mm_loadu_si128((const __m128i*)(view.data() + i));
 8243|   163k|    __m128i m1 = _mm_cmpeq_epi8(word, mask1);
 8244|   163k|    __m128i m2 = _mm_cmpeq_epi8(word, mask2);
 8245|   163k|    __m128i m3 = _mm_cmpeq_epi8(word, mask3);
 8246|   163k|    __m128i m4 = _mm_cmpeq_epi8(word, mask4);
 8247|   163k|    __m128i m5 = _mm_cmpeq_epi8(word, mask5);
 8248|   163k|    __m128i m = _mm_or_si128(
 8249|   163k|        _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m3, m4)), m5);
 8250|   163k|    int mask = _mm_movemask_epi8(m);
 8251|   163k|    if (mask != 0) {
  ------------------
  |  Branch (8251:9): [True: 90.6k, False: 72.6k]
  ------------------
 8252|  90.6k|      return i + trailing_zeroes(mask);
 8253|  90.6k|    }
 8254|   163k|  }
 8255|  45.5k|  if (i < view.size()) {
  ------------------
  |  Branch (8255:7): [True: 45.3k, False: 218]
  ------------------
 8256|  45.3k|    __m128i word =
 8257|  45.3k|        _mm_loadu_si128((const __m128i*)(view.data() + view.length() - 16));
 8258|  45.3k|    __m128i m1 = _mm_cmpeq_epi8(word, mask1);
 8259|  45.3k|    __m128i m2 = _mm_cmpeq_epi8(word, mask2);
 8260|  45.3k|    __m128i m3 = _mm_cmpeq_epi8(word, mask3);
 8261|  45.3k|    __m128i m4 = _mm_cmpeq_epi8(word, mask4);
 8262|  45.3k|    __m128i m5 = _mm_cmpeq_epi8(word, mask5);
 8263|  45.3k|    __m128i m = _mm_or_si128(
 8264|  45.3k|        _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m3, m4)), m5);
 8265|  45.3k|    int mask = _mm_movemask_epi8(m);
 8266|  45.3k|    if (mask != 0) {
  ------------------
  |  Branch (8266:9): [True: 43.8k, False: 1.53k]
  ------------------
 8267|  43.8k|      return view.length() - 16 + trailing_zeroes(mask);
 8268|  43.8k|    }
 8269|  45.3k|  }
 8270|  1.75k|  return size_t(view.length());
 8271|  45.5k|}
_ZN3ada7helpers15trailing_zeroesEj:
 8075|   135k|ada_really_inline int trailing_zeroes(uint32_t input_num) noexcept {
 8076|       |#ifdef ADA_REGULAR_VISUAL_STUDIO
 8077|       |  unsigned long ret;
 8078|       |  // Search the mask data from least significant bit (LSB)
 8079|       |  // to the most significant bit (MSB) for a set bit (1).
 8080|       |  _BitScanForward(&ret, input_num);
 8081|       |  return (int)ret;
 8082|       |#else   // ADA_REGULAR_VISUAL_STUDIO
 8083|   135k|  return __builtin_ctzl(input_num);
 8084|   135k|#endif  // ADA_REGULAR_VISUAL_STUDIO
 8085|   135k|}
_ZN3ada7helpers24find_next_host_delimiterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEm:
 8511|  1.53k|                                                  size_t location) noexcept {
 8512|       |  // first check for short strings in which case we do it naively.
 8513|  1.53k|  if (view.size() - location < 16) {  // slow path
  ------------------
  |  Branch (8513:7): [True: 422, False: 1.11k]
  ------------------
 8514|  2.62k|    for (size_t i = location; i < view.size(); i++) {
  ------------------
  |  Branch (8514:31): [True: 2.52k, False: 100]
  ------------------
 8515|  2.52k|      if (view[i] == ':' || view[i] == '/' || view[i] == '?' ||
  ------------------
  |  Branch (8515:11): [True: 70, False: 2.45k]
  |  Branch (8515:29): [True: 130, False: 2.32k]
  |  Branch (8515:47): [True: 70, False: 2.25k]
  ------------------
 8516|  2.25k|          view[i] == '[') {
  ------------------
  |  Branch (8516:11): [True: 52, False: 2.20k]
  ------------------
 8517|    322|        return i;
 8518|    322|      }
 8519|  2.52k|    }
 8520|    100|    return size_t(view.size());
 8521|    422|  }
 8522|       |  // fast path for long strings (expected to be common)
 8523|  1.11k|  size_t i = location;
 8524|  1.11k|  const __m128i mask1 = _mm_set1_epi8(':');
 8525|  1.11k|  const __m128i mask2 = _mm_set1_epi8('/');
 8526|  1.11k|  const __m128i mask4 = _mm_set1_epi8('?');
 8527|  1.11k|  const __m128i mask5 = _mm_set1_epi8('[');
 8528|       |
 8529|  1.64k|  for (; i + 15 < view.size(); i += 16) {
  ------------------
  |  Branch (8529:10): [True: 1.45k, False: 190]
  ------------------
 8530|  1.45k|    __m128i word = _mm_loadu_si128((const __m128i*)(view.data() + i));
 8531|  1.45k|    __m128i m1 = _mm_cmpeq_epi8(word, mask1);
 8532|  1.45k|    __m128i m2 = _mm_cmpeq_epi8(word, mask2);
 8533|  1.45k|    __m128i m4 = _mm_cmpeq_epi8(word, mask4);
 8534|  1.45k|    __m128i m5 = _mm_cmpeq_epi8(word, mask5);
 8535|  1.45k|    __m128i m = _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m4, m5));
 8536|  1.45k|    int mask = _mm_movemask_epi8(m);
 8537|  1.45k|    if (mask != 0) {
  ------------------
  |  Branch (8537:9): [True: 924, False: 534]
  ------------------
 8538|    924|      return i + trailing_zeroes(mask);
 8539|    924|    }
 8540|  1.45k|  }
 8541|    190|  if (i < view.size()) {
  ------------------
  |  Branch (8541:7): [True: 170, False: 20]
  ------------------
 8542|    170|    __m128i word =
 8543|    170|        _mm_loadu_si128((const __m128i*)(view.data() + view.length() - 16));
 8544|    170|    __m128i m1 = _mm_cmpeq_epi8(word, mask1);
 8545|    170|    __m128i m2 = _mm_cmpeq_epi8(word, mask2);
 8546|    170|    __m128i m4 = _mm_cmpeq_epi8(word, mask4);
 8547|    170|    __m128i m5 = _mm_cmpeq_epi8(word, mask5);
 8548|    170|    __m128i m = _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m4, m5));
 8549|    170|    int mask = _mm_movemask_epi8(m);
 8550|    170|    if (mask != 0) {
  ------------------
  |  Branch (8550:9): [True: 138, False: 32]
  ------------------
 8551|    138|      return view.length() - 16 + trailing_zeroes(mask);
 8552|    138|    }
 8553|    170|  }
 8554|     52|  return size_t(view.length());
 8555|    190|}
_ZN3ada3url10parse_hostENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9490|   159k|ada_really_inline bool url::parse_host(std::string_view input) {
 9491|   159k|  ada_log("parse_host ", input, " [", input.size(), " bytes]");
 9492|   159k|  if (input.empty()) {
  ------------------
  |  Branch (9492:7): [True: 7, False: 159k]
  ------------------
 9493|      7|    return is_valid = false;
 9494|      7|  }  // technically unnecessary.
 9495|       |  // If input starts with U+005B ([), then:
 9496|   159k|  if (input[0] == '[') {
  ------------------
  |  Branch (9496:7): [True: 720, False: 158k]
  ------------------
 9497|       |    // If input does not end with U+005D (]), validation error, return failure.
 9498|    720|    if (input.back() != ']') {
  ------------------
  |  Branch (9498:9): [True: 105, False: 615]
  ------------------
 9499|    105|      return is_valid = false;
 9500|    105|    }
 9501|    615|    ada_log("parse_host ipv6");
 9502|       |
 9503|       |    // Return the result of IPv6 parsing input with its leading U+005B ([) and
 9504|       |    // trailing U+005D (]) removed.
 9505|    615|    input.remove_prefix(1);
 9506|    615|    input.remove_suffix(1);
 9507|    615|    return parse_ipv6(input);
 9508|    720|  }
 9509|       |
 9510|       |  // If isNotSpecial is true, then return the result of opaque-host parsing
 9511|       |  // input.
 9512|   158k|  if (!is_special()) {
  ------------------
  |  Branch (9512:7): [True: 600, False: 157k]
  ------------------
 9513|    600|    return parse_opaque_host(input);
 9514|    600|  }
 9515|       |
 9516|       |  // Fast path: try to parse as pure decimal IPv4(a.b.c.d) first.
 9517|   157k|  const uint64_t fast_result = checkers::try_parse_ipv4_fast(input);
 9518|   157k|  if (fast_result < checkers::ipv4_fast_fail) {
  ------------------
  |  Branch (9518:7): [True: 38.1k, False: 119k]
  ------------------
 9519|       |    // Fast path succeeded - input is pure decimal IPv4
 9520|  38.1k|    if (!input.empty() && input.back() == '.') {
  ------------------
  |  Branch (9520:9): [True: 38.1k, False: 0]
  |  Branch (9520:27): [True: 7, False: 38.1k]
  ------------------
 9521|      7|      host = input.substr(0, input.size() - 1);
 9522|  38.1k|    } else {
 9523|  38.1k|      host = input;
 9524|  38.1k|    }
 9525|  38.1k|    host_type = IPV4;
 9526|  38.1k|    is_valid = true;
 9527|  38.1k|    ada_log("parse_host fast path decimal ipv4");
 9528|  38.1k|    return true;
 9529|  38.1k|  }
 9530|       |  // Let domain be the result of running UTF-8 decode without BOM on the
 9531|       |  // percent-decoding of input. Let asciiDomain be the result of running domain
 9532|       |  // to ASCII with domain and false. The most common case is an ASCII input, in
 9533|       |  // which case we do not need to call the expensive 'to_ascii' if a few
 9534|       |  // conditions are met: no '%' and no 'xn-' subsequence.
 9535|   119k|  std::string buffer = std::string(input);
 9536|       |  // This next function checks that the result is ascii, but we are going to
 9537|       |  // to check anyhow with is_forbidden.
 9538|       |  // bool is_ascii =
 9539|   119k|  unicode::to_lower_ascii(buffer.data(), buffer.size());
 9540|   119k|  bool is_forbidden = unicode::contains_forbidden_domain_code_point(
 9541|   119k|      buffer.data(), buffer.size());
 9542|   119k|  static constexpr std::string_view xn_dash{"xn-", 3};
 9543|   119k|  if (is_forbidden == 0 && buffer.find(xn_dash) == std::string_view::npos) {
  ------------------
  |  Branch (9543:7): [True: 116k, False: 2.92k]
  |  Branch (9543:28): [True: 71.6k, False: 45.0k]
  ------------------
 9544|       |    // fast path
 9545|  71.6k|    host = std::move(buffer);
 9546|       |
 9547|       |    // Check for other IPv4 formats (hex, octal, etc.)
 9548|  71.6k|    if (checkers::is_ipv4(host.value())) {
  ------------------
  |  Branch (9548:9): [True: 8.54k, False: 63.0k]
  ------------------
 9549|  8.54k|      ada_log("parse_host fast path ipv4");
 9550|  8.54k|      return parse_ipv4(host.value());
 9551|  8.54k|    }
 9552|  63.0k|    ada_log("parse_host fast path ", *host);
 9553|  63.0k|    is_valid = true;
 9554|  63.0k|    return true;
 9555|  71.6k|  }
 9556|  47.9k|  ada_log("parse_host calling to_ascii");
 9557|  47.9k|  is_valid = ada::unicode::to_ascii(host, input, input.find('%'));
 9558|  47.9k|  if (!is_valid || !host.has_value()) {
  ------------------
  |  Branch (9558:7): [True: 1.75k, False: 46.1k]
  |  Branch (9558:20): [True: 0, False: 46.1k]
  ------------------
 9559|  1.75k|    ada_log("parse_host to_ascii returns false");
 9560|  1.75k|    return is_valid = false;
 9561|  1.75k|  }
 9562|  46.1k|  ada_log("parse_host to_ascii succeeded ", *host, " [", host->size(),
 9563|  46.1k|          " bytes]");
 9564|       |
 9565|  46.1k|  if (std::any_of(host->begin(), host->end(),
  ------------------
  |  Branch (9565:7): [True: 0, False: 46.1k]
  ------------------
 9566|  46.1k|                  ada::unicode::is_forbidden_domain_code_point)) {
 9567|      0|    host = std::nullopt;
 9568|      0|    return is_valid = false;
 9569|      0|  }
 9570|       |
 9571|       |  // If asciiDomain ends in a number, then return the result of IPv4 parsing
 9572|       |  // asciiDomain.
 9573|  46.1k|  if (checkers::is_ipv4(*host)) {
  ------------------
  |  Branch (9573:7): [True: 86, False: 46.0k]
  ------------------
 9574|     86|    ada_log("parse_host got ipv4 ", *host);
 9575|     86|    return parse_ipv4(*host);
 9576|     86|  }
 9577|       |
 9578|  46.0k|  return true;
 9579|  46.1k|}
_ZN3ada7unicode30is_forbidden_domain_code_pointEc:
 6993|  1.33M|    const char c) noexcept {
 6994|  1.33M|  return is_forbidden_domain_code_point_table[uint8_t(c)];
 6995|  1.33M|}
_ZN3ada7unicode14percent_encodeILb1EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKhRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEE:
 7308|  20.1k|                    std::string& out) {
 7309|  20.1k|  ada_log("percent_encode ", input, " to output string while ",
 7310|  20.1k|          append ? "appending" : "overwriting");
 7311|  20.1k|  auto pointer = std::ranges::find_if(input, [character_set](const char c) {
 7312|  20.1k|    return character_sets::bit_at(character_set, c);
 7313|  20.1k|  });
 7314|  20.1k|  ada_log("percent_encode done checking, moved to ",
 7315|  20.1k|          std::distance(input.begin(), pointer));
 7316|       |
 7317|       |  // Optimization: Don't iterate if percent encode is not required
 7318|  20.1k|  if (pointer == input.end()) {
  ------------------
  |  Branch (7318:7): [True: 19.7k, False: 341]
  ------------------
 7319|  19.7k|    ada_log("percent_encode encoding not needed.");
 7320|  19.7k|    return false;
 7321|  19.7k|  }
 7322|       |  if constexpr (!append) {
 7323|       |    out.clear();
 7324|       |  }
 7325|    341|  ada_log("percent_encode appending ", std::distance(input.begin(), pointer),
 7326|    341|          " bytes");
 7327|       |  // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage)
 7328|    341|  out.append(input.data(), std::distance(input.begin(), pointer));
 7329|    341|  ada_log("percent_encode processing ", std::distance(pointer, input.end()),
 7330|    341|          " bytes");
 7331|  22.9k|  for (; pointer != input.end(); pointer++) {
  ------------------
  |  Branch (7331:10): [True: 22.6k, False: 341]
  ------------------
 7332|  22.6k|    if (character_sets::bit_at(character_set, *pointer)) {
  ------------------
  |  Branch (7332:9): [True: 16.0k, False: 6.58k]
  ------------------
 7333|  16.0k|      out.append(character_sets::hex + uint8_t(*pointer) * 4, 3);
 7334|  16.0k|    } else {
 7335|  6.58k|      out += *pointer;
 7336|  6.58k|    }
 7337|  22.6k|  }
 7338|    341|  return true;
 7339|  20.1k|}
_ZZN3ada7unicode14percent_encodeILb1EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKhRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEEENKUlcE_clEc:
 7311|   215k|  auto pointer = std::ranges::find_if(input, [character_set](const char c) {
 7312|   215k|    return character_sets::bit_at(character_set, c);
 7313|   215k|  });
simple_absolute.cc:_ZN12_GLOBAL__N_132apply_shifted_non_scheme_offsetsERN3ada14url_componentsEj:
11430|   160k|    ada::url_components& components, uint32_t new_difference) {
11431|   160k|  components.username_end += new_difference;
11432|   160k|  components.host_start += new_difference;
11433|   160k|  components.host_end += new_difference;
11434|   160k|  components.pathname_start += new_difference;
11435|   160k|  if (components.search_start != ada::url_components::omitted) {
  ------------------
  |  Branch (11435:7): [True: 0, False: 160k]
  ------------------
11436|      0|    components.search_start += new_difference;
11437|      0|  }
11438|   160k|  if (components.hash_start != ada::url_components::omitted) {
  ------------------
  |  Branch (11438:7): [True: 0, False: 160k]
  ------------------
11439|      0|    components.hash_start += new_difference;
11440|      0|  }
11441|   160k|}
_ZN3ada14url_aggregator10parse_hostENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11890|   159k|ada_really_inline bool url_aggregator::parse_host(std::string_view input) {
11891|   159k|  ada_log("url_aggregator:parse_host \"", input, "\" [", input.size(),
11892|   159k|          " bytes]");
11893|   159k|  ADA_ASSERT_TRUE(validate());
11894|   159k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
11895|   159k|  if (input.empty()) {
  ------------------
  |  Branch (11895:7): [True: 7, False: 159k]
  ------------------
11896|      7|    return is_valid = false;
11897|      7|  }  // technically unnecessary.
11898|       |  // If input starts with U+005B ([), then:
11899|   159k|  if (input[0] == '[') {
  ------------------
  |  Branch (11899:7): [True: 720, False: 158k]
  ------------------
11900|       |    // If input does not end with U+005D (]), validation error, return failure.
11901|    720|    if (input.back() != ']') {
  ------------------
  |  Branch (11901:9): [True: 105, False: 615]
  ------------------
11902|    105|      return is_valid = false;
11903|    105|    }
11904|    615|    ada_log("parse_host ipv6");
11905|       |
11906|       |    // Return the result of IPv6 parsing input with its leading U+005B ([) and
11907|       |    // trailing U+005D (]) removed.
11908|    615|    input.remove_prefix(1);
11909|    615|    input.remove_suffix(1);
11910|    615|    return parse_ipv6(input);
11911|    720|  }
11912|       |
11913|       |  // If isNotSpecial is true, then return the result of opaque-host parsing
11914|       |  // input.
11915|   158k|  if (!is_special()) {
  ------------------
  |  Branch (11915:7): [True: 600, False: 157k]
  ------------------
11916|    600|    return parse_opaque_host(input);
11917|    600|  }
11918|       |  // Let domain be the result of running UTF-8 decode without BOM on the
11919|       |  // percent-decoding of input. Let asciiDomain be the result of running domain
11920|       |  // to ASCII with domain and false. The most common case is an ASCII input, in
11921|       |  // which case we do not need to call the expensive 'to_ascii' if a few
11922|       |  // conditions are met: no '%' and no 'xn-' subsequence.
11923|       |
11924|       |  // Often, the input does not contain any forbidden code points, and no upper
11925|       |  // case ASCII letter, then we can just copy it to the buffer. We want to
11926|       |  // optimize for such a common case.
11927|       |
11928|       |  // Fast path: try to parse as pure decimal IPv4(a.b.c.d) first.
11929|   157k|  const uint64_t fast_result = checkers::try_parse_ipv4_fast(input);
11930|   157k|  if (fast_result < checkers::ipv4_fast_fail) {
  ------------------
  |  Branch (11930:7): [True: 38.1k, False: 119k]
  ------------------
11931|       |    // Fast path succeeded - input is pure decimal IPv4
11932|  38.1k|    if (!input.empty() && input.back() == '.') {
  ------------------
  |  Branch (11932:9): [True: 38.1k, False: 0]
  |  Branch (11932:27): [True: 7, False: 38.1k]
  ------------------
11933|      7|      update_base_hostname(input.substr(0, input.size() - 1));
11934|  38.1k|    } else {
11935|  38.1k|      update_base_hostname(input);
11936|  38.1k|    }
11937|  38.1k|    host_type = IPV4;
11938|  38.1k|    is_valid = true;
11939|  38.1k|    ada_log("parse_host fast path decimal ipv4");
11940|  38.1k|    ADA_ASSERT_TRUE(validate());
11941|  38.1k|    return true;
11942|  38.1k|  }
11943|   119k|  uint8_t is_forbidden_or_upper =
11944|   119k|      unicode::contains_forbidden_domain_code_point_or_upper(input.data(),
11945|   119k|                                                             input.size());
11946|       |  // Minor optimization opportunity:
11947|       |  // contains_forbidden_domain_code_point_or_upper could be extend to check for
11948|       |  // the presence of characters that cannot appear in the ipv4 address and we
11949|       |  // could also check whether x and n and - are present, and so we could skip
11950|       |  // some of the checks below. However, the gains are likely to be small, and
11951|       |  // the code would be more complex.
11952|   119k|  static constexpr std::string_view xn_dash{"xn-", 3};
11953|   119k|  if (is_forbidden_or_upper == 0 &&
  ------------------
  |  Branch (11953:7): [True: 115k, False: 3.65k]
  ------------------
11954|   115k|      input.find(xn_dash) == std::string_view::npos) {
  ------------------
  |  Branch (11954:7): [True: 71.1k, False: 44.7k]
  ------------------
11955|       |    // fast path
11956|  71.1k|    update_base_hostname(input);
11957|       |
11958|       |    // Check for other IPv4 formats (hex, octal, etc.)
11959|  71.1k|    if (checkers::is_ipv4(get_hostname())) {
  ------------------
  |  Branch (11959:9): [True: 8.47k, False: 62.6k]
  ------------------
11960|  8.47k|      ada_log("parse_host fast path ipv4");
11961|  8.47k|      return parse_ipv4(get_hostname(), true);
11962|  8.47k|    }
11963|  62.6k|    ada_log("parse_host fast path ", get_hostname());
11964|  62.6k|    is_valid = true;
11965|  62.6k|    return true;
11966|  71.1k|  }
11967|       |  // We have encountered at least one forbidden code point or the input contains
11968|       |  // 'xn-' (case insensitive), so we need to call 'to_ascii' to perform the full
11969|       |  // conversion.
11970|       |
11971|  48.4k|  ada_log("parse_host calling to_ascii");
11972|  48.4k|  std::optional<std::string> host = std::string(get_hostname());
11973|  48.4k|  is_valid = ada::unicode::to_ascii(host, input, input.find('%'));
11974|  48.4k|  if (!is_valid) {
  ------------------
  |  Branch (11974:7): [True: 1.75k, False: 46.6k]
  ------------------
11975|  1.75k|    ada_log("parse_host to_ascii returns false");
11976|  1.75k|    return is_valid = false;
11977|  1.75k|  }
11978|  46.6k|  ada_log("parse_host to_ascii succeeded ", *host, " [", host->size(),
11979|  46.6k|          " bytes]");
11980|       |
11981|  46.6k|  if (std::ranges::any_of(host.value(),
  ------------------
  |  Branch (11981:7): [True: 0, False: 46.6k]
  ------------------
11982|  46.6k|                          ada::unicode::is_forbidden_domain_code_point)) {
11983|      0|    return is_valid = false;
11984|      0|  }
11985|       |
11986|       |  // If asciiDomain ends in a number, then return the result of IPv4 parsing
11987|       |  // asciiDomain.
11988|  46.6k|  if (checkers::is_ipv4(host.value())) {
  ------------------
  |  Branch (11988:7): [True: 158, False: 46.5k]
  ------------------
11989|    158|    ada_log("parse_host got ipv4 ", *host);
11990|    158|    return parse_ipv4(host.value(), false);
11991|    158|  }
11992|       |
11993|  46.5k|  update_base_hostname(host.value());
11994|  46.5k|  ADA_ASSERT_TRUE(validate());
11995|  46.5k|  return true;
11996|  46.6k|}
_ZN3ada7unicode45contains_forbidden_domain_code_point_or_upperEPKcm:
 7034|   119k|                                              size_t length) noexcept {
 7035|   119k|  size_t i = 0;
 7036|   119k|  uint8_t accumulator{};
 7037|   425k|  for (; i + 4 <= length; i += 4) {
  ------------------
  |  Branch (7037:10): [True: 305k, False: 119k]
  ------------------
 7038|   305k|    accumulator |=
 7039|   305k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i])];
 7040|   305k|    accumulator |=
 7041|   305k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 1])];
 7042|   305k|    accumulator |=
 7043|   305k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 2])];
 7044|   305k|    accumulator |=
 7045|   305k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 3])];
 7046|   305k|  }
 7047|   348k|  for (; i < length; i++) {
  ------------------
  |  Branch (7047:10): [True: 228k, False: 119k]
  ------------------
 7048|   228k|    accumulator |=
 7049|   228k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i])];
 7050|   228k|  }
 7051|   119k|  return accumulator;
 7052|   119k|}
_ZN3ada7helpers9substringENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEm:
 8061|  16.8k|                                                       size_t pos) {
 8062|  16.8k|  ADA_ASSERT_TRUE(pos <= input.size());
 8063|       |  // The following is safer but unneeded if we have the above line:
 8064|       |  // return pos > input.size() ? std::string_view() : input.substr(pos);
 8065|  16.8k|  return input.substr(pos);
 8066|  16.8k|}
_ZN3ada14url_aggregator21consume_prepared_pathENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
12803|   155k|inline void url_aggregator::consume_prepared_path(std::string_view input) {
12804|   155k|  ada_log("url_aggregator::consume_prepared_path ", input);
12805|       |  /***
12806|       |   * This is largely duplicated code from helpers::parse_prepared_path, which is
12807|       |   * unfortunate. This particular function is nearly identical, except that it
12808|       |   * is a method on url_aggregator. The idea is that the trivial path (which is
12809|       |   * very common) merely appends to the buffer. This is the same trivial path as
12810|       |   * with helpers::parse_prepared_path, except that we have the additional check
12811|       |   * for is_at_path(). Otherwise, we grab a copy of the current path and we
12812|       |   * modify it, and then insert it back into the buffer.
12813|       |   */
12814|   155k|  uint8_t accumulator = checkers::path_signature(input);
12815|       |  // Let us first detect a trivial case.
12816|       |  // If it is special, we check that we have no dot, no %,  no \ and no
12817|       |  // character needing percent encoding. Otherwise, we check that we have no %,
12818|       |  // no dot, and no character needing percent encoding.
12819|   155k|  constexpr uint8_t need_encoding = 1;
12820|   155k|  constexpr uint8_t backslash_char = 2;
12821|   155k|  constexpr uint8_t dot_char = 4;
12822|   155k|  constexpr uint8_t percent_char = 8;
12823|   155k|  bool special = type != ada::scheme::NOT_SPECIAL;
12824|   155k|  bool may_need_slow_file_handling = (type == ada::scheme::type::FILE &&
  ------------------
  |  Branch (12824:39): [True: 1.18k, False: 153k]
  ------------------
12825|  1.18k|                                      checkers::is_windows_drive_letter(input));
  ------------------
  |  Branch (12825:39): [True: 40, False: 1.14k]
  ------------------
12826|   155k|  bool trivial_path =
12827|   155k|      (special ? (accumulator == 0)
  ------------------
  |  Branch (12827:7): [True: 133k, False: 21.3k]
  |  Branch (12827:8): [True: 154k, False: 732]
  ------------------
12828|   155k|               : ((accumulator & (need_encoding | dot_char | percent_char)) ==
12829|    732|                  0)) &&
12830|   133k|      (!may_need_slow_file_handling);
  ------------------
  |  Branch (12830:7): [True: 133k, False: 13]
  ------------------
12831|   155k|  if (accumulator == dot_char && !may_need_slow_file_handling) {
  ------------------
  |  Branch (12831:7): [True: 9.53k, False: 145k]
  |  Branch (12831:34): [True: 9.51k, False: 17]
  ------------------
12832|       |    // '4' means that we have at least one dot, but nothing that requires
12833|       |    // percent encoding or decoding. The only part that is not trivial is
12834|       |    // that we may have single dots and double dots path segments.
12835|       |    // If we have such segments, then we either have a path that begins
12836|       |    // with '.' (easy to check), or we have the sequence './'.
12837|       |    // Note: input cannot be empty, it must at least contain one character ('.')
12838|       |    // Note: we know that '\' is not present.
12839|  9.51k|    if (input[0] != '.') {
  ------------------
  |  Branch (12839:9): [True: 8.53k, False: 980]
  ------------------
12840|  8.53k|      size_t slashdot = 0;
12841|  8.53k|      bool dot_is_file = true;
12842|  25.5k|      for (;;) {
12843|  25.5k|        slashdot = input.find("/.", slashdot);
12844|  25.5k|        if (slashdot == std::string_view::npos) {  // common case
  ------------------
  |  Branch (12844:13): [True: 8.53k, False: 16.9k]
  ------------------
12845|  8.53k|          break;
12846|  16.9k|        } else {  // uncommon
12847|       |          // only three cases matter: /./, /.. or a final /
12848|  16.9k|          slashdot += 2;
12849|  16.9k|          dot_is_file &= !(slashdot == input.size() || input[slashdot] == '.' ||
  ------------------
  |  Branch (12849:28): [True: 30, False: 16.9k]
  |  Branch (12849:56): [True: 8.41k, False: 8.52k]
  ------------------
12850|  8.52k|                           input[slashdot] == '/');
  ------------------
  |  Branch (12850:28): [True: 7.31k, False: 1.21k]
  ------------------
12851|  16.9k|        }
12852|  25.5k|      }
12853|  8.53k|      trivial_path = dot_is_file;
12854|  8.53k|    }
12855|  9.51k|  }
12856|   155k|  if (trivial_path && is_at_path()) {
  ------------------
  |  Branch (12856:7): [True: 134k, False: 20.3k]
  |  Branch (12856:23): [True: 134k, False: 0]
  ------------------
12857|   134k|    ada_log("parse_path trivial");
12858|   134k|    buffer += '/';
12859|   134k|    buffer += input;
12860|   134k|    return;
12861|   134k|  }
12862|  20.3k|  std::string path = std::string(get_pathname());
12863|       |  // We are going to need to look a bit at the path, but let us see if we can
12864|       |  // ignore percent encoding *and* backslashes *and* percent characters.
12865|       |  // Except for the trivial case, this is likely to capture 99% of paths out
12866|       |  // there.
12867|  20.3k|  bool fast_path =
12868|  20.3k|      (special &&
  ------------------
  |  Branch (12868:8): [True: 19.9k, False: 387]
  ------------------
12869|  19.9k|       (accumulator & (need_encoding | backslash_char | percent_char)) == 0) &&
  ------------------
  |  Branch (12869:8): [True: 8.46k, False: 11.5k]
  ------------------
12870|  8.46k|      (type != ada::scheme::type::FILE);
  ------------------
  |  Branch (12870:7): [True: 8.36k, False: 103]
  ------------------
12871|  20.3k|  if (fast_path) {
  ------------------
  |  Branch (12871:7): [True: 8.36k, False: 12.0k]
  ------------------
12872|  8.36k|    ada_log("parse_prepared_path fast");
12873|       |    // Here we don't need to worry about \ or percent encoding.
12874|       |    // We also do not have a file protocol. We might have dots, however,
12875|       |    // but dots must as appear as '.', and they cannot be encoded because
12876|       |    // the symbol '%' is not present.
12877|  8.36k|    size_t previous_location = 0;  // We start at 0.
12878|  49.2k|    do {
12879|  49.2k|      size_t new_location = input.find('/', previous_location);
12880|       |      // std::string_view path_view = input;
12881|       |      //  We process the last segment separately:
12882|  49.2k|      if (new_location == std::string_view::npos) {
  ------------------
  |  Branch (12882:11): [True: 8.36k, False: 40.8k]
  ------------------
12883|  8.36k|        std::string_view path_view = input.substr(previous_location);
12884|  8.36k|        if (path_view == "..") {  // The path ends with ..
  ------------------
  |  Branch (12884:13): [True: 34, False: 8.33k]
  ------------------
12885|       |          // e.g., if you receive ".." with an empty path, you go to "/".
12886|     34|          if (path.empty()) {
  ------------------
  |  Branch (12886:15): [True: 6, False: 28]
  ------------------
12887|      6|            path = '/';
12888|      6|            update_base_pathname(path);
12889|      6|            return;
12890|      6|          }
12891|       |          // Fast case where we have nothing to do:
12892|     28|          if (path.back() == '/') {
  ------------------
  |  Branch (12892:15): [True: 9, False: 19]
  ------------------
12893|      9|            update_base_pathname(path);
12894|      9|            return;
12895|      9|          }
12896|       |          // If you have the path "/joe/myfriend",
12897|       |          // then you delete 'myfriend'.
12898|     19|          path.resize(path.rfind('/') + 1);
12899|     19|          update_base_pathname(path);
12900|     19|          return;
12901|     28|        }
12902|  8.33k|        path += '/';
12903|  8.33k|        if (path_view != ".") {
  ------------------
  |  Branch (12903:13): [True: 8.28k, False: 46]
  ------------------
12904|  8.28k|          path.append(path_view);
12905|  8.28k|        }
12906|  8.33k|        update_base_pathname(path);
12907|  8.33k|        return;
12908|  40.8k|      } else {
12909|       |        // This is a non-final segment.
12910|  40.8k|        std::string_view path_view =
12911|  40.8k|            input.substr(previous_location, new_location - previous_location);
12912|  40.8k|        previous_location = new_location + 1;
12913|  40.8k|        if (path_view == "..") {
  ------------------
  |  Branch (12913:13): [True: 8.24k, False: 32.5k]
  ------------------
12914|  8.24k|          size_t last_delimiter = path.rfind('/');
12915|  8.24k|          if (last_delimiter != std::string::npos) {
  ------------------
  |  Branch (12915:15): [True: 7.38k, False: 863]
  ------------------
12916|  7.38k|            path.erase(last_delimiter);
12917|  7.38k|          }
12918|  32.5k|        } else if (path_view != ".") {
  ------------------
  |  Branch (12918:20): [True: 24.4k, False: 8.18k]
  ------------------
12919|  24.4k|          path += '/';
12920|  24.4k|          path.append(path_view);
12921|  24.4k|        }
12922|  40.8k|      }
12923|  49.2k|    } while (true);
  ------------------
  |  Branch (12923:14): [True: 40.8k, Folded]
  ------------------
12924|  12.0k|  } else {
12925|  12.0k|    ada_log("parse_path slow");
12926|       |    // we have reached the general case
12927|  12.0k|    bool needs_percent_encoding = (accumulator & 1);
12928|  12.0k|    std::string path_buffer_tmp;
12929|  37.0k|    do {
12930|  37.0k|      size_t location = (special && (accumulator & 2))
  ------------------
  |  Branch (12930:26): [True: 35.5k, False: 1.49k]
  |  Branch (12930:37): [True: 2.48k, False: 33.0k]
  ------------------
12931|  37.0k|                            ? input.find_first_of("/\\")
12932|  37.0k|                            : input.find('/');
12933|  37.0k|      std::string_view path_view = input;
12934|  37.0k|      if (location != std::string_view::npos) {
  ------------------
  |  Branch (12934:11): [True: 25.0k, False: 12.0k]
  ------------------
12935|  25.0k|        path_view.remove_suffix(path_view.size() - location);
12936|  25.0k|        input.remove_prefix(location + 1);
12937|  25.0k|      }
12938|       |      // path_buffer is either path_view or it might point at a percent encoded
12939|       |      // temporary string.
12940|  37.0k|      std::string_view path_buffer =
12941|  37.0k|          (needs_percent_encoding &&
  ------------------
  |  Branch (12941:12): [True: 6.39k, False: 30.6k]
  ------------------
12942|  6.39k|           ada::unicode::percent_encode<false>(
  ------------------
  |  Branch (12942:12): [True: 2.44k, False: 3.94k]
  ------------------
12943|  6.39k|               path_view, character_sets::PATH_PERCENT_ENCODE, path_buffer_tmp))
12944|  37.0k|              ? path_buffer_tmp
12945|  37.0k|              : path_view;
12946|  37.0k|      if (unicode::is_double_dot_path_segment(path_buffer)) {
  ------------------
  |  Branch (12946:11): [True: 8.42k, False: 28.6k]
  ------------------
12947|  8.42k|        helpers::shorten_path(path, type);
12948|  8.42k|        if (location == std::string_view::npos) {
  ------------------
  |  Branch (12948:13): [True: 7.12k, False: 1.29k]
  ------------------
12949|  7.12k|          path += '/';
12950|  7.12k|        }
12951|  28.6k|      } else if (unicode::is_single_dot_path_segment(path_buffer) &&
  ------------------
  |  Branch (12951:18): [True: 1.07k, False: 27.5k]
  ------------------
12952|  1.07k|                 (location == std::string_view::npos)) {
  ------------------
  |  Branch (12952:18): [True: 374, False: 701]
  ------------------
12953|    374|        path += '/';
12954|    374|      }
12955|       |      // Otherwise, if path_buffer is not a single-dot path segment, then:
12956|  28.2k|      else if (!unicode::is_single_dot_path_segment(path_buffer)) {
  ------------------
  |  Branch (12956:16): [True: 27.5k, False: 701]
  ------------------
12957|       |        // If url's scheme is "file", url's path is empty, and path_buffer is a
12958|       |        // Windows drive letter, then replace the second code point in
12959|       |        // path_buffer with U+003A (:).
12960|  27.5k|        if (type == ada::scheme::type::FILE && path.empty() &&
  ------------------
  |  Branch (12960:13): [True: 1.80k, False: 25.7k]
  |  Branch (12960:48): [True: 524, False: 1.27k]
  ------------------
12961|    524|            checkers::is_windows_drive_letter(path_buffer)) {
  ------------------
  |  Branch (12961:13): [True: 42, False: 482]
  ------------------
12962|     42|          path += '/';
12963|     42|          path += path_buffer[0];
12964|     42|          path += ':';
12965|     42|          path_buffer.remove_prefix(2);
12966|     42|          path.append(path_buffer);
12967|  27.4k|        } else {
12968|       |          // Append path_buffer to url's path.
12969|  27.4k|          path += '/';
12970|  27.4k|          path.append(path_buffer);
12971|  27.4k|        }
12972|  27.5k|      }
12973|  37.0k|      if (location == std::string_view::npos) {
  ------------------
  |  Branch (12973:11): [True: 12.0k, False: 25.0k]
  ------------------
12974|  12.0k|        update_base_pathname(path);
12975|  12.0k|        return;
12976|  12.0k|      }
12977|  37.0k|    } while (true);
  ------------------
  |  Branch (12977:14): [True: 25.0k, Folded]
  ------------------
12978|  12.0k|  }
12979|  20.3k|}
_ZN3ada7unicode14to_lower_asciiEPcm:
 6750|   156k|constexpr bool to_lower_ascii(char* input, size_t length) noexcept {
 6751|   156k|  uint64_t broadcast_80 = broadcast(0x80);
 6752|   156k|  uint64_t broadcast_Ap = broadcast(128 - 'A');
 6753|   156k|  uint64_t broadcast_Zp = broadcast(128 - 'Z' - 1);
 6754|   156k|  uint64_t non_ascii = 0;
 6755|   156k|  size_t i = 0;
 6756|       |
 6757|   320k|  for (; i + 7 < length; i += 8) {
  ------------------
  |  Branch (6757:10): [True: 164k, False: 156k]
  ------------------
 6758|   164k|    uint64_t word{};
 6759|   164k|    memcpy(&word, input + i, sizeof(word));
 6760|   164k|    non_ascii |= (word & broadcast_80);
 6761|   164k|    word ^=
 6762|   164k|        (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
 6763|   164k|    memcpy(input + i, &word, sizeof(word));
 6764|   164k|  }
 6765|   156k|  if (i < length) {
  ------------------
  |  Branch (6765:7): [True: 134k, False: 21.9k]
  ------------------
 6766|   134k|    uint64_t word{};
 6767|   134k|    memcpy(&word, input + i, length - i);
 6768|   134k|    non_ascii |= (word & broadcast_80);
 6769|   134k|    word ^=
 6770|   134k|        (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
 6771|   134k|    memcpy(input + i, &word, length - i);
 6772|   134k|  }
 6773|   156k|  return non_ascii == 0;
 6774|   156k|}
_ZN3ada7unicode9broadcastEh:
 6746|   468k|constexpr uint64_t broadcast(uint8_t v) noexcept {
 6747|   468k|  return 0x101010101010101ull * v;
 6748|   468k|}
_ZN3ada8checkers7is_ipv4ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
   12|   748k|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|       |  //
   15|       |  // Optimization. To be considered as a possible ipv4, the string must end
   16|       |  // with 'x' or a lowercase hex character.
   17|       |  // Most of the time, this will be false so this simple check will save a lot
   18|       |  // of effort.
   19|       |  // If the address ends with a dot, we need to prune it (special case).
   20|   748k|  if (view.ends_with('.')) {
  ------------------
  |  Branch (20:7): [True: 3.11k, False: 745k]
  ------------------
   21|  3.11k|    view.remove_suffix(1);
   22|  3.11k|    if (view.empty()) {
  ------------------
  |  Branch (22:9): [True: 1.70k, False: 1.40k]
  ------------------
   23|  1.70k|      return false;
   24|  1.70k|    }
   25|  3.11k|  }
   26|   746k|  char last_char = view.back();
   27|   746k|  bool possible_ipv4 = (last_char >= '0' && last_char <= '9') ||
  ------------------
  |  Branch (27:25): [True: 744k, False: 2.32k]
  |  Branch (27:45): [True: 18.3k, False: 726k]
  ------------------
   28|   728k|                       (last_char >= 'a' && last_char <= 'f') ||
  ------------------
  |  Branch (28:25): [True: 726k, False: 2.58k]
  |  Branch (28:45): [True: 97.6k, False: 628k]
  ------------------
   29|   630k|                       last_char == 'x';
  ------------------
  |  Branch (29:24): [True: 1.27k, False: 629k]
  ------------------
   30|   746k|  if (!possible_ipv4) {
  ------------------
  |  Branch (30:7): [True: 629k, False: 117k]
  ------------------
   31|   629k|    return false;
   32|   629k|  }
   33|       |  // From the last character, find the last dot.
   34|   117k|  size_t last_dot = view.rfind('.');
   35|   117k|  if (last_dot != std::string_view::npos) {
  ------------------
  |  Branch (35:7): [True: 20.4k, False: 96.8k]
  ------------------
   36|       |    // We have at least one dot.
   37|  20.4k|    view.remove_prefix(last_dot + 1);
   38|  20.4k|  }
   39|       |  /** Optimization opportunity: we have basically identified the last number of
   40|       |     the ipv4 if we return true here. We might as well parse it and have at
   41|       |     least one number parsed when we get to parse_ipv4. */
   42|   117k|  if (std::ranges::all_of(view, ada::checkers::is_digit)) {
  ------------------
  |  Branch (42:7): [True: 16.9k, False: 100k]
  ------------------
   43|  16.9k|    return true;
   44|  16.9k|  }
   45|       |  // It could be hex (0x), but not if there is a single character.
   46|   100k|  if (view.size() == 1) {
  ------------------
  |  Branch (46:7): [True: 5.29k, False: 95.0k]
  ------------------
   47|  5.29k|    return false;
   48|  5.29k|  }
   49|       |  // It must start with 0x.
   50|  95.0k|  if (!view.starts_with("0x")) {
  ------------------
  |  Branch (50:7): [True: 93.6k, False: 1.41k]
  ------------------
   51|  93.6k|    return false;
   52|  93.6k|  }
   53|       |  // We must allow "0x".
   54|  1.41k|  if (view.size() == 2) {
  ------------------
  |  Branch (54:7): [True: 82, False: 1.32k]
  ------------------
   55|     82|    return true;
   56|     82|  }
   57|       |  // We have 0x followed by some characters, we need to check that they are
   58|       |  // hexadecimals.
   59|  1.32k|  view.remove_prefix(2);
   60|  1.32k|  return std::ranges::all_of(view, ada::unicode::is_lowercase_hex);
   61|  1.41k|}
_ZN3ada7unicode16is_lowercase_hexEc:
 7153|  13.7k|ada_really_inline constexpr bool is_lowercase_hex(const char c) noexcept {
 7154|  13.7k|  return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f');
  ------------------
  |  Branch (7154:11): [True: 13.4k, False: 288]
  |  Branch (7154:23): [True: 5.64k, False: 7.78k]
  |  Branch (7154:37): [True: 7.72k, False: 342]
  |  Branch (7154:49): [True: 7.00k, False: 722]
  ------------------
 7155|  13.7k|}
_ZN3ada6parser25try_parse_simple_absoluteINS_3urlEEEbNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEERT_:
10106|   310k|                                                result_type& out) {
10107|   310k|  constexpr bool is_ada_url = std::is_same_v<result_type, ada::url>;
10108|   310k|  constexpr bool is_aggregator =
10109|   310k|      std::is_same_v<result_type, ada::url_aggregator>;
10110|   310k|  static_assert(is_ada_url || is_aggregator);
10111|       |
10112|   310k|  const size_t len = input.size();
10113|   310k|  if (len < 8) [[unlikely]] {
  ------------------
  |  Branch (10113:7): [True: 45, False: 310k]
  ------------------
10114|     45|    return false;
10115|     45|  }
10116|   310k|  const auto* b = reinterpret_cast<const uint8_t*>(input.data());
10117|       |
10118|   310k|  size_t pos;
10119|   310k|  ada::scheme::type scheme_type;
10120|   310k|  uint32_t protocol_end;
10121|   310k|  if (b[0] == 'h' && b[1] == 't' && b[2] == 't' && b[3] == 'p') {
  ------------------
  |  Branch (10121:7): [True: 306k, False: 3.61k]
  |  Branch (10121:22): [True: 306k, False: 80]
  |  Branch (10121:37): [True: 306k, False: 555]
  |  Branch (10121:52): [True: 305k, False: 46]
  ------------------
10122|   305k|    if (b[4] == ':' && b[5] == '/' && b[6] == '/') {
  ------------------
  |  Branch (10122:9): [True: 51.6k, False: 254k]
  |  Branch (10122:24): [True: 51.1k, False: 510]
  |  Branch (10122:39): [True: 51.0k, False: 72]
  ------------------
10123|  51.0k|      pos = 7;
10124|  51.0k|      scheme_type = ada::scheme::type::HTTP;
10125|  51.0k|      protocol_end = 5;
10126|   254k|    } else if (len >= 8 && b[4] == 's' && b[5] == ':' && b[6] == '/' &&
  ------------------
  |  Branch (10126:16): [True: 254k, False: 0]
  |  Branch (10126:28): [True: 254k, False: 633]
  |  Branch (10126:43): [True: 254k, False: 30]
  |  Branch (10126:58): [True: 253k, False: 591]
  ------------------
10127|   253k|               b[7] == '/') {
  ------------------
  |  Branch (10127:16): [True: 253k, False: 28]
  ------------------
10128|   253k|      pos = 8;
10129|   253k|      scheme_type = ada::scheme::type::HTTPS;
10130|   253k|      protocol_end = 6;
10131|   253k|    } else {
10132|  1.28k|      return false;
10133|  1.28k|    }
10134|   305k|  } else {
10135|  4.30k|    return false;
10136|  4.30k|  }
10137|   304k|  if (pos < len && (b[pos] == '/' || b[pos] == '\\')) [[unlikely]] {
  ------------------
  |  Branch (10137:7): [True: 304k, False: 1]
  |  Branch (10137:21): [True: 87, False: 304k]
  |  Branch (10137:38): [True: 33, False: 304k]
  ------------------
10138|    120|    return false;
10139|    120|  }
10140|       |
10141|       |  // Digit-led hosts are IPv4/numeric; skip before scanning.
10142|   304k|  if (pos < len && b[pos] >= '0' && b[pos] <= '9') {
  ------------------
  |  Branch (10142:7): [True: 304k, False: 1]
  |  Branch (10142:20): [True: 302k, False: 1.86k]
  |  Branch (10142:37): [True: 0, False: 302k]
  ------------------
10143|      0|    return false;
10144|      0|  }
10145|       |
10146|   304k|  const size_t host_start = pos;
10147|   304k|  bool has_upper = false;
10148|   304k|  size_t i = pos;
10149|  3.75M|  for (; i < len; ++i) {
  ------------------
  |  Branch (10149:10): [True: 3.74M, False: 7.10k]
  ------------------
10150|  3.74M|    const uint8_t c = b[i];
10151|  3.74M|    const uint8_t cls = k_host_class[c];
10152|  3.74M|    if (cls == 1) {
  ------------------
  |  Branch (10152:9): [True: 249k, False: 3.49M]
  ------------------
10153|   249k|      break;
10154|   249k|    }
10155|  3.49M|    if (cls == 2) [[unlikely]] {
  ------------------
  |  Branch (10155:9): [True: 47.9k, False: 3.44M]
  ------------------
10156|  47.9k|      return false;
10157|  47.9k|    }
10158|  3.44M|    if (c >= 'A' && c <= 'Z') {
  ------------------
  |  Branch (10158:9): [True: 2.97M, False: 478k]
  |  Branch (10158:21): [True: 53.7k, False: 2.91M]
  ------------------
10159|  53.7k|      has_upper = true;
10160|  53.7k|    }
10161|  3.44M|  }
10162|   256k|  const size_t host_end = i;
10163|   256k|  if (host_start == host_end) [[unlikely]] {
  ------------------
  |  Branch (10163:7): [True: 9, False: 256k]
  ------------------
10164|      9|    return false;
10165|      9|  }
10166|   256k|  const size_t host_len = host_end - host_start;
10167|   256k|  if (host_len > 253) [[unlikely]] {
  ------------------
  |  Branch (10167:7): [True: 125, False: 256k]
  ------------------
10168|    125|    return false;
10169|    125|  }
10170|   256k|  {
10171|   256k|    std::string_view hv(input.data() + host_start, host_len);
10172|   256k|    char host_buf[256];
10173|   256k|    if (has_upper) [[unlikely]] {
  ------------------
  |  Branch (10173:9): [True: 7.09k, False: 249k]
  ------------------
10174|  7.09k|      std::memcpy(host_buf, input.data() + host_start, host_len);
10175|  7.09k|      unicode::to_lower_ascii(host_buf, host_len);
10176|  7.09k|      hv = std::string_view(host_buf, host_len);
10177|  7.09k|    }
10178|   256k|    if (checkers::is_ipv4(hv)) [[unlikely]] {
  ------------------
  |  Branch (10178:9): [True: 30, False: 256k]
  ------------------
10179|     30|      return false;
10180|     30|    }
10181|   256k|    static constexpr std::string_view xn{"xn-", 3};
10182|   256k|    if (hv.find(xn) != std::string_view::npos) [[unlikely]] {
  ------------------
  |  Branch (10182:9): [True: 44.0k, False: 212k]
  ------------------
10183|  44.0k|      return false;
10184|  44.0k|    }
10185|   256k|  }
10186|       |
10187|   212k|  size_t path_start = host_end;
10188|   212k|  size_t path_end = host_end;
10189|   212k|  size_t query_start = std::string_view::npos;
10190|   212k|  size_t hash_start = std::string_view::npos;
10191|   212k|  bool has_path = false;
10192|   212k|  bool path_has_dot = false;
10193|       |
10194|   212k|  if (i < len && b[i] == '/') {
  ------------------
  |  Branch (10194:7): [True: 205k, False: 7.05k]
  |  Branch (10194:18): [True: 191k, False: 14.0k]
  ------------------
10195|   191k|    has_path = true;
10196|   191k|    path_start = i;
10197|   191k|    ++i;
10198|   876k|    for (; i < len; ++i) {
  ------------------
  |  Branch (10198:12): [True: 765k, False: 111k]
  ------------------
10199|   765k|      const uint8_t c = b[i];
10200|   765k|      const uint8_t cls = k_rest[c];
10201|   765k|      if (cls == 0) {
  ------------------
  |  Branch (10201:11): [True: 685k, False: 79.8k]
  ------------------
10202|   685k|        path_has_dot |= (c == '.');
10203|   685k|        continue;
10204|   685k|      }
10205|  79.8k|      if (cls == 1) {
  ------------------
  |  Branch (10205:11): [True: 71.6k, False: 8.22k]
  ------------------
10206|  71.6k|        path_end = i;
10207|  71.6k|        if (c == '?') {
  ------------------
  |  Branch (10207:13): [True: 57.1k, False: 14.4k]
  ------------------
10208|  57.1k|          query_start = i;
10209|  57.1k|          ++i;
10210|  57.1k|          goto scan_query;
10211|  57.1k|        }
10212|  14.4k|        hash_start = i;
10213|  14.4k|        ++i;
10214|  14.4k|        goto scan_hash;
10215|  71.6k|      }
10216|  8.22k|      return false;
10217|  79.8k|    }
10218|   111k|    path_end = i;
10219|   111k|  } else if (i < len && b[i] == '?') {
  ------------------
  |  Branch (10219:14): [True: 14.0k, False: 7.05k]
  |  Branch (10219:25): [True: 7.07k, False: 6.97k]
  ------------------
10220|  7.07k|    query_start = i;
10221|  7.07k|    ++i;
10222|  7.07k|    goto scan_query;
10223|  14.0k|  } else if (i < len && b[i] == '#') {
  ------------------
  |  Branch (10223:14): [True: 6.97k, False: 7.05k]
  |  Branch (10223:25): [True: 6.97k, False: 0]
  ------------------
10224|  6.97k|    hash_start = i;
10225|  6.97k|    ++i;
10226|  6.97k|    goto scan_hash;
10227|  6.97k|  }
10228|   118k|  goto after_rest;
10229|       |
10230|   118k|scan_query:
10231|   517k|  for (; i < len; ++i) {
  ------------------
  |  Branch (10231:10): [True: 475k, False: 41.9k]
  ------------------
10232|   475k|    const uint8_t c = b[i];
10233|   475k|    if (c == '#') {
  ------------------
  |  Branch (10233:9): [True: 22.1k, False: 453k]
  ------------------
10234|  22.1k|      hash_start = i;
10235|  22.1k|      ++i;
10236|  22.1k|      goto scan_hash;
10237|  22.1k|    }
10238|   453k|    if (c == '?' || c == '%') {
  ------------------
  |  Branch (10238:9): [True: 1.09k, False: 452k]
  |  Branch (10238:21): [True: 17.0k, False: 435k]
  ------------------
10239|  18.1k|      continue;
10240|  18.1k|    }
10241|   435k|    if (k_rest[c] == 2) [[unlikely]] {
  ------------------
  |  Branch (10241:9): [True: 117, False: 435k]
  ------------------
10242|    117|      return false;
10243|    117|    }
10244|   435k|  }
10245|  41.9k|  goto after_rest;
10246|       |
10247|  43.6k|scan_hash:
10248|   241k|  for (; i < len; ++i) {
  ------------------
  |  Branch (10248:10): [True: 197k, False: 43.5k]
  ------------------
10249|   197k|    const uint8_t c = b[i];
10250|   197k|    if (c == '?' || c == '#' || c == '%') {
  ------------------
  |  Branch (10250:9): [True: 524, False: 197k]
  |  Branch (10250:21): [True: 526, False: 196k]
  |  Branch (10250:33): [True: 8.28k, False: 188k]
  ------------------
10251|  9.33k|      continue;
10252|  9.33k|    }
10253|   188k|    if (k_rest[c] == 2) [[unlikely]] {
  ------------------
  |  Branch (10253:9): [True: 71, False: 188k]
  ------------------
10254|     71|      return false;
10255|     71|    }
10256|   188k|  }
10257|       |
10258|   204k|after_rest:
10259|   204k|  if (path_has_dot) [[unlikely]] {
  ------------------
  |  Branch (10259:7): [True: 48.7k, False: 155k]
  ------------------
10260|  48.7k|    const std::string_view path_body(input.data() + path_start,
10261|  48.7k|                                     path_end - path_start);
10262|  48.7k|    if (path_body.size() >= 2 && path_body[1] == '.') {
  ------------------
  |  Branch (10262:9): [True: 48.7k, False: 0]
  |  Branch (10262:34): [True: 273, False: 48.4k]
  ------------------
10263|    273|      if (path_body.size() == 2 || path_body[2] == '/' ||
  ------------------
  |  Branch (10263:11): [True: 6, False: 267]
  |  Branch (10263:36): [True: 47, False: 220]
  ------------------
10264|    220|          (path_body.size() >= 3 && path_body[2] == '.' &&
  ------------------
  |  Branch (10264:12): [True: 220, False: 0]
  |  Branch (10264:37): [True: 124, False: 96]
  ------------------
10265|    124|           (path_body.size() == 3 || path_body[3] == '/'))) {
  ------------------
  |  Branch (10265:13): [True: 3, False: 121]
  |  Branch (10265:38): [True: 54, False: 67]
  ------------------
10266|    110|        return false;
10267|    110|      }
10268|    273|    }
10269|  48.6k|    static constexpr std::string_view slash_dot{"/.", 2};
10270|  48.6k|    size_t p = 1;
10271|  51.2k|    while ((p = path_body.find(slash_dot, p)) != std::string_view::npos) {
  ------------------
  |  Branch (10271:12): [True: 9.58k, False: 41.6k]
  ------------------
10272|  9.58k|      const size_t after = p + 2;
10273|  9.58k|      if (after == path_body.size() || path_body[after] == '/' ||
  ------------------
  |  Branch (10273:11): [True: 23, False: 9.56k]
  |  Branch (10273:40): [True: 6.92k, False: 2.64k]
  ------------------
10274|  2.64k|          (after + 1 <= path_body.size() && path_body[after] == '.' &&
  ------------------
  |  Branch (10274:12): [True: 2.64k, False: 0]
  |  Branch (10274:45): [True: 1.16k, False: 1.47k]
  ------------------
10275|  6.98k|           (after + 1 == path_body.size() || path_body[after + 1] == '/'))) {
  ------------------
  |  Branch (10275:13): [True: 17, False: 1.15k]
  |  Branch (10275:46): [True: 26, False: 1.12k]
  ------------------
10276|  6.98k|        return false;
10277|  6.98k|      }
10278|  2.60k|      p = after;
10279|  2.60k|    }
10280|  48.6k|  }
10281|       |
10282|   196k|  const bool need_slash = !has_path;
10283|   196k|  out.type = scheme_type;
10284|   196k|  out.is_valid = true;
10285|   196k|  out.has_opaque_path = false;
10286|   196k|  out.host_type = DEFAULT;
10287|       |
10288|       |  if constexpr (is_aggregator) {
10289|       |    if (!need_slash) {
10290|       |      out.buffer.resize(len);
10291|       |      // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage)
10292|       |      std::memcpy(out.buffer.data(), input.data(), len);
10293|       |      if (has_upper) {
10294|       |        unicode::to_lower_ascii(out.buffer.data() + host_start,
10295|       |                                host_end - host_start);
10296|       |      }
10297|       |      out.components.protocol_end = protocol_end;
10298|       |      out.components.username_end = protocol_end + 2;
10299|       |      out.components.host_start = protocol_end + 2;
10300|       |      out.components.host_end = static_cast<uint32_t>(host_end);
10301|       |      out.components.port = url_components::omitted;
10302|       |      out.components.pathname_start = static_cast<uint32_t>(path_start);
10303|       |      out.components.search_start = (query_start != std::string_view::npos)
10304|       |                                        ? static_cast<uint32_t>(query_start)
10305|       |                                        : url_components::omitted;
10306|       |      out.components.hash_start = (hash_start != std::string_view::npos)
10307|       |                                      ? static_cast<uint32_t>(hash_start)
10308|       |                                      : url_components::omitted;
10309|       |    } else {
10310|       |      out.buffer.resize(len + 1);
10311|       |      // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage)
10312|       |      std::memcpy(out.buffer.data(), input.data(), host_end);
10313|       |      out.buffer[host_end] = '/';
10314|       |      if (host_end < len) {
10315|       |        std::memcpy(out.buffer.data() + host_end + 1, input.data() + host_end,
10316|       |                    len - host_end);
10317|       |      }
10318|       |      if (has_upper) {
10319|       |        unicode::to_lower_ascii(out.buffer.data() + host_start,
10320|       |                                host_end - host_start);
10321|       |      }
10322|       |      out.components.protocol_end = protocol_end;
10323|       |      out.components.username_end = protocol_end + 2;
10324|       |      out.components.host_start = protocol_end + 2;
10325|       |      out.components.host_end = static_cast<uint32_t>(host_end);
10326|       |      out.components.port = url_components::omitted;
10327|       |      out.components.pathname_start = static_cast<uint32_t>(host_end);
10328|       |      out.components.search_start = (query_start != std::string_view::npos)
10329|       |                                        ? static_cast<uint32_t>(query_start + 1)
10330|       |                                        : url_components::omitted;
10331|       |      out.components.hash_start = (hash_start != std::string_view::npos)
10332|       |                                      ? static_cast<uint32_t>(hash_start + 1)
10333|       |                                      : url_components::omitted;
10334|       |    }
10335|   196k|  } else {
10336|   196k|    std::string host_str(input.substr(host_start, host_end - host_start));
10337|   196k|    if (has_upper) {
  ------------------
  |  Branch (10337:9): [True: 6.96k, False: 189k]
  ------------------
10338|  6.96k|      unicode::to_lower_ascii(host_str.data(), host_str.size());
10339|  6.96k|    }
10340|   196k|    out.host = std::move(host_str);
10341|   196k|    if (need_slash) {
  ------------------
  |  Branch (10341:9): [True: 20.9k, False: 175k]
  ------------------
10342|  20.9k|      out.path = "/";
10343|   175k|    } else {
10344|   175k|      out.path.assign(input.data() + path_start, path_end - path_start);
10345|   175k|    }
10346|   196k|    if (query_start != std::string_view::npos) {
  ------------------
  |  Branch (10346:9): [True: 64.0k, False: 132k]
  ------------------
10347|  64.0k|      const size_t q_end =
10348|  64.0k|          (hash_start != std::string_view::npos) ? hash_start : len;
  ------------------
  |  Branch (10348:11): [True: 22.0k, False: 41.9k]
  ------------------
10349|  64.0k|      out.query.emplace(input.data() + query_start + 1,
10350|  64.0k|                        q_end - query_start - 1);
10351|  64.0k|    }
10352|   196k|    if (hash_start != std::string_view::npos) {
  ------------------
  |  Branch (10352:9): [True: 43.4k, False: 153k]
  ------------------
10353|  43.4k|      out.hash.emplace(input.data() + hash_start + 1, len - hash_start - 1);
10354|  43.4k|    }
10355|   196k|  }
10356|   196k|  return true;
10357|   204k|}
_ZN3ada3url12parse_schemeILb0EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE:
 9392|   160k|ada_really_inline bool url::parse_scheme(const std::string_view input) {
 9393|   160k|  auto parsed_type = ada::scheme::get_scheme_type(input);
 9394|   160k|  bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL);
 9395|       |  /**
 9396|       |   * In the common case, we will immediately recognize a special scheme (e.g.,
 9397|       |   *http, https), in which case, we can go really fast.
 9398|       |   **/
 9399|   160k|  if (is_input_special) {  // fast path!!!
  ------------------
  |  Branch (9399:7): [True: 156k, False: 4.16k]
  ------------------
 9400|       |    if constexpr (has_state_override) {
 9401|       |      // If url's scheme is not a special scheme and buffer is a special scheme,
 9402|       |      // then return.
 9403|       |      if (is_special() != is_input_special) {
 9404|       |        return false;
 9405|       |      }
 9406|       |
 9407|       |      // If url includes credentials or has a non-null port, and buffer is
 9408|       |      // "file", then return.
 9409|       |      if ((has_credentials() || port.has_value()) &&
 9410|       |          parsed_type == ada::scheme::type::FILE) {
 9411|       |        return false;
 9412|       |      }
 9413|       |
 9414|       |      // If url's scheme is "file" and its host is an empty host, then return.
 9415|       |      // An empty host is the empty string.
 9416|       |      if (type == ada::scheme::type::FILE && host.has_value() &&
 9417|       |          host->empty()) {
 9418|       |        return false;
 9419|       |      }
 9420|       |    }
 9421|       |
 9422|   156k|    type = parsed_type;
 9423|       |
 9424|       |    if constexpr (has_state_override) {
 9425|       |      // This is uncommon.
 9426|       |      uint16_t urls_scheme_port = get_special_port();
 9427|       |
 9428|       |      if (urls_scheme_port) {
 9429|       |        // If url's port is url's scheme's default port, then set url's port to
 9430|       |        // null.
 9431|       |        if (port.has_value() && *port == urls_scheme_port) {
 9432|       |          port = std::nullopt;
 9433|       |        }
 9434|       |      }
 9435|       |    }
 9436|   156k|  } else {  // slow path
 9437|  4.16k|    std::string _buffer(input);
 9438|       |    // Next function is only valid if the input is ASCII and returns false
 9439|       |    // otherwise, but it seems that we always have ascii content so we do not
 9440|       |    // need to check the return value.
 9441|       |    // bool is_ascii =
 9442|  4.16k|    unicode::to_lower_ascii(_buffer.data(), _buffer.size());
 9443|       |
 9444|       |    if constexpr (has_state_override) {
 9445|       |      // The state-override validation errors below ("return" in the WHATWG URL
 9446|       |      // parser) leave the URL unchanged. The setter contract is
 9447|       |      // "true on success, false if the scheme is invalid" -- the fast path
 9448|       |      // above already returns false here, so the slow path must agree.
 9449|       |
 9450|       |      // If url's scheme is a special scheme and buffer is not a special scheme,
 9451|       |      // then return. If url's scheme is not a special scheme and buffer is a
 9452|       |      // special scheme, then return.
 9453|       |      if (is_special() != ada::scheme::is_special(_buffer)) {
 9454|       |        return false;
 9455|       |      }
 9456|       |
 9457|       |      // If url includes credentials or has a non-null port, and buffer is
 9458|       |      // "file", then return.
 9459|       |      if ((has_credentials() || port.has_value()) && _buffer == "file") {
 9460|       |        return false;
 9461|       |      }
 9462|       |
 9463|       |      // If url's scheme is "file" and its host is an empty host, then return.
 9464|       |      // An empty host is the empty string.
 9465|       |      if (type == ada::scheme::type::FILE && host.has_value() &&
 9466|       |          host->empty()) {
 9467|       |        return false;
 9468|       |      }
 9469|       |    }
 9470|       |
 9471|  4.16k|    set_scheme(std::move(_buffer));
 9472|       |
 9473|       |    if constexpr (has_state_override) {
 9474|       |      // This is uncommon.
 9475|       |      uint16_t urls_scheme_port = get_special_port();
 9476|       |
 9477|       |      if (urls_scheme_port) {
 9478|       |        // If url's port is url's scheme's default port, then set url's port to
 9479|       |        // null.
 9480|       |        if (port.has_value() && *port == urls_scheme_port) {
 9481|       |          port = std::nullopt;
 9482|       |        }
 9483|       |      }
 9484|       |    }
 9485|  4.16k|  }
 9486|       |
 9487|   160k|  return true;
 9488|   160k|}
_ZN3ada6parser25try_parse_simple_absoluteINS_14url_aggregatorEEEbNSt3__117basic_string_viewIcNS3_11char_traitsIcEEEERT_:
10106|   310k|                                                result_type& out) {
10107|   310k|  constexpr bool is_ada_url = std::is_same_v<result_type, ada::url>;
10108|   310k|  constexpr bool is_aggregator =
10109|   310k|      std::is_same_v<result_type, ada::url_aggregator>;
10110|   310k|  static_assert(is_ada_url || is_aggregator);
10111|       |
10112|   310k|  const size_t len = input.size();
10113|   310k|  if (len < 8) [[unlikely]] {
  ------------------
  |  Branch (10113:7): [True: 45, False: 310k]
  ------------------
10114|     45|    return false;
10115|     45|  }
10116|   310k|  const auto* b = reinterpret_cast<const uint8_t*>(input.data());
10117|       |
10118|   310k|  size_t pos;
10119|   310k|  ada::scheme::type scheme_type;
10120|   310k|  uint32_t protocol_end;
10121|   310k|  if (b[0] == 'h' && b[1] == 't' && b[2] == 't' && b[3] == 'p') {
  ------------------
  |  Branch (10121:7): [True: 306k, False: 3.61k]
  |  Branch (10121:22): [True: 306k, False: 80]
  |  Branch (10121:37): [True: 306k, False: 555]
  |  Branch (10121:52): [True: 305k, False: 46]
  ------------------
10122|   305k|    if (b[4] == ':' && b[5] == '/' && b[6] == '/') {
  ------------------
  |  Branch (10122:9): [True: 51.6k, False: 254k]
  |  Branch (10122:24): [True: 51.1k, False: 510]
  |  Branch (10122:39): [True: 51.0k, False: 72]
  ------------------
10123|  51.0k|      pos = 7;
10124|  51.0k|      scheme_type = ada::scheme::type::HTTP;
10125|  51.0k|      protocol_end = 5;
10126|   254k|    } else if (len >= 8 && b[4] == 's' && b[5] == ':' && b[6] == '/' &&
  ------------------
  |  Branch (10126:16): [True: 254k, False: 0]
  |  Branch (10126:28): [True: 254k, False: 633]
  |  Branch (10126:43): [True: 254k, False: 30]
  |  Branch (10126:58): [True: 253k, False: 591]
  ------------------
10127|   253k|               b[7] == '/') {
  ------------------
  |  Branch (10127:16): [True: 253k, False: 28]
  ------------------
10128|   253k|      pos = 8;
10129|   253k|      scheme_type = ada::scheme::type::HTTPS;
10130|   253k|      protocol_end = 6;
10131|   253k|    } else {
10132|  1.28k|      return false;
10133|  1.28k|    }
10134|   305k|  } else {
10135|  4.30k|    return false;
10136|  4.30k|  }
10137|   304k|  if (pos < len && (b[pos] == '/' || b[pos] == '\\')) [[unlikely]] {
  ------------------
  |  Branch (10137:7): [True: 304k, False: 1]
  |  Branch (10137:21): [True: 87, False: 304k]
  |  Branch (10137:38): [True: 33, False: 304k]
  ------------------
10138|    120|    return false;
10139|    120|  }
10140|       |
10141|       |  // Digit-led hosts are IPv4/numeric; skip before scanning.
10142|   304k|  if (pos < len && b[pos] >= '0' && b[pos] <= '9') {
  ------------------
  |  Branch (10142:7): [True: 304k, False: 1]
  |  Branch (10142:20): [True: 302k, False: 1.86k]
  |  Branch (10142:37): [True: 0, False: 302k]
  ------------------
10143|      0|    return false;
10144|      0|  }
10145|       |
10146|   304k|  const size_t host_start = pos;
10147|   304k|  bool has_upper = false;
10148|   304k|  size_t i = pos;
10149|  3.75M|  for (; i < len; ++i) {
  ------------------
  |  Branch (10149:10): [True: 3.74M, False: 7.10k]
  ------------------
10150|  3.74M|    const uint8_t c = b[i];
10151|  3.74M|    const uint8_t cls = k_host_class[c];
10152|  3.74M|    if (cls == 1) {
  ------------------
  |  Branch (10152:9): [True: 249k, False: 3.49M]
  ------------------
10153|   249k|      break;
10154|   249k|    }
10155|  3.49M|    if (cls == 2) [[unlikely]] {
  ------------------
  |  Branch (10155:9): [True: 47.9k, False: 3.44M]
  ------------------
10156|  47.9k|      return false;
10157|  47.9k|    }
10158|  3.44M|    if (c >= 'A' && c <= 'Z') {
  ------------------
  |  Branch (10158:9): [True: 2.97M, False: 478k]
  |  Branch (10158:21): [True: 53.7k, False: 2.91M]
  ------------------
10159|  53.7k|      has_upper = true;
10160|  53.7k|    }
10161|  3.44M|  }
10162|   256k|  const size_t host_end = i;
10163|   256k|  if (host_start == host_end) [[unlikely]] {
  ------------------
  |  Branch (10163:7): [True: 9, False: 256k]
  ------------------
10164|      9|    return false;
10165|      9|  }
10166|   256k|  const size_t host_len = host_end - host_start;
10167|   256k|  if (host_len > 253) [[unlikely]] {
  ------------------
  |  Branch (10167:7): [True: 125, False: 256k]
  ------------------
10168|    125|    return false;
10169|    125|  }
10170|   256k|  {
10171|   256k|    std::string_view hv(input.data() + host_start, host_len);
10172|   256k|    char host_buf[256];
10173|   256k|    if (has_upper) [[unlikely]] {
  ------------------
  |  Branch (10173:9): [True: 7.09k, False: 249k]
  ------------------
10174|  7.09k|      std::memcpy(host_buf, input.data() + host_start, host_len);
10175|  7.09k|      unicode::to_lower_ascii(host_buf, host_len);
10176|  7.09k|      hv = std::string_view(host_buf, host_len);
10177|  7.09k|    }
10178|   256k|    if (checkers::is_ipv4(hv)) [[unlikely]] {
  ------------------
  |  Branch (10178:9): [True: 30, False: 256k]
  ------------------
10179|     30|      return false;
10180|     30|    }
10181|   256k|    static constexpr std::string_view xn{"xn-", 3};
10182|   256k|    if (hv.find(xn) != std::string_view::npos) [[unlikely]] {
  ------------------
  |  Branch (10182:9): [True: 44.0k, False: 212k]
  ------------------
10183|  44.0k|      return false;
10184|  44.0k|    }
10185|   256k|  }
10186|       |
10187|   212k|  size_t path_start = host_end;
10188|   212k|  size_t path_end = host_end;
10189|   212k|  size_t query_start = std::string_view::npos;
10190|   212k|  size_t hash_start = std::string_view::npos;
10191|   212k|  bool has_path = false;
10192|   212k|  bool path_has_dot = false;
10193|       |
10194|   212k|  if (i < len && b[i] == '/') {
  ------------------
  |  Branch (10194:7): [True: 205k, False: 7.05k]
  |  Branch (10194:18): [True: 191k, False: 14.0k]
  ------------------
10195|   191k|    has_path = true;
10196|   191k|    path_start = i;
10197|   191k|    ++i;
10198|   876k|    for (; i < len; ++i) {
  ------------------
  |  Branch (10198:12): [True: 765k, False: 111k]
  ------------------
10199|   765k|      const uint8_t c = b[i];
10200|   765k|      const uint8_t cls = k_rest[c];
10201|   765k|      if (cls == 0) {
  ------------------
  |  Branch (10201:11): [True: 685k, False: 79.8k]
  ------------------
10202|   685k|        path_has_dot |= (c == '.');
10203|   685k|        continue;
10204|   685k|      }
10205|  79.8k|      if (cls == 1) {
  ------------------
  |  Branch (10205:11): [True: 71.6k, False: 8.22k]
  ------------------
10206|  71.6k|        path_end = i;
10207|  71.6k|        if (c == '?') {
  ------------------
  |  Branch (10207:13): [True: 57.1k, False: 14.4k]
  ------------------
10208|  57.1k|          query_start = i;
10209|  57.1k|          ++i;
10210|  57.1k|          goto scan_query;
10211|  57.1k|        }
10212|  14.4k|        hash_start = i;
10213|  14.4k|        ++i;
10214|  14.4k|        goto scan_hash;
10215|  71.6k|      }
10216|  8.22k|      return false;
10217|  79.8k|    }
10218|   111k|    path_end = i;
10219|   111k|  } else if (i < len && b[i] == '?') {
  ------------------
  |  Branch (10219:14): [True: 14.0k, False: 7.05k]
  |  Branch (10219:25): [True: 7.07k, False: 6.97k]
  ------------------
10220|  7.07k|    query_start = i;
10221|  7.07k|    ++i;
10222|  7.07k|    goto scan_query;
10223|  14.0k|  } else if (i < len && b[i] == '#') {
  ------------------
  |  Branch (10223:14): [True: 6.97k, False: 7.05k]
  |  Branch (10223:25): [True: 6.97k, False: 0]
  ------------------
10224|  6.97k|    hash_start = i;
10225|  6.97k|    ++i;
10226|  6.97k|    goto scan_hash;
10227|  6.97k|  }
10228|   118k|  goto after_rest;
10229|       |
10230|   118k|scan_query:
10231|   517k|  for (; i < len; ++i) {
  ------------------
  |  Branch (10231:10): [True: 475k, False: 41.9k]
  ------------------
10232|   475k|    const uint8_t c = b[i];
10233|   475k|    if (c == '#') {
  ------------------
  |  Branch (10233:9): [True: 22.1k, False: 453k]
  ------------------
10234|  22.1k|      hash_start = i;
10235|  22.1k|      ++i;
10236|  22.1k|      goto scan_hash;
10237|  22.1k|    }
10238|   453k|    if (c == '?' || c == '%') {
  ------------------
  |  Branch (10238:9): [True: 1.09k, False: 452k]
  |  Branch (10238:21): [True: 17.0k, False: 435k]
  ------------------
10239|  18.1k|      continue;
10240|  18.1k|    }
10241|   435k|    if (k_rest[c] == 2) [[unlikely]] {
  ------------------
  |  Branch (10241:9): [True: 117, False: 435k]
  ------------------
10242|    117|      return false;
10243|    117|    }
10244|   435k|  }
10245|  41.9k|  goto after_rest;
10246|       |
10247|  43.6k|scan_hash:
10248|   241k|  for (; i < len; ++i) {
  ------------------
  |  Branch (10248:10): [True: 197k, False: 43.5k]
  ------------------
10249|   197k|    const uint8_t c = b[i];
10250|   197k|    if (c == '?' || c == '#' || c == '%') {
  ------------------
  |  Branch (10250:9): [True: 524, False: 197k]
  |  Branch (10250:21): [True: 526, False: 196k]
  |  Branch (10250:33): [True: 8.28k, False: 188k]
  ------------------
10251|  9.33k|      continue;
10252|  9.33k|    }
10253|   188k|    if (k_rest[c] == 2) [[unlikely]] {
  ------------------
  |  Branch (10253:9): [True: 71, False: 188k]
  ------------------
10254|     71|      return false;
10255|     71|    }
10256|   188k|  }
10257|       |
10258|   204k|after_rest:
10259|   204k|  if (path_has_dot) [[unlikely]] {
  ------------------
  |  Branch (10259:7): [True: 48.7k, False: 155k]
  ------------------
10260|  48.7k|    const std::string_view path_body(input.data() + path_start,
10261|  48.7k|                                     path_end - path_start);
10262|  48.7k|    if (path_body.size() >= 2 && path_body[1] == '.') {
  ------------------
  |  Branch (10262:9): [True: 48.7k, False: 0]
  |  Branch (10262:34): [True: 273, False: 48.4k]
  ------------------
10263|    273|      if (path_body.size() == 2 || path_body[2] == '/' ||
  ------------------
  |  Branch (10263:11): [True: 6, False: 267]
  |  Branch (10263:36): [True: 47, False: 220]
  ------------------
10264|    220|          (path_body.size() >= 3 && path_body[2] == '.' &&
  ------------------
  |  Branch (10264:12): [True: 220, False: 0]
  |  Branch (10264:37): [True: 124, False: 96]
  ------------------
10265|    124|           (path_body.size() == 3 || path_body[3] == '/'))) {
  ------------------
  |  Branch (10265:13): [True: 3, False: 121]
  |  Branch (10265:38): [True: 54, False: 67]
  ------------------
10266|    110|        return false;
10267|    110|      }
10268|    273|    }
10269|  48.6k|    static constexpr std::string_view slash_dot{"/.", 2};
10270|  48.6k|    size_t p = 1;
10271|  51.2k|    while ((p = path_body.find(slash_dot, p)) != std::string_view::npos) {
  ------------------
  |  Branch (10271:12): [True: 9.58k, False: 41.6k]
  ------------------
10272|  9.58k|      const size_t after = p + 2;
10273|  9.58k|      if (after == path_body.size() || path_body[after] == '/' ||
  ------------------
  |  Branch (10273:11): [True: 23, False: 9.56k]
  |  Branch (10273:40): [True: 6.92k, False: 2.64k]
  ------------------
10274|  2.64k|          (after + 1 <= path_body.size() && path_body[after] == '.' &&
  ------------------
  |  Branch (10274:12): [True: 2.64k, False: 0]
  |  Branch (10274:45): [True: 1.16k, False: 1.47k]
  ------------------
10275|  6.98k|           (after + 1 == path_body.size() || path_body[after + 1] == '/'))) {
  ------------------
  |  Branch (10275:13): [True: 17, False: 1.15k]
  |  Branch (10275:46): [True: 26, False: 1.12k]
  ------------------
10276|  6.98k|        return false;
10277|  6.98k|      }
10278|  2.60k|      p = after;
10279|  2.60k|    }
10280|  48.6k|  }
10281|       |
10282|   196k|  const bool need_slash = !has_path;
10283|   196k|  out.type = scheme_type;
10284|   196k|  out.is_valid = true;
10285|   196k|  out.has_opaque_path = false;
10286|   196k|  out.host_type = DEFAULT;
10287|       |
10288|   196k|  if constexpr (is_aggregator) {
10289|   196k|    if (!need_slash) {
  ------------------
  |  Branch (10289:9): [True: 175k, False: 20.9k]
  ------------------
10290|   175k|      out.buffer.resize(len);
10291|       |      // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage)
10292|   175k|      std::memcpy(out.buffer.data(), input.data(), len);
10293|   175k|      if (has_upper) {
  ------------------
  |  Branch (10293:11): [True: 6.90k, False: 169k]
  ------------------
10294|  6.90k|        unicode::to_lower_ascii(out.buffer.data() + host_start,
10295|  6.90k|                                host_end - host_start);
10296|  6.90k|      }
10297|   175k|      out.components.protocol_end = protocol_end;
10298|   175k|      out.components.username_end = protocol_end + 2;
10299|   175k|      out.components.host_start = protocol_end + 2;
10300|   175k|      out.components.host_end = static_cast<uint32_t>(host_end);
10301|   175k|      out.components.port = url_components::omitted;
10302|   175k|      out.components.pathname_start = static_cast<uint32_t>(path_start);
10303|   175k|      out.components.search_start = (query_start != std::string_view::npos)
  ------------------
  |  Branch (10303:37): [True: 57.0k, False: 118k]
  ------------------
10304|   175k|                                        ? static_cast<uint32_t>(query_start)
10305|   175k|                                        : url_components::omitted;
10306|   175k|      out.components.hash_start = (hash_start != std::string_view::npos)
  ------------------
  |  Branch (10306:35): [True: 36.4k, False: 139k]
  ------------------
10307|   175k|                                      ? static_cast<uint32_t>(hash_start)
10308|   175k|                                      : url_components::omitted;
10309|   175k|    } else {
10310|  20.9k|      out.buffer.resize(len + 1);
10311|       |      // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage)
10312|  20.9k|      std::memcpy(out.buffer.data(), input.data(), host_end);
10313|  20.9k|      out.buffer[host_end] = '/';
10314|  20.9k|      if (host_end < len) {
  ------------------
  |  Branch (10314:11): [True: 13.9k, False: 7.05k]
  ------------------
10315|  13.9k|        std::memcpy(out.buffer.data() + host_end + 1, input.data() + host_end,
10316|  13.9k|                    len - host_end);
10317|  13.9k|      }
10318|  20.9k|      if (has_upper) {
  ------------------
  |  Branch (10318:11): [True: 56, False: 20.9k]
  ------------------
10319|     56|        unicode::to_lower_ascii(out.buffer.data() + host_start,
10320|     56|                                host_end - host_start);
10321|     56|      }
10322|  20.9k|      out.components.protocol_end = protocol_end;
10323|  20.9k|      out.components.username_end = protocol_end + 2;
10324|  20.9k|      out.components.host_start = protocol_end + 2;
10325|  20.9k|      out.components.host_end = static_cast<uint32_t>(host_end);
10326|  20.9k|      out.components.port = url_components::omitted;
10327|  20.9k|      out.components.pathname_start = static_cast<uint32_t>(host_end);
10328|  20.9k|      out.components.search_start = (query_start != std::string_view::npos)
  ------------------
  |  Branch (10328:37): [True: 6.99k, False: 13.9k]
  ------------------
10329|  20.9k|                                        ? static_cast<uint32_t>(query_start + 1)
10330|  20.9k|                                        : url_components::omitted;
10331|  20.9k|      out.components.hash_start = (hash_start != std::string_view::npos)
  ------------------
  |  Branch (10331:35): [True: 7.01k, False: 13.9k]
  ------------------
10332|  20.9k|                                      ? static_cast<uint32_t>(hash_start + 1)
10333|  20.9k|                                      : url_components::omitted;
10334|  20.9k|    }
10335|       |  } else {
10336|       |    std::string host_str(input.substr(host_start, host_end - host_start));
10337|       |    if (has_upper) {
10338|       |      unicode::to_lower_ascii(host_str.data(), host_str.size());
10339|       |    }
10340|       |    out.host = std::move(host_str);
10341|       |    if (need_slash) {
10342|       |      out.path = "/";
10343|       |    } else {
10344|       |      out.path.assign(input.data() + path_start, path_end - path_start);
10345|       |    }
10346|       |    if (query_start != std::string_view::npos) {
10347|       |      const size_t q_end =
10348|       |          (hash_start != std::string_view::npos) ? hash_start : len;
10349|       |      out.query.emplace(input.data() + query_start + 1,
10350|       |                        q_end - query_start - 1);
10351|       |    }
10352|       |    if (hash_start != std::string_view::npos) {
10353|       |      out.hash.emplace(input.data() + hash_start + 1, len - hash_start - 1);
10354|       |    }
10355|       |  }
10356|   196k|  return true;
10357|   204k|}
_ZN3ada14url_aggregator23parse_scheme_with_colonILb0EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE:
11448|   160k|    const std::string_view input_with_colon) {
11449|   160k|  ada_log("url_aggregator::parse_scheme_with_colon ", input_with_colon);
11450|   160k|  ADA_ASSERT_TRUE(validate());
11451|   160k|  ADA_ASSERT_TRUE(!helpers::overlaps(input_with_colon, buffer));
11452|   160k|  std::string_view input{input_with_colon};
11453|   160k|  input.remove_suffix(1);
11454|   160k|  auto parsed_type = ada::scheme::get_scheme_type(input);
11455|   160k|  const bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL);
11456|       |  /**
11457|       |   * In the common case, we will immediately recognize a special scheme (e.g.,
11458|       |   *http, https), in which case, we can go really fast.
11459|       |   **/
11460|   160k|  if (is_input_special) {  // fast path!!!
  ------------------
  |  Branch (11460:7): [True: 156k, False: 4.16k]
  ------------------
11461|       |    if constexpr (has_state_override) {
11462|       |      // If url's scheme is not a special scheme and buffer is a special scheme,
11463|       |      // then return.
11464|       |      if (is_special() != is_input_special) {
11465|       |        return false;
11466|       |      }
11467|       |
11468|       |      // If url includes credentials or has a non-null port, and buffer is
11469|       |      // "file", then return.
11470|       |      if ((has_credentials() || components.port != url_components::omitted) &&
11471|       |          parsed_type == ada::scheme::type::FILE) {
11472|       |        return false;
11473|       |      }
11474|       |
11475|       |      // If url's scheme is "file" and its host is an empty host, then return.
11476|       |      // An empty host is the empty string.
11477|       |      if (type == ada::scheme::type::FILE &&
11478|       |          components.host_start == components.host_end) {
11479|       |        return false;
11480|       |      }
11481|       |    }
11482|       |
11483|   156k|    type = parsed_type;
11484|   156k|    set_scheme_from_view_with_colon(input_with_colon);
11485|       |
11486|       |    if constexpr (has_state_override) {
11487|       |      // This is uncommon.
11488|       |      uint16_t urls_scheme_port = get_special_port();
11489|       |
11490|       |      if (urls_scheme_port) {
11491|       |        // If url's port is url's scheme's default port, then set url's port to
11492|       |        // null.
11493|       |        if (components.port == urls_scheme_port) {
11494|       |          clear_port();
11495|       |        }
11496|       |      }
11497|       |    }
11498|   156k|  } else {  // slow path
11499|  4.16k|    std::string _buffer(input);
11500|       |    // Next function is only valid if the input is ASCII and returns false
11501|       |    // otherwise, but it seems that we always have ascii content so we do not
11502|       |    // need to check the return value.
11503|  4.16k|    unicode::to_lower_ascii(_buffer.data(), _buffer.size());
11504|       |
11505|       |    if constexpr (has_state_override) {
11506|       |      // The state-override validation errors below ("return" in the WHATWG URL
11507|       |      // parser) leave the URL unchanged. The setter contract is
11508|       |      // "true on success, false if the scheme is invalid" -- the fast path
11509|       |      // above already returns false here, so the slow path must agree.
11510|       |
11511|       |      // If url's scheme is a special scheme and buffer is not a special scheme,
11512|       |      // then return. If url's scheme is not a special scheme and buffer is a
11513|       |      // special scheme, then return.
11514|       |      if (is_special() != ada::scheme::is_special(_buffer)) {
11515|       |        return false;
11516|       |      }
11517|       |
11518|       |      // If url includes credentials or has a non-null port, and buffer is
11519|       |      // "file", then return.
11520|       |      if ((has_credentials() || components.port != url_components::omitted) &&
11521|       |          _buffer == "file") {
11522|       |        return false;
11523|       |      }
11524|       |
11525|       |      // If url's scheme is "file" and its host is an empty host, then return.
11526|       |      // An empty host is the empty string.
11527|       |      if (type == ada::scheme::type::FILE &&
11528|       |          components.host_start == components.host_end) {
11529|       |        return false;
11530|       |      }
11531|       |    }
11532|       |
11533|  4.16k|    set_scheme(_buffer);
11534|       |
11535|       |    if constexpr (has_state_override) {
11536|       |      // This is uncommon.
11537|       |      uint16_t urls_scheme_port = get_special_port();
11538|       |
11539|       |      if (urls_scheme_port) {
11540|       |        // If url's port is url's scheme's default port, then set url's port to
11541|       |        // null.
11542|       |        if (components.port == urls_scheme_port) {
11543|       |          clear_port();
11544|       |        }
11545|       |      }
11546|       |    }
11547|  4.16k|  }
11548|   160k|  ADA_ASSERT_TRUE(validate());
11549|   160k|  return true;
11550|   160k|}
_ZN3ada14url_aggregator31set_scheme_from_view_with_colonENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11574|   156k|    std::string_view new_scheme_with_colon) {
11575|   156k|  ada_log("url_aggregator::set_scheme_from_view_with_colon ",
11576|   156k|          new_scheme_with_colon);
11577|   156k|  ADA_ASSERT_TRUE(validate());
11578|   156k|  ADA_ASSERT_TRUE(!new_scheme_with_colon.empty() &&
11579|   156k|                  new_scheme_with_colon.back() == ':');
11580|       |  // next line could overflow but unsigned arithmetic has well-defined
11581|       |  // overflows.
11582|   156k|  uint32_t new_difference =
11583|   156k|      uint32_t(new_scheme_with_colon.size()) - components.protocol_end;
11584|       |
11585|   156k|  if (buffer.empty()) {
  ------------------
  |  Branch (11585:7): [True: 156k, False: 0]
  ------------------
11586|   156k|    buffer.append(new_scheme_with_colon);
11587|   156k|  } else {
11588|      0|    buffer.erase(0, components.protocol_end);
11589|      0|    buffer.insert(0, new_scheme_with_colon);
11590|      0|  }
11591|   156k|  components.protocol_end += new_difference;
11592|       |
11593|   156k|  apply_shifted_non_scheme_offsets(components, new_difference);
11594|   156k|  ADA_ASSERT_TRUE(validate());
11595|   156k|}
_ZN3ada14url_aggregator10set_schemeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11597|  4.16k|inline void url_aggregator::set_scheme(std::string_view new_scheme) {
11598|  4.16k|  ada_log("url_aggregator::set_scheme ", new_scheme);
11599|  4.16k|  ADA_ASSERT_TRUE(validate());
11600|  4.16k|  ADA_ASSERT_TRUE(new_scheme.empty() || new_scheme.back() != ':');
11601|       |  // next line could overflow but unsigned arithmetic has well-defined
11602|       |  // overflows.
11603|  4.16k|  uint32_t new_difference =
11604|  4.16k|      uint32_t(new_scheme.size()) - components.protocol_end + 1;
11605|       |
11606|  4.16k|  type = ada::scheme::get_scheme_type(new_scheme);
11607|  4.16k|  if (buffer.empty()) {
  ------------------
  |  Branch (11607:7): [True: 4.16k, False: 0]
  ------------------
11608|  4.16k|    buffer.append(helpers::concat(new_scheme, ":"));
11609|  4.16k|  } else {
11610|      0|    buffer.erase(0, components.protocol_end);
11611|      0|    buffer.insert(0, helpers::concat(new_scheme, ":"));
11612|      0|  }
11613|  4.16k|  components.protocol_end = uint32_t(new_scheme.size() + 1);
11614|       |
11615|  4.16k|  apply_shifted_non_scheme_offsets(components, new_difference);
11616|  4.16k|  ADA_ASSERT_TRUE(validate());
11617|  4.16k|}

_ZN3ada37url_pattern_compile_component_optionsC2ENSt3__18optionalIcEES3_:
 5678|      6|      : delimiter(new_delimiter), prefix(new_prefix) {}
_ZN3ada14character_sets6bit_atEPKhh:
 1074|  1.32M|ada_really_inline constexpr bool bit_at(const uint8_t a[], const uint8_t i) {
 1075|  1.32M|  return !!(a[i >> 3] & (1 << (i & 7)));
 1076|  1.32M|}
_ZN2tl10unexpectedIN3ada6errorsEEC2EOS2_:
 2145|  11.5k|  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:
 3631|  2.88k|      : impl_base(unexpect, std::move(e.value())),
 3632|  2.88k|        ctor_base(detail::default_constructor_tag{}) {}
_ZNR2tl10unexpectedIN3ada6errorsEE5valueEv:
 2159|  5.76k|  TL_EXPECTED_11_CONSTEXPR E& value() & { return m_val; }
_ZN2tl6detail21expected_storage_baseIN3ada3urlENS2_6errorsELb0ELb1EEC2IJS4_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS4_DpOT_EE5valueEvE4typeELPv0EEENS_10unexpect_tESB_:
 2617|  2.88k|      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
_ZN2tl6detail26expected_default_ctor_baseIN3ada3urlENS2_6errorsELb1EEC2ENS0_23default_constructor_tagE:
 3235|   357k|  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_:
 3717|   354k|      : expected(in_place, std::forward<U>(v)) {}
_ZN2tl8expectedIN3ada3urlENS1_6errorsEEC2IJS2_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS2_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESA_:
 3590|   354k|      : impl_base(in_place, std::forward<Args>(args)...),
 3591|   354k|        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl6detail21expected_storage_baseIN3ada3urlENS2_6errorsELb0ELb1EEC2IJS3_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESB_:
 2605|   354k|      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
_ZN3ada3urlC2EOS0_:
 4986|   354k|  url(url&& u) noexcept = default;
_ZN3ada8url_baseD2Ev:
 1649|  1.42M|  virtual ~url_base() = default;
_ZN3ada3urlD2Ev:
 4989|   712k|  ~url() override = default;
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEC2IS3_TnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_OT_EE5valueEvE4typeELPv0ETnPNS7_IXsr3std14is_convertibleIS9_S3_EE5valueEvE4typeELSD_0EEEONS_10unexpectedIS8_EE:
 3631|  2.88k|      : impl_base(unexpect, std::move(e.value())),
 3632|  2.88k|        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl6detail21expected_storage_baseIN3ada14url_aggregatorENS2_6errorsELb0ELb1EEC2IJS4_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS4_DpOT_EE5valueEvE4typeELPv0EEENS_10unexpect_tESB_:
 2617|  2.88k|      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
_ZN2tl6detail26expected_default_ctor_baseIN3ada14url_aggregatorENS2_6errorsELb1EEC2ENS0_23default_constructor_tagE:
 3235|   357k|  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_:
 3717|   354k|      : expected(in_place, std::forward<U>(v)) {}
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEC2IJS2_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS2_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESA_:
 3590|   354k|      : impl_base(in_place, std::forward<Args>(args)...),
 3591|   354k|        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl6detail21expected_storage_baseIN3ada14url_aggregatorENS2_6errorsELb0ELb1EEC2IJS3_ETnPNSt3__19enable_ifIXsr3std16is_constructibleIS3_DpOT_EE5valueEvE4typeELPv0EEENS_10in_place_tESB_:
 2605|   354k|      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
_ZN3ada14url_aggregatorC2EOS0_:
 7691|   354k|  url_aggregator(url_aggregator&& u) noexcept = default;
_ZN3ada14url_aggregatorD2Ev:
 7694|   712k|  ~url_aggregator() override = default;
_ZN3ada6scheme15get_scheme_typeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6709|   329k|constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept {
 6710|   329k|  if (scheme.empty()) {
  ------------------
  |  Branch (6710:7): [True: 0, False: 329k]
  ------------------
 6711|      0|    return ada::scheme::NOT_SPECIAL;
 6712|      0|  }
 6713|   329k|  int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
 6714|   329k|  const std::string_view target = details::is_special_list[hash_value];
 6715|   329k|  if (scheme.size() == target.size() &&
  ------------------
  |  Branch (6715:7): [True: 325k, False: 4.48k]
  ------------------
 6716|   325k|      details::branchless_load5(scheme.data(), scheme.size()) ==
  ------------------
  |  Branch (6716:7): [True: 318k, False: 6.92k]
  ------------------
 6717|   325k|          details::scheme_keys[hash_value]) {
 6718|   318k|    return ada::scheme::type(hash_value);
 6719|   318k|  } else {
 6720|  11.4k|    return ada::scheme::NOT_SPECIAL;
 6721|  11.4k|  }
 6722|   329k|}
_ZN3ada6scheme7details16branchless_load5EPKcm:
 6650|   325k|inline uint64_t branchless_load5(const char* p, size_t n) {
 6651|   325k|  uint64_t input = (uint8_t)p[0];
 6652|   325k|  input |= ((uint64_t)(uint8_t)p[n > 1] << 8) & (0 - (uint64_t)(n > 1));
 6653|   325k|  input |= ((uint64_t)(uint8_t)p[(n > 2) * 2] << 16) & (0 - (uint64_t)(n > 2));
 6654|   325k|  input |= ((uint64_t)(uint8_t)p[(n > 3) * 3] << 24) & (0 - (uint64_t)(n > 3));
 6655|   325k|  input |= ((uint64_t)(uint8_t)p[(n > 4) * 4] << 32) & (0 - (uint64_t)(n > 4));
 6656|   325k|  return input;
 6657|   325k|}
_ZN3ada14url_aggregatorC2Ev:
 7689|   357k|  url_aggregator() = default;
_ZN3ada14url_componentsC2Ev:
 4895|   357k|  url_components() = default;
_ZN3ada8checkers19try_parse_ipv4_fastENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 1402|   332k|try_parse_ipv4_fast(std::string_view input) noexcept {
 1403|   332k|  const size_t len = input.size();
 1404|       |  // Shortest pure decimal: "0.0.0.0" (7). Longest + trailing dot: 16.
 1405|   332k|  if (len < 7 || len > 16) [[unlikely]] {
  ------------------
  |  Branch (1405:7): [True: 83.3k, False: 249k]
  |  Branch (1405:18): [True: 4.82k, False: 244k]
  ------------------
 1406|  88.2k|    return ipv4_fast_fail;
 1407|  88.2k|  }
 1408|   244k|  const char* data = input.data();
 1409|       |
 1410|       |#if defined(ADA_AVX512)
 1411|       |  return detail::try_parse_ipv4_avx512(data, len);
 1412|       |#else
 1413|   244k|  return detail::parse_ipv4_decimal_scalar(data, data + len);
 1414|   332k|#endif
 1415|   332k|}
_ZN3ada8checkers6detail25parse_ipv4_decimal_scalarEPKcS3_:
 1277|   244k|parse_ipv4_decimal_scalar(const char* p, const char* pend) noexcept {
 1278|   244k|  uint32_t ipv4 = 0;
 1279|   552k|  for (int i = 0; i < 4; ++i) {
  ------------------
  |  Branch (1279:19): [True: 475k, False: 76.7k]
  ------------------
 1280|   475k|    if (p == pend) [[unlikely]] {
  ------------------
  |  Branch (1280:9): [True: 10, False: 475k]
  ------------------
 1281|     10|      return ipv4_fast_fail;
 1282|     10|    }
 1283|   475k|    uint32_t val;
 1284|   475k|    char c = *p;
 1285|   475k|    if (c >= '0' && c <= '9') [[likely]] {
  ------------------
  |  Branch (1285:9): [True: 474k, False: 1.09k]
  |  Branch (1285:21): [True: 310k, False: 164k]
  ------------------
 1286|   310k|      val = static_cast<uint32_t>(c - '0');
 1287|   310k|      ++p;
 1288|   310k|    } else {
 1289|   165k|      return ipv4_fast_fail;
 1290|   165k|    }
 1291|   310k|    if (p < pend) {
  ------------------
  |  Branch (1291:9): [True: 234k, False: 75.5k]
  ------------------
 1292|   234k|      c = *p;
 1293|   234k|      if (c >= '0' && c <= '9') {
  ------------------
  |  Branch (1293:11): [True: 123k, False: 111k]
  |  Branch (1293:23): [True: 122k, False: 622]
  ------------------
 1294|   122k|        if (val == 0) [[unlikely]] {
  ------------------
  |  Branch (1294:13): [True: 300, False: 122k]
  ------------------
 1295|    300|          return ipv4_fast_fail;
 1296|    300|        }
 1297|   122k|        val = val * 10u + static_cast<uint32_t>(c - '0');
 1298|   122k|        ++p;
 1299|   122k|        if (p < pend) {
  ------------------
  |  Branch (1299:13): [True: 122k, False: 398]
  ------------------
 1300|   122k|          c = *p;
 1301|   122k|          if (c >= '0' && c <= '9') {
  ------------------
  |  Branch (1301:15): [True: 121k, False: 744]
  |  Branch (1301:27): [True: 121k, False: 114]
  ------------------
 1302|   121k|            val = val * 10u + static_cast<uint32_t>(c - '0');
 1303|   121k|            ++p;
 1304|   121k|            if (val > 255u) [[unlikely]] {
  ------------------
  |  Branch (1304:17): [True: 1.43k, False: 119k]
  ------------------
 1305|  1.43k|              return ipv4_fast_fail;
 1306|  1.43k|            }
 1307|   121k|          }
 1308|   122k|        }
 1309|   122k|      }
 1310|   234k|    }
 1311|   308k|    ipv4 = (ipv4 << 8) | val;
 1312|   308k|    if (i < 3) {
  ------------------
  |  Branch (1312:9): [True: 231k, False: 76.7k]
  ------------------
 1313|   231k|      if (p == pend || *p != '.') [[unlikely]] {
  ------------------
  |  Branch (1313:11): [True: 106, False: 231k]
  |  Branch (1313:24): [True: 870, False: 230k]
  ------------------
 1314|    976|        return ipv4_fast_fail;
 1315|    976|      }
 1316|   230k|      ++p;
 1317|   230k|    }
 1318|   308k|  }
 1319|  76.7k|  if (p != pend) {
  ------------------
  |  Branch (1319:7): [True: 350, False: 76.3k]
  ------------------
 1320|    350|    if (p == pend - 1 && *p == '.') {
  ------------------
  |  Branch (1320:9): [True: 154, False: 196]
  |  Branch (1320:26): [True: 14, False: 140]
  ------------------
 1321|     14|      return ipv4;
 1322|     14|    }
 1323|    336|    return ipv4_fast_fail;
 1324|    350|  }
 1325|  76.3k|  return ipv4;
 1326|  76.7k|}
_ZNK3ada3url15has_credentialsEv:
 7227|   914k|[[nodiscard]] ada_really_inline bool url::has_credentials() const noexcept {
 7228|   914k|  return !username.empty() || !password.empty();
  ------------------
  |  Branch (7228:10): [True: 150k, False: 763k]
  |  Branch (7228:31): [True: 594, False: 762k]
  ------------------
 7229|   914k|}
_ZNK3ada8url_base10is_specialEv:
 7192|  3.59M|    const noexcept {
 7193|  3.59M|  return type != ada::scheme::NOT_SPECIAL;
 7194|  3.59M|}
_ZNK2tl8expectedIN3ada3urlENS1_6errorsEEcvbEv:
 4030|   357k|  constexpr explicit operator bool() const noexcept { return this->m_has_val; }
_ZN2tl8expectedIN3ada3urlENS1_6errorsEEptEv:
 3999|   591k|  TL_EXPECTED_11_CONSTEXPR T* operator->() {
 4000|   591k|    TL_ASSERT(has_value());
  ------------------
  |  | 2052|   591k|#define TL_ASSERT(x) assert(x)
  ------------------
  |  Branch (4000:5): [True: 591k, False: 0]
  ------------------
 4001|   591k|    return valptr();
 4002|   591k|  }
_ZN2tl8expectedIN3ada3urlENS1_6errorsEE6valptrEv:
 3295|   591k|  T* valptr() { return std::addressof(this->m_val); }
_ZN2tl6detail21expected_storage_baseIN3ada3urlENS2_6errorsELb0ELb1EED2Ev:
 2627|   357k|  ~expected_storage_base() {
 2628|   357k|    if (m_has_val) {
  ------------------
  |  Branch (2628:9): [True: 354k, False: 2.88k]
  ------------------
 2629|   354k|      m_val.~T();
 2630|   354k|    }
 2631|   357k|  }
_ZNK3ada3url13get_href_sizeEv:
 7482|   808k|[[nodiscard]] inline size_t url::get_href_size() const noexcept {
 7483|   808k|  size_t size = 0;
 7484|   808k|  if (is_special()) {
  ------------------
  |  Branch (7484:7): [True: 803k, False: 5.31k]
  ------------------
 7485|   803k|    size += ada::scheme::details::is_special_list[type].size() + 1;
 7486|   803k|  } else {
 7487|  5.31k|    size += non_special_scheme.size() + 1;
 7488|  5.31k|  }
 7489|   808k|  if (host.has_value()) {
  ------------------
  |  Branch (7489:7): [True: 805k, False: 3.10k]
  ------------------
 7490|   805k|    size += host->size();
 7491|   805k|    size += 2;
 7492|   805k|    if (has_credentials()) {
  ------------------
  |  Branch (7492:9): [True: 97.9k, False: 707k]
  ------------------
 7493|  97.9k|      size += username.size();
 7494|  97.9k|      if (!password.empty()) {
  ------------------
  |  Branch (7494:11): [True: 94.6k, False: 3.31k]
  ------------------
 7495|  94.6k|        size += 1 + password.size();
 7496|  94.6k|      }
 7497|  97.9k|      size += 1;
 7498|  97.9k|    }
 7499|   805k|    if (port.has_value()) {
  ------------------
  |  Branch (7499:9): [True: 99.5k, False: 705k]
  ------------------
 7500|  99.5k|      size += 1;
 7501|  99.5k|      uint16_t p = *port;
 7502|  99.5k|      size += (p >= 10000)  ? 5
  ------------------
  |  Branch (7502:15): [True: 3.29k, False: 96.3k]
  ------------------
 7503|  99.5k|              : (p >= 1000) ? 4
  ------------------
  |  Branch (7503:17): [True: 91.6k, False: 4.66k]
  ------------------
 7504|  96.3k|              : (p >= 100)  ? 3
  ------------------
  |  Branch (7504:17): [True: 314, False: 4.35k]
  ------------------
 7505|  4.66k|              : (p >= 10)   ? 2
  ------------------
  |  Branch (7505:17): [True: 298, False: 4.05k]
  ------------------
 7506|  4.35k|                            : 1;
 7507|  99.5k|    }
 7508|   805k|  } else if (!has_opaque_path && path.starts_with("//")) {
  ------------------
  |  Branch (7508:14): [True: 1.20k, False: 1.90k]
  |  Branch (7508:34): [True: 92, False: 1.11k]
  ------------------
 7509|     92|    size += 2;
 7510|     92|  }
 7511|   808k|  size += path.size();
 7512|   808k|  if (query.has_value()) {
  ------------------
  |  Branch (7512:7): [True: 146k, False: 661k]
  ------------------
 7513|   146k|    size += 1 + query->size();
 7514|   146k|  }
 7515|   808k|  if (hash.has_value()) {
  ------------------
  |  Branch (7515:7): [True: 107k, False: 700k]
  ------------------
 7516|   107k|    size += 1 + hash->size();
 7517|   107k|  }
 7518|   808k|  return size;
 7519|   808k|}
_ZN3ada8checkers8is_alphaEc:
 1257|   326k|constexpr bool is_alpha(char x) noexcept {
 1258|   326k|  return (to_lower(x) >= 'a') && (to_lower(x) <= 'z');
  ------------------
  |  Branch (1258:10): [True: 324k, False: 1.66k]
  |  Branch (1258:34): [True: 324k, False: 48]
  ------------------
 1259|   326k|}
_ZN3ada8checkers8to_lowerEc:
 1255|   650k|constexpr char to_lower(char x) noexcept { return (x | 0x20); }
_ZNR2tl8expectedIN3ada3urlENS1_6errorsEEdeIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v:
 4012|   591k|  TL_EXPECTED_11_CONSTEXPR U& operator*() & {
 4013|   591k|    TL_ASSERT(has_value());
  ------------------
  |  | 2052|   591k|#define TL_ASSERT(x) assert(x)
  ------------------
  |  Branch (4013:5): [True: 591k, False: 0]
  ------------------
 4014|   591k|    return val();
 4015|   591k|  }
_ZN2tl8expectedIN3ada3urlENS1_6errorsEE3valIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v:
 3304|   591k|  TL_EXPECTED_11_CONSTEXPR U& val() {
 3305|   591k|    return this->m_val;
 3306|   591k|  }
_ZN3ada3urlaSERKS0_:
 4988|   118k|  url& operator=(const url& u) = default;
_ZNK2tl8expectedIN3ada3urlENS1_6errorsEE9has_valueEv:
 4029|  1.42M|  constexpr bool has_value() const noexcept { return this->m_has_val; }
_ZN3ada3urlC2Ev:
 4984|   357k|  url() = default;
_ZN3ada3url26update_unencoded_base_hashENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 7332|  10.0k|inline void url::update_unencoded_base_hash(std::string_view input) {
 7333|       |  // We do the percent encoding
 7334|  10.0k|  hash = unicode::percent_encode(input,
 7335|  10.0k|                                 ada::character_sets::FRAGMENT_PERCENT_ENCODE);
 7336|  10.0k|}
_ZN3ada3url18update_base_searchENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKh:
 7339|  10.0k|                                    const uint8_t query_percent_encode_set[]) {
 7340|  10.0k|  query = ada::unicode::percent_encode(input, query_percent_encode_set);
 7341|  10.0k|}
_ZN3ada3url20update_base_hostnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 7330|     39|inline void url::update_base_hostname(std::string_view input) { host = input; }
_ZN3ada3url20update_base_pathnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 7347|  2.69k|inline void url::update_base_pathname(const std::string_view input) {
 7348|  2.69k|  path = input;
 7349|  2.69k|}
_ZN3ada3url10parse_portENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEb:
 7522|  23.8k|                                         bool check_trailing_content) noexcept {
 7523|  23.8k|  ada_log("parse_port('", view, "') ", view.size());
 7524|  23.8k|  if (!view.empty() && view[0] == '-') {
  ------------------
  |  Branch (7524:7): [True: 23.6k, False: 158]
  |  Branch (7524:24): [True: 4, False: 23.6k]
  ------------------
 7525|      4|    ada_log("parse_port: view[0] == '0' && view.size() > 1");
 7526|      4|    is_valid = false;
 7527|      4|    return 0;
 7528|      4|  }
 7529|  23.8k|  uint16_t parsed_port{};
 7530|  23.8k|  auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port);
 7531|  23.8k|  if (r.ec == std::errc::result_out_of_range) {
  ------------------
  |  Branch (7531:7): [True: 24, False: 23.7k]
  ------------------
 7532|     24|    ada_log("parse_port: r.ec == std::errc::result_out_of_range");
 7533|     24|    is_valid = false;
 7534|     24|    return 0;
 7535|     24|  }
 7536|  23.7k|  ada_log("parse_port: ", parsed_port);
 7537|  23.7k|  const auto consumed = size_t(r.ptr - view.data());
 7538|  23.7k|  ada_log("parse_port: consumed ", consumed);
 7539|  23.7k|  if (check_trailing_content) {
  ------------------
  |  Branch (7539:7): [True: 23.7k, False: 0]
  ------------------
 7540|  23.7k|    is_valid &=
 7541|  23.7k|        (consumed == view.size() || view[consumed] == '/' ||
  ------------------
  |  Branch (7541:10): [True: 415, False: 23.3k]
  |  Branch (7541:37): [True: 23.0k, False: 279]
  ------------------
 7542|    279|         view[consumed] == '?' || (is_special() && view[consumed] == '\\'));
  ------------------
  |  Branch (7542:10): [True: 106, False: 173]
  |  Branch (7542:36): [True: 163, False: 10]
  |  Branch (7542:52): [True: 53, False: 110]
  ------------------
 7543|  23.7k|  }
 7544|  23.7k|  ada_log("parse_port: is_valid = ", is_valid);
 7545|  23.7k|  if (is_valid) {
  ------------------
  |  Branch (7545:7): [True: 23.6k, False: 120]
  ------------------
 7546|       |    // scheme_default_port can return 0, and we should allow 0 as a base port.
 7547|  23.6k|    auto default_port = scheme_default_port();
 7548|  23.6k|    bool is_port_valid = (default_port == 0 && parsed_port == 0) ||
  ------------------
  |  Branch (7548:27): [True: 146, False: 23.5k]
  |  Branch (7548:48): [True: 41, False: 105]
  ------------------
 7549|  23.6k|                         (default_port != parsed_port);
  ------------------
  |  Branch (7549:26): [True: 23.6k, False: 3]
  ------------------
 7550|  23.6k|    port = (r.ec == std::errc() && is_port_valid) ? std::optional(parsed_port)
  ------------------
  |  Branch (7550:13): [True: 23.3k, False: 277]
  |  Branch (7550:36): [True: 23.3k, False: 3]
  ------------------
 7551|  23.6k|                                                  : std::nullopt;
 7552|  23.6k|  }
 7553|  23.7k|  return consumed;
 7554|  23.8k|}
_ZNK3ada8url_base19scheme_default_portEv:
 7201|  47.3k|url_base::scheme_default_port() const noexcept {
 7202|  47.3k|  return scheme::get_special_port(type);
 7203|  47.3k|}
_ZN3ada6scheme16get_special_portENS0_4typeE:
 6706|  47.3k|constexpr uint16_t get_special_port(ada::scheme::type type) noexcept {
 6707|  47.3k|  return details::special_ports[int(type)];
 6708|  47.3k|}
_ZNK3ada3url12get_pathnameEv:
 7253|   118k|[[nodiscard]] constexpr std::string_view url::get_pathname() const noexcept {
 7254|   118k|  return path;
 7255|   118k|}
_ZN3ada8checkers23is_windows_drive_letterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 1261|  5.66k|constexpr bool is_windows_drive_letter(std::string_view input) noexcept {
 1262|  5.66k|  return input.size() >= 2 &&
  ------------------
  |  Branch (1262:10): [True: 4.25k, False: 1.41k]
  ------------------
 1263|  4.25k|         (is_alpha(input[0]) && ((input[1] == ':') || (input[1] == '|'))) &&
  ------------------
  |  Branch (1263:11): [True: 2.64k, False: 1.60k]
  |  Branch (1263:34): [True: 340, False: 2.30k]
  |  Branch (1263:55): [True: 130, False: 2.17k]
  ------------------
 1264|    470|         ((input.size() == 2) || (input[2] == '/' || input[2] == '\\' ||
  ------------------
  |  Branch (1264:11): [True: 100, False: 370]
  |  Branch (1264:35): [True: 60, False: 310]
  |  Branch (1264:54): [True: 6, False: 304]
  ------------------
 1265|    304|                                  input[2] == '?' || input[2] == '#'));
  ------------------
  |  Branch (1265:35): [True: 0, False: 304]
  |  Branch (1265:54): [True: 0, False: 304]
  ------------------
 1266|  5.66k|}
_ZN3ada8checkers34is_normalized_windows_drive_letterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 1269|    146|    std::string_view input) noexcept {
 1270|    146|  return input.size() == 2 && (is_alpha(input[0]) && (input[1] == ':'));
  ------------------
  |  Branch (1270:10): [True: 52, False: 94]
  |  Branch (1270:32): [True: 34, False: 18]
  |  Branch (1270:54): [True: 24, False: 10]
  ------------------
 1271|    146|}
_ZN3ada3url20set_protocol_as_fileEv:
 7375|  1.28k|constexpr void url::set_protocol_as_file() { type = ada::scheme::type::FILE; }
_ZN3ada7helpers14leading_zeroesEj:
 1934|   168k|inline int leading_zeroes(uint32_t input_num) noexcept {
 1935|       |#if ADA_REGULAR_VISUAL_STUDIO
 1936|       |  unsigned long leading_zero(0);
 1937|       |  unsigned long in(input_num);
 1938|       |  return _BitScanReverse(&leading_zero, in) ? int(31 - leading_zero) : 32;
 1939|       |#else
 1940|   168k|  return __builtin_clz(input_num);
 1941|   168k|#endif  // ADA_REGULAR_VISUAL_STUDIO
 1942|   168k|}
_ZN3ada14url_aggregator7reserveEj:
 8901|   160k|constexpr void ada::url_aggregator::reserve(uint32_t capacity) {
 8902|   160k|  buffer.reserve(capacity);
 8903|   160k|}
_ZN3ada14url_aggregator20update_base_pathnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8391|  23.0k|inline void url_aggregator::update_base_pathname(const std::string_view input) {
 8392|  23.0k|  ada_log("url_aggregator::update_base_pathname '", input, "' [", input.size(),
 8393|  23.0k|          " bytes] \n", to_diagram());
 8394|  23.0k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 8395|  23.0k|  ADA_ASSERT_TRUE(validate());
 8396|       |
 8397|  23.0k|  const bool begins_with_dashdash = input.starts_with("//");
 8398|  23.0k|  if (!begins_with_dashdash && has_dash_dot()) {
  ------------------
  |  Branch (8398:7): [True: 22.5k, False: 513]
  |  Branch (8398:32): [True: 0, False: 22.5k]
  ------------------
 8399|       |    // We must delete the ./
 8400|      0|    delete_dash_dot();
 8401|      0|  }
 8402|       |
 8403|  23.0k|  if (begins_with_dashdash && !has_opaque_path && !has_authority() &&
  ------------------
  |  Branch (8403:7): [True: 513, False: 22.5k]
  |  Branch (8403:31): [True: 513, False: 0]
  |  Branch (8403:51): [True: 24, False: 489]
  ------------------
 8404|     24|      !has_dash_dot()) {
  ------------------
  |  Branch (8404:7): [True: 24, False: 0]
  ------------------
 8405|       |    // If url's host is null, url does not have an opaque path, url's path's
 8406|       |    // size is greater than 1, then append U+002F (/) followed by U+002E (.) to
 8407|       |    // output.
 8408|     24|    buffer.insert(components.pathname_start, "/.");
 8409|     24|    components.pathname_start += 2;
 8410|     24|    if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (8410:9): [True: 0, False: 24]
  ------------------
 8411|      0|      components.search_start += 2;
 8412|      0|    }
 8413|     24|    if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8413:9): [True: 0, False: 24]
  ------------------
 8414|      0|      components.hash_start += 2;
 8415|      0|    }
 8416|     24|  }
 8417|       |
 8418|  23.0k|  uint32_t difference = replace_and_resize(
 8419|  23.0k|      components.pathname_start,
 8420|  23.0k|      components.pathname_start + get_pathname_length(), input);
 8421|  23.0k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (8421:7): [True: 0, False: 23.0k]
  ------------------
 8422|      0|    components.search_start += difference;
 8423|      0|  }
 8424|  23.0k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8424:7): [True: 0, False: 23.0k]
  ------------------
 8425|      0|    components.hash_start += difference;
 8426|      0|  }
 8427|  23.0k|  ADA_ASSERT_TRUE(validate());
 8428|  23.0k|}
_ZN3ada14url_aggregator18replace_and_resizeEjjNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8234|   189k|    uint32_t start, uint32_t end, std::string_view input) {
 8235|   189k|  uint32_t current_length = end - start;
 8236|   189k|  uint32_t input_size = uint32_t(input.size());
 8237|   189k|  uint32_t new_difference = input_size - current_length;
 8238|       |
 8239|   189k|  if (current_length == 0) {
  ------------------
  |  Branch (8239:7): [True: 158k, False: 31.2k]
  ------------------
 8240|   158k|    buffer.insert(start, input);
 8241|   158k|  } else if (input_size == current_length) {
  ------------------
  |  Branch (8241:14): [True: 364, False: 30.8k]
  ------------------
 8242|    364|    buffer.replace(start, input_size, input);
 8243|  30.8k|  } else if (input_size < current_length) {
  ------------------
  |  Branch (8243:14): [True: 32, False: 30.8k]
  ------------------
 8244|     32|    buffer.erase(start, current_length - input_size);
 8245|     32|    buffer.replace(start, input_size, input);
 8246|  30.8k|  } else {
 8247|  30.8k|    buffer.replace(start, current_length, input.substr(0, current_length));
 8248|  30.8k|    buffer.insert(start + current_length, input.substr(current_length));
 8249|  30.8k|  }
 8250|       |
 8251|   189k|  return new_difference;
 8252|   189k|}
_ZNK3ada14url_aggregator19get_pathname_lengthEv:
 8283|  23.0k|url_aggregator::get_pathname_length() const noexcept {
 8284|  23.0k|  ada_log("url_aggregator::get_pathname_length");
 8285|  23.0k|  uint32_t ending_index = uint32_t(buffer.size());
 8286|  23.0k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (8286:7): [True: 0, False: 23.0k]
  ------------------
 8287|      0|    ending_index = components.search_start;
 8288|  23.0k|  } else if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8288:14): [True: 0, False: 23.0k]
  ------------------
 8289|      0|    ending_index = components.hash_start;
 8290|      0|  }
 8291|  23.0k|  return ending_index - components.pathname_start;
 8292|  23.0k|}
_ZNK3ada14url_aggregator12get_pathnameEv:
 9228|   138k|    ada_lifetime_bound {
 9229|   138k|  ada_log("url_aggregator::get_pathname pathname_start = ",
 9230|   138k|          components.pathname_start, " buffer.size() = ", buffer.size(),
 9231|   138k|          " components.search_start = ", components.search_start,
 9232|   138k|          " components.hash_start = ", components.hash_start);
 9233|   138k|  auto ending_index = uint32_t(buffer.size());
 9234|   138k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (9234:7): [True: 24.7k, False: 113k]
  ------------------
 9235|  24.7k|    ending_index = components.search_start;
 9236|   113k|  } else if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (9236:14): [True: 8.01k, False: 105k]
  ------------------
 9237|  8.01k|    ending_index = components.hash_start;
 9238|  8.01k|  }
 9239|   138k|  return helpers::substring(buffer, components.pathname_start, ending_index);
 9240|   138k|}
_ZN3ada14url_aggregator26update_unencoded_base_hashENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8210|  10.0k|inline void url_aggregator::update_unencoded_base_hash(std::string_view input) {
 8211|  10.0k|  ada_log("url_aggregator::update_unencoded_base_hash ", input, " [",
 8212|  10.0k|          input.size(), " bytes], buffer is '", buffer, "' [", buffer.size(),
 8213|  10.0k|          " bytes] components.hash_start = ", components.hash_start);
 8214|  10.0k|  ADA_ASSERT_TRUE(validate());
 8215|  10.0k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 8216|  10.0k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8216:7): [True: 0, False: 10.0k]
  ------------------
 8217|      0|    buffer.resize(components.hash_start);
 8218|      0|  }
 8219|  10.0k|  components.hash_start = uint32_t(buffer.size());
 8220|  10.0k|  buffer += "#";
 8221|  10.0k|  bool encoding_required = unicode::percent_encode<true>(
 8222|  10.0k|      input, ada::character_sets::FRAGMENT_PERCENT_ENCODE, buffer);
 8223|       |  // When encoding_required is false, then buffer is left unchanged, and percent
 8224|       |  // encoding was not deemed required.
 8225|  10.0k|  if (!encoding_required) {
  ------------------
  |  Branch (8225:7): [True: 9.92k, False: 130]
  ------------------
 8226|  9.92k|    buffer.append(input);
 8227|  9.92k|  }
 8228|  10.0k|  ada_log("url_aggregator::update_unencoded_base_hash final buffer is '",
 8229|  10.0k|          buffer, "' [", buffer.size(), " bytes]");
 8230|  10.0k|  ADA_ASSERT_TRUE(validate());
 8231|  10.0k|}
_ZN3ada14url_aggregator20append_base_passwordENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8619|  30.7k|inline void url_aggregator::append_base_password(const std::string_view input) {
 8620|  30.7k|  ada_log("url_aggregator::append_base_password ", input, " ", to_string(),
 8621|  30.7k|          "\n", to_diagram());
 8622|  30.7k|  ADA_ASSERT_TRUE(validate());
 8623|  30.7k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 8624|       |#if ADA_DEVELOPMENT_CHECKS
 8625|       |  // computing the expected password.
 8626|       |  std::string password_expected = std::string(get_password());
 8627|       |  password_expected.append(input);
 8628|       |#endif  // ADA_DEVELOPMENT_CHECKS
 8629|  30.7k|  add_authority_slashes_if_needed();
 8630|       |
 8631|       |  // If input is empty, do nothing.
 8632|  30.7k|  if (input.empty()) {
  ------------------
  |  Branch (8632:7): [True: 3.13k, False: 27.6k]
  ------------------
 8633|  3.13k|    return;
 8634|  3.13k|  }
 8635|       |
 8636|  27.6k|  uint32_t difference = uint32_t(input.size());
 8637|  27.6k|  if (has_password()) {
  ------------------
  |  Branch (8637:7): [True: 5.44k, False: 22.1k]
  ------------------
 8638|  5.44k|    buffer.insert(components.host_start, input);
 8639|  22.1k|  } else {
 8640|  22.1k|    difference++;  // Increment for ":"
 8641|  22.1k|    buffer.insert(components.username_end, ":");
 8642|  22.1k|    buffer.insert(components.username_end + 1, input);
 8643|  22.1k|  }
 8644|  27.6k|  components.host_start += difference;
 8645|       |
 8646|       |  // The following line is required to add "@" to hostname. When updating
 8647|       |  // password if hostname does not start with "@", it is "append_base_password"s
 8648|       |  // responsibility to set it.
 8649|  27.6k|  if (buffer[components.host_start] != '@') {
  ------------------
  |  Branch (8649:7): [True: 152, False: 27.4k]
  ------------------
 8650|    152|    buffer.insert(components.host_start, "@");
 8651|    152|    difference++;
 8652|    152|  }
 8653|       |
 8654|  27.6k|  components.host_end += difference;
 8655|  27.6k|  components.pathname_start += difference;
 8656|  27.6k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (8656:7): [True: 0, False: 27.6k]
  ------------------
 8657|      0|    components.search_start += difference;
 8658|      0|  }
 8659|  27.6k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8659:7): [True: 0, False: 27.6k]
  ------------------
 8660|      0|    components.hash_start += difference;
 8661|      0|  }
 8662|       |#if ADA_DEVELOPMENT_CHECKS
 8663|       |  std::string password_after(get_password());
 8664|       |  ADA_ASSERT_EQUAL(
 8665|       |      password_expected, password_after,
 8666|       |      "append_base_password problem after inserting " + std::string(input));
 8667|       |#endif  // ADA_DEVELOPMENT_CHECKS
 8668|  27.6k|  ADA_ASSERT_TRUE(validate());
 8669|  27.6k|}
_ZN3ada14url_aggregator31add_authority_slashes_if_neededEv:
 8875|   237k|inline void ada::url_aggregator::add_authority_slashes_if_needed() {
 8876|   237k|  ada_log("url_aggregator::add_authority_slashes_if_needed");
 8877|   237k|  ADA_ASSERT_TRUE(validate());
 8878|       |  // Protocol setter will insert `http:` to the URL. It is up to hostname setter
 8879|       |  // to insert
 8880|       |  // `//` initially to the buffer, since it depends on the hostname existence.
 8881|   237k|  if (has_authority()) {
  ------------------
  |  Branch (8881:7): [True: 79.8k, False: 157k]
  ------------------
 8882|  79.8k|    return;
 8883|  79.8k|  }
 8884|       |  // Performance: the common case is components.protocol_end == buffer.size()
 8885|       |  // Optimization opportunity: in many cases, the "//" is part of the input and
 8886|       |  // the insert could be fused with another insert.
 8887|   157k|  buffer.insert(components.protocol_end, "//");
 8888|   157k|  components.username_end += 2;
 8889|   157k|  components.host_start += 2;
 8890|   157k|  components.host_end += 2;
 8891|   157k|  components.pathname_start += 2;
 8892|   157k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (8892:7): [True: 0, False: 157k]
  ------------------
 8893|      0|    components.search_start += 2;
 8894|      0|  }
 8895|   157k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8895:7): [True: 0, False: 157k]
  ------------------
 8896|      0|    components.hash_start += 2;
 8897|      0|  }
 8898|   157k|  ADA_ASSERT_TRUE(validate());
 8899|   157k|}
_ZN3ada14url_aggregator20append_base_usernameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8501|  39.9k|inline void url_aggregator::append_base_username(const std::string_view input) {
 8502|  39.9k|  ada_log("url_aggregator::append_base_username ", input);
 8503|  39.9k|  ADA_ASSERT_TRUE(validate());
 8504|  39.9k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 8505|       |#if ADA_DEVELOPMENT_CHECKS
 8506|       |  // computing the expected password.
 8507|       |  std::string username_expected(get_username());
 8508|       |  username_expected.append(input);
 8509|       |#endif  // ADA_DEVELOPMENT_CHECKS
 8510|  39.9k|  add_authority_slashes_if_needed();
 8511|       |
 8512|       |  // If input is empty, do nothing.
 8513|  39.9k|  if (input.empty()) {
  ------------------
  |  Branch (8513:7): [True: 7.16k, False: 32.7k]
  ------------------
 8514|  7.16k|    return;
 8515|  7.16k|  }
 8516|       |
 8517|  32.7k|  uint32_t difference = uint32_t(input.size());
 8518|  32.7k|  buffer.insert(components.username_end, input);
 8519|  32.7k|  components.username_end += difference;
 8520|  32.7k|  components.host_start += difference;
 8521|       |
 8522|  32.7k|  if (buffer[components.host_start] != '@' &&
  ------------------
  |  Branch (8522:7): [True: 23.0k, False: 9.74k]
  ------------------
 8523|  23.0k|      components.host_start != components.host_end) {
  ------------------
  |  Branch (8523:7): [True: 23.0k, False: 0]
  ------------------
 8524|  23.0k|    buffer.insert(components.host_start, "@");
 8525|  23.0k|    difference++;
 8526|  23.0k|  }
 8527|       |
 8528|  32.7k|  components.host_end += difference;
 8529|  32.7k|  components.pathname_start += difference;
 8530|  32.7k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (8530:7): [True: 0, False: 32.7k]
  ------------------
 8531|      0|    components.search_start += difference;
 8532|      0|  }
 8533|  32.7k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8533:7): [True: 0, False: 32.7k]
  ------------------
 8534|      0|    components.hash_start += difference;
 8535|      0|  }
 8536|       |#if ADA_DEVELOPMENT_CHECKS
 8537|       |  std::string username_after(get_username());
 8538|       |  ADA_ASSERT_EQUAL(
 8539|       |      username_expected, username_after,
 8540|       |      "append_base_username problem after inserting " + std::string(input));
 8541|       |#endif  // ADA_DEVELOPMENT_CHECKS
 8542|  32.7k|  ADA_ASSERT_TRUE(validate());
 8543|  32.7k|}
_ZNK3ada14url_aggregator8get_hrefEv:
 8979|   709k|    const noexcept ada_lifetime_bound {
 8980|   709k|  ada_log("url_aggregator::get_href");
 8981|   709k|  return buffer;
 8982|   709k|}
_ZN3ada14url_aggregator16update_base_portEj:
 8671|  23.3k|inline void url_aggregator::update_base_port(uint32_t input) {
 8672|  23.3k|  ada_log("url_aggregator::update_base_port");
 8673|  23.3k|  ADA_ASSERT_TRUE(validate());
 8674|  23.3k|  if (input == url_components::omitted) {
  ------------------
  |  Branch (8674:7): [True: 0, False: 23.3k]
  ------------------
 8675|      0|    clear_port();
 8676|      0|    return;
 8677|      0|  }
 8678|       |  // calling std::to_string(input.value()) is unfortunate given that the port
 8679|       |  // value is probably already available as a string.
 8680|  23.3k|  std::string value = helpers::concat(":", std::to_string(input));
 8681|  23.3k|  uint32_t difference = uint32_t(value.size());
 8682|       |
 8683|  23.3k|  if (components.port != url_components::omitted) {
  ------------------
  |  Branch (8683:7): [True: 0, False: 23.3k]
  ------------------
 8684|      0|    difference -= components.pathname_start - components.host_end;
 8685|      0|    buffer.erase(components.host_end,
 8686|      0|                 components.pathname_start - components.host_end);
 8687|      0|  }
 8688|       |
 8689|  23.3k|  buffer.insert(components.host_end, value);
 8690|  23.3k|  components.pathname_start += difference;
 8691|  23.3k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (8691:7): [True: 0, False: 23.3k]
  ------------------
 8692|      0|    components.search_start += difference;
 8693|      0|  }
 8694|  23.3k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8694:7): [True: 0, False: 23.3k]
  ------------------
 8695|      0|    components.hash_start += difference;
 8696|      0|  }
 8697|  23.3k|  components.port = input;
 8698|  23.3k|  ADA_ASSERT_TRUE(validate());
 8699|  23.3k|}
_ZN3ada7helpers6concatIJPKcNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEEEESA_DpT_:
 1924|  23.3k|std::string concat(Args... args) {
 1925|  23.3k|  std::string answer;
 1926|  23.3k|  inner_concat(answer, args...);
 1927|  23.3k|  return answer;
 1928|  23.3k|}
_ZN3ada7helpers12inner_concatIPKcJNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEEEEvRSA_T_DpT0_:
 1913|  23.3k|inline void inner_concat(std::string& buffer, T t, Args... args) {
 1914|  23.3k|  buffer.append(t);
 1915|  23.3k|  return inner_concat(buffer, args...);
 1916|  23.3k|}
_ZN3ada7helpers12inner_concatINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEJEEEvRS8_T_:
 1905|  23.3k|inline void inner_concat(std::string& buffer, T t) {
 1906|  23.3k|  buffer.append(t);
 1907|  23.3k|}
_ZN3ada14url_aggregator18update_base_searchENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKh:
 8339|  10.0k|    std::string_view input, const uint8_t query_percent_encode_set[]) {
 8340|  10.0k|  ada_log("url_aggregator::update_base_search ", input,
 8341|  10.0k|          " with encoding parameter ", to_string(), "\n", to_diagram());
 8342|  10.0k|  ADA_ASSERT_TRUE(validate());
 8343|  10.0k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 8344|       |
 8345|  10.0k|  if (components.hash_start == url_components::omitted) {
  ------------------
  |  Branch (8345:7): [True: 10.0k, False: 0]
  ------------------
 8346|  10.0k|    if (components.search_start == url_components::omitted) {
  ------------------
  |  Branch (8346:9): [True: 10.0k, False: 0]
  ------------------
 8347|  10.0k|      components.search_start = uint32_t(buffer.size());
 8348|  10.0k|      buffer += "?";
 8349|  10.0k|    } else {
 8350|      0|      buffer.resize(components.search_start + 1);
 8351|      0|    }
 8352|       |
 8353|  10.0k|    bool encoding_required =
 8354|  10.0k|        unicode::percent_encode<true>(input, query_percent_encode_set, buffer);
 8355|       |    // When encoding_required is false, then buffer is left unchanged, and
 8356|       |    // percent encoding was not deemed required.
 8357|  10.0k|    if (!encoding_required) {
  ------------------
  |  Branch (8357:9): [True: 9.87k, False: 211]
  ------------------
 8358|  9.87k|      buffer.append(input);
 8359|  9.87k|    }
 8360|  10.0k|  } else {
 8361|      0|    if (components.search_start == url_components::omitted) {
  ------------------
  |  Branch (8361:9): [True: 0, False: 0]
  ------------------
 8362|      0|      components.search_start = components.hash_start;
 8363|      0|    } else {
 8364|      0|      buffer.erase(components.search_start,
 8365|      0|                   components.hash_start - components.search_start);
 8366|      0|      components.hash_start = components.search_start;
 8367|      0|    }
 8368|       |
 8369|      0|    buffer.insert(components.search_start, "?");
 8370|      0|    size_t idx =
 8371|      0|        ada::unicode::percent_encode_index(input, query_percent_encode_set);
 8372|      0|    if (idx == input.size()) {
  ------------------
  |  Branch (8372:9): [True: 0, False: 0]
  ------------------
 8373|      0|      buffer.insert(components.search_start + 1, input);
 8374|      0|      components.hash_start += uint32_t(input.size() + 1);  // Do not forget `?`
 8375|      0|    } else {
 8376|      0|      buffer.insert(components.search_start + 1, input, 0, idx);
 8377|      0|      input.remove_prefix(idx);
 8378|       |      // We only create a temporary string if we need percent encoding and
 8379|       |      // we attempt to create as small a temporary string as we can.
 8380|      0|      std::string encoded =
 8381|      0|          ada::unicode::percent_encode(input, query_percent_encode_set);
 8382|      0|      buffer.insert(components.search_start + idx + 1, encoded);
 8383|      0|      components.hash_start +=
 8384|      0|          uint32_t(encoded.size() + idx + 1);  // Do not forget `?`
 8385|      0|    }
 8386|      0|  }
 8387|       |
 8388|  10.0k|  ADA_ASSERT_TRUE(validate());
 8389|  10.0k|}
_ZN3ada14url_aggregator20update_base_hostnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8254|   166k|inline void url_aggregator::update_base_hostname(const std::string_view input) {
 8255|   166k|  ada_log("url_aggregator::update_base_hostname ", input, " [", input.size(),
 8256|   166k|          " bytes], buffer is '", buffer, "' [", buffer.size(), " bytes]");
 8257|   166k|  ADA_ASSERT_TRUE(validate());
 8258|   166k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 8259|       |
 8260|       |  // This next line is required for when parsing a URL like `foo://`
 8261|   166k|  add_authority_slashes_if_needed();
 8262|       |
 8263|   166k|  bool has_credentials = components.protocol_end + 2 < components.host_start;
 8264|   166k|  uint32_t new_difference =
 8265|   166k|      replace_and_resize(components.host_start, components.host_end, input);
 8266|       |
 8267|   166k|  if (has_credentials) {
  ------------------
  |  Branch (8267:7): [True: 23.0k, False: 143k]
  ------------------
 8268|  23.0k|    buffer.insert(components.host_start, "@");
 8269|  23.0k|    new_difference++;
 8270|  23.0k|  }
 8271|   166k|  components.host_end += new_difference;
 8272|   166k|  components.pathname_start += new_difference;
 8273|   166k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (8273:7): [True: 0, False: 166k]
  ------------------
 8274|      0|    components.search_start += new_difference;
 8275|      0|  }
 8276|   166k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8276:7): [True: 0, False: 166k]
  ------------------
 8277|      0|    components.hash_start += new_difference;
 8278|      0|  }
 8279|   166k|  ADA_ASSERT_TRUE(validate());
 8280|   166k|}
_ZN3ada14url_aggregator10parse_portENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEb:
 8989|  23.8k|url_aggregator::parse_port(std::string_view view, bool check_trailing_content) {
 8990|  23.8k|  ada_log("url_aggregator::parse_port('", view, "') ", view.size());
 8991|  23.8k|  if (!view.empty() && view[0] == '-') {
  ------------------
  |  Branch (8991:7): [True: 23.6k, False: 158]
  |  Branch (8991:24): [True: 4, False: 23.6k]
  ------------------
 8992|      4|    ada_log("parse_port: view[0] == '0' && view.size() > 1");
 8993|      4|    is_valid = false;
 8994|      4|    return 0;
 8995|      4|  }
 8996|  23.8k|  uint16_t parsed_port{};
 8997|  23.8k|  auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port);
 8998|  23.8k|  if (r.ec == std::errc::result_out_of_range) {
  ------------------
  |  Branch (8998:7): [True: 24, False: 23.7k]
  ------------------
 8999|     24|    ada_log("parse_port: r.ec == std::errc::result_out_of_range");
 9000|     24|    is_valid = false;
 9001|     24|    return 0;
 9002|     24|  }
 9003|  23.7k|  ada_log("parse_port: ", parsed_port);
 9004|  23.7k|  const size_t consumed = size_t(r.ptr - view.data());
 9005|  23.7k|  ada_log("parse_port: consumed ", consumed);
 9006|  23.7k|  if (check_trailing_content) {
  ------------------
  |  Branch (9006:7): [True: 23.7k, False: 0]
  ------------------
 9007|  23.7k|    is_valid &=
 9008|  23.7k|        (consumed == view.size() || view[consumed] == '/' ||
  ------------------
  |  Branch (9008:10): [True: 415, False: 23.3k]
  |  Branch (9008:37): [True: 23.0k, False: 279]
  ------------------
 9009|    279|         view[consumed] == '?' || (is_special() && view[consumed] == '\\'));
  ------------------
  |  Branch (9009:10): [True: 106, False: 173]
  |  Branch (9009:36): [True: 163, False: 10]
  |  Branch (9009:52): [True: 53, False: 110]
  ------------------
 9010|  23.7k|  }
 9011|  23.7k|  ada_log("parse_port: is_valid = ", is_valid);
 9012|  23.7k|  if (is_valid) {
  ------------------
  |  Branch (9012:7): [True: 23.6k, False: 120]
  ------------------
 9013|  23.6k|    ada_log("parse_port", r.ec == std::errc());
 9014|       |    // scheme_default_port can return 0, and we should allow 0 as a base port.
 9015|  23.6k|    auto default_port = scheme_default_port();
 9016|  23.6k|    bool is_port_valid = (default_port == 0 && parsed_port == 0) ||
  ------------------
  |  Branch (9016:27): [True: 146, False: 23.5k]
  |  Branch (9016:48): [True: 41, False: 105]
  ------------------
 9017|  23.6k|                         (default_port != parsed_port);
  ------------------
  |  Branch (9017:26): [True: 23.6k, False: 3]
  ------------------
 9018|  23.6k|    if (r.ec == std::errc() && is_port_valid) {
  ------------------
  |  Branch (9018:9): [True: 23.3k, False: 277]
  |  Branch (9018:32): [True: 23.3k, False: 3]
  ------------------
 9019|  23.3k|      update_base_port(parsed_port);
 9020|  23.3k|    } else {
 9021|    280|      clear_port();
 9022|    280|    }
 9023|  23.6k|  }
 9024|  23.7k|  return consumed;
 9025|  23.8k|}
_ZN3ada14url_aggregator20set_protocol_as_fileEv:
 9027|  1.28k|constexpr void url_aggregator::set_protocol_as_file() {
 9028|  1.28k|  ada_log("url_aggregator::set_protocol_as_file ");
 9029|  1.28k|  ADA_ASSERT_TRUE(validate());
 9030|  1.28k|  type = ada::scheme::type::FILE;
 9031|       |  // next line could overflow but unsigned arithmetic has well-defined
 9032|       |  // overflows.
 9033|  1.28k|  uint32_t new_difference = 5 - components.protocol_end;
 9034|       |
 9035|  1.28k|  if (buffer.empty()) {
  ------------------
  |  Branch (9035:7): [True: 0, False: 1.28k]
  ------------------
 9036|      0|    buffer.append("file:");
 9037|  1.28k|  } else {
 9038|  1.28k|    buffer.erase(0, components.protocol_end);
 9039|  1.28k|    buffer.insert(0, "file:");
 9040|  1.28k|  }
 9041|  1.28k|  components.protocol_end = 5;
 9042|       |
 9043|       |  // Update the rest of the components.
 9044|  1.28k|  components.username_end += new_difference;
 9045|  1.28k|  components.host_start += new_difference;
 9046|  1.28k|  components.host_end += new_difference;
 9047|  1.28k|  components.pathname_start += new_difference;
 9048|  1.28k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (9048:7): [True: 0, False: 1.28k]
  ------------------
 9049|      0|    components.search_start += new_difference;
 9050|      0|  }
 9051|  1.28k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (9051:7): [True: 0, False: 1.28k]
  ------------------
 9052|      0|    components.hash_start += new_difference;
 9053|      0|  }
 9054|  1.28k|  ADA_ASSERT_TRUE(validate());
 9055|  1.28k|}
_ZN3ada7unicode20percent_encode_indexENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKh:
 8112|    566|                                              const uint8_t character_set[]) {
 8113|    566|  const char* data = input.data();
 8114|    566|  const size_t size = input.size();
 8115|       |
 8116|       |  // Process 8 bytes at a time using unrolled loop
 8117|    566|  size_t i = 0;
 8118|  1.30k|  for (; i + 8 <= size; i += 8) {
  ------------------
  |  Branch (8118:10): [True: 787, False: 520]
  ------------------
 8119|    787|    unsigned char chunk[8];
 8120|    787|    std::memcpy(&chunk, data + i,
 8121|    787|                8);  // entices compiler to unconditionally process 8 characters
 8122|       |
 8123|       |    // Check 8 characters at once
 8124|  6.86k|    for (size_t j = 0; j < 8; j++) {
  ------------------
  |  Branch (8124:24): [True: 6.12k, False: 741]
  ------------------
 8125|  6.12k|      if (character_sets::bit_at(character_set, chunk[j])) {
  ------------------
  |  Branch (8125:11): [True: 46, False: 6.08k]
  ------------------
 8126|     46|        return i + j;
 8127|     46|      }
 8128|  6.12k|    }
 8129|    787|  }
 8130|       |
 8131|       |  // Handle remaining bytes
 8132|  2.07k|  for (; i < size; i++) {
  ------------------
  |  Branch (8132:10): [True: 1.56k, False: 507]
  ------------------
 8133|  1.56k|    if (character_sets::bit_at(character_set, data[i])) {
  ------------------
  |  Branch (8133:9): [True: 13, False: 1.55k]
  ------------------
 8134|     13|      return i;
 8135|     13|    }
 8136|  1.56k|  }
 8137|       |
 8138|    507|  return size;
 8139|    520|}
_ZN3ada14url_aggregator10clear_portEv:
 8701|    280|inline void url_aggregator::clear_port() {
 8702|    280|  ada_log("url_aggregator::clear_port");
 8703|    280|  ADA_ASSERT_TRUE(validate());
 8704|    280|  if (components.port == url_components::omitted) {
  ------------------
  |  Branch (8704:7): [True: 280, False: 0]
  ------------------
 8705|    280|    return;
 8706|    280|  }
 8707|      0|  uint32_t length = components.pathname_start - components.host_end;
 8708|      0|  buffer.erase(components.host_end, length);
 8709|      0|  components.pathname_start -= length;
 8710|      0|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (8710:7): [True: 0, False: 0]
  ------------------
 8711|      0|    components.search_start -= length;
 8712|      0|  }
 8713|      0|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (8713:7): [True: 0, False: 0]
  ------------------
 8714|      0|    components.hash_start -= length;
 8715|      0|  }
 8716|      0|  components.port = url_components::omitted;
 8717|      0|  ADA_ASSERT_TRUE(validate());
 8718|      0|}
_ZNK3ada14url_aggregator13has_authorityEv:
 8866|   238k|    const noexcept {
 8867|   238k|  ada_log("url_aggregator::has_authority");
 8868|       |  // Performance: instead of doing this potentially expensive check, we could
 8869|       |  // have a boolean in the struct.
 8870|   238k|  return components.protocol_end + 2 <= components.host_start &&
  ------------------
  |  Branch (8870:10): [True: 80.3k, False: 157k]
  ------------------
 8871|  80.3k|         buffer[components.protocol_end] == '/' &&
  ------------------
  |  Branch (8871:10): [True: 80.3k, False: 0]
  ------------------
 8872|  80.3k|         buffer[components.protocol_end + 1] == '/';
  ------------------
  |  Branch (8872:10): [True: 80.3k, False: 0]
  ------------------
 8873|   238k|}
_ZNK3ada14url_aggregator12has_dash_dotEv:
 8946|  22.5k|[[nodiscard]] constexpr bool url_aggregator::has_dash_dot() const noexcept {
 8947|       |  // If url's host is null, url does not have an opaque path, url's path's size
 8948|       |  // is greater than 1, and url's path[0] is the empty string, then append
 8949|       |  // U+002F (/) followed by U+002E (.) to output.
 8950|  22.5k|  ada_log("url_aggregator::has_dash_dot");
 8951|       |#if ADA_DEVELOPMENT_CHECKS
 8952|       |  // If pathname_start and host_end are exactly two characters apart, then we
 8953|       |  // either have a one-digit port such as http://test.com:5?param=1 or else we
 8954|       |  // have a /.: sequence such as "non-spec:/.//". We test that this is the case.
 8955|       |  if (components.pathname_start == components.host_end + 2) {
 8956|       |    ADA_ASSERT_TRUE((buffer[components.host_end] == '/' &&
 8957|       |                     buffer[components.host_end + 1] == '.') ||
 8958|       |                    (buffer[components.host_end] == ':' &&
 8959|       |                     checkers::is_digit(buffer[components.host_end + 1])));
 8960|       |  }
 8961|       |  if (components.pathname_start == components.host_end + 2 &&
 8962|       |      buffer[components.host_end] == '/' &&
 8963|       |      buffer[components.host_end + 1] == '.') {
 8964|       |    ADA_ASSERT_TRUE(components.pathname_start + 1 < buffer.size());
 8965|       |    ADA_ASSERT_TRUE(buffer[components.pathname_start] == '/');
 8966|       |    ADA_ASSERT_TRUE(buffer[components.pathname_start + 1] == '/');
 8967|       |  }
 8968|       |#endif
 8969|       |  // Performance: it should be uncommon for components.pathname_start ==
 8970|       |  // components.host_end + 2 to be true. So we put this check first in the
 8971|       |  // sequence. Most times, we do not have an opaque path. Checking for '/.' is
 8972|       |  // more expensive, but should be uncommon.
 8973|  22.5k|  return components.pathname_start == components.host_end + 2 &&
  ------------------
  |  Branch (8973:10): [True: 407, False: 22.1k]
  ------------------
 8974|    407|         !has_opaque_path && buffer[components.host_end] == '/' &&
  ------------------
  |  Branch (8974:10): [True: 407, False: 0]
  |  Branch (8974:30): [True: 0, False: 407]
  ------------------
 8975|      0|         buffer[components.host_end + 1] == '.';
  ------------------
  |  Branch (8975:10): [True: 0, False: 0]
  ------------------
 8976|  22.5k|}
_ZNK2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEcvbEv:
 4030|   236k|  constexpr explicit operator bool() const noexcept { return this->m_has_val; }
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEptEv:
 3999|   591k|  TL_EXPECTED_11_CONSTEXPR T* operator->() {
 4000|   591k|    TL_ASSERT(has_value());
  ------------------
  |  | 2052|   591k|#define TL_ASSERT(x) assert(x)
  ------------------
  |  Branch (4000:5): [True: 591k, False: 0]
  ------------------
 4001|   591k|    return valptr();
 4002|   591k|  }
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEE6valptrEv:
 3295|   591k|  T* valptr() { return std::addressof(this->m_val); }
_ZNR2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEdeIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v:
 4012|   591k|  TL_EXPECTED_11_CONSTEXPR U& operator*() & {
 4013|   591k|    TL_ASSERT(has_value());
  ------------------
  |  | 2052|   591k|#define TL_ASSERT(x) assert(x)
  ------------------
  |  Branch (4013:5): [True: 591k, False: 0]
  ------------------
 4014|   591k|    return val();
 4015|   591k|  }
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEE3valIS2_TnPNSt3__19enable_ifIXntsr3std7is_voidIT_EE5valueEvE4typeELPv0EEERS8_v:
 3304|   591k|  TL_EXPECTED_11_CONSTEXPR U& val() {
 3305|   591k|    return this->m_val;
 3306|   591k|  }
_ZN3ada14url_aggregatoraSERKS0_:
 7693|   118k|  url_aggregator& operator=(const url_aggregator& u) = default;
_ZNK2tl8expectedIN3ada14url_aggregatorENS1_6errorsEE9has_valueEv:
 4029|  1.42M|  constexpr bool has_value() const noexcept { return this->m_has_val; }
_ZN2tl6detail21expected_storage_baseIN3ada14url_aggregatorENS2_6errorsELb0ELb1EED2Ev:
 2627|   357k|  ~expected_storage_base() {
 2628|   357k|    if (m_has_val) {
  ------------------
  |  Branch (2628:9): [True: 354k, False: 2.88k]
  ------------------
 2629|   354k|      m_val.~T();
 2630|   354k|    }
 2631|   357k|  }
_ZNK3ada14url_aggregator22has_non_empty_usernameEv:
 8905|   118k|constexpr bool url_aggregator::has_non_empty_username() const noexcept {
 8906|   118k|  ada_log("url_aggregator::has_non_empty_username");
 8907|   118k|  return components.protocol_end + 2 < components.username_end;
 8908|   118k|}
_ZN3ada7helpers9substringENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEmm:
 1846|   669k|                                                       size_t pos2) {
 1847|       |#if ADA_DEVELOPMENT_CHECKS
 1848|       |  if (pos2 < pos1) {
 1849|       |    std::cerr << "Negative-length substring: [" << pos1 << " to " << pos2 << ")"
 1850|       |              << std::endl;
 1851|       |    abort();
 1852|       |  }
 1853|       |#endif
 1854|   669k|  return input.substr(pos1, pos2 - pos1);
 1855|   669k|}
_ZNK3ada14url_aggregator22has_non_empty_passwordEv:
 8910|   118k|constexpr bool url_aggregator::has_non_empty_password() const noexcept {
 8911|   118k|  ada_log("url_aggregator::has_non_empty_password");
 8912|   118k|  return components.host_start > components.username_end;
 8913|   118k|}
_ZNK3ada14url_aggregator10is_at_pathEv:
 8295|   134k|    const noexcept {
 8296|   134k|  return buffer.size() == components.pathname_start;
 8297|   134k|}
_ZN3ada8checkers8is_digitEc:
 1253|   133k|constexpr bool is_digit(char x) noexcept { return (x >= '0') & (x <= '9'); }
_ZNK3ada14url_aggregator12has_passwordEv:
 8915|  27.6k|constexpr bool url_aggregator::has_password() const noexcept {
 8916|  27.6k|  ada_log("url_aggregator::has_password");
 8917|       |  // This function does not care about the length of the password
 8918|  27.6k|  return components.host_start > components.username_end &&
  ------------------
  |  Branch (8918:10): [True: 5.44k, False: 22.1k]
  ------------------
 8919|  5.44k|         buffer[components.username_end] == ':';
  ------------------
  |  Branch (8919:10): [True: 5.44k, False: 0]
  ------------------
 8920|  27.6k|}
_ZNK3ada14url_aggregator13get_href_sizeEv:
 8984|   236k|[[nodiscard]] constexpr size_t url_aggregator::get_href_size() const noexcept {
 8985|   236k|  return buffer.size();
 8986|   236k|}
_ZNK3ada3url8get_hrefEv:
 7395|   828k|[[nodiscard]] ada_really_inline std::string url::get_href() const {
 7396|   828k|  if (is_special() && host.has_value() && username.empty() &&
  ------------------
  |  Branch (7396:7): [True: 824k, False: 3.40k]
  |  Branch (7396:23): [True: 824k, False: 0]
  |  Branch (7396:43): [True: 771k, False: 53.0k]
  ------------------
 7397|   771k|      password.empty() && !port.has_value()) [[likely]] {
  ------------------
  |  Branch (7397:7): [True: 771k, False: 224]
  |  Branch (7397:27): [True: 717k, False: 54.1k]
  ------------------
 7398|   717k|    const std::string_view scheme = ada::scheme::details::is_special_list[type];
 7399|   717k|    const size_t host_size = host->size();
 7400|   717k|    const size_t path_size = path.size();
 7401|   717k|    const size_t query_size = query.has_value() ? query->size() : 0;
  ------------------
  |  Branch (7401:31): [True: 164k, False: 552k]
  ------------------
 7402|   717k|    const size_t hash_size = hash.has_value() ? hash->size() : 0;
  ------------------
  |  Branch (7402:30): [True: 116k, False: 600k]
  ------------------
 7403|   717k|    const size_t total = scheme.size() + 3 + host_size + path_size +
 7404|   717k|                         (query.has_value() ? query_size + 1 : 0) +
  ------------------
  |  Branch (7404:27): [True: 164k, False: 552k]
  ------------------
 7405|   717k|                         (hash.has_value() ? hash_size + 1 : 0);
  ------------------
  |  Branch (7405:27): [True: 116k, False: 600k]
  ------------------
 7406|   717k|    std::string output(total, '\0');
 7407|   717k|    char* p = output.data();
 7408|   717k|    std::memcpy(p, scheme.data(), scheme.size());
 7409|   717k|    p += scheme.size();
 7410|   717k|    p[0] = ':';
 7411|   717k|    p[1] = '/';
 7412|   717k|    p[2] = '/';
 7413|   717k|    p += 3;
 7414|       |    // NOLINTNEXTLINE(bugprone-not-null-terminated-result)
 7415|   717k|    std::memcpy(p, host->data(), host_size);
 7416|   717k|    p += host_size;
 7417|   717k|    std::memcpy(p, path.data(), path_size);
 7418|   717k|    p += path_size;
 7419|   717k|    if (query.has_value()) {
  ------------------
  |  Branch (7419:9): [True: 164k, False: 552k]
  ------------------
 7420|   164k|      *p++ = '?';
 7421|       |      // NOLINTNEXTLINE(bugprone-not-null-terminated-result)
 7422|   164k|      std::memcpy(p, query->data(), query_size);
 7423|   164k|      p += query_size;
 7424|   164k|    }
 7425|   717k|    if (hash.has_value()) {
  ------------------
  |  Branch (7425:9): [True: 116k, False: 600k]
  ------------------
 7426|   116k|      *p++ = '#';
 7427|       |      // NOLINTNEXTLINE(bugprone-not-null-terminated-result)
 7428|   116k|      std::memcpy(p, hash->data(), hash_size);
 7429|   116k|    }
 7430|   717k|    return output;
 7431|   717k|  }
 7432|       |
 7433|   110k|  std::string output;
 7434|   110k|  output.reserve(get_href_size());
 7435|       |
 7436|   110k|  if (is_special()) {
  ------------------
  |  Branch (7436:7): [True: 107k, False: 3.40k]
  ------------------
 7437|   107k|    output.append(ada::scheme::details::is_special_list[type]);
 7438|   107k|    output += ':';
 7439|   107k|  } else {
 7440|  3.40k|    output.append(non_special_scheme);
 7441|  3.40k|    output += ':';
 7442|  3.40k|  }
 7443|       |
 7444|   110k|  if (host.has_value()) {
  ------------------
  |  Branch (7444:7): [True: 108k, False: 1.98k]
  ------------------
 7445|   108k|    output += '/';
 7446|   108k|    output += '/';
 7447|   108k|    if (has_credentials()) {
  ------------------
  |  Branch (7447:9): [True: 53.5k, False: 55.2k]
  ------------------
 7448|  53.5k|      output.append(username);
 7449|  53.5k|      if (!password.empty()) {
  ------------------
  |  Branch (7449:11): [True: 51.4k, False: 2.05k]
  ------------------
 7450|  51.4k|        output += ':';
 7451|  51.4k|        output.append(password);
 7452|  51.4k|      }
 7453|  53.5k|      output += '@';
 7454|  53.5k|    }
 7455|   108k|    output.append(*host);
 7456|   108k|    if (port.has_value()) {
  ------------------
  |  Branch (7456:9): [True: 54.5k, False: 54.2k]
  ------------------
 7457|  54.5k|      output += ':';
 7458|  54.5k|      char port_buf[5];
 7459|  54.5k|      auto [ptr, ec] = std::to_chars(port_buf, port_buf + 5, *port);
 7460|  54.5k|      (void)ec;
 7461|  54.5k|      output.append(port_buf, static_cast<size_t>(ptr - port_buf));
 7462|  54.5k|    }
 7463|   108k|  } else if (!has_opaque_path && path.starts_with("//")) {
  ------------------
  |  Branch (7463:14): [True: 770, False: 1.21k]
  |  Branch (7463:34): [True: 56, False: 714]
  ------------------
 7464|       |    // If url's host is null, url does not have an opaque path, url's path's
 7465|       |    // size is greater than 1, and url's path[0] is the empty string, then
 7466|       |    // append U+002F (/) followed by U+002E (.) to output.
 7467|     56|    output += '/';
 7468|     56|    output += '.';
 7469|     56|  }
 7470|   110k|  output.append(path);
 7471|   110k|  if (query.has_value()) {
  ------------------
  |  Branch (7471:7): [True: 8.40k, False: 102k]
  ------------------
 7472|  8.40k|    output += '?';
 7473|  8.40k|    output.append(*query);
 7474|  8.40k|  }
 7475|   110k|  if (hash.has_value()) {
  ------------------
  |  Branch (7475:7): [True: 8.28k, False: 102k]
  ------------------
 7476|  8.28k|    output += '#';
 7477|  8.28k|    output.append(*hash);
 7478|  8.28k|  }
 7479|   110k|  return output;
 7480|   828k|}
_ZNK3ada14url_aggregator8validateEv:
 9057|   118k|[[nodiscard]] constexpr bool url_aggregator::validate() const noexcept {
 9058|   118k|  if (!is_valid) {
  ------------------
  |  Branch (9058:7): [True: 0, False: 118k]
  ------------------
 9059|      0|    return true;
 9060|      0|  }
 9061|   118k|  if (!components.check_offset_consistency()) {
  ------------------
  |  Branch (9061:7): [True: 0, False: 118k]
  ------------------
 9062|      0|    ada_log("url_aggregator::validate inconsistent components \n",
 9063|      0|            to_diagram());
 9064|      0|    return false;
 9065|      0|  }
 9066|       |  // We have a credible components struct, but let us investivate more
 9067|       |  // carefully:
 9068|       |  /**
 9069|       |   * https://user:pass@example.com:1234/foo/bar?baz#quux
 9070|       |   *       |     |    |          | ^^^^|       |   |
 9071|       |   *       |     |    |          | |   |       |   `----- hash_start
 9072|       |   *       |     |    |          | |   |       `--------- search_start
 9073|       |   *       |     |    |          | |   `----------------- pathname_start
 9074|       |   *       |     |    |          | `--------------------- port
 9075|       |   *       |     |    |          `----------------------- host_end
 9076|       |   *       |     |    `---------------------------------- host_start
 9077|       |   *       |     `--------------------------------------- username_end
 9078|       |   *       `--------------------------------------------- protocol_end
 9079|       |   */
 9080|   118k|  if (components.protocol_end == url_components::omitted) {
  ------------------
  |  Branch (9080:7): [True: 0, False: 118k]
  ------------------
 9081|      0|    ada_log("url_aggregator::validate omitted protocol_end \n", to_diagram());
 9082|      0|    return false;
 9083|      0|  }
 9084|   118k|  if (components.username_end == url_components::omitted) {
  ------------------
  |  Branch (9084:7): [True: 0, False: 118k]
  ------------------
 9085|      0|    ada_log("url_aggregator::validate omitted username_end \n", to_diagram());
 9086|      0|    return false;
 9087|      0|  }
 9088|   118k|  if (components.host_start == url_components::omitted) {
  ------------------
  |  Branch (9088:7): [True: 0, False: 118k]
  ------------------
 9089|      0|    ada_log("url_aggregator::validate omitted host_start \n", to_diagram());
 9090|      0|    return false;
 9091|      0|  }
 9092|   118k|  if (components.host_end == url_components::omitted) {
  ------------------
  |  Branch (9092:7): [True: 0, False: 118k]
  ------------------
 9093|      0|    ada_log("url_aggregator::validate omitted host_end \n", to_diagram());
 9094|      0|    return false;
 9095|      0|  }
 9096|   118k|  if (components.pathname_start == url_components::omitted) {
  ------------------
  |  Branch (9096:7): [True: 0, False: 118k]
  ------------------
 9097|      0|    ada_log("url_aggregator::validate omitted pathname_start \n", to_diagram());
 9098|      0|    return false;
 9099|      0|  }
 9100|       |
 9101|   118k|  if (components.protocol_end > buffer.size()) {
  ------------------
  |  Branch (9101:7): [True: 0, False: 118k]
  ------------------
 9102|      0|    ada_log("url_aggregator::validate protocol_end overflow \n", to_diagram());
 9103|      0|    return false;
 9104|      0|  }
 9105|   118k|  if (components.username_end > buffer.size()) {
  ------------------
  |  Branch (9105:7): [True: 0, False: 118k]
  ------------------
 9106|      0|    ada_log("url_aggregator::validate username_end overflow \n", to_diagram());
 9107|      0|    return false;
 9108|      0|  }
 9109|   118k|  if (components.host_start > buffer.size()) {
  ------------------
  |  Branch (9109:7): [True: 0, False: 118k]
  ------------------
 9110|      0|    ada_log("url_aggregator::validate host_start overflow \n", to_diagram());
 9111|      0|    return false;
 9112|      0|  }
 9113|   118k|  if (components.host_end > buffer.size()) {
  ------------------
  |  Branch (9113:7): [True: 0, False: 118k]
  ------------------
 9114|      0|    ada_log("url_aggregator::validate host_end overflow \n", to_diagram());
 9115|      0|    return false;
 9116|      0|  }
 9117|   118k|  if (components.pathname_start > buffer.size()) {
  ------------------
  |  Branch (9117:7): [True: 0, False: 118k]
  ------------------
 9118|      0|    ada_log("url_aggregator::validate pathname_start overflow \n",
 9119|      0|            to_diagram());
 9120|      0|    return false;
 9121|      0|  }
 9122|       |
 9123|   118k|  if (components.protocol_end > 0) {
  ------------------
  |  Branch (9123:7): [True: 118k, False: 0]
  ------------------
 9124|   118k|    if (buffer[components.protocol_end - 1] != ':') {
  ------------------
  |  Branch (9124:9): [True: 0, False: 118k]
  ------------------
 9125|      0|      ada_log(
 9126|      0|          "url_aggregator::validate missing : at the end of the protocol \n",
 9127|      0|          to_diagram());
 9128|      0|      return false;
 9129|      0|    }
 9130|   118k|  }
 9131|       |
 9132|   118k|  if (components.username_end != buffer.size() &&
  ------------------
  |  Branch (9132:7): [True: 118k, False: 3]
  ------------------
 9133|   118k|      components.username_end > components.protocol_end + 2) {
  ------------------
  |  Branch (9133:7): [True: 7.61k, False: 110k]
  ------------------
 9134|  7.61k|    if (buffer[components.username_end] != ':' &&
  ------------------
  |  Branch (9134:9): [True: 293, False: 7.32k]
  ------------------
 9135|    293|        buffer[components.username_end] != '@') {
  ------------------
  |  Branch (9135:9): [True: 0, False: 293]
  ------------------
 9136|      0|      ada_log(
 9137|      0|          "url_aggregator::validate missing : or @ at the end of the username "
 9138|      0|          "\n",
 9139|      0|          to_diagram());
 9140|      0|      return false;
 9141|      0|    }
 9142|  7.61k|  }
 9143|       |
 9144|   118k|  if (components.host_start != buffer.size()) {
  ------------------
  |  Branch (9144:7): [True: 118k, False: 3]
  ------------------
 9145|   118k|    if (components.host_start > components.username_end) {
  ------------------
  |  Branch (9145:9): [True: 7.35k, False: 110k]
  ------------------
 9146|  7.35k|      if (buffer[components.host_start] != '@') {
  ------------------
  |  Branch (9146:11): [True: 0, False: 7.35k]
  ------------------
 9147|      0|        ada_log(
 9148|      0|            "url_aggregator::validate missing @ at the end of the password \n",
 9149|      0|            to_diagram());
 9150|      0|        return false;
 9151|      0|      }
 9152|   110k|    } else if (components.host_start == components.username_end &&
  ------------------
  |  Branch (9152:16): [True: 110k, False: 0]
  ------------------
 9153|   110k|               components.host_end > components.host_start) {
  ------------------
  |  Branch (9153:16): [True: 110k, False: 468]
  ------------------
 9154|   110k|      if (components.host_start == components.protocol_end + 2) {
  ------------------
  |  Branch (9154:11): [True: 110k, False: 293]
  ------------------
 9155|   110k|        if (buffer[components.protocol_end] != '/' ||
  ------------------
  |  Branch (9155:13): [True: 0, False: 110k]
  ------------------
 9156|   110k|            buffer[components.protocol_end + 1] != '/') {
  ------------------
  |  Branch (9156:13): [True: 0, False: 110k]
  ------------------
 9157|      0|          ada_log(
 9158|      0|              "url_aggregator::validate missing // between protocol and host "
 9159|      0|              "\n",
 9160|      0|              to_diagram());
 9161|      0|          return false;
 9162|      0|        }
 9163|   110k|      } else {
 9164|    293|        if (components.host_start > components.protocol_end &&
  ------------------
  |  Branch (9164:13): [True: 293, False: 0]
  ------------------
 9165|    293|            buffer[components.host_start] != '@') {
  ------------------
  |  Branch (9165:13): [True: 0, False: 293]
  ------------------
 9166|      0|          ada_log(
 9167|      0|              "url_aggregator::validate missing @ at the end of the username "
 9168|      0|              "\n",
 9169|      0|              to_diagram());
 9170|      0|          return false;
 9171|      0|        }
 9172|    293|      }
 9173|   110k|    } else {
 9174|    468|      if (components.host_end != components.host_start) {
  ------------------
  |  Branch (9174:11): [True: 0, False: 468]
  ------------------
 9175|      0|        ada_log("url_aggregator::validate expected omitted host \n",
 9176|      0|                to_diagram());
 9177|      0|        return false;
 9178|      0|      }
 9179|    468|    }
 9180|   118k|  }
 9181|   118k|  if (components.host_end != buffer.size() &&
  ------------------
  |  Branch (9181:7): [True: 118k, False: 8]
  ------------------
 9182|   118k|      components.pathname_start > components.host_end) {
  ------------------
  |  Branch (9182:7): [True: 7.80k, False: 110k]
  ------------------
 9183|  7.80k|    if (components.pathname_start == components.host_end + 2 &&
  ------------------
  |  Branch (9183:9): [True: 362, False: 7.44k]
  ------------------
 9184|    362|        buffer[components.host_end] == '/' &&
  ------------------
  |  Branch (9184:9): [True: 8, False: 354]
  ------------------
 9185|      8|        buffer[components.host_end + 1] == '.') {
  ------------------
  |  Branch (9185:9): [True: 8, False: 0]
  ------------------
 9186|      8|      if (components.pathname_start + 1 >= buffer.size() ||
  ------------------
  |  Branch (9186:11): [True: 0, False: 8]
  ------------------
 9187|      8|          buffer[components.pathname_start] != '/' ||
  ------------------
  |  Branch (9187:11): [True: 0, False: 8]
  ------------------
 9188|      8|          buffer[components.pathname_start + 1] != '/') {
  ------------------
  |  Branch (9188:11): [True: 0, False: 8]
  ------------------
 9189|      0|        ada_log(
 9190|      0|            "url_aggregator::validate expected the path to begin with // \n",
 9191|      0|            to_diagram());
 9192|      0|        return false;
 9193|      0|      }
 9194|  7.79k|    } else if (buffer[components.host_end] != ':') {
  ------------------
  |  Branch (9194:16): [True: 0, False: 7.79k]
  ------------------
 9195|      0|      ada_log("url_aggregator::validate missing : at the port \n",
 9196|      0|              to_diagram());
 9197|      0|      return false;
 9198|      0|    }
 9199|  7.80k|  }
 9200|   118k|  if (components.pathname_start != buffer.size() &&
  ------------------
  |  Branch (9200:7): [True: 118k, False: 12]
  ------------------
 9201|   118k|      components.pathname_start < components.search_start &&
  ------------------
  |  Branch (9201:7): [True: 118k, False: 47]
  ------------------
 9202|   118k|      components.pathname_start < components.hash_start && !has_opaque_path) {
  ------------------
  |  Branch (9202:7): [True: 118k, False: 33]
  |  Branch (9202:60): [True: 118k, False: 150]
  ------------------
 9203|   118k|    if (buffer[components.pathname_start] != '/') {
  ------------------
  |  Branch (9203:9): [True: 0, False: 118k]
  ------------------
 9204|      0|      ada_log("url_aggregator::validate missing / at the path \n",
 9205|      0|              to_diagram());
 9206|      0|      return false;
 9207|      0|    }
 9208|   118k|  }
 9209|   118k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (9209:7): [True: 24.7k, False: 93.6k]
  ------------------
 9210|  24.7k|    if (buffer[components.search_start] != '?') {
  ------------------
  |  Branch (9210:9): [True: 0, False: 24.7k]
  ------------------
 9211|      0|      ada_log("url_aggregator::validate missing ? at the search \n",
 9212|      0|              to_diagram());
 9213|      0|      return false;
 9214|      0|    }
 9215|  24.7k|  }
 9216|   118k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (9216:7): [True: 17.8k, False: 100k]
  ------------------
 9217|  17.8k|    if (buffer[components.hash_start] != '#') {
  ------------------
  |  Branch (9217:9): [True: 0, False: 17.8k]
  ------------------
 9218|      0|      ada_log("url_aggregator::validate missing # at the hash \n",
 9219|      0|              to_diagram());
 9220|      0|      return false;
 9221|      0|    }
 9222|  17.8k|  }
 9223|       |
 9224|   118k|  return true;
 9225|   118k|}
_ZNK3ada14url_components24check_offset_consistencyEv:
 7572|   118k|    const noexcept {
 7573|       |  /**
 7574|       |   * https://user:pass@example.com:1234/foo/bar?baz#quux
 7575|       |   *       |     |    |          | ^^^^|       |   |
 7576|       |   *       |     |    |          | |   |       |   `----- hash_start
 7577|       |   *       |     |    |          | |   |       `--------- search_start
 7578|       |   *       |     |    |          | |   `----------------- pathname_start
 7579|       |   *       |     |    |          | `--------------------- port
 7580|       |   *       |     |    |          `----------------------- host_end
 7581|       |   *       |     |    `---------------------------------- host_start
 7582|       |   *       |     `--------------------------------------- username_end
 7583|       |   *       `--------------------------------------------- protocol_end
 7584|       |   */
 7585|       |  // These conditions can be made more strict.
 7586|   118k|  if (protocol_end == url_components::omitted) {
  ------------------
  |  Branch (7586:7): [True: 0, False: 118k]
  ------------------
 7587|      0|    return false;
 7588|      0|  }
 7589|   118k|  uint32_t index = protocol_end;
 7590|       |
 7591|   118k|  if (username_end == url_components::omitted) {
  ------------------
  |  Branch (7591:7): [True: 0, False: 118k]
  ------------------
 7592|      0|    return false;
 7593|      0|  }
 7594|   118k|  if (username_end < index) {
  ------------------
  |  Branch (7594:7): [True: 0, False: 118k]
  ------------------
 7595|      0|    return false;
 7596|      0|  }
 7597|   118k|  index = username_end;
 7598|       |
 7599|   118k|  if (host_start == url_components::omitted) {
  ------------------
  |  Branch (7599:7): [True: 0, False: 118k]
  ------------------
 7600|      0|    return false;
 7601|      0|  }
 7602|   118k|  if (host_start < index) {
  ------------------
  |  Branch (7602:7): [True: 0, False: 118k]
  ------------------
 7603|      0|    return false;
 7604|      0|  }
 7605|   118k|  index = host_start;
 7606|       |
 7607|   118k|  if (port != url_components::omitted) {
  ------------------
  |  Branch (7607:7): [True: 7.79k, False: 110k]
  ------------------
 7608|  7.79k|    if (port > 0xffff) {
  ------------------
  |  Branch (7608:9): [True: 0, False: 7.79k]
  ------------------
 7609|      0|      return false;
 7610|      0|    }
 7611|  7.79k|    uint32_t port_length = helpers::fast_digit_count(port) + 1;
 7612|  7.79k|    if (index + port_length < index) {
  ------------------
  |  Branch (7612:9): [True: 0, False: 7.79k]
  ------------------
 7613|      0|      return false;
 7614|      0|    }
 7615|  7.79k|    index += port_length;
 7616|  7.79k|  }
 7617|       |
 7618|   118k|  if (pathname_start == url_components::omitted) {
  ------------------
  |  Branch (7618:7): [True: 0, False: 118k]
  ------------------
 7619|      0|    return false;
 7620|      0|  }
 7621|   118k|  if (pathname_start < index) {
  ------------------
  |  Branch (7621:7): [True: 0, False: 118k]
  ------------------
 7622|      0|    return false;
 7623|      0|  }
 7624|   118k|  index = pathname_start;
 7625|       |
 7626|   118k|  if (search_start != url_components::omitted) {
  ------------------
  |  Branch (7626:7): [True: 24.7k, False: 93.6k]
  ------------------
 7627|  24.7k|    if (search_start < index) {
  ------------------
  |  Branch (7627:9): [True: 0, False: 24.7k]
  ------------------
 7628|      0|      return false;
 7629|      0|    }
 7630|  24.7k|    index = search_start;
 7631|  24.7k|  }
 7632|       |
 7633|   118k|  if (hash_start != url_components::omitted) {
  ------------------
  |  Branch (7633:7): [True: 17.8k, False: 100k]
  ------------------
 7634|  17.8k|    if (hash_start < index) {
  ------------------
  |  Branch (7634:9): [True: 0, False: 17.8k]
  ------------------
 7635|      0|      return false;
 7636|      0|    }
 7637|  17.8k|  }
 7638|       |
 7639|   118k|  return true;
 7640|   118k|}
_ZN3ada7helpers16fast_digit_countEj:
 1950|  7.79k|inline int fast_digit_count(uint32_t x) noexcept {
 1951|  7.79k|  auto int_log2 = [](uint32_t z) -> int {
 1952|  7.79k|    return 31 - ada::helpers::leading_zeroes(z | 1);
 1953|  7.79k|  };
 1954|       |  // Compiles to very few instructions. Note that the
 1955|       |  // table is static and thus effectively a constant.
 1956|       |  // We leave it inside the function because it is meaningless
 1957|       |  // outside of it (this comes at no performance cost).
 1958|  7.79k|  const static uint64_t table[] = {
 1959|  7.79k|      4294967296,  8589934582,  8589934582,  8589934582,  12884901788,
 1960|  7.79k|      12884901788, 12884901788, 17179868184, 17179868184, 17179868184,
 1961|  7.79k|      21474826480, 21474826480, 21474826480, 21474826480, 25769703776,
 1962|  7.79k|      25769703776, 25769703776, 30063771072, 30063771072, 30063771072,
 1963|  7.79k|      34349738368, 34349738368, 34349738368, 34349738368, 38554705664,
 1964|  7.79k|      38554705664, 38554705664, 41949672960, 41949672960, 41949672960,
 1965|  7.79k|      42949672960, 42949672960};
 1966|  7.79k|  return int((x + table[int_log2(x)]) >> 32);
 1967|  7.79k|}
_ZZN3ada7helpers16fast_digit_countEjENKUljE_clEj:
 1951|  7.79k|  auto int_log2 = [](uint32_t z) -> int {
 1952|  7.79k|    return 31 - ada::helpers::leading_zeroes(z | 1);
 1953|  7.79k|  };
_ZN3ada7helpers6concatIJNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKcEEENS2_12basic_stringIcS5_NS2_9allocatorIcEEEEDpT_:
 1924|   121k|std::string concat(Args... args) {
 1925|   121k|  std::string answer;
 1926|   121k|  inner_concat(answer, args...);
 1927|   121k|  return answer;
 1928|   121k|}
_ZN3ada7helpers12inner_concatINSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEJPKcEEEvRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEET_DpT0_:
 1913|   121k|inline void inner_concat(std::string& buffer, T t, Args... args) {
 1914|   121k|  buffer.append(t);
 1915|   121k|  return inner_concat(buffer, args...);
 1916|   121k|}
_ZN3ada7helpers12inner_concatIPKcJEEEvRNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEET_:
 1905|   122k|inline void inner_concat(std::string& buffer, T t) {
 1906|   122k|  buffer.append(t);
 1907|   122k|}
_ZN3ada7helpers6concatIJNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPKcEEES8_DpT_:
 1924|    486|std::string concat(Args... args) {
 1925|    486|  std::string answer;
 1926|    486|  inner_concat(answer, args...);
 1927|    486|  return answer;
 1928|    486|}
_ZN3ada7helpers12inner_concatINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEJPKcEEEvRS8_T_DpT0_:
 1913|    486|inline void inner_concat(std::string& buffer, T t, Args... args) {
 1914|    486|  buffer.append(t);
 1915|    486|  return inner_concat(buffer, args...);
 1916|    486|}
_ZN3ada3url10set_schemeEONSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
 7377|  4.16k|inline void url::set_scheme(std::string&& new_scheme) noexcept {
 7378|  4.16k|  type = ada::scheme::get_scheme_type(new_scheme);
 7379|       |  // We only move the 'scheme' if it is non-special.
 7380|  4.16k|  if (!is_special()) {
  ------------------
  |  Branch (7380:7): [True: 1.54k, False: 2.62k]
  ------------------
 7381|  1.54k|    non_special_scheme = std::move(new_scheme);
 7382|  1.54k|  }
 7383|  4.16k|}

LLVMFuzzerTestOneInput:
  211|  6.86k|extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  212|  6.86k|  FuzzedDataProvider fdp(data, size);
  213|       |
  214|  6.86k|  fuzz_one_input(make_candidate(fdp));
  215|       |
  216|  6.86k|  if (fdp.remaining_bytes() > 0) {
  ------------------
  |  Branch (216:7): [True: 4.50k, False: 2.35k]
  ------------------
  217|  4.50k|    std::string raw = fdp.ConsumeRemainingBytesAsString();
  218|  4.50k|    if (raw.size() > 512) {
  ------------------
  |  Branch (218:9): [True: 28, False: 4.48k]
  ------------------
  219|     28|      raw.resize(512);
  220|     28|    }
  221|  4.50k|    if (!raw.empty() && (static_cast<unsigned char>(raw[0]) & 1u)) {
  ------------------
  |  Branch (221:9): [True: 4.50k, False: 0]
  |  Branch (221:25): [True: 1.63k, False: 2.87k]
  ------------------
  222|  1.63k|      raw = std::string("https://") + raw;
  223|  2.87k|    } else if (!raw.empty()) {
  ------------------
  |  Branch (223:16): [True: 2.87k, False: 0]
  ------------------
  224|  2.87k|      raw = std::string("http://") + raw;
  225|  2.87k|    }
  226|  4.50k|    fuzz_one_input(raw);
  227|  4.50k|  }
  228|       |
  229|  6.86k|  static constexpr const char* kAnchors[] = {
  230|  6.86k|      "https://example.com",
  231|  6.86k|      "https://example.com/",
  232|  6.86k|      "https://example.com?q=1",
  233|  6.86k|      "https://example.com#frag",
  234|  6.86k|      "https://example.com/?q=1#frag",
  235|  6.86k|      "http://www.example.com/path/file.js",
  236|  6.86k|      "http://WWW.Example.COM/file.js",
  237|  6.86k|      "https://www.google.com/imghp?hl=en&tab=wi",
  238|  6.86k|      "http://192.168.0.1/x",
  239|  6.86k|      "http://0x7f.1/",
  240|  6.86k|      "https://user:pass@example.com/x",
  241|  6.86k|      "https://example.com:8080/x",
  242|  6.86k|      "https://example.com/a/./b/../c",
  243|  6.86k|      "https://example.com/foo/%2e%2e",
  244|  6.86k|      "https://xn--nxasmq6b.com/",
  245|  6.86k|      "https://xn--a/",
  246|  6.86k|  };
  247|   109k|  for (const char* seed : kAnchors) {
  ------------------
  |  Branch (247:25): [True: 109k, False: 6.86k]
  ------------------
  248|   109k|    fuzz_one_input(seed);
  249|   109k|  }
  250|       |
  251|  6.86k|  return 0;
  252|  6.86k|}
simple_absolute.cc:_ZL14fuzz_one_inputNSt3__117basic_string_viewIcNS_11char_traitsIcEEEE:
  170|   121k|static void fuzz_one_input(std::string_view input) {
  171|   121k|  auto url = ada::parse<ada::url>(input);
  172|   121k|  auto agg = ada::parse<ada::url_aggregator>(input);
  173|       |
  174|   121k|  if (url.has_value() != agg.has_value()) {
  ------------------
  |  Branch (174:7): [True: 0, False: 121k]
  ------------------
  175|      0|    printf(
  176|      0|        "parse agreement failure\n"
  177|      0|        "  input: %.*s\n"
  178|      0|        "  url: %d aggregator: %d\n",
  179|      0|        static_cast<int>(input.size()), input.data(), url.has_value(),
  180|      0|        agg.has_value());
  181|      0|    abort();
  182|      0|  }
  183|       |
  184|   121k|  if (!url) {
  ------------------
  |  Branch (184:7): [True: 2.88k, False: 118k]
  ------------------
  185|  2.88k|    return;
  186|  2.88k|  }
  187|       |
  188|   118k|  check_components_agree(*url, *agg, input);
  189|   118k|  check_href_size(*url, input);
  190|   118k|  check_href_size(*agg, input);
  191|   118k|  check_reparse_idempotent(*url, input);
  192|   118k|  check_reparse_idempotent(*agg, input);
  193|       |
  194|   118k|  const std::string href = url->get_href();
  195|   118k|  url->set_href(href);
  196|   118k|  agg->set_href(href);
  197|   118k|  if (url->get_href() != std::string(agg->get_href())) {
  ------------------
  |  Branch (197:7): [True: 0, False: 118k]
  ------------------
  198|      0|    printf(
  199|      0|        "set_href agreement failure\n"
  200|      0|        "  href: %s\n",
  201|      0|        href.c_str());
  202|      0|    abort();
  203|      0|  }
  204|   118k|  check_href_size(*url, href);
  205|   118k|  check_href_size(*agg, href);
  206|       |
  207|   118k|  volatile bool valid = agg->validate();
  208|   118k|  (void)valid;
  209|   118k|}
simple_absolute.cc:_ZL22check_components_agreeRKN3ada3urlERKNS_14url_aggregatorENSt3__117basic_string_viewIcNS6_11char_traitsIcEEEE:
  148|   118k|                                   std::string_view input) {
  149|   118k|  if (u.get_protocol() != a.get_protocol() ||
  ------------------
  |  Branch (149:7): [True: 0, False: 118k]
  |  Branch (149:7): [True: 0, False: 118k]
  ------------------
  150|   118k|      u.get_href() != std::string(a.get_href()) ||
  ------------------
  |  Branch (150:7): [True: 0, False: 118k]
  ------------------
  151|   118k|      std::string(u.get_hostname()) != std::string(a.get_hostname()) ||
  ------------------
  |  Branch (151:7): [True: 0, False: 118k]
  ------------------
  152|   118k|      std::string(u.get_pathname()) != std::string(a.get_pathname()) ||
  ------------------
  |  Branch (152:7): [True: 0, False: 118k]
  ------------------
  153|   118k|      std::string(u.get_search()) != std::string(a.get_search()) ||
  ------------------
  |  Branch (153:7): [True: 0, False: 118k]
  ------------------
  154|   118k|      std::string(u.get_hash()) != std::string(a.get_hash()) ||
  ------------------
  |  Branch (154:7): [True: 0, False: 118k]
  ------------------
  155|   118k|      std::string(u.get_port()) != std::string(a.get_port()) ||
  ------------------
  |  Branch (155:7): [True: 0, False: 118k]
  ------------------
  156|   118k|      u.get_username() != std::string(a.get_username()) ||
  ------------------
  |  Branch (156:7): [True: 0, False: 118k]
  ------------------
  157|   118k|      u.get_password() != std::string(a.get_password()) ||
  ------------------
  |  Branch (157:7): [True: 0, False: 118k]
  ------------------
  158|   118k|      std::string(u.get_host()) != std::string(a.get_host())) {
  ------------------
  |  Branch (158:7): [True: 0, False: 118k]
  ------------------
  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|      0|    abort();
  167|      0|  }
  168|   118k|}
simple_absolute.cc:_ZL15check_href_sizeRKN3ada3urlENSt3__117basic_string_viewIcNS3_11char_traitsIcEEEE:
   94|   236k|static void check_href_size(const ada::url& u, std::string_view input) {
   95|   236k|  if (u.get_href_size() != u.get_href().size()) {
  ------------------
  |  Branch (95:7): [True: 0, False: 236k]
  ------------------
   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|   236k|}
simple_absolute.cc:_ZL15check_href_sizeRKN3ada14url_aggregatorENSt3__117basic_string_viewIcNS3_11char_traitsIcEEEE:
  108|   236k|                            std::string_view input) {
  109|   236k|  if (u.get_href_size() != u.get_href().size()) {
  ------------------
  |  Branch (109:7): [True: 0, False: 236k]
  ------------------
  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|   236k|}
simple_absolute.cc:_ZL24check_reparse_idempotentIN3ada3urlEEvRKT_NSt3__117basic_string_viewIcNS5_11char_traitsIcEEEE:
  123|   118k|                                     std::string_view input) {
  124|   118k|  const std::string href = std::string(parsed.get_href());
  125|   118k|  auto again = ada::parse<Result>(href);
  126|   118k|  if (!again) {
  ------------------
  |  Branch (126:7): [True: 0, False: 118k]
  ------------------
  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|   118k|  if (std::string(again->get_href()) != href) {
  ------------------
  |  Branch (134:7): [True: 0, False: 118k]
  ------------------
  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|   118k|}
simple_absolute.cc:_ZL24check_reparse_idempotentIN3ada14url_aggregatorEEvRKT_NSt3__117basic_string_viewIcNS5_11char_traitsIcEEEE:
  123|   118k|                                     std::string_view input) {
  124|   118k|  const std::string href = std::string(parsed.get_href());
  125|   118k|  auto again = ada::parse<Result>(href);
  126|   118k|  if (!again) {
  ------------------
  |  Branch (126:7): [True: 0, False: 118k]
  ------------------
  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|   118k|  if (std::string(again->get_href()) != href) {
  ------------------
  |  Branch (134:7): [True: 0, False: 118k]
  ------------------
  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|   118k|}
simple_absolute.cc:_ZL14make_candidateR18FuzzedDataProvider:
   74|  6.86k|static std::string make_candidate(FuzzedDataProvider& fdp) {
   75|  6.86k|  std::string out;
   76|  6.86k|  out += pick(fdp, kSchemes);
   77|  6.86k|  out += pick(fdp, kHosts);
   78|  6.86k|  out += pick(fdp, kPaths);
   79|  6.86k|  out += pick(fdp, kQueries);
   80|  6.86k|  out += pick(fdp, kFrags);
   81|       |
   82|  6.86k|  if (fdp.ConsumeBool() && !out.empty()) {
  ------------------
  |  Branch (82:7): [True: 1.82k, False: 5.04k]
  |  Branch (82:28): [True: 1.82k, False: 0]
  ------------------
   83|  1.82k|    std::string mid = fdp.ConsumeRandomLengthString(24);
   84|  1.82k|    size_t pos = fdp.ConsumeIntegralInRange<size_t>(0, out.size());
   85|  1.82k|    out.insert(pos, mid);
   86|  1.82k|  }
   87|  6.86k|  if (fdp.ConsumeBool() && !out.empty()) {
  ------------------
  |  Branch (87:7): [True: 1.46k, False: 5.39k]
  |  Branch (87:28): [True: 1.46k, False: 0]
  ------------------
   88|  1.46k|    size_t i = fdp.ConsumeIntegralInRange<size_t>(0, out.size() - 1);
   89|  1.46k|    out[i] = static_cast<char>(fdp.ConsumeIntegral<uint8_t>());
   90|  1.46k|  }
   91|  6.86k|  return out;
   92|  6.86k|}
simple_absolute.cc:_ZL4pickILm8EEPKcR18FuzzedDataProviderRAT__KS1_:
   70|  6.86k|static const char* pick(FuzzedDataProvider& fdp, const char* const (&arr)[N]) {
   71|  6.86k|  return arr[fdp.ConsumeIntegralInRange<size_t>(0, N - 1)];
   72|  6.86k|}
simple_absolute.cc:_ZL4pickILm20EEPKcR18FuzzedDataProviderRAT__KS1_:
   70|  6.86k|static const char* pick(FuzzedDataProvider& fdp, const char* const (&arr)[N]) {
   71|  6.86k|  return arr[fdp.ConsumeIntegralInRange<size_t>(0, N - 1)];
   72|  6.86k|}
simple_absolute.cc:_ZL4pickILm16EEPKcR18FuzzedDataProviderRAT__KS1_:
   70|  6.86k|static const char* pick(FuzzedDataProvider& fdp, const char* const (&arr)[N]) {
   71|  6.86k|  return arr[fdp.ConsumeIntegralInRange<size_t>(0, N - 1)];
   72|  6.86k|}
simple_absolute.cc:_ZL4pickILm6EEPKcR18FuzzedDataProviderRAT__KS1_:
   70|  6.86k|static const char* pick(FuzzedDataProvider& fdp, const char* const (&arr)[N]) {
   71|  6.86k|  return arr[fdp.ConsumeIntegralInRange<size_t>(0, N - 1)];
   72|  6.86k|}
simple_absolute.cc:_ZL4pickILm5EEPKcR18FuzzedDataProviderRAT__KS1_:
   70|  6.86k|static const char* pick(FuzzedDataProvider& fdp, const char* const (&arr)[N]) {
   71|  6.86k|  return arr[fdp.ConsumeIntegralInRange<size_t>(0, N - 1)];
   72|  6.86k|}

