_ZN3ada4idna13utf8_to_utf32EPKcmPDi:
  160|  2.63k|size_t utf8_to_utf32(const char* buf, size_t len, char32_t* utf32_output) {
  161|  2.63k|  const uint8_t* data = reinterpret_cast<const uint8_t*>(buf);
  162|  2.63k|  size_t pos = 0;
  163|  2.63k|  const char32_t* start{utf32_output};
  164|  19.8k|  while (pos < len) {
  ------------------
  |  Branch (164:10): [True: 17.2k, False: 2.50k]
  ------------------
  165|       |    // try to convert the next block of 16 ASCII bytes
  166|  17.2k|    if (pos + 16 <= len) {  // if it is safe to read 16 more
  ------------------
  |  Branch (166:9): [True: 4.35k, False: 12.9k]
  ------------------
  167|       |                            // bytes, check that they are ascii
  168|  4.35k|      uint64_t v1;
  169|  4.35k|      std::memcpy(&v1, data + pos, sizeof(uint64_t));
  170|  4.35k|      uint64_t v2;
  171|  4.35k|      std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t));
  172|  4.35k|      uint64_t v{v1 | v2};
  173|  4.35k|      if ((v & 0x8080808080808080) == 0) {
  ------------------
  |  Branch (173:11): [True: 266, False: 4.08k]
  ------------------
  174|    266|        size_t final_pos = pos + 16;
  175|  4.52k|        while (pos < final_pos) {
  ------------------
  |  Branch (175:16): [True: 4.25k, False: 266]
  ------------------
  176|  4.25k|          *utf32_output++ = char32_t(buf[pos]);
  177|  4.25k|          pos++;
  178|  4.25k|        }
  179|    266|        continue;
  180|    266|      }
  181|  4.35k|    }
  182|  17.0k|    uint8_t leading_byte = data[pos];  // leading byte
  183|  17.0k|    if (leading_byte < 0b10000000) {
  ------------------
  |  Branch (183:9): [True: 10.2k, False: 6.75k]
  ------------------
  184|       |      // converting one ASCII byte !!!
  185|  10.2k|      *utf32_output++ = char32_t(leading_byte);
  186|  10.2k|      pos++;
  187|  10.2k|    } else if ((leading_byte & 0b11100000) == 0b11000000) {
  ------------------
  |  Branch (187:16): [True: 2.60k, False: 4.15k]
  ------------------
  188|       |      // We have a two-byte UTF-8
  189|  2.60k|      if (pos + 1 >= len) {
  ------------------
  |  Branch (189:11): [True: 12, False: 2.59k]
  ------------------
  190|     12|        return 0;
  191|     12|      }  // minimal bound checking
  192|  2.59k|      if ((data[pos + 1] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (192:11): [True: 18, False: 2.57k]
  ------------------
  193|     18|        return 0;
  194|     18|      }
  195|       |      // range check
  196|  2.57k|      uint32_t code_point =
  197|  2.57k|          (leading_byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111);
  198|  2.57k|      if (code_point < 0x80 || 0x7ff < code_point) {
  ------------------
  |  Branch (198:11): [True: 3, False: 2.57k]
  |  Branch (198:32): [True: 0, False: 2.57k]
  ------------------
  199|      3|        return 0;
  200|      3|      }
  201|  2.57k|      *utf32_output++ = char32_t(code_point);
  202|  2.57k|      pos += 2;
  203|  4.15k|    } else if ((leading_byte & 0b11110000) == 0b11100000) {
  ------------------
  |  Branch (203:16): [True: 3.72k, False: 429]
  ------------------
  204|       |      // We have a three-byte UTF-8
  205|  3.72k|      if (pos + 2 >= len) {
  ------------------
  |  Branch (205:11): [True: 8, False: 3.71k]
  ------------------
  206|      8|        return 0;
  207|      8|      }  // minimal bound checking
  208|       |
  209|  3.71k|      if ((data[pos + 1] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (209:11): [True: 10, False: 3.70k]
  ------------------
  210|     10|        return 0;
  211|     10|      }
  212|  3.70k|      if ((data[pos + 2] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (212:11): [True: 5, False: 3.70k]
  ------------------
  213|      5|        return 0;
  214|      5|      }
  215|       |      // range check
  216|  3.70k|      uint32_t code_point = (leading_byte & 0b00001111) << 12 |
  217|  3.70k|                            (data[pos + 1] & 0b00111111) << 6 |
  218|  3.70k|                            (data[pos + 2] & 0b00111111);
  219|  3.70k|      if (code_point < 0x800 || 0xffff < code_point ||
  ------------------
  |  Branch (219:11): [True: 2, False: 3.69k]
  |  Branch (219:33): [True: 0, False: 3.69k]
  ------------------
  220|  3.69k|          (0xd7ff < code_point && code_point < 0xe000)) {
  ------------------
  |  Branch (220:12): [True: 1.07k, False: 2.62k]
  |  Branch (220:35): [True: 1, False: 1.07k]
  ------------------
  221|      3|        return 0;
  222|      3|      }
  223|  3.69k|      *utf32_output++ = char32_t(code_point);
  224|  3.69k|      pos += 3;
  225|  3.69k|    } else if ((leading_byte & 0b11111000) == 0b11110000) {  // 0b11110000
  ------------------
  |  Branch (225:16): [True: 385, False: 44]
  ------------------
  226|       |      // we have a 4-byte UTF-8 word.
  227|    385|      if (pos + 3 >= len) {
  ------------------
  |  Branch (227:11): [True: 7, False: 378]
  ------------------
  228|      7|        return 0;
  229|      7|      }  // minimal bound checking
  230|    378|      if ((data[pos + 1] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (230:11): [True: 8, False: 370]
  ------------------
  231|      8|        return 0;
  232|      8|      }
  233|    370|      if ((data[pos + 2] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (233:11): [True: 1, False: 369]
  ------------------
  234|      1|        return 0;
  235|      1|      }
  236|    369|      if ((data[pos + 3] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (236:11): [True: 3, False: 366]
  ------------------
  237|      3|        return 0;
  238|      3|      }
  239|       |
  240|       |      // range check
  241|    366|      uint32_t code_point = (leading_byte & 0b00000111) << 18 |
  242|    366|                            (data[pos + 1] & 0b00111111) << 12 |
  243|    366|                            (data[pos + 2] & 0b00111111) << 6 |
  244|    366|                            (data[pos + 3] & 0b00111111);
  245|    366|      if (code_point <= 0xffff || 0x10ffff < code_point) {
  ------------------
  |  Branch (245:11): [True: 5, False: 361]
  |  Branch (245:35): [True: 3, False: 358]
  ------------------
  246|      8|        return 0;
  247|      8|      }
  248|    358|      *utf32_output++ = char32_t(code_point);
  249|    358|      pos += 4;
  250|    358|    } else {
  251|     44|      return 0;
  252|     44|    }
  253|  17.0k|  }
  254|  2.50k|  return utf32_output - start;
  255|  2.63k|}
_ZN3ada4idna22utf32_length_from_utf8EPKcm:
  270|  2.65k|size_t utf32_length_from_utf8(const char* buf, size_t len) {
  271|  2.65k|  const int8_t* p = reinterpret_cast<const int8_t*>(buf);
  272|  2.65k|  return std::count_if(p, std::next(p, len), [](int8_t c) {
  273|       |    // -65 is 0b10111111, anything larger in two-complement's
  274|       |    // should start a new code point.
  275|  2.65k|    return c > -65;
  276|  2.65k|  });
  277|  2.65k|}
_ZN3ada4idna7deflate9BitReader3getEi:
  405|   457k|  uint32_t get(int n) {
  406|   457k|    if (!ensure(n)) return UINT32_MAX;
  ------------------
  |  Branch (406:9): [True: 0, False: 457k]
  ------------------
  407|   457k|    uint32_t v = acc & ((1u << n) - 1);
  408|   457k|    acc >>= n;
  409|   457k|    bits -= n;
  410|   457k|    return v;
  411|   457k|  }
_ZN3ada4idna9ascii_mapEPcm:
 5126|    677|void ascii_map(char* input, size_t length) {
 5127|    677|  auto broadcast = [](uint8_t v) -> uint64_t {
 5128|    677|    return 0x101010101010101ull * v;
 5129|    677|  };
 5130|    677|  uint64_t broadcast_80 = broadcast(0x80);
 5131|    677|  uint64_t broadcast_Ap = broadcast(128 - 'A');
 5132|    677|  uint64_t broadcast_Zp = broadcast(128 - 'Z' - 1);
 5133|    677|  size_t i = 0;
 5134|       |
 5135|    803|  for (; i + 7 < length; i += 8) {
  ------------------
  |  Branch (5135:10): [True: 126, False: 677]
  ------------------
 5136|    126|    uint64_t word{};
 5137|    126|    std::memcpy(&word, input + i, sizeof(word));
 5138|    126|    word ^=
 5139|    126|        (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
 5140|    126|    std::memcpy(input + i, &word, sizeof(word));
 5141|    126|  }
 5142|    677|  if (i < length) {
  ------------------
  |  Branch (5142:7): [True: 106, False: 571]
  ------------------
 5143|    106|    uint64_t word{};
 5144|    106|    std::memcpy(&word, input + i, length - i);
 5145|    106|    word ^=
 5146|    106|        (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
 5147|    106|    std::memcpy(input + i, &word, length - i);
 5148|    106|  }
 5149|    677|}
_ZN3ada4idna3mapENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEERNS1_12basic_stringIDiS4_NS1_9allocatorIDiEEEE:
 5153|  3.34k|bool map(std::u32string_view input, std::u32string& out) {
 5154|       |  //  [Map](https://www.unicode.org/reports/tr46/#ProcessingStepMap).
 5155|  3.34k|  out.clear();
 5156|  3.34k|  if (!ensure_tables()) {
  ------------------
  |  Branch (5156:7): [True: 0, False: 3.34k]
  ------------------
 5157|      0|    return false;
 5158|      0|  }
 5159|       |
 5160|       |  // Pass 1: validate and compute exact output length.
 5161|  3.34k|  size_t out_size = 0;
 5162|  25.6k|  for (char32_t x : input) {
  ------------------
  |  Branch (5162:19): [True: 25.6k, False: 3.11k]
  ------------------
 5163|  25.6k|    uint16_t status = idna_lookup(static_cast<uint32_t>(x));
 5164|  25.6k|    if (status == IDNA_DISALLOWED) {
  ------------------
  |  Branch (5164:9): [True: 238, False: 25.3k]
  ------------------
 5165|    238|      return false;
 5166|    238|    }
 5167|  25.3k|    if (status == IDNA_VALID) {
  ------------------
  |  Branch (5167:9): [True: 18.7k, False: 6.60k]
  ------------------
 5168|  18.7k|      ++out_size;
 5169|  18.7k|      continue;
 5170|  18.7k|    }
 5171|  6.60k|    if (static_cast<size_t>(status) >= idna_utf8_mappings_size) {
  ------------------
  |  Branch (5171:9): [True: 0, False: 6.60k]
  ------------------
 5172|      0|      return false;
 5173|      0|    }
 5174|  6.60k|    out_size += utf8_count_codepoints(idna_utf8_mappings + status);
 5175|  6.60k|  }
 5176|       |
 5177|       |  // Pass 2: write into a single allocation.
 5178|  3.11k|  out.resize(out_size);
 5179|  3.11k|  size_t w = 0;
 5180|  25.2k|  for (char32_t x : input) {
  ------------------
  |  Branch (5180:19): [True: 25.2k, False: 3.11k]
  ------------------
 5181|  25.2k|    uint16_t status = idna_lookup(static_cast<uint32_t>(x));
 5182|  25.2k|    if (status == IDNA_VALID) {
  ------------------
  |  Branch (5182:9): [True: 18.6k, False: 6.59k]
  ------------------
 5183|  18.6k|      out[w++] = x;
 5184|  18.6k|      continue;
 5185|  18.6k|    }
 5186|       |    // IGNORED or mapped (status already validated in pass 1).
 5187|  6.59k|    const uint8_t* ptr = idna_utf8_mappings + status;
 5188|  38.7k|    while (*ptr != 0) {
  ------------------
  |  Branch (5188:12): [True: 32.1k, False: 6.59k]
  ------------------
 5189|  32.1k|      out[w++] = utf8_next(ptr);
 5190|  32.1k|    }
 5191|  6.59k|  }
 5192|  3.11k|  return true;
 5193|  3.34k|}
_ZN3ada4idna28compute_decomposition_lengthENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5286|    828|    const std::u32string_view input) noexcept {
 5287|    828|  bool decomposition_needed{false};
 5288|    828|  size_t additional_elements{0};
 5289|  10.2k|  for (char32_t current_character : input) {
  ------------------
  |  Branch (5289:35): [True: 10.2k, False: 828]
  ------------------
 5290|  10.2k|    size_t decomposition_length{0};
 5291|       |
 5292|  10.2k|    if (current_character >= hangul_sbase &&
  ------------------
  |  Branch (5292:9): [True: 1.11k, False: 9.16k]
  ------------------
 5293|  1.11k|        current_character < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (5293:9): [True: 632, False: 485]
  ------------------
 5294|       |      // Full NFD-style Hangul decomp for the decompose() step.
 5295|    632|      decomposition_length = 2;
 5296|    632|      if ((current_character - hangul_sbase) % hangul_tcount) {
  ------------------
  |  Branch (5296:11): [True: 424, False: 208]
  ------------------
 5297|    424|        decomposition_length = 3;
 5298|    424|      }
 5299|  9.65k|    } else if (current_character < 0x110000) {
  ------------------
  |  Branch (5299:16): [True: 9.65k, False: 0]
  ------------------
 5300|  9.65k|      const uint8_t di = decomposition_index[current_character >> 8];
 5301|  9.65k|      const uint16_t* const decomposition =
 5302|  9.65k|          decomposition_block_row(di) + (current_character % 256);
 5303|  9.65k|      decomposition_length = (decomposition[1] >> 2) - (decomposition[0] >> 2);
 5304|  9.65k|      if ((decomposition_length > 0) && (decomposition[0] & 1)) {
  ------------------
  |  Branch (5304:11): [True: 702, False: 8.95k]
  |  Branch (5304:41): [True: 0, False: 702]
  ------------------
 5305|      0|        decomposition_length = 0;
 5306|      0|      }
 5307|  9.65k|    }
 5308|  10.2k|    if (decomposition_length != 0) {
  ------------------
  |  Branch (5308:9): [True: 1.33k, False: 8.95k]
  ------------------
 5309|  1.33k|      decomposition_needed = true;
 5310|  1.33k|      additional_elements += decomposition_length - 1;
 5311|  1.33k|    }
 5312|  10.2k|  }
 5313|    828|  return {decomposition_needed, additional_elements};
 5314|    828|}
_ZN3ada4idna9decomposeERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEEm:
 5316|    456|void decompose(std::u32string& input, size_t additional_elements) {
 5317|    456|  input.resize(input.size() + additional_elements);
 5318|    456|  for (size_t descending_idx = input.size(),
 5319|    456|              input_count = descending_idx - additional_elements;
 5320|  5.41k|       input_count--;) {
  ------------------
  |  Branch (5320:8): [True: 4.95k, False: 456]
  ------------------
 5321|  4.95k|    if (input[input_count] >= hangul_sbase &&
  ------------------
  |  Branch (5321:9): [True: 1.00k, False: 3.94k]
  ------------------
 5322|  1.00k|        input[input_count] < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (5322:9): [True: 632, False: 377]
  ------------------
 5323|       |      // Hangul decomposition.
 5324|    632|      char32_t s_index = input[input_count] - hangul_sbase;
 5325|    632|      if (s_index % hangul_tcount != 0) {
  ------------------
  |  Branch (5325:11): [True: 424, False: 208]
  ------------------
 5326|    424|        input[--descending_idx] = hangul_tbase + s_index % hangul_tcount;
 5327|    424|      }
 5328|    632|      input[--descending_idx] =
 5329|    632|          hangul_vbase + (s_index % hangul_ncount) / hangul_tcount;
 5330|    632|      input[--descending_idx] = hangul_lbase + s_index / hangul_ncount;
 5331|  4.32k|    } else if (input[input_count] < 0x110000) {
  ------------------
  |  Branch (5331:16): [True: 4.32k, False: 0]
  ------------------
 5332|  4.32k|      const uint16_t* decomposition =
 5333|  4.32k|          decomposition_block_row(
 5334|  4.32k|              decomposition_index[input[input_count] >> 8]) +
 5335|  4.32k|          (input[input_count] % 256);
 5336|  4.32k|      uint16_t decomposition_length =
 5337|  4.32k|          (decomposition[1] >> 2) - (decomposition[0] >> 2);
 5338|  4.32k|      if (decomposition_length > 0 && (decomposition[0] & 1)) {
  ------------------
  |  Branch (5338:11): [True: 702, False: 3.62k]
  |  Branch (5338:39): [True: 0, False: 702]
  ------------------
 5339|      0|        decomposition_length = 0;
 5340|      0|      }
 5341|  4.32k|      if (decomposition_length > 0) {
  ------------------
  |  Branch (5341:11): [True: 702, False: 3.62k]
  ------------------
 5342|    702|        const size_t base = static_cast<size_t>(decomposition[0] >> 2);
 5343|    702|        if (base + decomposition_length > decomposition_data_size) {
  ------------------
  |  Branch (5343:13): [True: 0, False: 702]
  ------------------
 5344|      0|          input[--descending_idx] = input[input_count];
 5345|    702|        } else {
 5346|  2.41k|          while (decomposition_length-- > 0) {
  ------------------
  |  Branch (5346:18): [True: 1.70k, False: 702]
  ------------------
 5347|  1.70k|            input[--descending_idx] =
 5348|  1.70k|                decomposition_data[base + decomposition_length];
 5349|  1.70k|          }
 5350|    702|        }
 5351|  3.62k|      } else {
 5352|  3.62k|        input[--descending_idx] = input[input_count];
 5353|  3.62k|      }
 5354|  4.32k|    } else {
 5355|      0|      input[--descending_idx] = input[input_count];
 5356|      0|    }
 5357|  4.95k|  }
 5358|    456|}
_ZN3ada4idna7get_cccEDi:
 5360|   132k|uint8_t get_ccc(char32_t c) noexcept {
 5361|   132k|  if (c >= 0x110000) {
  ------------------
  |  Branch (5361:7): [True: 0, False: 132k]
  ------------------
 5362|      0|    return 0;
 5363|      0|  }
 5364|   132k|  return ccc_block_row(ccc_index[c >> 8])[c % 256];
 5365|   132k|}
_ZN3ada4idna10sort_marksERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEE:
 5367|    828|void sort_marks(std::u32string& input) {
 5368|  12.3k|  for (size_t idx = 1; idx < input.size(); idx++) {
  ------------------
  |  Branch (5368:24): [True: 11.5k, False: 828]
  ------------------
 5369|  11.5k|    uint8_t ccc = get_ccc(input[idx]);
 5370|  11.5k|    if (ccc == 0) {
  ------------------
  |  Branch (5370:9): [True: 9.01k, False: 2.50k]
  ------------------
 5371|  9.01k|      continue;
 5372|  9.01k|    }
 5373|  2.50k|    auto current_character = input[idx];
 5374|  2.50k|    size_t back_idx = idx;
 5375|  3.79k|    while (back_idx != 0 && get_ccc(input[back_idx - 1]) > ccc) {
  ------------------
  |  Branch (5375:12): [True: 3.69k, False: 102]
  |  Branch (5375:29): [True: 1.29k, False: 2.39k]
  ------------------
 5376|  1.29k|      input[back_idx] = input[back_idx - 1];
 5377|  1.29k|      back_idx--;
 5378|  1.29k|    }
 5379|  2.50k|    input[back_idx] = current_character;
 5380|  2.50k|  }
 5381|    828|}
_ZN3ada4idna13decompose_nfcERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEE:
 5383|    828|void decompose_nfc(std::u32string& input) {
 5384|       |  /**
 5385|       |   * Decompose the domain_name string to Unicode Normalization Form C.
 5386|       |   * @see https://www.unicode.org/reports/tr46/#ProcessingStepDecompose
 5387|       |   */
 5388|    828|  auto [decomposition_needed, additional_elements] =
 5389|    828|      compute_decomposition_length(input);
 5390|    828|  if (decomposition_needed) {
  ------------------
  |  Branch (5390:7): [True: 456, False: 372]
  ------------------
 5391|    456|    decompose(input, additional_elements);
 5392|    456|  }
 5393|    828|  sort_marks(input);
 5394|    828|}
_ZN3ada4idna14is_already_nfcENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5477|  3.18k|bool is_already_nfc(std::u32string_view input) noexcept {
 5478|  3.18k|  if (input.empty()) {
  ------------------
  |  Branch (5478:7): [True: 0, False: 3.18k]
  ------------------
 5479|      0|    return true;
 5480|      0|  }
 5481|  3.18k|  if (!tables_are_ready() && !ensure_tables()) {
  ------------------
  |  Branch (5481:7): [True: 0, False: 3.18k]
  |  Branch (5481:30): [True: 0, False: 0]
  ------------------
 5482|      0|    return false;
 5483|      0|  }
 5484|       |  // 1) Singleton decompositions are never NFC (e.g. U+212B ANGSTROM SIGN).
 5485|       |  //    Multi-code-point decomps are primary composites that are NFC as-is.
 5486|  41.7k|  for (char32_t c : input) {
  ------------------
  |  Branch (5486:19): [True: 41.7k, False: 3.18k]
  ------------------
 5487|  41.7k|    if (canonical_decomp_length(c) == 1) {
  ------------------
  |  Branch (5487:9): [True: 0, False: 41.7k]
  ------------------
 5488|      0|      return false;
 5489|      0|    }
 5490|  41.7k|  }
 5491|       |  // 2) Combining marks already in canonical order. prev_ccc carries the
 5492|       |  //    trailing class of the previous character's canonical decomposition so a
 5493|       |  //    composite starter followed by a lower-class mark is caught.
 5494|  3.18k|  uint8_t prev_ccc = 0;
 5495|  40.0k|  for (char32_t c : input) {
  ------------------
  |  Branch (5495:19): [True: 40.0k, False: 2.41k]
  ------------------
 5496|  40.0k|    uint8_t ccc = get_ccc(c);
 5497|  40.0k|    if (ccc != 0 && prev_ccc > ccc) {
  ------------------
  |  Branch (5497:9): [True: 3.72k, False: 36.2k]
  |  Branch (5497:21): [True: 768, False: 2.96k]
  ------------------
 5498|    768|      return false;
 5499|    768|    }
 5500|  39.2k|    prev_ccc = trailing_ccc(c);
 5501|  39.2k|  }
 5502|       |  // 3) No pairwise composition would apply (including Hangul L+V / LV+T).
 5503|  2.41k|  return !would_compose(input);
 5504|  3.18k|}
_ZN3ada4idna7composeERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEE:
 5506|    828|void compose(std::u32string& input) {
 5507|       |  /**
 5508|       |   * Compose the domain_name string to Unicode Normalization Form C.
 5509|       |   * @see https://www.unicode.org/reports/tr46/#ProcessingStepCompose
 5510|       |   */
 5511|    828|  size_t input_count{0};
 5512|    828|  size_t composition_count{0};
 5513|  9.55k|  for (; input_count < input.size(); input_count++, composition_count++) {
  ------------------
  |  Branch (5513:10): [True: 8.72k, False: 828]
  ------------------
 5514|  8.72k|    input[composition_count] = input[input_count];
 5515|  8.72k|    if (input[input_count] >= hangul_lbase &&
  ------------------
  |  Branch (5515:9): [True: 1.69k, False: 7.02k]
  ------------------
 5516|  1.69k|        input[input_count] < hangul_lbase + hangul_lcount) {
  ------------------
  |  Branch (5516:9): [True: 863, False: 834]
  ------------------
 5517|    863|      if (input_count + 1 < input.size() &&
  ------------------
  |  Branch (5517:11): [True: 847, False: 16]
  ------------------
 5518|    847|          input[input_count + 1] >= hangul_vbase &&
  ------------------
  |  Branch (5518:11): [True: 736, False: 111]
  ------------------
 5519|    736|          input[input_count + 1] < hangul_vbase + hangul_vcount) {
  ------------------
  |  Branch (5519:11): [True: 679, False: 57]
  ------------------
 5520|    679|        input[composition_count] =
 5521|    679|            hangul_sbase +
 5522|    679|            ((input[input_count] - hangul_lbase) * hangul_vcount +
 5523|    679|             input[input_count + 1] - hangul_vbase) *
 5524|    679|                hangul_tcount;
 5525|    679|        input_count++;
 5526|    679|        if (input_count + 1 < input.size() &&
  ------------------
  |  Branch (5526:13): [True: 642, False: 37]
  ------------------
 5527|    642|            input[input_count + 1] > hangul_tbase &&
  ------------------
  |  Branch (5527:13): [True: 475, False: 167]
  ------------------
 5528|    475|            input[input_count + 1] < hangul_tbase + hangul_tcount) {
  ------------------
  |  Branch (5528:13): [True: 424, False: 51]
  ------------------
 5529|    424|          input[composition_count] += input[++input_count] - hangul_tbase;
 5530|    424|        }
 5531|    679|      }
 5532|  7.86k|    } else if (input[input_count] >= hangul_sbase &&
  ------------------
  |  Branch (5532:16): [True: 402, False: 7.45k]
  ------------------
 5533|    402|               input[input_count] < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (5533:16): [True: 0, False: 402]
  ------------------
 5534|      0|      if ((input[input_count] - hangul_sbase) % hangul_tcount &&
  ------------------
  |  Branch (5534:11): [True: 0, False: 0]
  ------------------
 5535|      0|          input_count + 1 < input.size() &&
  ------------------
  |  Branch (5535:11): [True: 0, False: 0]
  ------------------
 5536|      0|          input[input_count + 1] > hangul_tbase &&
  ------------------
  |  Branch (5536:11): [True: 0, False: 0]
  ------------------
 5537|      0|          input[input_count + 1] < hangul_tbase + hangul_tcount) {
  ------------------
  |  Branch (5537:11): [True: 0, False: 0]
  ------------------
 5538|      0|        input[composition_count] += input[++input_count] - hangul_tbase;
 5539|      0|      }
 5540|  7.86k|    } else if (input[input_count] < 0x110000) {
  ------------------
  |  Branch (5540:16): [True: 7.86k, False: 0]
  ------------------
 5541|  7.86k|      const uint16_t* composition =
 5542|  7.86k|          composition_block_row(composition_index[input[input_count] >> 8]) +
 5543|  7.86k|          (input[input_count] % 256);
 5544|  7.86k|      size_t initial_composition_count = composition_count;
 5545|  10.3k|      for (int32_t previous_ccc = -1; input_count + 1 < input.size();
  ------------------
  |  Branch (5545:39): [True: 9.62k, False: 755]
  ------------------
 5546|  9.62k|           input_count++) {
 5547|  9.62k|        uint8_t ccc = get_ccc(input[input_count + 1]);
 5548|       |
 5549|  9.62k|        if (composition[1] != composition[0] && previous_ccc < ccc) {
  ------------------
  |  Branch (5549:13): [True: 3.88k, False: 5.74k]
  |  Branch (5549:49): [True: 3.73k, False: 144]
  ------------------
 5550|  3.73k|          int left = composition[0];
 5551|  3.73k|          int right = composition[1];
 5552|  3.73k|          if (left < 0 || right < left ||
  ------------------
  |  Branch (5552:15): [True: 0, False: 3.73k]
  |  Branch (5552:27): [True: 0, False: 3.73k]
  ------------------
 5553|  3.73k|              static_cast<size_t>(right) > composition_data_size) {
  ------------------
  |  Branch (5553:15): [True: 0, False: 3.73k]
  ------------------
 5554|      0|            break;
 5555|      0|          }
 5556|  9.72k|          while (left + 2 < right) {
  ------------------
  |  Branch (5556:18): [True: 5.99k, False: 3.73k]
  ------------------
 5557|  5.99k|            int middle = left + (((right - left) >> 1) & ~1);
 5558|  5.99k|            if (composition_data[static_cast<size_t>(middle)] <=
  ------------------
  |  Branch (5558:17): [True: 2.60k, False: 3.38k]
  ------------------
 5559|  5.99k|                input[input_count + 1]) {
 5560|  2.60k|              left = middle;
 5561|  2.60k|            }
 5562|  5.99k|            if (composition_data[static_cast<size_t>(middle)] >=
  ------------------
  |  Branch (5562:17): [True: 4.31k, False: 1.67k]
  ------------------
 5563|  5.99k|                input[input_count + 1]) {
 5564|  4.31k|              right = middle;
 5565|  4.31k|            }
 5566|  5.99k|          }
 5567|  3.73k|          if (static_cast<size_t>(left + 1) < composition_data_size &&
  ------------------
  |  Branch (5567:15): [True: 3.73k, False: 0]
  ------------------
 5568|  3.73k|              composition_data[static_cast<size_t>(left)] ==
  ------------------
  |  Branch (5568:15): [True: 1.36k, False: 2.37k]
  ------------------
 5569|  3.73k|                  input[input_count + 1]) {
 5570|  1.36k|            char32_t composed = composition_data[static_cast<size_t>(left + 1)];
 5571|  1.36k|            input[initial_composition_count] = composed;
 5572|  1.36k|            composition =
 5573|  1.36k|                composition_block_row(composition_index[composed >> 8]) +
 5574|  1.36k|                (composed % 256);
 5575|  1.36k|            continue;
 5576|  1.36k|          }
 5577|  3.73k|        }
 5578|       |
 5579|  8.25k|        if (ccc == 0) {
  ------------------
  |  Branch (5579:13): [True: 7.10k, False: 1.15k]
  ------------------
 5580|  7.10k|          break;
 5581|  7.10k|        }
 5582|  1.15k|        previous_ccc = ccc;
 5583|  1.15k|        input[++composition_count] = input[input_count + 1];
 5584|  1.15k|      }
 5585|  7.86k|    }
 5586|  8.72k|  }
 5587|       |
 5588|    828|  if (composition_count < input_count) {
  ------------------
  |  Branch (5588:7): [True: 728, False: 100]
  ------------------
 5589|    728|    input.resize(composition_count);
 5590|    728|  }
 5591|    828|}
_ZN3ada4idna9normalizeERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEE:
 5593|    828|bool normalize(std::u32string& input) {
 5594|       |  /**
 5595|       |   * Normalize the characters according to IDNA (Unicode Normalization Form C).
 5596|       |   * @see https://www.unicode.org/reports/tr46/#ProcessingStepNormalize
 5597|       |   */
 5598|    828|  if (!ensure_tables() || decomposition_index == nullptr ||
  ------------------
  |  Branch (5598:7): [True: 0, False: 828]
  |  Branch (5598:27): [True: 0, False: 828]
  ------------------
 5599|    828|      composition_index == nullptr) {
  ------------------
  |  Branch (5599:7): [True: 0, False: 828]
  ------------------
 5600|      0|    return false;
 5601|      0|  }
 5602|    828|  if (is_already_nfc(input)) {
  ------------------
  |  Branch (5602:7): [True: 0, False: 828]
  ------------------
 5603|      0|    return true;
 5604|      0|  }
 5605|    828|  decompose_nfc(input);
 5606|    828|  compose(input);
 5607|    828|  return true;
 5608|    828|}
_ZN3ada4idna17punycode_to_utf32ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEERNS1_12basic_stringIDiNS3_IDiEENS1_9allocatorIDiEEEE:
 5668|  1.02k|bool punycode_to_utf32(std::string_view input, std::u32string &out) {
 5669|  1.02k|  int32_t written_out{0};
 5670|  1.02k|  out.reserve(out.size() + input.size());
 5671|  1.02k|  uint32_t n = initial_n;
 5672|  1.02k|  int32_t i = 0;
 5673|  1.02k|  int32_t bias = initial_bias;
 5674|       |  // grab ascii content
 5675|  1.02k|  size_t end_of_ascii = input.find_last_of('-');
 5676|  1.02k|  if (end_of_ascii != std::string_view::npos) {
  ------------------
  |  Branch (5676:7): [True: 191, False: 830]
  ------------------
 5677|  1.03k|    for (uint8_t c : input.substr(0, end_of_ascii)) {
  ------------------
  |  Branch (5677:20): [True: 1.03k, False: 191]
  ------------------
 5678|  1.03k|      if (c >= 0x80) {
  ------------------
  |  Branch (5678:11): [True: 0, False: 1.03k]
  ------------------
 5679|      0|        return false;
 5680|      0|      }
 5681|  1.03k|      out.push_back(c);
 5682|  1.03k|      written_out++;
 5683|  1.03k|    }
 5684|    191|    input.remove_prefix(end_of_ascii + 1);
 5685|    191|  }
 5686|  6.30k|  while (!input.empty()) {
  ------------------
  |  Branch (5686:10): [True: 5.39k, False: 907]
  ------------------
 5687|  5.39k|    int32_t oldi = i;
 5688|  5.39k|    int32_t w = 1;
 5689|  8.95k|    for (int32_t k = base;; k += base) {
 5690|  8.95k|      if (input.empty()) {
  ------------------
  |  Branch (5690:11): [True: 62, False: 8.89k]
  ------------------
 5691|     62|        return false;
 5692|     62|      }
 5693|  8.89k|      uint8_t code_point = input.front();
 5694|  8.89k|      input.remove_prefix(1);
 5695|  8.89k|      int32_t digit = char_to_digit_value(code_point);
 5696|  8.89k|      if (digit < 0) {
  ------------------
  |  Branch (5696:11): [True: 18, False: 8.87k]
  ------------------
 5697|     18|        return false;
 5698|     18|      }
 5699|  8.87k|      if (digit > (0x7fffffff - i) / w) {
  ------------------
  |  Branch (5699:11): [True: 5, False: 8.86k]
  ------------------
 5700|      5|        return false;
 5701|      5|      }
 5702|  8.86k|      i = i + digit * w;
 5703|  8.86k|      int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias;
  ------------------
  |  Branch (5703:19): [True: 2.19k, False: 6.67k]
  |  Branch (5703:38): [True: 6.23k, False: 446]
  ------------------
 5704|  8.86k|      if (digit < t) {
  ------------------
  |  Branch (5704:11): [True: 5.31k, False: 3.55k]
  ------------------
 5705|  5.31k|        break;
 5706|  5.31k|      }
 5707|  3.55k|      if (w > 0x7fffffff / (base - t)) {
  ------------------
  |  Branch (5707:11): [True: 0, False: 3.55k]
  ------------------
 5708|      0|        return false;
 5709|      0|      }
 5710|  3.55k|      w = w * (base - t);
 5711|  3.55k|    }
 5712|  5.31k|    bias = adapt(i - oldi, written_out + 1, oldi == 0);
 5713|  5.31k|    if (i / (written_out + 1) > int32_t(0x7fffffff - n)) {
  ------------------
  |  Branch (5713:9): [True: 29, False: 5.28k]
  ------------------
 5714|     29|      return false;
 5715|     29|    }
 5716|  5.28k|    n = n + i / (written_out + 1);
 5717|  5.28k|    i = i % (written_out + 1);
 5718|  5.28k|    if (n < 0x80) {
  ------------------
  |  Branch (5718:9): [True: 0, False: 5.28k]
  ------------------
 5719|      0|      return false;
 5720|      0|    }
 5721|  5.28k|    out.insert(out.begin() + i, n);
 5722|  5.28k|    written_out++;
 5723|  5.28k|    ++i;
 5724|  5.28k|  }
 5725|       |  // See https://github.com/whatwg/url/issues/803
 5726|       |  // Reject labels whose decoded form begins with "xn--" (double-encoded ACE).
 5727|    907|  if (out.size() >= 4 && out[0] == U'x' && out[1] == U'n' && out[2] == U'-' &&
  ------------------
  |  Branch (5727:7): [True: 395, False: 512]
  |  Branch (5727:26): [True: 109, False: 286]
  |  Branch (5727:44): [True: 71, False: 38]
  |  Branch (5727:62): [True: 40, False: 31]
  ------------------
 5728|     40|      out[3] == U'-') {
  ------------------
  |  Branch (5728:7): [True: 1, False: 39]
  ------------------
 5729|      1|    return false;
 5730|      1|  }
 5731|    906|  return true;
 5732|    907|}
_ZN3ada4idna17utf32_to_punycodeENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEERNS1_12basic_stringIcNS3_IcEENS1_9allocatorIcEEEE:
 5812|  1.61k|bool utf32_to_punycode(std::u32string_view input, std::string &out) {
 5813|  1.61k|  out.reserve(input.size() + out.size());
 5814|  1.61k|  uint32_t n = initial_n;
 5815|  1.61k|  int32_t d = 0;
 5816|  1.61k|  int32_t bias = initial_bias;
 5817|  1.61k|  size_t h = 0;
 5818|       |  // first push the ascii content
 5819|  12.2k|  for (uint32_t c : input) {
  ------------------
  |  Branch (5819:19): [True: 12.2k, False: 1.61k]
  ------------------
 5820|  12.2k|    if (c < 0x80) {
  ------------------
  |  Branch (5820:9): [True: 2.43k, False: 9.76k]
  ------------------
 5821|  2.43k|      ++h;
 5822|  2.43k|      out.push_back(char(c));
 5823|  2.43k|    }
 5824|  12.2k|    if (c > 0x10ffff || (c >= 0xd800 && c < 0xe000)) {
  ------------------
  |  Branch (5824:9): [True: 0, False: 12.2k]
  |  Branch (5824:26): [True: 326, False: 11.8k]
  |  Branch (5824:41): [True: 0, False: 326]
  ------------------
 5825|      0|      return false;
 5826|      0|    }
 5827|  12.2k|  }
 5828|  1.61k|  size_t b = h;
 5829|  1.61k|  if (b > 0) {
  ------------------
  |  Branch (5829:7): [True: 626, False: 985]
  ------------------
 5830|    626|    out.push_back('-');
 5831|    626|  }
 5832|  5.82k|  while (h < input.size()) {
  ------------------
  |  Branch (5832:10): [True: 4.21k, False: 1.61k]
  ------------------
 5833|  4.21k|    uint32_t m = 0x10FFFF;
 5834|   102k|    for (auto code_point : input) {
  ------------------
  |  Branch (5834:26): [True: 102k, False: 4.21k]
  ------------------
 5835|   102k|      if (code_point >= n && code_point < m) m = code_point;
  ------------------
  |  Branch (5835:11): [True: 43.8k, False: 58.5k]
  |  Branch (5835:30): [True: 6.94k, False: 36.9k]
  ------------------
 5836|   102k|    }
 5837|       |
 5838|  4.21k|    if ((m - n) > (0x7fffffff - d) / (h + 1)) {
  ------------------
  |  Branch (5838:9): [True: 0, False: 4.21k]
  ------------------
 5839|      0|      return false;
 5840|      0|    }
 5841|  4.21k|    d = d + int32_t((m - n) * (h + 1));
 5842|  4.21k|    n = m;
 5843|   102k|    for (auto c : input) {
  ------------------
  |  Branch (5843:17): [True: 102k, False: 4.21k]
  ------------------
 5844|   102k|      if (c < n) {
  ------------------
  |  Branch (5844:11): [True: 58.5k, False: 43.8k]
  ------------------
 5845|  58.5k|        if (d == 0x7fffffff) {
  ------------------
  |  Branch (5845:13): [True: 0, False: 58.5k]
  ------------------
 5846|      0|          return false;
 5847|      0|        }
 5848|  58.5k|        ++d;
 5849|  58.5k|      }
 5850|   102k|      if (c == n) {
  ------------------
  |  Branch (5850:11): [True: 9.76k, False: 92.6k]
  ------------------
 5851|  9.76k|        int32_t q = d;
 5852|  18.2k|        for (int32_t k = base;; k += base) {
 5853|  18.2k|          int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias;
  ------------------
  |  Branch (5853:23): [True: 4.02k, False: 14.2k]
  |  Branch (5853:42): [True: 12.8k, False: 1.44k]
  ------------------
 5854|       |
 5855|  18.2k|          if (q < t) {
  ------------------
  |  Branch (5855:15): [True: 9.76k, False: 8.53k]
  ------------------
 5856|  9.76k|            break;
 5857|  9.76k|          }
 5858|  8.53k|          out.push_back(digit_to_char(t + ((q - t) % (base - t))));
 5859|  8.53k|          q = (q - t) / (base - t);
 5860|  8.53k|        }
 5861|  9.76k|        out.push_back(digit_to_char(q));
 5862|  9.76k|        bias = adapt(d, int32_t(h + 1), h == b);
 5863|  9.76k|        d = 0;
 5864|  9.76k|        ++h;
 5865|  9.76k|      }
 5866|   102k|    }
 5867|  4.21k|    ++d;
 5868|  4.21k|    ++n;
 5869|  4.21k|  }
 5870|  1.61k|  return true;
 5871|  1.61k|}
_ZN3ada4idna14is_label_validENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5955|  2.73k|bool is_label_valid(const std::u32string_view label) {
 5956|  2.73k|  if (label.empty()) {
  ------------------
  |  Branch (5956:7): [True: 0, False: 2.73k]
  ------------------
 5957|      0|    return true;
 5958|      0|  }
 5959|  2.73k|  if (!ensure_tables() || combining_ranges == nullptr || dir_start == nullptr ||
  ------------------
  |  Branch (5959:7): [True: 0, False: 2.73k]
  |  Branch (5959:27): [True: 0, False: 2.73k]
  |  Branch (5959:58): [True: 0, False: 2.73k]
  ------------------
 5960|  2.73k|      dir_final == nullptr || dir_value == nullptr) {
  ------------------
  |  Branch (5960:7): [True: 0, False: 2.73k]
  |  Branch (5960:31): [True: 0, False: 2.73k]
  ------------------
 5961|      0|    return false;
 5962|      0|  }
 5963|       |
 5964|       |  ///////////////
 5965|       |  // We have a normalization step which ensures that we are in NFC.
 5966|       |  // If we receive punycode, we normalize and check that the normalized
 5967|       |  // version matches the original.
 5968|       |  // --------------------------------------
 5969|       |  // The label must be in Unicode Normalization Form NFC.
 5970|       |
 5971|       |  // Current URL standard indicatest that CheckHyphens is set to false.
 5972|       |  // ---------------------------------------
 5973|       |  // If CheckHyphens, the label must not contain a U+002D HYPHEN-MINUS character
 5974|       |  // in both the third and fourth positions. If CheckHyphens, the label must
 5975|       |  // neither begin nor end with a U+002D HYPHEN-MINUS character.
 5976|       |
 5977|       |  // This is not necessary because we segment the
 5978|       |  // labels by '.'.
 5979|       |  // ---------------------------------------
 5980|       |  // The label must not contain a U+002E ( . ) FULL STOP.
 5981|       |  // if (label.find('.') != std::string_view::npos) return false;
 5982|       |
 5983|       |  // The label must not begin with a combining mark.
 5984|       |  // Range membership via lower_bound on range end.
 5985|  2.73k|  const std::span<const uint32_t[2]> comb_span{combining_ranges,
 5986|  2.73k|                                               combining_range_count};
 5987|  2.73k|  const auto comb_it = std::ranges::lower_bound(
 5988|  2.73k|      comb_span, label.front(), {}, [](const auto& range) { return range[1]; });
 5989|  2.73k|  if (comb_it != comb_span.end() && label.front() >= (*comb_it)[0]) {
  ------------------
  |  Branch (5989:7): [True: 2.73k, False: 0]
  |  Branch (5989:7): [True: 112, False: 2.62k]
  |  Branch (5989:37): [True: 112, False: 2.62k]
  ------------------
 5990|    112|    return false;
 5991|    112|  }
 5992|       |  // We verify this next step as part of the mapping:
 5993|       |  // ---------------------------------------------
 5994|       |  // Each code point in the label must only have certain status values
 5995|       |  // according to Section 5, IDNA Mapping Table:
 5996|       |  // - For Transitional Processing, each value must be valid.
 5997|       |  // - For Nontransitional Processing, each value must be either valid or
 5998|       |  // deviation.
 5999|       |
 6000|       |  // If CheckJoiners, the label must satisfy the ContextJ rules from Appendix
 6001|       |  // A, in The Unicode Code Points and Internationalized Domain Names for
 6002|       |  // Applications (IDNA) [IDNA2008].
 6003|  2.62k|  constexpr static uint32_t virama[] = {
 6004|  2.62k|      0x094D,  0x09CD,  0x0A4D,  0x0ACD,  0x0B4D,  0x0BCD,  0x0C4D,  0x0CCD,
 6005|  2.62k|      0x0D3B,  0x0D3C,  0x0D4D,  0x0DCA,  0x0E3A,  0x0EBA,  0x0F84,  0x1039,
 6006|  2.62k|      0x103A,  0x1714,  0x1734,  0x17D2,  0x1A60,  0x1B44,  0x1BAA,  0x1BAB,
 6007|  2.62k|      0x1BF2,  0x1BF3,  0x2D7F,  0xA806,  0xA82C,  0xA8C4,  0xA953,  0xA9C0,
 6008|  2.62k|      0xAAF6,  0xABED,  0x10A3F, 0x11046, 0x1107F, 0x110B9, 0x11133, 0x11134,
 6009|  2.62k|      0x111C0, 0x11235, 0x112EA, 0x1134D, 0x11442, 0x114C2, 0x115BF, 0x1163F,
 6010|  2.62k|      0x116B6, 0x1172B, 0x11839, 0x1193D, 0x1193E, 0x119E0, 0x11A34, 0x11A47,
 6011|  2.62k|      0x11A99, 0x11C3F, 0x11D44, 0x11D45, 0x11D97};
 6012|  2.62k|  constexpr static uint32_t R[] = {
 6013|  2.62k|      0x622, 0x623, 0x624, 0x625, 0x627, 0x629, 0x62f, 0x630, 0x631,
 6014|  2.62k|      0x632, 0x648, 0x671, 0x672, 0x673, 0x675, 0x676, 0x677, 0x688,
 6015|  2.62k|      0x689, 0x68a, 0x68b, 0x68c, 0x68d, 0x68e, 0x68f, 0x690, 0x691,
 6016|  2.62k|      0x692, 0x693, 0x694, 0x695, 0x696, 0x697, 0x698, 0x699, 0x6c0,
 6017|  2.62k|      0x6c3, 0x6c4, 0x6c5, 0x6c6, 0x6c7, 0x6c8, 0x6c9, 0x6ca, 0x6cb,
 6018|  2.62k|      0x6cd, 0x6cf, 0x6d2, 0x6d3, 0x6d5, 0x6ee, 0x6ef, 0x710, 0x715,
 6019|  2.62k|      0x716, 0x717, 0x718, 0x719, 0x71e, 0x728, 0x72a, 0x72c, 0x72f,
 6020|  2.62k|      0x74d, 0x759, 0x75a, 0x75b, 0x854, 0x8aa, 0x8ab, 0x8ac};
 6021|  2.62k|  constexpr static uint32_t L[] = {0xa872};
 6022|  2.62k|  constexpr static uint32_t D[] = {
 6023|  2.62k|      0x620,  0x626,  0x628,  0x62a,  0x62b,  0x62c,  0x62d,  0x62e,  0x633,
 6024|  2.62k|      0x634,  0x635,  0x636,  0x637,  0x638,  0x639,  0x63a,  0x63b,  0x63c,
 6025|  2.62k|      0x63d,  0x63e,  0x63f,  0x641,  0x642,  0x643,  0x644,  0x645,  0x646,
 6026|  2.62k|      0x647,  0x649,  0x64a,  0x66e,  0x66f,  0x678,  0x679,  0x67a,  0x67b,
 6027|  2.62k|      0x67c,  0x67d,  0x67e,  0x67f,  0x680,  0x681,  0x682,  0x683,  0x684,
 6028|  2.62k|      0x685,  0x686,  0x687,  0x69a,  0x69b,  0x69c,  0x69d,  0x69e,  0x69f,
 6029|  2.62k|      0x6a0,  0x6a1,  0x6a2,  0x6a3,  0x6a4,  0x6a5,  0x6a6,  0x6a7,  0x6a8,
 6030|  2.62k|      0x6a9,  0x6aa,  0x6ab,  0x6ac,  0x6ad,  0x6ae,  0x6af,  0x6b0,  0x6b1,
 6031|  2.62k|      0x6b2,  0x6b3,  0x6b4,  0x6b5,  0x6b6,  0x6b7,  0x6b8,  0x6b9,  0x6ba,
 6032|  2.62k|      0x6bb,  0x6bc,  0x6bd,  0x6be,  0x6bf,  0x6c1,  0x6c2,  0x6cc,  0x6ce,
 6033|  2.62k|      0x6d0,  0x6d1,  0x6fa,  0x6fb,  0x6fc,  0x6ff,  0x712,  0x713,  0x714,
 6034|  2.62k|      0x71a,  0x71b,  0x71c,  0x71d,  0x71f,  0x720,  0x721,  0x722,  0x723,
 6035|  2.62k|      0x724,  0x725,  0x726,  0x727,  0x729,  0x72b,  0x72d,  0x72e,  0x74e,
 6036|  2.62k|      0x74f,  0x750,  0x751,  0x752,  0x753,  0x754,  0x755,  0x756,  0x757,
 6037|  2.62k|      0x758,  0x75c,  0x75d,  0x75e,  0x75f,  0x760,  0x761,  0x762,  0x763,
 6038|  2.62k|      0x764,  0x765,  0x766,  0x850,  0x851,  0x852,  0x853,  0x855,  0x8a0,
 6039|  2.62k|      0x8a2,  0x8a3,  0x8a4,  0x8a5,  0x8a6,  0x8a7,  0x8a8,  0x8a9,  0x1807,
 6040|  2.62k|      0x1820, 0x1821, 0x1822, 0x1823, 0x1824, 0x1825, 0x1826, 0x1827, 0x1828,
 6041|  2.62k|      0x1829, 0x182a, 0x182b, 0x182c, 0x182d, 0x182e, 0x182f, 0x1830, 0x1831,
 6042|  2.62k|      0x1832, 0x1833, 0x1834, 0x1835, 0x1836, 0x1837, 0x1838, 0x1839, 0x183a,
 6043|  2.62k|      0x183b, 0x183c, 0x183d, 0x183e, 0x183f, 0x1840, 0x1841, 0x1842, 0x1843,
 6044|  2.62k|      0x1844, 0x1845, 0x1846, 0x1847, 0x1848, 0x1849, 0x184a, 0x184b, 0x184c,
 6045|  2.62k|      0x184d, 0x184e, 0x184f, 0x1850, 0x1851, 0x1852, 0x1853, 0x1854, 0x1855,
 6046|  2.62k|      0x1856, 0x1857, 0x1858, 0x1859, 0x185a, 0x185b, 0x185c, 0x185d, 0x185e,
 6047|  2.62k|      0x185f, 0x1860, 0x1861, 0x1862, 0x1863, 0x1864, 0x1865, 0x1866, 0x1867,
 6048|  2.62k|      0x1868, 0x1869, 0x186a, 0x186b, 0x186c, 0x186d, 0x186e, 0x186f, 0x1870,
 6049|  2.62k|      0x1871, 0x1872, 0x1873, 0x1874, 0x1875, 0x1876, 0x1877, 0x1887, 0x1888,
 6050|  2.62k|      0x1889, 0x188a, 0x188b, 0x188c, 0x188d, 0x188e, 0x188f, 0x1890, 0x1891,
 6051|  2.62k|      0x1892, 0x1893, 0x1894, 0x1895, 0x1896, 0x1897, 0x1898, 0x1899, 0x189a,
 6052|  2.62k|      0x189b, 0x189c, 0x189d, 0x189e, 0x189f, 0x18a0, 0x18a1, 0x18a2, 0x18a3,
 6053|  2.62k|      0x18a4, 0x18a5, 0x18a6, 0x18a7, 0x18a8, 0x18aa, 0xa840, 0xa841, 0xa842,
 6054|  2.62k|      0xa843, 0xa844, 0xa845, 0xa846, 0xa847, 0xa848, 0xa849, 0xa84a, 0xa84b,
 6055|  2.62k|      0xa84c, 0xa84d, 0xa84e, 0xa84f, 0xa850, 0xa851, 0xa852, 0xa853, 0xa854,
 6056|  2.62k|      0xa855, 0xa856, 0xa857, 0xa858, 0xa859, 0xa85a, 0xa85b, 0xa85c, 0xa85d,
 6057|  2.62k|      0xa85e, 0xa85f, 0xa860, 0xa861, 0xa862, 0xa863, 0xa864, 0xa865, 0xa866,
 6058|  2.62k|      0xa867, 0xa868, 0xa869, 0xa86a, 0xa86b, 0xa86c, 0xa86d, 0xa86e, 0xa86f,
 6059|  2.62k|      0xa870, 0xa871};
 6060|       |
 6061|  23.7k|  for (size_t i = 0; i < label.size(); i++) {
  ------------------
  |  Branch (6061:22): [True: 21.5k, False: 2.15k]
  ------------------
 6062|  21.5k|    uint32_t c = label[i];
 6063|  21.5k|    if (c == 0x200c) {
  ------------------
  |  Branch (6063:9): [True: 373, False: 21.1k]
  ------------------
 6064|    373|      if (i > 0) {
  ------------------
  |  Branch (6064:11): [True: 370, False: 3]
  ------------------
 6065|    370|        if (std::ranges::binary_search(virama, label[i - 1])) {
  ------------------
  |  Branch (6065:13): [True: 45, False: 325]
  ------------------
 6066|     45|          return true;
 6067|     45|        }
 6068|    370|      }
 6069|    328|      if ((i == 0) || (i + 1 >= label.size())) {
  ------------------
  |  Branch (6069:11): [True: 3, False: 325]
  |  Branch (6069:23): [True: 51, False: 274]
  ------------------
 6070|     54|        return false;
 6071|     54|      }
 6072|       |      // we go backward looking for L or D
 6073|    274|      auto is_l_or_d = [](uint32_t code) {
 6074|    274|        return std::ranges::binary_search(L, code) ||
 6075|    274|               std::ranges::binary_search(D, code);
 6076|    274|      };
 6077|    274|      auto is_r_or_d = [](uint32_t code) {
 6078|    274|        return std::ranges::binary_search(R, code) ||
 6079|    274|               std::ranges::binary_search(D, code);
 6080|    274|      };
 6081|    274|      std::u32string_view before = label.substr(0, i);
 6082|    274|      std::u32string_view after = label.substr(i + 1);
 6083|    274|      return (std::find_if(before.begin(), before.end(), is_l_or_d) !=
  ------------------
  |  Branch (6083:14): [True: 227, False: 47]
  ------------------
 6084|    274|              before.end()) &&
 6085|    227|             (std::find_if(after.begin(), after.end(), is_r_or_d) !=
  ------------------
  |  Branch (6085:14): [True: 136, False: 91]
  ------------------
 6086|    227|              after.end());
 6087|  21.1k|    } else if (c == 0x200d) {
  ------------------
  |  Branch (6087:16): [True: 96, False: 21.0k]
  ------------------
 6088|     96|      if (i > 0) {
  ------------------
  |  Branch (6088:11): [True: 93, False: 3]
  ------------------
 6089|     93|        if (std::ranges::binary_search(virama, label[i - 1])) {
  ------------------
  |  Branch (6089:13): [True: 59, False: 34]
  ------------------
 6090|     59|          return true;
 6091|     59|        }
 6092|     93|      }
 6093|     37|      return false;
 6094|     96|    }
 6095|  21.5k|  }
 6096|       |
 6097|       |  // If CheckBidi, and if the domain name is a  Bidi domain name, then the label
 6098|       |  // must satisfy all six of the numbered conditions in [IDNA2008] RFC 5893,
 6099|       |  // Section 2.
 6100|       |
 6101|       |  // The following rule, consisting of six conditions, applies to labels
 6102|       |  // in Bidi domain names.  The requirements that this rule satisfies are
 6103|       |  // described in Section 3.  All of the conditions must be satisfied for
 6104|       |  // the rule to be satisfied.
 6105|       |  //
 6106|       |  //  1.  The first character must be a character with Bidi property L, R,
 6107|       |  //     or AL.  If it has the R or AL property, it is an RTL label; if it
 6108|       |  //     has the L property, it is an LTR label.
 6109|       |  //
 6110|       |  //  2.  In an RTL label, only characters with the Bidi properties R, AL,
 6111|       |  //      AN, EN, ES, CS, ET, ON, BN, or NSM are allowed.
 6112|       |  //
 6113|       |  //   3.  In an RTL label, the end of the label must be a character with
 6114|       |  //       Bidi property R, AL, EN, or AN, followed by zero or more
 6115|       |  //       characters with Bidi property NSM.
 6116|       |  //
 6117|       |  //   4.  In an RTL label, if an EN is present, no AN may be present, and
 6118|       |  //       vice versa.
 6119|       |  //
 6120|       |  //  5.  In an LTR label, only characters with the Bidi properties L, EN,
 6121|       |  //       ES, CS, ET, ON, BN, or NSM are allowed.
 6122|       |  //
 6123|       |  //   6.  In an LTR label, the end of the label must be a character with
 6124|       |  //       Bidi property L or EN, followed by zero or more characters with
 6125|       |  //       Bidi property NSM.
 6126|       |
 6127|  2.15k|  size_t last_non_nsm_char = find_last_not_of_nsm(label);
 6128|  2.15k|  if (last_non_nsm_char == std::u32string_view::npos) {
  ------------------
  |  Branch (6128:7): [True: 0, False: 2.15k]
  ------------------
 6129|      0|    return false;
 6130|      0|  }
 6131|       |
 6132|       |  // A "Bidi domain name" is a domain name that contains at least one RTL label.
 6133|       |  // The following rule, consisting of six conditions, applies to labels in Bidi
 6134|       |  // domain names.
 6135|  2.15k|  if (is_rtl_label(label)) {
  ------------------
  |  Branch (6135:7): [True: 612, False: 1.54k]
  ------------------
 6136|       |    // The first character must be a character with Bidi property L, R,
 6137|       |    // or AL. If it has the R or AL property, it is an RTL label; if it
 6138|       |    // has the L property, it is an LTR label.
 6139|       |
 6140|    612|    if (find_direction(label[0]) == direction::L) {
  ------------------
  |  Branch (6140:9): [True: 147, False: 465]
  ------------------
 6141|       |      // Eval as LTR
 6142|       |
 6143|       |      // In an LTR label, only characters with the Bidi properties L, EN,
 6144|       |      // ES, CS, ET, ON, BN, or NSM are allowed.
 6145|  1.10k|      for (size_t i = 0; i <= last_non_nsm_char; i++) {
  ------------------
  |  Branch (6145:26): [True: 1.10k, False: 0]
  ------------------
 6146|  1.10k|        const direction d = find_direction(label[i]);
 6147|  1.10k|        if (!(d == direction::L || d == direction::EN || d == direction::ES ||
  ------------------
  |  Branch (6147:15): [True: 424, False: 679]
  |  Branch (6147:36): [True: 70, False: 609]
  |  Branch (6147:58): [True: 79, False: 530]
  ------------------
 6148|    530|              d == direction::CS || d == direction::ET || d == direction::ON ||
  ------------------
  |  Branch (6148:15): [True: 71, False: 459]
  |  Branch (6148:37): [True: 66, False: 393]
  |  Branch (6148:59): [True: 69, False: 324]
  ------------------
 6149|    324|              d == direction::BN || d == direction::NSM)) {
  ------------------
  |  Branch (6149:15): [True: 102, False: 222]
  |  Branch (6149:37): [True: 75, False: 147]
  ------------------
 6150|    147|          return false;
 6151|    147|        }
 6152|  1.10k|      }
 6153|       |
 6154|      0|      const direction last_dir = find_direction(label[last_non_nsm_char]);
 6155|      0|      if (!(last_dir == direction::L || last_dir == direction::EN)) {
  ------------------
  |  Branch (6155:13): [True: 0, False: 0]
  |  Branch (6155:41): [True: 0, False: 0]
  ------------------
 6156|      0|        return false;
 6157|      0|      }
 6158|       |
 6159|      0|      return true;
 6160|       |
 6161|    465|    } else {
 6162|       |      // Eval as RTL
 6163|       |
 6164|       |      // The first character must be R or AL; a leading AN (or any other
 6165|       |      // direction) does not start a valid RTL label.
 6166|    465|      const direction first_dir = find_direction(label[0]);
 6167|    465|      if (first_dir != direction::R && first_dir != direction::AL) {
  ------------------
  |  Branch (6167:11): [True: 384, False: 81]
  |  Branch (6167:40): [True: 27, False: 357]
  ------------------
 6168|     27|        return false;
 6169|     27|      }
 6170|       |
 6171|    438|      bool has_an = false;
 6172|    438|      bool has_en = false;
 6173|  2.15k|      for (size_t i = 0; i <= last_non_nsm_char; i++) {
  ------------------
  |  Branch (6173:26): [True: 1.83k, False: 323]
  ------------------
 6174|  1.83k|        const direction d = find_direction(label[i]);
 6175|       |
 6176|       |        // In an RTL label, if an EN is present, no AN may be present, and vice
 6177|       |        // versa.
 6178|  1.83k|        if ((d == direction::EN && ((has_en = true) && has_an)) ||
  ------------------
  |  Branch (6178:14): [True: 119, False: 1.71k]
  |  Branch (6178:37): [True: 119, False: 0]
  |  Branch (6178:56): [True: 1, False: 118]
  ------------------
 6179|  1.83k|            (d == direction::AN && ((has_an = true) && has_en))) {
  ------------------
  |  Branch (6179:14): [True: 97, False: 1.73k]
  |  Branch (6179:37): [True: 97, False: 0]
  |  Branch (6179:56): [True: 1, False: 96]
  ------------------
 6180|      2|          return false;
 6181|      2|        }
 6182|       |
 6183|  1.82k|        if (!(d == direction::R || d == direction::AL || d == direction::AN ||
  ------------------
  |  Branch (6183:15): [True: 145, False: 1.68k]
  |  Branch (6183:36): [True: 901, False: 783]
  |  Branch (6183:58): [True: 96, False: 687]
  ------------------
 6184|    687|              d == direction::EN || d == direction::ES || d == direction::CS ||
  ------------------
  |  Branch (6184:15): [True: 118, False: 569]
  |  Branch (6184:37): [True: 67, False: 502]
  |  Branch (6184:59): [True: 69, False: 433]
  ------------------
 6185|    433|              d == direction::ET || d == direction::ON || d == direction::BN ||
  ------------------
  |  Branch (6185:15): [True: 105, False: 328]
  |  Branch (6185:37): [True: 74, False: 254]
  |  Branch (6185:59): [True: 83, False: 171]
  ------------------
 6186|    171|              d == direction::NSM)) {
  ------------------
  |  Branch (6186:15): [True: 107, False: 64]
  ------------------
 6187|     64|          return false;
 6188|     64|        }
 6189|       |
 6190|  1.76k|        if (i == last_non_nsm_char &&
  ------------------
  |  Branch (6190:13): [True: 372, False: 1.39k]
  ------------------
 6191|    372|            !(d == direction::R || d == direction::AL || d == direction::AN ||
  ------------------
  |  Branch (6191:15): [True: 53, False: 319]
  |  Branch (6191:36): [True: 201, False: 118]
  |  Branch (6191:58): [True: 27, False: 91]
  ------------------
 6192|     91|              d == direction::EN)) {
  ------------------
  |  Branch (6192:15): [True: 42, False: 49]
  ------------------
 6193|     49|          return false;
 6194|     49|        }
 6195|  1.76k|      }
 6196|       |
 6197|    323|      return true;
 6198|    438|    }
 6199|    612|  }
 6200|       |
 6201|  1.54k|  return true;
 6202|  2.15k|}
_ZN3ada4idna8to_asciiENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEERNS1_12basic_stringIcS4_NS1_9allocatorIcEEEE:
 6359|  3.32k|[[nodiscard]] bool to_ascii(std::string_view ut8_string, std::string& out) {
 6360|  3.32k|  out.clear();
 6361|  3.32k|  if (ut8_string.size() > max_domain_input_bytes) {
  ------------------
  |  Branch (6361:7): [True: 0, False: 3.32k]
  ------------------
 6362|      0|    return false;
 6363|      0|  }
 6364|  3.32k|  if (is_ascii(ut8_string)) {
  ------------------
  |  Branch (6364:7): [True: 677, False: 2.65k]
  ------------------
 6365|    677|    from_ascii_to_ascii(ut8_string, out);
 6366|    677|    return true;
 6367|    677|  }
 6368|       |
 6369|       |#ifdef ADA_USE_SIMDUTF
 6370|       |  size_t utf32_length =
 6371|       |      simdutf::utf32_length_from_utf8(ut8_string.data(), ut8_string.size());
 6372|       |  if (utf32_length == 0 && !ut8_string.empty()) {
 6373|       |    return false;
 6374|       |  }
 6375|       |  std::u32string working(utf32_length, U'\0');
 6376|       |  size_t actual_utf32_length = simdutf::convert_utf8_to_utf32(
 6377|       |      ut8_string.data(), ut8_string.size(), working.data());
 6378|       |#else
 6379|  2.65k|  size_t utf32_length =
 6380|  2.65k|      ada::idna::utf32_length_from_utf8(ut8_string.data(), ut8_string.size());
 6381|  2.65k|  if (utf32_length == 0 && !ut8_string.empty()) {
  ------------------
  |  Branch (6381:7): [True: 16, False: 2.63k]
  |  Branch (6381:28): [True: 16, False: 0]
  ------------------
 6382|     16|    return false;
 6383|     16|  }
 6384|  2.63k|  std::u32string working(utf32_length, U'\0');
 6385|  2.63k|  size_t actual_utf32_length = ada::idna::utf8_to_utf32(
 6386|  2.63k|      ut8_string.data(), ut8_string.size(), working.data());
 6387|  2.63k|#endif
 6388|  2.63k|  if (actual_utf32_length == 0 || actual_utf32_length != utf32_length) {
  ------------------
  |  Branch (6388:7): [True: 130, False: 2.50k]
  |  Branch (6388:35): [True: 0, False: 2.50k]
  ------------------
 6389|    130|    return false;
 6390|    130|  }
 6391|  2.50k|  working.resize(actual_utf32_length);
 6392|       |
 6393|       |  // Map into a second buffer with exact sizing (no growth reallocs).
 6394|  2.50k|  std::u32string mapped;
 6395|  2.50k|  if (!ada::idna::map(working, mapped)) {
  ------------------
  |  Branch (6395:7): [True: 45, False: 2.46k]
  ------------------
 6396|     45|    return false;
 6397|     45|  }
 6398|       |  // Drop UTF-32 input; reuse `working` as scratch for ACE validation below.
 6399|  2.46k|  working.clear();
 6400|       |
 6401|       |  // Skip NFC when already normalized (ASCII is a fast subset of this check).
 6402|  2.46k|  if (!is_ascii(mapped) && !is_already_nfc(mapped)) {
  ------------------
  |  Branch (6402:7): [True: 1.76k, False: 696]
  |  Branch (6402:28): [True: 529, False: 1.23k]
  ------------------
 6403|    529|    if (!normalize(mapped)) {
  ------------------
  |  Branch (6403:9): [True: 0, False: 529]
  ------------------
 6404|      0|      return false;
 6405|      0|    }
 6406|    529|  }
 6407|       |
 6408|       |  // Estimate ASCII output size (punycode may expand non-ASCII labels).
 6409|  2.46k|  out.reserve(mapped.size() + 8);
 6410|       |
 6411|       |  // Walk labels with a single pointer scan (no repeated string::find).
 6412|  2.46k|  const char32_t* p = mapped.data();
 6413|  2.46k|  const char32_t* const end = p + mapped.size();
 6414|  2.46k|  std::u32string post_map;
 6415|       |
 6416|  4.88k|  while (p < end) {
  ------------------
  |  Branch (6416:10): [True: 3.57k, False: 1.30k]
  ------------------
 6417|  3.57k|    const char32_t* label_begin = p;
 6418|  42.4k|    while (p < end && *p != U'.') {
  ------------------
  |  Branch (6418:12): [True: 40.0k, False: 2.41k]
  |  Branch (6418:23): [True: 38.8k, False: 1.16k]
  ------------------
 6419|  38.8k|      ++p;
 6420|  38.8k|    }
 6421|  3.57k|    const size_t label_size = static_cast<size_t>(p - label_begin);
 6422|  3.57k|    std::u32string_view label_view(label_begin, label_size);
 6423|  3.57k|    const bool is_last_label = (p == end);
 6424|  3.57k|    if (p < end) {
  ------------------
  |  Branch (6424:9): [True: 1.16k, False: 2.41k]
  ------------------
 6425|  1.16k|      ++p;  // skip dot
 6426|  1.16k|    }
 6427|       |
 6428|  3.57k|    if (label_size == 0) {
  ------------------
  |  Branch (6428:9): [True: 128, False: 3.45k]
  ------------------
 6429|       |      // empty label
 6430|  3.45k|    } else if (is_ace_prefix(label_view)) {
  ------------------
  |  Branch (6430:16): [True: 1.03k, False: 2.41k]
  ------------------
 6431|  14.3k|      for (char32_t c : label_view) {
  ------------------
  |  Branch (6431:23): [True: 14.3k, False: 1.02k]
  ------------------
 6432|  14.3k|        if (c >= 0x80) {
  ------------------
  |  Branch (6432:13): [True: 13, False: 14.3k]
  ------------------
 6433|     13|          out.clear();
 6434|     13|          return false;
 6435|     13|        }
 6436|  14.3k|      }
 6437|  1.02k|      append_ascii_label(out, label_view);
 6438|  1.02k|      std::string_view puny_segment_ascii(
 6439|  1.02k|          out.data() + (out.size() - label_size) + 4, label_size - 4);
 6440|  1.02k|      working.clear();
 6441|  1.02k|      if (!ada::idna::punycode_to_utf32(puny_segment_ascii, working)) {
  ------------------
  |  Branch (6441:11): [True: 115, False: 906]
  ------------------
 6442|    115|        out.clear();
 6443|    115|        return false;
 6444|    115|      }
 6445|    906|      if (is_ascii(working)) {
  ------------------
  |  Branch (6445:11): [True: 64, False: 842]
  ------------------
 6446|     64|        out.clear();
 6447|     64|        return false;
 6448|     64|      }
 6449|    842|      if (!ada::idna::map(working, post_map) || working != post_map) {
  ------------------
  |  Branch (6449:11): [True: 193, False: 649]
  |  Branch (6449:49): [True: 60, False: 589]
  ------------------
 6450|    253|        out.clear();
 6451|    253|        return false;
 6452|    253|      }
 6453|       |      // Mapping must be stable; NFC must not change the mapped form either.
 6454|    589|      if (!is_ascii(post_map) && !is_already_nfc(post_map)) {
  ------------------
  |  Branch (6454:11): [True: 589, False: 0]
  |  Branch (6454:34): [True: 299, False: 290]
  ------------------
 6455|    299|        if (!normalize(post_map) || post_map != working) {
  ------------------
  |  Branch (6455:13): [True: 0, False: 299]
  |  Branch (6455:37): [True: 80, False: 219]
  ------------------
 6456|     80|          out.clear();
 6457|     80|          return false;
 6458|     80|        }
 6459|    299|      }
 6460|    509|      if (post_map.empty() || !is_label_valid(post_map)) {
  ------------------
  |  Branch (6460:11): [True: 0, False: 509]
  |  Branch (6460:31): [True: 12, False: 497]
  ------------------
 6461|     12|        out.clear();
 6462|     12|        return false;
 6463|     12|      }
 6464|  2.41k|    } else if (is_ascii(label_view)) {
  ------------------
  |  Branch (6464:16): [True: 187, False: 2.22k]
  ------------------
 6465|    187|      append_ascii_label(out, label_view);
 6466|  2.22k|    } else {
 6467|  2.22k|      if (!is_label_valid(label_view)) {
  ------------------
  |  Branch (6467:11): [True: 618, False: 1.61k]
  ------------------
 6468|    618|        out.clear();
 6469|    618|        return false;
 6470|    618|      }
 6471|  1.61k|      out.append("xn--");
 6472|  1.61k|      if (!ada::idna::utf32_to_punycode(label_view, out)) {
  ------------------
  |  Branch (6472:11): [True: 0, False: 1.61k]
  ------------------
 6473|      0|        out.clear();
 6474|      0|        return false;
 6475|      0|      }
 6476|  1.61k|    }
 6477|  2.42k|    if (!is_last_label) {
  ------------------
  |  Branch (6477:9): [True: 1.14k, False: 1.28k]
  ------------------
 6478|  1.14k|      out.push_back('.');
 6479|  1.14k|    }
 6480|  2.42k|  }
 6481|  1.30k|  return true;
 6482|  2.46k|}
_ZN3ada4idna8to_asciiENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6484|  3.32k|std::string to_ascii(std::string_view ut8_string) {
 6485|  3.32k|  std::string out;
 6486|  3.32k|  if (!to_ascii(ut8_string, out)) {
  ------------------
  |  Branch (6486:7): [True: 1.34k, False: 1.98k]
  ------------------
 6487|  1.34k|    return {};
 6488|  1.34k|  }
 6489|  1.98k|  return out;
 6490|  3.32k|}
_ZN3ada7unicode14percent_decodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEm:
 7180|  3.32k|std::string percent_decode(const std::string_view input, size_t first_percent) {
 7181|       |  // next line is for safety only, we expect users to avoid calling
 7182|       |  // percent_decode when first_percent is outside the range.
 7183|  3.32k|  if (first_percent == std::string_view::npos) {
  ------------------
  |  Branch (7183:7): [True: 0, False: 3.32k]
  ------------------
 7184|      0|    return std::string(input);
 7185|      0|  }
 7186|       |
 7187|       |  // NOLINTNEXTLINE(bugprone-suspicious-stringview-data-usage)
 7188|  3.32k|  const char* const src = input.data();
 7189|  3.32k|  const char* const end = src + input.size();
 7190|       |
 7191|       |  // Decoding never grows the string, so a single pre-sized buffer written via
 7192|       |  // bulk memcpy of the plain runs (then shrunk to the final length) avoids the
 7193|       |  // byte-at-a-time appends of the naive version.
 7194|  3.32k|  std::string out(input.size(), '\0');
 7195|  3.32k|  char* d = out.data();
 7196|  3.32k|  char* const d0 = d;
 7197|       |
 7198|  3.32k|  std::memcpy(d, src, first_percent);
 7199|  3.32k|  d += first_percent;
 7200|       |
 7201|  3.32k|  const char* p = src + first_percent;
 7202|  4.32k|  while (p < end) {
  ------------------
  |  Branch (7202:10): [True: 998, False: 3.32k]
  ------------------
 7203|    998|    if (*p == '%') {
  ------------------
  |  Branch (7203:9): [True: 624, False: 374]
  ------------------
 7204|       |      // Decode runs of valid %XX tightly (common for nested/encoded URLs).
 7205|    824|      while (p + 2 < end && *p == '%') {
  ------------------
  |  Branch (7205:14): [True: 708, False: 116]
  |  Branch (7205:29): [True: 642, False: 66]
  ------------------
 7206|    642|        if (!is_ascii_hex_digit(p[1]) || !is_ascii_hex_digit(p[2])) {
  ------------------
  |  Branch (7206:13): [True: 249, False: 393]
  |  Branch (7206:42): [True: 193, False: 200]
  ------------------
 7207|    442|          break;
 7208|    442|        }
 7209|    200|        *d++ = static_cast<char>(convert_hex_to_binary(p[1]) * 16 +
 7210|    200|                                 convert_hex_to_binary(p[2]));
 7211|    200|        p += 3;
 7212|    200|      }
 7213|    624|      if (p < end && *p == '%') {
  ------------------
  |  Branch (7213:11): [True: 592, False: 32]
  |  Branch (7213:22): [True: 519, False: 73]
  ------------------
 7214|       |        // Not a valid escape (too few chars left or bad hex): copy '%'
 7215|       |        // literally and keep scanning after it.
 7216|    519|        *d++ = *p++;
 7217|    519|      }
 7218|    624|    } else {
 7219|    374|      const char* q = static_cast<const char*>(
 7220|    374|          std::memchr(p, '%', static_cast<size_t>(end - p)));
 7221|    374|      const char* run_end = q ? q : end;
  ------------------
  |  Branch (7221:29): [True: 251, False: 123]
  ------------------
 7222|    374|      const size_t n = static_cast<size_t>(run_end - p);
 7223|    374|      std::memcpy(d, p, n);
 7224|    374|      d += n;
 7225|    374|      p = run_end;
 7226|    374|    }
 7227|    998|  }
 7228|       |
 7229|  3.32k|  out.resize(static_cast<size_t>(d - d0));
 7230|  3.32k|  return out;
 7231|  3.32k|}
_ZN3ada7unicode8to_asciiERNSt3__18optionalINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEENS1_17basic_string_viewIcS5_EEm:
 7390|  3.32k|              size_t first_percent) {
 7391|  3.32k|  std::string percent_decoded_buffer;
 7392|  3.32k|  std::string_view input = plain;
 7393|  3.32k|  if (first_percent != std::string_view::npos) {
  ------------------
  |  Branch (7393:7): [True: 3.32k, False: 0]
  ------------------
 7394|  3.32k|    percent_decoded_buffer = unicode::percent_decode(plain, first_percent);
 7395|  3.32k|    input = percent_decoded_buffer;
 7396|  3.32k|  }
 7397|       |  // input is a non-empty UTF-8 string, must be percent decoded
 7398|  3.32k|  std::string idna_ascii = ada::idna::to_ascii(input);
 7399|  3.32k|  if (idna_ascii.empty() || contains_forbidden_domain_code_point(
  ------------------
  |  Branch (7399:7): [True: 1.92k, False: 1.40k]
  |  Branch (7399:29): [True: 315, False: 1.09k]
  ------------------
 7400|  2.23k|                                idna_ascii.data(), idna_ascii.size())) {
 7401|  2.23k|    return false;
 7402|  2.23k|  }
 7403|  1.09k|  out = std::move(idna_ascii);
 7404|  1.09k|  return true;
 7405|  3.32k|}
_ZN3ada7helpers18trim_c0_whitespaceERNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9243|  3.32k|void trim_c0_whitespace(std::string_view& input) noexcept {
 9244|  4.65k|  while (!input.empty() &&
  ------------------
  |  Branch (9244:10): [True: 1.79k, False: 2.85k]
  ------------------
 9245|  1.79k|         ada::unicode::is_c0_control_or_space(input.front())) {
  ------------------
  |  Branch (9245:10): [True: 1.32k, False: 478]
  ------------------
 9246|  1.32k|    input.remove_prefix(1);
 9247|  1.32k|  }
 9248|  3.94k|  while (!input.empty() && ada::unicode::is_c0_control_or_space(input.back())) {
  ------------------
  |  Branch (9248:10): [True: 1.09k, False: 2.85k]
  |  Branch (9248:28): [True: 618, False: 478]
  ------------------
 9249|    618|    input.remove_suffix(1);
 9250|    618|  }
 9251|  3.32k|}
unicode.cc:_ZZN3ada4idna22utf32_length_from_utf8EPKcmENK3$_0clEa:
  272|  33.1k|  return std::count_if(p, std::next(p, len), [](int8_t c) {
  273|       |    // -65 is 0b10111111, anything larger in two-complement's
  274|       |    // should start a new code point.
  275|  33.1k|    return c > -65;
  276|  33.1k|  });
_ZN3ada4idna7deflate22make_fixed_litlen_huffEv:
  483|      2|inline Huff make_fixed_litlen_huff() {
  484|      2|  Huff h;
  485|      2|  uint8_t lens[288];
  486|       |  // Fixed Huffman: 0-143:8, 144-255:9, 256-279:7, 280-287:8
  487|    290|  for (int i = 0; i <= 143; i++) lens[i] = 8;
  ------------------
  |  Branch (487:19): [True: 288, False: 2]
  ------------------
  488|    226|  for (int i = 144; i <= 255; i++) lens[i] = 9;
  ------------------
  |  Branch (488:21): [True: 224, False: 2]
  ------------------
  489|     50|  for (int i = 256; i <= 279; i++) lens[i] = 7;
  ------------------
  |  Branch (489:21): [True: 48, False: 2]
  ------------------
  490|     18|  for (int i = 280; i <= 287; i++) lens[i] = 8;
  ------------------
  |  Branch (490:21): [True: 16, False: 2]
  ------------------
  491|      2|  h.build(lens, 288);
  492|      2|  return h;
  493|      2|}
_ZN3ada4idna7deflate4Huff5buildEPKhi:
  432|     16|  bool build(const uint8_t* lens, int n) {
  433|     16|    std::memset(counts, 0, sizeof(counts));
  434|     16|    std::memset(first_code, 0, sizeof(first_code));
  435|     16|    std::memset(base_idx, 0, sizeof(base_idx));
  436|     16|    nsymbols = n;
  437|     16|    max_bits = 0;
  438|  1.98k|    for (int i = 0; i < n; i++) {
  ------------------
  |  Branch (438:21): [True: 1.96k, False: 16]
  ------------------
  439|  1.96k|      lengths[i] = lens[i];
  440|  1.96k|      if (lens[i]) {
  ------------------
  |  Branch (440:11): [True: 1.91k, False: 49]
  ------------------
  441|  1.91k|        counts[lens[i]]++;
  442|  1.91k|        if (lens[i] > max_bits) max_bits = lens[i];
  ------------------
  |  Branch (442:13): [True: 46, False: 1.87k]
  ------------------
  443|  1.91k|      }
  444|  1.96k|    }
  445|       |    // Canonical first code for each bit length (RFC 1951).
  446|     16|    int code = 0;
  447|    256|    for (int bits = 1; bits <= MAXBITS; bits++) {
  ------------------
  |  Branch (447:24): [True: 240, False: 16]
  ------------------
  448|    240|      code = (code + counts[bits - 1]) << 1;
  449|    240|      first_code[bits] = code;
  450|    240|    }
  451|     16|    int idx = 0;
  452|    158|    for (int bits = 1; bits <= max_bits; bits++) {
  ------------------
  |  Branch (452:24): [True: 142, False: 16]
  ------------------
  453|    142|      base_idx[bits] = idx;
  454|       |      // assign symbols in symbol order for codes of this length
  455|  21.6k|      for (int sym = 0; sym < n; sym++) {
  ------------------
  |  Branch (455:25): [True: 21.5k, False: 142]
  ------------------
  456|  21.5k|        if (lengths[sym] == bits) {
  ------------------
  |  Branch (456:13): [True: 1.91k, False: 19.6k]
  ------------------
  457|  1.91k|          symbols[idx++] = static_cast<int16_t>(sym);
  458|  1.91k|        }
  459|  21.5k|      }
  460|    142|    }
  461|     16|    return true;
  462|     16|  }
_ZN3ada4idna7deflate20make_fixed_dist_huffEv:
  495|      2|inline Huff make_fixed_dist_huff() {
  496|      2|  Huff h;
  497|      2|  uint8_t lens[32];
  498|     66|  for (int i = 0; i < 32; i++) lens[i] = 5;
  ------------------
  |  Branch (498:19): [True: 64, False: 2]
  ------------------
  499|      2|  h.build(lens, 32);
  500|      2|  return h;
  501|      2|}
_ZN3ada4idna7deflate9BitReader6ensureEi:
  392|   457k|  bool ensure(int n) {
  393|   520k|    while (bits < n) {
  ------------------
  |  Branch (393:12): [True: 62.3k, False: 457k]
  ------------------
  394|  62.3k|      if (p >= end) return false;
  ------------------
  |  Branch (394:11): [True: 0, False: 62.3k]
  ------------------
  395|  62.3k|      acc |= uint32_t(*p++) << bits;
  396|  62.3k|      bits += 8;
  397|  62.3k|    }
  398|   457k|    return true;
  399|   457k|  }
unicode.cc:_ZZN3ada4idna9ascii_mapEPcmENK3$_0clEh:
 5127|  2.03k|  auto broadcast = [](uint8_t v) -> uint64_t {
 5128|  2.03k|    return 0x101010101010101ull * v;
 5129|  2.03k|  };
_ZN3ada4idna13ensure_tablesEv:
 4878|  6.91k|[[nodiscard]] inline bool ensure_tables() noexcept {
 4879|  6.91k|  uint8_t state = tables_init_state.load(std::memory_order_acquire);
 4880|  6.91k|  if (state == kTablesReady) {
  ------------------
  |  Branch (4880:7): [True: 6.91k, False: 1]
  ------------------
 4881|  6.91k|    return true;
 4882|  6.91k|  }
 4883|      1|  if (state == kTablesFailed) {
  ------------------
  |  Branch (4883:7): [True: 0, False: 1]
  ------------------
 4884|      0|    return false;
 4885|      0|  }
 4886|       |
 4887|      1|  uint8_t expected = kTablesUninit;
 4888|      1|  if (tables_init_state.compare_exchange_strong(expected, kTablesInProgress,
  ------------------
  |  Branch (4888:7): [True: 1, False: 0]
  ------------------
 4889|      1|                                                std::memory_order_acq_rel,
 4890|      1|                                                std::memory_order_acquire)) {
 4891|      1|    uint8_t* buffer = new (std::nothrow) uint8_t[table_blob::uncompressed_size];
 4892|      1|    if (buffer == nullptr) {
  ------------------
  |  Branch (4892:9): [True: 0, False: 1]
  ------------------
 4893|      0|      tables_init_state.store(kTablesFailed, std::memory_order_release);
 4894|      0|      return false;
 4895|      0|    }
 4896|       |
 4897|      1|    const size_t n = deflate::inflate_raw(table_blob::compressed,
 4898|      1|                                          table_blob::compressed_size, buffer,
 4899|      1|                                          table_blob::uncompressed_size);
 4900|      1|    if (n != table_blob::uncompressed_size ||
  ------------------
  |  Branch (4900:9): [True: 0, False: 1]
  ------------------
 4901|      1|        crc32_ieee(buffer, n) != table_blob::uncompressed_crc32) {
  ------------------
  |  Branch (4901:9): [True: 0, False: 1]
  ------------------
 4902|      0|      delete[] buffer;
 4903|      0|      tables_init_state.store(kTablesFailed, std::memory_order_release);
 4904|      0|      return false;
 4905|      0|    }
 4906|       |
 4907|       |    // LE payload verified; convert multi-byte fields for big-endian hosts.
 4908|      1|    detail::convert_table_blob_to_host_endian(buffer);
 4909|       |
 4910|      1|    auto at = [&](size_t off) noexcept -> const uint8_t* {
 4911|      1|      return buffer + off;
 4912|      1|    };
 4913|       |
 4914|       |    // Publish all non-atomic pointers before READY. Waiters synchronize via
 4915|       |    // acquire on tables_init_state and then observe these writes.
 4916|      1|    idna_stage1 =
 4917|      1|        reinterpret_cast<const uint16_t*>(at(table_blob::off_idna_stage1));
 4918|      1|    idna_stage2 =
 4919|      1|        reinterpret_cast<const uint16_t*>(at(table_blob::off_idna_stage2));
 4920|      1|    idna_bool_blocks =
 4921|      1|        reinterpret_cast<const uint64_t*>(at(table_blob::off_idna_bool_blocks));
 4922|      1|    idna_utf8_mappings = at(table_blob::off_idna_utf8_mappings);
 4923|       |
 4924|      1|    decomposition_index = at(table_blob::off_decomposition_index);
 4925|      1|    decomposition_block_flat = reinterpret_cast<const uint16_t*>(
 4926|      1|        at(table_blob::off_decomposition_block));
 4927|      1|    decomposition_data = reinterpret_cast<const char32_t*>(
 4928|      1|        at(table_blob::off_decomposition_data));
 4929|      1|    ccc_index = at(table_blob::off_ccc_index);
 4930|      1|    ccc_block_flat = at(table_blob::off_ccc_block);
 4931|      1|    composition_index = at(table_blob::off_composition_index);
 4932|      1|    composition_block_flat = reinterpret_cast<const uint16_t*>(
 4933|      1|        at(table_blob::off_composition_block));
 4934|      1|    composition_data =
 4935|      1|        reinterpret_cast<const char32_t*>(at(table_blob::off_composition_data));
 4936|       |
 4937|      1|    id_continue =
 4938|      1|        reinterpret_cast<range_pair_ptr>(at(table_blob::off_id_continue_flat));
 4939|      1|    id_start =
 4940|      1|        reinterpret_cast<range_pair_ptr>(at(table_blob::off_id_start_flat));
 4941|       |
 4942|      1|    dir_start =
 4943|      1|        reinterpret_cast<const uint32_t*>(at(table_blob::off_dir_start));
 4944|      1|    dir_final =
 4945|      1|        reinterpret_cast<const uint32_t*>(at(table_blob::off_dir_final));
 4946|      1|    dir_value = at(table_blob::off_dir_value);
 4947|      1|    combining_ranges =
 4948|      1|        reinterpret_cast<range_pair_ptr>(at(table_blob::off_combining_flat));
 4949|       |
 4950|      1|    tables_buffer = buffer;
 4951|      1|    tables_init_state.store(kTablesReady, std::memory_order_release);
 4952|      1|    return true;
 4953|      1|  }
 4954|       |
 4955|       |  // Another thread owns init (or finished between our loads).
 4956|      0|  for (uint64_t spins = 0; spins < kTablesSpinLimit; ++spins) {
  ------------------
  |  Branch (4956:28): [True: 0, False: 0]
  ------------------
 4957|      0|    state = tables_init_state.load(std::memory_order_acquire);
 4958|      0|    if (state == kTablesReady) {
  ------------------
  |  Branch (4958:9): [True: 0, False: 0]
  ------------------
 4959|      0|      return true;
 4960|      0|    }
 4961|      0|    if (state == kTablesFailed) {
  ------------------
  |  Branch (4961:9): [True: 0, False: 0]
  ------------------
 4962|      0|      return false;
 4963|      0|    }
 4964|      0|#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || \
 4965|      0|    defined(_M_IX86)
 4966|      0|#if defined(__GNUC__) || defined(__clang__)
 4967|      0|    __builtin_ia32_pause();
 4968|      0|#endif
 4969|       |#elif defined(__aarch64__) || defined(_M_ARM64)
 4970|       |#if defined(__GNUC__) || defined(__clang__)
 4971|       |    asm volatile("yield" ::: "memory");
 4972|       |#endif
 4973|       |#endif
 4974|      0|  }
 4975|       |  // Timed out waiting for a peer - treat as failure rather than hang.
 4976|      0|  return false;
 4977|      0|}
_ZN3ada4idna7deflate11inflate_rawEPKhmPhm:
  528|      1|                          size_t dst_cap) {
  529|      1|  BitReader br(src, src_len);
  530|      1|  size_t out = 0;
  531|      4|  for (;;) {
  532|      4|    uint32_t bfinal = br.get(1);
  533|      4|    uint32_t btype = br.get(2);
  534|      4|    if (bfinal == UINT32_MAX || btype == UINT32_MAX) return 0;
  ------------------
  |  Branch (534:9): [True: 0, False: 4]
  |  Branch (534:33): [True: 0, False: 4]
  ------------------
  535|      4|    if (btype == 0) {
  ------------------
  |  Branch (535:9): [True: 0, False: 4]
  ------------------
  536|       |      // stored
  537|      0|      br.align_byte();
  538|      0|      if (!br.ensure(16)) return 0;
  ------------------
  |  Branch (538:11): [True: 0, False: 0]
  ------------------
  539|       |      // read 16+16 from bit buffer awkwardly - use byte path
  540|       |      // Align: bits is multiple of 8
  541|       |      // Get len from remaining bits then bytes
  542|      0|      uint32_t len = br.get(16);
  543|      0|      uint32_t nlen = br.get(16);
  544|      0|      if (len == UINT32_MAX || nlen == UINT32_MAX) return 0;
  ------------------
  |  Branch (544:11): [True: 0, False: 0]
  |  Branch (544:32): [True: 0, False: 0]
  ------------------
  545|      0|      if ((len ^ 0xFFFF) != nlen) return 0;
  ------------------
  |  Branch (545:11): [True: 0, False: 0]
  ------------------
  546|       |      // After get, may have bits in acc from previous - for stored, should be
  547|       |      // byte aligned Copy len bytes from p
  548|      0|      if (br.bits != 0) {
  ------------------
  |  Branch (548:11): [True: 0, False: 0]
  ------------------
  549|       |        // leftover bits should be 0 if aligned
  550|      0|      }
  551|      0|      if (size_t(br.end - br.p) < len) return 0;
  ------------------
  |  Branch (551:11): [True: 0, False: 0]
  ------------------
  552|      0|      if (out + len > dst_cap) return 0;
  ------------------
  |  Branch (552:11): [True: 0, False: 0]
  ------------------
  553|      0|      std::memcpy(dst + out, br.p, len);
  554|      0|      br.p += len;
  555|      0|      out += len;
  556|      4|    } else if (btype == 1 || btype == 2) {
  ------------------
  |  Branch (556:16): [True: 0, False: 4]
  |  Branch (556:30): [True: 4, False: 0]
  ------------------
  557|      4|      Huff lit, dist;
  558|      4|      if (btype == 1) {
  ------------------
  |  Branch (558:11): [True: 0, False: 4]
  ------------------
  559|       |        // use fixed via functions
  560|      4|      } else {
  561|       |        // dynamic
  562|      4|        uint32_t hlit = br.get(5);
  563|      4|        if (hlit == UINT32_MAX) return 0;
  ------------------
  |  Branch (563:13): [True: 0, False: 4]
  ------------------
  564|      4|        hlit += 257;
  565|      4|        uint32_t hdist = br.get(5);
  566|      4|        if (hdist == UINT32_MAX) return 0;
  ------------------
  |  Branch (566:13): [True: 0, False: 4]
  ------------------
  567|      4|        hdist += 1;
  568|      4|        uint32_t hclen = br.get(4);
  569|      4|        if (hclen == UINT32_MAX) return 0;
  ------------------
  |  Branch (569:13): [True: 0, False: 4]
  ------------------
  570|      4|        hclen += 4;
  571|      4|        static const int order[19] = {16, 17, 18, 0, 8,  7, 9,  6, 10, 5,
  572|      4|                                      11, 4,  12, 3, 13, 2, 14, 1, 15};
  573|      4|        uint8_t clen[19]{};
  574|     69|        for (uint32_t i = 0; i < hclen; i++) {
  ------------------
  |  Branch (574:30): [True: 65, False: 4]
  ------------------
  575|     65|          uint32_t v = br.get(3);
  576|     65|          if (v == UINT32_MAX) return 0;
  ------------------
  |  Branch (576:15): [True: 0, False: 65]
  ------------------
  577|     65|          clen[order[i]] = uint8_t(v);
  578|     65|        }
  579|      4|        Huff cl;
  580|      4|        if (!cl.build(clen, 19)) return 0;
  ------------------
  |  Branch (580:13): [True: 0, False: 4]
  ------------------
  581|      4|        uint8_t lens[288 + 32]{};
  582|      4|        uint32_t n = hlit + hdist;
  583|  1.09k|        for (uint32_t i = 0; i < n;) {
  ------------------
  |  Branch (583:30): [True: 1.08k, False: 4]
  ------------------
  584|  1.08k|          int sym = cl.decode(br);
  585|  1.08k|          if (sym < 0) return 0;
  ------------------
  |  Branch (585:15): [True: 0, False: 1.08k]
  ------------------
  586|  1.08k|          if (sym < 16) {
  ------------------
  |  Branch (586:15): [True: 1.03k, False: 49]
  ------------------
  587|  1.03k|            lens[i++] = uint8_t(sym);
  588|  1.03k|          } else if (sym == 16) {
  ------------------
  |  Branch (588:22): [True: 49, False: 0]
  ------------------
  589|     49|            uint32_t rep = br.get(2);
  590|     49|            if (rep == UINT32_MAX) return 0;
  ------------------
  |  Branch (590:17): [True: 0, False: 49]
  ------------------
  591|     49|            rep += 3;
  592|     49|            if (i == 0) return 0;
  ------------------
  |  Branch (592:17): [True: 0, False: 49]
  ------------------
  593|     49|            uint8_t v = lens[i - 1];
  594|    263|            while (rep--) lens[i++] = v;
  ------------------
  |  Branch (594:20): [True: 214, False: 49]
  ------------------
  595|     49|          } else if (sym == 17) {
  ------------------
  |  Branch (595:22): [True: 0, False: 0]
  ------------------
  596|      0|            uint32_t rep = br.get(3);
  597|      0|            if (rep == UINT32_MAX) return 0;
  ------------------
  |  Branch (597:17): [True: 0, False: 0]
  ------------------
  598|      0|            rep += 3;
  599|      0|            while (rep--) lens[i++] = 0;
  ------------------
  |  Branch (599:20): [True: 0, False: 0]
  ------------------
  600|      0|          } else if (sym == 18) {
  ------------------
  |  Branch (600:22): [True: 0, False: 0]
  ------------------
  601|      0|            uint32_t rep = br.get(7);
  602|      0|            if (rep == UINT32_MAX) return 0;
  ------------------
  |  Branch (602:17): [True: 0, False: 0]
  ------------------
  603|      0|            rep += 11;
  604|      0|            while (rep--) lens[i++] = 0;
  ------------------
  |  Branch (604:20): [True: 0, False: 0]
  ------------------
  605|      0|          } else
  606|      0|            return 0;
  607|  1.08k|        }
  608|      4|        if (!lit.build(lens, int(hlit))) return 0;
  ------------------
  |  Branch (608:13): [True: 0, False: 4]
  ------------------
  609|      4|        if (!dist.build(lens + hlit, int(hdist))) return 0;
  ------------------
  |  Branch (609:13): [True: 0, False: 4]
  ------------------
  610|      4|      }
  611|  52.2k|      for (;;) {
  612|  52.2k|        int sym;
  613|  52.2k|        if (btype == 1)
  ------------------
  |  Branch (613:13): [True: 0, False: 52.2k]
  ------------------
  614|      0|          sym = fixed_litlen(br);
  615|  52.2k|        else
  616|  52.2k|          sym = lit.decode(br);
  617|  52.2k|        if (sym < 0) return 0;
  ------------------
  |  Branch (617:13): [True: 0, False: 52.2k]
  ------------------
  618|  52.2k|        if (sym < 256) {
  ------------------
  |  Branch (618:13): [True: 37.2k, False: 14.9k]
  ------------------
  619|  37.2k|          if (out >= dst_cap) return 0;
  ------------------
  |  Branch (619:15): [True: 0, False: 37.2k]
  ------------------
  620|  37.2k|          dst[out++] = uint8_t(sym);
  621|  37.2k|        } else if (sym == 256) {
  ------------------
  |  Branch (621:20): [True: 4, False: 14.9k]
  ------------------
  622|      4|          break;
  623|  14.9k|        } else {
  624|  14.9k|          int len_code = sym - 257;
  625|  14.9k|          if (len_code < 0 || len_code > 28) return 0;
  ------------------
  |  Branch (625:15): [True: 0, False: 14.9k]
  |  Branch (625:31): [True: 0, False: 14.9k]
  ------------------
  626|  14.9k|          uint32_t extra = br.get(len_extra[len_code]);
  627|  14.9k|          if (len_extra[len_code] && extra == UINT32_MAX) return 0;
  ------------------
  |  Branch (627:15): [True: 2.03k, False: 12.9k]
  |  Branch (627:38): [True: 0, False: 2.03k]
  ------------------
  628|  14.9k|          uint32_t length =
  629|  14.9k|              len_base[len_code] + (len_extra[len_code] ? extra : 0);
  ------------------
  |  Branch (629:37): [True: 2.03k, False: 12.9k]
  ------------------
  630|  14.9k|          int dsym;
  631|  14.9k|          if (btype == 1)
  ------------------
  |  Branch (631:15): [True: 0, False: 14.9k]
  ------------------
  632|      0|            dsym = fixed_dist(br);
  633|  14.9k|          else
  634|  14.9k|            dsym = dist.decode(br);
  635|  14.9k|          if (dsym < 0 || dsym > 29) return 0;
  ------------------
  |  Branch (635:15): [True: 0, False: 14.9k]
  |  Branch (635:27): [True: 0, False: 14.9k]
  ------------------
  636|  14.9k|          uint32_t dextra = br.get(dist_extra[dsym]);
  637|  14.9k|          if (dist_extra[dsym] && dextra == UINT32_MAX) return 0;
  ------------------
  |  Branch (637:15): [True: 9.97k, False: 5.01k]
  |  Branch (637:35): [True: 0, False: 9.97k]
  ------------------
  638|  14.9k|          uint32_t distance = dist_base[dsym] + (dist_extra[dsym] ? dextra : 0);
  ------------------
  |  Branch (638:50): [True: 9.97k, False: 5.01k]
  ------------------
  639|  14.9k|          if (distance > out || out + length > dst_cap) return 0;
  ------------------
  |  Branch (639:15): [True: 0, False: 14.9k]
  |  Branch (639:33): [True: 0, False: 14.9k]
  ------------------
  640|   202k|          for (uint32_t k = 0; k < length; k++) {
  ------------------
  |  Branch (640:32): [True: 187k, False: 14.9k]
  ------------------
  641|   187k|            dst[out] = dst[out - distance];
  642|   187k|            out++;
  643|   187k|          }
  644|  14.9k|        }
  645|  52.2k|      }
  646|      4|    } else {
  647|      0|      return 0;  // reserved
  648|      0|    }
  649|      4|    if (bfinal) break;
  ------------------
  |  Branch (649:9): [True: 1, False: 3]
  ------------------
  650|      4|  }
  651|      1|  return out;
  652|      1|}
_ZN3ada4idna7deflate9BitReaderC2EPKhm:
  390|      1|      : p(data), end(data + len) {}
_ZNK3ada4idna7deflate4Huff6decodeERNS1_9BitReaderE:
  464|  68.3k|  int decode(BitReader& br) const {
  465|  68.3k|    if (max_bits == 0) return -1;
  ------------------
  |  Branch (465:9): [True: 0, False: 68.3k]
  ------------------
  466|  68.3k|    int code = 0;
  467|   427k|    for (int len = 1; len <= max_bits; len++) {
  ------------------
  |  Branch (467:23): [True: 427k, False: 0]
  ------------------
  468|   427k|      uint32_t b = br.get(1);
  469|   427k|      if (b == UINT32_MAX) return -1;
  ------------------
  |  Branch (469:11): [True: 0, False: 427k]
  ------------------
  470|   427k|      code = (code << 1) | int(b);
  471|   427k|      int first = first_code[len];
  472|   427k|      int cnt = counts[len];
  473|   427k|      if (cnt && code - first < cnt) {
  ------------------
  |  Branch (473:11): [True: 263k, False: 164k]
  |  Branch (473:18): [True: 68.3k, False: 195k]
  ------------------
  474|  68.3k|        return symbols[base_idx[len] + (code - first)];
  475|  68.3k|      }
  476|   427k|    }
  477|      0|    return -1;
  478|  68.3k|  }
_ZN3ada4idna10crc32_ieeeEPKhm:
 4861|      1|                                         size_t len) noexcept {
 4862|      1|  uint32_t c = 0xFFFFFFFFu;
 4863|   224k|  for (size_t i = 0; i < len; ++i) {
  ------------------
  |  Branch (4863:22): [True: 224k, False: 1]
  ------------------
 4864|   224k|    c ^= data[i];
 4865|  2.02M|    for (int k = 0; k < 8; ++k) {
  ------------------
  |  Branch (4865:21): [True: 1.79M, False: 224k]
  ------------------
 4866|  1.79M|      const uint32_t mask = 0u - (c & 1u);
 4867|  1.79M|      c = (c >> 1) ^ (0xEDB88320u & mask);
 4868|  1.79M|    }
 4869|   224k|  }
 4870|      1|  return ~c;
 4871|      1|}
_ZN3ada4idna6detail33convert_table_blob_to_host_endianEPh:
 4684|      1|inline void convert_table_blob_to_host_endian(uint8_t* buffer) noexcept {
 4685|      1|  if constexpr (std::endian::native == std::endian::little) {
 4686|      1|    (void)buffer;
 4687|      1|    return;
 4688|      1|  }
 4689|      0|  auto u16 = [&](size_t off, size_t count) {
 4690|      1|    bswap_inplace(reinterpret_cast<uint16_t*>(buffer + off), count);
 4691|      1|  };
 4692|      1|  auto u32 = [&](size_t off, size_t count) {
 4693|      1|    bswap_inplace(reinterpret_cast<uint32_t*>(buffer + off), count);
 4694|      1|  };
 4695|      1|  auto u64 = [&](size_t off, size_t count) {
 4696|      1|    bswap_inplace(reinterpret_cast<uint64_t*>(buffer + off), count);
 4697|      1|  };
 4698|       |
 4699|      1|  u16(table_blob::off_idna_stage1, table_blob::count_idna_stage1);
 4700|      1|  u16(table_blob::off_idna_stage2, table_blob::count_idna_stage2);
 4701|      1|  u64(table_blob::off_idna_bool_blocks, table_blob::count_idna_bool_blocks);
 4702|      1|  u16(table_blob::off_decomposition_block,
 4703|      1|      table_blob::count_decomposition_block);
 4704|      1|  u32(table_blob::off_decomposition_data, table_blob::count_decomposition_data);
 4705|      1|  u16(table_blob::off_composition_block, table_blob::count_composition_block);
 4706|      1|  u32(table_blob::off_composition_data, table_blob::count_composition_data);
 4707|      1|  u32(table_blob::off_id_continue_flat, table_blob::count_id_continue_flat);
 4708|      1|  u32(table_blob::off_id_start_flat, table_blob::count_id_start_flat);
 4709|      1|  u32(table_blob::off_dir_start, table_blob::count_dir_start);
 4710|      1|  u32(table_blob::off_dir_final, table_blob::count_dir_final);
 4711|      1|  u32(table_blob::off_combining_flat, table_blob::count_combining_flat);
 4712|      1|}
_ZZN3ada4idna13ensure_tablesEvENKUlmE_clEm:
 4910|     18|    auto at = [&](size_t off) noexcept -> const uint8_t* {
 4911|     18|      return buffer + off;
 4912|     18|    };
unicode.cc:_ZN3ada4idnaL11idna_lookupEj:
 5065|  50.8k|static uint16_t idna_lookup(uint32_t cp) noexcept {
 5066|  50.8k|  if (cp < IDNA_LOW_RANGE_END) {
  ------------------
  |  Branch (5066:7): [True: 50.3k, False: 526]
  ------------------
 5067|  50.3k|    uint16_t ref = idna_stage1[cp >> IDNA_BLOCK_BITS];
 5068|  50.3k|    if (ref & IDNA_BOOL_FLAG) {
  ------------------
  |  Branch (5068:9): [True: 23.2k, False: 27.0k]
  ------------------
 5069|  23.2k|      uint32_t bit_idx =
 5070|  23.2k|          static_cast<uint32_t>(ref & ~IDNA_BOOL_FLAG) * IDNA_BLOCK_SIZE +
 5071|  23.2k|          (cp & IDNA_BLOCK_MASK);
 5072|  23.2k|      bool is_valid = (idna_bool_blocks[bit_idx >> 6] >> (bit_idx & 63u)) & 1u;
 5073|  23.2k|      return is_valid ? IDNA_VALID : IDNA_DISALLOWED;
  ------------------
  |  Branch (5073:14): [True: 23.2k, False: 9]
  ------------------
 5074|  23.2k|    }
 5075|  27.0k|    return idna_stage2[ref + (cp & IDNA_BLOCK_MASK)];
 5076|  50.3k|  }
 5077|       |
 5078|    526|  if (cp >= IDNA_HIGH_IGNORED_START && cp < IDNA_HIGH_IGNORED_END) {
  ------------------
  |  Branch (5078:7): [True: 491, False: 35]
  |  Branch (5078:40): [True: 343, False: 148]
  ------------------
 5079|    343|    return IDNA_IGNORED;
 5080|    343|  }
 5081|       |
 5082|    183|  return IDNA_DISALLOWED;
 5083|    526|}
unicode.cc:_ZN3ada4idnaL21utf8_count_codepointsEPKh:
 5108|  6.60k|static size_t utf8_count_codepoints(const uint8_t* ptr) noexcept {
 5109|  6.60k|  size_t n = 0;
 5110|  38.7k|  while (*ptr != 0) {
  ------------------
  |  Branch (5110:10): [True: 32.1k, False: 6.60k]
  ------------------
 5111|  32.1k|    ++n;
 5112|  32.1k|    if (*ptr < 0x80u) {
  ------------------
  |  Branch (5112:9): [True: 10.2k, False: 21.8k]
  ------------------
 5113|  10.2k|      ++ptr;
 5114|  21.8k|    } else if (*ptr < 0xE0u) {
  ------------------
  |  Branch (5114:16): [True: 18.5k, False: 3.37k]
  ------------------
 5115|  18.5k|      ptr += 2;
 5116|  18.5k|    } else if (*ptr < 0xF0u) {
  ------------------
  |  Branch (5116:16): [True: 3.02k, False: 348]
  ------------------
 5117|  3.02k|      ptr += 3;
 5118|  3.02k|    } else {
 5119|    348|      ptr += 4;
 5120|    348|    }
 5121|  32.1k|  }
 5122|  6.60k|  return n;
 5123|  6.60k|}
unicode.cc:_ZN3ada4idnaL9utf8_nextERPKh:
 5086|  32.1k|static char32_t utf8_next(const uint8_t*& ptr) noexcept {
 5087|  32.1k|  uint8_t b0 = *ptr++;
 5088|  32.1k|  if (b0 < 0x80u) return static_cast<char32_t>(b0);
  ------------------
  |  Branch (5088:7): [True: 10.2k, False: 21.8k]
  ------------------
 5089|  21.8k|  if (b0 < 0xE0u) {
  ------------------
  |  Branch (5089:7): [True: 18.5k, False: 3.36k]
  ------------------
 5090|  18.5k|    uint32_t cp = (b0 & 0x1Fu) << 6;
 5091|  18.5k|    cp |= (*ptr++ & 0x3Fu);
 5092|  18.5k|    return static_cast<char32_t>(cp);
 5093|  18.5k|  }
 5094|  3.36k|  if (b0 < 0xF0u) {
  ------------------
  |  Branch (5094:7): [True: 3.02k, False: 348]
  ------------------
 5095|  3.02k|    uint32_t cp = (b0 & 0x0Fu) << 12;
 5096|  3.02k|    cp |= ((*ptr++ & 0x3Fu) << 6);
 5097|  3.02k|    cp |= (*ptr++ & 0x3Fu);
 5098|  3.02k|    return static_cast<char32_t>(cp);
 5099|  3.02k|  }
 5100|    348|  uint32_t cp = (b0 & 0x07u) << 18;
 5101|    348|  cp |= ((*ptr++ & 0x3Fu) << 12);
 5102|    348|  cp |= ((*ptr++ & 0x3Fu) << 6);
 5103|    348|  cp |= (*ptr++ & 0x3Fu);
 5104|    348|  return static_cast<char32_t>(cp);
 5105|  3.36k|}
_ZN3ada4idna23decomposition_block_rowEh:
 4982|  93.3k|inline const uint16_t* decomposition_block_row(uint8_t bi) noexcept {
 4983|  93.3k|  if (bi >= kDecompBlockRows) {
  ------------------
  |  Branch (4983:7): [True: 0, False: 93.3k]
  ------------------
 4984|      0|    bi = 0;
 4985|      0|  }
 4986|  93.3k|  return decomposition_block_flat + static_cast<size_t>(bi) * kDecompBlockCols;
 4987|  93.3k|}
_ZN3ada4idna13ccc_block_rowEh:
 4989|   132k|inline const uint8_t* ccc_block_row(uint8_t bi) noexcept {
 4990|   132k|  if (bi >= kCccBlockRows) {
  ------------------
  |  Branch (4990:7): [True: 0, False: 132k]
  ------------------
 4991|      0|    bi = 0;
 4992|      0|  }
 4993|   132k|  return ccc_block_flat + static_cast<size_t>(bi) * kCccBlockCols;
 4994|   132k|}
_ZN3ada4idna16tables_are_readyEv:
 4873|  3.18k|[[nodiscard]] inline bool tables_are_ready() noexcept {
 4874|  3.18k|  return tables_init_state.load(std::memory_order_acquire) == kTablesReady;
 4875|  3.18k|}
unicode.cc:_ZN3ada4idnaL23canonical_decomp_lengthEDi:
 5265|  81.0k|static size_t canonical_decomp_length(char32_t current_character) noexcept {
 5266|  81.0k|  if (current_character >= hangul_sbase &&
  ------------------
  |  Branch (5266:7): [True: 5.72k, False: 75.2k]
  ------------------
 5267|  5.72k|      current_character < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (5267:7): [True: 3.11k, False: 2.60k]
  ------------------
 5268|       |    // Hangul precomposed syllables are NFC.
 5269|  3.11k|    return 0;
 5270|  3.11k|  }
 5271|  77.8k|  if (current_character >= 0x110000) {
  ------------------
  |  Branch (5271:7): [True: 0, False: 77.8k]
  ------------------
 5272|      0|    return 0;
 5273|      0|  }
 5274|  77.8k|  const uint8_t di = decomposition_index[current_character >> 8];
 5275|  77.8k|  const uint16_t* const decomposition =
 5276|  77.8k|      decomposition_block_row(di) + (current_character % 256);
 5277|  77.8k|  size_t decomposition_length =
 5278|  77.8k|      (decomposition[1] >> 2) - (decomposition[0] >> 2);
 5279|  77.8k|  if ((decomposition_length > 0) && (decomposition[0] & 1)) {
  ------------------
  |  Branch (5279:7): [True: 2.99k, False: 74.9k]
  |  Branch (5279:37): [True: 0, False: 2.99k]
  ------------------
 5280|      0|    decomposition_length = 0;  // compatibility-only: ignored for NFC
 5281|      0|  }
 5282|  77.8k|  return decomposition_length;
 5283|  77.8k|}
unicode.cc:_ZN3ada4idnaL12trailing_cccEDi:
 5466|  39.2k|static uint8_t trailing_ccc(char32_t c) noexcept {
 5467|  39.2k|  const size_t length = canonical_decomp_length(c);
 5468|  39.2k|  if (length == 0) {
  ------------------
  |  Branch (5468:7): [True: 37.7k, False: 1.45k]
  ------------------
 5469|  37.7k|    return get_ccc(c);
 5470|  37.7k|  }
 5471|  1.45k|  const uint16_t* const decomposition =
 5472|  1.45k|      decomposition_block_row(decomposition_index[c >> 8]) + (c % 256);
 5473|  1.45k|  const size_t base = decomposition[0] >> 2;
 5474|  1.45k|  return get_ccc(decomposition_data[base + length - 1]);
 5475|  39.2k|}
unicode.cc:_ZN3ada4idnaL13would_composeENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5397|  2.41k|static bool would_compose(std::u32string_view input) noexcept {
 5398|  31.7k|  for (size_t input_count = 0; input_count < input.size();) {
  ------------------
  |  Branch (5398:32): [True: 30.2k, False: 1.52k]
  ------------------
 5399|  30.2k|    const char32_t current = input[input_count];
 5400|  30.2k|    if (current >= hangul_lbase && current < hangul_lbase + hangul_lcount) {
  ------------------
  |  Branch (5400:9): [True: 6.29k, False: 23.9k]
  |  Branch (5400:36): [True: 425, False: 5.87k]
  ------------------
 5401|    425|      if (input_count + 1 < input.size() &&
  ------------------
  |  Branch (5401:11): [True: 403, False: 22]
  ------------------
 5402|    403|          input[input_count + 1] >= hangul_vbase &&
  ------------------
  |  Branch (5402:11): [True: 198, False: 205]
  ------------------
 5403|    198|          input[input_count + 1] < hangul_vbase + hangul_vcount) {
  ------------------
  |  Branch (5403:11): [True: 88, False: 110]
  ------------------
 5404|     88|        return true;
 5405|     88|      }
 5406|    337|      ++input_count;
 5407|    337|      continue;
 5408|    425|    }
 5409|  29.7k|    if (current >= hangul_sbase && current < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (5409:9): [True: 1.91k, False: 27.8k]
  |  Branch (5409:36): [True: 1.20k, False: 704]
  ------------------
 5410|  1.20k|      if ((current - hangul_sbase) % hangul_tcount &&
  ------------------
  |  Branch (5410:11): [True: 835, False: 371]
  ------------------
 5411|    835|          input_count + 1 < input.size() &&
  ------------------
  |  Branch (5411:11): [True: 774, False: 61]
  ------------------
 5412|    774|          input[input_count + 1] > hangul_tbase &&
  ------------------
  |  Branch (5412:11): [True: 620, False: 154]
  ------------------
 5413|    620|          input[input_count + 1] < hangul_tbase + hangul_tcount) {
  ------------------
  |  Branch (5413:11): [True: 118, False: 502]
  ------------------
 5414|    118|        return true;
 5415|    118|      }
 5416|  1.08k|      ++input_count;
 5417|  1.08k|      continue;
 5418|  1.20k|    }
 5419|  28.5k|    if (current < 0x110000) {
  ------------------
  |  Branch (5419:9): [True: 28.5k, False: 0]
  ------------------
 5420|  28.5k|      const uint16_t* composition =
 5421|  28.5k|          composition_block_row(composition_index[current >> 8]) +
 5422|  28.5k|          (current % 256);
 5423|  28.5k|      int32_t previous_ccc = -1;
 5424|  28.5k|      size_t j = input_count;
 5425|  29.8k|      for (; j + 1 < input.size(); ++j) {
  ------------------
  |  Branch (5425:14): [True: 28.4k, False: 1.42k]
  ------------------
 5426|  28.4k|        uint8_t ccc = get_ccc(input[j + 1]);
 5427|  28.4k|        if (composition[1] != composition[0] && previous_ccc < ccc) {
  ------------------
  |  Branch (5427:13): [True: 6.58k, False: 21.8k]
  |  Branch (5427:49): [True: 6.40k, False: 182]
  ------------------
 5428|  6.40k|          int left = composition[0];
 5429|  6.40k|          int right = composition[1];
 5430|  6.40k|          if (left < 0 || right < left ||
  ------------------
  |  Branch (5430:15): [True: 0, False: 6.40k]
  |  Branch (5430:27): [True: 0, False: 6.40k]
  ------------------
 5431|  6.40k|              static_cast<size_t>(right) > composition_data_size) {
  ------------------
  |  Branch (5431:15): [True: 0, False: 6.40k]
  ------------------
 5432|      0|            break;
 5433|      0|          }
 5434|  14.4k|          while (left + 2 < right) {
  ------------------
  |  Branch (5434:18): [True: 8.04k, False: 6.40k]
  ------------------
 5435|  8.04k|            int middle = left + (((right - left) >> 1) & ~1);
 5436|  8.04k|            if (composition_data[static_cast<size_t>(middle)] <= input[j + 1]) {
  ------------------
  |  Branch (5436:17): [True: 1.95k, False: 6.09k]
  ------------------
 5437|  1.95k|              left = middle;
 5438|  1.95k|            }
 5439|  8.04k|            if (composition_data[static_cast<size_t>(middle)] >= input[j + 1]) {
  ------------------
  |  Branch (5439:17): [True: 6.65k, False: 1.38k]
  ------------------
 5440|  6.65k|              right = middle;
 5441|  6.65k|            }
 5442|  8.04k|          }
 5443|  6.40k|          if (static_cast<size_t>(left + 1) < composition_data_size &&
  ------------------
  |  Branch (5443:15): [True: 6.40k, False: 0]
  ------------------
 5444|  6.40k|              composition_data[static_cast<size_t>(left)] == input[j + 1]) {
  ------------------
  |  Branch (5444:15): [True: 682, False: 5.72k]
  ------------------
 5445|    682|            return true;
 5446|    682|          }
 5447|  6.40k|        }
 5448|  27.7k|        if (ccc == 0) {
  ------------------
  |  Branch (5448:13): [True: 26.4k, False: 1.27k]
  ------------------
 5449|  26.4k|          break;
 5450|  26.4k|        }
 5451|  1.27k|        previous_ccc = ccc;
 5452|  1.27k|      }
 5453|  27.8k|      input_count = j + 1;
 5454|  27.8k|      continue;
 5455|  28.5k|    }
 5456|      0|    ++input_count;
 5457|      0|  }
 5458|  1.52k|  return false;
 5459|  2.41k|}
_ZN3ada4idna21composition_block_rowEh:
 4996|  37.8k|inline const uint16_t* composition_block_row(uint8_t bi) noexcept {
 4997|  37.8k|  if (bi >= kCompBlockRows) {
  ------------------
  |  Branch (4997:7): [True: 0, False: 37.8k]
  ------------------
 4998|      0|    bi = 0;
 4999|      0|  }
 5000|  37.8k|  return composition_block_flat + static_cast<size_t>(bi) * kCompBlockCols;
 5001|  37.8k|}
unicode.cc:_ZN3ada4idnaL19char_to_digit_valueEc:
 5643|  8.89k|static constexpr int32_t char_to_digit_value(char value) {
 5644|  8.89k|  if (value >= 'a' && value <= 'z') return value - 'a';
  ------------------
  |  Branch (5644:7): [True: 6.88k, False: 2.00k]
  |  Branch (5644:23): [True: 6.88k, False: 4]
  ------------------
 5645|  2.01k|  if (value >= '0' && value <= '9') return value - '0' + 26;
  ------------------
  |  Branch (5645:7): [True: 2.00k, False: 9]
  |  Branch (5645:23): [True: 1.99k, False: 9]
  ------------------
 5646|     18|  return -1;
 5647|  2.01k|}
unicode.cc:_ZN3ada4idnaL5adaptEiib:
 5653|  15.0k|static constexpr int32_t adapt(int32_t d, int32_t n, bool firsttime) {
 5654|  15.0k|  if (firsttime) {
  ------------------
  |  Branch (5654:7): [True: 2.52k, False: 12.5k]
  ------------------
 5655|  2.52k|    d = d / damp;
 5656|  12.5k|  } else {
 5657|  12.5k|    d = d / 2;
 5658|  12.5k|  }
 5659|  15.0k|  d += d / n;
 5660|  15.0k|  int32_t k = 0;
 5661|  17.9k|  while (d > ((base - tmin) * tmax) / 2) {
  ------------------
  |  Branch (5661:10): [True: 2.85k, False: 15.0k]
  ------------------
 5662|  2.85k|    d /= base - tmin;
 5663|  2.85k|    k += base;
 5664|  2.85k|  }
 5665|  15.0k|  return k + (((base - tmin + 1) * d) / (d + skew));
 5666|  15.0k|}
unicode.cc:_ZN3ada4idnaL13digit_to_charEi:
 5649|  18.2k|static constexpr char digit_to_char(int32_t digit) {
 5650|  18.2k|  return digit < 26 ? char(digit + 97) : char(digit + 22);
  ------------------
  |  Branch (5650:10): [True: 13.4k, False: 4.81k]
  ------------------
 5651|  18.2k|}
unicode.cc:_ZZN3ada4idna14is_label_validENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEEENK3$_0clIA2_jEEDaRKT_:
 5988|  23.5k|      comb_span, label.front(), {}, [](const auto& range) { return range[1]; });
unicode.cc:_ZZN3ada4idna14is_label_validENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEEENK3$_1clEj:
 6073|    653|      auto is_l_or_d = [](uint32_t code) {
 6074|    653|        return std::ranges::binary_search(L, code) ||
  ------------------
  |  Branch (6074:16): [True: 10, False: 643]
  ------------------
 6075|    643|               std::ranges::binary_search(D, code);
  ------------------
  |  Branch (6075:16): [True: 217, False: 426]
  ------------------
 6076|    653|      };
unicode.cc:_ZZN3ada4idna14is_label_validENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEEENK3$_2clEj:
 6077|    844|      auto is_r_or_d = [](uint32_t code) {
 6078|    844|        return std::ranges::binary_search(R, code) ||
  ------------------
  |  Branch (6078:16): [True: 36, False: 808]
  ------------------
 6079|    808|               std::ranges::binary_search(D, code);
  ------------------
  |  Branch (6079:16): [True: 100, False: 708]
  ------------------
 6080|    844|      };
unicode.cc:_ZN3ada4idnaL20find_last_not_of_nsmENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5935|  2.15k|    const std::u32string_view label) noexcept {
 5936|  3.08k|  for (int i = static_cast<int>(label.size() - 1); i >= 0; i--)
  ------------------
  |  Branch (5936:52): [True: 3.08k, False: 0]
  ------------------
 5937|  3.08k|    if (find_direction(label[i]) != direction::NSM) return i;
  ------------------
  |  Branch (5937:9): [True: 2.15k, False: 929]
  ------------------
 5938|       |
 5939|      0|  return std::u32string_view::npos;
 5940|  2.15k|}
