_ZN3ada4idna13utf8_to_utf32EPKcmPDi:
  172|  14.8k|size_t utf8_to_utf32(const char* buf, size_t len, char32_t* utf32_output) {
  173|  14.8k|  const uint8_t* data = reinterpret_cast<const uint8_t*>(buf);
  174|  14.8k|  size_t pos = 0;
  175|  14.8k|  const char32_t* start{utf32_output};
  176|   137k|  while (pos < len) {
  ------------------
  |  Branch (176:10): [True: 123k, False: 13.9k]
  ------------------
  177|       |    // try to convert the next block of 16 ASCII bytes
  178|   123k|    if (pos + 16 <= len) {  // if it is safe to read 16 more
  ------------------
  |  Branch (178:9): [True: 55.1k, False: 68.0k]
  ------------------
  179|       |                            // bytes, check that they are ascii
  180|  55.1k|      uint64_t v1;
  181|  55.1k|      std::memcpy(&v1, data + pos, sizeof(uint64_t));
  182|  55.1k|      uint64_t v2;
  183|  55.1k|      std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t));
  184|  55.1k|      uint64_t v{v1 | v2};
  185|  55.1k|      if ((v & 0x8080808080808080) == 0) {
  ------------------
  |  Branch (185:11): [True: 9.66k, False: 45.4k]
  ------------------
  186|  9.66k|        size_t final_pos = pos + 16;
  187|   164k|        while (pos < final_pos) {
  ------------------
  |  Branch (187:16): [True: 154k, False: 9.66k]
  ------------------
  188|   154k|          *utf32_output++ = char32_t(buf[pos]);
  189|   154k|          pos++;
  190|   154k|        }
  191|  9.66k|        continue;
  192|  9.66k|      }
  193|  55.1k|    }
  194|   113k|    uint8_t leading_byte = data[pos];  // leading byte
  195|   113k|    if (leading_byte < 0b10000000) {
  ------------------
  |  Branch (195:9): [True: 61.8k, False: 51.7k]
  ------------------
  196|       |      // converting one ASCII byte !!!
  197|  61.8k|      *utf32_output++ = char32_t(leading_byte);
  198|  61.8k|      pos++;
  199|  61.8k|    } else if ((leading_byte & 0b11100000) == 0b11000000) {
  ------------------
  |  Branch (199:16): [True: 15.0k, False: 36.6k]
  ------------------
  200|       |      // We have a two-byte UTF-8
  201|  15.0k|      if (pos + 1 >= len) {
  ------------------
  |  Branch (201:11): [True: 67, False: 14.9k]
  ------------------
  202|     67|        return 0;
  203|     67|      }  // minimal bound checking
  204|  14.9k|      if ((data[pos + 1] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (204:11): [True: 94, False: 14.9k]
  ------------------
  205|     94|        return 0;
  206|     94|      }
  207|       |      // range check
  208|  14.9k|      uint32_t code_point =
  209|  14.9k|          (leading_byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111);
  210|  14.9k|      if (code_point < 0x80 || 0x7ff < code_point) {
  ------------------
  |  Branch (210:11): [True: 11, False: 14.8k]
  |  Branch (210:32): [True: 0, False: 14.8k]
  ------------------
  211|     11|        return 0;
  212|     11|      }
  213|  14.8k|      *utf32_output++ = char32_t(code_point);
  214|  14.8k|      pos += 2;
  215|  36.6k|    } else if ((leading_byte & 0b11110000) == 0b11100000) {
  ------------------
  |  Branch (215:16): [True: 34.3k, False: 2.28k]
  ------------------
  216|       |      // We have a three-byte UTF-8
  217|  34.3k|      if (pos + 2 >= len) {
  ------------------
  |  Branch (217:11): [True: 58, False: 34.3k]
  ------------------
  218|     58|        return 0;
  219|     58|      }  // minimal bound checking
  220|       |
  221|  34.3k|      if ((data[pos + 1] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (221:11): [True: 62, False: 34.2k]
  ------------------
  222|     62|        return 0;
  223|     62|      }
  224|  34.2k|      if ((data[pos + 2] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (224:11): [True: 31, False: 34.2k]
  ------------------
  225|     31|        return 0;
  226|     31|      }
  227|       |      // range check
  228|  34.2k|      uint32_t code_point = (leading_byte & 0b00001111) << 12 |
  229|  34.2k|                            (data[pos + 1] & 0b00111111) << 6 |
  230|  34.2k|                            (data[pos + 2] & 0b00111111);
  231|  34.2k|      if (code_point < 0x800 || 0xffff < code_point ||
  ------------------
  |  Branch (231:11): [True: 25, False: 34.1k]
  |  Branch (231:33): [True: 0, False: 34.1k]
  ------------------
  232|  34.1k|          (0xd7ff < code_point && code_point < 0xe000)) {
  ------------------
  |  Branch (232:12): [True: 21.8k, False: 12.3k]
  |  Branch (232:35): [True: 5, False: 21.8k]
  ------------------
  233|     30|        return 0;
  234|     30|      }
  235|  34.1k|      *utf32_output++ = char32_t(code_point);
  236|  34.1k|      pos += 3;
  237|  34.1k|    } else if ((leading_byte & 0b11111000) == 0b11110000) {  // 0b11110000
  ------------------
  |  Branch (237:16): [True: 1.86k, False: 427]
  ------------------
  238|       |      // we have a 4-byte UTF-8 word.
  239|  1.86k|      if (pos + 3 >= len) {
  ------------------
  |  Branch (239:11): [True: 64, False: 1.79k]
  ------------------
  240|     64|        return 0;
  241|     64|      }  // minimal bound checking
  242|  1.79k|      if ((data[pos + 1] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (242:11): [True: 27, False: 1.77k]
  ------------------
  243|     27|        return 0;
  244|     27|      }
  245|  1.77k|      if ((data[pos + 2] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (245:11): [True: 14, False: 1.75k]
  ------------------
  246|     14|        return 0;
  247|     14|      }
  248|  1.75k|      if ((data[pos + 3] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (248:11): [True: 16, False: 1.74k]
  ------------------
  249|     16|        return 0;
  250|     16|      }
  251|       |
  252|       |      // range check
  253|  1.74k|      uint32_t code_point = (leading_byte & 0b00000111) << 18 |
  254|  1.74k|                            (data[pos + 1] & 0b00111111) << 12 |
  255|  1.74k|                            (data[pos + 2] & 0b00111111) << 6 |
  256|  1.74k|                            (data[pos + 3] & 0b00111111);
  257|  1.74k|      if (code_point <= 0xffff || 0x10ffff < code_point) {
  ------------------
  |  Branch (257:11): [True: 21, False: 1.72k]
  |  Branch (257:35): [True: 5, False: 1.71k]
  ------------------
  258|     26|        return 0;
  259|     26|      }
  260|  1.71k|      *utf32_output++ = char32_t(code_point);
  261|  1.71k|      pos += 4;
  262|  1.71k|    } else {
  263|    427|      return 0;
  264|    427|    }
  265|   113k|  }
  266|  13.9k|  return utf32_output - start;
  267|  14.8k|}
_ZN3ada4idna22utf8_length_from_utf32EPKDim:
  269|  8.23k|size_t utf8_length_from_utf32(const char32_t* buf, size_t len) {
  270|       |  // We are not BOM aware.
  271|  8.23k|  const uint32_t* p = reinterpret_cast<const uint32_t*>(buf);
  272|  8.23k|  size_t counter{0};
  273|   165k|  for (size_t i = 0; i != len; ++i) {
  ------------------
  |  Branch (273:22): [True: 157k, False: 8.23k]
  ------------------
  274|   157k|    ++counter;                                      // ASCII
  275|   157k|    counter += static_cast<size_t>(p[i] > 0x7F);    // two-byte
  276|   157k|    counter += static_cast<size_t>(p[i] > 0x7FF);   // three-byte
  277|   157k|    counter += static_cast<size_t>(p[i] > 0xFFFF);  // four-bytes
  278|   157k|  }
  279|  8.23k|  return counter;
  280|  8.23k|}
_ZN3ada4idna22utf32_length_from_utf8EPKcm:
  282|  16.6k|size_t utf32_length_from_utf8(const char* buf, size_t len) {
  283|  16.6k|  const int8_t* p = reinterpret_cast<const int8_t*>(buf);
  284|  16.6k|  return std::count_if(p, std::next(p, len), [](int8_t c) {
  285|       |    // -65 is 0b10111111, anything larger in two-complement's
  286|       |    // should start a new code point.
  287|  16.6k|    return c > -65;
  288|  16.6k|  });
  289|  16.6k|}
_ZN3ada4idna13utf32_to_utf8EPKDimPc:
  291|  8.23k|size_t utf32_to_utf8(const char32_t* buf, size_t len, char* utf8_output) {
  292|  8.23k|  const uint32_t* data = reinterpret_cast<const uint32_t*>(buf);
  293|  8.23k|  size_t pos = 0;
  294|  8.23k|  const char* start{utf8_output};
  295|   133k|  while (pos < len) {
  ------------------
  |  Branch (295:10): [True: 125k, False: 8.23k]
  ------------------
  296|       |    // try to convert the next block of 2 ASCII characters
  297|   125k|    if (pos + 2 <= len) {  // if it is safe to read 8 more
  ------------------
  |  Branch (297:9): [True: 118k, False: 7.37k]
  ------------------
  298|       |                           // bytes, check that they are ascii
  299|   118k|      uint64_t v;
  300|   118k|      std::memcpy(&v, data + pos, sizeof(uint64_t));
  301|   118k|      if ((v & 0xFFFFFF80FFFFFF80) == 0) {
  ------------------
  |  Branch (301:11): [True: 31.6k, False: 86.6k]
  ------------------
  302|  31.6k|        *utf8_output++ = char(buf[pos]);
  303|  31.6k|        *utf8_output++ = char(buf[pos + 1]);
  304|  31.6k|        pos += 2;
  305|  31.6k|        continue;
  306|  31.6k|      }
  307|   118k|    }
  308|  94.0k|    uint32_t word = data[pos];
  309|  94.0k|    if ((word & 0xFFFFFF80) == 0) {
  ------------------
  |  Branch (309:9): [True: 15.2k, False: 78.7k]
  ------------------
  310|       |      // will generate one UTF-8 bytes
  311|  15.2k|      *utf8_output++ = char(word);
  312|  15.2k|      pos++;
  313|  78.7k|    } else if ((word & 0xFFFFF800) == 0) {
  ------------------
  |  Branch (313:16): [True: 61.0k, False: 17.6k]
  ------------------
  314|       |      // will generate two UTF-8 bytes
  315|       |      // we have 0b110XXXXX 0b10XXXXXX
  316|  61.0k|      *utf8_output++ = char((word >> 6) | 0b11000000);
  317|  61.0k|      *utf8_output++ = char((word & 0b111111) | 0b10000000);
  318|  61.0k|      pos++;
  319|  61.0k|    } else if ((word & 0xFFFF0000) == 0) {
  ------------------
  |  Branch (319:16): [True: 15.3k, False: 2.27k]
  ------------------
  320|       |      // will generate three UTF-8 bytes
  321|       |      // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX
  322|  15.3k|      if (word >= 0xD800 && word <= 0xDFFF) {
  ------------------
  |  Branch (322:11): [True: 5.60k, False: 9.76k]
  |  Branch (322:29): [True: 0, False: 5.60k]
  ------------------
  323|      0|        return 0;
  324|      0|      }
  325|  15.3k|      *utf8_output++ = char((word >> 12) | 0b11100000);
  326|  15.3k|      *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000);
  327|  15.3k|      *utf8_output++ = char((word & 0b111111) | 0b10000000);
  328|  15.3k|      pos++;
  329|  15.3k|    } else {
  330|       |      // will generate four UTF-8 bytes
  331|       |      // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX
  332|       |      // 0b10XXXXXX
  333|  2.27k|      if (word > 0x10FFFF) {
  ------------------
  |  Branch (333:11): [True: 0, False: 2.27k]
  ------------------
  334|      0|        return 0;
  335|      0|      }
  336|  2.27k|      *utf8_output++ = char((word >> 18) | 0b11110000);
  337|  2.27k|      *utf8_output++ = char(((word >> 12) & 0b111111) | 0b10000000);
  338|  2.27k|      *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000);
  339|  2.27k|      *utf8_output++ = char((word & 0b111111) | 0b10000000);
  340|  2.27k|      pos++;
  341|  2.27k|    }
  342|  94.0k|  }
  343|  8.23k|  return utf8_output - start;
  344|  8.23k|}
_ZN3ada4idna9ascii_mapEPcm:
 5133|  13.3k|void ascii_map(char* input, size_t length) {
 5134|  13.3k|  auto broadcast = [](uint8_t v) -> uint64_t {
 5135|  13.3k|    return 0x101010101010101ull * v;
 5136|  13.3k|  };
 5137|  13.3k|  uint64_t broadcast_80 = broadcast(0x80);
 5138|  13.3k|  uint64_t broadcast_Ap = broadcast(128 - 'A');
 5139|  13.3k|  uint64_t broadcast_Zp = broadcast(128 - 'Z' - 1);
 5140|  13.3k|  size_t i = 0;
 5141|       |
 5142|  50.2k|  for (; i + 7 < length; i += 8) {
  ------------------
  |  Branch (5142:10): [True: 36.8k, False: 13.3k]
  ------------------
 5143|  36.8k|    uint64_t word{};
 5144|  36.8k|    std::memcpy(&word, input + i, sizeof(word));
 5145|  36.8k|    word ^=
 5146|  36.8k|        (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
 5147|  36.8k|    std::memcpy(input + i, &word, sizeof(word));
 5148|  36.8k|  }
 5149|  13.3k|  if (i < length) {
  ------------------
  |  Branch (5149:7): [True: 7.14k, False: 6.23k]
  ------------------
 5150|  7.14k|    uint64_t word{};
 5151|  7.14k|    std::memcpy(&word, input + i, length - i);
 5152|  7.14k|    word ^=
 5153|  7.14k|        (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
 5154|  7.14k|    std::memcpy(input + i, &word, length - i);
 5155|  7.14k|  }
 5156|  13.3k|}
_ZN3ada4idna3mapENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEERNS1_12basic_stringIDiS4_NS1_9allocatorIDiEEEE:
 5160|  18.1k|bool map(std::u32string_view input, std::u32string& out) {
 5161|       |  //  [Map](https://www.unicode.org/reports/tr46/#ProcessingStepMap).
 5162|  18.1k|  out.clear();
 5163|  18.1k|  if (!ensure_tables()) {
  ------------------
  |  Branch (5163:7): [True: 0, False: 18.1k]
  ------------------
 5164|      0|    return false;
 5165|      0|  }
 5166|       |
 5167|       |  // Pass 1: validate and compute exact output length.
 5168|  18.1k|  size_t out_size = 0;
 5169|   221k|  for (char32_t x : input) {
  ------------------
  |  Branch (5169:19): [True: 221k, False: 16.5k]
  ------------------
 5170|   221k|    uint16_t status = idna_lookup(static_cast<uint32_t>(x));
 5171|   221k|    if (status == IDNA_DISALLOWED) {
  ------------------
  |  Branch (5171:9): [True: 1.66k, False: 219k]
  ------------------
 5172|  1.66k|      return false;
 5173|  1.66k|    }
 5174|   219k|    if (status == IDNA_VALID) {
  ------------------
  |  Branch (5174:9): [True: 189k, False: 30.5k]
  ------------------
 5175|   189k|      ++out_size;
 5176|   189k|      continue;
 5177|   189k|    }
 5178|  30.5k|    if (static_cast<size_t>(status) >= idna_utf8_mappings_size) {
  ------------------
  |  Branch (5178:9): [True: 0, False: 30.5k]
  ------------------
 5179|      0|      return false;
 5180|      0|    }
 5181|  30.5k|    out_size += utf8_count_codepoints(idna_utf8_mappings + status);
 5182|  30.5k|  }
 5183|       |
 5184|       |  // Pass 2: write into a single allocation.
 5185|  16.5k|  out.resize(out_size);
 5186|  16.5k|  size_t w = 0;
 5187|   219k|  for (char32_t x : input) {
  ------------------
  |  Branch (5187:19): [True: 219k, False: 16.5k]
  ------------------
 5188|   219k|    uint16_t status = idna_lookup(static_cast<uint32_t>(x));
 5189|   219k|    if (status == IDNA_VALID) {
  ------------------
  |  Branch (5189:9): [True: 188k, False: 30.4k]
  ------------------
 5190|   188k|      out[w++] = x;
 5191|   188k|      continue;
 5192|   188k|    }
 5193|       |    // IGNORED or mapped (status already validated in pass 1).
 5194|  30.4k|    const uint8_t* ptr = idna_utf8_mappings + status;
 5195|   361k|    while (*ptr != 0) {
  ------------------
  |  Branch (5195:12): [True: 331k, False: 30.4k]
  ------------------
 5196|   331k|      out[w++] = utf8_next(ptr);
 5197|   331k|    }
 5198|  30.4k|  }
 5199|  16.5k|  return true;
 5200|  18.1k|}
_ZN3ada4idna3mapENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5202|  3.75k|std::u32string map(std::u32string_view input) {
 5203|  3.75k|  std::u32string answer;
 5204|  3.75k|  if (!map(input, answer)) {
  ------------------
  |  Branch (5204:7): [True: 268, False: 3.48k]
  ------------------
 5205|    268|    return {};
 5206|    268|  }
 5207|  3.48k|  return answer;
 5208|  3.75k|}
_ZN3ada4idna28compute_decomposition_lengthENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5293|  3.69k|    const std::u32string_view input) noexcept {
 5294|  3.69k|  bool decomposition_needed{false};
 5295|  3.69k|  size_t additional_elements{0};
 5296|  31.5k|  for (char32_t current_character : input) {
  ------------------
  |  Branch (5296:35): [True: 31.5k, False: 3.69k]
  ------------------
 5297|  31.5k|    size_t decomposition_length{0};
 5298|       |
 5299|  31.5k|    if (current_character >= hangul_sbase &&
  ------------------
  |  Branch (5299:9): [True: 3.14k, False: 28.4k]
  ------------------
 5300|  3.14k|        current_character < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (5300:9): [True: 1.96k, False: 1.18k]
  ------------------
 5301|       |      // Full NFD-style Hangul decomp for the decompose() step.
 5302|  1.96k|      decomposition_length = 2;
 5303|  1.96k|      if ((current_character - hangul_sbase) % hangul_tcount) {
  ------------------
  |  Branch (5303:11): [True: 1.34k, False: 624]
  ------------------
 5304|  1.34k|        decomposition_length = 3;
 5305|  1.34k|      }
 5306|  29.6k|    } else if (current_character < 0x110000) {
  ------------------
  |  Branch (5306:16): [True: 29.6k, False: 0]
  ------------------
 5307|  29.6k|      const uint8_t di = decomposition_index[current_character >> 8];
 5308|  29.6k|      const uint16_t* const decomposition =
 5309|  29.6k|          decomposition_block_row(di) + (current_character % 256);
 5310|  29.6k|      decomposition_length = (decomposition[1] >> 2) - (decomposition[0] >> 2);
 5311|  29.6k|      if ((decomposition_length > 0) && (decomposition[0] & 1)) {
  ------------------
  |  Branch (5311:11): [True: 3.39k, False: 26.2k]
  |  Branch (5311:41): [True: 261, False: 3.13k]
  ------------------
 5312|    261|        decomposition_length = 0;
 5313|    261|      }
 5314|  29.6k|    }
 5315|  31.5k|    if (decomposition_length != 0) {
  ------------------
  |  Branch (5315:9): [True: 5.09k, False: 26.4k]
  ------------------
 5316|  5.09k|      decomposition_needed = true;
 5317|  5.09k|      additional_elements += decomposition_length - 1;
 5318|  5.09k|    }
 5319|  31.5k|  }
 5320|  3.69k|  return {decomposition_needed, additional_elements};
 5321|  3.69k|}
_ZN3ada4idna9decomposeERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEEm:
 5323|  2.16k|void decompose(std::u32string& input, size_t additional_elements) {
 5324|  2.16k|  input.resize(input.size() + additional_elements);
 5325|  2.16k|  for (size_t descending_idx = input.size(),
 5326|  2.16k|              input_count = descending_idx - additional_elements;
 5327|  23.4k|       input_count--;) {
  ------------------
  |  Branch (5327:8): [True: 21.2k, False: 2.16k]
  ------------------
 5328|  21.2k|    if (input[input_count] >= hangul_sbase &&
  ------------------
  |  Branch (5328:9): [True: 2.77k, False: 18.4k]
  ------------------
 5329|  2.77k|        input[input_count] < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (5329:9): [True: 1.96k, False: 813]
  ------------------
 5330|       |      // Hangul decomposition.
 5331|  1.96k|      char32_t s_index = input[input_count] - hangul_sbase;
 5332|  1.96k|      if (s_index % hangul_tcount != 0) {
  ------------------
  |  Branch (5332:11): [True: 1.34k, False: 624]
  ------------------
 5333|  1.34k|        input[--descending_idx] = hangul_tbase + s_index % hangul_tcount;
 5334|  1.34k|      }
 5335|  1.96k|      input[--descending_idx] =
 5336|  1.96k|          hangul_vbase + (s_index % hangul_ncount) / hangul_tcount;
 5337|  1.96k|      input[--descending_idx] = hangul_lbase + s_index / hangul_ncount;
 5338|  19.2k|    } else if (input[input_count] < 0x110000) {
  ------------------
  |  Branch (5338:16): [True: 19.2k, False: 0]
  ------------------
 5339|  19.2k|      const uint16_t* decomposition =
 5340|  19.2k|          decomposition_block_row(
 5341|  19.2k|              decomposition_index[input[input_count] >> 8]) +
 5342|  19.2k|          (input[input_count] % 256);
 5343|  19.2k|      uint16_t decomposition_length =
 5344|  19.2k|          (decomposition[1] >> 2) - (decomposition[0] >> 2);
 5345|  19.2k|      if (decomposition_length > 0 && (decomposition[0] & 1)) {
  ------------------
  |  Branch (5345:11): [True: 3.35k, False: 15.9k]
  |  Branch (5345:39): [True: 225, False: 3.13k]
  ------------------
 5346|    225|        decomposition_length = 0;
 5347|    225|      }
 5348|  19.2k|      if (decomposition_length > 0) {
  ------------------
  |  Branch (5348:11): [True: 3.13k, False: 16.1k]
  ------------------
 5349|  3.13k|        const size_t base = static_cast<size_t>(decomposition[0] >> 2);
 5350|  3.13k|        if (base + decomposition_length > decomposition_data_size) {
  ------------------
  |  Branch (5350:13): [True: 0, False: 3.13k]
  ------------------
 5351|      0|          input[--descending_idx] = input[input_count];
 5352|  3.13k|        } else {
 5353|  9.72k|          while (decomposition_length-- > 0) {
  ------------------
  |  Branch (5353:18): [True: 6.59k, False: 3.13k]
  ------------------
 5354|  6.59k|            input[--descending_idx] =
 5355|  6.59k|                decomposition_data[base + decomposition_length];
 5356|  6.59k|          }
 5357|  3.13k|        }
 5358|  16.1k|      } else {
 5359|  16.1k|        input[--descending_idx] = input[input_count];
 5360|  16.1k|      }
 5361|  19.2k|    } else {
 5362|      0|      input[--descending_idx] = input[input_count];
 5363|      0|    }
 5364|  21.2k|  }
 5365|  2.16k|}
_ZN3ada4idna7get_cccEDi:
 5367|   644k|uint8_t get_ccc(char32_t c) noexcept {
 5368|   644k|  if (c >= 0x110000) {
  ------------------
  |  Branch (5368:7): [True: 0, False: 644k]
  ------------------
 5369|      0|    return 0;
 5370|      0|  }
 5371|   644k|  return ccc_block_row(ccc_index[c >> 8])[c % 256];
 5372|   644k|}
_ZN3ada4idna10sort_marksERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEE:
 5374|  3.69k|void sort_marks(std::u32string& input) {
 5375|  38.3k|  for (size_t idx = 1; idx < input.size(); idx++) {
  ------------------
  |  Branch (5375:24): [True: 34.6k, False: 3.69k]
  ------------------
 5376|  34.6k|    uint8_t ccc = get_ccc(input[idx]);
 5377|  34.6k|    if (ccc == 0) {
  ------------------
  |  Branch (5377:9): [True: 27.7k, False: 6.87k]
  ------------------
 5378|  27.7k|      continue;
 5379|  27.7k|    }
 5380|  6.87k|    auto current_character = input[idx];
 5381|  6.87k|    size_t back_idx = idx;
 5382|  12.0k|    while (back_idx != 0 && get_ccc(input[back_idx - 1]) > ccc) {
  ------------------
  |  Branch (5382:12): [True: 10.9k, False: 1.16k]
  |  Branch (5382:29): [True: 5.18k, False: 5.71k]
  ------------------
 5383|  5.18k|      input[back_idx] = input[back_idx - 1];
 5384|  5.18k|      back_idx--;
 5385|  5.18k|    }
 5386|  6.87k|    input[back_idx] = current_character;
 5387|  6.87k|  }
 5388|  3.69k|}
_ZN3ada4idna13decompose_nfcERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEE:
 5390|  3.69k|void decompose_nfc(std::u32string& input) {
 5391|       |  /**
 5392|       |   * Decompose the domain_name string to Unicode Normalization Form C.
 5393|       |   * @see https://www.unicode.org/reports/tr46/#ProcessingStepDecompose
 5394|       |   */
 5395|  3.69k|  auto [decomposition_needed, additional_elements] =
 5396|  3.69k|      compute_decomposition_length(input);
 5397|  3.69k|  if (decomposition_needed) {
  ------------------
  |  Branch (5397:7): [True: 2.16k, False: 1.52k]
  ------------------
 5398|  2.16k|    decompose(input, additional_elements);
 5399|  2.16k|  }
 5400|  3.69k|  sort_marks(input);
 5401|  3.69k|}
_ZN3ada4idna14is_already_nfcENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5468|  16.2k|bool is_already_nfc(std::u32string_view input) noexcept {
 5469|  16.2k|  if (input.empty()) {
  ------------------
  |  Branch (5469:7): [True: 0, False: 16.2k]
  ------------------
 5470|      0|    return true;
 5471|      0|  }
 5472|  16.2k|  if (!tables_are_ready() && !ensure_tables()) {
  ------------------
  |  Branch (5472:7): [True: 0, False: 16.2k]
  |  Branch (5472:30): [True: 0, False: 0]
  ------------------
 5473|      0|    return false;
 5474|      0|  }
 5475|       |  // 1) Singleton decompositions are never NFC (e.g. U+212B ANGSTROM SIGN).
 5476|       |  //    Multi-code-point decomps are primary composites that are NFC as-is.
 5477|   312k|  for (char32_t c : input) {
  ------------------
  |  Branch (5477:19): [True: 312k, False: 15.8k]
  ------------------
 5478|   312k|    if (canonical_decomp_length(c) == 1) {
  ------------------
  |  Branch (5478:9): [True: 418, False: 312k]
  ------------------
 5479|    418|      return false;
 5480|    418|    }
 5481|   312k|  }
 5482|       |  // 2) Combining marks already in canonical order.
 5483|  15.8k|  uint8_t prev_ccc = 0;
 5484|   308k|  for (char32_t c : input) {
  ------------------
  |  Branch (5484:19): [True: 308k, False: 14.2k]
  ------------------
 5485|   308k|    uint8_t ccc = get_ccc(c);
 5486|   308k|    if (ccc != 0 && prev_ccc > ccc) {
  ------------------
  |  Branch (5486:9): [True: 9.23k, False: 299k]
  |  Branch (5486:21): [True: 1.53k, False: 7.69k]
  ------------------
 5487|  1.53k|      return false;
 5488|  1.53k|    }
 5489|   307k|    prev_ccc = ccc;
 5490|   307k|  }
 5491|       |  // 3) No pairwise composition would apply (including Hangul L+V / LV+T).
 5492|  14.2k|  return !would_compose(input);
 5493|  15.8k|}
_ZN3ada4idna7composeERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEE:
 5495|  3.69k|void compose(std::u32string& input) {
 5496|       |  /**
 5497|       |   * Compose the domain_name string to Unicode Normalization Form C.
 5498|       |   * @see https://www.unicode.org/reports/tr46/#ProcessingStepCompose
 5499|       |   */
 5500|  3.69k|  size_t input_count{0};
 5501|  3.69k|  size_t composition_count{0};
 5502|  29.9k|  for (; input_count < input.size(); input_count++, composition_count++) {
  ------------------
  |  Branch (5502:10): [True: 26.2k, False: 3.69k]
  ------------------
 5503|  26.2k|    input[composition_count] = input[input_count];
 5504|  26.2k|    if (input[input_count] >= hangul_lbase &&
  ------------------
  |  Branch (5504:9): [True: 8.36k, False: 17.8k]
  ------------------
 5505|  8.36k|        input[input_count] < hangul_lbase + hangul_lcount) {
  ------------------
  |  Branch (5505:9): [True: 3.53k, False: 4.83k]
  ------------------
 5506|  3.53k|      if (input_count + 1 < input.size() &&
  ------------------
  |  Branch (5506:11): [True: 3.44k, False: 93]
  ------------------
 5507|  3.44k|          input[input_count + 1] >= hangul_vbase &&
  ------------------
  |  Branch (5507:11): [True: 2.70k, False: 742]
  ------------------
 5508|  2.70k|          input[input_count + 1] < hangul_vbase + hangul_vcount) {
  ------------------
  |  Branch (5508:11): [True: 2.38k, False: 319]
  ------------------
 5509|  2.38k|        input[composition_count] =
 5510|  2.38k|            hangul_sbase +
 5511|  2.38k|            ((input[input_count] - hangul_lbase) * hangul_vcount +
 5512|  2.38k|             input[input_count + 1] - hangul_vbase) *
 5513|  2.38k|                hangul_tcount;
 5514|  2.38k|        input_count++;
 5515|  2.38k|        if (input_count + 1 < input.size() &&
  ------------------
  |  Branch (5515:13): [True: 2.16k, False: 213]
  ------------------
 5516|  2.16k|            input[input_count + 1] > hangul_tbase &&
  ------------------
  |  Branch (5516:13): [True: 1.62k, False: 543]
  ------------------
 5517|  1.62k|            input[input_count + 1] < hangul_tbase + hangul_tcount) {
  ------------------
  |  Branch (5517:13): [True: 1.40k, False: 221]
  ------------------
 5518|  1.40k|          input[composition_count] += input[++input_count] - hangul_tbase;
 5519|  1.40k|        }
 5520|  2.38k|      }
 5521|  22.7k|    } else if (input[input_count] >= hangul_sbase &&
  ------------------
  |  Branch (5521:16): [True: 983, False: 21.7k]
  ------------------
 5522|    983|               input[input_count] < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (5522:16): [True: 0, False: 983]
  ------------------
 5523|      0|      if ((input[input_count] - hangul_sbase) % hangul_tcount &&
  ------------------
  |  Branch (5523:11): [True: 0, False: 0]
  ------------------
 5524|      0|          input_count + 1 < input.size() &&
  ------------------
  |  Branch (5524:11): [True: 0, False: 0]
  ------------------
 5525|      0|          input[input_count + 1] > hangul_tbase &&
  ------------------
  |  Branch (5525:11): [True: 0, False: 0]
  ------------------
 5526|      0|          input[input_count + 1] < hangul_tbase + hangul_tcount) {
  ------------------
  |  Branch (5526:11): [True: 0, False: 0]
  ------------------
 5527|      0|        input[composition_count] += input[++input_count] - hangul_tbase;
 5528|      0|      }
 5529|  22.7k|    } else if (input[input_count] < 0x110000) {
  ------------------
  |  Branch (5529:16): [True: 22.7k, False: 0]
  ------------------
 5530|  22.7k|      const uint16_t* composition =
 5531|  22.7k|          composition_block_row(composition_index[input[input_count] >> 8]) +
 5532|  22.7k|          (input[input_count] % 256);
 5533|  22.7k|      size_t initial_composition_count = composition_count;
 5534|  31.0k|      for (int32_t previous_ccc = -1; input_count + 1 < input.size();
  ------------------
  |  Branch (5534:39): [True: 27.7k, False: 3.26k]
  ------------------
 5535|  27.7k|           input_count++) {
 5536|  27.7k|        uint8_t ccc = get_ccc(input[input_count + 1]);
 5537|       |
 5538|  27.7k|        if (composition[1] != composition[0] && previous_ccc < ccc) {
  ------------------
  |  Branch (5538:13): [True: 9.53k, False: 18.2k]
  |  Branch (5538:49): [True: 9.01k, False: 520]
  ------------------
 5539|  9.01k|          int left = composition[0];
 5540|  9.01k|          int right = composition[1];
 5541|  9.01k|          if (left < 0 || right < left ||
  ------------------
  |  Branch (5541:15): [True: 0, False: 9.01k]
  |  Branch (5541:27): [True: 0, False: 9.01k]
  ------------------
 5542|  9.01k|              static_cast<size_t>(right) > composition_data_size) {
  ------------------
  |  Branch (5542:15): [True: 0, False: 9.01k]
  ------------------
 5543|      0|            break;
 5544|      0|          }
 5545|  19.7k|          while (left + 2 < right) {
  ------------------
  |  Branch (5545:18): [True: 10.7k, False: 9.01k]
  ------------------
 5546|  10.7k|            int middle = left + (((right - left) >> 1) & ~1);
 5547|  10.7k|            if (composition_data[static_cast<size_t>(middle)] <=
  ------------------
  |  Branch (5547:17): [True: 4.81k, False: 5.92k]
  ------------------
 5548|  10.7k|                input[input_count + 1]) {
 5549|  4.81k|              left = middle;
 5550|  4.81k|            }
 5551|  10.7k|            if (composition_data[static_cast<size_t>(middle)] >=
  ------------------
  |  Branch (5551:17): [True: 7.33k, False: 3.40k]
  ------------------
 5552|  10.7k|                input[input_count + 1]) {
 5553|  7.33k|              right = middle;
 5554|  7.33k|            }
 5555|  10.7k|          }
 5556|  9.01k|          if (static_cast<size_t>(left + 1) < composition_data_size &&
  ------------------
  |  Branch (5556:15): [True: 9.01k, False: 0]
  ------------------
 5557|  9.01k|              composition_data[static_cast<size_t>(left)] ==
  ------------------
  |  Branch (5557:15): [True: 4.23k, False: 4.78k]
  ------------------
 5558|  9.01k|                  input[input_count + 1]) {
 5559|  4.23k|            char32_t composed = composition_data[static_cast<size_t>(left + 1)];
 5560|  4.23k|            input[initial_composition_count] = composed;
 5561|  4.23k|            composition =
 5562|  4.23k|                composition_block_row(composition_index[composed >> 8]) +
 5563|  4.23k|                (composed % 256);
 5564|  4.23k|            continue;
 5565|  4.23k|          }
 5566|  9.01k|        }
 5567|       |
 5568|  23.5k|        if (ccc == 0) {
  ------------------
  |  Branch (5568:13): [True: 19.4k, False: 4.06k]
  ------------------
 5569|  19.4k|          break;
 5570|  19.4k|        }
 5571|  4.06k|        previous_ccc = ccc;
 5572|  4.06k|        input[++composition_count] = input[input_count + 1];
 5573|  4.06k|      }
 5574|  22.7k|    }
 5575|  26.2k|  }
 5576|       |
 5577|  3.69k|  if (composition_count < input_count) {
  ------------------
  |  Branch (5577:7): [True: 2.53k, False: 1.15k]
  ------------------
 5578|  2.53k|    input.resize(composition_count);
 5579|  2.53k|  }
 5580|  3.69k|}
_ZN3ada4idna9normalizeERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEE:
 5582|  13.2k|bool normalize(std::u32string& input) {
 5583|       |  /**
 5584|       |   * Normalize the characters according to IDNA (Unicode Normalization Form C).
 5585|       |   * @see https://www.unicode.org/reports/tr46/#ProcessingStepNormalize
 5586|       |   */
 5587|  13.2k|  if (!ensure_tables() || decomposition_index == nullptr ||
  ------------------
  |  Branch (5587:7): [True: 0, False: 13.2k]
  |  Branch (5587:27): [True: 0, False: 13.2k]
  ------------------
 5588|  13.2k|      composition_index == nullptr) {
  ------------------
  |  Branch (5588:7): [True: 0, False: 13.2k]
  ------------------
 5589|      0|    return false;
 5590|      0|  }
 5591|  13.2k|  if (is_already_nfc(input)) {
  ------------------
  |  Branch (5591:7): [True: 9.53k, False: 3.69k]
  ------------------
 5592|  9.53k|    return true;
 5593|  9.53k|  }
 5594|  3.69k|  decompose_nfc(input);
 5595|  3.69k|  compose(input);
 5596|  3.69k|  return true;
 5597|  13.2k|}
_ZN3ada4idna17punycode_to_utf32ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEERNS1_12basic_stringIDiNS3_IDiEENS1_9allocatorIDiEEEE:
 5657|  28.2k|bool punycode_to_utf32(std::string_view input, std::u32string &out) {
 5658|  28.2k|  int32_t written_out{0};
 5659|  28.2k|  out.reserve(out.size() + input.size());
 5660|  28.2k|  uint32_t n = initial_n;
 5661|  28.2k|  int32_t i = 0;
 5662|  28.2k|  int32_t bias = initial_bias;
 5663|       |  // grab ascii content
 5664|  28.2k|  size_t end_of_ascii = input.find_last_of('-');
 5665|  28.2k|  if (end_of_ascii != std::string_view::npos) {
  ------------------
  |  Branch (5665:7): [True: 4.47k, False: 23.8k]
  ------------------
 5666|  57.0k|    for (uint8_t c : input.substr(0, end_of_ascii)) {
  ------------------
  |  Branch (5666:20): [True: 57.0k, False: 4.16k]
  ------------------
 5667|  57.0k|      if (c >= 0x80) {
  ------------------
  |  Branch (5667:11): [True: 313, False: 56.7k]
  ------------------
 5668|    313|        return false;
 5669|    313|      }
 5670|  56.7k|      out.push_back(c);
 5671|  56.7k|      written_out++;
 5672|  56.7k|    }
 5673|  4.16k|    input.remove_prefix(end_of_ascii + 1);
 5674|  4.16k|  }
 5675|   145k|  while (!input.empty()) {
  ------------------
  |  Branch (5675:10): [True: 121k, False: 23.5k]
  ------------------
 5676|   121k|    int32_t oldi = i;
 5677|   121k|    int32_t w = 1;
 5678|   170k|    for (int32_t k = base;; k += base) {
 5679|   170k|      if (input.empty()) {
  ------------------
  |  Branch (5679:11): [True: 372, False: 170k]
  ------------------
 5680|    372|        return false;
 5681|    372|      }
 5682|   170k|      uint8_t code_point = input.front();
 5683|   170k|      input.remove_prefix(1);
 5684|   170k|      int32_t digit = char_to_digit_value(code_point);
 5685|   170k|      if (digit < 0) {
  ------------------
  |  Branch (5685:11): [True: 3.77k, False: 166k]
  ------------------
 5686|  3.77k|        return false;
 5687|  3.77k|      }
 5688|   166k|      if (digit > (0x7fffffff - i) / w) {
  ------------------
  |  Branch (5688:11): [True: 122, False: 166k]
  ------------------
 5689|    122|        return false;
 5690|    122|      }
 5691|   166k|      i = i + digit * w;
 5692|   166k|      int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias;
  ------------------
  |  Branch (5692:19): [True: 32.4k, False: 134k]
  |  Branch (5692:38): [True: 126k, False: 7.91k]
  ------------------
 5693|   166k|      if (digit < t) {
  ------------------
  |  Branch (5693:11): [True: 117k, False: 49.2k]
  ------------------
 5694|   117k|        break;
 5695|   117k|      }
 5696|  49.2k|      if (w > 0x7fffffff / (base - t)) {
  ------------------
  |  Branch (5696:11): [True: 0, False: 49.2k]
  ------------------
 5697|      0|        return false;
 5698|      0|      }
 5699|  49.2k|      w = w * (base - t);
 5700|  49.2k|    }
 5701|   117k|    bias = adapt(i - oldi, written_out + 1, oldi == 0);
 5702|   117k|    if (i / (written_out + 1) > int32_t(0x7fffffff - n)) {
  ------------------
  |  Branch (5702:9): [True: 113, False: 117k]
  ------------------
 5703|    113|      return false;
 5704|    113|    }
 5705|   117k|    n = n + i / (written_out + 1);
 5706|   117k|    i = i % (written_out + 1);
 5707|   117k|    if (n < 0x80) {
  ------------------
  |  Branch (5707:9): [True: 0, False: 117k]
  ------------------
 5708|      0|      return false;
 5709|      0|    }
 5710|   117k|    out.insert(out.begin() + i, n);
 5711|   117k|    written_out++;
 5712|   117k|    ++i;
 5713|   117k|  }
 5714|       |  // See https://github.com/whatwg/url/issues/803
 5715|       |  // Reject labels whose decoded form begins with "xn--" (double-encoded ACE).
 5716|  23.5k|  if (out.size() >= 4 && out[0] == U'x' && out[1] == U'n' && out[2] == U'-' &&
  ------------------
  |  Branch (5716:7): [True: 4.22k, False: 19.3k]
  |  Branch (5716:26): [True: 1.12k, False: 3.10k]
  |  Branch (5716:44): [True: 734, False: 389]
  |  Branch (5716:62): [True: 496, False: 238]
  ------------------
 5717|    496|      out[3] == U'-') {
  ------------------
  |  Branch (5717:7): [True: 303, False: 193]
  ------------------
 5718|    303|    return false;
 5719|    303|  }
 5720|  23.2k|  return true;
 5721|  23.5k|}
_ZN3ada4idna15verify_punycodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 5723|  4.53k|bool verify_punycode(std::string_view input) {
 5724|       |  // Track only the first 4 decoded code points to check for the "xn--" prefix.
 5725|       |  // This avoids heap allocation while still detecting double-encoded ACE
 5726|       |  // labels.
 5727|  4.53k|  uint32_t first4[4]{};
 5728|  4.53k|  size_t written_out{0};
 5729|  4.53k|  uint32_t n = initial_n;
 5730|  4.53k|  int32_t i = 0;
 5731|  4.53k|  int32_t bias = initial_bias;
 5732|       |  // grab ascii content
 5733|  4.53k|  size_t end_of_ascii = input.find_last_of('-');
 5734|  4.53k|  if (end_of_ascii != std::string_view::npos) {
  ------------------
  |  Branch (5734:7): [True: 1.37k, False: 3.16k]
  ------------------
 5735|  31.7k|    for (uint8_t c : input.substr(0, end_of_ascii)) {
  ------------------
  |  Branch (5735:20): [True: 31.7k, False: 1.09k]
  ------------------
 5736|  31.7k|      if (c >= 0x80) {
  ------------------
  |  Branch (5736:11): [True: 287, False: 31.4k]
  ------------------
 5737|    287|        return false;
 5738|    287|      }
 5739|  31.4k|      if (written_out < 4) {
  ------------------
  |  Branch (5739:11): [True: 4.07k, False: 27.3k]
  ------------------
 5740|  4.07k|        first4[written_out] = c;
 5741|  4.07k|      }
 5742|  31.4k|      written_out++;
 5743|  31.4k|    }
 5744|  1.09k|    input.remove_prefix(end_of_ascii + 1);
 5745|  1.09k|  }
 5746|  14.1k|  while (!input.empty()) {
  ------------------
  |  Branch (5746:10): [True: 12.6k, False: 1.50k]
  ------------------
 5747|  12.6k|    int32_t oldi = i;
 5748|  12.6k|    int32_t w = 1;
 5749|  18.9k|    for (int32_t k = base;; k += base) {
 5750|  18.9k|      if (input.empty()) {
  ------------------
  |  Branch (5750:11): [True: 90, False: 18.8k]
  ------------------
 5751|     90|        return false;
 5752|     90|      }
 5753|  18.8k|      uint8_t code_point = input.front();
 5754|  18.8k|      input.remove_prefix(1);
 5755|  18.8k|      int32_t digit = char_to_digit_value(code_point);
 5756|  18.8k|      if (digit < 0) {
  ------------------
  |  Branch (5756:11): [True: 2.60k, False: 16.2k]
  ------------------
 5757|  2.60k|        return false;
 5758|  2.60k|      }
 5759|  16.2k|      if (digit > (0x7fffffff - i) / w) {
  ------------------
  |  Branch (5759:11): [True: 19, False: 16.2k]
  ------------------
 5760|     19|        return false;
 5761|     19|      }
 5762|  16.2k|      i = i + digit * w;
 5763|  16.2k|      int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias;
  ------------------
  |  Branch (5763:19): [True: 4.17k, False: 12.1k]
  |  Branch (5763:38): [True: 11.3k, False: 713]
  ------------------
 5764|  16.2k|      if (digit < t) {
  ------------------
  |  Branch (5764:11): [True: 9.93k, False: 6.33k]
  ------------------
 5765|  9.93k|        break;
 5766|  9.93k|      }
 5767|  6.33k|      if (w > 0x7fffffff / (base - t)) {
  ------------------
  |  Branch (5767:11): [True: 0, False: 6.33k]
  ------------------
 5768|      0|        return false;
 5769|      0|      }
 5770|  6.33k|      w = w * (base - t);
 5771|  6.33k|    }
 5772|  9.93k|    bias = adapt(i - oldi, int32_t(written_out + 1), oldi == 0);
 5773|  9.93k|    if (i / (written_out + 1) > 0x7fffffff - n) {
  ------------------
  |  Branch (5773:9): [True: 32, False: 9.90k]
  ------------------
 5774|     32|      return false;
 5775|     32|    }
 5776|  9.90k|    n = n + i / int32_t(written_out + 1);
 5777|  9.90k|    i = i % int32_t(written_out + 1);
 5778|  9.90k|    if (n < 0x80) {
  ------------------
  |  Branch (5778:9): [True: 0, False: 9.90k]
  ------------------
 5779|      0|      return false;
 5780|      0|    }
 5781|       |    // Simulate insert at position i, maintaining only the first 4 slots.
 5782|  9.90k|    size_t insert_pos = size_t(i);
 5783|  9.90k|    if (insert_pos < 4) {
  ------------------
  |  Branch (5783:9): [True: 2.40k, False: 7.50k]
  ------------------
 5784|  6.55k|      for (size_t j = 3; j > insert_pos; j--) {
  ------------------
  |  Branch (5784:26): [True: 4.15k, False: 2.40k]
  ------------------
 5785|  4.15k|        first4[j] = first4[j - 1];
 5786|  4.15k|      }
 5787|  2.40k|      first4[insert_pos] = n;
 5788|  2.40k|    }
 5789|  9.90k|    written_out++;
 5790|  9.90k|    ++i;
 5791|  9.90k|  }
 5792|       |  // See https://github.com/whatwg/url/issues/803
 5793|       |  // Reject labels whose decoded form begins with "xn--" (double-encoded ACE).
 5794|  1.50k|  if (written_out >= 4 && first4[0] == U'x' && first4[1] == U'n' &&
  ------------------
  |  Branch (5794:7): [True: 792, False: 711]
  |  Branch (5794:27): [True: 519, False: 273]
  |  Branch (5794:48): [True: 398, False: 121]
  ------------------
 5795|    398|      first4[2] == U'-' && first4[3] == U'-') {
  ------------------
  |  Branch (5795:7): [True: 308, False: 90]
  |  Branch (5795:28): [True: 239, False: 69]
  ------------------
 5796|    239|    return false;
 5797|    239|  }
 5798|  1.26k|  return true;
 5799|  1.50k|}
_ZN3ada4idna17utf32_to_punycodeENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEERNS1_12basic_stringIcNS3_IcEENS1_9allocatorIcEEEE:
 5801|  4.47k|bool utf32_to_punycode(std::u32string_view input, std::string &out) {
 5802|  4.47k|  out.reserve(input.size() + out.size());
 5803|  4.47k|  uint32_t n = initial_n;
 5804|  4.47k|  int32_t d = 0;
 5805|  4.47k|  int32_t bias = initial_bias;
 5806|  4.47k|  size_t h = 0;
 5807|       |  // first push the ascii content
 5808|  98.5k|  for (uint32_t c : input) {
  ------------------
  |  Branch (5808:19): [True: 98.5k, False: 4.31k]
  ------------------
 5809|  98.5k|    if (c < 0x80) {
  ------------------
  |  Branch (5809:9): [True: 23.3k, False: 75.1k]
  ------------------
 5810|  23.3k|      ++h;
 5811|  23.3k|      out.push_back(char(c));
 5812|  23.3k|    }
 5813|  98.5k|    if (c > 0x10ffff || (c >= 0xd800 && c < 0xe000)) {
  ------------------
  |  Branch (5813:9): [True: 144, False: 98.4k]
  |  Branch (5813:26): [True: 794, False: 97.6k]
  |  Branch (5813:41): [True: 16, False: 778]
  ------------------
 5814|    160|      return false;
 5815|    160|    }
 5816|  98.5k|  }
 5817|  4.31k|  size_t b = h;
 5818|  4.31k|  if (b > 0) {
  ------------------
  |  Branch (5818:7): [True: 1.96k, False: 2.34k]
  ------------------
 5819|  1.96k|    out.push_back('-');
 5820|  1.96k|  }
 5821|  16.9k|  while (h < input.size()) {
  ------------------
  |  Branch (5821:10): [True: 12.6k, False: 4.31k]
  ------------------
 5822|  12.6k|    uint32_t m = 0x10FFFF;
 5823|   993k|    for (auto code_point : input) {
  ------------------
  |  Branch (5823:26): [True: 993k, False: 12.6k]
  ------------------
 5824|   993k|      if (code_point >= n && code_point < m) m = code_point;
  ------------------
  |  Branch (5824:11): [True: 408k, False: 584k]
  |  Branch (5824:30): [True: 21.7k, False: 386k]
  ------------------
 5825|   993k|    }
 5826|       |
 5827|  12.6k|    if ((m - n) > (0x7fffffff - d) / (h + 1)) {
  ------------------
  |  Branch (5827:9): [True: 0, False: 12.6k]
  ------------------
 5828|      0|      return false;
 5829|      0|    }
 5830|  12.6k|    d = d + int32_t((m - n) * (h + 1));
 5831|  12.6k|    n = m;
 5832|   993k|    for (auto c : input) {
  ------------------
  |  Branch (5832:17): [True: 993k, False: 12.6k]
  ------------------
 5833|   993k|      if (c < n) {
  ------------------
  |  Branch (5833:11): [True: 584k, False: 408k]
  ------------------
 5834|   584k|        if (d == 0x7fffffff) {
  ------------------
  |  Branch (5834:13): [True: 0, False: 584k]
  ------------------
 5835|      0|          return false;
 5836|      0|        }
 5837|   584k|        ++d;
 5838|   584k|      }
 5839|   993k|      if (c == n) {
  ------------------
  |  Branch (5839:11): [True: 74.9k, False: 918k]
  ------------------
 5840|  74.9k|        int32_t q = d;
 5841|  95.6k|        for (int32_t k = base;; k += base) {
 5842|  95.6k|          int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias;
  ------------------
  |  Branch (5842:23): [True: 10.5k, False: 85.0k]
  |  Branch (5842:42): [True: 80.6k, False: 4.41k]
  ------------------
 5843|       |
 5844|  95.6k|          if (q < t) {
  ------------------
  |  Branch (5844:15): [True: 74.9k, False: 20.6k]
  ------------------
 5845|  74.9k|            break;
 5846|  74.9k|          }
 5847|  20.6k|          out.push_back(digit_to_char(t + ((q - t) % (base - t))));
 5848|  20.6k|          q = (q - t) / (base - t);
 5849|  20.6k|        }
 5850|  74.9k|        out.push_back(digit_to_char(q));
 5851|  74.9k|        bias = adapt(d, int32_t(h + 1), h == b);
 5852|  74.9k|        d = 0;
 5853|  74.9k|        ++h;
 5854|  74.9k|      }
 5855|   993k|    }
 5856|  12.6k|    ++d;
 5857|  12.6k|    ++n;
 5858|  12.6k|  }
 5859|  4.31k|  return true;
 5860|  4.31k|}
_ZN3ada4idna14is_label_validENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5944|  12.3k|bool is_label_valid(const std::u32string_view label) {
 5945|  12.3k|  if (label.empty()) {
  ------------------
  |  Branch (5945:7): [True: 0, False: 12.3k]
  ------------------
 5946|      0|    return true;
 5947|      0|  }
 5948|  12.3k|  if (!ensure_tables() || combining_ranges == nullptr || dir_start == nullptr ||
  ------------------
  |  Branch (5948:7): [True: 0, False: 12.3k]
  |  Branch (5948:27): [True: 0, False: 12.3k]
  |  Branch (5948:58): [True: 0, False: 12.3k]
  ------------------
 5949|  12.3k|      dir_final == nullptr || dir_value == nullptr) {
  ------------------
  |  Branch (5949:7): [True: 0, False: 12.3k]
  |  Branch (5949:31): [True: 0, False: 12.3k]
  ------------------
 5950|      0|    return false;
 5951|      0|  }
 5952|       |
 5953|       |  ///////////////
 5954|       |  // We have a normalization step which ensures that we are in NFC.
 5955|       |  // If we receive punycode, we normalize and check that the normalized
 5956|       |  // version matches the original.
 5957|       |  // --------------------------------------
 5958|       |  // The label must be in Unicode Normalization Form NFC.
 5959|       |
 5960|       |  // Current URL standard indicatest that CheckHyphens is set to false.
 5961|       |  // ---------------------------------------
 5962|       |  // If CheckHyphens, the label must not contain a U+002D HYPHEN-MINUS character
 5963|       |  // in both the third and fourth positions. If CheckHyphens, the label must
 5964|       |  // neither begin nor end with a U+002D HYPHEN-MINUS character.
 5965|       |
 5966|       |  // This is not necessary because we segment the
 5967|       |  // labels by '.'.
 5968|       |  // ---------------------------------------
 5969|       |  // The label must not contain a U+002E ( . ) FULL STOP.
 5970|       |  // if (label.find('.') != std::string_view::npos) return false;
 5971|       |
 5972|       |  // The label must not begin with a combining mark.
 5973|       |  // Range membership via lower_bound on range end.
 5974|  12.3k|  const std::span<const uint32_t[2]> comb_span{combining_ranges,
 5975|  12.3k|                                               combining_range_count};
 5976|  12.3k|  const auto comb_it = std::ranges::lower_bound(
 5977|  12.3k|      comb_span, label.front(), {}, [](const auto& range) { return range[1]; });
 5978|  12.3k|  if (comb_it != comb_span.end() && label.front() >= (*comb_it)[0]) {
  ------------------
  |  Branch (5978:7): [True: 12.1k, False: 111]
  |  Branch (5978:7): [True: 292, False: 12.0k]
  |  Branch (5978:37): [True: 292, False: 11.9k]
  ------------------
 5979|    292|    return false;
 5980|    292|  }
 5981|       |  // We verify this next step as part of the mapping:
 5982|       |  // ---------------------------------------------
 5983|       |  // Each code point in the label must only have certain status values
 5984|       |  // according to Section 5, IDNA Mapping Table:
 5985|       |  // - For Transitional Processing, each value must be valid.
 5986|       |  // - For Nontransitional Processing, each value must be either valid or
 5987|       |  // deviation.
 5988|       |
 5989|       |  // If CheckJoiners, the label must satisfy the ContextJ rules from Appendix
 5990|       |  // A, in The Unicode Code Points and Internationalized Domain Names for
 5991|       |  // Applications (IDNA) [IDNA2008].
 5992|  12.0k|  constexpr static uint32_t virama[] = {
 5993|  12.0k|      0x094D,  0x09CD,  0x0A4D,  0x0ACD,  0x0B4D,  0x0BCD,  0x0C4D,  0x0CCD,
 5994|  12.0k|      0x0D3B,  0x0D3C,  0x0D4D,  0x0DCA,  0x0E3A,  0x0EBA,  0x0F84,  0x1039,
 5995|  12.0k|      0x103A,  0x1714,  0x1734,  0x17D2,  0x1A60,  0x1B44,  0x1BAA,  0x1BAB,
 5996|  12.0k|      0x1BF2,  0x1BF3,  0x2D7F,  0xA806,  0xA82C,  0xA8C4,  0xA953,  0xA9C0,
 5997|  12.0k|      0xAAF6,  0xABED,  0x10A3F, 0x11046, 0x1107F, 0x110B9, 0x11133, 0x11134,
 5998|  12.0k|      0x111C0, 0x11235, 0x112EA, 0x1134D, 0x11442, 0x114C2, 0x115BF, 0x1163F,
 5999|  12.0k|      0x116B6, 0x1172B, 0x11839, 0x1193D, 0x1193E, 0x119E0, 0x11A34, 0x11A47,
 6000|  12.0k|      0x11A99, 0x11C3F, 0x11D44, 0x11D45, 0x11D97};
 6001|  12.0k|  constexpr static uint32_t R[] = {
 6002|  12.0k|      0x622, 0x623, 0x624, 0x625, 0x627, 0x629, 0x62f, 0x630, 0x631,
 6003|  12.0k|      0x632, 0x648, 0x671, 0x672, 0x673, 0x675, 0x676, 0x677, 0x688,
 6004|  12.0k|      0x689, 0x68a, 0x68b, 0x68c, 0x68d, 0x68e, 0x68f, 0x690, 0x691,
 6005|  12.0k|      0x692, 0x693, 0x694, 0x695, 0x696, 0x697, 0x698, 0x699, 0x6c0,
 6006|  12.0k|      0x6c3, 0x6c4, 0x6c5, 0x6c6, 0x6c7, 0x6c8, 0x6c9, 0x6ca, 0x6cb,
 6007|  12.0k|      0x6cd, 0x6cf, 0x6d2, 0x6d3, 0x6d5, 0x6ee, 0x6ef, 0x710, 0x715,
 6008|  12.0k|      0x716, 0x717, 0x718, 0x719, 0x71e, 0x728, 0x72a, 0x72c, 0x72f,
 6009|  12.0k|      0x74d, 0x759, 0x75a, 0x75b, 0x854, 0x8aa, 0x8ab, 0x8ac};
 6010|  12.0k|  constexpr static uint32_t L[] = {0xa872};
 6011|  12.0k|  constexpr static uint32_t D[] = {
 6012|  12.0k|      0x620,  0x626,  0x628,  0x62a,  0x62b,  0x62c,  0x62d,  0x62e,  0x633,
 6013|  12.0k|      0x634,  0x635,  0x636,  0x637,  0x638,  0x639,  0x63a,  0x63b,  0x63c,
 6014|  12.0k|      0x63d,  0x63e,  0x63f,  0x641,  0x642,  0x643,  0x644,  0x645,  0x646,
 6015|  12.0k|      0x647,  0x649,  0x64a,  0x66e,  0x66f,  0x678,  0x679,  0x67a,  0x67b,
 6016|  12.0k|      0x67c,  0x67d,  0x67e,  0x67f,  0x680,  0x681,  0x682,  0x683,  0x684,
 6017|  12.0k|      0x685,  0x686,  0x687,  0x69a,  0x69b,  0x69c,  0x69d,  0x69e,  0x69f,
 6018|  12.0k|      0x6a0,  0x6a1,  0x6a2,  0x6a3,  0x6a4,  0x6a5,  0x6a6,  0x6a7,  0x6a8,
 6019|  12.0k|      0x6a9,  0x6aa,  0x6ab,  0x6ac,  0x6ad,  0x6ae,  0x6af,  0x6b0,  0x6b1,
 6020|  12.0k|      0x6b2,  0x6b3,  0x6b4,  0x6b5,  0x6b6,  0x6b7,  0x6b8,  0x6b9,  0x6ba,
 6021|  12.0k|      0x6bb,  0x6bc,  0x6bd,  0x6be,  0x6bf,  0x6c1,  0x6c2,  0x6cc,  0x6ce,
 6022|  12.0k|      0x6d0,  0x6d1,  0x6fa,  0x6fb,  0x6fc,  0x6ff,  0x712,  0x713,  0x714,
 6023|  12.0k|      0x71a,  0x71b,  0x71c,  0x71d,  0x71f,  0x720,  0x721,  0x722,  0x723,
 6024|  12.0k|      0x724,  0x725,  0x726,  0x727,  0x729,  0x72b,  0x72d,  0x72e,  0x74e,
 6025|  12.0k|      0x74f,  0x750,  0x751,  0x752,  0x753,  0x754,  0x755,  0x756,  0x757,
 6026|  12.0k|      0x758,  0x75c,  0x75d,  0x75e,  0x75f,  0x760,  0x761,  0x762,  0x763,
 6027|  12.0k|      0x764,  0x765,  0x766,  0x850,  0x851,  0x852,  0x853,  0x855,  0x8a0,
 6028|  12.0k|      0x8a2,  0x8a3,  0x8a4,  0x8a5,  0x8a6,  0x8a7,  0x8a8,  0x8a9,  0x1807,
 6029|  12.0k|      0x1820, 0x1821, 0x1822, 0x1823, 0x1824, 0x1825, 0x1826, 0x1827, 0x1828,
 6030|  12.0k|      0x1829, 0x182a, 0x182b, 0x182c, 0x182d, 0x182e, 0x182f, 0x1830, 0x1831,
 6031|  12.0k|      0x1832, 0x1833, 0x1834, 0x1835, 0x1836, 0x1837, 0x1838, 0x1839, 0x183a,
 6032|  12.0k|      0x183b, 0x183c, 0x183d, 0x183e, 0x183f, 0x1840, 0x1841, 0x1842, 0x1843,
 6033|  12.0k|      0x1844, 0x1845, 0x1846, 0x1847, 0x1848, 0x1849, 0x184a, 0x184b, 0x184c,
 6034|  12.0k|      0x184d, 0x184e, 0x184f, 0x1850, 0x1851, 0x1852, 0x1853, 0x1854, 0x1855,
 6035|  12.0k|      0x1856, 0x1857, 0x1858, 0x1859, 0x185a, 0x185b, 0x185c, 0x185d, 0x185e,
 6036|  12.0k|      0x185f, 0x1860, 0x1861, 0x1862, 0x1863, 0x1864, 0x1865, 0x1866, 0x1867,
 6037|  12.0k|      0x1868, 0x1869, 0x186a, 0x186b, 0x186c, 0x186d, 0x186e, 0x186f, 0x1870,
 6038|  12.0k|      0x1871, 0x1872, 0x1873, 0x1874, 0x1875, 0x1876, 0x1877, 0x1887, 0x1888,
 6039|  12.0k|      0x1889, 0x188a, 0x188b, 0x188c, 0x188d, 0x188e, 0x188f, 0x1890, 0x1891,
 6040|  12.0k|      0x1892, 0x1893, 0x1894, 0x1895, 0x1896, 0x1897, 0x1898, 0x1899, 0x189a,
 6041|  12.0k|      0x189b, 0x189c, 0x189d, 0x189e, 0x189f, 0x18a0, 0x18a1, 0x18a2, 0x18a3,
 6042|  12.0k|      0x18a4, 0x18a5, 0x18a6, 0x18a7, 0x18a8, 0x18aa, 0xa840, 0xa841, 0xa842,
 6043|  12.0k|      0xa843, 0xa844, 0xa845, 0xa846, 0xa847, 0xa848, 0xa849, 0xa84a, 0xa84b,
 6044|  12.0k|      0xa84c, 0xa84d, 0xa84e, 0xa84f, 0xa850, 0xa851, 0xa852, 0xa853, 0xa854,
 6045|  12.0k|      0xa855, 0xa856, 0xa857, 0xa858, 0xa859, 0xa85a, 0xa85b, 0xa85c, 0xa85d,
 6046|  12.0k|      0xa85e, 0xa85f, 0xa860, 0xa861, 0xa862, 0xa863, 0xa864, 0xa865, 0xa866,
 6047|  12.0k|      0xa867, 0xa868, 0xa869, 0xa86a, 0xa86b, 0xa86c, 0xa86d, 0xa86e, 0xa86f,
 6048|  12.0k|      0xa870, 0xa871};
 6049|       |
 6050|   111k|  for (size_t i = 0; i < label.size(); i++) {
  ------------------
  |  Branch (6050:22): [True: 101k, False: 9.74k]
  ------------------
 6051|   101k|    uint32_t c = label[i];
 6052|   101k|    if (c == 0x200c) {
  ------------------
  |  Branch (6052:9): [True: 1.58k, False: 99.7k]
  ------------------
 6053|  1.58k|      if (i > 0) {
  ------------------
  |  Branch (6053:11): [True: 1.43k, False: 151]
  ------------------
 6054|  1.43k|        if (std::ranges::binary_search(virama, label[i - 1])) {
  ------------------
  |  Branch (6054:13): [True: 70, False: 1.36k]
  ------------------
 6055|     70|          return true;
 6056|     70|        }
 6057|  1.43k|      }
 6058|  1.51k|      if ((i == 0) || (i + 1 >= label.size())) {
  ------------------
  |  Branch (6058:11): [True: 151, False: 1.36k]
  |  Branch (6058:23): [True: 447, False: 913]
  ------------------
 6059|    598|        return false;
 6060|    598|      }
 6061|       |      // we go backward looking for L or D
 6062|    913|      auto is_l_or_d = [](uint32_t code) {
 6063|    913|        return std::ranges::binary_search(L, code) ||
 6064|    913|               std::ranges::binary_search(D, code);
 6065|    913|      };
 6066|    913|      auto is_r_or_d = [](uint32_t code) {
 6067|    913|        return std::ranges::binary_search(R, code) ||
 6068|    913|               std::ranges::binary_search(D, code);
 6069|    913|      };
 6070|    913|      std::u32string_view before = label.substr(0, i);
 6071|    913|      std::u32string_view after = label.substr(i + 1);
 6072|    913|      return (std::find_if(before.begin(), before.end(), is_l_or_d) !=
  ------------------
  |  Branch (6072:14): [True: 773, False: 140]
  ------------------
 6073|    913|              before.end()) &&
 6074|    773|             (std::find_if(after.begin(), after.end(), is_r_or_d) !=
  ------------------
  |  Branch (6074:14): [True: 616, False: 157]
  ------------------
 6075|    773|              after.end());
 6076|  99.7k|    } else if (c == 0x200d) {
  ------------------
  |  Branch (6076:16): [True: 686, False: 99.0k]
  ------------------
 6077|    686|      if (i > 0) {
  ------------------
  |  Branch (6077:11): [True: 540, False: 146]
  ------------------
 6078|    540|        if (std::ranges::binary_search(virama, label[i - 1])) {
  ------------------
  |  Branch (6078:13): [True: 100, False: 440]
  ------------------
 6079|    100|          return true;
 6080|    100|        }
 6081|    540|      }
 6082|    586|      return false;
 6083|    686|    }
 6084|   101k|  }
 6085|       |
 6086|       |  // If CheckBidi, and if the domain name is a  Bidi domain name, then the label
 6087|       |  // must satisfy all six of the numbered conditions in [IDNA2008] RFC 5893,
 6088|       |  // Section 2.
 6089|       |
 6090|       |  // The following rule, consisting of six conditions, applies to labels
 6091|       |  // in Bidi domain names.  The requirements that this rule satisfies are
 6092|       |  // described in Section 3.  All of the conditions must be satisfied for
 6093|       |  // the rule to be satisfied.
 6094|       |  //
 6095|       |  //  1.  The first character must be a character with Bidi property L, R,
 6096|       |  //     or AL.  If it has the R or AL property, it is an RTL label; if it
 6097|       |  //     has the L property, it is an LTR label.
 6098|       |  //
 6099|       |  //  2.  In an RTL label, only characters with the Bidi properties R, AL,
 6100|       |  //      AN, EN, ES, CS, ET, ON, BN, or NSM are allowed.
 6101|       |  //
 6102|       |  //   3.  In an RTL label, the end of the label must be a character with
 6103|       |  //       Bidi property R, AL, EN, or AN, followed by zero or more
 6104|       |  //       characters with Bidi property NSM.
 6105|       |  //
 6106|       |  //   4.  In an RTL label, if an EN is present, no AN may be present, and
 6107|       |  //       vice versa.
 6108|       |  //
 6109|       |  //  5.  In an LTR label, only characters with the Bidi properties L, EN,
 6110|       |  //       ES, CS, ET, ON, BN, or NSM are allowed.
 6111|       |  //
 6112|       |  //   6.  In an LTR label, the end of the label must be a character with
 6113|       |  //       Bidi property L or EN, followed by zero or more characters with
 6114|       |  //       Bidi property NSM.
 6115|       |
 6116|  9.74k|  size_t last_non_nsm_char = find_last_not_of_nsm(label);
 6117|  9.74k|  if (last_non_nsm_char == std::u32string_view::npos) {
  ------------------
  |  Branch (6117:7): [True: 0, False: 9.74k]
  ------------------
 6118|      0|    return false;
 6119|      0|  }
 6120|       |
 6121|       |  // A "Bidi domain name" is a domain name that contains at least one RTL label.
 6122|       |  // The following rule, consisting of six conditions, applies to labels in Bidi
 6123|       |  // domain names.
 6124|  9.74k|  if (is_rtl_label(label)) {
  ------------------
  |  Branch (6124:7): [True: 2.99k, False: 6.75k]
  ------------------
 6125|       |    // The first character must be a character with Bidi property L, R,
 6126|       |    // or AL. If it has the R or AL property, it is an RTL label; if it
 6127|       |    // has the L property, it is an LTR label.
 6128|       |
 6129|  2.99k|    if (find_direction(label[0]) == direction::L) {
  ------------------
  |  Branch (6129:9): [True: 419, False: 2.57k]
  ------------------
 6130|       |      // Eval as LTR
 6131|       |
 6132|       |      // In an LTR label, only characters with the Bidi properties L, EN,
 6133|       |      // ES, CS, ET, ON, BN, or NSM are allowed.
 6134|  3.26k|      for (size_t i = 0; i <= last_non_nsm_char; i++) {
  ------------------
  |  Branch (6134:26): [True: 3.26k, False: 0]
  ------------------
 6135|  3.26k|        const direction d = find_direction(label[i]);
 6136|  3.26k|        if (!(d == direction::L || d == direction::EN || d == direction::ES ||
  ------------------
  |  Branch (6136:15): [True: 947, False: 2.32k]
  |  Branch (6136:36): [True: 245, False: 2.07k]
  |  Branch (6136:58): [True: 236, False: 1.84k]
  ------------------
 6137|  1.84k|              d == direction::CS || d == direction::ET || d == direction::ON ||
  ------------------
  |  Branch (6137:15): [True: 203, False: 1.63k]
  |  Branch (6137:37): [True: 335, False: 1.30k]
  |  Branch (6137:59): [True: 278, False: 1.02k]
  ------------------
 6138|  1.02k|              d == direction::BN || d == direction::NSM)) {
  ------------------
  |  Branch (6138:15): [True: 244, False: 780]
  |  Branch (6138:37): [True: 361, False: 419]
  ------------------
 6139|    419|          return false;
 6140|    419|        }
 6141|  3.26k|      }
 6142|       |
 6143|      0|      const direction last_dir = find_direction(label[last_non_nsm_char]);
 6144|      0|      if (!(last_dir == direction::L || last_dir == direction::EN)) {
  ------------------
  |  Branch (6144:13): [True: 0, False: 0]
  |  Branch (6144:41): [True: 0, False: 0]
  ------------------
 6145|      0|        return false;
 6146|      0|      }
 6147|       |
 6148|      0|      return true;
 6149|       |
 6150|  2.57k|    } else {
 6151|       |      // Eval as RTL
 6152|       |
 6153|       |      // The first character must be R or AL; a leading AN (or any other
 6154|       |      // direction) does not start a valid RTL label.
 6155|  2.57k|      const direction first_dir = find_direction(label[0]);
 6156|  2.57k|      if (first_dir != direction::R && first_dir != direction::AL) {
  ------------------
  |  Branch (6156:11): [True: 1.39k, False: 1.18k]
  |  Branch (6156:40): [True: 159, False: 1.23k]
  ------------------
 6157|    159|        return false;
 6158|    159|      }
 6159|       |
 6160|  2.41k|      bool has_an = false;
 6161|  2.41k|      bool has_en = false;
 6162|  10.2k|      for (size_t i = 0; i <= last_non_nsm_char; i++) {
  ------------------
  |  Branch (6162:26): [True: 8.35k, False: 1.86k]
  ------------------
 6163|  8.35k|        const direction d = find_direction(label[i]);
 6164|       |
 6165|       |        // In an RTL label, if an EN is present, no AN may be present, and vice
 6166|       |        // versa.
 6167|  8.35k|        if ((d == direction::EN && ((has_en = true) && has_an)) ||
  ------------------
  |  Branch (6167:14): [True: 646, False: 7.71k]
  |  Branch (6167:37): [True: 646, False: 0]
  |  Branch (6167:56): [True: 76, False: 570]
  ------------------
 6168|  8.28k|            (d == direction::AN && ((has_an = true) && has_en))) {
  ------------------
  |  Branch (6168:14): [True: 676, False: 7.60k]
  |  Branch (6168:37): [True: 676, False: 0]
  |  Branch (6168:56): [True: 71, False: 605]
  ------------------
 6169|    147|          return false;
 6170|    147|        }
 6171|       |
 6172|  8.21k|        if (!(d == direction::R || d == direction::AL || d == direction::AN ||
  ------------------
  |  Branch (6172:15): [True: 2.52k, False: 5.68k]
  |  Branch (6172:36): [True: 2.77k, False: 2.90k]
  |  Branch (6172:58): [True: 605, False: 2.30k]
  ------------------
 6173|  2.30k|              d == direction::EN || d == direction::ES || d == direction::CS ||
  ------------------
  |  Branch (6173:15): [True: 570, False: 1.73k]
  |  Branch (6173:37): [True: 213, False: 1.52k]
  |  Branch (6173:59): [True: 279, False: 1.24k]
  ------------------
 6174|  1.24k|              d == direction::ET || d == direction::ON || d == direction::BN ||
  ------------------
  |  Branch (6174:15): [True: 213, False: 1.02k]
  |  Branch (6174:37): [True: 296, False: 732]
  |  Branch (6174:59): [True: 208, False: 524]
  ------------------
 6175|    524|              d == direction::NSM)) {
  ------------------
  |  Branch (6175:15): [True: 253, False: 271]
  ------------------
 6176|    271|          return false;
 6177|    271|        }
 6178|       |
 6179|  7.94k|        if (i == last_non_nsm_char &&
  ------------------
  |  Branch (6179:13): [True: 1.99k, False: 5.94k]
  ------------------
 6180|  1.99k|            !(d == direction::R || d == direction::AL || d == direction::AN ||
  ------------------
  |  Branch (6180:15): [True: 692, False: 1.30k]
  |  Branch (6180:36): [True: 589, False: 715]
  |  Branch (6180:58): [True: 310, False: 405]
  ------------------
 6181|    405|              d == direction::EN)) {
  ------------------
  |  Branch (6181:15): [True: 278, False: 127]
  ------------------
 6182|    127|          return false;
 6183|    127|        }
 6184|  7.94k|      }
 6185|       |
 6186|  1.86k|      return true;
 6187|  2.41k|    }
 6188|  2.99k|  }
 6189|       |
 6190|  6.75k|  return true;
 6191|  9.74k|}
_ZN3ada4idna36contains_forbidden_domain_code_pointENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6318|  4.53k|bool contains_forbidden_domain_code_point(std::string_view view) {
 6319|  4.53k|  return std::ranges::any_of(view, is_forbidden_domain_code_point);
 6320|  4.53k|}
_ZN3ada4idna8to_asciiENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEERNS1_12basic_stringIcS4_NS1_9allocatorIcEEEE:
 6348|  11.8k|[[nodiscard]] bool to_ascii(std::string_view ut8_string, std::string& out) {
 6349|  11.8k|  out.clear();
 6350|  11.8k|  if (ut8_string.size() > max_domain_input_bytes) {
  ------------------
  |  Branch (6350:7): [True: 0, False: 11.8k]
  ------------------
 6351|      0|    return false;
 6352|      0|  }
 6353|  11.8k|  if (is_ascii(ut8_string)) {
  ------------------
  |  Branch (6353:7): [True: 8.84k, False: 2.98k]
  ------------------
 6354|  8.84k|    from_ascii_to_ascii(ut8_string, out);
 6355|  8.84k|    return true;
 6356|  8.84k|  }
 6357|       |
 6358|       |#ifdef ADA_USE_SIMDUTF
 6359|       |  size_t utf32_length =
 6360|       |      simdutf::utf32_length_from_utf8(ut8_string.data(), ut8_string.size());
 6361|       |  if (utf32_length == 0 && !ut8_string.empty()) {
 6362|       |    return false;
 6363|       |  }
 6364|       |  std::u32string working(utf32_length, U'\0');
 6365|       |  size_t actual_utf32_length = simdutf::convert_utf8_to_utf32(
 6366|       |      ut8_string.data(), ut8_string.size(), working.data());
 6367|       |#else
 6368|  2.98k|  size_t utf32_length =
 6369|  2.98k|      ada::idna::utf32_length_from_utf8(ut8_string.data(), ut8_string.size());
 6370|  2.98k|  if (utf32_length == 0 && !ut8_string.empty()) {
  ------------------
  |  Branch (6370:7): [True: 22, False: 2.96k]
  |  Branch (6370:28): [True: 22, False: 0]
  ------------------
 6371|     22|    return false;
 6372|     22|  }
 6373|  2.96k|  std::u32string working(utf32_length, U'\0');
 6374|  2.96k|  size_t actual_utf32_length = ada::idna::utf8_to_utf32(
 6375|  2.96k|      ut8_string.data(), ut8_string.size(), working.data());
 6376|  2.96k|#endif
 6377|  2.96k|  if (actual_utf32_length == 0 || actual_utf32_length != utf32_length) {
  ------------------
  |  Branch (6377:7): [True: 344, False: 2.62k]
  |  Branch (6377:35): [True: 0, False: 2.62k]
  ------------------
 6378|    344|    return false;
 6379|    344|  }
 6380|  2.62k|  working.resize(actual_utf32_length);
 6381|       |
 6382|       |  // Map into a second buffer with exact sizing (no growth reallocs).
 6383|  2.62k|  std::u32string mapped;
 6384|  2.62k|  if (!ada::idna::map(working, mapped)) {
  ------------------
  |  Branch (6384:7): [True: 274, False: 2.34k]
  ------------------
 6385|    274|    return false;
 6386|    274|  }
 6387|       |  // Drop UTF-32 input; reuse `working` as scratch for ACE validation below.
 6388|  2.34k|  working.clear();
 6389|       |
 6390|       |  // Skip NFC when already normalized (ASCII is a fast subset of this check).
 6391|  2.34k|  if (!is_ascii(mapped) && !is_already_nfc(mapped)) {
  ------------------
  |  Branch (6391:7): [True: 2.08k, False: 266]
  |  Branch (6391:28): [True: 268, False: 1.81k]
  ------------------
 6392|    268|    if (!normalize(mapped)) {
  ------------------
  |  Branch (6392:9): [True: 0, False: 268]
  ------------------
 6393|      0|      return false;
 6394|      0|    }
 6395|    268|  }
 6396|       |
 6397|       |  // Estimate ASCII output size (punycode may expand non-ASCII labels).
 6398|  2.34k|  out.reserve(mapped.size() + 8);
 6399|       |
 6400|       |  // Walk labels with a single pointer scan (no repeated string::find).
 6401|  2.34k|  const char32_t* p = mapped.data();
 6402|  2.34k|  const char32_t* const end = p + mapped.size();
 6403|  2.34k|  std::u32string post_map;
 6404|       |
 6405|  7.98k|  while (p < end) {
  ------------------
  |  Branch (6405:10): [True: 6.39k, False: 1.59k]
  ------------------
 6406|  6.39k|    const char32_t* label_begin = p;
 6407|   130k|    while (p < end && *p != U'.') {
  ------------------
  |  Branch (6407:12): [True: 127k, False: 2.22k]
  |  Branch (6407:23): [True: 123k, False: 4.16k]
  ------------------
 6408|   123k|      ++p;
 6409|   123k|    }
 6410|  6.39k|    const size_t label_size = static_cast<size_t>(p - label_begin);
 6411|  6.39k|    std::u32string_view label_view(label_begin, label_size);
 6412|  6.39k|    const bool is_last_label = (p == end);
 6413|  6.39k|    if (p < end) {
  ------------------
  |  Branch (6413:9): [True: 4.16k, False: 2.22k]
  ------------------
 6414|  4.16k|      ++p;  // skip dot
 6415|  4.16k|    }
 6416|       |
 6417|  6.39k|    if (label_size == 0) {
  ------------------
  |  Branch (6417:9): [True: 602, False: 5.79k]
  ------------------
 6418|       |      // empty label
 6419|  5.79k|    } else if (is_ace_prefix(label_view)) {
  ------------------
  |  Branch (6419:16): [True: 1.06k, False: 4.72k]
  ------------------
 6420|  11.4k|      for (char32_t c : label_view) {
  ------------------
  |  Branch (6420:23): [True: 11.4k, False: 1.04k]
  ------------------
 6421|  11.4k|        if (c >= 0x80) {
  ------------------
  |  Branch (6421:13): [True: 18, False: 11.4k]
  ------------------
 6422|     18|          out.clear();
 6423|     18|          return false;
 6424|     18|        }
 6425|  11.4k|      }
 6426|  1.04k|      append_ascii_label(out, label_view);
 6427|  1.04k|      std::string_view puny_segment_ascii(
 6428|  1.04k|          out.data() + (out.size() - label_size) + 4, label_size - 4);
 6429|  1.04k|      working.clear();
 6430|  1.04k|      if (!ada::idna::punycode_to_utf32(puny_segment_ascii, working)) {
  ------------------
  |  Branch (6430:11): [True: 13, False: 1.03k]
  ------------------
 6431|     13|        out.clear();
 6432|     13|        return false;
 6433|     13|      }
 6434|  1.03k|      if (is_ascii(working)) {
  ------------------
  |  Branch (6434:11): [True: 39, False: 991]
  ------------------
 6435|     39|        out.clear();
 6436|     39|        return false;
 6437|     39|      }
 6438|    991|      if (!ada::idna::map(working, post_map) || working != post_map) {
  ------------------
  |  Branch (6438:11): [True: 34, False: 957]
  |  Branch (6438:49): [True: 38, False: 919]
  ------------------
 6439|     72|        out.clear();
 6440|     72|        return false;
 6441|     72|      }
 6442|       |      // Mapping must be stable; NFC must not change the mapped form either.
 6443|    919|      if (!is_ascii(post_map) && !is_already_nfc(post_map)) {
  ------------------
  |  Branch (6443:11): [True: 919, False: 0]
  |  Branch (6443:34): [True: 240, False: 679]
  ------------------
 6444|    240|        if (!normalize(post_map) || post_map != working) {
  ------------------
  |  Branch (6444:13): [True: 0, False: 240]
  |  Branch (6444:37): [True: 44, False: 196]
  ------------------
 6445|     44|          out.clear();
 6446|     44|          return false;
 6447|     44|        }
 6448|    240|      }
 6449|    875|      if (post_map.empty() || !is_label_valid(post_map)) {
  ------------------
  |  Branch (6449:11): [True: 0, False: 875]
  |  Branch (6449:31): [True: 8, False: 867]
  ------------------
 6450|      8|        out.clear();
 6451|      8|        return false;
 6452|      8|      }
 6453|  4.72k|    } else if (is_ascii(label_view)) {
  ------------------
  |  Branch (6453:16): [True: 464, False: 4.26k]
  ------------------
 6454|    464|      append_ascii_label(out, label_view);
 6455|  4.26k|    } else {
 6456|  4.26k|      if (!is_label_valid(label_view)) {
  ------------------
  |  Branch (6456:11): [True: 564, False: 3.70k]
  ------------------
 6457|    564|        out.clear();
 6458|    564|        return false;
 6459|    564|      }
 6460|  3.70k|      out.append("xn--");
 6461|  3.70k|      if (!ada::idna::utf32_to_punycode(label_view, out)) {
  ------------------
  |  Branch (6461:11): [True: 0, False: 3.70k]
  ------------------
 6462|      0|        out.clear();
 6463|      0|        return false;
 6464|      0|      }
 6465|  3.70k|    }
 6466|  5.63k|    if (!is_last_label) {
  ------------------
  |  Branch (6466:9): [True: 4.11k, False: 1.51k]
  ------------------
 6467|  4.11k|      out.push_back('.');
 6468|  4.11k|    }
 6469|  5.63k|  }
 6470|  1.59k|  return true;
 6471|  2.34k|}
_ZN3ada4idna8to_asciiENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6473|  11.8k|std::string to_ascii(std::string_view ut8_string) {
 6474|  11.8k|  std::string out;
 6475|  11.8k|  if (!to_ascii(ut8_string, out)) {
  ------------------
  |  Branch (6475:7): [True: 1.39k, False: 10.4k]
  ------------------
 6476|  1.39k|    return {};
 6477|  1.39k|  }
 6478|  10.4k|  return out;
 6479|  11.8k|}
_ZN3ada4idna10to_unicodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEERNS1_12basic_stringIcS4_NS1_9allocatorIcEEEE:
 6547|  11.2k|[[nodiscard]] bool to_unicode(std::string_view input, std::string& output) {
 6548|  11.2k|  output.clear();
 6549|  11.2k|  if (input.size() > max_domain_input_bytes) {
  ------------------
  |  Branch (6549:7): [True: 0, False: 11.2k]
  ------------------
 6550|      0|    return false;
 6551|      0|  }
 6552|  11.2k|  output.reserve(input.size());
 6553|       |
 6554|  11.2k|  size_t label_start = 0;
 6555|  11.2k|  std::u32string tmp_buffer;
 6556|  11.2k|  std::u32string post_map;
 6557|  40.7k|  while (label_start < input.size()) {
  ------------------
  |  Branch (6557:10): [True: 29.4k, False: 11.2k]
  ------------------
 6558|  29.4k|    size_t loc_dot = input.find('.', label_start);
 6559|  29.4k|    bool is_last_label = (loc_dot == std::string_view::npos);
 6560|  29.4k|    size_t label_size =
 6561|  29.4k|        is_last_label ? input.size() - label_start : loc_dot - label_start;
  ------------------
  |  Branch (6561:9): [True: 10.6k, False: 18.7k]
  ------------------
 6562|  29.4k|    auto label_view = std::string_view(input.data() + label_start, label_size);
 6563|       |
 6564|  29.4k|    if (label_view.starts_with("xn--") && ada::idna::is_ascii(label_view)) {
  ------------------
  |  Branch (6564:9): [True: 13.9k, False: 15.4k]
  |  Branch (6564:43): [True: 13.5k, False: 324]
  ------------------
 6565|  13.5k|      label_view.remove_prefix(4);
 6566|  13.5k|      tmp_buffer.clear();
 6567|  13.5k|      if (ada::idna::punycode_to_utf32(label_view, tmp_buffer)) {
  ------------------
  |  Branch (6567:11): [True: 12.1k, False: 1.44k]
  ------------------
 6568|       |        // Per UTS #46, the decoded label must be re-validated. Reject decodings
 6569|       |        // that are pure ASCII (xn-- encoding of an ASCII-only label), or whose
 6570|       |        // mapping/normalization is not stable, or that fail label validity.
 6571|  12.1k|        bool accept_decoded = true;
 6572|  12.1k|        if (ada::idna::is_ascii(tmp_buffer)) {
  ------------------
  |  Branch (6572:13): [True: 1.34k, False: 10.8k]
  ------------------
 6573|  1.34k|          accept_decoded = false;
 6574|  10.8k|        } else {
 6575|  10.8k|          post_map.clear();
 6576|  10.8k|          if (!ada::idna::map(tmp_buffer, post_map) || post_map != tmp_buffer) {
  ------------------
  |  Branch (6576:15): [True: 1.08k, False: 9.71k]
  |  Branch (6576:56): [True: 750, False: 8.96k]
  ------------------
 6577|  1.83k|            accept_decoded = false;
 6578|  8.96k|          } else if (!ada::idna::normalize(post_map) ||
  ------------------
  |  Branch (6578:22): [True: 0, False: 8.96k]
  ------------------
 6579|  8.96k|                     post_map != tmp_buffer || post_map.empty() ||
  ------------------
  |  Branch (6579:22): [True: 2.30k, False: 6.65k]
  |  Branch (6579:48): [True: 0, False: 6.65k]
  ------------------
 6580|  6.65k|                     !ada::idna::is_label_valid(post_map)) {
  ------------------
  |  Branch (6580:22): [True: 2.19k, False: 4.46k]
  ------------------
 6581|  4.50k|            accept_decoded = false;
 6582|  4.50k|          }
 6583|  10.8k|        }
 6584|       |
 6585|  12.1k|        if (accept_decoded) {
  ------------------
  |  Branch (6585:13): [True: 4.46k, False: 7.69k]
  ------------------
 6586|       |#ifdef ADA_USE_SIMDUTF
 6587|       |          auto utf8_size = simdutf::utf8_length_from_utf32(tmp_buffer.data(),
 6588|       |                                                           tmp_buffer.size());
 6589|       |          size_t old_size = output.size();
 6590|       |          output.resize(old_size + utf8_size);
 6591|       |          size_t written = simdutf::convert_utf32_to_utf8(
 6592|       |              tmp_buffer.data(), tmp_buffer.size(), output.data() + old_size);
 6593|       |          if (written != utf8_size) {
 6594|       |            output.resize(old_size);
 6595|       |            output.append(
 6596|       |                std::string_view(input.data() + label_start, label_size));
 6597|       |          }
 6598|       |#else
 6599|  4.46k|          auto utf8_size = ada::idna::utf8_length_from_utf32(tmp_buffer.data(),
 6600|  4.46k|                                                             tmp_buffer.size());
 6601|  4.46k|          size_t old_size = output.size();
 6602|  4.46k|          output.resize(old_size + utf8_size);
 6603|  4.46k|          size_t written = ada::idna::utf32_to_utf8(
 6604|  4.46k|              tmp_buffer.data(), tmp_buffer.size(), output.data() + old_size);
 6605|  4.46k|          if (written != utf8_size) {
  ------------------
  |  Branch (6605:15): [True: 0, False: 4.46k]
  ------------------
 6606|      0|            output.resize(old_size);
 6607|      0|            output.append(
 6608|      0|                std::string_view(input.data() + label_start, label_size));
 6609|      0|          }
 6610|  4.46k|#endif
 6611|  7.69k|        } else {
 6612|       |          // ToUnicode never fails. If any step fails, return the original
 6613|       |          // input sequence for the label.
 6614|  7.69k|          output.append(
 6615|  7.69k|              std::string_view(input.data() + label_start, label_size));
 6616|  7.69k|        }
 6617|  12.1k|      } else {
 6618|  1.44k|        output.append(std::string_view(input.data() + label_start, label_size));
 6619|  1.44k|      }
 6620|  15.8k|    } else {
 6621|  15.8k|      output.append(label_view);
 6622|  15.8k|    }
 6623|       |
 6624|  29.4k|    if (!is_last_label) {
  ------------------
  |  Branch (6624:9): [True: 18.7k, False: 10.6k]
  ------------------
 6625|  18.7k|      output.push_back('.');
 6626|  18.7k|    }
 6627|       |
 6628|  29.4k|    label_start += label_size + 1;
 6629|  29.4k|  }
 6630|       |
 6631|  11.2k|  return true;
 6632|  11.2k|}
_ZN3ada4idna10to_unicodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6634|  11.2k|std::string to_unicode(std::string_view input) {
 6635|  11.2k|  std::string output;
 6636|  11.2k|  if (!to_unicode(input, output)) {
  ------------------
  |  Branch (6636:7): [True: 0, False: 11.2k]
  ------------------
 6637|       |    // Over-limit input: return original (ToUnicode never fails in the sense of
 6638|       |    // producing no answer for valid-length inputs).
 6639|      0|    return std::string(input);
 6640|      0|  }
 6641|  11.2k|  return output;
 6642|  11.2k|}
idna.cc:_ZZN3ada4idna22utf32_length_from_utf8EPKcmENK3$_0clEa:
  284|   406k|  return std::count_if(p, std::next(p, len), [](int8_t c) {
  285|       |    // -65 is 0b10111111, anything larger in two-complement's
  286|       |    // should start a new code point.
  287|   406k|    return c > -65;
  288|   406k|  });
_ZN3ada4idna7deflate22make_fixed_litlen_huffEv:
  490|      2|inline Huff make_fixed_litlen_huff() {
  491|      2|  Huff h;
  492|      2|  uint8_t lens[288];
  493|       |  // Fixed Huffman: 0-143:8, 144-255:9, 256-279:7, 280-287:8
  494|    290|  for (int i = 0; i <= 143; i++) lens[i] = 8;
  ------------------
  |  Branch (494:19): [True: 288, False: 2]
  ------------------
  495|    226|  for (int i = 144; i <= 255; i++) lens[i] = 9;
  ------------------
  |  Branch (495:21): [True: 224, False: 2]
  ------------------
  496|     50|  for (int i = 256; i <= 279; i++) lens[i] = 7;
  ------------------
  |  Branch (496:21): [True: 48, False: 2]
  ------------------
  497|     18|  for (int i = 280; i <= 287; i++) lens[i] = 8;
  ------------------
  |  Branch (497:21): [True: 16, False: 2]
  ------------------
  498|      2|  h.build(lens, 288);
  499|      2|  return h;
  500|      2|}
_ZN3ada4idna7deflate4Huff5buildEPKhi:
  439|     16|  bool build(const uint8_t* lens, int n) {
  440|     16|    std::memset(counts, 0, sizeof(counts));
  441|     16|    std::memset(first_code, 0, sizeof(first_code));
  442|     16|    std::memset(base_idx, 0, sizeof(base_idx));
  443|     16|    nsymbols = n;
  444|     16|    max_bits = 0;
  445|  1.98k|    for (int i = 0; i < n; i++) {
  ------------------
  |  Branch (445:21): [True: 1.96k, False: 16]
  ------------------
  446|  1.96k|      lengths[i] = lens[i];
  447|  1.96k|      if (lens[i]) {
  ------------------
  |  Branch (447:11): [True: 1.91k, False: 49]
  ------------------
  448|  1.91k|        counts[lens[i]]++;
  449|  1.91k|        if (lens[i] > max_bits) max_bits = lens[i];
  ------------------
  |  Branch (449:13): [True: 46, False: 1.87k]
  ------------------
  450|  1.91k|      }
  451|  1.96k|    }
  452|       |    // Canonical first code for each bit length (RFC 1951).
  453|     16|    int code = 0;
  454|    256|    for (int bits = 1; bits <= MAXBITS; bits++) {
  ------------------
  |  Branch (454:24): [True: 240, False: 16]
  ------------------
  455|    240|      code = (code + counts[bits - 1]) << 1;
  456|    240|      first_code[bits] = code;
  457|    240|    }
  458|     16|    int idx = 0;
  459|    158|    for (int bits = 1; bits <= max_bits; bits++) {
  ------------------
  |  Branch (459:24): [True: 142, False: 16]
  ------------------
  460|    142|      base_idx[bits] = idx;
  461|       |      // assign symbols in symbol order for codes of this length
  462|  21.6k|      for (int sym = 0; sym < n; sym++) {
  ------------------
  |  Branch (462:25): [True: 21.5k, False: 142]
  ------------------
  463|  21.5k|        if (lengths[sym] == bits) {
  ------------------
  |  Branch (463:13): [True: 1.91k, False: 19.6k]
  ------------------
  464|  1.91k|          symbols[idx++] = static_cast<int16_t>(sym);
  465|  1.91k|        }
  466|  21.5k|      }
  467|    142|    }
  468|     16|    return true;
  469|     16|  }
_ZN3ada4idna7deflate20make_fixed_dist_huffEv:
  502|      2|inline Huff make_fixed_dist_huff() {
  503|      2|  Huff h;
  504|      2|  uint8_t lens[32];
  505|     66|  for (int i = 0; i < 32; i++) lens[i] = 5;
  ------------------
  |  Branch (505:19): [True: 64, False: 2]
  ------------------
  506|      2|  h.build(lens, 32);
  507|      2|  return h;
  508|      2|}
idna.cc:_ZZN3ada4idna9ascii_mapEPcmENK3$_0clEh:
 5134|  40.1k|  auto broadcast = [](uint8_t v) -> uint64_t {
 5135|  40.1k|    return 0x101010101010101ull * v;
 5136|  40.1k|  };
_ZN3ada4idna13ensure_tablesEv:
 4885|  43.7k|[[nodiscard]] inline bool ensure_tables() noexcept {
 4886|  43.7k|  uint8_t state = tables_init_state.load(std::memory_order_acquire);
 4887|  43.7k|  if (state == kTablesReady) {
  ------------------
  |  Branch (4887:7): [True: 43.7k, False: 1]
  ------------------
 4888|  43.7k|    return true;
 4889|  43.7k|  }
 4890|      1|  if (state == kTablesFailed) {
  ------------------
  |  Branch (4890:7): [True: 0, False: 1]
  ------------------
 4891|      0|    return false;
 4892|      0|  }
 4893|       |
 4894|      1|  uint8_t expected = kTablesUninit;
 4895|      1|  if (tables_init_state.compare_exchange_strong(expected, kTablesInProgress,
  ------------------
  |  Branch (4895:7): [True: 1, False: 0]
  ------------------
 4896|      1|                                                std::memory_order_acq_rel,
 4897|      1|                                                std::memory_order_acquire)) {
 4898|      1|    uint8_t* buffer = new (std::nothrow) uint8_t[table_blob::uncompressed_size];
 4899|      1|    if (buffer == nullptr) {
  ------------------
  |  Branch (4899:9): [True: 0, False: 1]
  ------------------
 4900|      0|      tables_init_state.store(kTablesFailed, std::memory_order_release);
 4901|      0|      return false;
 4902|      0|    }
 4903|       |
 4904|      1|    const size_t n = deflate::inflate_raw(table_blob::compressed,
 4905|      1|                                          table_blob::compressed_size, buffer,
 4906|      1|                                          table_blob::uncompressed_size);
 4907|      1|    if (n != table_blob::uncompressed_size ||
  ------------------
  |  Branch (4907:9): [True: 0, False: 1]
  ------------------
 4908|      1|        crc32_ieee(buffer, n) != table_blob::uncompressed_crc32) {
  ------------------
  |  Branch (4908:9): [True: 0, False: 1]
  ------------------
 4909|      0|      delete[] buffer;
 4910|      0|      tables_init_state.store(kTablesFailed, std::memory_order_release);
 4911|      0|      return false;
 4912|      0|    }
 4913|       |
 4914|       |    // LE payload verified; convert multi-byte fields for big-endian hosts.
 4915|      1|    detail::convert_table_blob_to_host_endian(buffer);
 4916|       |
 4917|      1|    auto at = [&](size_t off) noexcept -> const uint8_t* {
 4918|      1|      return buffer + off;
 4919|      1|    };
 4920|       |
 4921|       |    // Publish all non-atomic pointers before READY. Waiters synchronize via
 4922|       |    // acquire on tables_init_state and then observe these writes.
 4923|      1|    idna_stage1 =
 4924|      1|        reinterpret_cast<const uint16_t*>(at(table_blob::off_idna_stage1));
 4925|      1|    idna_stage2 =
 4926|      1|        reinterpret_cast<const uint16_t*>(at(table_blob::off_idna_stage2));
 4927|      1|    idna_bool_blocks =
 4928|      1|        reinterpret_cast<const uint64_t*>(at(table_blob::off_idna_bool_blocks));
 4929|      1|    idna_utf8_mappings = at(table_blob::off_idna_utf8_mappings);
 4930|       |
 4931|      1|    decomposition_index = at(table_blob::off_decomposition_index);
 4932|      1|    decomposition_block_flat = reinterpret_cast<const uint16_t*>(
 4933|      1|        at(table_blob::off_decomposition_block));
 4934|      1|    decomposition_data = reinterpret_cast<const char32_t*>(
 4935|      1|        at(table_blob::off_decomposition_data));
 4936|      1|    ccc_index = at(table_blob::off_ccc_index);
 4937|      1|    ccc_block_flat = at(table_blob::off_ccc_block);
 4938|      1|    composition_index = at(table_blob::off_composition_index);
 4939|      1|    composition_block_flat = reinterpret_cast<const uint16_t*>(
 4940|      1|        at(table_blob::off_composition_block));
 4941|      1|    composition_data =
 4942|      1|        reinterpret_cast<const char32_t*>(at(table_blob::off_composition_data));
 4943|       |
 4944|      1|    id_continue =
 4945|      1|        reinterpret_cast<range_pair_ptr>(at(table_blob::off_id_continue_flat));
 4946|      1|    id_start =
 4947|      1|        reinterpret_cast<range_pair_ptr>(at(table_blob::off_id_start_flat));
 4948|       |
 4949|      1|    dir_start =
 4950|      1|        reinterpret_cast<const uint32_t*>(at(table_blob::off_dir_start));
 4951|      1|    dir_final =
 4952|      1|        reinterpret_cast<const uint32_t*>(at(table_blob::off_dir_final));
 4953|      1|    dir_value = at(table_blob::off_dir_value);
 4954|      1|    combining_ranges =
 4955|      1|        reinterpret_cast<range_pair_ptr>(at(table_blob::off_combining_flat));
 4956|       |
 4957|      1|    tables_buffer = buffer;
 4958|      1|    tables_init_state.store(kTablesReady, std::memory_order_release);
 4959|      1|    return true;
 4960|      1|  }
 4961|       |
 4962|       |  // Another thread owns init (or finished between our loads).
 4963|      0|  for (uint64_t spins = 0; spins < kTablesSpinLimit; ++spins) {
  ------------------
  |  Branch (4963:28): [True: 0, False: 0]
  ------------------
 4964|      0|    state = tables_init_state.load(std::memory_order_acquire);
 4965|      0|    if (state == kTablesReady) {
  ------------------
  |  Branch (4965:9): [True: 0, False: 0]
  ------------------
 4966|      0|      return true;
 4967|      0|    }
 4968|      0|    if (state == kTablesFailed) {
  ------------------
  |  Branch (4968:9): [True: 0, False: 0]
  ------------------
 4969|      0|      return false;
 4970|      0|    }
 4971|      0|#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || \
 4972|      0|    defined(_M_IX86)
 4973|      0|#if defined(__GNUC__) || defined(__clang__)
 4974|      0|    __builtin_ia32_pause();
 4975|      0|#endif
 4976|       |#elif defined(__aarch64__) || defined(_M_ARM64)
 4977|       |#if defined(__GNUC__) || defined(__clang__)
 4978|       |    asm volatile("yield" ::: "memory");
 4979|       |#endif
 4980|       |#endif
 4981|      0|  }
 4982|       |  // Timed out waiting for a peer - treat as failure rather than hang.
 4983|      0|  return false;
 4984|      0|}
_ZN3ada4idna7deflate11inflate_rawEPKhmPhm:
  535|      1|                          size_t dst_cap) {
  536|      1|  BitReader br(src, src_len);
  537|      1|  size_t out = 0;
  538|      4|  for (;;) {
  539|      4|    uint32_t bfinal = br.get(1);
  540|      4|    uint32_t btype = br.get(2);
  541|      4|    if (bfinal == UINT32_MAX || btype == UINT32_MAX) return 0;
  ------------------
  |  Branch (541:9): [True: 0, False: 4]
  |  Branch (541:33): [True: 0, False: 4]
  ------------------
  542|      4|    if (btype == 0) {
  ------------------
  |  Branch (542:9): [True: 0, False: 4]
  ------------------
  543|       |      // stored
  544|      0|      br.align_byte();
  545|      0|      if (!br.ensure(16)) return 0;
  ------------------
  |  Branch (545:11): [True: 0, False: 0]
  ------------------
  546|       |      // read 16+16 from bit buffer awkwardly - use byte path
  547|       |      // Align: bits is multiple of 8
  548|       |      // Get len from remaining bits then bytes
  549|      0|      uint32_t len = br.get(16);
  550|      0|      uint32_t nlen = br.get(16);
  551|      0|      if (len == UINT32_MAX || nlen == UINT32_MAX) return 0;
  ------------------
  |  Branch (551:11): [True: 0, False: 0]
  |  Branch (551:32): [True: 0, False: 0]
  ------------------
  552|      0|      if ((len ^ 0xFFFF) != nlen) return 0;
  ------------------
  |  Branch (552:11): [True: 0, False: 0]
  ------------------
  553|       |      // After get, may have bits in acc from previous - for stored, should be
  554|       |      // byte aligned Copy len bytes from p
  555|      0|      if (br.bits != 0) {
  ------------------
  |  Branch (555:11): [True: 0, False: 0]
  ------------------
  556|       |        // leftover bits should be 0 if aligned
  557|      0|      }
  558|      0|      if (size_t(br.end - br.p) < len) return 0;
  ------------------
  |  Branch (558:11): [True: 0, False: 0]
  ------------------
  559|      0|      if (out + len > dst_cap) return 0;
  ------------------
  |  Branch (559:11): [True: 0, False: 0]
  ------------------
  560|      0|      std::memcpy(dst + out, br.p, len);
  561|      0|      br.p += len;
  562|      0|      out += len;
  563|      4|    } else if (btype == 1 || btype == 2) {
  ------------------
  |  Branch (563:16): [True: 0, False: 4]
  |  Branch (563:30): [True: 4, False: 0]
  ------------------
  564|      4|      Huff lit, dist;
  565|      4|      if (btype == 1) {
  ------------------
  |  Branch (565:11): [True: 0, False: 4]
  ------------------
  566|       |        // use fixed via functions
  567|      4|      } else {
  568|       |        // dynamic
  569|      4|        uint32_t hlit = br.get(5);
  570|      4|        if (hlit == UINT32_MAX) return 0;
  ------------------
  |  Branch (570:13): [True: 0, False: 4]
  ------------------
  571|      4|        hlit += 257;
  572|      4|        uint32_t hdist = br.get(5);
  573|      4|        if (hdist == UINT32_MAX) return 0;
  ------------------
  |  Branch (573:13): [True: 0, False: 4]
  ------------------
  574|      4|        hdist += 1;
  575|      4|        uint32_t hclen = br.get(4);
  576|      4|        if (hclen == UINT32_MAX) return 0;
  ------------------
  |  Branch (576:13): [True: 0, False: 4]
  ------------------
  577|      4|        hclen += 4;
  578|      4|        static const int order[19] = {16, 17, 18, 0, 8,  7, 9,  6, 10, 5,
  579|      4|                                      11, 4,  12, 3, 13, 2, 14, 1, 15};
  580|      4|        uint8_t clen[19]{};
  581|     69|        for (uint32_t i = 0; i < hclen; i++) {
  ------------------
  |  Branch (581:30): [True: 65, False: 4]
  ------------------
  582|     65|          uint32_t v = br.get(3);
  583|     65|          if (v == UINT32_MAX) return 0;
  ------------------
  |  Branch (583:15): [True: 0, False: 65]
  ------------------
  584|     65|          clen[order[i]] = uint8_t(v);
  585|     65|        }
  586|      4|        Huff cl;
  587|      4|        if (!cl.build(clen, 19)) return 0;
  ------------------
  |  Branch (587:13): [True: 0, False: 4]
  ------------------
  588|      4|        uint8_t lens[288 + 32]{};
  589|      4|        uint32_t n = hlit + hdist;
  590|  1.09k|        for (uint32_t i = 0; i < n;) {
  ------------------
  |  Branch (590:30): [True: 1.08k, False: 4]
  ------------------
  591|  1.08k|          int sym = cl.decode(br);
  592|  1.08k|          if (sym < 0) return 0;
  ------------------
  |  Branch (592:15): [True: 0, False: 1.08k]
  ------------------
  593|  1.08k|          if (sym < 16) {
  ------------------
  |  Branch (593:15): [True: 1.03k, False: 49]
  ------------------
  594|  1.03k|            lens[i++] = uint8_t(sym);
  595|  1.03k|          } else if (sym == 16) {
  ------------------
  |  Branch (595:22): [True: 49, False: 0]
  ------------------
  596|     49|            uint32_t rep = br.get(2);
  597|     49|            if (rep == UINT32_MAX) return 0;
  ------------------
  |  Branch (597:17): [True: 0, False: 49]
  ------------------
  598|     49|            rep += 3;
  599|     49|            if (i == 0) return 0;
  ------------------
  |  Branch (599:17): [True: 0, False: 49]
  ------------------
  600|     49|            uint8_t v = lens[i - 1];
  601|    263|            while (rep--) lens[i++] = v;
  ------------------
  |  Branch (601:20): [True: 214, False: 49]
  ------------------
  602|     49|          } else if (sym == 17) {
  ------------------
  |  Branch (602:22): [True: 0, False: 0]
  ------------------
  603|      0|            uint32_t rep = br.get(3);
  604|      0|            if (rep == UINT32_MAX) return 0;
  ------------------
  |  Branch (604:17): [True: 0, False: 0]
  ------------------
  605|      0|            rep += 3;
  606|      0|            while (rep--) lens[i++] = 0;
  ------------------
  |  Branch (606:20): [True: 0, False: 0]
  ------------------
  607|      0|          } else if (sym == 18) {
  ------------------
  |  Branch (607:22): [True: 0, False: 0]
  ------------------
  608|      0|            uint32_t rep = br.get(7);
  609|      0|            if (rep == UINT32_MAX) return 0;
  ------------------
  |  Branch (609:17): [True: 0, False: 0]
  ------------------
  610|      0|            rep += 11;
  611|      0|            while (rep--) lens[i++] = 0;
  ------------------
  |  Branch (611:20): [True: 0, False: 0]
  ------------------
  612|      0|          } else
  613|      0|            return 0;
  614|  1.08k|        }
  615|      4|        if (!lit.build(lens, int(hlit))) return 0;
  ------------------
  |  Branch (615:13): [True: 0, False: 4]
  ------------------
  616|      4|        if (!dist.build(lens + hlit, int(hdist))) return 0;
  ------------------
  |  Branch (616:13): [True: 0, False: 4]
  ------------------
  617|      4|      }
  618|  52.2k|      for (;;) {
  619|  52.2k|        int sym;
  620|  52.2k|        if (btype == 1)
  ------------------
  |  Branch (620:13): [True: 0, False: 52.2k]
  ------------------
  621|      0|          sym = fixed_litlen(br);
  622|  52.2k|        else
  623|  52.2k|          sym = lit.decode(br);
  624|  52.2k|        if (sym < 0) return 0;
  ------------------
  |  Branch (624:13): [True: 0, False: 52.2k]
  ------------------
  625|  52.2k|        if (sym < 256) {
  ------------------
  |  Branch (625:13): [True: 37.2k, False: 14.9k]
  ------------------
  626|  37.2k|          if (out >= dst_cap) return 0;
  ------------------
  |  Branch (626:15): [True: 0, False: 37.2k]
  ------------------
  627|  37.2k|          dst[out++] = uint8_t(sym);
  628|  37.2k|        } else if (sym == 256) {
  ------------------
  |  Branch (628:20): [True: 4, False: 14.9k]
  ------------------
  629|      4|          break;
  630|  14.9k|        } else {
  631|  14.9k|          int len_code = sym - 257;
  632|  14.9k|          if (len_code < 0 || len_code > 28) return 0;
  ------------------
  |  Branch (632:15): [True: 0, False: 14.9k]
  |  Branch (632:31): [True: 0, False: 14.9k]
  ------------------
  633|  14.9k|          uint32_t extra = br.get(len_extra[len_code]);
  634|  14.9k|          if (len_extra[len_code] && extra == UINT32_MAX) return 0;
  ------------------
  |  Branch (634:15): [True: 2.03k, False: 12.9k]
  |  Branch (634:38): [True: 0, False: 2.03k]
  ------------------
  635|  14.9k|          uint32_t length =
  636|  14.9k|              len_base[len_code] + (len_extra[len_code] ? extra : 0);
  ------------------
  |  Branch (636:37): [True: 2.03k, False: 12.9k]
  ------------------
  637|  14.9k|          int dsym;
  638|  14.9k|          if (btype == 1)
  ------------------
  |  Branch (638:15): [True: 0, False: 14.9k]
  ------------------
  639|      0|            dsym = fixed_dist(br);
  640|  14.9k|          else
  641|  14.9k|            dsym = dist.decode(br);
  642|  14.9k|          if (dsym < 0 || dsym > 29) return 0;
  ------------------
  |  Branch (642:15): [True: 0, False: 14.9k]
  |  Branch (642:27): [True: 0, False: 14.9k]
  ------------------
  643|  14.9k|          uint32_t dextra = br.get(dist_extra[dsym]);
  644|  14.9k|          if (dist_extra[dsym] && dextra == UINT32_MAX) return 0;
  ------------------
  |  Branch (644:15): [True: 9.97k, False: 5.01k]
  |  Branch (644:35): [True: 0, False: 9.97k]
  ------------------
  645|  14.9k|          uint32_t distance = dist_base[dsym] + (dist_extra[dsym] ? dextra : 0);
  ------------------
  |  Branch (645:50): [True: 9.97k, False: 5.01k]
  ------------------
  646|  14.9k|          if (distance > out || out + length > dst_cap) return 0;
  ------------------
  |  Branch (646:15): [True: 0, False: 14.9k]
  |  Branch (646:33): [True: 0, False: 14.9k]
  ------------------
  647|   202k|          for (uint32_t k = 0; k < length; k++) {
  ------------------
  |  Branch (647:32): [True: 187k, False: 14.9k]
  ------------------
  648|   187k|            dst[out] = dst[out - distance];
  649|   187k|            out++;
  650|   187k|          }
  651|  14.9k|        }
  652|  52.2k|      }
  653|      4|    } else {
  654|      0|      return 0;  // reserved
  655|      0|    }
  656|      4|    if (bfinal) break;
  ------------------
  |  Branch (656:9): [True: 1, False: 3]
  ------------------
  657|      4|  }
  658|      1|  return out;
  659|      1|}
_ZN3ada4idna7deflate9BitReaderC2EPKhm:
  402|      1|      : p(data), end(data + len) {}
_ZN3ada4idna7deflate9BitReader3getEi:
  412|   457k|  uint32_t get(int n) {
  413|   457k|    if (!ensure(n)) return UINT32_MAX;
  ------------------
  |  Branch (413:9): [True: 0, False: 457k]
  ------------------
  414|   457k|    uint32_t v = acc & ((1u << n) - 1);
  415|   457k|    acc >>= n;
  416|   457k|    bits -= n;
  417|   457k|    return v;
  418|   457k|  }
_ZN3ada4idna7deflate9BitReader6ensureEi:
  404|   457k|  bool ensure(int n) {
  405|   520k|    while (bits < n) {
  ------------------
  |  Branch (405:12): [True: 62.3k, False: 457k]
  ------------------
  406|  62.3k|      if (p >= end) return false;
  ------------------
  |  Branch (406:11): [True: 0, False: 62.3k]
  ------------------
  407|  62.3k|      acc |= uint32_t(*p++) << bits;
  408|  62.3k|      bits += 8;
  409|  62.3k|    }
  410|   457k|    return true;
  411|   457k|  }
_ZNK3ada4idna7deflate4Huff6decodeERNS1_9BitReaderE:
  471|  68.3k|  int decode(BitReader& br) const {
  472|  68.3k|    if (max_bits == 0) return -1;
  ------------------
  |  Branch (472:9): [True: 0, False: 68.3k]
  ------------------
  473|  68.3k|    int code = 0;
  474|   427k|    for (int len = 1; len <= max_bits; len++) {
  ------------------
  |  Branch (474:23): [True: 427k, False: 0]
  ------------------
  475|   427k|      uint32_t b = br.get(1);
  476|   427k|      if (b == UINT32_MAX) return -1;
  ------------------
  |  Branch (476:11): [True: 0, False: 427k]
  ------------------
  477|   427k|      code = (code << 1) | int(b);
  478|   427k|      int first = first_code[len];
  479|   427k|      int cnt = counts[len];
  480|   427k|      if (cnt && code - first < cnt) {
  ------------------
  |  Branch (480:11): [True: 263k, False: 164k]
  |  Branch (480:18): [True: 68.3k, False: 195k]
  ------------------
  481|  68.3k|        return symbols[base_idx[len] + (code - first)];
  482|  68.3k|      }
  483|   427k|    }
  484|      0|    return -1;
  485|  68.3k|  }
_ZN3ada4idna10crc32_ieeeEPKhm:
 4868|      1|                                         size_t len) noexcept {
 4869|      1|  uint32_t c = 0xFFFFFFFFu;
 4870|   224k|  for (size_t i = 0; i < len; ++i) {
  ------------------
  |  Branch (4870:22): [True: 224k, False: 1]
  ------------------
 4871|   224k|    c ^= data[i];
 4872|  2.02M|    for (int k = 0; k < 8; ++k) {
  ------------------
  |  Branch (4872:21): [True: 1.79M, False: 224k]
  ------------------
 4873|  1.79M|      const uint32_t mask = 0u - (c & 1u);
 4874|  1.79M|      c = (c >> 1) ^ (0xEDB88320u & mask);
 4875|  1.79M|    }
 4876|   224k|  }
 4877|      1|  return ~c;
 4878|      1|}
_ZN3ada4idna6detail33convert_table_blob_to_host_endianEPh:
 4691|      1|inline void convert_table_blob_to_host_endian(uint8_t* buffer) noexcept {
 4692|      1|  if constexpr (std::endian::native == std::endian::little) {
 4693|      1|    (void)buffer;
 4694|      1|    return;
 4695|      1|  }
 4696|      0|  auto u16 = [&](size_t off, size_t count) {
 4697|      1|    bswap_inplace(reinterpret_cast<uint16_t*>(buffer + off), count);
 4698|      1|  };
 4699|      1|  auto u32 = [&](size_t off, size_t count) {
 4700|      1|    bswap_inplace(reinterpret_cast<uint32_t*>(buffer + off), count);
 4701|      1|  };
 4702|      1|  auto u64 = [&](size_t off, size_t count) {
 4703|      1|    bswap_inplace(reinterpret_cast<uint64_t*>(buffer + off), count);
 4704|      1|  };
 4705|       |
 4706|      1|  u16(table_blob::off_idna_stage1, table_blob::count_idna_stage1);
 4707|      1|  u16(table_blob::off_idna_stage2, table_blob::count_idna_stage2);
 4708|      1|  u64(table_blob::off_idna_bool_blocks, table_blob::count_idna_bool_blocks);
 4709|      1|  u16(table_blob::off_decomposition_block,
 4710|      1|      table_blob::count_decomposition_block);
 4711|      1|  u32(table_blob::off_decomposition_data, table_blob::count_decomposition_data);
 4712|      1|  u16(table_blob::off_composition_block, table_blob::count_composition_block);
 4713|      1|  u32(table_blob::off_composition_data, table_blob::count_composition_data);
 4714|      1|  u32(table_blob::off_id_continue_flat, table_blob::count_id_continue_flat);
 4715|      1|  u32(table_blob::off_id_start_flat, table_blob::count_id_start_flat);
 4716|      1|  u32(table_blob::off_dir_start, table_blob::count_dir_start);
 4717|      1|  u32(table_blob::off_dir_final, table_blob::count_dir_final);
 4718|      1|  u32(table_blob::off_combining_flat, table_blob::count_combining_flat);
 4719|      1|}
_ZZN3ada4idna13ensure_tablesEvENKUlmE_clEm:
 4917|     18|    auto at = [&](size_t off) noexcept -> const uint8_t* {
 4918|     18|      return buffer + off;
 4919|     18|    };
idna.cc:_ZN3ada4idnaL11idna_lookupEj:
 5072|   440k|static uint16_t idna_lookup(uint32_t cp) noexcept {
 5073|   440k|  if (cp < IDNA_LOW_RANGE_END) {
  ------------------
  |  Branch (5073:7): [True: 438k, False: 2.18k]
  ------------------
 5074|   438k|    uint16_t ref = idna_stage1[cp >> IDNA_BLOCK_BITS];
 5075|   438k|    if (ref & IDNA_BOOL_FLAG) {
  ------------------
  |  Branch (5075:9): [True: 183k, False: 255k]
  ------------------
 5076|   183k|      uint32_t bit_idx =
 5077|   183k|          static_cast<uint32_t>(ref & ~IDNA_BOOL_FLAG) * IDNA_BLOCK_SIZE +
 5078|   183k|          (cp & IDNA_BLOCK_MASK);
 5079|   183k|      bool is_valid = (idna_bool_blocks[bit_idx >> 6] >> (bit_idx & 63u)) & 1u;
 5080|   183k|      return is_valid ? IDNA_VALID : IDNA_DISALLOWED;
  ------------------
  |  Branch (5080:14): [True: 183k, False: 122]
  ------------------
 5081|   183k|    }
 5082|   255k|    return idna_stage2[ref + (cp & IDNA_BLOCK_MASK)];
 5083|   438k|  }
 5084|       |
 5085|  2.18k|  if (cp >= IDNA_HIGH_IGNORED_START && cp < IDNA_HIGH_IGNORED_END) {
  ------------------
  |  Branch (5085:7): [True: 2.04k, False: 138]
  |  Branch (5085:40): [True: 1.39k, False: 652]
  ------------------
 5086|  1.39k|    return IDNA_IGNORED;
 5087|  1.39k|  }
 5088|       |
 5089|    790|  return IDNA_DISALLOWED;
 5090|  2.18k|}
idna.cc:_ZN3ada4idnaL21utf8_count_codepointsEPKh:
 5115|  30.5k|static size_t utf8_count_codepoints(const uint8_t* ptr) noexcept {
 5116|  30.5k|  size_t n = 0;
 5117|   361k|  while (*ptr != 0) {
  ------------------
  |  Branch (5117:10): [True: 331k, False: 30.5k]
  ------------------
 5118|   331k|    ++n;
 5119|   331k|    if (*ptr < 0x80u) {
  ------------------
  |  Branch (5119:9): [True: 63.4k, False: 267k]
  ------------------
 5120|  63.4k|      ++ptr;
 5121|   267k|    } else if (*ptr < 0xE0u) {
  ------------------
  |  Branch (5121:16): [True: 257k, False: 10.2k]
  ------------------
 5122|   257k|      ptr += 2;
 5123|   257k|    } else if (*ptr < 0xF0u) {
  ------------------
  |  Branch (5123:16): [True: 9.78k, False: 426]
  ------------------
 5124|  9.78k|      ptr += 3;
 5125|  9.78k|    } else {
 5126|    426|      ptr += 4;
 5127|    426|    }
 5128|   331k|  }
 5129|  30.5k|  return n;
 5130|  30.5k|}
idna.cc:_ZN3ada4idnaL9utf8_nextERPKh:
 5093|   331k|static char32_t utf8_next(const uint8_t*& ptr) noexcept {
 5094|   331k|  uint8_t b0 = *ptr++;
 5095|   331k|  if (b0 < 0x80u) return static_cast<char32_t>(b0);
  ------------------
  |  Branch (5095:7): [True: 63.4k, False: 267k]
  ------------------
 5096|   267k|  if (b0 < 0xE0u) {
  ------------------
  |  Branch (5096:7): [True: 257k, False: 10.1k]
  ------------------
 5097|   257k|    uint32_t cp = (b0 & 0x1Fu) << 6;
 5098|   257k|    cp |= (*ptr++ & 0x3Fu);
 5099|   257k|    return static_cast<char32_t>(cp);
 5100|   257k|  }
 5101|  10.1k|  if (b0 < 0xF0u) {
  ------------------
  |  Branch (5101:7): [True: 9.77k, False: 424]
  ------------------
 5102|  9.77k|    uint32_t cp = (b0 & 0x0Fu) << 12;
 5103|  9.77k|    cp |= ((*ptr++ & 0x3Fu) << 6);
 5104|  9.77k|    cp |= (*ptr++ & 0x3Fu);
 5105|  9.77k|    return static_cast<char32_t>(cp);
 5106|  9.77k|  }
 5107|    424|  uint32_t cp = (b0 & 0x07u) << 18;
 5108|    424|  cp |= ((*ptr++ & 0x3Fu) << 12);
 5109|    424|  cp |= ((*ptr++ & 0x3Fu) << 6);
 5110|    424|  cp |= (*ptr++ & 0x3Fu);
 5111|    424|  return static_cast<char32_t>(cp);
 5112|  10.1k|}
_ZN3ada4idna23decomposition_block_rowEh:
 4989|   357k|inline const uint16_t* decomposition_block_row(uint8_t bi) noexcept {
 4990|   357k|  if (bi >= kDecompBlockRows) {
  ------------------
  |  Branch (4990:7): [True: 0, False: 357k]
  ------------------
 4991|      0|    bi = 0;
 4992|      0|  }
 4993|   357k|  return decomposition_block_flat + static_cast<size_t>(bi) * kDecompBlockCols;
 4994|   357k|}
_ZN3ada4idna13ccc_block_rowEh:
 4996|   644k|inline const uint8_t* ccc_block_row(uint8_t bi) noexcept {
 4997|   644k|  if (bi >= kCccBlockRows) {
  ------------------
  |  Branch (4997:7): [True: 0, False: 644k]
  ------------------
 4998|      0|    bi = 0;
 4999|      0|  }
 5000|   644k|  return ccc_block_flat + static_cast<size_t>(bi) * kCccBlockCols;
 5001|   644k|}
_ZN3ada4idna16tables_are_readyEv:
 4880|  16.2k|[[nodiscard]] inline bool tables_are_ready() noexcept {
 4881|  16.2k|  return tables_init_state.load(std::memory_order_acquire) == kTablesReady;
 4882|  16.2k|}
idna.cc:_ZN3ada4idnaL23canonical_decomp_lengthEDi:
 5272|   312k|static size_t canonical_decomp_length(char32_t current_character) noexcept {
 5273|   312k|  if (current_character >= hangul_sbase &&
  ------------------
  |  Branch (5273:7): [True: 13.3k, False: 299k]
  ------------------
 5274|  13.3k|      current_character < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (5274:7): [True: 3.83k, False: 9.52k]
  ------------------
 5275|       |    // Hangul precomposed syllables are NFC.
 5276|  3.83k|    return 0;
 5277|  3.83k|  }
 5278|   308k|  if (current_character >= 0x110000) {
  ------------------
  |  Branch (5278:7): [True: 0, False: 308k]
  ------------------
 5279|      0|    return 0;
 5280|      0|  }
 5281|   308k|  const uint8_t di = decomposition_index[current_character >> 8];
 5282|   308k|  const uint16_t* const decomposition =
 5283|   308k|      decomposition_block_row(di) + (current_character % 256);
 5284|   308k|  size_t decomposition_length =
 5285|   308k|      (decomposition[1] >> 2) - (decomposition[0] >> 2);
 5286|   308k|  if ((decomposition_length > 0) && (decomposition[0] & 1)) {
  ------------------
  |  Branch (5286:7): [True: 12.4k, False: 296k]
  |  Branch (5286:37): [True: 7.28k, False: 5.16k]
  ------------------
 5287|  7.28k|    decomposition_length = 0;  // compatibility-only: ignored for NFC
 5288|  7.28k|  }
 5289|   308k|  return decomposition_length;
 5290|   308k|}
idna.cc:_ZN3ada4idnaL13would_composeENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5404|  14.2k|static bool would_compose(std::u32string_view input) noexcept {
 5405|   286k|  for (size_t input_count = 0; input_count < input.size();) {
  ------------------
  |  Branch (5405:32): [True: 274k, False: 12.0k]
  ------------------
 5406|   274k|    const char32_t current = input[input_count];
 5407|   274k|    if (current >= hangul_lbase && current < hangul_lbase + hangul_lcount) {
  ------------------
  |  Branch (5407:9): [True: 29.2k, False: 244k]
  |  Branch (5407:36): [True: 1.80k, False: 27.4k]
  ------------------
 5408|  1.80k|      if (input_count + 1 < input.size() &&
  ------------------
  |  Branch (5408:11): [True: 1.65k, False: 149]
  ------------------
 5409|  1.65k|          input[input_count + 1] >= hangul_vbase &&
  ------------------
  |  Branch (5409:11): [True: 701, False: 953]
  ------------------
 5410|    701|          input[input_count + 1] < hangul_vbase + hangul_vcount) {
  ------------------
  |  Branch (5410:11): [True: 391, False: 310]
  ------------------
 5411|    391|        return true;
 5412|    391|      }
 5413|  1.41k|      ++input_count;
 5414|  1.41k|      continue;
 5415|  1.80k|    }
 5416|   272k|    if (current >= hangul_sbase && current < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (5416:9): [True: 11.5k, False: 260k]
  |  Branch (5416:36): [True: 2.88k, False: 8.62k]
  ------------------
 5417|  2.88k|      if ((current - hangul_sbase) % hangul_tcount &&
  ------------------
  |  Branch (5417:11): [True: 2.34k, False: 540]
  ------------------
 5418|  2.34k|          input_count + 1 < input.size() &&
  ------------------
  |  Branch (5418:11): [True: 2.15k, False: 194]
  ------------------
 5419|  2.15k|          input[input_count + 1] > hangul_tbase &&
  ------------------
  |  Branch (5419:11): [True: 1.76k, False: 392]
  ------------------
 5420|  1.76k|          input[input_count + 1] < hangul_tbase + hangul_tcount) {
  ------------------
  |  Branch (5420:11): [True: 776, False: 987]
  ------------------
 5421|    776|        return true;
 5422|    776|      }
 5423|  2.11k|      ++input_count;
 5424|  2.11k|      continue;
 5425|  2.88k|    }
 5426|   269k|    if (current < 0x110000) {
  ------------------
  |  Branch (5426:9): [True: 269k, False: 0]
  ------------------
 5427|   269k|      const uint16_t* composition =
 5428|   269k|          composition_block_row(composition_index[current >> 8]) +
 5429|   269k|          (current % 256);
 5430|   269k|      int32_t previous_ccc = -1;
 5431|   269k|      size_t j = input_count;
 5432|   274k|      for (; j + 1 < input.size(); ++j) {
  ------------------
  |  Branch (5432:14): [True: 262k, False: 11.6k]
  ------------------
 5433|   262k|        uint8_t ccc = get_ccc(input[j + 1]);
 5434|   262k|        if (composition[1] != composition[0] && previous_ccc < ccc) {
  ------------------
  |  Branch (5434:13): [True: 71.2k, False: 191k]
  |  Branch (5434:49): [True: 70.3k, False: 946]
  ------------------
 5435|  70.3k|          int left = composition[0];
 5436|  70.3k|          int right = composition[1];
 5437|  70.3k|          if (left < 0 || right < left ||
  ------------------
  |  Branch (5437:15): [True: 0, False: 70.3k]
  |  Branch (5437:27): [True: 0, False: 70.3k]
  ------------------
 5438|  70.3k|              static_cast<size_t>(right) > composition_data_size) {
  ------------------
  |  Branch (5438:15): [True: 0, False: 70.3k]
  ------------------
 5439|      0|            break;
 5440|      0|          }
 5441|   185k|          while (left + 2 < right) {
  ------------------
  |  Branch (5441:18): [True: 115k, False: 70.3k]
  ------------------
 5442|   115k|            int middle = left + (((right - left) >> 1) & ~1);
 5443|   115k|            if (composition_data[static_cast<size_t>(middle)] <= input[j + 1]) {
  ------------------
  |  Branch (5443:17): [True: 5.28k, False: 110k]
  ------------------
 5444|  5.28k|              left = middle;
 5445|  5.28k|            }
 5446|   115k|            if (composition_data[static_cast<size_t>(middle)] >= input[j + 1]) {
  ------------------
  |  Branch (5446:17): [True: 110k, False: 4.94k]
  ------------------
 5447|   110k|              right = middle;
 5448|   110k|            }
 5449|   115k|          }
 5450|  70.3k|          if (static_cast<size_t>(left + 1) < composition_data_size &&
  ------------------
  |  Branch (5450:15): [True: 70.3k, False: 0]
  ------------------
 5451|  70.3k|              composition_data[static_cast<size_t>(left)] == input[j + 1]) {
  ------------------
  |  Branch (5451:15): [True: 1.07k, False: 69.2k]
  ------------------
 5452|  1.07k|            return true;
 5453|  1.07k|          }
 5454|  70.3k|        }
 5455|   261k|        if (ccc == 0) {
  ------------------
  |  Branch (5455:13): [True: 256k, False: 4.51k]
  ------------------
 5456|   256k|          break;
 5457|   256k|        }
 5458|  4.51k|        previous_ccc = ccc;
 5459|  4.51k|      }
 5460|   268k|      input_count = j + 1;
 5461|   268k|      continue;
 5462|   269k|    }
 5463|      0|    ++input_count;
 5464|      0|  }
 5465|  12.0k|  return false;
 5466|  14.2k|}
_ZN3ada4idna21composition_block_rowEh:
 5003|   296k|inline const uint16_t* composition_block_row(uint8_t bi) noexcept {
 5004|   296k|  if (bi >= kCompBlockRows) {
  ------------------
  |  Branch (5004:7): [True: 0, False: 296k]
  ------------------
 5005|      0|    bi = 0;
 5006|      0|  }
 5007|   296k|  return composition_block_flat + static_cast<size_t>(bi) * kCompBlockCols;
 5008|   296k|}
idna.cc:_ZN3ada4idnaL19char_to_digit_valueEc:
 5632|   189k|static constexpr int32_t char_to_digit_value(char value) {
 5633|   189k|  if (value >= 'a' && value <= 'z') return value - 'a';
  ------------------
  |  Branch (5633:7): [True: 152k, False: 36.7k]
  |  Branch (5633:23): [True: 152k, False: 244]
  ------------------
 5634|  37.0k|  if (value >= '0' && value <= '9') return value - '0' + 26;
  ------------------
  |  Branch (5634:7): [True: 31.8k, False: 5.11k]
  |  Branch (5634:23): [True: 30.6k, False: 1.26k]
  ------------------
 5635|  6.38k|  return -1;
 5636|  37.0k|}
idna.cc:_ZN3ada4idnaL5adaptEiib:
 5642|   202k|static constexpr int32_t adapt(int32_t d, int32_t n, bool firsttime) {
 5643|   202k|  if (firsttime) {
  ------------------
  |  Branch (5643:7): [True: 18.8k, False: 183k]
  ------------------
 5644|  18.8k|    d = d / damp;
 5645|   183k|  } else {
 5646|   183k|    d = d / 2;
 5647|   183k|  }
 5648|   202k|  d += d / n;
 5649|   202k|  int32_t k = 0;
 5650|   219k|  while (d > ((base - tmin) * tmax) / 2) {
  ------------------
  |  Branch (5650:10): [True: 16.7k, False: 202k]
  ------------------
 5651|  16.7k|    d /= base - tmin;
 5652|  16.7k|    k += base;
 5653|  16.7k|  }
 5654|   202k|  return k + (((base - tmin + 1) * d) / (d + skew));
 5655|   202k|}
idna.cc:_ZN3ada4idnaL13digit_to_charEi:
 5638|  95.6k|static constexpr char digit_to_char(int32_t digit) {
 5639|  95.6k|  return digit < 26 ? char(digit + 97) : char(digit + 22);
  ------------------
  |  Branch (5639:10): [True: 84.6k, False: 11.0k]
  ------------------
 5640|  95.6k|}
idna.cc:_ZZN3ada4idna14is_label_validENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEEENK3$_0clIA2_jEEDaRKT_:
 5977|   105k|      comb_span, label.front(), {}, [](const auto& range) { return range[1]; });