unicode.cc:_ZN3ada4idnaL12is_rtl_labelENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5944|  2.15k|inline static bool is_rtl_label(const std::u32string_view label) noexcept {
 5945|  2.15k|  const size_t mask =
 5946|  2.15k|      (1u << direction::R) | (1u << direction::AL) | (1u << direction::AN);
 5947|       |
 5948|  2.15k|  size_t directions = 0;
 5949|  18.9k|  for (size_t i = 0; i < label.size(); i++) {
  ------------------
  |  Branch (5949:22): [True: 16.7k, False: 2.15k]
  ------------------
 5950|  16.7k|    directions |= 1u << find_direction(label[i]);
 5951|  16.7k|  }
 5952|  2.15k|  return (directions & mask) != 0;
 5953|  2.15k|}
unicode.cc:_ZN3ada4idnaL14find_directionEj:
 5916|  23.8k|inline static direction find_direction(uint32_t code_point) noexcept {
 5917|       |  // Binary search on dir_final (sorted upper bounds).
 5918|  23.8k|  size_t lo = 0, hi = dir_table_count;
 5919|   277k|  while (lo < hi) {
  ------------------
  |  Branch (5919:10): [True: 253k, False: 23.8k]
  ------------------
 5920|   253k|    size_t mid = lo + (hi - lo) / 2;
 5921|   253k|    if (dir_final[mid] < code_point) {
  ------------------
  |  Branch (5921:9): [True: 98.7k, False: 154k]
  ------------------
 5922|  98.7k|      lo = mid + 1;
 5923|   154k|    } else {
 5924|   154k|      hi = mid;
 5925|   154k|    }
 5926|   253k|  }
 5927|  23.8k|  if (lo == dir_table_count) {
  ------------------
  |  Branch (5927:7): [True: 0, False: 23.8k]
  ------------------
 5928|      0|    return direction::NONE;
 5929|      0|  }
 5930|  23.8k|  return code_point >= dir_start[lo] ? static_cast<direction>(dir_value[lo])
  ------------------
  |  Branch (5930:10): [True: 23.6k, False: 281]
  ------------------
 5931|  23.8k|                                     : direction::NONE;
 5932|  23.8k|}
_ZN3ada4idna8is_asciiENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6301|  3.32k|bool constexpr is_ascii(std::string_view view) {
 6302|  12.3k|  for (uint8_t c : view) {
  ------------------
  |  Branch (6302:18): [True: 12.3k, False: 677]
  ------------------
 6303|  12.3k|    if (c >= 0x80) {
  ------------------
  |  Branch (6303:9): [True: 2.65k, False: 9.73k]
  ------------------
 6304|  2.65k|      return false;
 6305|  2.65k|    }
 6306|  12.3k|  }
 6307|    677|  return true;
 6308|  3.32k|}
unicode.cc:_ZN3ada4idnaL19from_ascii_to_asciiENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEERNS1_12basic_stringIcS4_NS1_9allocatorIcEEEE:
 6338|    677|static void from_ascii_to_ascii(std::string_view ut8_string, std::string& out) {
 6339|    677|  out.assign(ut8_string);
 6340|    677|  ascii_map(out.data(), out.size());
 6341|    677|}
_ZN3ada4idna8is_asciiENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 6292|  6.37k|bool constexpr is_ascii(std::u32string_view view) {
 6293|  24.1k|  for (uint32_t c : view) {
  ------------------
  |  Branch (6293:19): [True: 24.1k, False: 947]
  ------------------
 6294|  24.1k|    if (c >= 0x80) {
  ------------------
  |  Branch (6294:9): [True: 5.42k, False: 18.7k]
  ------------------
 6295|  5.42k|      return false;
 6296|  5.42k|    }
 6297|  24.1k|  }
 6298|    947|  return true;
 6299|  6.37k|}