idna.cc:_ZZN3ada4idna14is_label_validENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEEENK3$_1clEj:
 6062|  1.88k|      auto is_l_or_d = [](uint32_t code) {
 6063|  1.88k|        return std::ranges::binary_search(L, code) ||
  ------------------
  |  Branch (6063:16): [True: 68, False: 1.81k]
  ------------------
 6064|  1.81k|               std::ranges::binary_search(D, code);
  ------------------
  |  Branch (6064:16): [True: 705, False: 1.10k]
  ------------------
 6065|  1.88k|      };
idna.cc:_ZZN3ada4idna14is_label_validENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEEENK3$_2clEj:
 6066|  1.89k|      auto is_r_or_d = [](uint32_t code) {
 6067|  1.89k|        return std::ranges::binary_search(R, code) ||
  ------------------
  |  Branch (6067:16): [True: 173, False: 1.71k]
  ------------------
 6068|  1.71k|               std::ranges::binary_search(D, code);
  ------------------
  |  Branch (6068:16): [True: 443, False: 1.27k]
  ------------------
 6069|  1.89k|      };
idna.cc:_ZN3ada4idnaL20find_last_not_of_nsmENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5924|  9.74k|    const std::u32string_view label) noexcept {
 5925|  12.4k|  for (int i = static_cast<int>(label.size() - 1); i >= 0; i--)
  ------------------
  |  Branch (5925:52): [True: 12.4k, False: 0]
  ------------------
 5926|  12.4k|    if (find_direction(label[i]) != direction::NSM) return i;
  ------------------
  |  Branch (5926:9): [True: 9.74k, False: 2.70k]
  ------------------
 5927|       |
 5928|      0|  return std::u32string_view::npos;
 5929|  9.74k|}