unicode.cc:_ZN3ada4idnaL13is_ace_prefixENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 6354|  3.45k|static bool is_ace_prefix(std::u32string_view label) noexcept {
 6355|  3.45k|  return label.size() >= 4 && label[0] == U'x' && label[1] == U'n' &&
  ------------------
  |  Branch (6355:10): [True: 1.84k, False: 1.61k]
  |  Branch (6355:31): [True: 1.15k, False: 684]
  |  Branch (6355:51): [True: 1.09k, False: 62]
  ------------------
 6356|  1.09k|         label[2] == U'-' && label[3] == U'-';
  ------------------
  |  Branch (6356:10): [True: 1.05k, False: 40]
  |  Branch (6356:30): [True: 1.03k, False: 20]
  ------------------
 6357|  3.45k|}
unicode.cc:_ZN3ada4idnaL18append_ascii_labelERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS1_17basic_string_viewIDiNS3_IDiEEEE:
 6344|  1.20k|static void append_ascii_label(std::string& out, std::u32string_view label) {
 6345|  1.20k|  const size_t old = out.size();
 6346|  1.20k|  out.resize(old + label.size());
 6347|  1.20k|  char* dest = out.data() + old;
 6348|  14.7k|  for (char32_t c : label) {
  ------------------
  |  Branch (6348:19): [True: 14.7k, False: 1.20k]
  ------------------
 6349|  14.7k|    *dest++ = static_cast<char>(c);
 6350|  14.7k|  }
 6351|  1.20k|}