idna.cc:_ZN3ada4idnaL12is_rtl_labelENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 5933|  9.74k|inline static bool is_rtl_label(const std::u32string_view label) noexcept {
 5934|  9.74k|  const size_t mask =
 5935|  9.74k|      (1u << direction::R) | (1u << direction::AL) | (1u << direction::AN);
 5936|       |
 5937|  9.74k|  size_t directions = 0;
 5938|  73.1k|  for (size_t i = 0; i < label.size(); i++) {
  ------------------
  |  Branch (5938:22): [True: 63.3k, False: 9.74k]
  ------------------
 5939|  63.3k|    directions |= 1u << find_direction(label[i]);
 5940|  63.3k|  }
 5941|  9.74k|  return (directions & mask) != 0;
 5942|  9.74k|}
idna.cc:_ZN3ada4idnaL14find_directionEj:
 5905|  92.9k|inline static direction find_direction(uint32_t code_point) noexcept {
 5906|       |  // Binary search on dir_final (sorted upper bounds).
 5907|  92.9k|  size_t lo = 0, hi = dir_table_count;
 5908|  1.07M|  while (lo < hi) {
  ------------------
  |  Branch (5908:10): [True: 979k, False: 92.9k]
  ------------------
 5909|   979k|    size_t mid = lo + (hi - lo) / 2;
 5910|   979k|    if (dir_final[mid] < code_point) {
  ------------------
  |  Branch (5910:9): [True: 378k, False: 601k]
  ------------------
 5911|   378k|      lo = mid + 1;
 5912|   601k|    } else {
 5913|   601k|      hi = mid;
 5914|   601k|    }
 5915|   979k|  }
 5916|  92.9k|  if (lo == dir_table_count) {
  ------------------
  |  Branch (5916:7): [True: 610, False: 92.3k]
  ------------------
 5917|    610|    return direction::NONE;
 5918|    610|  }
 5919|  92.3k|  return code_point >= dir_start[lo] ? static_cast<direction>(dir_value[lo])
  ------------------
  |  Branch (5919:10): [True: 90.4k, False: 1.93k]
  ------------------
 5920|  92.3k|                                     : direction::NONE;
 5921|  92.9k|}