_ZN3ada7unicode18is_ascii_hex_digitEc:
 7086|  11.3k|ada_really_inline constexpr bool is_ascii_hex_digit(const char c) noexcept {
 7087|  11.3k|  return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') ||
  ------------------
  |  Branch (7087:11): [True: 5.38k, False: 5.94k]
  |  Branch (7087:23): [True: 1.10k, False: 4.27k]
  |  Branch (7087:37): [True: 3.82k, False: 6.39k]
  |  Branch (7087:49): [True: 433, False: 3.39k]
  ------------------
 7088|  9.79k|         (c >= 'a' && c <= 'f');
  ------------------
  |  Branch (7088:11): [True: 1.26k, False: 8.52k]
  |  Branch (7088:23): [True: 461, False: 803]
  ------------------
 7089|  11.3k|}
_ZN3ada7unicode21convert_hex_to_binaryEc:
 7176|  1.81k|unsigned constexpr convert_hex_to_binary(const char c) noexcept {
 7177|  1.81k|  return hex_to_binary_table[c - '0'];
 7178|  1.81k|}
_ZN3ada7unicode36contains_forbidden_domain_code_pointEPKcm:
 7013|  4.73k|    const char* input, size_t length) noexcept {
 7014|  4.73k|  size_t i = 0;
 7015|  4.73k|  uint8_t accumulator{};
 7016|  14.8k|  for (; i + 4 <= length; i += 4) {
  ------------------
  |  Branch (7016:10): [True: 10.1k, False: 4.73k]
  ------------------
 7017|  10.1k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i])];
 7018|  10.1k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 1])];
 7019|  10.1k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 2])];
 7020|  10.1k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 3])];
 7021|  10.1k|  }
 7022|  7.60k|  for (; i < length; i++) {
  ------------------
  |  Branch (7022:10): [True: 2.86k, False: 4.73k]
  ------------------
 7023|  2.86k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i])];
 7024|  2.86k|  }
 7025|  4.73k|  return accumulator;
 7026|  4.73k|}
_ZN3ada7unicode19has_tabs_or_newlineENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6862|  3.32k|    std::string_view user_input) noexcept {
 6863|       |  // first check for short strings in which case we do it naively.
 6864|  3.32k|  if (user_input.size() < 16) {  // slow path
  ------------------
  |  Branch (6864:7): [True: 3.13k, False: 195]
  ------------------
 6865|  3.13k|    return std::ranges::any_of(user_input, is_tabs_or_newline);
 6866|  3.13k|  }
 6867|       |  // fast path for long strings (expected to be common)
 6868|    195|  size_t i = 0;
 6869|    195|  const __m128i mask1 = _mm_set1_epi8('\r');
 6870|    195|  const __m128i mask2 = _mm_set1_epi8('\n');
 6871|    195|  const __m128i mask3 = _mm_set1_epi8('\t');
 6872|       |  // If we supported SSSE3, we could use the algorithm that we use for NEON.
 6873|    195|  __m128i running{0};
 6874|    722|  for (; i + 15 < user_input.size(); i += 16) {
  ------------------
  |  Branch (6874:10): [True: 527, False: 195]
  ------------------
 6875|    527|    __m128i word = _mm_loadu_si128((const __m128i*)(user_input.data() + i));
 6876|    527|    running = _mm_or_si128(
 6877|    527|        _mm_or_si128(running, _mm_or_si128(_mm_cmpeq_epi8(word, mask1),
 6878|    527|                                           _mm_cmpeq_epi8(word, mask2))),
 6879|    527|        _mm_cmpeq_epi8(word, mask3));
 6880|    527|  }
 6881|    195|  if (i < user_input.size()) {
  ------------------
  |  Branch (6881:7): [True: 108, False: 87]
  ------------------
 6882|    108|    __m128i word = _mm_loadu_si128(
 6883|    108|        (const __m128i*)(user_input.data() + user_input.length() - 16));
 6884|    108|    running = _mm_or_si128(
 6885|    108|        _mm_or_si128(running, _mm_or_si128(_mm_cmpeq_epi8(word, mask1),
 6886|    108|                                           _mm_cmpeq_epi8(word, mask2))),
 6887|    108|        _mm_cmpeq_epi8(word, mask3));
 6888|    108|  }
 6889|    195|  return _mm_movemask_epi8(running) != 0;
 6890|  3.32k|}