_ZN3ada4idna30is_forbidden_domain_code_pointEc:
 6314|  48.2k|inline bool is_forbidden_domain_code_point(const char c) noexcept {
 6315|  48.2k|  return is_forbidden_domain_code_point_table[uint8_t(c)];
 6316|  48.2k|}
_ZN3ada4idna8is_asciiENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6290|  30.2k|bool constexpr is_ascii(std::string_view view) {
 6291|   522k|  for (uint8_t c : view) {
  ------------------
  |  Branch (6291:18): [True: 522k, False: 24.2k]
  ------------------
 6292|   522k|    if (c >= 0x80) {
  ------------------
  |  Branch (6292:9): [True: 6.01k, False: 516k]
  ------------------
 6293|  6.01k|      return false;
 6294|  6.01k|    }
 6295|   522k|  }
 6296|  24.2k|  return true;
 6297|  30.2k|}
idna.cc:_ZN3ada4idnaL19from_ascii_to_asciiENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEERNS1_12basic_stringIcS4_NS1_9allocatorIcEEEE:
 6327|  8.84k|static void from_ascii_to_ascii(std::string_view ut8_string, std::string& out) {
 6328|  8.84k|  out.assign(ut8_string);
 6329|  8.84k|  ascii_map(out.data(), out.size());
 6330|  8.84k|}
_ZN3ada4idna8is_asciiENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 6281|  21.1k|bool constexpr is_ascii(std::u32string_view view) {
 6282|  45.1k|  for (uint32_t c : view) {
  ------------------
  |  Branch (6282:19): [True: 45.1k, False: 2.11k]
  ------------------
 6283|  45.1k|    if (c >= 0x80) {
  ------------------
  |  Branch (6283:9): [True: 19.0k, False: 26.0k]
  ------------------
 6284|  19.0k|      return false;
 6285|  19.0k|    }
 6286|  45.1k|  }
 6287|  2.11k|  return true;
 6288|  21.1k|}
idna.cc:_ZN3ada4idnaL13is_ace_prefixENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 6343|  5.79k|static bool is_ace_prefix(std::u32string_view label) noexcept {
 6344|  5.79k|  return label.size() >= 4 && label[0] == U'x' && label[1] == U'n' &&
  ------------------
  |  Branch (6344:10): [True: 2.84k, False: 2.94k]
  |  Branch (6344:31): [True: 1.61k, False: 1.22k]
  |  Branch (6344:51): [True: 1.34k, False: 269]
  ------------------
 6345|  1.34k|         label[2] == U'-' && label[3] == U'-';
  ------------------
  |  Branch (6345:10): [True: 1.22k, False: 122]
  |  Branch (6345:30): [True: 1.06k, False: 160]
  ------------------
 6346|  5.79k|}