_ZN3ada7unicode18is_tabs_or_newlineEc:
 6753|    994|constexpr bool is_tabs_or_newline(char c) noexcept {
 6754|    994|  return c == '\r' || c == '\n' || c == '\t';
  ------------------
  |  Branch (6754:10): [True: 21, False: 973]
  |  Branch (6754:23): [True: 14, False: 959]
  |  Branch (6754:36): [True: 21, False: 938]
  ------------------
 6755|    994|}
_ZN3ada7helpers27remove_ascii_tab_or_newlineERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
 8558|  3.32k|ada_really_inline void remove_ascii_tab_or_newline(std::string& input) {
 8559|       |  // if this ever becomes a performance issue, we could use an approach similar
 8560|       |  // to has_tabs_or_newline
 8561|  3.32k|  std::erase_if(input, ada::unicode::is_ascii_tab_or_newline);
 8562|  3.32k|}
_ZN3ada7unicode22is_c0_control_or_spaceEc:
 7102|  13.1k|ada_really_inline constexpr bool is_c0_control_or_space(const char c) noexcept {
 7103|  13.1k|  return (unsigned char)c <= ' ';
 7104|  13.1k|}
_ZN3ada7unicode28is_forbidden_host_code_pointEc:
 6985|  10.3k|    const char c) noexcept {
 6986|  10.3k|  return is_forbidden_host_code_point_table[uint8_t(c)];
 6987|  10.3k|}
_ZN3ada7unicode14is_ascii_digitEc:
 7091|  10.3k|ada_really_inline constexpr bool is_ascii_digit(const char c) noexcept {
 7092|       |  // An ASCII digit is a code point in the range U+0030 (0) to U+0039 (9),
 7093|       |  // inclusive.
 7094|  10.3k|  return (c >= '0' && c <= '9');
  ------------------
  |  Branch (7094:11): [True: 4.73k, False: 5.56k]
  |  Branch (7094:23): [True: 823, False: 3.91k]
  ------------------
 7095|  10.3k|}
_ZN3ada7unicode13is_alnum_plusEc:
 7079|  10.3k|ada_really_inline constexpr bool is_alnum_plus(const char c) noexcept {
 7080|  10.3k|  return is_alnum_plus_table[uint8_t(c)];
 7081|       |  // A table is almost surely much faster than the
 7082|       |  // following under most compilers: return
 7083|       |  // return (std::isalnum(c) || c == '+' || c == '-' || c == '.');
 7084|  10.3k|}
_ZN3ada7unicode14to_lower_asciiEPcm:
 6761|  3.32k|constexpr bool to_lower_ascii(char* input, size_t length) noexcept {
 6762|  3.32k|  uint64_t broadcast_80 = broadcast(0x80);
 6763|  3.32k|  uint64_t broadcast_Ap = broadcast(128 - 'A');
 6764|  3.32k|  uint64_t broadcast_Zp = broadcast(128 - 'Z' - 1);
 6765|  3.32k|  uint64_t non_ascii = 0;
 6766|  3.32k|  size_t i = 0;
 6767|       |
 6768|  4.46k|  for (; i + 7 < length; i += 8) {
  ------------------
  |  Branch (6768:10): [True: 1.13k, False: 3.32k]
  ------------------
 6769|  1.13k|    uint64_t word{};
 6770|  1.13k|    memcpy(&word, input + i, sizeof(word));
 6771|  1.13k|    non_ascii |= (word & broadcast_80);
 6772|  1.13k|    word ^=
 6773|  1.13k|        (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
 6774|  1.13k|    memcpy(input + i, &word, sizeof(word));
 6775|  1.13k|  }
 6776|  3.32k|  if (i < length) {
  ------------------
  |  Branch (6776:7): [True: 428, False: 2.90k]
  ------------------
 6777|    428|    uint64_t word{};
 6778|    428|    memcpy(&word, input + i, length - i);
 6779|    428|    non_ascii |= (word & broadcast_80);
 6780|    428|    word ^=
 6781|    428|        (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
 6782|    428|    memcpy(input + i, &word, length - i);
 6783|    428|  }
 6784|  3.32k|  return non_ascii == 0;
 6785|  3.32k|}
_ZN3ada7unicode9broadcastEh:
 6757|  9.98k|constexpr uint64_t broadcast(uint8_t v) noexcept {
 6758|  9.98k|  return 0x101010101010101ull * v;
 6759|  9.98k|}
_ZN3ada7helpers10prune_hashERNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8498|  3.32k|    std::string_view& input) noexcept {
 8499|       |  // compiles down to 20--30 instructions including a class to memchr (C
 8500|       |  // function). this function should be quite fast.
 8501|  3.32k|  size_t location_of_first = input.find('#');
 8502|  3.32k|  if (location_of_first == std::string_view::npos) {
  ------------------
  |  Branch (8502:7): [True: 3.28k, False: 40]
  ------------------
 8503|  3.28k|    return std::nullopt;
 8504|  3.28k|  }
 8505|     40|  std::string_view hash = input;
 8506|     40|  hash.remove_prefix(location_of_first + 1);
 8507|     40|  input.remove_suffix(input.size() - location_of_first);
 8508|     40|  return hash;
 8509|  3.32k|}
_ZN3ada7helpers32find_authority_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9451|  3.32k|find_authority_delimiter_special(std::string_view view) noexcept {
 9452|       |  // performance note: we might be able to gain further performance
 9453|       |  // with SIMD intrinsics.
 9454|  11.8k|  for (auto pos = view.begin(); pos != view.end(); ++pos) {
  ------------------
  |  Branch (9454:33): [True: 8.67k, False: 3.22k]
  ------------------
 9455|  8.67k|    if (authority_delimiter_special[(uint8_t)*pos]) {
  ------------------
  |  Branch (9455:9): [True: 108, False: 8.56k]
  ------------------
 9456|    108|      return pos - view.begin();
 9457|    108|    }
 9458|  8.67k|  }
 9459|  3.22k|  return size_t(view.size());
 9460|  3.32k|}
_ZN3ada7helpers24find_authority_delimiterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9472|  3.32k|find_authority_delimiter(std::string_view view) noexcept {
 9473|       |  // performance note: we might be able to gain further performance
 9474|       |  // with SIMD instrinsics.
 9475|  12.1k|  for (auto pos = view.begin(); pos != view.end(); ++pos) {
  ------------------
  |  Branch (9475:33): [True: 8.90k, False: 3.23k]
  ------------------
 9476|  8.90k|    if (authority_delimiter[(uint8_t)*pos]) {
  ------------------
  |  Branch (9476:9): [True: 91, False: 8.80k]
  ------------------
 9477|     91|      return pos - view.begin();
 9478|     91|    }
 9479|  8.90k|  }
 9480|  3.23k|  return size_t(view.size());
 9481|  3.32k|}
_ZN3ada7helpers27get_host_delimiter_locationEbRNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9164|  6.65k|    const bool is_special, std::string_view& view) noexcept {
 9165|       |  /**
 9166|       |   * The spec at https://url.spec.whatwg.org/#hostname-state expects us to
 9167|       |   * compute a variable called insideBrackets but this variable is only used
 9168|       |   * once, to check whether a ':' character was found outside brackets. Exact
 9169|       |   * text: "Otherwise, if c is U+003A (:) and insideBrackets is false, then:".
 9170|       |   * It is conceptually simpler and arguably more efficient to just return a
 9171|       |   * Boolean indicating whether ':' was found outside brackets.
 9172|       |   */
 9173|  6.65k|  const size_t view_size = view.size();
 9174|  6.65k|  size_t location = 0;
 9175|  6.65k|  bool found_colon = false;
 9176|       |  /**
 9177|       |   * Performance analysis:
 9178|       |   *
 9179|       |   * We are basically seeking the end of the hostname which can be indicated
 9180|       |   * by the end of the view, or by one of the characters ':', '/', '?', '\\'
 9181|       |   * (where '\\' is only applicable for special URLs). However, these must
 9182|       |   * appear outside a bracket range. E.g., if you have [something?]fd: then the
 9183|       |   * '?' does not count.
 9184|       |   *
 9185|       |   * So we can skip ahead to the next delimiter, as long as we include '[' in
 9186|       |   * the set of delimiters, and that we handle it first.
 9187|       |   *
 9188|       |   * So the trick is to have a fast function that locates the next delimiter.
 9189|       |   * Unless we find '[', then it only needs to be called once! Ideally, such a
 9190|       |   * function would be provided by the C++ standard library, but it seems that
 9191|       |   * find_first_of is not very fast, so we are forced to roll our own.
 9192|       |   *
 9193|       |   * We do not break into two loops for speed, but for clarity.
 9194|       |   */
 9195|  6.65k|  if (is_special) {
  ------------------
  |  Branch (9195:7): [True: 3.32k, False: 3.32k]
  ------------------
 9196|       |    // We move to the next delimiter.
 9197|  3.32k|    location = find_next_host_delimiter_special(view, location);
 9198|       |    // Unless we find '[' then we are going only going to have to call
 9199|       |    // find_next_host_delimiter_special once.
 9200|  3.93k|    for (; location < view_size;
  ------------------
  |  Branch (9200:12): [True: 754, False: 3.18k]
  ------------------
 9201|  3.32k|         location = find_next_host_delimiter_special(view, location)) {
 9202|    754|      if (view[location] == '[') {
  ------------------
  |  Branch (9202:11): [True: 650, False: 104]
  ------------------
 9203|    650|        location = view.find(']', location);
 9204|    650|        if (location == std::string_view::npos) {
  ------------------
  |  Branch (9204:13): [True: 42, False: 608]
  ------------------
 9205|       |          // performance: view.find might get translated to a memchr, which
 9206|       |          // has no notion of std::string_view::npos, so the code does not
 9207|       |          // reflect the assembly.
 9208|     42|          location = view_size;
 9209|     42|          break;
 9210|     42|        }
 9211|    650|      } else {
 9212|    104|        found_colon = view[location] == ':';
 9213|    104|        break;
 9214|    104|      }
 9215|    754|    }
 9216|  3.32k|  } else {
 9217|       |    // We move to the next delimiter.
 9218|  3.32k|    location = find_next_host_delimiter(view, location);
 9219|       |    // Unless we find '[' then we are going only going to have to call
 9220|       |    // find_next_host_delimiter_special once.
 9221|  3.93k|    for (; location < view_size;
  ------------------
  |  Branch (9221:12): [True: 738, False: 3.19k]
  ------------------
 9222|  3.32k|         location = find_next_host_delimiter(view, location)) {
 9223|    738|      if (view[location] == '[') {
  ------------------
  |  Branch (9223:11): [True: 650, False: 88]
  ------------------
 9224|    650|        location = view.find(']', location);
 9225|    650|        if (location == std::string_view::npos) {
  ------------------
  |  Branch (9225:13): [True: 42, False: 608]
  ------------------
 9226|       |          // performance: view.find might get translated to a memchr, which
 9227|       |          // has no notion of std::string_view::npos, so the code does not
 9228|       |          // reflect the assembly.
 9229|     42|          location = view_size;
 9230|     42|          break;
 9231|     42|        }
 9232|    650|      } else {
 9233|     88|        found_colon = view[location] == ':';
 9234|     88|        break;
 9235|     88|      }
 9236|    738|    }
 9237|  3.32k|  }
 9238|       |  // performance: remove_suffix may translate into a single instruction.
 9239|  6.65k|  view.remove_suffix(view_size - location);
 9240|  6.65k|  return {location, found_colon};
 9241|  6.65k|}
_ZN3ada7helpers32find_next_host_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEm:
 8754|  3.93k|    std::string_view view, size_t location) noexcept {
 8755|       |  // first check for short strings in which case we do it naively.
 8756|  3.93k|  if (view.size() - location < 16) {  // slow path
  ------------------
  |  Branch (8756:7): [True: 3.30k, False: 631]
  ------------------
 8757|  4.45k|    for (size_t i = location; i < view.size(); i++) {
  ------------------
  |  Branch (8757:31): [True: 1.34k, False: 3.10k]
  ------------------
 8758|  1.34k|      if (view[i] == ':' || view[i] == '/' || view[i] == '\\' ||
  ------------------
  |  Branch (8758:11): [True: 12, False: 1.33k]
  |  Branch (8758:29): [True: 16, False: 1.32k]
  |  Branch (8758:47): [True: 8, False: 1.31k]
  ------------------
 8759|  1.31k|          view[i] == '?' || view[i] == '[') {
  ------------------
  |  Branch (8759:11): [True: 6, False: 1.30k]
  |  Branch (8759:29): [True: 159, False: 1.14k]
  ------------------
 8760|    201|        return i;
 8761|    201|      }
 8762|  1.34k|    }
 8763|  3.10k|    return size_t(view.size());
 8764|  3.30k|  }
 8765|       |  // fast path for long strings (expected to be common)
 8766|    631|  size_t i = location;
 8767|    631|  const __m128i mask1 = _mm_set1_epi8(':');
 8768|    631|  const __m128i mask2 = _mm_set1_epi8('/');
 8769|    631|  const __m128i mask3 = _mm_set1_epi8('\\');
 8770|    631|  const __m128i mask4 = _mm_set1_epi8('?');
 8771|    631|  const __m128i mask5 = _mm_set1_epi8('[');
 8772|       |
 8773|    930|  for (; i + 15 < view.size(); i += 16) {
  ------------------
  |  Branch (8773:10): [True: 824, False: 106]
  ------------------
 8774|    824|    __m128i word = _mm_loadu_si128((const __m128i*)(view.data() + i));
 8775|    824|    __m128i m1 = _mm_cmpeq_epi8(word, mask1);
 8776|    824|    __m128i m2 = _mm_cmpeq_epi8(word, mask2);
 8777|    824|    __m128i m3 = _mm_cmpeq_epi8(word, mask3);
 8778|    824|    __m128i m4 = _mm_cmpeq_epi8(word, mask4);
 8779|    824|    __m128i m5 = _mm_cmpeq_epi8(word, mask5);
 8780|    824|    __m128i m = _mm_or_si128(
 8781|    824|        _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m3, m4)), m5);
 8782|    824|    int mask = _mm_movemask_epi8(m);
 8783|    824|    if (mask != 0) {
  ------------------
  |  Branch (8783:9): [True: 525, False: 299]
  ------------------
 8784|    525|      return i + trailing_zeroes(mask);
 8785|    525|    }
 8786|    824|  }
 8787|    106|  if (i < view.size()) {
  ------------------
  |  Branch (8787:7): [True: 67, False: 39]
  ------------------
 8788|     67|    __m128i word =
 8789|     67|        _mm_loadu_si128((const __m128i*)(view.data() + view.length() - 16));
 8790|     67|    __m128i m1 = _mm_cmpeq_epi8(word, mask1);
 8791|     67|    __m128i m2 = _mm_cmpeq_epi8(word, mask2);
 8792|     67|    __m128i m3 = _mm_cmpeq_epi8(word, mask3);
 8793|     67|    __m128i m4 = _mm_cmpeq_epi8(word, mask4);
 8794|     67|    __m128i m5 = _mm_cmpeq_epi8(word, mask5);
 8795|     67|    __m128i m = _mm_or_si128(
 8796|     67|        _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m3, m4)), m5);
 8797|     67|    int mask = _mm_movemask_epi8(m);
 8798|     67|    if (mask != 0) {
  ------------------
  |  Branch (8798:9): [True: 28, False: 39]
  ------------------
 8799|     28|      return view.length() - 16 + trailing_zeroes(mask);
 8800|     28|    }
 8801|     67|  }
 8802|     78|  return size_t(view.length());
 8803|    106|}
_ZN3ada7helpers15trailing_zeroesEj:
 8579|  1.09k|ada_really_inline int trailing_zeroes(uint32_t input_num) noexcept {
 8580|       |#ifdef ADA_REGULAR_VISUAL_STUDIO
 8581|       |  unsigned long ret;
 8582|       |  // Search the mask data from least significant bit (LSB)
 8583|       |  // to the most significant bit (MSB) for a set bit (1).
 8584|       |  _BitScanForward(&ret, input_num);
 8585|       |  return (int)ret;
 8586|       |#else   // ADA_REGULAR_VISUAL_STUDIO
 8587|  1.09k|  return __builtin_ctzl(input_num);
 8588|  1.09k|#endif  // ADA_REGULAR_VISUAL_STUDIO
 8589|  1.09k|}
_ZN3ada7helpers24find_next_host_delimiterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEm:
 9030|  3.93k|                                                  size_t location) noexcept {
 9031|       |  // first check for short strings in which case we do it naively.
 9032|  3.93k|  if (view.size() - location < 16) {  // slow path
  ------------------
  |  Branch (9032:7): [True: 3.30k, False: 631]
  ------------------
 9033|  4.47k|    for (size_t i = location; i < view.size(); i++) {
  ------------------
  |  Branch (9033:31): [True: 1.36k, False: 3.11k]
  ------------------
 9034|  1.36k|      if (view[i] == ':' || view[i] == '/' || view[i] == '?' ||
  ------------------
  |  Branch (9034:11): [True: 12, False: 1.34k]
  |  Branch (9034:29): [True: 16, False: 1.33k]
  |  Branch (9034:47): [True: 6, False: 1.32k]
  ------------------
 9035|  1.32k|          view[i] == '[') {
  ------------------
  |  Branch (9035:11): [True: 159, False: 1.16k]
  ------------------
 9036|    193|        return i;
 9037|    193|      }
 9038|  1.36k|    }
 9039|  3.11k|    return size_t(view.size());
 9040|  3.30k|  }
 9041|       |  // fast path for long strings (expected to be common)
 9042|    631|  size_t i = location;
 9043|    631|  const __m128i mask1 = _mm_set1_epi8(':');
 9044|    631|  const __m128i mask2 = _mm_set1_epi8('/');
 9045|    631|  const __m128i mask4 = _mm_set1_epi8('?');
 9046|    631|  const __m128i mask5 = _mm_set1_epi8('[');
 9047|       |
 9048|    944|  for (; i + 15 < view.size(); i += 16) {
  ------------------
  |  Branch (9048:10): [True: 832, False: 112]
  ------------------
 9049|    832|    __m128i word = _mm_loadu_si128((const __m128i*)(view.data() + i));
 9050|    832|    __m128i m1 = _mm_cmpeq_epi8(word, mask1);
 9051|    832|    __m128i m2 = _mm_cmpeq_epi8(word, mask2);
 9052|    832|    __m128i m4 = _mm_cmpeq_epi8(word, mask4);
 9053|    832|    __m128i m5 = _mm_cmpeq_epi8(word, mask5);
 9054|    832|    __m128i m = _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m4, m5));
 9055|    832|    int mask = _mm_movemask_epi8(m);
 9056|    832|    if (mask != 0) {
  ------------------
  |  Branch (9056:9): [True: 519, False: 313]
  ------------------
 9057|    519|      return i + trailing_zeroes(mask);
 9058|    519|    }
 9059|    832|  }
 9060|    112|  if (i < view.size()) {
  ------------------
  |  Branch (9060:7): [True: 68, False: 44]
  ------------------
 9061|     68|    __m128i word =
 9062|     68|        _mm_loadu_si128((const __m128i*)(view.data() + view.length() - 16));
 9063|     68|    __m128i m1 = _mm_cmpeq_epi8(word, mask1);
 9064|     68|    __m128i m2 = _mm_cmpeq_epi8(word, mask2);
 9065|     68|    __m128i m4 = _mm_cmpeq_epi8(word, mask4);
 9066|     68|    __m128i m5 = _mm_cmpeq_epi8(word, mask5);
 9067|     68|    __m128i m = _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m4, m5));
 9068|     68|    int mask = _mm_movemask_epi8(m);
 9069|     68|    if (mask != 0) {
  ------------------
  |  Branch (9069:9): [True: 26, False: 42]
  ------------------
 9070|     26|      return view.length() - 16 + trailing_zeroes(mask);
 9071|     26|    }
 9072|     68|  }
 9073|     86|  return size_t(view.length());
 9074|    112|}