idna.cc:_ZN3ada4idnaL18append_ascii_labelERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS1_17basic_string_viewIDiNS3_IDiEEEE:
 6333|  1.50k|static void append_ascii_label(std::string& out, std::u32string_view label) {
 6334|  1.50k|  const size_t old = out.size();
 6335|  1.50k|  out.resize(old + label.size());
 6336|  1.50k|  char* dest = out.data() + old;
 6337|  12.7k|  for (char32_t c : label) {
  ------------------
  |  Branch (6337:19): [True: 12.7k, False: 1.50k]
  ------------------
 6338|  12.7k|    *dest++ = static_cast<char>(c);
 6339|  12.7k|  }
 6340|  1.50k|}
_ZN3ada8checkers17verify_dns_lengthENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
  112|  4.71k|    std::string_view input) noexcept {
  113|  4.71k|  if (input.empty()) return false;
  ------------------
  |  Branch (113:7): [True: 4.17k, False: 539]
  ------------------
  114|    539|  if (input.back() == '.') {
  ------------------
  |  Branch (114:7): [True: 90, False: 449]
  ------------------
  115|     90|    if (input.size() > 254) return false;
  ------------------
  |  Branch (115:9): [True: 7, False: 83]
  ------------------
  116|    449|  } else if (input.size() > 253)
  ------------------
  |  Branch (116:14): [True: 67, False: 382]
  ------------------
  117|     67|    return false;
  118|       |
  119|    465|  size_t start = 0;
  120|  1.86k|  while (start < input.size()) {
  ------------------
  |  Branch (120:10): [True: 1.47k, False: 388]
  ------------------
  121|  1.47k|    auto dot_location = input.find('.', start);
  122|       |    // If not found, it's likely the end of the domain
  123|  1.47k|    if (dot_location == std::string_view::npos) dot_location = input.size();
  ------------------
  |  Branch (123:9): [True: 367, False: 1.10k]
  ------------------
  124|       |
  125|  1.47k|    auto label_size = dot_location - start;
  126|  1.47k|    if (label_size > 63 || label_size == 0) return false;
  ------------------
  |  Branch (126:9): [True: 50, False: 1.42k]
  |  Branch (126:28): [True: 27, False: 1.39k]
  ------------------
  127|       |
  128|  1.39k|    start = dot_location + 1;
  129|  1.39k|  }
  130|       |
  131|    388|  return true;
  132|    465|}

_ZN3ada37url_pattern_compile_component_optionsC2ENSt3__18optionalIcEES3_:
 5632|      6|      : delimiter(new_delimiter), prefix(new_prefix) {}

LLVMFuzzerTestOneInput:
    9|  4.53k|extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
   10|  4.53k|  FuzzedDataProvider fdp(data, size);
   11|  4.53k|  std::string source = fdp.ConsumeRandomLengthString(256);
   12|  4.53k|  std::string source2 = fdp.ConsumeRandomLengthString(64);
   13|       |
   14|       |  /**
   15|       |   * High-level IDNA API
   16|       |   */
   17|  4.53k|  std::string ascii_result = ada::idna::to_ascii(source);
   18|  4.53k|  std::string unicode_result = ada::idna::to_unicode(source);
   19|       |
   20|       |  // Avoid dead-code elimination
   21|  4.53k|  volatile size_t length = 0;
   22|  4.53k|  length += ascii_result.size();
   23|  4.53k|  length += unicode_result.size();
   24|       |
   25|       |  /**
   26|       |   * Round-trip property: to_unicode(to_ascii(x)) should not crash.
   27|       |   * We don't assert equality because IDNA may normalize/reject inputs.
   28|       |   */
   29|  4.53k|  if (!ascii_result.empty()) {
  ------------------
  |  Branch (29:7): [True: 2.75k, False: 1.77k]
  ------------------
   30|  2.75k|    std::string roundtrip = ada::idna::to_unicode(ascii_result);
   31|  2.75k|    length += roundtrip.size();
   32|  2.75k|  }
   33|       |
   34|       |  /**
   35|       |   * Punycode functions
   36|       |   */
   37|  4.53k|  {
   38|  4.53k|    std::u32string utf32_out;
   39|       |    // punycode_to_utf32: source can be any string (it's a punycode label)
   40|  4.53k|    bool punycode_ok = ada::idna::punycode_to_utf32(source, utf32_out);
   41|  4.53k|    length += utf32_out.size();
   42|       |
   43|       |    // verify_punycode: checks if source is valid punycode
   44|  4.53k|    volatile bool is_valid_punycode = ada::idna::verify_punycode(source);
   45|  4.53k|    (void)is_valid_punycode;
   46|       |
   47|       |    // utf32_to_punycode: round-trip if punycode_to_utf32 succeeded
   48|  4.53k|    if (punycode_ok && !utf32_out.empty()) {
  ------------------
  |  Branch (48:9): [True: 1.26k, False: 3.27k]
  |  Branch (48:24): [True: 723, False: 541]
  ------------------
   49|    723|      std::string punycode_back;
   50|    723|      volatile bool encode_ok =
   51|    723|          ada::idna::utf32_to_punycode(utf32_out, punycode_back);
   52|    723|      length += punycode_back.size();
   53|    723|      (void)encode_ok;
   54|    723|    }
   55|  4.53k|  }
   56|       |
   57|       |  /**
   58|       |   * Unicode transcoding
   59|       |   */
   60|  4.53k|  {
   61|       |    // UTF-8 to UTF-32 conversion
   62|  4.53k|    size_t utf32_len =
   63|  4.53k|        ada::idna::utf32_length_from_utf8(source.data(), source.size());
   64|  4.53k|    if (utf32_len > 0 && utf32_len < 1024) {
  ------------------
  |  Branch (64:9): [True: 3.97k, False: 559]
  |  Branch (64:26): [True: 3.97k, False: 0]
  ------------------
   65|  3.97k|      std::vector<char32_t> utf32_buf(utf32_len + 1, 0);
   66|  3.97k|      size_t actual = ada::idna::utf8_to_utf32(source.data(), source.size(),
   67|  3.97k|                                               utf32_buf.data());
   68|  3.97k|      length += actual;
   69|       |
   70|       |      // UTF-32 to UTF-8 round-trip
   71|  3.97k|      if (actual > 0) {
  ------------------
  |  Branch (71:11): [True: 3.77k, False: 205]
  ------------------
   72|  3.77k|        size_t utf8_len =
   73|  3.77k|            ada::idna::utf8_length_from_utf32(utf32_buf.data(), actual);
   74|  3.77k|        if (utf8_len > 0 && utf8_len < 4096) {
  ------------------
  |  Branch (74:13): [True: 3.77k, False: 0]
  |  Branch (74:29): [True: 3.77k, False: 0]
  ------------------
   75|  3.77k|          std::string utf8_back(utf8_len, '\0');
   76|  3.77k|          size_t written = ada::idna::utf32_to_utf8(utf32_buf.data(), actual,
   77|  3.77k|                                                    utf8_back.data());
   78|  3.77k|          length += written;
   79|  3.77k|        }
   80|  3.77k|      }
   81|  3.97k|    }
   82|  4.53k|  }
   83|       |
   84|       |  /**
   85|       |   * IDNA label validation
   86|       |   */
   87|  4.53k|  {
   88|       |    // is_label_valid requires a UTF-32 string
   89|  4.53k|    std::u32string utf32_label;
   90|  4.53k|    bool ok = ada::idna::punycode_to_utf32(source2, utf32_label);
   91|  4.53k|    if (ok && !utf32_label.empty()) {
  ------------------
  |  Branch (91:9): [True: 4.40k, False: 137]
  |  Branch (91:15): [True: 182, False: 4.21k]
  ------------------
   92|    182|      volatile bool label_valid = ada::idna::is_label_valid(utf32_label);
   93|    182|      (void)label_valid;
   94|    182|    }
   95|       |
   96|       |    // Also test is_label_valid with direct ASCII-to-UTF32 conversion
   97|  4.53k|    std::u32string ascii_label(source2.begin(), source2.end());
   98|  4.53k|    if (!ascii_label.empty()) {
  ------------------
  |  Branch (98:9): [True: 326, False: 4.21k]
  ------------------
   99|    326|      volatile bool ascii_label_valid = ada::idna::is_label_valid(ascii_label);
  100|    326|      (void)ascii_label_valid;
  101|    326|    }
  102|  4.53k|  }
  103|       |
  104|       |  /**
  105|       |   * IDNA mapping
  106|       |   */
  107|  4.53k|  {
  108|       |    // ASCII mapping: just lowercases ASCII characters
  109|  4.53k|    std::string ascii_copy = source;
  110|  4.53k|    ada::idna::ascii_map(ascii_copy.data(), ascii_copy.size());
  111|  4.53k|    length += ascii_copy.size();
  112|       |
  113|       |    // Unicode mapping: maps UTF-32 characters according to IDNA
  114|  4.53k|    size_t utf32_len =
  115|  4.53k|        ada::idna::utf32_length_from_utf8(source.data(), source.size());
  116|  4.53k|    if (utf32_len > 0 && utf32_len < 256) {
  ------------------
  |  Branch (116:9): [True: 3.97k, False: 559]
  |  Branch (116:26): [True: 3.94k, False: 35]
  ------------------
  117|  3.94k|      std::u32string utf32_input(utf32_len, 0);
  118|  3.94k|      size_t actual = ada::idna::utf8_to_utf32(source.data(), source.size(),
  119|  3.94k|                                               utf32_input.data());
  120|  3.94k|      if (actual > 0) {
  ------------------
  |  Branch (120:11): [True: 3.75k, False: 189]
  ------------------
  121|  3.75k|        utf32_input.resize(actual);
  122|  3.75k|        std::u32string mapped = ada::idna::map(utf32_input);
  123|  3.75k|        length += mapped.size();
  124|  3.75k|      }
  125|  3.94k|    }
  126|  4.53k|  }
  127|       |
  128|       |  /**
  129|       |   * Domain code point validation
  130|       |   */
  131|  4.53k|  {
  132|  4.53k|    volatile bool has_forbidden =
  133|  4.53k|        ada::idna::contains_forbidden_domain_code_point(source);
  134|  4.53k|    (void)has_forbidden;
  135|       |
  136|       |    // is_ascii checks
  137|  4.53k|    volatile bool is_ascii_str =
  138|  4.53k|        ada::idna::is_ascii(std::string_view(source.data(), source.size()));
  139|  4.53k|    (void)is_ascii_str;
  140|  4.53k|  }
  141|       |
  142|       |  /**
  143|       |   * Normalization
  144|       |   */
  145|  4.53k|  {
  146|  4.53k|    size_t utf32_len =
  147|  4.53k|        ada::idna::utf32_length_from_utf8(source.data(), source.size());
  148|  4.53k|    if (utf32_len > 0 && utf32_len < 256) {
  ------------------
  |  Branch (148:9): [True: 3.97k, False: 559]
  |  Branch (148:26): [True: 3.94k, False: 35]
  ------------------
  149|  3.94k|      std::u32string utf32_input(utf32_len, 0);
  150|  3.94k|      size_t actual = ada::idna::utf8_to_utf32(source.data(), source.size(),
  151|  3.94k|                                               utf32_input.data());
  152|  3.94k|      if (actual > 0) {
  ------------------
  |  Branch (152:11): [True: 3.75k, False: 189]
  ------------------
  153|  3.75k|        utf32_input.resize(actual);
  154|  3.75k|        ada::idna::normalize(utf32_input);
  155|  3.75k|        length += utf32_input.size();
  156|  3.75k|      }
  157|  3.94k|    }
  158|  4.53k|  }
  159|       |
  160|       |  /**
  161|       |   * IDNA stability property.
  162|       |   *
  163|       |   * Applying to_ascii twice must be idempotent: if to_ascii(x) produces a
  164|       |   * non-empty result, then to_ascii(to_ascii(x)) must equal to_ascii(x).
  165|       |   * A correctly normalised ACE label is already its own fixed point.
  166|       |   *
  167|       |   * We allow the second call to return an empty string only if the first
  168|       |   * result was itself not a valid IDNA domain (some implementations return
  169|       |   * empty on failure). If the first result is non-empty and looks like a
  170|       |   * valid domain the second application must match.
  171|       |   */
  172|  4.53k|  {
  173|  4.53k|    if (!ascii_result.empty()) {
  ------------------
  |  Branch (173:9): [True: 2.75k, False: 1.77k]
  ------------------
  174|  2.75k|      std::string ascii_result2 = ada::idna::to_ascii(ascii_result);
  175|  2.75k|      if (!ascii_result2.empty() && ascii_result2 != ascii_result) {
  ------------------
  |  Branch (175:11): [True: 2.75k, False: 0]
  |  Branch (175:37): [True: 0, False: 2.75k]
  ------------------
  176|      0|        printf(
  177|      0|            "IDNA to_ascii not idempotent!\n"
  178|      0|            "  input:   %s\n  first:   %s\n  second:  %s\n",
  179|      0|            source.c_str(), ascii_result.c_str(), ascii_result2.c_str());
  180|      0|        abort();
  181|      0|      }
  182|  2.75k|    }
  183|  4.53k|  }
  184|       |
  185|       |  /**
  186|       |   * to_unicode stability.
  187|       |   *
  188|       |   * Applying to_unicode twice should also be idempotent: once a domain is in
  189|       |   * its Unicode presentation form, converting again should give the same
  190|       |   * result.
  191|       |   */
  192|  4.53k|  {
  193|  4.53k|    if (!unicode_result.empty()) {
  ------------------
  |  Branch (193:9): [True: 3.99k, False: 539]
  ------------------
  194|  3.99k|      std::string unicode_result2 = ada::idna::to_unicode(unicode_result);
  195|  3.99k|      if (!unicode_result2.empty() && unicode_result2 != unicode_result) {
  ------------------
  |  Branch (195:11): [True: 3.99k, False: 0]
  |  Branch (195:39): [True: 0, False: 3.99k]
  ------------------
  196|      0|        printf(
  197|      0|            "IDNA to_unicode not idempotent!\n"
  198|      0|            "  input:   %s\n  first:   %s\n  second:  %s\n",
  199|      0|            source.c_str(), unicode_result.c_str(), unicode_result2.c_str());
  200|      0|        abort();
  201|      0|      }
  202|  3.99k|    }
  203|  4.53k|  }
  204|       |
  205|       |  /**
  206|       |   * Long domain names near the DNS length limit (253 characters).
  207|       |   *
  208|       |   * The IDNA and DNS-length checking code has special handling for domains
  209|       |   * close to or exceeding 253/255 characters and 63-character labels. Feed
  210|       |   * the fuzzer inputs of a controlled length to maximise coverage of those
  211|       |   * boundary checks.
  212|       |   */
  213|  4.53k|  {
  214|  4.53k|    std::string long_domain = fdp.ConsumeRandomLengthString(270);
  215|  4.53k|    std::string long_ascii = ada::idna::to_ascii(long_domain);
  216|  4.53k|    length += long_ascii.size();
  217|       |
  218|       |    // verify_dns_length on the long input (already called for `source` above,
  219|       |    // but we want to exercise the boundary cases separately).
  220|  4.53k|    volatile bool long_dns_ok = ada::checkers::verify_dns_length(long_domain);
  221|  4.53k|    (void)long_dns_ok;
  222|       |
  223|  4.53k|    if (!long_ascii.empty()) {
  ------------------
  |  Branch (223:9): [True: 178, False: 4.36k]
  ------------------
  224|    178|      volatile bool long_ascii_dns_ok =
  225|    178|          ada::checkers::verify_dns_length(long_ascii);
  226|    178|      (void)long_ascii_dns_ok;
  227|    178|    }
  228|  4.53k|  }
  229|       |
  230|       |  /**
  231|       |   * Punycode round-trip on arbitrary binary blobs.
  232|       |   *
  233|       |   * Feed random bytes directly into punycode_to_utf32, then if that succeeds
  234|       |   * encode the result back with utf32_to_punycode and verify the round-trip.
  235|       |   */
  236|  4.53k|  {
  237|  4.53k|    std::string blob = fdp.ConsumeRandomLengthString(128);
  238|  4.53k|    std::u32string decoded;
  239|  4.53k|    bool ok = ada::idna::punycode_to_utf32(blob, decoded);
  240|  4.53k|    if (ok && !decoded.empty()) {
  ------------------
  |  Branch (240:9): [True: 4.40k, False: 136]
  |  Branch (240:15): [True: 47, False: 4.35k]
  ------------------
  241|     47|      std::string reencoded;
  242|     47|      bool enc_ok = ada::idna::utf32_to_punycode(decoded, reencoded);
  243|     47|      (void)enc_ok;
  244|     47|      length += reencoded.size();
  245|       |
  246|       |      // Re-decode the re-encoded form; it must match the first decoded form.
  247|     47|      if (enc_ok && !reencoded.empty()) {
  ------------------
  |  Branch (247:11): [True: 42, False: 5]
  |  Branch (247:21): [True: 42, False: 0]
  ------------------
  248|     42|        std::u32string redecoded;
  249|     42|        bool redec_ok = ada::idna::punycode_to_utf32(reencoded, redecoded);
  250|     42|        if (redec_ok && redecoded != decoded) {
  ------------------
  |  Branch (250:13): [True: 42, False: 0]
  |  Branch (250:25): [True: 0, False: 42]
  ------------------
  251|      0|          printf("Punycode round-trip mismatch!\n");
  252|      0|          abort();
  253|      0|        }
  254|     42|      }
  255|     47|    }
  256|  4.53k|  }
  257|       |
  258|  4.53k|  return 0;
  259|  4.53k|}