_ZN3ada7unicode8is_asciiEDi:
 7097|  10.3k|ada_really_inline constexpr bool is_ascii(const char32_t c) noexcept {
 7098|       |  // If code point is between U+0000 and U+007F inclusive, then return true.
 7099|  10.3k|  return c <= 0x7F;
 7100|  10.3k|}
_ZN3ada7unicode30is_forbidden_domain_code_pointEc:
 7008|  10.3k|    const char c) noexcept {
 7009|  10.3k|  return is_forbidden_domain_code_point_table[uint8_t(c)];
 7010|  10.3k|}
_ZN3ada7unicode16is_lowercase_hexEc:
 7168|  10.3k|ada_really_inline constexpr bool is_lowercase_hex(const char c) noexcept {
 7169|  10.3k|  return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f');
  ------------------
  |  Branch (7169:11): [True: 4.73k, False: 5.56k]
  |  Branch (7169:23): [True: 823, False: 3.91k]
  |  Branch (7169:37): [True: 1.04k, False: 8.43k]
  |  Branch (7169:49): [True: 272, False: 775]
  ------------------
 7170|  10.3k|}
_ZN3ada7unicode23is_ascii_tab_or_newlineEc:
 7107|  20.6k|    const char c) noexcept {
 7108|  20.6k|  return c == '\t' || c == '\n' || c == '\r';
  ------------------
  |  Branch (7108:10): [True: 1.30k, False: 19.3k]
  |  Branch (7108:23): [True: 992, False: 18.3k]
  |  Branch (7108:36): [True: 448, False: 17.8k]
  ------------------
 7109|  20.6k|}
_ZN3ada7unicode26is_double_dot_path_segmentENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 7115|  3.32k|    std::string_view input) noexcept {
 7116|       |  // This will catch most cases:
 7117|       |  // The length must be 2,4 or 6.
 7118|       |  // We divide by two and require
 7119|       |  // that the result be between 1 and 3 inclusively.
 7120|  3.32k|  uint64_t half_length = uint64_t(input.size()) / 2;
 7121|  3.32k|  if (half_length - 1 > 2) {
  ------------------
  |  Branch (7121:7): [True: 3.10k, False: 225]
  ------------------
 7122|  3.10k|    return false;
 7123|  3.10k|  }
 7124|       |  // We have a string of length 2, 4 or 6.
 7125|       |  // We now check the first character:
 7126|    225|  if ((input[0] != '.') && (input[0] != '%')) {
  ------------------
  |  Branch (7126:7): [True: 203, False: 22]
  |  Branch (7126:28): [True: 142, False: 61]
  ------------------
 7127|    142|    return false;
 7128|    142|  }
 7129|       |  // We are unlikely the get beyond this point.
 7130|     83|  int hash_value = (input.size() + (unsigned)(input[0])) & 3;
 7131|     83|  const std::string_view target = table_is_double_dot_path_segment[hash_value];
 7132|     83|  if (target.size() != input.size()) {
  ------------------
  |  Branch (7132:7): [True: 41, False: 42]
  ------------------
 7133|     41|    return false;
 7134|     41|  }
 7135|       |  // We almost never get here.
 7136|       |  // Optimizing the rest is relatively unimportant.
 7137|     42|  auto prefix_equal_unsafe = [](std::string_view a, std::string_view b) {
 7138|     42|    uint16_t A, B;
 7139|     42|    memcpy(&A, a.data(), sizeof(A));
 7140|     42|    memcpy(&B, b.data(), sizeof(B));
 7141|     42|    return A == B;
 7142|     42|  };
 7143|     42|  if (!prefix_equal_unsafe(input, target)) {
  ------------------
  |  Branch (7143:7): [True: 17, False: 25]
  ------------------
 7144|     17|    return false;
 7145|     17|  }
 7146|     39|  for (size_t i = 2; i < input.size(); i++) {
  ------------------
  |  Branch (7146:22): [True: 37, False: 2]
  ------------------
 7147|     37|    char c = input[i];
 7148|     37|    if ((uint8_t((c | 0x20) - 0x61) <= 25 ? (c | 0x20) : c) != target[i]) {
  ------------------
  |  Branch (7148:9): [True: 23, False: 14]
  |  Branch (7148:10): [True: 18, False: 19]
  ------------------
 7149|     23|      return false;
 7150|     23|    }
 7151|     37|  }
 7152|      2|  return true;
 7153|       |  // The above code might be a bit better than the code below. Compilers
 7154|       |  // are not stupid and may use the fact that these strings have length 2,4 and
 7155|       |  // 6 and other tricks.
 7156|       |  // return input == ".." ||
 7157|       |  //  input == ".%2e" || input == ".%2E" ||
 7158|       |  //  input == "%2e." || input == "%2E." ||
 7159|       |  //  input == "%2e%2e" || input == "%2E%2E" || input == "%2E%2e" || input ==
 7160|       |  //  "%2e%2E";
 7161|     25|}
_ZZN3ada7unicode26is_double_dot_path_segmentENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlS5_S5_E_clES5_S5_:
 7137|     42|  auto prefix_equal_unsafe = [](std::string_view a, std::string_view b) {
 7138|     42|    uint16_t A, B;
 7139|     42|    memcpy(&A, a.data(), sizeof(A));
 7140|     42|    memcpy(&B, b.data(), sizeof(B));
 7141|     42|    return A == B;
 7142|     42|  };
_ZN3ada7unicode26is_single_dot_path_segmentENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 7164|  3.32k|    std::string_view input) noexcept {
 7165|  3.32k|  return input == "." || input == "%2e" || input == "%2E";
  ------------------
  |  Branch (7165:10): [True: 1, False: 3.32k]
  |  Branch (7165:26): [True: 1, False: 3.32k]
  |  Branch (7165:44): [True: 1, False: 3.32k]
  ------------------
 7166|  3.32k|}
_ZN3ada7unicode45contains_forbidden_domain_code_point_or_upperEPKcm:
 7049|  3.32k|                                              size_t length) noexcept {
 7050|  3.32k|  size_t i = 0;
 7051|  3.32k|  uint8_t accumulator{};
 7052|  5.71k|  for (; i + 4 <= length; i += 4) {
  ------------------
  |  Branch (7052:10): [True: 2.38k, False: 3.32k]
  ------------------
 7053|  2.38k|    accumulator |=
 7054|  2.38k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i])];
 7055|  2.38k|    accumulator |=
 7056|  2.38k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 1])];
 7057|  2.38k|    accumulator |=
 7058|  2.38k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 2])];
 7059|  2.38k|    accumulator |=
 7060|  2.38k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 3])];
 7061|  2.38k|  }
 7062|  4.08k|  for (; i < length; i++) {
  ------------------
  |  Branch (7062:10): [True: 752, False: 3.32k]
  ------------------
 7063|    752|    accumulator |=
 7064|    752|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i])];
 7065|    752|  }
 7066|  3.32k|  return accumulator;
 7067|  3.32k|}

_ZN3ada37url_pattern_compile_component_optionsC2ENSt3__18optionalIcEES3_:
 5755|      6|      : delimiter(new_delimiter), prefix(new_prefix) {}
_ZN3ada8checkers8is_alphaEc:
 1267|  10.3k|constexpr bool is_alpha(char x) noexcept {
 1268|  10.3k|  return (to_lower(x) >= 'a') && (to_lower(x) <= 'z');
  ------------------
  |  Branch (1268:10): [True: 3.43k, False: 6.86k]
  |  Branch (1268:34): [True: 1.57k, False: 1.86k]
  ------------------
 1269|  10.3k|}
_ZN3ada8checkers8is_digitEc:
 1232|  10.3k|constexpr bool is_digit(char x) noexcept { return (x >= '0') & (x <= '9'); }
_ZN3ada8checkers8to_lowerEc:
 1265|  24.0k|constexpr char to_lower(char x) noexcept { return (x | 0x20); }

LLVMFuzzerTestOneInput:
   19|  3.32k|extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   20|  3.32k|  FuzzedDataProvider fdp(data, size);
   21|  3.32k|  std::string input = fdp.ConsumeRandomLengthString(128);
   22|  3.32k|  std::string_view sv(input.data(), input.size());
   23|       |
   24|       |  // ===== Per-character classification =====
   25|       |  // Drive the fuzzer over every byte value so all lookup-table branches are
   26|       |  // reachable from the corpus without relying on URL structure.
   27|  10.3k|  for (char c : input) {
  ------------------
  |  Branch (27:15): [True: 10.3k, False: 3.32k]
  ------------------
   28|       |    // forbidden_host ⊆ forbidden_domain (every host-forbidden code point must
   29|       |    // also be domain-forbidden).
   30|  10.3k|    bool is_host = ada::unicode::is_forbidden_host_code_point(c);
   31|  10.3k|    bool is_domain = ada::unicode::is_forbidden_domain_code_point(c);
   32|  10.3k|    if (is_host && !is_domain) {
  ------------------
  |  Branch (32:9): [True: 5.10k, False: 5.19k]
  |  Branch (32:20): [True: 0, False: 5.10k]
  ------------------
   33|      0|      printf(
   34|      0|          "is_forbidden_host_code_point implies is_forbidden_domain_code_point"
   35|      0|          " but got inconsistent results for char 0x%02x\n",
   36|      0|          (unsigned char)c);
   37|      0|      abort();
   38|      0|    }
   39|       |
   40|       |    // ascii_digit ⊆ ascii_hex_digit
   41|  10.3k|    bool is_digit = ada::unicode::is_ascii_digit(c);
   42|  10.3k|    bool is_hex = ada::unicode::is_ascii_hex_digit(c);
   43|  10.3k|    if (is_digit && !is_hex) {
  ------------------
  |  Branch (43:9): [True: 823, False: 9.47k]
  |  Branch (43:21): [True: 0, False: 823]
  ------------------
   44|      0|      printf(
   45|      0|          "is_ascii_digit implies is_ascii_hex_digit"
   46|      0|          " but got inconsistent results for char 0x%02x\n",
   47|      0|          (unsigned char)c);
   48|      0|      abort();
   49|      0|    }
   50|       |
   51|       |    // lowercase_hex ⊆ ascii_hex_digit
   52|  10.3k|    bool is_lhex = ada::unicode::is_lowercase_hex(c);
   53|  10.3k|    if (is_lhex && !is_hex) {
  ------------------
  |  Branch (53:9): [True: 1.09k, False: 9.20k]
  |  Branch (53:20): [True: 0, False: 1.09k]
  ------------------
   54|      0|      printf(
   55|      0|          "is_lowercase_hex implies is_ascii_hex_digit"
   56|      0|          " but got inconsistent results for char 0x%02x\n",
   57|      0|          (unsigned char)c);
   58|      0|      abort();
   59|      0|    }
   60|       |
   61|       |    // convert_hex_to_binary result must be in [0, 15] for valid hex digits.
   62|  10.3k|    if (is_hex) {
  ------------------
  |  Branch (62:9): [True: 1.41k, False: 8.89k]
  ------------------
   63|  1.41k|      unsigned val = ada::unicode::convert_hex_to_binary(c);
   64|  1.41k|      if (val > 15) {
  ------------------
  |  Branch (64:11): [True: 0, False: 1.41k]
  ------------------
   65|      0|        printf(
   66|      0|            "convert_hex_to_binary returned %u (> 15) for hex digit 0x%02x\n",
   67|      0|            val, (unsigned char)c);
   68|      0|        abort();
   69|      0|      }
   70|  1.41k|    }
   71|       |
   72|       |    // Other classification functions – must not crash.
   73|  10.3k|    volatile bool alnum = ada::unicode::is_alnum_plus(c);
   74|  10.3k|    (void)alnum;
   75|  10.3k|    volatile bool c0 = ada::unicode::is_c0_control_or_space(c);
   76|  10.3k|    (void)c0;
   77|  10.3k|    volatile bool tab_nl = ada::unicode::is_ascii_tab_or_newline(c);
   78|  10.3k|    (void)tab_nl;
   79|  10.3k|    volatile bool ascii32 = ada::unicode::is_ascii(
   80|  10.3k|        static_cast<char32_t>(static_cast<unsigned char>(c)));
   81|  10.3k|    (void)ascii32;
   82|       |
   83|       |    // ada::checkers per-character functions.
   84|  10.3k|    volatile bool alpha = ada::checkers::is_alpha(c);
   85|  10.3k|    (void)alpha;
   86|  10.3k|    volatile bool digit2 = ada::checkers::is_digit(c);
   87|  10.3k|    (void)digit2;
   88|  10.3k|    volatile char lower = ada::checkers::to_lower(c);
   89|  10.3k|    (void)lower;
   90|  10.3k|  }
   91|       |
   92|       |  // ===== String-level classification =====
   93|       |
   94|       |  // has_tabs_or_newline: any string is valid input.
   95|  3.32k|  volatile bool has_tn = ada::unicode::has_tabs_or_newline(sv);
   96|  3.32k|  (void)has_tn;
   97|       |
   98|       |  // is_double_dot and is_single_dot are mutually exclusive.
   99|  3.32k|  {
  100|  3.32k|    bool double_dot = ada::unicode::is_double_dot_path_segment(sv);
  101|  3.32k|    bool single_dot = ada::unicode::is_single_dot_path_segment(sv);
  102|  3.32k|    if (double_dot && single_dot) {
  ------------------
  |  Branch (102:9): [True: 2, False: 3.32k]
  |  Branch (102:23): [True: 0, False: 2]
  ------------------
  103|      0|      printf(
  104|      0|          "is_double_dot_path_segment and is_single_dot_path_segment are"
  105|      0|          " mutually exclusive but both true for '%s'\n",
  106|      0|          input.c_str());
  107|      0|      abort();
  108|      0|    }
  109|  3.32k|  }
  110|       |
  111|       |  // contains_forbidden_domain_code_point: must not crash.
  112|  3.32k|  volatile bool has_forbidden =
  113|  3.32k|      ada::unicode::contains_forbidden_domain_code_point(input.data(),
  114|  3.32k|                                                         input.size());
  115|  3.32k|  (void)has_forbidden;
  116|       |
  117|       |  // contains_forbidden_domain_code_point_or_upper: bit 0 = forbidden, bit 1 =
  118|       |  // upper.
  119|  3.32k|  volatile uint8_t forbidden_or_upper =
  120|  3.32k|      ada::unicode::contains_forbidden_domain_code_point_or_upper(input.data(),
  121|  3.32k|                                                                  input.size());
  122|  3.32k|  (void)forbidden_or_upper;
  123|       |
  124|       |  // to_lower_ascii: in-place; result must have the same length.
  125|  3.32k|  {
  126|  3.32k|    std::string lower_copy = input;
  127|  3.32k|    volatile bool all_ascii =
  128|  3.32k|        ada::unicode::to_lower_ascii(lower_copy.data(), lower_copy.size());
  129|  3.32k|    (void)all_ascii;
  130|  3.32k|    assert(lower_copy.size() == input.size());
  ------------------
  |  Branch (130:5): [True: 3.32k, False: 0]
  ------------------
  131|  3.32k|  }
  132|       |
  133|       |  // ===== Helper functions =====
  134|       |
  135|       |  // prune_hash: the invariant is that the returned fragment (if any) is
  136|       |  // shorter than the original input (the '#' itself is consumed).
  137|  3.32k|  {
  138|  3.32k|    std::string_view pruned = sv;
  139|  3.32k|    auto frag = ada::helpers::prune_hash(pruned);
  140|       |    // The prefix + separator + suffix must not exceed original length.
  141|  3.32k|    assert(pruned.size() <= sv.size());
  ------------------
  |  Branch (141:5): [True: 3.32k, False: 0]
  ------------------
  142|  3.32k|    if (frag.has_value()) {
  ------------------
  |  Branch (142:9): [True: 40, False: 3.28k]
  ------------------
  143|     40|      assert(pruned.size() + 1 + frag->size() <= sv.size() + 1);
  ------------------
  |  Branch (143:7): [True: 40, False: 0]
  ------------------
  144|     40|    }
  145|  3.32k|  }
  146|       |
  147|       |  // trim_c0_whitespace: result must be a substring, so never longer.
  148|  3.32k|  {
  149|  3.32k|    std::string_view trimmed = sv;
  150|  3.32k|    ada::helpers::trim_c0_whitespace(trimmed);
  151|  3.32k|    assert(trimmed.size() <= sv.size());
  ------------------
  |  Branch (151:5): [True: 3.32k, False: 0]
  ------------------
  152|  3.32k|  }
  153|       |
  154|       |  // remove_ascii_tab_or_newline: must remove all \t / \n / \r characters.
  155|  3.32k|  {
  156|  3.32k|    std::string cleaned = input;
  157|  3.32k|    ada::helpers::remove_ascii_tab_or_newline(cleaned);
  158|  8.93k|    for (char c : cleaned) {
  ------------------
  |  Branch (158:17): [True: 8.93k, False: 3.32k]
  ------------------
  159|  8.93k|      if (c == '\t' || c == '\n' || c == '\r') {
  ------------------
  |  Branch (159:11): [True: 0, False: 8.93k]
  |  Branch (159:24): [True: 0, False: 8.93k]
  |  Branch (159:37): [True: 0, False: 8.93k]
  ------------------
  160|      0|        printf(
  161|      0|            "remove_ascii_tab_or_newline left tab/newline in output for"
  162|      0|            " input '%s'\n",
  163|      0|            input.c_str());
  164|      0|        abort();
  165|      0|      }
  166|  8.93k|    }
  167|       |    // Removing characters cannot make the string longer.
  168|  3.32k|    assert(cleaned.size() <= input.size());
  ------------------
  |  Branch (168:5): [True: 3.32k, False: 0]
  ------------------
  169|  3.32k|  }
  170|       |
  171|       |  // find_authority_delimiter and find_authority_delimiter_special: result must
  172|       |  // be within [0, input.size()].
  173|  3.32k|  {
  174|  3.32k|    size_t delim = ada::helpers::find_authority_delimiter(sv);
  175|  3.32k|    assert(delim <= sv.size());
  ------------------
  |  Branch (175:5): [True: 3.32k, False: 0]
  ------------------
  176|  3.32k|    size_t delim_special = ada::helpers::find_authority_delimiter_special(sv);
  177|  3.32k|    assert(delim_special <= sv.size());
  ------------------
  |  Branch (177:5): [True: 3.32k, False: 0]
  ------------------
  178|  3.32k|  }
  179|       |
  180|       |  // get_host_delimiter_location: result position must be within [0,
  181|       |  // view.size()].
  182|  3.32k|  {
  183|  3.32k|    std::string_view view = sv;
  184|  3.32k|    auto [pos, found_colon] =
  185|  3.32k|        ada::helpers::get_host_delimiter_location(true, view);
  186|  3.32k|    (void)found_colon;
  187|       |    // pos is relative to the original sv, not the possibly-trimmed view.
  188|  3.32k|    assert(pos <= sv.size());
  ------------------
  |  Branch (188:5): [True: 3.32k, False: 0]
  ------------------
  189|  3.32k|  }
  190|  3.32k|  {
  191|  3.32k|    std::string_view view = sv;
  192|  3.32k|    auto [pos, found_colon] =
  193|  3.32k|        ada::helpers::get_host_delimiter_location(false, view);
  194|  3.32k|    (void)found_colon;
  195|  3.32k|    assert(pos <= sv.size());
  ------------------
  |  Branch (195:5): [True: 3.32k, False: 0]
  ------------------
  196|  3.32k|  }
  197|       |
  198|       |  // ===== unicode::to_ascii (internal IDNA entry point) =====
  199|       |  // This is the internal function called by the URL parser's host processing.
  200|       |  // It takes an optional<string> output buffer, the input domain, and the
  201|       |  // position of the first percent character.
  202|  3.32k|  {
  203|  3.32k|    std::string input2 = fdp.ConsumeRandomLengthString(64);
  204|  3.32k|    size_t first_pct = input2.find('%');
  205|  3.32k|    if (first_pct == std::string::npos) first_pct = input2.size();
  ------------------
  |  Branch (205:9): [True: 3.12k, False: 201]
  ------------------
  206|  3.32k|    std::optional<std::string> out;
  207|  3.32k|    volatile bool ok = ada::unicode::to_ascii(out, input2, first_pct);
  208|  3.32k|    (void)ok;
  209|  3.32k|    if (out.has_value()) {
  ------------------
  |  Branch (209:9): [True: 1.09k, False: 2.23k]
  ------------------
  210|       |      // A successfully converted domain must always be parseable as a URL host.
  211|  1.09k|      volatile size_t olen = out->size();
  212|  1.09k|      (void)olen;
  213|  1.09k|    }
  214|  3.32k|  }
  215|       |
  216|  3.32k|  return 0;
  217|  3.32k|}

