_ZN3ada4idna13utf8_to_utf32EPKcmPDi:
  129|  6.80k|size_t utf8_to_utf32(const char* buf, size_t len, char32_t* utf32_output) {
  130|  6.80k|  const uint8_t* data = reinterpret_cast<const uint8_t*>(buf);
  131|  6.80k|  size_t pos = 0;
  132|  6.80k|  char32_t* start{utf32_output};
  133|  87.8k|  while (pos < len) {
  ------------------
  |  Branch (133:10): [True: 83.1k, False: 4.70k]
  ------------------
  134|       |    // try to convert the next block of 16 ASCII bytes
  135|  83.1k|    if (pos + 16 <= len) {  // if it is safe to read 16 more
  ------------------
  |  Branch (135:9): [True: 54.1k, False: 28.9k]
  ------------------
  136|       |                            // bytes, check that they are ascii
  137|  54.1k|      uint64_t v1;
  138|  54.1k|      std::memcpy(&v1, data + pos, sizeof(uint64_t));
  139|  54.1k|      uint64_t v2;
  140|  54.1k|      std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t));
  141|  54.1k|      uint64_t v{v1 | v2};
  142|  54.1k|      if ((v & 0x8080808080808080) == 0) {
  ------------------
  |  Branch (142:11): [True: 1.53k, False: 52.6k]
  ------------------
  143|  1.53k|        size_t final_pos = pos + 16;
  144|  26.1k|        while (pos < final_pos) {
  ------------------
  |  Branch (144:16): [True: 24.5k, False: 1.53k]
  ------------------
  145|  24.5k|          *utf32_output++ = char32_t(buf[pos]);
  146|  24.5k|          pos++;
  147|  24.5k|        }
  148|  1.53k|        continue;
  149|  1.53k|      }
  150|  54.1k|    }
  151|  81.5k|    uint8_t leading_byte = data[pos];  // leading byte
  152|  81.5k|    if (leading_byte < 0b10000000) {
  ------------------
  |  Branch (152:9): [True: 47.5k, False: 34.0k]
  ------------------
  153|       |      // converting one ASCII byte !!!
  154|  47.5k|      *utf32_output++ = char32_t(leading_byte);
  155|  47.5k|      pos++;
  156|  47.5k|    } else if ((leading_byte & 0b11100000) == 0b11000000) {
  ------------------
  |  Branch (156:16): [True: 6.80k, False: 27.2k]
  ------------------
  157|       |      // We have a two-byte UTF-8
  158|  6.80k|      if (pos + 1 >= len) {
  ------------------
  |  Branch (158:11): [True: 175, False: 6.63k]
  ------------------
  159|    175|        return 0;
  160|    175|      }  // minimal bound checking
  161|  6.63k|      if ((data[pos + 1] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (161:11): [True: 314, False: 6.31k]
  ------------------
  162|    314|        return 0;
  163|    314|      }
  164|       |      // range check
  165|  6.31k|      uint32_t code_point =
  166|  6.31k|          (leading_byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111);
  167|  6.31k|      if (code_point < 0x80 || 0x7ff < code_point) {
  ------------------
  |  Branch (167:11): [True: 20, False: 6.29k]
  |  Branch (167:32): [True: 0, False: 6.29k]
  ------------------
  168|     20|        return 0;
  169|     20|      }
  170|  6.29k|      *utf32_output++ = char32_t(code_point);
  171|  6.29k|      pos += 2;
  172|  27.2k|    } else if ((leading_byte & 0b11110000) == 0b11100000) {
  ------------------
  |  Branch (172:16): [True: 25.4k, False: 1.80k]
  ------------------
  173|       |      // We have a three-byte UTF-8
  174|  25.4k|      if (pos + 2 >= len) {
  ------------------
  |  Branch (174:11): [True: 73, False: 25.3k]
  ------------------
  175|     73|        return 0;
  176|     73|      }  // minimal bound checking
  177|       |
  178|  25.3k|      if ((data[pos + 1] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (178:11): [True: 114, False: 25.2k]
  ------------------
  179|    114|        return 0;
  180|    114|      }
  181|  25.2k|      if ((data[pos + 2] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (181:11): [True: 37, False: 25.2k]
  ------------------
  182|     37|        return 0;
  183|     37|      }
  184|       |      // range check
  185|  25.2k|      uint32_t code_point = (leading_byte & 0b00001111) << 12 |
  186|  25.2k|                            (data[pos + 1] & 0b00111111) << 6 |
  187|  25.2k|                            (data[pos + 2] & 0b00111111);
  188|  25.2k|      if (code_point < 0x800 || 0xffff < code_point ||
  ------------------
  |  Branch (188:11): [True: 18, False: 25.1k]
  |  Branch (188:33): [True: 0, False: 25.1k]
  ------------------
  189|  25.2k|          (0xd7ff < code_point && code_point < 0xe000)) {
  ------------------
  |  Branch (189:12): [True: 2.28k, False: 22.9k]
  |  Branch (189:35): [True: 16, False: 2.26k]
  ------------------
  190|     34|        return 0;
  191|     34|      }
  192|  25.1k|      *utf32_output++ = char32_t(code_point);
  193|  25.1k|      pos += 3;
  194|  25.1k|    } else if ((leading_byte & 0b11111000) == 0b11110000) {  // 0b11110000
  ------------------
  |  Branch (194:16): [True: 646, False: 1.15k]
  ------------------
  195|       |      // we have a 4-byte UTF-8 word.
  196|    646|      if (pos + 3 >= len) {
  ------------------
  |  Branch (196:11): [True: 43, False: 603]
  ------------------
  197|     43|        return 0;
  198|     43|      }  // minimal bound checking
  199|    603|      if ((data[pos + 1] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (199:11): [True: 69, False: 534]
  ------------------
  200|     69|        return 0;
  201|     69|      }
  202|    534|      if ((data[pos + 2] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (202:11): [True: 27, False: 507]
  ------------------
  203|     27|        return 0;
  204|     27|      }
  205|    507|      if ((data[pos + 3] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (205:11): [True: 18, False: 489]
  ------------------
  206|     18|        return 0;
  207|     18|      }
  208|       |
  209|       |      // range check
  210|    489|      uint32_t code_point = (leading_byte & 0b00000111) << 18 |
  211|    489|                            (data[pos + 1] & 0b00111111) << 12 |
  212|    489|                            (data[pos + 2] & 0b00111111) << 6 |
  213|    489|                            (data[pos + 3] & 0b00111111);
  214|    489|      if (code_point <= 0xffff || 0x10ffff < code_point) {
  ------------------
  |  Branch (214:11): [True: 13, False: 476]
  |  Branch (214:35): [True: 7, False: 469]
  ------------------
  215|     20|        return 0;
  216|     20|      }
  217|    469|      *utf32_output++ = char32_t(code_point);
  218|    469|      pos += 4;
  219|  1.15k|    } else {
  220|  1.15k|      return 0;
  221|  1.15k|    }
  222|  81.5k|  }
  223|  4.70k|  return utf32_output - start;
  224|  6.80k|}
_ZN3ada4idna22utf8_length_from_utf32EPKDim:
  226|    918|size_t utf8_length_from_utf32(const char32_t* buf, size_t len) {
  227|       |  // We are not BOM aware.
  228|    918|  const uint32_t* p = reinterpret_cast<const uint32_t*>(buf);
  229|    918|  size_t counter{0};
  230|  3.93k|  for (size_t i = 0; i != len; ++i) {
  ------------------
  |  Branch (230:22): [True: 3.01k, False: 918]
  ------------------
  231|  3.01k|    ++counter;                                      // ASCII
  232|  3.01k|    counter += static_cast<size_t>(p[i] > 0x7F);    // two-byte
  233|  3.01k|    counter += static_cast<size_t>(p[i] > 0x7FF);   // three-byte
  234|  3.01k|    counter += static_cast<size_t>(p[i] > 0xFFFF);  // four-bytes
  235|  3.01k|  }
  236|    918|  return counter;
  237|    918|}
_ZN3ada4idna22utf32_length_from_utf8EPKcm:
  239|  6.80k|size_t utf32_length_from_utf8(const char* buf, size_t len) {
  240|  6.80k|  const int8_t* p = reinterpret_cast<const int8_t*>(buf);
  241|  6.80k|  return std::count_if(p, std::next(p, len), [](int8_t c) {
  242|       |    // -65 is 0b10111111, anything larger in two-complement's
  243|       |    // should start a new code point.
  244|  6.80k|    return c > -65;
  245|  6.80k|  });
  246|  6.80k|}
_ZN3ada4idna13utf32_to_utf8EPKDimPc:
  248|    918|size_t utf32_to_utf8(const char32_t* buf, size_t len, char* utf8_output) {
  249|    918|  const uint32_t* data = reinterpret_cast<const uint32_t*>(buf);
  250|    918|  size_t pos = 0;
  251|    918|  char* start{utf8_output};
  252|  3.30k|  while (pos < len) {
  ------------------
  |  Branch (252:10): [True: 2.51k, False: 790]
  ------------------
  253|       |    // try to convert the next block of 2 ASCII characters
  254|  2.51k|    if (pos + 2 <= len) {  // if it is safe to read 8 more
  ------------------
  |  Branch (254:9): [True: 1.84k, False: 673]
  ------------------
  255|       |                           // bytes, check that they are ascii
  256|  1.84k|      uint64_t v;
  257|  1.84k|      std::memcpy(&v, data + pos, sizeof(uint64_t));
  258|  1.84k|      if ((v & 0xFFFFFF80FFFFFF80) == 0) {
  ------------------
  |  Branch (258:11): [True: 393, False: 1.44k]
  ------------------
  259|    393|        *utf8_output++ = char(buf[pos]);
  260|    393|        *utf8_output++ = char(buf[pos + 1]);
  261|    393|        pos += 2;
  262|    393|        continue;
  263|    393|      }
  264|  1.84k|    }
  265|  2.12k|    uint32_t word = data[pos];
  266|  2.12k|    if ((word & 0xFFFFFF80) == 0) {
  ------------------
  |  Branch (266:9): [True: 319, False: 1.80k]
  ------------------
  267|       |      // will generate one UTF-8 bytes
  268|    319|      *utf8_output++ = char(word);
  269|    319|      pos++;
  270|  1.80k|    } else if ((word & 0xFFFFF800) == 0) {
  ------------------
  |  Branch (270:16): [True: 627, False: 1.17k]
  ------------------
  271|       |      // will generate two UTF-8 bytes
  272|       |      // we have 0b110XXXXX 0b10XXXXXX
  273|    627|      *utf8_output++ = char((word >> 6) | 0b11000000);
  274|    627|      *utf8_output++ = char((word & 0b111111) | 0b10000000);
  275|    627|      pos++;
  276|  1.17k|    } else if ((word & 0xFFFF0000) == 0) {
  ------------------
  |  Branch (276:16): [True: 473, False: 702]
  ------------------
  277|       |      // will generate three UTF-8 bytes
  278|       |      // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX
  279|    473|      if (word >= 0xD800 && word <= 0xDFFF) {
  ------------------
  |  Branch (279:11): [True: 107, False: 366]
  |  Branch (279:29): [True: 24, False: 83]
  ------------------
  280|     24|        return 0;
  281|     24|      }
  282|    449|      *utf8_output++ = char((word >> 12) | 0b11100000);
  283|    449|      *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000);
  284|    449|      *utf8_output++ = char((word & 0b111111) | 0b10000000);
  285|    449|      pos++;
  286|    702|    } else {
  287|       |      // will generate four UTF-8 bytes
  288|       |      // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX
  289|       |      // 0b10XXXXXX
  290|    702|      if (word > 0x10FFFF) {
  ------------------
  |  Branch (290:11): [True: 104, False: 598]
  ------------------
  291|    104|        return 0;
  292|    104|      }
  293|    598|      *utf8_output++ = char((word >> 18) | 0b11110000);
  294|    598|      *utf8_output++ = char(((word >> 12) & 0b111111) | 0b10000000);
  295|    598|      *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000);
  296|    598|      *utf8_output++ = char((word & 0b111111) | 0b10000000);
  297|    598|      pos++;
  298|    598|    }
  299|  2.12k|  }
  300|    790|  return utf8_output - start;
  301|    918|}
_ZN3ada4idna16find_range_indexEj:
 2716|   120k|uint32_t find_range_index(uint32_t key) {
 2717|       |  ////////////////
 2718|       |  // This could be implemented with std::lower_bound, but we roll our own
 2719|       |  // because we want to allow further optimizations in the future.
 2720|       |  ////////////////
 2721|   120k|  uint32_t len = std::size(table);
 2722|   120k|  uint32_t low = 0;
 2723|   120k|  uint32_t high = len - 1;
 2724|  1.59M|  while (low <= high) {
  ------------------
  |  Branch (2724:10): [True: 1.51M, False: 81.9k]
  ------------------
 2725|  1.51M|    uint32_t middle_index = (low + high) >> 1;  // cannot overflow
 2726|  1.51M|    uint32_t middle_value = table[middle_index][0];
 2727|  1.51M|    if (middle_value < key) {
  ------------------
  |  Branch (2727:9): [True: 454k, False: 1.06M]
  ------------------
 2728|   454k|      low = middle_index + 1;
 2729|  1.06M|    } else if (middle_value > key) {
  ------------------
  |  Branch (2729:16): [True: 1.02M, False: 38.2k]
  ------------------
 2730|  1.02M|      high = middle_index - 1;
 2731|  1.02M|    } else {
 2732|  38.2k|      return middle_index;  // perfect match
 2733|  38.2k|    }
 2734|  1.51M|  }
 2735|  81.9k|  return low == 0 ? 0 : low - 1;
  ------------------
  |  Branch (2735:10): [True: 0, False: 81.9k]
  ------------------
 2736|   120k|}
_ZN3ada4idna9ascii_mapEPcm:
 2762|  10.2k|void ascii_map(char* input, size_t length) {
 2763|  10.2k|  auto broadcast = [](uint8_t v) -> uint64_t {
 2764|  10.2k|    return 0x101010101010101ull * v;
 2765|  10.2k|  };
 2766|  10.2k|  uint64_t broadcast_80 = broadcast(0x80);
 2767|  10.2k|  uint64_t broadcast_Ap = broadcast(128 - 'A');
 2768|  10.2k|  uint64_t broadcast_Zp = broadcast(128 - 'Z' - 1);
 2769|  10.2k|  size_t i = 0;
 2770|       |
 2771|  29.0k|  for (; i + 7 < length; i += 8) {
  ------------------
  |  Branch (2771:10): [True: 18.8k, False: 10.2k]
  ------------------
 2772|  18.8k|    uint64_t word{};
 2773|  18.8k|    memcpy(&word, input + i, sizeof(word));
 2774|  18.8k|    word ^=
 2775|  18.8k|        (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
 2776|  18.8k|    memcpy(input + i, &word, sizeof(word));
 2777|  18.8k|  }
 2778|  10.2k|  if (i < length) {
  ------------------
  |  Branch (2778:7): [True: 8.78k, False: 1.49k]
  ------------------
 2779|  8.78k|    uint64_t word{};
 2780|  8.78k|    memcpy(&word, input + i, length - i);
 2781|  8.78k|    word ^=
 2782|  8.78k|        (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
 2783|  8.78k|    memcpy(input + i, &word, length - i);
 2784|  8.78k|  }
 2785|  10.2k|}
_ZN3ada4idna3mapENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 2788|  11.4k|std::u32string map(std::u32string_view input) {
 2789|       |  //  [Map](https://www.unicode.org/reports/tr46/#ProcessingStepMap).
 2790|       |  //  For each code point in the domain_name string, look up the status
 2791|       |  //  value in Section 5, [IDNA Mapping
 2792|       |  //  Table](https://www.unicode.org/reports/tr46/#IDNA_Mapping_Table),
 2793|       |  //  and take the following actions:
 2794|       |  //    * disallowed: Leave the code point unchanged in the string, and
 2795|       |  //    record that there was an error.
 2796|       |  //    * ignored: Remove the code point from the string. This is
 2797|       |  //    equivalent to mapping the code point to an empty string.
 2798|       |  //    * mapped: Replace the code point in the string by the value for
 2799|       |  //    the mapping in Section 5, [IDNA Mapping
 2800|       |  //    Table](https://www.unicode.org/reports/tr46/#IDNA_Mapping_Table).
 2801|       |  //    * valid: Leave the code point unchanged in the string.
 2802|  11.4k|  static std::u32string error = U"";
 2803|  11.4k|  std::u32string answer;
 2804|  11.4k|  answer.reserve(input.size());
 2805|   120k|  for (char32_t x : input) {
  ------------------
  |  Branch (2805:19): [True: 120k, False: 11.1k]
  ------------------
 2806|   120k|    size_t index = find_range_index(x);
 2807|   120k|    uint32_t descriptor = table[index][1];
 2808|   120k|    uint8_t code = uint8_t(descriptor);
 2809|   120k|    switch (code) {
 2810|    199|      case 0:
  ------------------
  |  Branch (2810:7): [True: 199, False: 120k]
  ------------------
 2811|    199|        break;  // nothing to do, ignored
 2812|  86.2k|      case 1:
  ------------------
  |  Branch (2812:7): [True: 86.2k, False: 34.0k]
  ------------------
 2813|  86.2k|        answer.push_back(x);  // valid, we just copy it to output
 2814|  86.2k|        break;
 2815|    281|      case 2:
  ------------------
  |  Branch (2815:7): [True: 281, False: 119k]
  ------------------
 2816|    281|        return error;  // disallowed
 2817|       |      // case 3 :
 2818|  33.5k|      default:
  ------------------
  |  Branch (2818:7): [True: 33.5k, False: 86.7k]
  ------------------
 2819|       |        // We have a mapping
 2820|  33.5k|        {
 2821|  33.5k|          size_t char_count = (descriptor >> 24);
 2822|  33.5k|          uint16_t char_index = uint16_t(descriptor >> 8);
 2823|   171k|          for (size_t idx = char_index; idx < char_index + char_count; idx++) {
  ------------------
  |  Branch (2823:41): [True: 137k, False: 33.5k]
  ------------------
 2824|   137k|            answer.push_back(mappings[idx]);
 2825|   137k|          }
 2826|  33.5k|        }
 2827|   120k|    }
 2828|   120k|  }
 2829|  11.1k|  return answer;
 2830|  11.4k|}
_ZN3ada4idna28compute_decomposition_lengthENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 7749|  11.1k|    const std::u32string_view input) noexcept {
 7750|  11.1k|  bool decomposition_needed{false};
 7751|  11.1k|  size_t additional_elements{0};
 7752|   211k|  for (char32_t current_character : input) {
  ------------------
  |  Branch (7752:35): [True: 211k, False: 11.1k]
  ------------------
 7753|   211k|    size_t decomposition_length{0};
 7754|       |
 7755|   211k|    if (current_character >= hangul_sbase &&
  ------------------
  |  Branch (7755:9): [True: 6.52k, False: 204k]
  ------------------
 7756|   211k|        current_character < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (7756:9): [True: 4.81k, False: 1.70k]
  ------------------
 7757|  4.81k|      decomposition_length = 2;
 7758|  4.81k|      if ((current_character - hangul_sbase) % hangul_tcount) {
  ------------------
  |  Branch (7758:11): [True: 1.97k, False: 2.84k]
  ------------------
 7759|  1.97k|        decomposition_length = 3;
 7760|  1.97k|      }
 7761|   206k|    } else if (current_character < 0x110000) {
  ------------------
  |  Branch (7761:16): [True: 206k, False: 0]
  ------------------
 7762|   206k|      const uint8_t di = decomposition_index[current_character >> 8];
 7763|   206k|      const uint16_t* const decomposition =
 7764|   206k|          decomposition_block[di] + (current_character % 256);
 7765|   206k|      decomposition_length = (decomposition[1] >> 2) - (decomposition[0] >> 2);
 7766|   206k|      if ((decomposition_length > 0) && (decomposition[0] & 1)) {
  ------------------
  |  Branch (7766:11): [True: 4.45k, False: 201k]
  |  Branch (7766:41): [True: 0, False: 4.45k]
  ------------------
 7767|      0|        decomposition_length = 0;
 7768|      0|      }
 7769|   206k|    }
 7770|   211k|    if (decomposition_length != 0) {
  ------------------
  |  Branch (7770:9): [True: 9.27k, False: 201k]
  ------------------
 7771|  9.27k|      decomposition_needed = true;
 7772|  9.27k|      additional_elements += decomposition_length - 1;
 7773|  9.27k|    }
 7774|   211k|  }
 7775|  11.1k|  return {decomposition_needed, additional_elements};
 7776|  11.1k|}
_ZN3ada4idna9decomposeERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEEm:
 7778|  2.75k|void decompose(std::u32string& input, size_t additional_elements) {
 7779|  2.75k|  input.resize(input.size() + additional_elements);
 7780|  2.75k|  for (size_t descending_idx = input.size(),
 7781|  2.75k|              input_count = descending_idx - additional_elements;
 7782|  64.1k|       input_count--;) {
  ------------------
  |  Branch (7782:8): [True: 61.3k, False: 2.75k]
  ------------------
 7783|  61.3k|    if (input[input_count] >= hangul_sbase &&
  ------------------
  |  Branch (7783:9): [True: 5.21k, False: 56.1k]
  ------------------
 7784|  61.3k|        input[input_count] < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (7784:9): [True: 4.81k, False: 401]
  ------------------
 7785|       |      // Hangul decomposition.
 7786|  4.81k|      char32_t s_index = input[input_count] - hangul_sbase;
 7787|  4.81k|      if (s_index % hangul_tcount != 0) {
  ------------------
  |  Branch (7787:11): [True: 1.97k, False: 2.84k]
  ------------------
 7788|  1.97k|        input[--descending_idx] = hangul_tbase + s_index % hangul_tcount;
 7789|  1.97k|      }
 7790|  4.81k|      input[--descending_idx] =
 7791|  4.81k|          hangul_vbase + (s_index % hangul_ncount) / hangul_tcount;
 7792|  4.81k|      input[--descending_idx] = hangul_lbase + s_index / hangul_ncount;
 7793|  56.5k|    } else if (input[input_count] < 0x110000) {
  ------------------
  |  Branch (7793:16): [True: 56.5k, False: 0]
  ------------------
 7794|       |      // Check decomposition_data.
 7795|  56.5k|      const uint16_t* decomposition =
 7796|  56.5k|          decomposition_block[decomposition_index[input[input_count] >> 8]] +
 7797|  56.5k|          (input[input_count] % 256);
 7798|  56.5k|      uint16_t decomposition_length =
 7799|  56.5k|          (decomposition[1] >> 2) - (decomposition[0] >> 2);
 7800|  56.5k|      if (decomposition_length > 0 && (decomposition[0] & 1)) {
  ------------------
  |  Branch (7800:11): [True: 4.45k, False: 52.1k]
  |  Branch (7800:39): [True: 0, False: 4.45k]
  ------------------
 7801|      0|        decomposition_length = 0;
 7802|      0|      }
 7803|  56.5k|      if (decomposition_length > 0) {
  ------------------
  |  Branch (7803:11): [True: 4.45k, False: 52.1k]
  ------------------
 7804|       |        // Non-recursive decomposition.
 7805|  14.5k|        while (decomposition_length-- > 0) {
  ------------------
  |  Branch (7805:16): [True: 10.1k, False: 4.45k]
  ------------------
 7806|  10.1k|          input[--descending_idx] = decomposition_data[(decomposition[0] >> 2) +
 7807|  10.1k|                                                       decomposition_length];
 7808|  10.1k|        }
 7809|  52.1k|      } else {
 7810|       |        // No decomposition.
 7811|  52.1k|        input[--descending_idx] = input[input_count];
 7812|  52.1k|      }
 7813|  56.5k|    } else {
 7814|       |      // Non-Unicode character.
 7815|      0|      input[--descending_idx] = input[input_count];
 7816|      0|    }
 7817|  61.3k|  }
 7818|  2.75k|}
_ZN3ada4idna7get_cccEDi:
 7820|   423k|uint8_t get_ccc(char32_t c) noexcept {
 7821|   423k|  return c < 0x110000 ? canonical_combining_class_block
  ------------------
  |  Branch (7821:10): [True: 423k, False: 0]
  ------------------
 7822|   423k|                            [canonical_combining_class_index[c >> 8]][c % 256]
 7823|   423k|                      : 0;
 7824|   423k|}
_ZN3ada4idna10sort_marksERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEE:
 7826|  11.1k|void sort_marks(std::u32string& input) {
 7827|   223k|  for (size_t idx = 1; idx < input.size(); idx++) {
  ------------------
  |  Branch (7827:24): [True: 212k, False: 11.1k]
  ------------------
 7828|   212k|    uint8_t ccc = get_ccc(input[idx]);
 7829|   212k|    if (ccc == 0) {
  ------------------
  |  Branch (7829:9): [True: 204k, False: 8.68k]
  ------------------
 7830|   204k|      continue;
 7831|   204k|    }  // Skip non-combining characters.
 7832|  8.68k|    auto current_character = input[idx];
 7833|  8.68k|    size_t back_idx = idx;
 7834|  9.62k|    while (back_idx != 0 && get_ccc(input[back_idx - 1]) > ccc) {
  ------------------
  |  Branch (7834:12): [True: 9.50k, False: 127]
  |  Branch (7834:29): [True: 940, False: 8.56k]
  ------------------
 7835|    940|      input[back_idx] = input[back_idx - 1];
 7836|    940|      back_idx--;
 7837|    940|    }
 7838|  8.68k|    input[back_idx] = current_character;
 7839|  8.68k|  }
 7840|  11.1k|}
_ZN3ada4idna13decompose_nfcERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEE:
 7842|  11.1k|void decompose_nfc(std::u32string& input) {
 7843|       |  /**
 7844|       |   * Decompose the domain_name string to Unicode Normalization Form C.
 7845|       |   * @see https://www.unicode.org/reports/tr46/#ProcessingStepDecompose
 7846|       |   */
 7847|  11.1k|  auto [decomposition_needed, additional_elements] =
 7848|  11.1k|      compute_decomposition_length(input);
 7849|  11.1k|  if (decomposition_needed) {
  ------------------
  |  Branch (7849:7): [True: 2.75k, False: 8.39k]
  ------------------
 7850|  2.75k|    decompose(input, additional_elements);
 7851|  2.75k|  }
 7852|  11.1k|  sort_marks(input);
 7853|  11.1k|}
_ZN3ada4idna7composeERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEE:
 7855|  11.1k|void compose(std::u32string& input) {
 7856|       |  /**
 7857|       |   * Compose the domain_name string to Unicode Normalization Form C.
 7858|       |   * @see https://www.unicode.org/reports/tr46/#ProcessingStepCompose
 7859|       |   */
 7860|  11.1k|  size_t input_count{0};
 7861|  11.1k|  size_t composition_count{0};
 7862|   219k|  for (; input_count < input.size(); input_count++, composition_count++) {
  ------------------
  |  Branch (7862:10): [True: 208k, False: 11.1k]
  ------------------
 7863|   208k|    input[composition_count] = input[input_count];
 7864|   208k|    if (input[input_count] >= hangul_lbase &&
  ------------------
  |  Branch (7864:9): [True: 94.2k, False: 113k]
  ------------------
 7865|   208k|        input[input_count] < hangul_lbase + hangul_lcount) {
  ------------------
  |  Branch (7865:9): [True: 5.66k, False: 88.6k]
  ------------------
 7866|  5.66k|      if (input_count + 1 < input.size() &&
  ------------------
  |  Branch (7866:11): [True: 5.44k, False: 221]
  ------------------
 7867|  5.66k|          input[input_count + 1] >= hangul_vbase &&
  ------------------
  |  Branch (7867:11): [True: 5.04k, False: 402]
  ------------------
 7868|  5.66k|          input[input_count + 1] < hangul_vbase + hangul_vcount) {
  ------------------
  |  Branch (7868:11): [True: 4.82k, False: 219]
  ------------------
 7869|  4.82k|        input[composition_count] =
 7870|  4.82k|            hangul_sbase +
 7871|  4.82k|            ((input[input_count] - hangul_lbase) * hangul_vcount +
 7872|  4.82k|             input[input_count + 1] - hangul_vbase) *
 7873|  4.82k|                hangul_tcount;
 7874|  4.82k|        input_count++;
 7875|  4.82k|        if (input_count + 1 < input.size() &&
  ------------------
  |  Branch (7875:13): [True: 4.50k, False: 320]
  ------------------
 7876|  4.82k|            input[input_count + 1] > hangul_tbase &&
  ------------------
  |  Branch (7876:13): [True: 2.14k, False: 2.35k]
  ------------------
 7877|  4.82k|            input[input_count + 1] < hangul_tbase + hangul_tcount) {
  ------------------
  |  Branch (7877:13): [True: 1.97k, False: 171]
  ------------------
 7878|  1.97k|          input[composition_count] += input[++input_count] - hangul_tbase;
 7879|  1.97k|        }
 7880|  4.82k|      }
 7881|   202k|    } else if (input[input_count] >= hangul_sbase &&
  ------------------
  |  Branch (7881:16): [True: 1.50k, False: 201k]
  ------------------
 7882|   202k|               input[input_count] < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (7882:16): [True: 0, False: 1.50k]
  ------------------
 7883|      0|      if ((input[input_count] - hangul_sbase) % hangul_tcount &&
  ------------------
  |  Branch (7883:11): [True: 0, False: 0]
  ------------------
 7884|      0|          input_count + 1 < input.size() &&
  ------------------
  |  Branch (7884:11): [True: 0, False: 0]
  ------------------
 7885|      0|          input[input_count + 1] > hangul_tbase &&
  ------------------
  |  Branch (7885:11): [True: 0, False: 0]
  ------------------
 7886|      0|          input[input_count + 1] < hangul_tbase + hangul_tcount) {
  ------------------
  |  Branch (7886:11): [True: 0, False: 0]
  ------------------
 7887|      0|        input[composition_count] += input[++input_count] - hangul_tbase;
 7888|      0|      }
 7889|   202k|    } else if (input[input_count] < 0x110000) {
  ------------------
  |  Branch (7889:16): [True: 202k, False: 0]
  ------------------
 7890|   202k|      const uint16_t* composition =
 7891|   202k|          &composition_block[composition_index[input[input_count] >> 8]]
 7892|   202k|                            [input[input_count] % 256];
 7893|   202k|      size_t initial_composition_count = composition_count;
 7894|   211k|      for (int32_t previous_ccc = -1; input_count + 1 < input.size();
  ------------------
  |  Branch (7894:39): [True: 201k, False: 10.1k]
  ------------------
 7895|   202k|           input_count++) {
 7896|   201k|        uint8_t ccc = get_ccc(input[input_count + 1]);
 7897|       |
 7898|   201k|        if (composition[1] != composition[0] && previous_ccc < ccc) {
  ------------------
  |  Branch (7898:13): [True: 44.6k, False: 156k]
  |  Branch (7898:49): [True: 43.8k, False: 786]
  ------------------
 7899|       |          // Try finding a composition.
 7900|  43.8k|          uint16_t left = composition[0];
 7901|  43.8k|          uint16_t right = composition[1];
 7902|   113k|          while (left + 2 < right) {
  ------------------
  |  Branch (7902:18): [True: 69.7k, False: 43.8k]
  ------------------
 7903|       |            // mean without overflow
 7904|  69.7k|            uint16_t middle = left + (((right - left) >> 1) & ~1);
 7905|  69.7k|            if (composition_data[middle] <= input[input_count + 1]) {
  ------------------
  |  Branch (7905:17): [True: 12.3k, False: 57.4k]
  ------------------
 7906|  12.3k|              left = middle;
 7907|  12.3k|            }
 7908|  69.7k|            if (composition_data[middle] >= input[input_count + 1]) {
  ------------------
  |  Branch (7908:17): [True: 60.8k, False: 8.87k]
  ------------------
 7909|  60.8k|              right = middle;
 7910|  60.8k|            }
 7911|  69.7k|          }
 7912|  43.8k|          if (composition_data[left] == input[input_count + 1]) {
  ------------------
  |  Branch (7912:15): [True: 5.66k, False: 38.2k]
  ------------------
 7913|  5.66k|            input[initial_composition_count] = composition_data[left + 1];
 7914|  5.66k|            composition =
 7915|  5.66k|                &composition_block
 7916|  5.66k|                    [composition_index[composition_data[left + 1] >> 8]]
 7917|  5.66k|                    [composition_data[left + 1] % 256];
 7918|  5.66k|            continue;
 7919|  5.66k|          }
 7920|  43.8k|        }
 7921|       |
 7922|   195k|        if (ccc == 0) {
  ------------------
  |  Branch (7922:13): [True: 192k, False: 3.03k]
  ------------------
 7923|   192k|          break;
 7924|   192k|        }  // Not a combining character.
 7925|  3.03k|        previous_ccc = ccc;
 7926|  3.03k|        input[++composition_count] = input[input_count + 1];
 7927|  3.03k|      }
 7928|   202k|    }
 7929|   208k|  }
 7930|       |
 7931|  11.1k|  if (composition_count < input_count) {
  ------------------
  |  Branch (7931:7): [True: 2.78k, False: 8.36k]
  ------------------
 7932|  2.78k|    input.resize(composition_count);
 7933|  2.78k|  }
 7934|  11.1k|}
_ZN3ada4idna9normalizeERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEE:
 7936|  11.1k|void normalize(std::u32string& input) {
 7937|       |  /**
 7938|       |   * Normalize the domain_name string to Unicode Normalization Form C.
 7939|       |   * @see https://www.unicode.org/reports/tr46/#ProcessingStepNormalize
 7940|       |   */
 7941|  11.1k|  decompose_nfc(input);
 7942|  11.1k|  compose(input);
 7943|  11.1k|}
_ZN3ada4idna17punycode_to_utf32ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEERNS1_12basic_stringIDiNS3_IDiEENS1_9allocatorIDiEEEE:
 7986|  7.87k|bool punycode_to_utf32(std::string_view input, std::u32string &out) {
 7987|  7.87k|  int32_t written_out{0};
 7988|  7.87k|  out.reserve(out.size() + input.size());
 7989|  7.87k|  uint32_t n = initial_n;
 7990|  7.87k|  int32_t i = 0;
 7991|  7.87k|  int32_t bias = initial_bias;
 7992|       |  // grab ascii content
 7993|  7.87k|  size_t end_of_ascii = input.find_last_of('-');
 7994|  7.87k|  if (end_of_ascii != std::string_view::npos) {
  ------------------
  |  Branch (7994:7): [True: 2.47k, False: 5.39k]
  ------------------
 7995|  9.37k|    for (uint8_t c : input.substr(0, end_of_ascii)) {
  ------------------
  |  Branch (7995:20): [True: 9.37k, False: 2.47k]
  ------------------
 7996|  9.37k|      if (c >= 0x80) {
  ------------------
  |  Branch (7996:11): [True: 0, False: 9.37k]
  ------------------
 7997|      0|        return false;
 7998|      0|      }
 7999|  9.37k|      out.push_back(c);
 8000|  9.37k|      written_out++;
 8001|  9.37k|    }
 8002|  2.47k|    input.remove_prefix(end_of_ascii + 1);
 8003|  2.47k|  }
 8004|  34.9k|  while (!input.empty()) {
  ------------------
  |  Branch (8004:10): [True: 27.2k, False: 7.67k]
  ------------------
 8005|  27.2k|    int32_t oldi = i;
 8006|  27.2k|    int32_t w = 1;
 8007|  61.4k|    for (int32_t k = base;; k += base) {
 8008|  61.4k|      if (input.empty()) {
  ------------------
  |  Branch (8008:11): [True: 88, False: 61.3k]
  ------------------
 8009|     88|        return false;
 8010|     88|      }
 8011|  61.3k|      uint8_t code_point = input.front();
 8012|  61.3k|      input.remove_prefix(1);
 8013|  61.3k|      int32_t digit = char_to_digit_value(code_point);
 8014|  61.3k|      if (digit < 0) {
  ------------------
  |  Branch (8014:11): [True: 65, False: 61.2k]
  ------------------
 8015|     65|        return false;
 8016|     65|      }
 8017|  61.2k|      if (digit > (0x7fffffff - i) / w) {
  ------------------
  |  Branch (8017:11): [True: 14, False: 61.2k]
  ------------------
 8018|     14|        return false;
 8019|     14|      }
 8020|  61.2k|      i = i + digit * w;
 8021|  61.2k|      int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias;
  ------------------
  |  Branch (8021:19): [True: 17.7k, False: 43.5k]
  |  Branch (8021:38): [True: 34.1k, False: 9.42k]
  ------------------
 8022|  61.2k|      if (digit < t) {
  ------------------
  |  Branch (8022:11): [True: 27.0k, False: 34.1k]
  ------------------
 8023|  27.0k|        break;
 8024|  27.0k|      }
 8025|  34.1k|      if (w > 0x7fffffff / (base - t)) {
  ------------------
  |  Branch (8025:11): [True: 0, False: 34.1k]
  ------------------
 8026|      0|        return false;
 8027|      0|      }
 8028|  34.1k|      w = w * (base - t);
 8029|  34.1k|    }
 8030|  27.0k|    bias = adapt(i - oldi, written_out + 1, oldi == 0);
 8031|  27.0k|    if (i / (written_out + 1) > int32_t(0x7fffffff - n)) {
  ------------------
  |  Branch (8031:9): [True: 25, False: 27.0k]
  ------------------
 8032|     25|      return false;
 8033|     25|    }
 8034|  27.0k|    n = n + i / (written_out + 1);
 8035|  27.0k|    i = i % (written_out + 1);
 8036|  27.0k|    if (n < 0x80) {
  ------------------
  |  Branch (8036:9): [True: 0, False: 27.0k]
  ------------------
 8037|      0|      return false;
 8038|      0|    }
 8039|  27.0k|    out.insert(out.begin() + i, n);
 8040|  27.0k|    written_out++;
 8041|  27.0k|    ++i;
 8042|  27.0k|  }
 8043|       |
 8044|  7.67k|  return true;
 8045|  7.87k|}
_ZN3ada4idna15verify_punycodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8047|  1.51k|bool verify_punycode(std::string_view input) {
 8048|  1.51k|  size_t written_out{0};
 8049|  1.51k|  uint32_t n = initial_n;
 8050|  1.51k|  int32_t i = 0;
 8051|  1.51k|  int32_t bias = initial_bias;
 8052|       |  // grab ascii content
 8053|  1.51k|  size_t end_of_ascii = input.find_last_of('-');
 8054|  1.51k|  if (end_of_ascii != std::string_view::npos) {
  ------------------
  |  Branch (8054:7): [True: 376, False: 1.13k]
  ------------------
 8055|  1.15k|    for (uint8_t c : input.substr(0, end_of_ascii)) {
  ------------------
  |  Branch (8055:20): [True: 1.15k, False: 376]
  ------------------
 8056|  1.15k|      if (c >= 0x80) {
  ------------------
  |  Branch (8056:11): [True: 0, False: 1.15k]
  ------------------
 8057|      0|        return false;
 8058|      0|      }
 8059|  1.15k|      written_out++;
 8060|  1.15k|    }
 8061|    376|    input.remove_prefix(end_of_ascii + 1);
 8062|    376|  }
 8063|  3.77k|  while (!input.empty()) {
  ------------------
  |  Branch (8063:10): [True: 2.86k, False: 918]
  ------------------
 8064|  2.86k|    int32_t oldi = i;
 8065|  2.86k|    int32_t w = 1;
 8066|  6.20k|    for (int32_t k = base;; k += base) {
 8067|  6.20k|      if (input.empty()) {
  ------------------
  |  Branch (8067:11): [True: 141, False: 6.06k]
  ------------------
 8068|    141|        return false;
 8069|    141|      }
 8070|  6.06k|      uint8_t code_point = input.front();
 8071|  6.06k|      input.remove_prefix(1);
 8072|  6.06k|      int32_t digit = char_to_digit_value(code_point);
 8073|  6.06k|      if (digit < 0) {
  ------------------
  |  Branch (8073:11): [True: 392, False: 5.66k]
  ------------------
 8074|    392|        return false;
 8075|    392|      }
 8076|  5.66k|      if (digit > (0x7fffffff - i) / w) {
  ------------------
  |  Branch (8076:11): [True: 13, False: 5.65k]
  ------------------
 8077|     13|        return false;
 8078|     13|      }
 8079|  5.65k|      i = i + digit * w;
 8080|  5.65k|      int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias;
  ------------------
  |  Branch (8080:19): [True: 2.18k, False: 3.46k]
  |  Branch (8080:38): [True: 3.14k, False: 327]
  ------------------
 8081|  5.65k|      if (digit < t) {
  ------------------
  |  Branch (8081:11): [True: 2.31k, False: 3.34k]
  ------------------
 8082|  2.31k|        break;
 8083|  2.31k|      }
 8084|  3.34k|      if (w > 0x7fffffff / (base - t)) {
  ------------------
  |  Branch (8084:11): [True: 0, False: 3.34k]
  ------------------
 8085|      0|        return false;
 8086|      0|      }
 8087|  3.34k|      w = w * (base - t);
 8088|  3.34k|    }
 8089|  2.31k|    bias = adapt(i - oldi, int32_t(written_out + 1), oldi == 0);
 8090|  2.31k|    if (i / (written_out + 1) > 0x7fffffff - n) {
  ------------------
  |  Branch (8090:9): [True: 51, False: 2.26k]
  ------------------
 8091|     51|      return false;
 8092|     51|    }
 8093|  2.26k|    n = n + i / int32_t(written_out + 1);
 8094|  2.26k|    i = i % int32_t(written_out + 1);
 8095|  2.26k|    if (n < 0x80) {
  ------------------
  |  Branch (8095:9): [True: 0, False: 2.26k]
  ------------------
 8096|      0|      return false;
 8097|      0|    }
 8098|  2.26k|    written_out++;
 8099|  2.26k|    ++i;
 8100|  2.26k|  }
 8101|       |
 8102|    918|  return true;
 8103|  1.51k|}
_ZN3ada4idna17utf32_to_punycodeENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEERNS1_12basic_stringIcNS3_IcEENS1_9allocatorIcEEEE:
 8105|  17.3k|bool utf32_to_punycode(std::u32string_view input, std::string &out) {
 8106|  17.3k|  out.reserve(input.size() + out.size());
 8107|  17.3k|  uint32_t n = initial_n;
 8108|  17.3k|  int32_t d = 0;
 8109|  17.3k|  int32_t bias = initial_bias;
 8110|  17.3k|  size_t h = 0;
 8111|       |  // first push the ascii content
 8112|   112k|  for (uint32_t c : input) {
  ------------------
  |  Branch (8112:19): [True: 112k, False: 17.3k]
  ------------------
 8113|   112k|    if (c < 0x80) {
  ------------------
  |  Branch (8113:9): [True: 19.2k, False: 93.6k]
  ------------------
 8114|  19.2k|      ++h;
 8115|  19.2k|      out.push_back(char(c));
 8116|  19.2k|    }
 8117|   112k|    if (c > 0x10ffff || (c >= 0xd880 && c < 0xe000)) {
  ------------------
  |  Branch (8117:9): [True: 0, False: 112k]
  |  Branch (8117:26): [True: 747, False: 112k]
  |  Branch (8117:41): [True: 0, False: 747]
  ------------------
 8118|      0|      return false;
 8119|      0|    }
 8120|   112k|  }
 8121|  17.3k|  size_t b = h;
 8122|  17.3k|  if (b > 0) {
  ------------------
  |  Branch (8122:7): [True: 3.95k, False: 13.4k]
  ------------------
 8123|  3.95k|    out.push_back('-');
 8124|  3.95k|  }
 8125|  83.7k|  while (h < input.size()) {
  ------------------
  |  Branch (8125:10): [True: 66.4k, False: 17.3k]
  ------------------
 8126|  66.4k|    uint32_t m = 0x10FFFF;
 8127|  1.35M|    for (auto code_point : input) {
  ------------------
  |  Branch (8127:26): [True: 1.35M, False: 66.4k]
  ------------------
 8128|  1.35M|      if (code_point >= n && code_point < m) m = code_point;
  ------------------
  |  Branch (8128:11): [True: 552k, False: 800k]
  |  Branch (8128:30): [True: 122k, False: 430k]
  ------------------
 8129|  1.35M|    }
 8130|       |
 8131|  66.4k|    if ((m - n) > (0x7fffffff - d) / (h + 1)) {
  ------------------
  |  Branch (8131:9): [True: 0, False: 66.4k]
  ------------------
 8132|      0|      return false;
 8133|      0|    }
 8134|  66.4k|    d = d + int32_t((m - n) * (h + 1));
 8135|  66.4k|    n = m;
 8136|  1.35M|    for (auto c : input) {
  ------------------
  |  Branch (8136:17): [True: 1.35M, False: 66.4k]
  ------------------
 8137|  1.35M|      if (c < n) {
  ------------------
  |  Branch (8137:11): [True: 800k, False: 552k]
  ------------------
 8138|   800k|        if (d == 0x7fffffff) {
  ------------------
  |  Branch (8138:13): [True: 0, False: 800k]
  ------------------
 8139|      0|          return false;
 8140|      0|        }
 8141|   800k|        ++d;
 8142|   800k|      }
 8143|  1.35M|      if (c == n) {
  ------------------
  |  Branch (8143:11): [True: 93.6k, False: 1.25M]
  ------------------
 8144|  93.6k|        int32_t q = d;
 8145|   254k|        for (int32_t k = base;; k += base) {
 8146|   254k|          int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias;
  ------------------
  |  Branch (8146:23): [True: 68.2k, False: 186k]
  |  Branch (8146:42): [True: 137k, False: 48.7k]
  ------------------
 8147|       |
 8148|   254k|          if (q < t) {
  ------------------
  |  Branch (8148:15): [True: 93.6k, False: 161k]
  ------------------
 8149|  93.6k|            break;
 8150|  93.6k|          }
 8151|   161k|          out.push_back(digit_to_char(t + ((q - t) % (base - t))));
 8152|   161k|          q = (q - t) / (base - t);
 8153|   161k|        }
 8154|  93.6k|        out.push_back(digit_to_char(q));
 8155|  93.6k|        bias = adapt(d, int32_t(h + 1), h == b);
 8156|  93.6k|        d = 0;
 8157|  93.6k|        ++h;
 8158|  93.6k|      }
 8159|  1.35M|    }
 8160|  66.4k|    ++d;
 8161|  66.4k|    ++n;
 8162|  66.4k|  }
 8163|  17.3k|  return true;
 8164|  17.3k|}
_ZN3ada4idna14is_label_validENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 8973|  24.2k|bool is_label_valid(const std::u32string_view label) {
 8974|  24.2k|  if (label.empty()) {
  ------------------
  |  Branch (8974:7): [True: 0, False: 24.2k]
  ------------------
 8975|      0|    return true;
 8976|      0|  }
 8977|       |
 8978|       |  ///////////////
 8979|       |  // We have a normalization step which ensures that we are in NFC.
 8980|       |  // If we receive punycode, we normalize and check that the normalized
 8981|       |  // version matches the original.
 8982|       |  // --------------------------------------
 8983|       |  // The label must be in Unicode Normalization Form NFC.
 8984|       |
 8985|       |  // Current URL standard indicatest that CheckHyphens is set to false.
 8986|       |  // ---------------------------------------
 8987|       |  // If CheckHyphens, the label must not contain a U+002D HYPHEN-MINUS character
 8988|       |  // in both the third and fourth positions. If CheckHyphens, the label must
 8989|       |  // neither begin nor end with a U+002D HYPHEN-MINUS character.
 8990|       |
 8991|       |  // This is not necessary because we segment the
 8992|       |  // labels by '.'.
 8993|       |  // ---------------------------------------
 8994|       |  // The label must not contain a U+002E ( . ) FULL STOP.
 8995|       |  // if (label.find('.') != std::string_view::npos) return false;
 8996|       |
 8997|       |  // The label must not begin with a combining mark, that is:
 8998|       |  // General_Category=Mark.
 8999|  24.2k|  constexpr static uint32_t combining[] = {
 9000|  24.2k|      0x300,   0x301,   0x302,   0x303,   0x304,   0x305,   0x306,   0x307,
 9001|  24.2k|      0x308,   0x309,   0x30a,   0x30b,   0x30c,   0x30d,   0x30e,   0x30f,
 9002|  24.2k|      0x310,   0x311,   0x312,   0x313,   0x314,   0x315,   0x316,   0x317,
 9003|  24.2k|      0x318,   0x319,   0x31a,   0x31b,   0x31c,   0x31d,   0x31e,   0x31f,
 9004|  24.2k|      0x320,   0x321,   0x322,   0x323,   0x324,   0x325,   0x326,   0x327,
 9005|  24.2k|      0x328,   0x329,   0x32a,   0x32b,   0x32c,   0x32d,   0x32e,   0x32f,
 9006|  24.2k|      0x330,   0x331,   0x332,   0x333,   0x334,   0x335,   0x336,   0x337,
 9007|  24.2k|      0x338,   0x339,   0x33a,   0x33b,   0x33c,   0x33d,   0x33e,   0x33f,
 9008|  24.2k|      0x340,   0x341,   0x342,   0x343,   0x344,   0x345,   0x346,   0x347,
 9009|  24.2k|      0x348,   0x349,   0x34a,   0x34b,   0x34c,   0x34d,   0x34e,   0x34f,
 9010|  24.2k|      0x350,   0x351,   0x352,   0x353,   0x354,   0x355,   0x356,   0x357,
 9011|  24.2k|      0x358,   0x359,   0x35a,   0x35b,   0x35c,   0x35d,   0x35e,   0x35f,
 9012|  24.2k|      0x360,   0x361,   0x362,   0x363,   0x364,   0x365,   0x366,   0x367,
 9013|  24.2k|      0x368,   0x369,   0x36a,   0x36b,   0x36c,   0x36d,   0x36e,   0x36f,
 9014|  24.2k|      0x483,   0x484,   0x485,   0x486,   0x487,   0x488,   0x489,   0x591,
 9015|  24.2k|      0x592,   0x593,   0x594,   0x595,   0x596,   0x597,   0x598,   0x599,
 9016|  24.2k|      0x59a,   0x59b,   0x59c,   0x59d,   0x59e,   0x59f,   0x5a0,   0x5a1,
 9017|  24.2k|      0x5a2,   0x5a3,   0x5a4,   0x5a5,   0x5a6,   0x5a7,   0x5a8,   0x5a9,
 9018|  24.2k|      0x5aa,   0x5ab,   0x5ac,   0x5ad,   0x5ae,   0x5af,   0x5b0,   0x5b1,
 9019|  24.2k|      0x5b2,   0x5b3,   0x5b4,   0x5b5,   0x5b6,   0x5b7,   0x5b8,   0x5b9,
 9020|  24.2k|      0x5ba,   0x5bb,   0x5bc,   0x5bd,   0x5bf,   0x5c1,   0x5c2,   0x5c4,
 9021|  24.2k|      0x5c5,   0x5c7,   0x610,   0x611,   0x612,   0x613,   0x614,   0x615,
 9022|  24.2k|      0x616,   0x617,   0x618,   0x619,   0x61a,   0x64b,   0x64c,   0x64d,
 9023|  24.2k|      0x64e,   0x64f,   0x650,   0x651,   0x652,   0x653,   0x654,   0x655,
 9024|  24.2k|      0x656,   0x657,   0x658,   0x659,   0x65a,   0x65b,   0x65c,   0x65d,
 9025|  24.2k|      0x65e,   0x65f,   0x670,   0x6d6,   0x6d7,   0x6d8,   0x6d9,   0x6da,
 9026|  24.2k|      0x6db,   0x6dc,   0x6df,   0x6e0,   0x6e1,   0x6e2,   0x6e3,   0x6e4,
 9027|  24.2k|      0x6e7,   0x6e8,   0x6ea,   0x6eb,   0x6ec,   0x6ed,   0x711,   0x730,
 9028|  24.2k|      0x731,   0x732,   0x733,   0x734,   0x735,   0x736,   0x737,   0x738,
 9029|  24.2k|      0x739,   0x73a,   0x73b,   0x73c,   0x73d,   0x73e,   0x73f,   0x740,
 9030|  24.2k|      0x741,   0x742,   0x743,   0x744,   0x745,   0x746,   0x747,   0x748,
 9031|  24.2k|      0x749,   0x74a,   0x7a6,   0x7a7,   0x7a8,   0x7a9,   0x7aa,   0x7ab,
 9032|  24.2k|      0x7ac,   0x7ad,   0x7ae,   0x7af,   0x7b0,   0x7eb,   0x7ec,   0x7ed,
 9033|  24.2k|      0x7ee,   0x7ef,   0x7f0,   0x7f1,   0x7f2,   0x7f3,   0x7fd,   0x816,
 9034|  24.2k|      0x817,   0x818,   0x819,   0x81b,   0x81c,   0x81d,   0x81e,   0x81f,
 9035|  24.2k|      0x820,   0x821,   0x822,   0x823,   0x825,   0x826,   0x827,   0x829,
 9036|  24.2k|      0x82a,   0x82b,   0x82c,   0x82d,   0x859,   0x85a,   0x85b,   0x8d3,
 9037|  24.2k|      0x8d4,   0x8d5,   0x8d6,   0x8d7,   0x8d8,   0x8d9,   0x8da,   0x8db,
 9038|  24.2k|      0x8dc,   0x8dd,   0x8de,   0x8df,   0x8e0,   0x8e1,   0x8e3,   0x8e4,
 9039|  24.2k|      0x8e5,   0x8e6,   0x8e7,   0x8e8,   0x8e9,   0x8ea,   0x8eb,   0x8ec,
 9040|  24.2k|      0x8ed,   0x8ee,   0x8ef,   0x8f0,   0x8f1,   0x8f2,   0x8f3,   0x8f4,
 9041|  24.2k|      0x8f5,   0x8f6,   0x8f7,   0x8f8,   0x8f9,   0x8fa,   0x8fb,   0x8fc,
 9042|  24.2k|      0x8fd,   0x8fe,   0x8ff,   0x900,   0x901,   0x902,   0x903,   0x93a,
 9043|  24.2k|      0x93b,   0x93c,   0x93e,   0x93f,   0x940,   0x941,   0x942,   0x943,
 9044|  24.2k|      0x944,   0x945,   0x946,   0x947,   0x948,   0x949,   0x94a,   0x94b,
 9045|  24.2k|      0x94c,   0x94d,   0x94e,   0x94f,   0x951,   0x952,   0x953,   0x954,
 9046|  24.2k|      0x955,   0x956,   0x957,   0x962,   0x963,   0x981,   0x982,   0x983,
 9047|  24.2k|      0x9bc,   0x9be,   0x9bf,   0x9c0,   0x9c1,   0x9c2,   0x9c3,   0x9c4,
 9048|  24.2k|      0x9c7,   0x9c8,   0x9cb,   0x9cc,   0x9cd,   0x9d7,   0x9e2,   0x9e3,
 9049|  24.2k|      0x9fe,   0xa01,   0xa02,   0xa03,   0xa3c,   0xa3e,   0xa3f,   0xa40,
 9050|  24.2k|      0xa41,   0xa42,   0xa47,   0xa48,   0xa4b,   0xa4c,   0xa4d,   0xa51,
 9051|  24.2k|      0xa70,   0xa71,   0xa75,   0xa81,   0xa82,   0xa83,   0xabc,   0xabe,
 9052|  24.2k|      0xabf,   0xac0,   0xac1,   0xac2,   0xac3,   0xac4,   0xac5,   0xac7,
 9053|  24.2k|      0xac8,   0xac9,   0xacb,   0xacc,   0xacd,   0xae2,   0xae3,   0xafa,
 9054|  24.2k|      0xafb,   0xafc,   0xafd,   0xafe,   0xaff,   0xb01,   0xb02,   0xb03,
 9055|  24.2k|      0xb3c,   0xb3e,   0xb3f,   0xb40,   0xb41,   0xb42,   0xb43,   0xb44,
 9056|  24.2k|      0xb47,   0xb48,   0xb4b,   0xb4c,   0xb4d,   0xb55,   0xb56,   0xb57,
 9057|  24.2k|      0xb62,   0xb63,   0xb82,   0xbbe,   0xbbf,   0xbc0,   0xbc1,   0xbc2,
 9058|  24.2k|      0xbc6,   0xbc7,   0xbc8,   0xbca,   0xbcb,   0xbcc,   0xbcd,   0xbd7,
 9059|  24.2k|      0xc00,   0xc01,   0xc02,   0xc03,   0xc04,   0xc3e,   0xc3f,   0xc40,
 9060|  24.2k|      0xc41,   0xc42,   0xc43,   0xc44,   0xc46,   0xc47,   0xc48,   0xc4a,
 9061|  24.2k|      0xc4b,   0xc4c,   0xc4d,   0xc55,   0xc56,   0xc62,   0xc63,   0xc81,
 9062|  24.2k|      0xc82,   0xc83,   0xcbc,   0xcbe,   0xcbf,   0xcc0,   0xcc1,   0xcc2,
 9063|  24.2k|      0xcc3,   0xcc4,   0xcc6,   0xcc7,   0xcc8,   0xcca,   0xccb,   0xccc,
 9064|  24.2k|      0xccd,   0xcd5,   0xcd6,   0xce2,   0xce3,   0xd00,   0xd01,   0xd02,
 9065|  24.2k|      0xd03,   0xd3b,   0xd3c,   0xd3e,   0xd3f,   0xd40,   0xd41,   0xd42,
 9066|  24.2k|      0xd43,   0xd44,   0xd46,   0xd47,   0xd48,   0xd4a,   0xd4b,   0xd4c,
 9067|  24.2k|      0xd4d,   0xd57,   0xd62,   0xd63,   0xd81,   0xd82,   0xd83,   0xdca,
 9068|  24.2k|      0xdcf,   0xdd0,   0xdd1,   0xdd2,   0xdd3,   0xdd4,   0xdd6,   0xdd8,
 9069|  24.2k|      0xdd9,   0xdda,   0xddb,   0xddc,   0xddd,   0xdde,   0xddf,   0xdf2,
 9070|  24.2k|      0xdf3,   0xe31,   0xe34,   0xe35,   0xe36,   0xe37,   0xe38,   0xe39,
 9071|  24.2k|      0xe3a,   0xe47,   0xe48,   0xe49,   0xe4a,   0xe4b,   0xe4c,   0xe4d,
 9072|  24.2k|      0xe4e,   0xeb1,   0xeb4,   0xeb5,   0xeb6,   0xeb7,   0xeb8,   0xeb9,
 9073|  24.2k|      0xeba,   0xebb,   0xebc,   0xec8,   0xec9,   0xeca,   0xecb,   0xecc,
 9074|  24.2k|      0xecd,   0xf18,   0xf19,   0xf35,   0xf37,   0xf39,   0xf3e,   0xf3f,
 9075|  24.2k|      0xf71,   0xf72,   0xf73,   0xf74,   0xf75,   0xf76,   0xf77,   0xf78,
 9076|  24.2k|      0xf79,   0xf7a,   0xf7b,   0xf7c,   0xf7d,   0xf7e,   0xf7f,   0xf80,
 9077|  24.2k|      0xf81,   0xf82,   0xf83,   0xf84,   0xf86,   0xf87,   0xf8d,   0xf8e,
 9078|  24.2k|      0xf8f,   0xf90,   0xf91,   0xf92,   0xf93,   0xf94,   0xf95,   0xf96,
 9079|  24.2k|      0xf97,   0xf99,   0xf9a,   0xf9b,   0xf9c,   0xf9d,   0xf9e,   0xf9f,
 9080|  24.2k|      0xfa0,   0xfa1,   0xfa2,   0xfa3,   0xfa4,   0xfa5,   0xfa6,   0xfa7,
 9081|  24.2k|      0xfa8,   0xfa9,   0xfaa,   0xfab,   0xfac,   0xfad,   0xfae,   0xfaf,
 9082|  24.2k|      0xfb0,   0xfb1,   0xfb2,   0xfb3,   0xfb4,   0xfb5,   0xfb6,   0xfb7,
 9083|  24.2k|      0xfb8,   0xfb9,   0xfba,   0xfbb,   0xfbc,   0xfc6,   0x102b,  0x102c,
 9084|  24.2k|      0x102d,  0x102e,  0x102f,  0x1030,  0x1031,  0x1032,  0x1033,  0x1034,
 9085|  24.2k|      0x1035,  0x1036,  0x1037,  0x1038,  0x1039,  0x103a,  0x103b,  0x103c,
 9086|  24.2k|      0x103d,  0x103e,  0x1056,  0x1057,  0x1058,  0x1059,  0x105e,  0x105f,
 9087|  24.2k|      0x1060,  0x1062,  0x1063,  0x1064,  0x1067,  0x1068,  0x1069,  0x106a,
 9088|  24.2k|      0x106b,  0x106c,  0x106d,  0x1071,  0x1072,  0x1073,  0x1074,  0x1082,
 9089|  24.2k|      0x1083,  0x1084,  0x1085,  0x1086,  0x1087,  0x1088,  0x1089,  0x108a,
 9090|  24.2k|      0x108b,  0x108c,  0x108d,  0x108f,  0x109a,  0x109b,  0x109c,  0x109d,
 9091|  24.2k|      0x135d,  0x135e,  0x135f,  0x1712,  0x1713,  0x1714,  0x1732,  0x1733,
 9092|  24.2k|      0x1734,  0x1752,  0x1753,  0x1772,  0x1773,  0x17b4,  0x17b5,  0x17b6,
 9093|  24.2k|      0x17b7,  0x17b8,  0x17b9,  0x17ba,  0x17bb,  0x17bc,  0x17bd,  0x17be,
 9094|  24.2k|      0x17bf,  0x17c0,  0x17c1,  0x17c2,  0x17c3,  0x17c4,  0x17c5,  0x17c6,
 9095|  24.2k|      0x17c7,  0x17c8,  0x17c9,  0x17ca,  0x17cb,  0x17cc,  0x17cd,  0x17ce,
 9096|  24.2k|      0x17cf,  0x17d0,  0x17d1,  0x17d2,  0x17d3,  0x17dd,  0x180b,  0x180c,
 9097|  24.2k|      0x180d,  0x1885,  0x1886,  0x18a9,  0x1920,  0x1921,  0x1922,  0x1923,
 9098|  24.2k|      0x1924,  0x1925,  0x1926,  0x1927,  0x1928,  0x1929,  0x192a,  0x192b,
 9099|  24.2k|      0x1930,  0x1931,  0x1932,  0x1933,  0x1934,  0x1935,  0x1936,  0x1937,
 9100|  24.2k|      0x1938,  0x1939,  0x193a,  0x193b,  0x1a17,  0x1a18,  0x1a19,  0x1a1a,
 9101|  24.2k|      0x1a1b,  0x1a55,  0x1a56,  0x1a57,  0x1a58,  0x1a59,  0x1a5a,  0x1a5b,
 9102|  24.2k|      0x1a5c,  0x1a5d,  0x1a5e,  0x1a60,  0x1a61,  0x1a62,  0x1a63,  0x1a64,
 9103|  24.2k|      0x1a65,  0x1a66,  0x1a67,  0x1a68,  0x1a69,  0x1a6a,  0x1a6b,  0x1a6c,
 9104|  24.2k|      0x1a6d,  0x1a6e,  0x1a6f,  0x1a70,  0x1a71,  0x1a72,  0x1a73,  0x1a74,
 9105|  24.2k|      0x1a75,  0x1a76,  0x1a77,  0x1a78,  0x1a79,  0x1a7a,  0x1a7b,  0x1a7c,
 9106|  24.2k|      0x1a7f,  0x1ab0,  0x1ab1,  0x1ab2,  0x1ab3,  0x1ab4,  0x1ab5,  0x1ab6,
 9107|  24.2k|      0x1ab7,  0x1ab8,  0x1ab9,  0x1aba,  0x1abb,  0x1abc,  0x1abd,  0x1abe,
 9108|  24.2k|      0x1abf,  0x1ac0,  0x1b00,  0x1b01,  0x1b02,  0x1b03,  0x1b04,  0x1b34,
 9109|  24.2k|      0x1b35,  0x1b36,  0x1b37,  0x1b38,  0x1b39,  0x1b3a,  0x1b3b,  0x1b3c,
 9110|  24.2k|      0x1b3d,  0x1b3e,  0x1b3f,  0x1b40,  0x1b41,  0x1b42,  0x1b43,  0x1b44,
 9111|  24.2k|      0x1b6b,  0x1b6c,  0x1b6d,  0x1b6e,  0x1b6f,  0x1b70,  0x1b71,  0x1b72,
 9112|  24.2k|      0x1b73,  0x1b80,  0x1b81,  0x1b82,  0x1ba1,  0x1ba2,  0x1ba3,  0x1ba4,
 9113|  24.2k|      0x1ba5,  0x1ba6,  0x1ba7,  0x1ba8,  0x1ba9,  0x1baa,  0x1bab,  0x1bac,
 9114|  24.2k|      0x1bad,  0x1be6,  0x1be7,  0x1be8,  0x1be9,  0x1bea,  0x1beb,  0x1bec,
 9115|  24.2k|      0x1bed,  0x1bee,  0x1bef,  0x1bf0,  0x1bf1,  0x1bf2,  0x1bf3,  0x1c24,
 9116|  24.2k|      0x1c25,  0x1c26,  0x1c27,  0x1c28,  0x1c29,  0x1c2a,  0x1c2b,  0x1c2c,
 9117|  24.2k|      0x1c2d,  0x1c2e,  0x1c2f,  0x1c30,  0x1c31,  0x1c32,  0x1c33,  0x1c34,
 9118|  24.2k|      0x1c35,  0x1c36,  0x1c37,  0x1cd0,  0x1cd1,  0x1cd2,  0x1cd4,  0x1cd5,
 9119|  24.2k|      0x1cd6,  0x1cd7,  0x1cd8,  0x1cd9,  0x1cda,  0x1cdb,  0x1cdc,  0x1cdd,
 9120|  24.2k|      0x1cde,  0x1cdf,  0x1ce0,  0x1ce1,  0x1ce2,  0x1ce3,  0x1ce4,  0x1ce5,
 9121|  24.2k|      0x1ce6,  0x1ce7,  0x1ce8,  0x1ced,  0x1cf4,  0x1cf7,  0x1cf8,  0x1cf9,
 9122|  24.2k|      0x1dc0,  0x1dc1,  0x1dc2,  0x1dc3,  0x1dc4,  0x1dc5,  0x1dc6,  0x1dc7,
 9123|  24.2k|      0x1dc8,  0x1dc9,  0x1dca,  0x1dcb,  0x1dcc,  0x1dcd,  0x1dce,  0x1dcf,
 9124|  24.2k|      0x1dd0,  0x1dd1,  0x1dd2,  0x1dd3,  0x1dd4,  0x1dd5,  0x1dd6,  0x1dd7,
 9125|  24.2k|      0x1dd8,  0x1dd9,  0x1dda,  0x1ddb,  0x1ddc,  0x1ddd,  0x1dde,  0x1ddf,
 9126|  24.2k|      0x1de0,  0x1de1,  0x1de2,  0x1de3,  0x1de4,  0x1de5,  0x1de6,  0x1de7,
 9127|  24.2k|      0x1de8,  0x1de9,  0x1dea,  0x1deb,  0x1dec,  0x1ded,  0x1dee,  0x1def,
 9128|  24.2k|      0x1df0,  0x1df1,  0x1df2,  0x1df3,  0x1df4,  0x1df5,  0x1df6,  0x1df7,
 9129|  24.2k|      0x1df8,  0x1df9,  0x1dfb,  0x1dfc,  0x1dfd,  0x1dfe,  0x1dff,  0x20d0,
 9130|  24.2k|      0x20d1,  0x20d2,  0x20d3,  0x20d4,  0x20d5,  0x20d6,  0x20d7,  0x20d8,
 9131|  24.2k|      0x20d9,  0x20da,  0x20db,  0x20dc,  0x20dd,  0x20de,  0x20df,  0x20e0,
 9132|  24.2k|      0x20e1,  0x20e2,  0x20e3,  0x20e4,  0x20e5,  0x20e6,  0x20e7,  0x20e8,
 9133|  24.2k|      0x20e9,  0x20ea,  0x20eb,  0x20ec,  0x20ed,  0x20ee,  0x20ef,  0x20f0,
 9134|  24.2k|      0x2cef,  0x2cf0,  0x2cf1,  0x2d7f,  0x2de0,  0x2de1,  0x2de2,  0x2de3,
 9135|  24.2k|      0x2de4,  0x2de5,  0x2de6,  0x2de7,  0x2de8,  0x2de9,  0x2dea,  0x2deb,
 9136|  24.2k|      0x2dec,  0x2ded,  0x2dee,  0x2def,  0x2df0,  0x2df1,  0x2df2,  0x2df3,
 9137|  24.2k|      0x2df4,  0x2df5,  0x2df6,  0x2df7,  0x2df8,  0x2df9,  0x2dfa,  0x2dfb,
 9138|  24.2k|      0x2dfc,  0x2dfd,  0x2dfe,  0x2dff,  0x302a,  0x302b,  0x302c,  0x302d,
 9139|  24.2k|      0x302e,  0x302f,  0x3099,  0x309a,  0xa66f,  0xa670,  0xa671,  0xa672,
 9140|  24.2k|      0xa674,  0xa675,  0xa676,  0xa677,  0xa678,  0xa679,  0xa67a,  0xa67b,
 9141|  24.2k|      0xa67c,  0xa67d,  0xa69e,  0xa69f,  0xa6f0,  0xa6f1,  0xa802,  0xa806,
 9142|  24.2k|      0xa80b,  0xa823,  0xa824,  0xa825,  0xa826,  0xa827,  0xa82c,  0xa880,
 9143|  24.2k|      0xa881,  0xa8b4,  0xa8b5,  0xa8b6,  0xa8b7,  0xa8b8,  0xa8b9,  0xa8ba,
 9144|  24.2k|      0xa8bb,  0xa8bc,  0xa8bd,  0xa8be,  0xa8bf,  0xa8c0,  0xa8c1,  0xa8c2,
 9145|  24.2k|      0xa8c3,  0xa8c4,  0xa8c5,  0xa8e0,  0xa8e1,  0xa8e2,  0xa8e3,  0xa8e4,
 9146|  24.2k|      0xa8e5,  0xa8e6,  0xa8e7,  0xa8e8,  0xa8e9,  0xa8ea,  0xa8eb,  0xa8ec,
 9147|  24.2k|      0xa8ed,  0xa8ee,  0xa8ef,  0xa8f0,  0xa8f1,  0xa8ff,  0xa926,  0xa927,
 9148|  24.2k|      0xa928,  0xa929,  0xa92a,  0xa92b,  0xa92c,  0xa92d,  0xa947,  0xa948,
 9149|  24.2k|      0xa949,  0xa94a,  0xa94b,  0xa94c,  0xa94d,  0xa94e,  0xa94f,  0xa950,
 9150|  24.2k|      0xa951,  0xa952,  0xa953,  0xa980,  0xa981,  0xa982,  0xa983,  0xa9b3,
 9151|  24.2k|      0xa9b4,  0xa9b5,  0xa9b6,  0xa9b7,  0xa9b8,  0xa9b9,  0xa9ba,  0xa9bb,
 9152|  24.2k|      0xa9bc,  0xa9bd,  0xa9be,  0xa9bf,  0xa9c0,  0xa9e5,  0xaa29,  0xaa2a,
 9153|  24.2k|      0xaa2b,  0xaa2c,  0xaa2d,  0xaa2e,  0xaa2f,  0xaa30,  0xaa31,  0xaa32,
 9154|  24.2k|      0xaa33,  0xaa34,  0xaa35,  0xaa36,  0xaa43,  0xaa4c,  0xaa4d,  0xaa7b,
 9155|  24.2k|      0xaa7c,  0xaa7d,  0xaab0,  0xaab2,  0xaab3,  0xaab4,  0xaab7,  0xaab8,
 9156|  24.2k|      0xaabe,  0xaabf,  0xaac1,  0xaaeb,  0xaaec,  0xaaed,  0xaaee,  0xaaef,
 9157|  24.2k|      0xaaf5,  0xaaf6,  0xabe3,  0xabe4,  0xabe5,  0xabe6,  0xabe7,  0xabe8,
 9158|  24.2k|      0xabe9,  0xabea,  0xabec,  0xabed,  0xfb1e,  0xfe00,  0xfe01,  0xfe02,
 9159|  24.2k|      0xfe03,  0xfe04,  0xfe05,  0xfe06,  0xfe07,  0xfe08,  0xfe09,  0xfe0a,
 9160|  24.2k|      0xfe0b,  0xfe0c,  0xfe0d,  0xfe0e,  0xfe0f,  0xfe20,  0xfe21,  0xfe22,
 9161|  24.2k|      0xfe23,  0xfe24,  0xfe25,  0xfe26,  0xfe27,  0xfe28,  0xfe29,  0xfe2a,
 9162|  24.2k|      0xfe2b,  0xfe2c,  0xfe2d,  0xfe2e,  0xfe2f,  0x101fd, 0x102e0, 0x10376,
 9163|  24.2k|      0x10377, 0x10378, 0x10379, 0x1037a, 0x10a01, 0x10a02, 0x10a03, 0x10a05,
 9164|  24.2k|      0x10a06, 0x10a0c, 0x10a0d, 0x10a0e, 0x10a0f, 0x10a38, 0x10a39, 0x10a3a,
 9165|  24.2k|      0x10a3f, 0x10ae5, 0x10ae6, 0x10d24, 0x10d25, 0x10d26, 0x10d27, 0x10eab,
 9166|  24.2k|      0x10eac, 0x10f46, 0x10f47, 0x10f48, 0x10f49, 0x10f4a, 0x10f4b, 0x10f4c,
 9167|  24.2k|      0x10f4d, 0x10f4e, 0x10f4f, 0x10f50, 0x11000, 0x11001, 0x11002, 0x11038,
 9168|  24.2k|      0x11039, 0x1103a, 0x1103b, 0x1103c, 0x1103d, 0x1103e, 0x1103f, 0x11040,
 9169|  24.2k|      0x11041, 0x11042, 0x11043, 0x11044, 0x11045, 0x11046, 0x1107f, 0x11080,
 9170|  24.2k|      0x11081, 0x11082, 0x110b0, 0x110b1, 0x110b2, 0x110b3, 0x110b4, 0x110b5,
 9171|  24.2k|      0x110b6, 0x110b7, 0x110b8, 0x110b9, 0x110ba, 0x11100, 0x11101, 0x11102,
 9172|  24.2k|      0x11127, 0x11128, 0x11129, 0x1112a, 0x1112b, 0x1112c, 0x1112d, 0x1112e,
 9173|  24.2k|      0x1112f, 0x11130, 0x11131, 0x11132, 0x11133, 0x11134, 0x11145, 0x11146,
 9174|  24.2k|      0x11173, 0x11180, 0x11181, 0x11182, 0x111b3, 0x111b4, 0x111b5, 0x111b6,
 9175|  24.2k|      0x111b7, 0x111b8, 0x111b9, 0x111ba, 0x111bb, 0x111bc, 0x111bd, 0x111be,
 9176|  24.2k|      0x111bf, 0x111c0, 0x111c9, 0x111ca, 0x111cb, 0x111cc, 0x111ce, 0x111cf,
 9177|  24.2k|      0x1122c, 0x1122d, 0x1122e, 0x1122f, 0x11230, 0x11231, 0x11232, 0x11233,
 9178|  24.2k|      0x11234, 0x11235, 0x11236, 0x11237, 0x1123e, 0x112df, 0x112e0, 0x112e1,
 9179|  24.2k|      0x112e2, 0x112e3, 0x112e4, 0x112e5, 0x112e6, 0x112e7, 0x112e8, 0x112e9,
 9180|  24.2k|      0x112ea, 0x11300, 0x11301, 0x11302, 0x11303, 0x1133b, 0x1133c, 0x1133e,
 9181|  24.2k|      0x1133f, 0x11340, 0x11341, 0x11342, 0x11343, 0x11344, 0x11347, 0x11348,
 9182|  24.2k|      0x1134b, 0x1134c, 0x1134d, 0x11357, 0x11362, 0x11363, 0x11366, 0x11367,
 9183|  24.2k|      0x11368, 0x11369, 0x1136a, 0x1136b, 0x1136c, 0x11370, 0x11371, 0x11372,
 9184|  24.2k|      0x11373, 0x11374, 0x11435, 0x11436, 0x11437, 0x11438, 0x11439, 0x1143a,
 9185|  24.2k|      0x1143b, 0x1143c, 0x1143d, 0x1143e, 0x1143f, 0x11440, 0x11441, 0x11442,
 9186|  24.2k|      0x11443, 0x11444, 0x11445, 0x11446, 0x1145e, 0x114b0, 0x114b1, 0x114b2,
 9187|  24.2k|      0x114b3, 0x114b4, 0x114b5, 0x114b6, 0x114b7, 0x114b8, 0x114b9, 0x114ba,
 9188|  24.2k|      0x114bb, 0x114bc, 0x114bd, 0x114be, 0x114bf, 0x114c0, 0x114c1, 0x114c2,
 9189|  24.2k|      0x114c3, 0x115af, 0x115b0, 0x115b1, 0x115b2, 0x115b3, 0x115b4, 0x115b5,
 9190|  24.2k|      0x115b8, 0x115b9, 0x115ba, 0x115bb, 0x115bc, 0x115bd, 0x115be, 0x115bf,
 9191|  24.2k|      0x115c0, 0x115dc, 0x115dd, 0x11630, 0x11631, 0x11632, 0x11633, 0x11634,
 9192|  24.2k|      0x11635, 0x11636, 0x11637, 0x11638, 0x11639, 0x1163a, 0x1163b, 0x1163c,
 9193|  24.2k|      0x1163d, 0x1163e, 0x1163f, 0x11640, 0x116ab, 0x116ac, 0x116ad, 0x116ae,
 9194|  24.2k|      0x116af, 0x116b0, 0x116b1, 0x116b2, 0x116b3, 0x116b4, 0x116b5, 0x116b6,
 9195|  24.2k|      0x116b7, 0x1171d, 0x1171e, 0x1171f, 0x11720, 0x11721, 0x11722, 0x11723,
 9196|  24.2k|      0x11724, 0x11725, 0x11726, 0x11727, 0x11728, 0x11729, 0x1172a, 0x1172b,
 9197|  24.2k|      0x1182c, 0x1182d, 0x1182e, 0x1182f, 0x11830, 0x11831, 0x11832, 0x11833,
 9198|  24.2k|      0x11834, 0x11835, 0x11836, 0x11837, 0x11838, 0x11839, 0x1183a, 0x11930,
 9199|  24.2k|      0x11931, 0x11932, 0x11933, 0x11934, 0x11935, 0x11937, 0x11938, 0x1193b,
 9200|  24.2k|      0x1193c, 0x1193d, 0x1193e, 0x11940, 0x11942, 0x11943, 0x119d1, 0x119d2,
 9201|  24.2k|      0x119d3, 0x119d4, 0x119d5, 0x119d6, 0x119d7, 0x119da, 0x119db, 0x119dc,
 9202|  24.2k|      0x119dd, 0x119de, 0x119df, 0x119e0, 0x119e4, 0x11a01, 0x11a02, 0x11a03,
 9203|  24.2k|      0x11a04, 0x11a05, 0x11a06, 0x11a07, 0x11a08, 0x11a09, 0x11a0a, 0x11a33,
 9204|  24.2k|      0x11a34, 0x11a35, 0x11a36, 0x11a37, 0x11a38, 0x11a39, 0x11a3b, 0x11a3c,
 9205|  24.2k|      0x11a3d, 0x11a3e, 0x11a47, 0x11a51, 0x11a52, 0x11a53, 0x11a54, 0x11a55,
 9206|  24.2k|      0x11a56, 0x11a57, 0x11a58, 0x11a59, 0x11a5a, 0x11a5b, 0x11a8a, 0x11a8b,
 9207|  24.2k|      0x11a8c, 0x11a8d, 0x11a8e, 0x11a8f, 0x11a90, 0x11a91, 0x11a92, 0x11a93,
 9208|  24.2k|      0x11a94, 0x11a95, 0x11a96, 0x11a97, 0x11a98, 0x11a99, 0x11c2f, 0x11c30,
 9209|  24.2k|      0x11c31, 0x11c32, 0x11c33, 0x11c34, 0x11c35, 0x11c36, 0x11c38, 0x11c39,
 9210|  24.2k|      0x11c3a, 0x11c3b, 0x11c3c, 0x11c3d, 0x11c3e, 0x11c3f, 0x11c92, 0x11c93,
 9211|  24.2k|      0x11c94, 0x11c95, 0x11c96, 0x11c97, 0x11c98, 0x11c99, 0x11c9a, 0x11c9b,
 9212|  24.2k|      0x11c9c, 0x11c9d, 0x11c9e, 0x11c9f, 0x11ca0, 0x11ca1, 0x11ca2, 0x11ca3,
 9213|  24.2k|      0x11ca4, 0x11ca5, 0x11ca6, 0x11ca7, 0x11ca9, 0x11caa, 0x11cab, 0x11cac,
 9214|  24.2k|      0x11cad, 0x11cae, 0x11caf, 0x11cb0, 0x11cb1, 0x11cb2, 0x11cb3, 0x11cb4,
 9215|  24.2k|      0x11cb5, 0x11cb6, 0x11d31, 0x11d32, 0x11d33, 0x11d34, 0x11d35, 0x11d36,
 9216|  24.2k|      0x11d3a, 0x11d3c, 0x11d3d, 0x11d3f, 0x11d40, 0x11d41, 0x11d42, 0x11d43,
 9217|  24.2k|      0x11d44, 0x11d45, 0x11d47, 0x11d8a, 0x11d8b, 0x11d8c, 0x11d8d, 0x11d8e,
 9218|  24.2k|      0x11d90, 0x11d91, 0x11d93, 0x11d94, 0x11d95, 0x11d96, 0x11d97, 0x11ef3,
 9219|  24.2k|      0x11ef4, 0x11ef5, 0x11ef6, 0x16af0, 0x16af1, 0x16af2, 0x16af3, 0x16af4,
 9220|  24.2k|      0x16b30, 0x16b31, 0x16b32, 0x16b33, 0x16b34, 0x16b35, 0x16b36, 0x16f4f,
 9221|  24.2k|      0x16f51, 0x16f52, 0x16f53, 0x16f54, 0x16f55, 0x16f56, 0x16f57, 0x16f58,
 9222|  24.2k|      0x16f59, 0x16f5a, 0x16f5b, 0x16f5c, 0x16f5d, 0x16f5e, 0x16f5f, 0x16f60,
 9223|  24.2k|      0x16f61, 0x16f62, 0x16f63, 0x16f64, 0x16f65, 0x16f66, 0x16f67, 0x16f68,
 9224|  24.2k|      0x16f69, 0x16f6a, 0x16f6b, 0x16f6c, 0x16f6d, 0x16f6e, 0x16f6f, 0x16f70,
 9225|  24.2k|      0x16f71, 0x16f72, 0x16f73, 0x16f74, 0x16f75, 0x16f76, 0x16f77, 0x16f78,
 9226|  24.2k|      0x16f79, 0x16f7a, 0x16f7b, 0x16f7c, 0x16f7d, 0x16f7e, 0x16f7f, 0x16f80,
 9227|  24.2k|      0x16f81, 0x16f82, 0x16f83, 0x16f84, 0x16f85, 0x16f86, 0x16f87, 0x16f8f,
 9228|  24.2k|      0x16f90, 0x16f91, 0x16f92, 0x16fe4, 0x16ff0, 0x16ff1, 0x1bc9d, 0x1bc9e,
 9229|  24.2k|      0x1d165, 0x1d166, 0x1d167, 0x1d168, 0x1d169, 0x1d16d, 0x1d16e, 0x1d16f,
 9230|  24.2k|      0x1d170, 0x1d171, 0x1d172, 0x1d17b, 0x1d17c, 0x1d17d, 0x1d17e, 0x1d17f,
 9231|  24.2k|      0x1d180, 0x1d181, 0x1d182, 0x1d185, 0x1d186, 0x1d187, 0x1d188, 0x1d189,
 9232|  24.2k|      0x1d18a, 0x1d18b, 0x1d1aa, 0x1d1ab, 0x1d1ac, 0x1d1ad, 0x1d242, 0x1d243,
 9233|  24.2k|      0x1d244, 0x1da00, 0x1da01, 0x1da02, 0x1da03, 0x1da04, 0x1da05, 0x1da06,
 9234|  24.2k|      0x1da07, 0x1da08, 0x1da09, 0x1da0a, 0x1da0b, 0x1da0c, 0x1da0d, 0x1da0e,
 9235|  24.2k|      0x1da0f, 0x1da10, 0x1da11, 0x1da12, 0x1da13, 0x1da14, 0x1da15, 0x1da16,
 9236|  24.2k|      0x1da17, 0x1da18, 0x1da19, 0x1da1a, 0x1da1b, 0x1da1c, 0x1da1d, 0x1da1e,
 9237|  24.2k|      0x1da1f, 0x1da20, 0x1da21, 0x1da22, 0x1da23, 0x1da24, 0x1da25, 0x1da26,
 9238|  24.2k|      0x1da27, 0x1da28, 0x1da29, 0x1da2a, 0x1da2b, 0x1da2c, 0x1da2d, 0x1da2e,
 9239|  24.2k|      0x1da2f, 0x1da30, 0x1da31, 0x1da32, 0x1da33, 0x1da34, 0x1da35, 0x1da36,
 9240|  24.2k|      0x1da3b, 0x1da3c, 0x1da3d, 0x1da3e, 0x1da3f, 0x1da40, 0x1da41, 0x1da42,
 9241|  24.2k|      0x1da43, 0x1da44, 0x1da45, 0x1da46, 0x1da47, 0x1da48, 0x1da49, 0x1da4a,
 9242|  24.2k|      0x1da4b, 0x1da4c, 0x1da4d, 0x1da4e, 0x1da4f, 0x1da50, 0x1da51, 0x1da52,
 9243|  24.2k|      0x1da53, 0x1da54, 0x1da55, 0x1da56, 0x1da57, 0x1da58, 0x1da59, 0x1da5a,
 9244|  24.2k|      0x1da5b, 0x1da5c, 0x1da5d, 0x1da5e, 0x1da5f, 0x1da60, 0x1da61, 0x1da62,
 9245|  24.2k|      0x1da63, 0x1da64, 0x1da65, 0x1da66, 0x1da67, 0x1da68, 0x1da69, 0x1da6a,
 9246|  24.2k|      0x1da6b, 0x1da6c, 0x1da75, 0x1da84, 0x1da9b, 0x1da9c, 0x1da9d, 0x1da9e,
 9247|  24.2k|      0x1da9f, 0x1daa1, 0x1daa2, 0x1daa3, 0x1daa4, 0x1daa5, 0x1daa6, 0x1daa7,
 9248|  24.2k|      0x1daa8, 0x1daa9, 0x1daaa, 0x1daab, 0x1daac, 0x1daad, 0x1daae, 0x1daaf,
 9249|  24.2k|      0x1e000, 0x1e001, 0x1e002, 0x1e003, 0x1e004, 0x1e005, 0x1e006, 0x1e008,
 9250|  24.2k|      0x1e009, 0x1e00a, 0x1e00b, 0x1e00c, 0x1e00d, 0x1e00e, 0x1e00f, 0x1e010,
 9251|  24.2k|      0x1e011, 0x1e012, 0x1e013, 0x1e014, 0x1e015, 0x1e016, 0x1e017, 0x1e018,
 9252|  24.2k|      0x1e01b, 0x1e01c, 0x1e01d, 0x1e01e, 0x1e01f, 0x1e020, 0x1e021, 0x1e023,
 9253|  24.2k|      0x1e024, 0x1e026, 0x1e027, 0x1e028, 0x1e029, 0x1e02a, 0x1e130, 0x1e131,
 9254|  24.2k|      0x1e132, 0x1e133, 0x1e134, 0x1e135, 0x1e136, 0x1e2ec, 0x1e2ed, 0x1e2ee,
 9255|  24.2k|      0x1e2ef, 0x1e8d0, 0x1e8d1, 0x1e8d2, 0x1e8d3, 0x1e8d4, 0x1e8d5, 0x1e8d6,
 9256|  24.2k|      0x1e944, 0x1e945, 0x1e946, 0x1e947, 0x1e948, 0x1e949, 0x1e94a, 0xe0100,
 9257|  24.2k|      0xe0101, 0xe0102, 0xe0103, 0xe0104, 0xe0105, 0xe0106, 0xe0107, 0xe0108,
 9258|  24.2k|      0xe0109, 0xe010a, 0xe010b, 0xe010c, 0xe010d, 0xe010e, 0xe010f, 0xe0110,
 9259|  24.2k|      0xe0111, 0xe0112, 0xe0113, 0xe0114, 0xe0115, 0xe0116, 0xe0117, 0xe0118,
 9260|  24.2k|      0xe0119, 0xe011a, 0xe011b, 0xe011c, 0xe011d, 0xe011e, 0xe011f, 0xe0120,
 9261|  24.2k|      0xe0121, 0xe0122, 0xe0123, 0xe0124, 0xe0125, 0xe0126, 0xe0127, 0xe0128,
 9262|  24.2k|      0xe0129, 0xe012a, 0xe012b, 0xe012c, 0xe012d, 0xe012e, 0xe012f, 0xe0130,
 9263|  24.2k|      0xe0131, 0xe0132, 0xe0133, 0xe0134, 0xe0135, 0xe0136, 0xe0137, 0xe0138,
 9264|  24.2k|      0xe0139, 0xe013a, 0xe013b, 0xe013c, 0xe013d, 0xe013e, 0xe013f, 0xe0140,
 9265|  24.2k|      0xe0141, 0xe0142, 0xe0143, 0xe0144, 0xe0145, 0xe0146, 0xe0147, 0xe0148,
 9266|  24.2k|      0xe0149, 0xe014a, 0xe014b, 0xe014c, 0xe014d, 0xe014e, 0xe014f, 0xe0150,
 9267|  24.2k|      0xe0151, 0xe0152, 0xe0153, 0xe0154, 0xe0155, 0xe0156, 0xe0157, 0xe0158,
 9268|  24.2k|      0xe0159, 0xe015a, 0xe015b, 0xe015c, 0xe015d, 0xe015e, 0xe015f, 0xe0160,
 9269|  24.2k|      0xe0161, 0xe0162, 0xe0163, 0xe0164, 0xe0165, 0xe0166, 0xe0167, 0xe0168,
 9270|  24.2k|      0xe0169, 0xe016a, 0xe016b, 0xe016c, 0xe016d, 0xe016e, 0xe016f, 0xe0170,
 9271|  24.2k|      0xe0171, 0xe0172, 0xe0173, 0xe0174, 0xe0175, 0xe0176, 0xe0177, 0xe0178,
 9272|  24.2k|      0xe0179, 0xe017a, 0xe017b, 0xe017c, 0xe017d, 0xe017e, 0xe017f, 0xe0180,
 9273|  24.2k|      0xe0181, 0xe0182, 0xe0183, 0xe0184, 0xe0185, 0xe0186, 0xe0187, 0xe0188,
 9274|  24.2k|      0xe0189, 0xe018a, 0xe018b, 0xe018c, 0xe018d, 0xe018e, 0xe018f, 0xe0190,
 9275|  24.2k|      0xe0191, 0xe0192, 0xe0193, 0xe0194, 0xe0195, 0xe0196, 0xe0197, 0xe0198,
 9276|  24.2k|      0xe0199, 0xe019a, 0xe019b, 0xe019c, 0xe019d, 0xe019e, 0xe019f, 0xe01a0,
 9277|  24.2k|      0xe01a1, 0xe01a2, 0xe01a3, 0xe01a4, 0xe01a5, 0xe01a6, 0xe01a7, 0xe01a8,
 9278|  24.2k|      0xe01a9, 0xe01aa, 0xe01ab, 0xe01ac, 0xe01ad, 0xe01ae, 0xe01af, 0xe01b0,
 9279|  24.2k|      0xe01b1, 0xe01b2, 0xe01b3, 0xe01b4, 0xe01b5, 0xe01b6, 0xe01b7, 0xe01b8,
 9280|  24.2k|      0xe01b9, 0xe01ba, 0xe01bb, 0xe01bc, 0xe01bd, 0xe01be, 0xe01bf, 0xe01c0,
 9281|  24.2k|      0xe01c1, 0xe01c2, 0xe01c3, 0xe01c4, 0xe01c5, 0xe01c6, 0xe01c7, 0xe01c8,
 9282|  24.2k|      0xe01c9, 0xe01ca, 0xe01cb, 0xe01cc, 0xe01cd, 0xe01ce, 0xe01cf, 0xe01d0,
 9283|  24.2k|      0xe01d1, 0xe01d2, 0xe01d3, 0xe01d4, 0xe01d5, 0xe01d6, 0xe01d7, 0xe01d8,
 9284|  24.2k|      0xe01d9, 0xe01da, 0xe01db, 0xe01dc, 0xe01dd, 0xe01de, 0xe01df, 0xe01e0,
 9285|  24.2k|      0xe01e1, 0xe01e2, 0xe01e3, 0xe01e4, 0xe01e5, 0xe01e6, 0xe01e7, 0xe01e8,
 9286|  24.2k|      0xe01e9, 0xe01ea, 0xe01eb, 0xe01ec, 0xe01ed, 0xe01ee, 0xe01ef};
 9287|  24.2k|  if (std::binary_search(std::begin(combining), std::end(combining),
  ------------------
  |  Branch (9287:7): [True: 62, False: 24.1k]
  ------------------
 9288|  24.2k|                         label.front())) {
 9289|     62|    return false;
 9290|     62|  }
 9291|       |  // We verify this next step as part of the mapping:
 9292|       |  // ---------------------------------------------
 9293|       |  // Each code point in the label must only have certain status values
 9294|       |  // according to Section 5, IDNA Mapping Table:
 9295|       |  // - For Transitional Processing, each value must be valid.
 9296|       |  // - For Nontransitional Processing, each value must be either valid or
 9297|       |  // deviation.
 9298|       |
 9299|       |  // If CheckJoiners, the label must satisfy the ContextJ rules from Appendix
 9300|       |  // A, in The Unicode Code Points and Internationalized Domain Names for
 9301|       |  // Applications (IDNA) [IDNA2008].
 9302|  24.1k|  constexpr static uint32_t virama[] = {
 9303|  24.1k|      0x094D,  0x09CD,  0x0A4D,  0x0ACD,  0x0B4D,  0x0BCD,  0x0C4D,  0x0CCD,
 9304|  24.1k|      0x0D3B,  0x0D3C,  0x0D4D,  0x0DCA,  0x0E3A,  0x0EBA,  0x0F84,  0x1039,
 9305|  24.1k|      0x103A,  0x1714,  0x1734,  0x17D2,  0x1A60,  0x1B44,  0x1BAA,  0x1BAB,
 9306|  24.1k|      0x1BF2,  0x1BF3,  0x2D7F,  0xA806,  0xA82C,  0xA8C4,  0xA953,  0xA9C0,
 9307|  24.1k|      0xAAF6,  0xABED,  0x10A3F, 0x11046, 0x1107F, 0x110B9, 0x11133, 0x11134,
 9308|  24.1k|      0x111C0, 0x11235, 0x112EA, 0x1134D, 0x11442, 0x114C2, 0x115BF, 0x1163F,
 9309|  24.1k|      0x116B6, 0x1172B, 0x11839, 0x1193D, 0x1193E, 0x119E0, 0x11A34, 0x11A47,
 9310|  24.1k|      0x11A99, 0x11C3F, 0x11D44, 0x11D45, 0x11D97};
 9311|  24.1k|  constexpr static uint32_t R[] = {
 9312|  24.1k|      0x622, 0x623, 0x624, 0x625, 0x627, 0x629, 0x62f, 0x630, 0x631,
 9313|  24.1k|      0x632, 0x648, 0x671, 0x672, 0x673, 0x675, 0x676, 0x677, 0x688,
 9314|  24.1k|      0x689, 0x68a, 0x68b, 0x68c, 0x68d, 0x68e, 0x68f, 0x690, 0x691,
 9315|  24.1k|      0x692, 0x693, 0x694, 0x695, 0x696, 0x697, 0x698, 0x699, 0x6c0,
 9316|  24.1k|      0x6c3, 0x6c4, 0x6c5, 0x6c6, 0x6c7, 0x6c8, 0x6c9, 0x6ca, 0x6cb,
 9317|  24.1k|      0x6cd, 0x6cf, 0x6d2, 0x6d3, 0x6d5, 0x6ee, 0x6ef, 0x710, 0x715,
 9318|  24.1k|      0x716, 0x717, 0x718, 0x719, 0x71e, 0x728, 0x72a, 0x72c, 0x72f,
 9319|  24.1k|      0x74d, 0x759, 0x75a, 0x75b, 0x854, 0x8aa, 0x8ab, 0x8ac};
 9320|  24.1k|  constexpr static uint32_t L[] = {0xa872};
 9321|  24.1k|  constexpr static uint32_t D[] = {
 9322|  24.1k|      0x620,  0x626,  0x628,  0x62a,  0x62b,  0x62c,  0x62d,  0x62e,  0x633,
 9323|  24.1k|      0x634,  0x635,  0x636,  0x637,  0x638,  0x639,  0x63a,  0x63b,  0x63c,
 9324|  24.1k|      0x63d,  0x63e,  0x63f,  0x641,  0x642,  0x643,  0x644,  0x645,  0x646,
 9325|  24.1k|      0x647,  0x649,  0x64a,  0x66e,  0x66f,  0x678,  0x679,  0x67a,  0x67b,
 9326|  24.1k|      0x67c,  0x67d,  0x67e,  0x67f,  0x680,  0x681,  0x682,  0x683,  0x684,
 9327|  24.1k|      0x685,  0x686,  0x687,  0x69a,  0x69b,  0x69c,  0x69d,  0x69e,  0x69f,
 9328|  24.1k|      0x6a0,  0x6a1,  0x6a2,  0x6a3,  0x6a4,  0x6a5,  0x6a6,  0x6a7,  0x6a8,
 9329|  24.1k|      0x6a9,  0x6aa,  0x6ab,  0x6ac,  0x6ad,  0x6ae,  0x6af,  0x6b0,  0x6b1,
 9330|  24.1k|      0x6b2,  0x6b3,  0x6b4,  0x6b5,  0x6b6,  0x6b7,  0x6b8,  0x6b9,  0x6ba,
 9331|  24.1k|      0x6bb,  0x6bc,  0x6bd,  0x6be,  0x6bf,  0x6c1,  0x6c2,  0x6cc,  0x6ce,
 9332|  24.1k|      0x6d0,  0x6d1,  0x6fa,  0x6fb,  0x6fc,  0x6ff,  0x712,  0x713,  0x714,
 9333|  24.1k|      0x71a,  0x71b,  0x71c,  0x71d,  0x71f,  0x720,  0x721,  0x722,  0x723,
 9334|  24.1k|      0x724,  0x725,  0x726,  0x727,  0x729,  0x72b,  0x72d,  0x72e,  0x74e,
 9335|  24.1k|      0x74f,  0x750,  0x751,  0x752,  0x753,  0x754,  0x755,  0x756,  0x757,
 9336|  24.1k|      0x758,  0x75c,  0x75d,  0x75e,  0x75f,  0x760,  0x761,  0x762,  0x763,
 9337|  24.1k|      0x764,  0x765,  0x766,  0x850,  0x851,  0x852,  0x853,  0x855,  0x8a0,
 9338|  24.1k|      0x8a2,  0x8a3,  0x8a4,  0x8a5,  0x8a6,  0x8a7,  0x8a8,  0x8a9,  0x1807,
 9339|  24.1k|      0x1820, 0x1821, 0x1822, 0x1823, 0x1824, 0x1825, 0x1826, 0x1827, 0x1828,
 9340|  24.1k|      0x1829, 0x182a, 0x182b, 0x182c, 0x182d, 0x182e, 0x182f, 0x1830, 0x1831,
 9341|  24.1k|      0x1832, 0x1833, 0x1834, 0x1835, 0x1836, 0x1837, 0x1838, 0x1839, 0x183a,
 9342|  24.1k|      0x183b, 0x183c, 0x183d, 0x183e, 0x183f, 0x1840, 0x1841, 0x1842, 0x1843,
 9343|  24.1k|      0x1844, 0x1845, 0x1846, 0x1847, 0x1848, 0x1849, 0x184a, 0x184b, 0x184c,
 9344|  24.1k|      0x184d, 0x184e, 0x184f, 0x1850, 0x1851, 0x1852, 0x1853, 0x1854, 0x1855,
 9345|  24.1k|      0x1856, 0x1857, 0x1858, 0x1859, 0x185a, 0x185b, 0x185c, 0x185d, 0x185e,
 9346|  24.1k|      0x185f, 0x1860, 0x1861, 0x1862, 0x1863, 0x1864, 0x1865, 0x1866, 0x1867,
 9347|  24.1k|      0x1868, 0x1869, 0x186a, 0x186b, 0x186c, 0x186d, 0x186e, 0x186f, 0x1870,
 9348|  24.1k|      0x1871, 0x1872, 0x1873, 0x1874, 0x1875, 0x1876, 0x1877, 0x1887, 0x1888,
 9349|  24.1k|      0x1889, 0x188a, 0x188b, 0x188c, 0x188d, 0x188e, 0x188f, 0x1890, 0x1891,
 9350|  24.1k|      0x1892, 0x1893, 0x1894, 0x1895, 0x1896, 0x1897, 0x1898, 0x1899, 0x189a,
 9351|  24.1k|      0x189b, 0x189c, 0x189d, 0x189e, 0x189f, 0x18a0, 0x18a1, 0x18a2, 0x18a3,
 9352|  24.1k|      0x18a4, 0x18a5, 0x18a6, 0x18a7, 0x18a8, 0x18aa, 0xa840, 0xa841, 0xa842,
 9353|  24.1k|      0xa843, 0xa844, 0xa845, 0xa846, 0xa847, 0xa848, 0xa849, 0xa84a, 0xa84b,
 9354|  24.1k|      0xa84c, 0xa84d, 0xa84e, 0xa84f, 0xa850, 0xa851, 0xa852, 0xa853, 0xa854,
 9355|  24.1k|      0xa855, 0xa856, 0xa857, 0xa858, 0xa859, 0xa85a, 0xa85b, 0xa85c, 0xa85d,
 9356|  24.1k|      0xa85e, 0xa85f, 0xa860, 0xa861, 0xa862, 0xa863, 0xa864, 0xa865, 0xa866,
 9357|  24.1k|      0xa867, 0xa868, 0xa869, 0xa86a, 0xa86b, 0xa86c, 0xa86d, 0xa86e, 0xa86f,
 9358|  24.1k|      0xa870, 0xa871};
 9359|       |
 9360|   171k|  for (size_t i = 0; i < label.size(); i++) {
  ------------------
  |  Branch (9360:22): [True: 148k, False: 22.7k]
  ------------------
 9361|   148k|    uint32_t c = label[i];
 9362|   148k|    if (c == 0x200c) {
  ------------------
  |  Branch (9362:9): [True: 1.01k, False: 147k]
  ------------------
 9363|  1.01k|      if (i > 0) {
  ------------------
  |  Branch (9363:11): [True: 1.01k, False: 6]
  ------------------
 9364|  1.01k|        if (std::binary_search(std::begin(virama), std::end(virama),
  ------------------
  |  Branch (9364:13): [True: 203, False: 809]
  ------------------
 9365|  1.01k|                               label[i - 1])) {
 9366|    203|          return true;
 9367|    203|        }
 9368|  1.01k|      }
 9369|    815|      if ((i == 0) || (i + 1 >= label.size())) {
  ------------------
  |  Branch (9369:11): [True: 6, False: 809]
  |  Branch (9369:23): [True: 81, False: 728]
  ------------------
 9370|     87|        return false;
 9371|     87|      }
 9372|       |      // we go backward looking for L or D
 9373|    728|      auto is_l_or_d = [](uint32_t code) {
 9374|    728|        return std::binary_search(std::begin(L), std::end(L), code) ||
 9375|    728|               std::binary_search(std::begin(D), std::end(D), code);
 9376|    728|      };
 9377|    728|      auto is_r_or_d = [](uint32_t code) {
 9378|    728|        return std::binary_search(std::begin(R), std::end(R), code) ||
 9379|    728|               std::binary_search(std::begin(D), std::end(D), code);
 9380|    728|      };
 9381|    728|      std::u32string_view before = label.substr(0, i);
 9382|    728|      std::u32string_view after = label.substr(i + 1);
 9383|    728|      return (std::find_if(before.begin(), before.end(), is_l_or_d) !=
  ------------------
  |  Branch (9383:14): [True: 640, False: 88]
  ------------------
 9384|    728|              before.end()) &&
 9385|    728|             (std::find_if(after.begin(), after.end(), is_r_or_d) !=
  ------------------
  |  Branch (9385:14): [True: 513, False: 127]
  ------------------
 9386|    640|              after.end());
 9387|   147k|    } else if (c == 0x200d) {
  ------------------
  |  Branch (9387:16): [True: 423, False: 147k]
  ------------------
 9388|    423|      if (i > 0) {
  ------------------
  |  Branch (9388:11): [True: 411, False: 12]
  ------------------
 9389|    411|        if (std::binary_search(std::begin(virama), std::end(virama),
  ------------------
  |  Branch (9389:13): [True: 355, False: 56]
  ------------------
 9390|    411|                               label[i - 1])) {
 9391|    355|          return true;
 9392|    355|        }
 9393|    411|      }
 9394|     68|      return false;
 9395|    423|    }
 9396|   148k|  }
 9397|       |
 9398|       |  // If CheckBidi, and if the domain name is a  Bidi domain name, then the label
 9399|       |  // must satisfy all six of the numbered conditions in [IDNA2008] RFC 5893,
 9400|       |  // Section 2.
 9401|       |
 9402|       |  // The following rule, consisting of six conditions, applies to labels
 9403|       |  // in Bidi domain names.  The requirements that this rule satisfies are
 9404|       |  // described in Section 3.  All of the conditions must be satisfied for
 9405|       |  // the rule to be satisfied.
 9406|       |  //
 9407|       |  //  1.  The first character must be a character with Bidi property L, R,
 9408|       |  //     or AL.  If it has the R or AL property, it is an RTL label; if it
 9409|       |  //     has the L property, it is an LTR label.
 9410|       |  //
 9411|       |  //  2.  In an RTL label, only characters with the Bidi properties R, AL,
 9412|       |  //      AN, EN, ES, CS, ET, ON, BN, or NSM are allowed.
 9413|       |  //
 9414|       |  //   3.  In an RTL label, the end of the label must be a character with
 9415|       |  //       Bidi property R, AL, EN, or AN, followed by zero or more
 9416|       |  //       characters with Bidi property NSM.
 9417|       |  //
 9418|       |  //   4.  In an RTL label, if an EN is present, no AN may be present, and
 9419|       |  //       vice versa.
 9420|       |  //
 9421|       |  //  5.  In an LTR label, only characters with the Bidi properties L, EN,
 9422|       |  //       ES, CS, ET, ON, BN, or NSM are allowed.
 9423|       |  //
 9424|       |  //   6.  In an LTR label, the end of the label must be a character with
 9425|       |  //       Bidi property L or EN, followed by zero or more characters with
 9426|       |  //       Bidi property NSM.
 9427|       |
 9428|  22.7k|  size_t last_non_nsm_char = find_last_not_of_nsm(label);
 9429|  22.7k|  if (last_non_nsm_char == std::u32string_view::npos) {
  ------------------
  |  Branch (9429:7): [True: 0, False: 22.7k]
  ------------------
 9430|      0|    return false;
 9431|      0|  }
 9432|       |
 9433|       |  // A "Bidi domain name" is a domain name that contains at least one RTL label.
 9434|       |  // The following rule, consisting of six conditions, applies to labels in Bidi
 9435|       |  // domain names.
 9436|  22.7k|  if (is_rtl_label(label)) {
  ------------------
  |  Branch (9436:7): [True: 1.96k, False: 20.7k]
  ------------------
 9437|       |    // The first character must be a character with Bidi property L, R,
 9438|       |    // or AL. If it has the R or AL property, it is an RTL label; if it
 9439|       |    // has the L property, it is an LTR label.
 9440|       |
 9441|  1.96k|    if (find_direction(label[0]) == direction::L) {
  ------------------
  |  Branch (9441:9): [True: 484, False: 1.48k]
  ------------------
 9442|       |      // Eval as LTR
 9443|       |
 9444|       |      // In an LTR label, only characters with the Bidi properties L, EN,
 9445|       |      // ES, CS, ET, ON, BN, or NSM are allowed.
 9446|  3.00k|      for (size_t i = 0; i < last_non_nsm_char; i++) {
  ------------------
  |  Branch (9446:26): [True: 2.61k, False: 392]
  ------------------
 9447|  2.61k|        const direction d = find_direction(label[i]);
 9448|  2.61k|        if (!(d == direction::L || d == direction::EN || d == direction::ES ||
  ------------------
  |  Branch (9448:15): [True: 995, False: 1.61k]
  |  Branch (9448:36): [True: 208, False: 1.40k]
  |  Branch (9448:58): [True: 177, False: 1.23k]
  ------------------
 9449|  2.61k|              d == direction::CS || d == direction::ET || d == direction::ON ||
  ------------------
  |  Branch (9449:15): [True: 192, False: 1.03k]
  |  Branch (9449:37): [True: 227, False: 812]
  |  Branch (9449:59): [True: 194, False: 618]
  ------------------
 9450|  2.61k|              d == direction::BN || d == direction::NSM)) {
  ------------------
  |  Branch (9450:15): [True: 326, False: 292]
  |  Branch (9450:37): [True: 200, False: 92]
  ------------------
 9451|     92|          return false;
 9452|     92|        }
 9453|       |
 9454|  2.51k|        if ((i == last_non_nsm_char) &&
  ------------------
  |  Branch (9454:13): [True: 0, False: 2.51k]
  ------------------
 9455|  2.51k|            !(d == direction::L || d == direction::EN)) {
  ------------------
  |  Branch (9455:15): [True: 0, False: 0]
  |  Branch (9455:36): [True: 0, False: 0]
  ------------------
 9456|      0|          return false;
 9457|      0|        }
 9458|  2.51k|      }
 9459|       |
 9460|    392|      return true;
 9461|       |
 9462|  1.48k|    } else {
 9463|       |      // Eval as RTL
 9464|       |
 9465|  1.48k|      bool has_an = false;
 9466|  1.48k|      bool has_en = false;
 9467|  4.87k|      for (size_t i = 0; i <= last_non_nsm_char; i++) {
  ------------------
  |  Branch (9467:26): [True: 3.54k, False: 1.33k]
  ------------------
 9468|  3.54k|        const direction d = find_direction(label[i]);
 9469|       |
 9470|       |        // In an RTL label, if an EN is present, no AN may be present, and vice
 9471|       |        // versa.
 9472|  3.54k|        if ((d == direction::EN && ((has_en = true) && has_an)) ||
  ------------------
  |  Branch (9472:14): [True: 386, False: 3.15k]
  |  Branch (9472:37): [True: 386, False: 0]
  |  Branch (9472:56): [True: 9, False: 377]
  ------------------
 9473|  3.54k|            (d == direction::AN && ((has_an = true) && has_en))) {
  ------------------
  |  Branch (9473:14): [True: 579, False: 2.95k]
  |  Branch (9473:37): [True: 579, False: 0]
  |  Branch (9473:56): [True: 6, False: 573]
  ------------------
 9474|     15|          return false;
 9475|     15|        }
 9476|       |
 9477|  3.52k|        if (!(d == direction::R || d == direction::AL || d == direction::AN ||
  ------------------
  |  Branch (9477:15): [True: 461, False: 3.06k]
  |  Branch (9477:36): [True: 956, False: 2.10k]
  |  Branch (9477:58): [True: 573, False: 1.53k]
  ------------------
 9478|  3.52k|              d == direction::EN || d == direction::ES || d == direction::CS ||
  ------------------
  |  Branch (9478:15): [True: 377, False: 1.15k]
  |  Branch (9478:37): [True: 252, False: 907]
  |  Branch (9478:59): [True: 205, False: 702]
  ------------------
 9479|  3.52k|              d == direction::ET || d == direction::ON || d == direction::BN ||
  ------------------
  |  Branch (9479:15): [True: 84, False: 618]
  |  Branch (9479:37): [True: 66, False: 552]
  |  Branch (9479:59): [True: 249, False: 303]
  ------------------
 9480|  3.52k|              d == direction::NSM)) {
  ------------------
  |  Branch (9480:15): [True: 197, False: 106]
  ------------------
 9481|    106|          return false;
 9482|    106|        }
 9483|       |
 9484|  3.42k|        if (i == last_non_nsm_char &&
  ------------------
  |  Branch (9484:13): [True: 1.36k, False: 2.05k]
  ------------------
 9485|  3.42k|            !(d == direction::R || d == direction::AL || d == direction::AN ||
  ------------------
  |  Branch (9485:15): [True: 217, False: 1.14k]
  |  Branch (9485:36): [True: 485, False: 662]
  |  Branch (9485:58): [True: 422, False: 240]
  ------------------
 9486|  1.36k|              d == direction::EN)) {
  ------------------
  |  Branch (9486:15): [True: 208, False: 32]
  ------------------
 9487|     32|          return false;
 9488|     32|        }
 9489|  3.42k|      }
 9490|       |
 9491|  1.33k|      return true;
 9492|  1.48k|    }
 9493|  1.96k|  }
 9494|       |
 9495|  20.7k|  return true;
 9496|  22.7k|}
_ZN3ada4idna8to_asciiENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9622|  17.0k|std::string to_ascii(std::string_view ut8_string) {
 9623|  17.0k|  if (is_ascii(ut8_string)) {
  ------------------
  |  Branch (9623:7): [True: 10.2k, False: 6.80k]
  ------------------
 9624|  10.2k|    return from_ascii_to_ascii(ut8_string);
 9625|  10.2k|  }
 9626|  6.80k|  static const std::string error = "";
 9627|       |  // We convert to UTF-32
 9628|  6.80k|  size_t utf32_length =
 9629|  6.80k|      ada::idna::utf32_length_from_utf8(ut8_string.data(), ut8_string.size());
 9630|  6.80k|  std::u32string utf32(utf32_length, '\0');
 9631|  6.80k|  size_t actual_utf32_length = ada::idna::utf8_to_utf32(
 9632|  6.80k|      ut8_string.data(), ut8_string.size(), utf32.data());
 9633|  6.80k|  if (actual_utf32_length == 0) {
  ------------------
  |  Branch (9633:7): [True: 2.10k, False: 4.70k]
  ------------------
 9634|  2.10k|    return error;
 9635|  2.10k|  }
 9636|       |  // mapping
 9637|  4.70k|  utf32 = ada::idna::map(utf32);
 9638|  4.70k|  normalize(utf32);
 9639|  4.70k|  std::string out;
 9640|  4.70k|  size_t label_start = 0;
 9641|       |
 9642|  26.7k|  while (label_start != utf32.size()) {
  ------------------
  |  Branch (9642:10): [True: 22.8k, False: 3.87k]
  ------------------
 9643|  22.8k|    size_t loc_dot = utf32.find('.', label_start);
 9644|  22.8k|    bool is_last_label = (loc_dot == std::string_view::npos);
 9645|  22.8k|    size_t label_size =
 9646|  22.8k|        is_last_label ? utf32.size() - label_start : loc_dot - label_start;
  ------------------
  |  Branch (9646:9): [True: 4.34k, False: 18.5k]
  ------------------
 9647|  22.8k|    size_t label_size_with_dot = is_last_label ? label_size : label_size + 1;
  ------------------
  |  Branch (9647:34): [True: 4.34k, False: 18.5k]
  ------------------
 9648|  22.8k|    std::u32string_view label_view(utf32.data() + label_start, label_size);
 9649|  22.8k|    label_start += label_size_with_dot;
 9650|  22.8k|    if (label_size == 0) {
  ------------------
  |  Branch (9650:9): [True: 1.50k, False: 21.3k]
  ------------------
 9651|       |      // empty label? Nothing to do.
 9652|  21.3k|    } else if (begins_with(label_view, U"xn--")) {
  ------------------
  |  Branch (9652:16): [True: 1.42k, False: 19.9k]
  ------------------
 9653|       |      // we do not need to check, e.g., Xn-- because mapping goes to lower case
 9654|  15.2k|      for (char32_t c : label_view) {
  ------------------
  |  Branch (9654:23): [True: 15.2k, False: 1.40k]
  ------------------
 9655|  15.2k|        if (c >= 0x80) {
  ------------------
  |  Branch (9655:13): [True: 20, False: 15.2k]
  ------------------
 9656|     20|          return error;
 9657|     20|        }
 9658|  15.2k|        out += (unsigned char)(c);
 9659|  15.2k|      }
 9660|  1.40k|      std::string_view puny_segment_ascii(
 9661|  1.40k|          out.data() + out.size() - label_view.size() + 4,
 9662|  1.40k|          label_view.size() - 4);
 9663|  1.40k|      std::u32string tmp_buffer;
 9664|  1.40k|      bool is_ok = ada::idna::punycode_to_utf32(puny_segment_ascii, tmp_buffer);
 9665|  1.40k|      if (!is_ok) {
  ------------------
  |  Branch (9665:11): [True: 39, False: 1.36k]
  ------------------
 9666|     39|        return error;
 9667|     39|      }
 9668|  1.36k|      std::u32string post_map = ada::idna::map(tmp_buffer);
 9669|  1.36k|      if (tmp_buffer != post_map) {
  ------------------
  |  Branch (9669:11): [True: 34, False: 1.33k]
  ------------------
 9670|     34|        return error;
 9671|     34|      }
 9672|  1.33k|      std::u32string pre_normal = post_map;
 9673|  1.33k|      normalize(post_map);
 9674|  1.33k|      if (post_map != pre_normal) {
  ------------------
  |  Branch (9674:11): [True: 23, False: 1.30k]
  ------------------
 9675|     23|        return error;
 9676|     23|      }
 9677|  1.30k|      if (post_map.empty()) {
  ------------------
  |  Branch (9677:11): [True: 50, False: 1.25k]
  ------------------
 9678|     50|        return error;
 9679|     50|      }
 9680|  1.25k|      if (!is_label_valid(post_map)) {
  ------------------
  |  Branch (9680:11): [True: 11, False: 1.24k]
  ------------------
 9681|     11|        return error;
 9682|     11|      }
 9683|  19.9k|    } else {
 9684|       |      // The fast path here is an ascii label.
 9685|  19.9k|      if (is_ascii(label_view)) {
  ------------------
  |  Branch (9685:11): [True: 1.94k, False: 18.0k]
  ------------------
 9686|       |        // no validation needed.
 9687|  16.7k|        for (char32_t c : label_view) {
  ------------------
  |  Branch (9687:25): [True: 16.7k, False: 1.94k]
  ------------------
 9688|  16.7k|          out += (unsigned char)(c);
 9689|  16.7k|        }
 9690|  18.0k|      } else {
 9691|       |        // slow path.
 9692|       |        // first check validity.
 9693|  18.0k|        if (!is_label_valid(label_view)) {
  ------------------
  |  Branch (9693:13): [True: 654, False: 17.3k]
  ------------------
 9694|    654|          return error;
 9695|    654|        }
 9696|       |        // It is valid! So now we must encode it as punycode...
 9697|  17.3k|        out.append("xn--");
 9698|  17.3k|        bool is_ok = ada::idna::utf32_to_punycode(label_view, out);
 9699|  17.3k|        if (!is_ok) {
  ------------------
  |  Branch (9699:13): [True: 0, False: 17.3k]
  ------------------
 9700|      0|          return error;
 9701|      0|        }
 9702|  17.3k|      }
 9703|  19.9k|    }
 9704|  22.0k|    if (!is_last_label) {
  ------------------
  |  Branch (9704:9): [True: 18.5k, False: 3.53k]
  ------------------
 9705|  18.5k|      out.push_back('.');
 9706|  18.5k|    }
 9707|  22.0k|  }
 9708|  3.87k|  return out;
 9709|  4.70k|}
_ZN3ada4idna10to_unicodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9719|  9.85k|std::string to_unicode(std::string_view input) {
 9720|  9.85k|  std::string output;
 9721|  9.85k|  output.reserve(input.size());
 9722|       |
 9723|  9.85k|  size_t label_start = 0;
 9724|  32.4k|  while (label_start < input.size()) {
  ------------------
  |  Branch (9724:10): [True: 22.6k, False: 9.85k]
  ------------------
 9725|  22.6k|    size_t loc_dot = input.find('.', label_start);
 9726|  22.6k|    bool is_last_label = (loc_dot == std::string_view::npos);
 9727|  22.6k|    size_t label_size =
 9728|  22.6k|        is_last_label ? input.size() - label_start : loc_dot - label_start;
  ------------------
  |  Branch (9728:9): [True: 8.42k, False: 14.2k]
  ------------------
 9729|  22.6k|    auto label_view = std::string_view(input.data() + label_start, label_size);
 9730|       |
 9731|  22.6k|    if (ada::idna::begins_with(label_view, "xn--") &&
  ------------------
  |  Branch (9731:9): [True: 1.74k, False: 20.8k]
  ------------------
 9732|  22.6k|        ada::idna::is_ascii(label_view)) {
  ------------------
  |  Branch (9732:9): [True: 1.51k, False: 225]
  ------------------
 9733|  1.51k|      label_view.remove_prefix(4);
 9734|  1.51k|      if (ada::idna::verify_punycode(label_view)) {
  ------------------
  |  Branch (9734:11): [True: 918, False: 597]
  ------------------
 9735|    918|        std::u32string tmp_buffer;
 9736|    918|        if (ada::idna::punycode_to_utf32(label_view, tmp_buffer)) {
  ------------------
  |  Branch (9736:13): [True: 918, False: 0]
  ------------------
 9737|    918|          auto utf8_size = ada::idna::utf8_length_from_utf32(tmp_buffer.data(),
 9738|    918|                                                             tmp_buffer.size());
 9739|    918|          std::string final_utf8(utf8_size, '\0');
 9740|    918|          ada::idna::utf32_to_utf8(tmp_buffer.data(), tmp_buffer.size(),
 9741|    918|                                   final_utf8.data());
 9742|    918|          output.append(final_utf8);
 9743|    918|        } else {
 9744|       |          // ToUnicode never fails.  If any step fails, then the original input
 9745|       |          // sequence is returned immediately in that step.
 9746|      0|          output.append(
 9747|      0|              std::string_view(input.data() + label_start, label_size));
 9748|      0|        }
 9749|    918|      } else {
 9750|    597|        output.append(std::string_view(input.data() + label_start, label_size));
 9751|    597|      }
 9752|  21.1k|    } else {
 9753|  21.1k|      output.append(label_view);
 9754|  21.1k|    }
 9755|       |
 9756|  22.6k|    if (!is_last_label) {
  ------------------
  |  Branch (9756:9): [True: 14.2k, False: 8.42k]
  ------------------
 9757|  14.2k|      output.push_back('.');
 9758|  14.2k|    }
 9759|       |
 9760|  22.6k|    label_start += label_size + 1;
 9761|  22.6k|  }
 9762|       |
 9763|  9.85k|  return output;
 9764|  9.85k|}
_ZN3ada7unicode14percent_decodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEm:
10140|  4.71k|std::string percent_decode(const std::string_view input, size_t first_percent) {
10141|       |  // next line is for safety only, we expect users to avoid calling
10142|       |  // percent_decode when first_percent is outside the range.
10143|  4.71k|  if (first_percent == std::string_view::npos) {
  ------------------
  |  Branch (10143:7): [True: 3.71k, False: 994]
  ------------------
10144|  3.71k|    return std::string(input);
10145|  3.71k|  }
10146|    994|  std::string dest;
10147|    994|  dest.reserve(input.length());
10148|    994|  dest.append(input.substr(0, first_percent));
10149|    994|  const char* pointer = input.data() + first_percent;
10150|    994|  const char* end = input.data() + input.size();
10151|       |  // Optimization opportunity: if the following code gets
10152|       |  // called often, it can be optimized quite a bit.
10153|  20.4k|  while (pointer < end) {
  ------------------
  |  Branch (10153:10): [True: 19.4k, False: 994]
  ------------------
10154|  19.4k|    const char ch = pointer[0];
10155|  19.4k|    size_t remaining = end - pointer - 1;
10156|  19.4k|    if (ch != '%' || remaining < 2 ||
  ------------------
  |  Branch (10156:9): [True: 7.80k, False: 11.6k]
  |  Branch (10156:22): [True: 446, False: 11.1k]
  ------------------
10157|  19.4k|        (  // ch == '%' && // It is unnecessary to check that ch == '%'.
10158|  11.1k|            (!is_ascii_hex_digit(pointer[1]) ||
  ------------------
  |  Branch (10158:14): [True: 640, False: 10.5k]
  ------------------
10159|  11.1k|             !is_ascii_hex_digit(pointer[2])))) {
  ------------------
  |  Branch (10159:14): [True: 588, False: 9.97k]
  ------------------
10160|  9.47k|      dest += ch;
10161|  9.47k|      pointer++;
10162|  9.47k|      continue;
10163|  9.97k|    } else {
10164|  9.97k|      unsigned a = convert_hex_to_binary(pointer[1]);
10165|  9.97k|      unsigned b = convert_hex_to_binary(pointer[2]);
10166|  9.97k|      char c = static_cast<char>(a * 16 + b);
10167|  9.97k|      dest += c;
10168|  9.97k|      pointer += 3;
10169|  9.97k|    }
10170|  19.4k|  }
10171|    994|  return dest;
10172|  4.71k|}
_ZN3ada7unicode14percent_encodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKh:
10175|  41.6k|                           const uint8_t character_set[]) {
10176|  41.6k|  auto pointer =
10177|  41.6k|      std::find_if(input.begin(), input.end(), [character_set](const char c) {
10178|  41.6k|        return character_sets::bit_at(character_set, c);
10179|  41.6k|      });
10180|       |  // Optimization: Don't iterate if percent encode is not required
10181|  41.6k|  if (pointer == input.end()) {
  ------------------
  |  Branch (10181:7): [True: 31.0k, False: 10.6k]
  ------------------
10182|  31.0k|    return std::string(input);
10183|  31.0k|  }
10184|       |
10185|  10.6k|  std::string result;
10186|  10.6k|  result.reserve(input.length());  // in the worst case, percent encoding might
10187|       |                                   // produce 3 characters.
10188|  10.6k|  result.append(input.substr(0, std::distance(input.begin(), pointer)));
10189|       |
10190|   314k|  for (; pointer != input.end(); pointer++) {
  ------------------
  |  Branch (10190:10): [True: 304k, False: 10.6k]
  ------------------
10191|   304k|    if (character_sets::bit_at(character_set, *pointer)) {
  ------------------
  |  Branch (10191:9): [True: 214k, False: 90.2k]
  ------------------
10192|   214k|      result.append(character_sets::hex + uint8_t(*pointer) * 4, 3);
10193|   214k|    } else {
10194|  90.2k|      result += *pointer;
10195|  90.2k|    }
10196|   304k|  }
10197|       |
10198|  10.6k|  return result;
10199|  41.6k|}
_ZN3ada7unicode8to_asciiERNSt3__18optionalINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEENS1_17basic_string_viewIcS5_EEm:
10237|  7.22k|              size_t first_percent) {
10238|  7.22k|  std::string percent_decoded_buffer;
10239|  7.22k|  std::string_view input = plain;
10240|  7.22k|  if (first_percent != std::string_view::npos) {
  ------------------
  |  Branch (10240:7): [True: 729, False: 6.50k]
  ------------------
10241|    729|    percent_decoded_buffer = unicode::percent_decode(plain, first_percent);
10242|    729|    input = percent_decoded_buffer;
10243|    729|  }
10244|       |  // input is a non-empty UTF-8 string, must be percent decoded
10245|  7.22k|  std::string idna_ascii = ada::idna::to_ascii(input);
10246|  7.22k|  if (idna_ascii.empty() || contains_forbidden_domain_code_point(
  ------------------
  |  Branch (10246:7): [True: 1.54k, False: 5.68k]
  |  Branch (10246:29): [True: 699, False: 4.98k]
  ------------------
10247|  5.68k|                                idna_ascii.data(), idna_ascii.size())) {
10248|  2.24k|    return false;
10249|  2.24k|  }
10250|  4.98k|  out = std::move(idna_ascii);
10251|  4.98k|  return true;
10252|  7.22k|}
_ZN3ada7unicode14percent_encodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKhm:
10255|  1.14k|                           const uint8_t character_set[], size_t index) {
10256|  1.14k|  std::string out;
10257|  1.14k|  out.append(input.data(), index);
10258|  1.14k|  auto pointer = input.begin() + index;
10259|  43.6k|  for (; pointer != input.end(); pointer++) {
  ------------------
  |  Branch (10259:10): [True: 42.5k, False: 1.14k]
  ------------------
10260|  42.5k|    if (character_sets::bit_at(character_set, *pointer)) {
  ------------------
  |  Branch (10260:9): [True: 37.0k, False: 5.53k]
  ------------------
10261|  37.0k|      out.append(character_sets::hex + uint8_t(*pointer) * 4, 3);
10262|  37.0k|    } else {
10263|  5.53k|      out += *pointer;
10264|  5.53k|    }
10265|  42.5k|  }
10266|  1.14k|  return out;
10267|  1.14k|}
_ZN3ada11serializers36find_longest_sequence_of_ipv6_piecesERKNSt3__15arrayItLm8EEERmS6_:
10284|    458|    size_t& compress_length) noexcept {
10285|  1.91k|  for (size_t i = 0; i < 8; i++) {
  ------------------
  |  Branch (10285:22): [True: 1.61k, False: 306]
  ------------------
10286|  1.61k|    if (address[i] == 0) {
  ------------------
  |  Branch (10286:9): [True: 547, False: 1.06k]
  ------------------
10287|    547|      size_t next = i + 1;
10288|  2.41k|      while (next != 8 && address[next] == 0) ++next;
  ------------------
  |  Branch (10288:14): [True: 2.16k, False: 253]
  |  Branch (10288:27): [True: 1.87k, False: 294]
  ------------------
10289|    547|      const size_t count = next - i;
10290|    547|      if (compress_length < count) {
  ------------------
  |  Branch (10290:11): [True: 419, False: 128]
  ------------------
10291|    419|        compress_length = count;
10292|    419|        compress = i;
10293|    419|        if (next == 8) break;
  ------------------
  |  Branch (10293:13): [True: 152, False: 267]
  ------------------
10294|    267|        i = next;
10295|    267|      }
10296|    547|    }
10297|  1.61k|  }
10298|    458|}
_ZN3ada11serializers4ipv6ERKNSt3__15arrayItLm8EEE:
10300|    458|std::string ipv6(const std::array<uint16_t, 8>& address) noexcept {
10301|    458|  size_t compress_length = 0;  // The length of a long sequence of zeros.
10302|    458|  size_t compress = 0;         // The start of a long sequence of zeros.
10303|    458|  find_longest_sequence_of_ipv6_pieces(address, compress, compress_length);
10304|       |
10305|    458|  if (compress_length <= 1) {
  ------------------
  |  Branch (10305:7): [True: 98, False: 360]
  ------------------
10306|       |    // Optimization opportunity: Find a faster way then snprintf for imploding
10307|       |    // and return here.
10308|     98|    compress = compress_length = 8;
10309|     98|  }
10310|       |
10311|    458|  std::string output(4 * 8 + 7 + 2, '\0');
10312|    458|  size_t piece_index = 0;
10313|    458|  char* point = output.data();
10314|    458|  char* point_end = output.data() + output.size();
10315|    458|  *point++ = '[';
10316|  1.67k|  while (true) {
  ------------------
  |  Branch (10316:10): [Folded - Ignored]
  ------------------
10317|  1.67k|    if (piece_index == compress) {
  ------------------
  |  Branch (10317:9): [True: 360, False: 1.31k]
  ------------------
10318|    360|      *point++ = ':';
10319|       |      // If we skip a value initially, we need to write '::', otherwise
10320|       |      // a single ':' will do since it follows a previous ':'.
10321|    360|      if (piece_index == 0) {
  ------------------
  |  Branch (10321:11): [True: 221, False: 139]
  ------------------
10322|    221|        *point++ = ':';
10323|    221|      }
10324|    360|      piece_index += compress_length;
10325|    360|      if (piece_index == 8) {
  ------------------
  |  Branch (10325:11): [True: 146, False: 214]
  ------------------
10326|    146|        break;
10327|    146|      }
10328|    360|    }
10329|  1.52k|    point = std::to_chars(point, point_end, address[piece_index], 16).ptr;
10330|  1.52k|    piece_index++;
10331|  1.52k|    if (piece_index == 8) {
  ------------------
  |  Branch (10331:9): [True: 312, False: 1.21k]
  ------------------
10332|    312|      break;
10333|    312|    }
10334|  1.21k|    *point++ = ':';
10335|  1.21k|  }
10336|    458|  *point++ = ']';
10337|    458|  output.resize(point - output.data());
10338|    458|  return output;
10339|    458|}
_ZN3ada11serializers4ipv4Em:
10341|  3.26k|std::string ipv4(const uint64_t address) noexcept {
10342|  3.26k|  std::string output(15, '\0');
10343|  3.26k|  char* point = output.data();
10344|  3.26k|  char* point_end = output.data() + output.size();
10345|  3.26k|  point = std::to_chars(point, point_end, uint8_t(address >> 24)).ptr;
10346|  13.0k|  for (int i = 2; i >= 0; i--) {
  ------------------
  |  Branch (10346:19): [True: 9.78k, False: 3.26k]
  ------------------
10347|  9.78k|    *point++ = '.';
10348|  9.78k|    point = std::to_chars(point, point_end, uint8_t(address >> (i * 8))).ptr;
10349|  9.78k|  }
10350|  3.26k|  output.resize(point - output.data());
10351|  3.26k|  return output;
10352|  3.26k|}
_ZN3ada5parseINS_3urlEEEN2tl8expectedIT_NS_6errorsEEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEPKS4_:
10364|  10.1k|    std::string_view input, const result_type* base_url) {
10365|  10.1k|  result_type u = ada::parser::parse_url<result_type>(input, base_url);
10366|  10.1k|  if (!u.is_valid) {
  ------------------
  |  Branch (10366:7): [True: 4.36k, False: 5.75k]
  ------------------
10367|  4.36k|    return tl::unexpected(errors::generic_error);
10368|  4.36k|  }
10369|  5.75k|  return u;
10370|  10.1k|}
_ZN3ada5parseINS_14url_aggregatorEEEN2tl8expectedIT_NS_6errorsEEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEPKS4_:
10364|  31.6k|    std::string_view input, const result_type* base_url) {
10365|  31.6k|  result_type u = ada::parser::parse_url<result_type>(input, base_url);
10366|  31.6k|  if (!u.is_valid) {
  ------------------
  |  Branch (10366:7): [True: 16.8k, False: 14.8k]
  ------------------
10367|  16.8k|    return tl::unexpected(errors::generic_error);
10368|  16.8k|  }
10369|  14.8k|  return u;
10370|  31.6k|}
_ZN3ada14href_from_fileENSt3__117basic_string_viewIcNS0_11char_traitsIcEEEE:
10377|  9.85k|std::string href_from_file(std::string_view input) {
10378|       |  // This is going to be much faster than constructing a URL.
10379|  9.85k|  std::string tmp_buffer;
10380|  9.85k|  std::string_view internal_input;
10381|  9.85k|  if (unicode::has_tabs_or_newline(input)) {
  ------------------
  |  Branch (10381:7): [True: 141, False: 9.71k]
  ------------------
10382|    141|    tmp_buffer = input;
10383|    141|    helpers::remove_ascii_tab_or_newline(tmp_buffer);
10384|    141|    internal_input = tmp_buffer;
10385|  9.71k|  } else {
10386|  9.71k|    internal_input = input;
10387|  9.71k|  }
10388|  9.85k|  std::string path;
10389|  9.85k|  if (internal_input.empty()) {
  ------------------
  |  Branch (10389:7): [True: 824, False: 9.03k]
  ------------------
10390|    824|    path = "/";
10391|  9.03k|  } else if ((internal_input[0] == '/') || (internal_input[0] == '\\')) {
  ------------------
  |  Branch (10391:14): [True: 537, False: 8.49k]
  |  Branch (10391:44): [True: 8, False: 8.48k]
  ------------------
10392|    545|    helpers::parse_prepared_path(internal_input.substr(1),
10393|    545|                                 ada::scheme::type::FILE, path);
10394|  8.48k|  } else {
10395|  8.48k|    helpers::parse_prepared_path(internal_input, ada::scheme::type::FILE, path);
10396|  8.48k|  }
10397|  9.85k|  return "file://" + path;
10398|  9.85k|}
_ZN3ada9can_parseENSt3__117basic_string_viewIcNS0_11char_traitsIcEEEEPKS4_:
10400|  19.7k|bool can_parse(std::string_view input, const std::string_view* base_input) {
10401|  19.7k|  ada::result<ada::url_aggregator> base;
10402|  19.7k|  ada::url_aggregator* base_pointer = nullptr;
10403|  19.7k|  if (base_input != nullptr) {
  ------------------
  |  Branch (10403:7): [True: 9.85k, False: 9.85k]
  ------------------
10404|  9.85k|    base = ada::parse<url_aggregator>(*base_input);
10405|  9.85k|    if (!base) {
  ------------------
  |  Branch (10405:9): [True: 8.01k, False: 1.84k]
  ------------------
10406|  8.01k|      return false;
10407|  8.01k|    }
10408|  1.84k|    base_pointer = &base.value();
10409|  1.84k|  }
10410|  11.7k|  return ada::parse<url_aggregator>(input, base_pointer).has_value();
10411|  19.7k|}
_ZN3ada3url17parse_opaque_hostENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11135|    706|bool url::parse_opaque_host(std::string_view input) {
11136|    706|  ada_log("parse_opaque_host ", input, "[", input.size(), " bytes]");
11137|    706|  if (std::any_of(input.begin(), input.end(),
  ------------------
  |  Branch (11137:7): [True: 76, False: 630]
  ------------------
11138|    706|                  ada::unicode::is_forbidden_host_code_point)) {
11139|     76|    return is_valid = false;
11140|     76|  }
11141|       |
11142|       |  // Return the result of running UTF-8 percent-encode on input using the C0
11143|       |  // control percent-encode set.
11144|    630|  host = ada::unicode::percent_encode(
11145|    630|      input, ada::character_sets::C0_CONTROL_PERCENT_ENCODE);
11146|    630|  return true;
11147|    706|}
_ZN3ada3url10parse_ipv4ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11149|  1.54k|bool url::parse_ipv4(std::string_view input) {
11150|  1.54k|  ada_log("parse_ipv4 ", input, "[", input.size(), " bytes]");
11151|  1.54k|  if (input.back() == '.') {
  ------------------
  |  Branch (11151:7): [True: 29, False: 1.51k]
  ------------------
11152|     29|    input.remove_suffix(1);
11153|     29|  }
11154|  1.54k|  size_t digit_count{0};
11155|  1.54k|  int pure_decimal_count = 0;  // entries that are decimal
11156|  1.54k|  std::string_view original_input =
11157|  1.54k|      input;  // we might use this if pure_decimal_count == 4.
11158|  1.54k|  uint64_t ipv4{0};
11159|       |  // we could unroll for better performance?
11160|  1.93k|  for (; (digit_count < 4) && !(input.empty()); digit_count++) {
  ------------------
  |  Branch (11160:10): [True: 1.92k, False: 16]
  |  Branch (11160:31): [True: 1.92k, False: 0]
  ------------------
11161|  1.92k|    uint32_t
11162|  1.92k|        segment_result{};  // If any number exceeds 32 bits, we have an error.
11163|  1.92k|    bool is_hex = checkers::has_hex_prefix(input);
11164|  1.92k|    if (is_hex && ((input.length() == 2) ||
  ------------------
  |  Branch (11164:9): [True: 472, False: 1.44k]
  |  Branch (11164:20): [True: 26, False: 446]
  ------------------
11165|    472|                   ((input.length() > 2) && (input[2] == '.')))) {
  ------------------
  |  Branch (11165:21): [True: 446, False: 0]
  |  Branch (11165:45): [True: 10, False: 436]
  ------------------
11166|       |      // special case
11167|     36|      segment_result = 0;
11168|     36|      input.remove_prefix(2);
11169|  1.88k|    } else {
11170|  1.88k|      std::from_chars_result r;
11171|  1.88k|      if (is_hex) {
  ------------------
  |  Branch (11171:11): [True: 436, False: 1.44k]
  ------------------
11172|    436|        r = std::from_chars(input.data() + 2, input.data() + input.size(),
11173|    436|                            segment_result, 16);
11174|  1.44k|      } else if ((input.length() >= 2) && input[0] == '0' &&
  ------------------
  |  Branch (11174:18): [True: 770, False: 679]
  |  Branch (11174:43): [True: 339, False: 431]
  ------------------
11175|  1.44k|                 checkers::is_digit(input[1])) {
  ------------------
  |  Branch (11175:18): [True: 261, False: 78]
  ------------------
11176|    261|        r = std::from_chars(input.data() + 1, input.data() + input.size(),
11177|    261|                            segment_result, 8);
11178|  1.18k|      } else {
11179|  1.18k|        pure_decimal_count++;
11180|  1.18k|        r = std::from_chars(input.data(), input.data() + input.size(),
11181|  1.18k|                            segment_result, 10);
11182|  1.18k|      }
11183|  1.88k|      if (r.ec != std::errc()) {
  ------------------
  |  Branch (11183:11): [True: 285, False: 1.60k]
  ------------------
11184|    285|        return is_valid = false;
11185|    285|      }
11186|  1.60k|      input.remove_prefix(r.ptr - input.data());
11187|  1.60k|    }
11188|  1.63k|    if (input.empty()) {
  ------------------
  |  Branch (11188:9): [True: 1.16k, False: 475]
  ------------------
11189|       |      // We have the last value.
11190|       |      // At this stage, ipv4 contains digit_count*8 bits.
11191|       |      // So we have 32-digit_count*8 bits left.
11192|  1.16k|      if (segment_result > (uint64_t(1) << (32 - digit_count * 8))) {
  ------------------
  |  Branch (11192:11): [True: 9, False: 1.15k]
  ------------------
11193|      9|        return is_valid = false;
11194|      9|      }
11195|  1.15k|      ipv4 <<= (32 - digit_count * 8);
11196|  1.15k|      ipv4 |= segment_result;
11197|  1.15k|      goto final;
11198|  1.16k|    } else {
11199|       |      // There is more, so that the value must no be larger than 255
11200|       |      // and we must have a '.'.
11201|    475|      if ((segment_result > 255) || (input[0] != '.')) {
  ------------------
  |  Branch (11201:11): [True: 35, False: 440]
  |  Branch (11201:37): [True: 49, False: 391]
  ------------------
11202|     84|        return is_valid = false;
11203|     84|      }
11204|    391|      ipv4 <<= 8;
11205|    391|      ipv4 |= segment_result;
11206|    391|      input.remove_prefix(1);  // remove '.'
11207|    391|    }
11208|  1.63k|  }
11209|     16|  if ((digit_count != 4) || (!input.empty())) {
  ------------------
  |  Branch (11209:7): [True: 0, False: 16]
  |  Branch (11209:29): [True: 16, False: 0]
  ------------------
11210|     16|    return is_valid = false;
11211|     16|  }
11212|  1.15k|final:
11213|       |  // We could also check r.ptr to see where the parsing ended.
11214|  1.15k|  if (pure_decimal_count == 4) {
  ------------------
  |  Branch (11214:7): [True: 37, False: 1.11k]
  ------------------
11215|     37|    host = original_input;  // The original input was already all decimal and we
11216|       |                            // validated it.
11217|  1.11k|  } else {
11218|  1.11k|    host = ada::serializers::ipv4(ipv4);  // We have to reserialize the address.
11219|  1.11k|  }
11220|  1.15k|  host_type = IPV4;
11221|  1.15k|  return true;
11222|     16|}
_ZN3ada3url10parse_ipv6ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11224|    375|bool url::parse_ipv6(std::string_view input) {
11225|    375|  ada_log("parse_ipv6 ", input, "[", input.size(), " bytes]");
11226|       |
11227|    375|  if (input.empty()) {
  ------------------
  |  Branch (11227:7): [True: 23, False: 352]
  ------------------
11228|     23|    return is_valid = false;
11229|     23|  }
11230|       |  // Let address be a new IPv6 address whose IPv6 pieces are all 0.
11231|    352|  std::array<uint16_t, 8> address{};
11232|       |
11233|       |  // Let pieceIndex be 0.
11234|    352|  int piece_index = 0;
11235|       |
11236|       |  // Let compress be null.
11237|    352|  std::optional<int> compress{};
11238|       |
11239|       |  // Let pointer be a pointer for input.
11240|    352|  std::string_view::iterator pointer = input.begin();
11241|       |
11242|       |  // If c is U+003A (:), then:
11243|    352|  if (input[0] == ':') {
  ------------------
  |  Branch (11243:7): [True: 88, False: 264]
  ------------------
11244|       |    // If remaining does not start with U+003A (:), validation error, return
11245|       |    // failure.
11246|     88|    if (input.size() == 1 || input[1] != ':') {
  ------------------
  |  Branch (11246:9): [True: 3, False: 85]
  |  Branch (11246:30): [True: 7, False: 78]
  ------------------
11247|     10|      ada_log("parse_ipv6 starts with : but the rest does not start with :");
11248|     10|      return is_valid = false;
11249|     10|    }
11250|       |
11251|       |    // Increase pointer by 2.
11252|     78|    pointer += 2;
11253|       |
11254|       |    // Increase pieceIndex by 1 and then set compress to pieceIndex.
11255|     78|    compress = ++piece_index;
11256|     78|  }
11257|       |
11258|       |  // While c is not the EOF code point:
11259|  1.05k|  while (pointer != input.end()) {
  ------------------
  |  Branch (11259:10): [True: 884, False: 173]
  ------------------
11260|       |    // If pieceIndex is 8, validation error, return failure.
11261|    884|    if (piece_index == 8) {
  ------------------
  |  Branch (11261:9): [True: 5, False: 879]
  ------------------
11262|      5|      ada_log("parse_ipv6 piece_index == 8");
11263|      5|      return is_valid = false;
11264|      5|    }
11265|       |
11266|       |    // If c is U+003A (:), then:
11267|    879|    if (*pointer == ':') {
  ------------------
  |  Branch (11267:9): [True: 69, False: 810]
  ------------------
11268|       |      // If compress is non-null, validation error, return failure.
11269|     69|      if (compress.has_value()) {
  ------------------
  |  Branch (11269:11): [True: 6, False: 63]
  ------------------
11270|      6|        ada_log("parse_ipv6 compress is non-null");
11271|      6|        return is_valid = false;
11272|      6|      }
11273|       |
11274|       |      // Increase pointer and pieceIndex by 1, set compress to pieceIndex, and
11275|       |      // then continue.
11276|     63|      pointer++;
11277|     63|      compress = ++piece_index;
11278|     63|      continue;
11279|     69|    }
11280|       |
11281|       |    // Let value and length be 0.
11282|    810|    uint16_t value = 0, length = 0;
11283|       |
11284|       |    // While length is less than 4 and c is an ASCII hex digit,
11285|       |    // set value to value times 0x10 + c interpreted as hexadecimal number, and
11286|       |    // increase pointer and length by 1.
11287|  2.17k|    while (length < 4 && pointer != input.end() &&
  ------------------
  |  Branch (11287:12): [True: 2.01k, False: 152]
  |  Branch (11287:26): [True: 1.92k, False: 92]
  ------------------
11288|  2.17k|           unicode::is_ascii_hex_digit(*pointer)) {
  ------------------
  |  Branch (11288:12): [True: 1.36k, False: 566]
  ------------------
11289|       |      // https://stackoverflow.com/questions/39060852/why-does-the-addition-of-two-shorts-return-an-int
11290|  1.36k|      value = uint16_t(value * 0x10 + unicode::convert_hex_to_binary(*pointer));
11291|  1.36k|      pointer++;
11292|  1.36k|      length++;
11293|  1.36k|    }
11294|       |
11295|       |    // If c is U+002E (.), then:
11296|    810|    if (pointer != input.end() && *pointer == '.') {
  ------------------
  |  Branch (11296:9): [True: 682, False: 128]
  |  Branch (11296:35): [True: 70, False: 612]
  ------------------
11297|       |      // If length is 0, validation error, return failure.
11298|     70|      if (length == 0) {
  ------------------
  |  Branch (11298:11): [True: 0, False: 70]
  ------------------
11299|      0|        ada_log("parse_ipv6 length is 0");
11300|      0|        return is_valid = false;
11301|      0|      }
11302|       |
11303|       |      // Decrease pointer by length.
11304|     70|      pointer -= length;
11305|       |
11306|       |      // If pieceIndex is greater than 6, validation error, return failure.
11307|     70|      if (piece_index > 6) {
  ------------------
  |  Branch (11307:11): [True: 4, False: 66]
  ------------------
11308|      4|        ada_log("parse_ipv6 piece_index > 6");
11309|      4|        return is_valid = false;
11310|      4|      }
11311|       |
11312|       |      // Let numbersSeen be 0.
11313|     66|      int numbers_seen = 0;
11314|       |
11315|       |      // While c is not the EOF code point:
11316|    209|      while (pointer != input.end()) {
  ------------------
  |  Branch (11316:14): [True: 187, False: 22]
  ------------------
11317|       |        // Let ipv4Piece be null.
11318|    187|        std::optional<uint16_t> ipv4_piece{};
11319|       |
11320|       |        // If numbersSeen is greater than 0, then:
11321|    187|        if (numbers_seen > 0) {
  ------------------
  |  Branch (11321:13): [True: 121, False: 66]
  ------------------
11322|       |          // If c is a U+002E (.) and numbersSeen is less than 4, then increase
11323|       |          // pointer by 1.
11324|    121|          if (*pointer == '.' && numbers_seen < 4) {
  ------------------
  |  Branch (11324:15): [True: 111, False: 10]
  |  Branch (11324:34): [True: 108, False: 3]
  ------------------
11325|    108|            pointer++;
11326|    108|          }
11327|       |          // Otherwise, validation error, return failure.
11328|     13|          else {
11329|     13|            ada_log("parse_ipv6 Otherwise, validation error, return failure");
11330|     13|            return is_valid = false;
11331|     13|          }
11332|    121|        }
11333|       |
11334|       |        // If c is not an ASCII digit, validation error, return failure.
11335|    174|        if (pointer == input.end() || !checkers::is_digit(*pointer)) {
  ------------------
  |  Branch (11335:13): [True: 14, False: 160]
  |  Branch (11335:39): [True: 5, False: 155]
  ------------------
11336|     19|          ada_log(
11337|     19|              "parse_ipv6 If c is not an ASCII digit, validation error, return "
11338|     19|              "failure");
11339|     19|          return is_valid = false;
11340|     19|        }
11341|       |
11342|       |        // While c is an ASCII digit:
11343|    359|        while (pointer != input.end() && checkers::is_digit(*pointer)) {
  ------------------
  |  Branch (11343:16): [True: 337, False: 22]
  |  Branch (11343:42): [True: 216, False: 121]
  ------------------
11344|       |          // Let number be c interpreted as decimal number.
11345|    216|          int number = *pointer - '0';
11346|       |
11347|       |          // If ipv4Piece is null, then set ipv4Piece to number.
11348|    216|          if (!ipv4_piece.has_value()) {
  ------------------
  |  Branch (11348:15): [True: 155, False: 61]
  ------------------
11349|    155|            ipv4_piece = number;
11350|    155|          }
11351|       |          // Otherwise, if ipv4Piece is 0, validation error, return failure.
11352|     61|          else if (ipv4_piece == 0) {
  ------------------
  |  Branch (11352:20): [True: 5, False: 56]
  ------------------
11353|      5|            ada_log("parse_ipv6 if ipv4Piece is 0, validation error");
11354|      5|            return is_valid = false;
11355|      5|          }
11356|       |          // Otherwise, set ipv4Piece to ipv4Piece times 10 + number.
11357|     56|          else {
11358|     56|            ipv4_piece = *ipv4_piece * 10 + number;
11359|     56|          }
11360|       |
11361|       |          // If ipv4Piece is greater than 255, validation error, return failure.
11362|    211|          if (ipv4_piece > 255) {
  ------------------
  |  Branch (11362:15): [True: 7, False: 204]
  ------------------
11363|      7|            ada_log("parse_ipv6 ipv4_piece > 255");
11364|      7|            return is_valid = false;
11365|      7|          }
11366|       |
11367|       |          // Increase pointer by 1.
11368|    204|          pointer++;
11369|    204|        }
11370|       |
11371|       |        // Set address[pieceIndex] to address[pieceIndex] times 0x100 +
11372|       |        // ipv4Piece.
11373|       |        // https://stackoverflow.com/questions/39060852/why-does-the-addition-of-two-shorts-return-an-int
11374|    143|        address[piece_index] =
11375|    143|            uint16_t(address[piece_index] * 0x100 + *ipv4_piece);
11376|       |
11377|       |        // Increase numbersSeen by 1.
11378|    143|        numbers_seen++;
11379|       |
11380|       |        // If numbersSeen is 2 or 4, then increase pieceIndex by 1.
11381|    143|        if (numbers_seen == 2 || numbers_seen == 4) {
  ------------------
  |  Branch (11381:13): [True: 43, False: 100]
  |  Branch (11381:34): [True: 17, False: 83]
  ------------------
11382|     60|          piece_index++;
11383|     60|        }
11384|    143|      }
11385|       |
11386|       |      // If numbersSeen is not 4, validation error, return failure.
11387|     22|      if (numbers_seen != 4) {
  ------------------
  |  Branch (11387:11): [True: 8, False: 14]
  ------------------
11388|      8|        return is_valid = false;
11389|      8|      }
11390|       |
11391|       |      // Break.
11392|     14|      break;
11393|     22|    }
11394|       |    // Otherwise, if c is U+003A (:):
11395|    740|    else if ((pointer != input.end()) && (*pointer == ':')) {
  ------------------
  |  Branch (11395:14): [True: 612, False: 128]
  |  Branch (11395:42): [True: 528, False: 84]
  ------------------
11396|       |      // Increase pointer by 1.
11397|    528|      pointer++;
11398|       |
11399|       |      // If c is the EOF code point, validation error, return failure.
11400|    528|      if (pointer == input.end()) {
  ------------------
  |  Branch (11400:11): [True: 4, False: 524]
  ------------------
11401|      4|        ada_log(
11402|      4|            "parse_ipv6 If c is the EOF code point, validation error, return "
11403|      4|            "failure");
11404|      4|        return is_valid = false;
11405|      4|      }
11406|    528|    }
11407|       |    // Otherwise, if c is not the EOF code point, validation error, return
11408|       |    // failure.
11409|    212|    else if (pointer != input.end()) {
  ------------------
  |  Branch (11409:14): [True: 84, False: 128]
  ------------------
11410|     84|      ada_log(
11411|     84|          "parse_ipv6 Otherwise, if c is not the EOF code point, validation "
11412|     84|          "error, return failure");
11413|     84|      return is_valid = false;
11414|     84|    }
11415|       |
11416|       |    // Set address[pieceIndex] to value.
11417|    652|    address[piece_index] = value;
11418|       |
11419|       |    // Increase pieceIndex by 1.
11420|    652|    piece_index++;
11421|    652|  }
11422|       |
11423|       |  // If compress is non-null, then:
11424|    187|  if (compress.has_value()) {
  ------------------
  |  Branch (11424:7): [True: 126, False: 61]
  ------------------
11425|       |    // Let swaps be pieceIndex - compress.
11426|    126|    int swaps = piece_index - *compress;
11427|       |
11428|       |    // Set pieceIndex to 7.
11429|    126|    piece_index = 7;
11430|       |
11431|       |    // While pieceIndex is not 0 and swaps is greater than 0,
11432|       |    // swap address[pieceIndex] with address[compress + swaps - 1], and then
11433|       |    // decrease both pieceIndex and swaps by 1.
11434|    377|    while (piece_index != 0 && swaps > 0) {
  ------------------
  |  Branch (11434:12): [True: 368, False: 9]
  |  Branch (11434:32): [True: 251, False: 117]
  ------------------
11435|    251|      std::swap(address[piece_index], address[*compress + swaps - 1]);
11436|    251|      piece_index--;
11437|    251|      swaps--;
11438|    251|    }
11439|    126|  }
11440|       |  // Otherwise, if compress is null and pieceIndex is not 8, validation error,
11441|       |  // return failure.
11442|     61|  else if (piece_index != 8) {
  ------------------
  |  Branch (11442:12): [True: 45, False: 16]
  ------------------
11443|     45|    ada_log(
11444|     45|        "parse_ipv6 if compress is null and pieceIndex is not 8, validation "
11445|     45|        "error, return failure");
11446|     45|    return is_valid = false;
11447|     45|  }
11448|    142|  host = ada::serializers::ipv6(address);
11449|    142|  ada_log("parse_ipv6 ", *host);
11450|    142|  host_type = IPV6;
11451|    142|  return true;
11452|    187|}
_ZNK3ada3url10get_originEv:
11727|  5.68k|[[nodiscard]] std::string url::get_origin() const noexcept {
11728|  5.68k|  if (is_special()) {
  ------------------
  |  Branch (11728:7): [True: 3.82k, False: 1.86k]
  ------------------
11729|       |    // Return a new opaque origin.
11730|  3.82k|    if (type == scheme::FILE) {
  ------------------
  |  Branch (11730:9): [True: 1.03k, False: 2.78k]
  ------------------
11731|  1.03k|      return "null";
11732|  1.03k|    }
11733|  2.78k|    return ada::helpers::concat(get_protocol(), "//", get_host());
11734|  3.82k|  }
11735|       |
11736|  1.86k|  if (non_special_scheme == "blob") {
  ------------------
  |  Branch (11736:7): [True: 259, False: 1.60k]
  ------------------
11737|    259|    if (!path.empty()) {
  ------------------
  |  Branch (11737:9): [True: 255, False: 4]
  ------------------
11738|    255|      auto result = ada::parse<ada::url>(path);
11739|    255|      if (result &&
  ------------------
  |  Branch (11739:11): [True: 67, False: 188]
  ------------------
11740|    255|          (result->type == scheme::HTTP || result->type == scheme::HTTPS)) {
  ------------------
  |  Branch (11740:12): [True: 4, False: 63]
  |  Branch (11740:44): [True: 1, False: 62]
  ------------------
11741|       |        // If pathURL's scheme is not "http" and not "https", then return a
11742|       |        // new opaque origin.
11743|      5|        return ada::helpers::concat(result->get_protocol(), "//",
11744|      5|                                    result->get_host());
11745|      5|      }
11746|    255|    }
11747|    259|  }
11748|       |
11749|       |  // Return a new opaque origin.
11750|  1.85k|  return "null";
11751|  1.86k|}
_ZNK3ada3url12get_protocolEv:
11753|  8.47k|[[nodiscard]] std::string url::get_protocol() const noexcept {
11754|  8.47k|  if (is_special()) {
  ------------------
  |  Branch (11754:7): [True: 6.61k, False: 1.86k]
  ------------------
11755|  6.61k|    return helpers::concat(ada::scheme::details::is_special_list[type], ":");
11756|  6.61k|  }
11757|       |  // We only move the 'scheme' if it is non-special.
11758|  1.86k|  return helpers::concat(non_special_scheme, ":");
11759|  8.47k|}
_ZNK3ada3url8get_hostEv:
11761|  8.47k|[[nodiscard]] std::string url::get_host() const noexcept {
11762|       |  // If url's host is null, then return the empty string.
11763|       |  // If url's port is null, return url's host, serialized.
11764|       |  // Return url's host, serialized, followed by U+003A (:) and url's port,
11765|       |  // serialized.
11766|  8.47k|  if (!host.has_value()) {
  ------------------
  |  Branch (11766:7): [True: 802, False: 7.67k]
  ------------------
11767|    802|    return "";
11768|    802|  }
11769|  7.67k|  if (port.has_value()) {
  ------------------
  |  Branch (11769:7): [True: 314, False: 7.36k]
  ------------------
11770|    314|    return host.value() + ":" + get_port();
11771|    314|  }
11772|  7.36k|  return host.value();
11773|  7.67k|}
_ZNK3ada3url12get_hostnameEv:
11775|  5.68k|[[nodiscard]] std::string url::get_hostname() const noexcept {
11776|  5.68k|  return host.value_or("");
11777|  5.68k|}
_ZNK3ada3url12get_pathnameEv:
11779|  6.81k|[[nodiscard]] const std::string_view url::get_pathname() const noexcept {
11780|  6.81k|  return path;
11781|  6.81k|}
_ZNK3ada3url10get_searchEv:
11783|  5.68k|[[nodiscard]] std::string url::get_search() const noexcept {
11784|       |  // If this's URL's query is either null or the empty string, then return the
11785|       |  // empty string. Return U+003F (?), followed by this's URL's query.
11786|  5.68k|  return (!query.has_value() || (query.value().empty())) ? ""
  ------------------
  |  Branch (11786:11): [True: 3.62k, False: 2.06k]
  |  Branch (11786:33): [True: 35, False: 2.02k]
  ------------------
11787|  5.68k|                                                         : "?" + query.value();
11788|  5.68k|}
_ZNK3ada3url12get_usernameEv:
11790|  5.68k|[[nodiscard]] const std::string& url::get_username() const noexcept {
11791|  5.68k|  return username;
11792|  5.68k|}
_ZNK3ada3url12get_passwordEv:
11794|  5.68k|[[nodiscard]] const std::string& url::get_password() const noexcept {
11795|  5.68k|  return password;
11796|  5.68k|}
_ZNK3ada3url8get_portEv:
11798|  5.99k|[[nodiscard]] std::string url::get_port() const noexcept {
11799|  5.99k|  return port.has_value() ? std::to_string(port.value()) : "";
  ------------------
  |  Branch (11799:10): [True: 490, False: 5.50k]
  ------------------
11800|  5.99k|}
_ZNK3ada3url8get_hashEv:
11802|  5.68k|[[nodiscard]] std::string url::get_hash() const noexcept {
11803|       |  // If this's URL's fragment is either null or the empty string, then return
11804|       |  // the empty string. Return U+0023 (#), followed by this's URL's fragment.
11805|  5.68k|  return (!hash.has_value() || (hash.value().empty())) ? ""
  ------------------
  |  Branch (11805:11): [True: 3.62k, False: 2.06k]
  |  Branch (11805:32): [True: 34, False: 2.02k]
  ------------------
11806|  5.68k|                                                       : "#" + hash.value();
11807|  5.68k|}
_ZN3ada3url8set_hostENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11904|  5.68k|bool url::set_host(const std::string_view input) {
11905|  5.68k|  return set_host_or_hostname<false>(input);
11906|  5.68k|}
_ZN3ada3url12set_hostnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11908|  5.68k|bool url::set_hostname(const std::string_view input) {
11909|  5.68k|  return set_host_or_hostname<true>(input);
11910|  5.68k|}
_ZN3ada3url12set_usernameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11912|  5.68k|bool url::set_username(const std::string_view input) {
11913|  5.68k|  if (cannot_have_credentials_or_port()) {
  ------------------
  |  Branch (11913:7): [True: 2.73k, False: 2.94k]
  ------------------
11914|  2.73k|    return false;
11915|  2.73k|  }
11916|  2.94k|  username = ada::unicode::percent_encode(
11917|  2.94k|      input, character_sets::USERINFO_PERCENT_ENCODE);
11918|  2.94k|  return true;
11919|  5.68k|}
_ZN3ada3url12set_passwordENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11921|  5.68k|bool url::set_password(const std::string_view input) {
11922|  5.68k|  if (cannot_have_credentials_or_port()) {
  ------------------
  |  Branch (11922:7): [True: 2.73k, False: 2.94k]
  ------------------
11923|  2.73k|    return false;
11924|  2.73k|  }
11925|  2.94k|  password = ada::unicode::percent_encode(
11926|  2.94k|      input, character_sets::USERINFO_PERCENT_ENCODE);
11927|  2.94k|  return true;
11928|  5.68k|}
_ZN3ada3url8set_portENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11930|  5.75k|bool url::set_port(const std::string_view input) {
11931|  5.75k|  if (cannot_have_credentials_or_port()) {
  ------------------
  |  Branch (11931:7): [True: 2.62k, False: 3.13k]
  ------------------
11932|  2.62k|    return false;
11933|  2.62k|  }
11934|  3.13k|  std::string trimmed(input);
11935|  3.13k|  helpers::remove_ascii_tab_or_newline(trimmed);
11936|  3.13k|  if (trimmed.empty()) {
  ------------------
  |  Branch (11936:7): [True: 1.87k, False: 1.26k]
  ------------------
11937|  1.87k|    port = std::nullopt;
11938|  1.87k|    return true;
11939|  1.87k|  }
11940|       |  // Input should not start with control characters.
11941|  1.26k|  if (ada::unicode::is_c0_control_or_space(trimmed.front())) {
  ------------------
  |  Branch (11941:7): [True: 47, False: 1.21k]
  ------------------
11942|     47|    return false;
11943|     47|  }
11944|       |  // Input should contain at least one ascii digit.
11945|  1.21k|  if (input.find_first_of("0123456789") == std::string_view::npos) {
  ------------------
  |  Branch (11945:7): [True: 689, False: 528]
  ------------------
11946|    689|    return false;
11947|    689|  }
11948|       |
11949|       |  // Revert changes if parse_port fails.
11950|    528|  std::optional<uint16_t> previous_port = port;
11951|    528|  parse_port(trimmed);
11952|    528|  if (is_valid) {
  ------------------
  |  Branch (11952:7): [True: 398, False: 130]
  ------------------
11953|    398|    return true;
11954|    398|  }
11955|    130|  port = previous_port;
11956|    130|  is_valid = true;
11957|    130|  return false;
11958|    528|}
_ZN3ada3url8set_hashENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11960|  5.68k|void url::set_hash(const std::string_view input) {
11961|  5.68k|  if (input.empty()) {
  ------------------
  |  Branch (11961:7): [True: 3.62k, False: 2.06k]
  ------------------
11962|  3.62k|    hash = std::nullopt;
11963|  3.62k|    helpers::strip_trailing_spaces_from_opaque_path(*this);
11964|  3.62k|    return;
11965|  3.62k|  }
11966|       |
11967|  2.06k|  std::string new_value;
11968|  2.06k|  new_value = input[0] == '#' ? input.substr(1) : input;
  ------------------
  |  Branch (11968:15): [True: 1, False: 2.06k]
  ------------------
11969|  2.06k|  helpers::remove_ascii_tab_or_newline(new_value);
11970|  2.06k|  hash = unicode::percent_encode(new_value,
11971|  2.06k|                                 ada::character_sets::FRAGMENT_PERCENT_ENCODE);
11972|  2.06k|  return;
11973|  5.68k|}
_ZN3ada3url10set_searchENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11975|  5.68k|void url::set_search(const std::string_view input) {
11976|  5.68k|  if (input.empty()) {
  ------------------
  |  Branch (11976:7): [True: 3.62k, False: 2.06k]
  ------------------
11977|  3.62k|    query = std::nullopt;
11978|  3.62k|    helpers::strip_trailing_spaces_from_opaque_path(*this);
11979|  3.62k|    return;
11980|  3.62k|  }
11981|       |
11982|  2.06k|  std::string new_value;
11983|  2.06k|  new_value = input[0] == '?' ? input.substr(1) : input;
  ------------------
  |  Branch (11983:15): [True: 3, False: 2.05k]
  ------------------
11984|  2.06k|  helpers::remove_ascii_tab_or_newline(new_value);
11985|       |
11986|  2.06k|  auto query_percent_encode_set =
11987|  2.06k|      is_special() ? ada::character_sets::SPECIAL_QUERY_PERCENT_ENCODE
  ------------------
  |  Branch (11987:7): [True: 1.39k, False: 667]
  ------------------
11988|  2.06k|                   : ada::character_sets::QUERY_PERCENT_ENCODE;
11989|       |
11990|  2.06k|  query = ada::unicode::percent_encode(std::string_view(new_value),
11991|  2.06k|                                       query_percent_encode_set);
11992|  2.06k|}
_ZN3ada3url12set_pathnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11994|  5.68k|bool url::set_pathname(const std::string_view input) {
11995|  5.68k|  if (has_opaque_path) {
  ------------------
  |  Branch (11995:7): [True: 709, False: 4.97k]
  ------------------
11996|    709|    return false;
11997|    709|  }
11998|  4.97k|  path = "";
11999|  4.97k|  parse_path(input);
12000|  4.97k|  return true;
12001|  5.68k|}
_ZN3ada3url12set_protocolENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
12003|  5.68k|bool url::set_protocol(const std::string_view input) {
12004|  5.68k|  std::string view(input);
12005|  5.68k|  helpers::remove_ascii_tab_or_newline(view);
12006|  5.68k|  if (view.empty()) {
  ------------------
  |  Branch (12006:7): [True: 3.65k, False: 2.02k]
  ------------------
12007|  3.65k|    return true;
12008|  3.65k|  }
12009|       |
12010|       |  // Schemes should start with alpha values.
12011|  2.02k|  if (!checkers::is_alpha(view[0])) {
  ------------------
  |  Branch (12011:7): [True: 1.66k, False: 360]
  ------------------
12012|  1.66k|    return false;
12013|  1.66k|  }
12014|       |
12015|    360|  view.append(":");
12016|       |
12017|    360|  std::string::iterator pointer =
12018|    360|      std::find_if_not(view.begin(), view.end(), unicode::is_alnum_plus);
12019|       |
12020|    360|  if (pointer != view.end() && *pointer == ':') {
  ------------------
  |  Branch (12020:7): [True: 360, False: 0]
  |  Branch (12020:7): [True: 222, False: 138]
  |  Branch (12020:32): [True: 222, False: 138]
  ------------------
12021|    222|    return parse_scheme<true>(
12022|    222|        std::string_view(view.data(), pointer - view.begin()));
12023|    222|  }
12024|    138|  return false;
12025|    360|}
_ZN3ada6parser9parse_urlINS_3urlEEET_NSt3__117basic_string_viewIcNS4_11char_traitsIcEEEEPKS3_:
12057|  10.1k|                      const result_type* base_url) {
12058|       |  // We can specialize the implementation per type.
12059|       |  // Important: result_type_is_ada_url is evaluated at *compile time*. This
12060|       |  // means that doing if constexpr(result_type_is_ada_url) { something } else {
12061|       |  // something else } is free (at runtime). This means that ada::url_aggregator
12062|       |  // and ada::url **do not have to support the exact same API**.
12063|  10.1k|  constexpr bool result_type_is_ada_url =
12064|  10.1k|      std::is_same<ada::url, result_type>::value;
12065|  10.1k|  constexpr bool result_type_is_ada_url_aggregator =
12066|  10.1k|      std::is_same<ada::url_aggregator, result_type>::value;
12067|  10.1k|  static_assert(result_type_is_ada_url ||
12068|  10.1k|                result_type_is_ada_url_aggregator);  // We don't support
12069|       |                                                     // anything else for now.
12070|       |
12071|  10.1k|  ada_log("ada::parser::parse_url('", user_input, "' [", user_input.size(),
12072|  10.1k|          " bytes],", (base_url != nullptr ? base_url->to_string() : "null"),
12073|  10.1k|          ")");
12074|       |
12075|  10.1k|  ada::state state = ada::state::SCHEME_START;
12076|  10.1k|  result_type url{};
12077|       |
12078|       |  // We refuse to parse URL strings that exceed 4GB. Such strings are almost
12079|       |  // surely the result of a bug or are otherwise a security concern.
12080|  10.1k|  if (user_input.size() > std::numeric_limits<uint32_t>::max()) {
  ------------------
  |  Branch (12080:7): [True: 0, False: 10.1k]
  ------------------
12081|      0|    url.is_valid = false;
12082|      0|  }
12083|       |  // Going forward, user_input.size() is in [0,
12084|       |  // std::numeric_limits<uint32_t>::max). If we are provided with an invalid
12085|       |  // base, or the optional_url was invalid, we must return.
12086|  10.1k|  if (base_url != nullptr) {
  ------------------
  |  Branch (12086:7): [True: 0, False: 10.1k]
  ------------------
12087|      0|    url.is_valid &= base_url->is_valid;
12088|      0|  }
12089|  10.1k|  if (!url.is_valid) {
  ------------------
  |  Branch (12089:7): [True: 0, False: 10.1k]
  ------------------
12090|      0|    return url;
12091|      0|  }
12092|  10.1k|  if constexpr (result_type_is_ada_url_aggregator) {
  ------------------
  |  Branch (12092:17): [Folded - Ignored]
  ------------------
12093|       |    // Most of the time, we just need user_input.size().
12094|       |    // In some instances, we may need a bit more.
12095|       |    ///////////////////////////
12096|       |    // This is *very* important. This line should *not* be removed
12097|       |    // hastily. There are principled reasons why reserve is important
12098|       |    // for performance. If you have a benchmark with small inputs,
12099|       |    // it may not matter, but in other instances, it could.
12100|       |    ////
12101|       |    // This rounds up to the next power of two.
12102|       |    // We know that user_input.size() is in [0,
12103|       |    // std::numeric_limits<uint32_t>::max).
12104|  10.1k|    uint32_t reserve_capacity =
12105|  10.1k|        (0xFFFFFFFF >>
12106|  10.1k|         helpers::leading_zeroes(uint32_t(1 | user_input.size()))) +
12107|  10.1k|        1;
12108|  10.1k|    url.reserve(reserve_capacity);
12109|       |    //
12110|       |    //
12111|       |    //
12112|  10.1k|  }
12113|  10.1k|  std::string tmp_buffer;
12114|  10.1k|  std::string_view internal_input;
12115|  10.1k|  if (unicode::has_tabs_or_newline(user_input)) {
  ------------------
  |  Branch (12115:7): [True: 141, False: 9.97k]
  ------------------
12116|    141|    tmp_buffer = user_input;
12117|       |    // Optimization opportunity: Instead of copying and then pruning, we could
12118|       |    // just directly build the string from user_input.
12119|    141|    helpers::remove_ascii_tab_or_newline(tmp_buffer);
12120|    141|    internal_input = tmp_buffer;
12121|  9.97k|  } else {
12122|  9.97k|    internal_input = user_input;
12123|  9.97k|  }
12124|       |
12125|       |  // Leading and trailing control characters are uncommon and easy to deal with
12126|       |  // (no performance concern).
12127|  10.1k|  std::string_view url_data = internal_input;
12128|  10.1k|  helpers::trim_c0_whitespace(url_data);
12129|       |
12130|       |  // Optimization opportunity. Most websites do not have fragment.
12131|  10.1k|  std::optional<std::string_view> fragment = helpers::prune_hash(url_data);
12132|       |  // We add it last so that an implementation like ada::url_aggregator
12133|       |  // can append it last to its internal buffer, thus improving performance.
12134|       |
12135|       |  // Here url_data no longer has its fragment.
12136|       |  // We are going to access the data from url_data (it is immutable).
12137|       |  // At any given time, we are pointing at byte 'input_position' in url_data.
12138|       |  // The input_position variable should range from 0 to input_size.
12139|       |  // It is illegal to access url_data at input_size.
12140|  10.1k|  size_t input_position = 0;
12141|  10.1k|  const size_t input_size = url_data.size();
12142|       |  // Keep running the following state machine by switching on state.
12143|       |  // If after a run pointer points to the EOF code point, go to the next step.
12144|       |  // Otherwise, increase pointer by 1 and continue with the state machine.
12145|       |  // We never decrement input_position.
12146|  45.2k|  while (input_position <= input_size) {
  ------------------
  |  Branch (12146:10): [True: 42.4k, False: 2.77k]
  ------------------
12147|  42.4k|    ada_log("In parsing at ", input_position, " out of ", input_size,
12148|  42.4k|            " in state ", ada::to_string(state));
12149|  42.4k|    switch (state) {
12150|  10.1k|      case ada::state::SCHEME_START: {
  ------------------
  |  Branch (12150:7): [True: 10.1k, False: 32.3k]
  ------------------
12151|  10.1k|        ada_log("SCHEME_START ", helpers::substring(url_data, input_position));
12152|       |        // If c is an ASCII alpha, append c, lowercased, to buffer, and set
12153|       |        // state to scheme state.
12154|  10.1k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12154:13): [True: 9.23k, False: 878]
  ------------------
12155|  10.1k|            checkers::is_alpha(url_data[input_position])) {
  ------------------
  |  Branch (12155:13): [True: 7.69k, False: 1.53k]
  ------------------
12156|  7.69k|          state = ada::state::SCHEME;
12157|  7.69k|          input_position++;
12158|  7.69k|        } else {
12159|       |          // Otherwise, if state override is not given, set state to no scheme
12160|       |          // state and decrease pointer by 1.
12161|  2.41k|          state = ada::state::NO_SCHEME;
12162|  2.41k|        }
12163|  10.1k|        break;
12164|      0|      }
12165|  7.69k|      case ada::state::SCHEME: {
  ------------------
  |  Branch (12165:7): [True: 7.69k, False: 34.7k]
  ------------------
12166|  7.69k|        ada_log("SCHEME ", helpers::substring(url_data, input_position));
12167|       |        // If c is an ASCII alphanumeric, U+002B (+), U+002D (-), or U+002E (.),
12168|       |        // append c, lowercased, to buffer.
12169|  25.5k|        while ((input_position != input_size) &&
  ------------------
  |  Branch (12169:16): [True: 25.1k, False: 437]
  ------------------
12170|  25.5k|               (ada::unicode::is_alnum_plus(url_data[input_position]))) {
  ------------------
  |  Branch (12170:16): [True: 17.8k, False: 7.25k]
  ------------------
12171|  17.8k|          input_position++;
12172|  17.8k|        }
12173|       |        // Otherwise, if c is U+003A (:), then:
12174|  7.69k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12174:13): [True: 7.25k, False: 437]
  ------------------
12175|  7.69k|            (url_data[input_position] == ':')) {
  ------------------
  |  Branch (12175:13): [True: 6.97k, False: 281]
  ------------------
12176|  6.97k|          ada_log("SCHEME the scheme should be ",
12177|  6.97k|                  url_data.substr(0, input_position));
12178|  6.97k|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12178:25): [Folded - Ignored]
  ------------------
12179|  6.97k|            if (!url.parse_scheme(url_data.substr(0, input_position))) {
  ------------------
  |  Branch (12179:17): [True: 0, False: 6.97k]
  ------------------
12180|      0|              return url;
12181|      0|            }
12182|  6.97k|          } else {
12183|       |            // we pass the colon along instead of painfully adding it back.
12184|  6.97k|            if (!url.parse_scheme_with_colon(
12185|  6.97k|                    url_data.substr(0, input_position + 1))) {
12186|  6.97k|              return url;
12187|  6.97k|            }
12188|  6.97k|          }
12189|  6.97k|          ada_log("SCHEME the scheme is ", url.get_protocol());
12190|       |
12191|       |          // If url's scheme is "file", then:
12192|  6.97k|          if (url.type == ada::scheme::type::FILE) {
  ------------------
  |  Branch (12192:15): [True: 1.12k, False: 5.85k]
  ------------------
12193|       |            // Set state to file state.
12194|  1.12k|            state = ada::state::FILE;
12195|  1.12k|          }
12196|       |          // Otherwise, if url is special, base is non-null, and base's scheme
12197|       |          // is url's scheme: Note: Doing base_url->scheme is unsafe if base_url
12198|       |          // != nullptr is false.
12199|  5.85k|          else if (url.is_special() && base_url != nullptr &&
  ------------------
  |  Branch (12199:20): [True: 3.85k, False: 2.00k]
  |  Branch (12199:40): [True: 0, False: 3.85k]
  ------------------
12200|  5.85k|                   base_url->type == url.type) {
  ------------------
  |  Branch (12200:20): [True: 0, False: 0]
  ------------------
12201|       |            // Set state to special relative or authority state.
12202|      0|            state = ada::state::SPECIAL_RELATIVE_OR_AUTHORITY;
12203|      0|          }
12204|       |          // Otherwise, if url is special, set state to special authority
12205|       |          // slashes state.
12206|  5.85k|          else if (url.is_special()) {
  ------------------
  |  Branch (12206:20): [True: 3.85k, False: 2.00k]
  ------------------
12207|  3.85k|            state = ada::state::SPECIAL_AUTHORITY_SLASHES;
12208|  3.85k|          }
12209|       |          // Otherwise, if remaining starts with an U+002F (/), set state to
12210|       |          // path or authority state and increase pointer by 1.
12211|  2.00k|          else if (input_position + 1 < input_size &&
  ------------------
  |  Branch (12211:20): [True: 1.67k, False: 322]
  ------------------
12212|  2.00k|                   url_data[input_position + 1] == '/') {
  ------------------
  |  Branch (12212:20): [True: 1.28k, False: 398]
  ------------------
12213|  1.28k|            state = ada::state::PATH_OR_AUTHORITY;
12214|  1.28k|            input_position++;
12215|  1.28k|          }
12216|       |          // Otherwise, set url's path to the empty string and set state to
12217|       |          // opaque path state.
12218|    720|          else {
12219|    720|            state = ada::state::OPAQUE_PATH;
12220|    720|          }
12221|  6.97k|        }
12222|       |        // Otherwise, if state override is not given, set buffer to the empty
12223|       |        // string, state to no scheme state, and start over (from the first code
12224|       |        // point in input).
12225|    718|        else {
12226|    718|          state = ada::state::NO_SCHEME;
12227|    718|          input_position = 0;
12228|    718|          break;
12229|    718|        }
12230|  6.97k|        input_position++;
12231|  6.97k|        break;
12232|  7.69k|      }
12233|  3.13k|      case ada::state::NO_SCHEME: {
  ------------------
  |  Branch (12233:7): [True: 3.13k, False: 39.3k]
  ------------------
12234|  3.13k|        ada_log("NO_SCHEME ", helpers::substring(url_data, input_position));
12235|       |        // If base is null, or base has an opaque path and c is not U+0023 (#),
12236|       |        // validation error, return failure.
12237|  3.13k|        if (base_url == nullptr ||
  ------------------
  |  Branch (12237:13): [True: 3.13k, False: 0]
  ------------------
12238|  3.13k|            (base_url->has_opaque_path && !fragment.has_value())) {
  ------------------
  |  Branch (12238:14): [True: 0, False: 0]
  |  Branch (12238:43): [True: 0, False: 0]
  ------------------
12239|  3.13k|          ada_log("NO_SCHEME validation error");
12240|  3.13k|          url.is_valid = false;
12241|  3.13k|          return url;
12242|  3.13k|        }
12243|       |        // Otherwise, if base has an opaque path and c is U+0023 (#),
12244|       |        // set url's scheme to base's scheme, url's path to base's path, url's
12245|       |        // query to base's query, and set state to fragment state.
12246|      0|        else if (base_url->has_opaque_path && fragment.has_value() &&
  ------------------
  |  Branch (12246:18): [True: 0, False: 0]
  |  Branch (12246:47): [True: 0, False: 0]
  ------------------
12247|      0|                 input_position == input_size) {
  ------------------
  |  Branch (12247:18): [True: 0, False: 0]
  ------------------
12248|      0|          ada_log("NO_SCHEME opaque base with fragment");
12249|      0|          url.copy_scheme(*base_url);
12250|      0|          url.has_opaque_path = base_url->has_opaque_path;
12251|       |
12252|      0|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12252:25): [Folded - Ignored]
  ------------------
12253|      0|            url.path = base_url->path;
12254|      0|            url.query = base_url->query;
12255|      0|          } else {
12256|      0|            url.update_base_pathname(base_url->get_pathname());
12257|      0|            url.update_base_search(base_url->get_search());
12258|      0|          }
12259|      0|          url.update_unencoded_base_hash(*fragment);
12260|      0|          return url;
12261|      0|        }
12262|       |        // Otherwise, if base's scheme is not "file", set state to relative
12263|       |        // state and decrease pointer by 1.
12264|      0|        else if (base_url->type != ada::scheme::type::FILE) {
  ------------------
  |  Branch (12264:18): [True: 0, False: 0]
  ------------------
12265|      0|          ada_log("NO_SCHEME non-file relative path");
12266|      0|          state = ada::state::RELATIVE_SCHEME;
12267|      0|        }
12268|       |        // Otherwise, set state to file state and decrease pointer by 1.
12269|      0|        else {
12270|      0|          ada_log("NO_SCHEME file base type");
12271|      0|          state = ada::state::FILE;
12272|      0|        }
12273|      0|        break;
12274|  3.13k|      }
12275|  4.14k|      case ada::state::AUTHORITY: {
  ------------------
  |  Branch (12275:7): [True: 4.14k, False: 38.2k]
  ------------------
12276|  4.14k|        ada_log("AUTHORITY ", helpers::substring(url_data, input_position));
12277|       |        // most URLs have no @. Having no @ tells us that we don't have to worry
12278|       |        // about AUTHORITY. Of course, we could have @ and still not have to
12279|       |        // worry about AUTHORITY.
12280|       |        // TODO: Instead of just collecting a bool, collect the location of the
12281|       |        // '@' and do something useful with it.
12282|       |        // TODO: We could do various processing early on, using a single pass
12283|       |        // over the string to collect information about it, e.g., telling us
12284|       |        // whether there is a @ and if so, where (or how many).
12285|  4.14k|        const bool contains_ampersand =
12286|  4.14k|            (url_data.find('@', input_position) != std::string_view::npos);
12287|       |
12288|  4.14k|        if (!contains_ampersand) {
  ------------------
  |  Branch (12288:13): [True: 3.82k, False: 321]
  ------------------
12289|  3.82k|          state = ada::state::HOST;
12290|  3.82k|          break;
12291|  3.82k|        }
12292|    321|        bool at_sign_seen{false};
12293|    321|        bool password_token_seen{false};
12294|       |        /**
12295|       |         * We expect something of the sort...
12296|       |         * https://user:pass@example.com:1234/foo/bar?baz#quux
12297|       |         * --------^
12298|       |         */
12299|  2.59k|        do {
12300|  2.59k|          std::string_view view = helpers::substring(url_data, input_position);
12301|       |          // The delimiters are @, /, ? \\.
12302|  2.59k|          size_t location =
12303|  2.59k|              url.is_special() ? helpers::find_authority_delimiter_special(view)
  ------------------
  |  Branch (12303:15): [True: 2.25k, False: 342]
  ------------------
12304|  2.59k|                               : helpers::find_authority_delimiter(view);
12305|  2.59k|          std::string_view authority_view(view.data(), location);
12306|  2.59k|          size_t end_of_authority = input_position + authority_view.size();
12307|       |          // If c is U+0040 (@), then:
12308|  2.59k|          if ((end_of_authority != input_size) &&
  ------------------
  |  Branch (12308:15): [True: 2.31k, False: 281]
  ------------------
12309|  2.59k|              (url_data[end_of_authority] == '@')) {
  ------------------
  |  Branch (12309:15): [True: 2.27k, False: 40]
  ------------------
12310|       |            // If atSignSeen is true, then prepend "%40" to buffer.
12311|  2.27k|            if (at_sign_seen) {
  ------------------
  |  Branch (12311:17): [True: 1.96k, False: 309]
  ------------------
12312|  1.96k|              if (password_token_seen) {
  ------------------
  |  Branch (12312:19): [True: 578, False: 1.38k]
  ------------------
12313|    578|                if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12313:31): [Folded - Ignored]
  ------------------
12314|    578|                  url.password += "%40";
12315|    578|                } else {
12316|    578|                  url.append_base_password("%40");
12317|    578|                }
12318|  1.38k|              } else {
12319|  1.38k|                if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12319:31): [Folded - Ignored]
  ------------------
12320|  1.38k|                  url.username += "%40";
12321|  1.38k|                } else {
12322|  1.38k|                  url.append_base_username("%40");
12323|  1.38k|                }
12324|  1.38k|              }
12325|  1.96k|            }
12326|       |
12327|  2.27k|            at_sign_seen = true;
12328|       |
12329|  2.27k|            if (!password_token_seen) {
  ------------------
  |  Branch (12329:17): [True: 1.69k, False: 578]
  ------------------
12330|  1.69k|              size_t password_token_location = authority_view.find(':');
12331|  1.69k|              password_token_seen =
12332|  1.69k|                  password_token_location != std::string_view::npos;
12333|       |
12334|  1.69k|              if (!password_token_seen) {
  ------------------
  |  Branch (12334:19): [True: 1.58k, False: 114]
  ------------------
12335|  1.58k|                if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12335:31): [Folded - Ignored]
  ------------------
12336|  1.58k|                  url.username += unicode::percent_encode(
12337|  1.58k|                      authority_view, character_sets::USERINFO_PERCENT_ENCODE);
12338|  1.58k|                } else {
12339|  1.58k|                  url.append_base_username(unicode::percent_encode(
12340|  1.58k|                      authority_view, character_sets::USERINFO_PERCENT_ENCODE));
12341|  1.58k|                }
12342|  1.58k|              } else {
12343|    114|                if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12343:31): [Folded - Ignored]
  ------------------
12344|    114|                  url.username += unicode::percent_encode(
12345|    114|                      authority_view.substr(0, password_token_location),
12346|    114|                      character_sets::USERINFO_PERCENT_ENCODE);
12347|    114|                  url.password += unicode::percent_encode(
12348|    114|                      authority_view.substr(password_token_location + 1),
12349|    114|                      character_sets::USERINFO_PERCENT_ENCODE);
12350|    114|                } else {
12351|    114|                  url.append_base_username(unicode::percent_encode(
12352|    114|                      authority_view.substr(0, password_token_location),
12353|    114|                      character_sets::USERINFO_PERCENT_ENCODE));
12354|    114|                  url.append_base_password(unicode::percent_encode(
12355|    114|                      authority_view.substr(password_token_location + 1),
12356|    114|                      character_sets::USERINFO_PERCENT_ENCODE));
12357|    114|                }
12358|    114|              }
12359|  1.69k|            } else {
12360|    578|              if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12360:29): [Folded - Ignored]
  ------------------
12361|    578|                url.password += unicode::percent_encode(
12362|    578|                    authority_view, character_sets::USERINFO_PERCENT_ENCODE);
12363|    578|              } else {
12364|    578|                url.append_base_password(unicode::percent_encode(
12365|    578|                    authority_view, character_sets::USERINFO_PERCENT_ENCODE));
12366|    578|              }
12367|    578|            }
12368|  2.27k|          }
12369|       |          // Otherwise, if one of the following is true:
12370|       |          // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
12371|       |          // - url is special and c is U+005C (\)
12372|    321|          else if (end_of_authority == input_size ||
  ------------------
  |  Branch (12372:20): [True: 281, False: 40]
  ------------------
12373|    321|                   url_data[end_of_authority] == '/' ||
  ------------------
  |  Branch (12373:20): [True: 21, False: 19]
  ------------------
12374|    321|                   url_data[end_of_authority] == '?' ||
  ------------------
  |  Branch (12374:20): [True: 17, False: 2]
  ------------------
12375|    321|                   (url.is_special() && url_data[end_of_authority] == '\\')) {
  ------------------
  |  Branch (12375:21): [True: 2, False: 0]
  |  Branch (12375:41): [True: 2, False: 0]
  ------------------
12376|       |            // If atSignSeen is true and authority_view is the empty string,
12377|       |            // validation error, return failure.
12378|    321|            if (at_sign_seen && authority_view.empty()) {
  ------------------
  |  Branch (12378:17): [True: 309, False: 12]
  |  Branch (12378:33): [True: 155, False: 154]
  ------------------
12379|    155|              url.is_valid = false;
12380|    155|              return url;
12381|    155|            }
12382|    166|            state = ada::state::HOST;
12383|    166|            break;
12384|    321|          }
12385|  2.27k|          if (end_of_authority == input_size) {
  ------------------
  |  Branch (12385:15): [True: 0, False: 2.27k]
  ------------------
12386|      0|            if (fragment.has_value()) {
  ------------------
  |  Branch (12386:17): [True: 0, False: 0]
  ------------------
12387|      0|              url.update_unencoded_base_hash(*fragment);
12388|      0|            }
12389|      0|            return url;
12390|      0|          }
12391|  2.27k|          input_position = end_of_authority + 1;
12392|  2.27k|        } while (true);
  ------------------
  |  Branch (12392:18): [Folded - Ignored]
  ------------------
12393|       |
12394|    166|        break;
12395|    321|      }
12396|    166|      case ada::state::SPECIAL_RELATIVE_OR_AUTHORITY: {
  ------------------
  |  Branch (12396:7): [True: 0, False: 42.4k]
  ------------------
12397|      0|        ada_log("SPECIAL_RELATIVE_OR_AUTHORITY ",
12398|      0|                helpers::substring(url_data, input_position));
12399|       |
12400|       |        // If c is U+002F (/) and remaining starts with U+002F (/),
12401|       |        // then set state to special authority ignore slashes state and increase
12402|       |        // pointer by 1.
12403|      0|        std::string_view view = helpers::substring(url_data, input_position);
12404|      0|        if (ada::checkers::begins_with(view, "//")) {
  ------------------
  |  Branch (12404:13): [True: 0, False: 0]
  ------------------
12405|      0|          state = ada::state::SPECIAL_AUTHORITY_IGNORE_SLASHES;
12406|      0|          input_position += 2;
12407|      0|        } else {
12408|       |          // Otherwise, validation error, set state to relative state and
12409|       |          // decrease pointer by 1.
12410|      0|          state = ada::state::RELATIVE_SCHEME;
12411|      0|        }
12412|       |
12413|      0|        break;
12414|    321|      }
12415|  1.28k|      case ada::state::PATH_OR_AUTHORITY: {
  ------------------
  |  Branch (12415:7): [True: 1.28k, False: 41.1k]
  ------------------
12416|  1.28k|        ada_log("PATH_OR_AUTHORITY ",
12417|  1.28k|                helpers::substring(url_data, input_position));
12418|       |
12419|       |        // If c is U+002F (/), then set state to authority state.
12420|  1.28k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12420:13): [True: 599, False: 682]
  ------------------
12421|  1.28k|            (url_data[input_position] == '/')) {
  ------------------
  |  Branch (12421:13): [True: 291, False: 308]
  ------------------
12422|    291|          state = ada::state::AUTHORITY;
12423|    291|          input_position++;
12424|    990|        } else {
12425|       |          // Otherwise, set state to path state, and decrease pointer by 1.
12426|    990|          state = ada::state::PATH;
12427|    990|        }
12428|       |
12429|  1.28k|        break;
12430|    321|      }
12431|      0|      case ada::state::RELATIVE_SCHEME: {
  ------------------
  |  Branch (12431:7): [True: 0, False: 42.4k]
  ------------------
12432|      0|        ada_log("RELATIVE_SCHEME ",
12433|      0|                helpers::substring(url_data, input_position));
12434|       |
12435|       |        // Set url's scheme to base's scheme.
12436|      0|        url.copy_scheme(*base_url);
12437|       |
12438|       |        // If c is U+002F (/), then set state to relative slash state.
12439|      0|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12439:13): [True: 0, False: 0]
  ------------------
12440|      0|            (url_data[input_position] == '/')) {
  ------------------
  |  Branch (12440:13): [True: 0, False: 0]
  ------------------
12441|      0|          ada_log(
12442|      0|              "RELATIVE_SCHEME if c is U+002F (/), then set state to relative "
12443|      0|              "slash state");
12444|      0|          state = ada::state::RELATIVE_SLASH;
12445|      0|        } else if (url.is_special() && (input_position != input_size) &&
  ------------------
  |  Branch (12445:20): [True: 0, False: 0]
  |  Branch (12445:40): [True: 0, False: 0]
  ------------------
12446|      0|                   (url_data[input_position] == '\\')) {
  ------------------
  |  Branch (12446:20): [True: 0, False: 0]
  ------------------
12447|       |          // Otherwise, if url is special and c is U+005C (\), validation error,
12448|       |          // set state to relative slash state.
12449|      0|          ada_log(
12450|      0|              "RELATIVE_SCHEME  if url is special and c is U+005C, validation "
12451|      0|              "error, set state to relative slash state");
12452|      0|          state = ada::state::RELATIVE_SLASH;
12453|      0|        } else {
12454|      0|          ada_log("RELATIVE_SCHEME otherwise");
12455|       |          // Set url's username to base's username, url's password to base's
12456|       |          // password, url's host to base's host, url's port to base's port,
12457|       |          // url's path to a clone of base's path, and url's query to base's
12458|       |          // query.
12459|      0|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12459:25): [Folded - Ignored]
  ------------------
12460|      0|            url.username = base_url->username;
12461|      0|            url.password = base_url->password;
12462|      0|            url.host = base_url->host;
12463|      0|            url.port = base_url->port;
12464|       |            // cloning the base path includes cloning the has_opaque_path flag
12465|      0|            url.has_opaque_path = base_url->has_opaque_path;
12466|      0|            url.path = base_url->path;
12467|      0|            url.query = base_url->query;
12468|      0|          } else {
12469|      0|            url.update_base_authority(base_url->get_href(),
12470|      0|                                      base_url->get_components());
12471|       |            // TODO: Get rid of set_hostname and replace it with
12472|       |            // update_base_hostname
12473|      0|            url.set_hostname(base_url->get_hostname());
12474|      0|            url.update_base_port(base_url->retrieve_base_port());
12475|       |            // cloning the base path includes cloning the has_opaque_path flag
12476|      0|            url.has_opaque_path = base_url->has_opaque_path;
12477|      0|            url.update_base_pathname(base_url->get_pathname());
12478|      0|            url.update_base_search(base_url->get_search());
12479|      0|          }
12480|       |
12481|      0|          url.has_opaque_path = base_url->has_opaque_path;
12482|       |
12483|       |          // If c is U+003F (?), then set url's query to the empty string, and
12484|       |          // state to query state.
12485|      0|          if ((input_position != input_size) &&
  ------------------
  |  Branch (12485:15): [True: 0, False: 0]
  ------------------
12486|      0|              (url_data[input_position] == '?')) {
  ------------------
  |  Branch (12486:15): [True: 0, False: 0]
  ------------------
12487|      0|            state = ada::state::QUERY;
12488|      0|          }
12489|       |          // Otherwise, if c is not the EOF code point:
12490|      0|          else if (input_position != input_size) {
  ------------------
  |  Branch (12490:20): [True: 0, False: 0]
  ------------------
12491|       |            // Set url's query to null.
12492|      0|            url.clear_search();
12493|      0|            if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12493:27): [Folded - Ignored]
  ------------------
12494|       |              // Shorten url's path.
12495|      0|              helpers::shorten_path(url.path, url.type);
12496|      0|            } else {
12497|      0|              std::string_view path = url.get_pathname();
12498|      0|              if (helpers::shorten_path(path, url.type)) {
12499|      0|                url.update_base_pathname(std::string(path));
12500|      0|              }
12501|      0|            }
12502|       |            // Set state to path state and decrease pointer by 1.
12503|      0|            state = ada::state::PATH;
12504|      0|            break;
12505|      0|          }
12506|      0|        }
12507|      0|        input_position++;
12508|      0|        break;
12509|      0|      }
12510|      0|      case ada::state::RELATIVE_SLASH: {
  ------------------
  |  Branch (12510:7): [True: 0, False: 42.4k]
  ------------------
12511|      0|        ada_log("RELATIVE_SLASH ",
12512|      0|                helpers::substring(url_data, input_position));
12513|       |
12514|       |        // If url is special and c is U+002F (/) or U+005C (\), then:
12515|      0|        if (url.is_special() && (input_position != input_size) &&
  ------------------
  |  Branch (12515:13): [True: 0, False: 0]
  |  Branch (12515:33): [True: 0, False: 0]
  ------------------
12516|      0|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (12516:14): [True: 0, False: 0]
  ------------------
12517|      0|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (12517:14): [True: 0, False: 0]
  ------------------
12518|       |          // Set state to special authority ignore slashes state.
12519|      0|          state = ada::state::SPECIAL_AUTHORITY_IGNORE_SLASHES;
12520|      0|        }
12521|       |        // Otherwise, if c is U+002F (/), then set state to authority state.
12522|      0|        else if ((input_position != input_size) &&
  ------------------
  |  Branch (12522:18): [True: 0, False: 0]
  ------------------
12523|      0|                 (url_data[input_position] == '/')) {
  ------------------
  |  Branch (12523:18): [True: 0, False: 0]
  ------------------
12524|      0|          state = ada::state::AUTHORITY;
12525|      0|        }
12526|       |        // Otherwise, set
12527|       |        // - url's username to base's username,
12528|       |        // - url's password to base's password,
12529|       |        // - url's host to base's host,
12530|       |        // - url's port to base's port,
12531|       |        // - state to path state, and then, decrease pointer by 1.
12532|      0|        else {
12533|      0|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12533:25): [Folded - Ignored]
  ------------------
12534|      0|            url.username = base_url->username;
12535|      0|            url.password = base_url->password;
12536|      0|            url.host = base_url->host;
12537|      0|            url.port = base_url->port;
12538|      0|          } else {
12539|      0|            url.update_base_authority(base_url->get_href(),
12540|      0|                                      base_url->get_components());
12541|       |            // TODO: Get rid of set_hostname and replace it with
12542|       |            // update_base_hostname
12543|      0|            url.set_hostname(base_url->get_hostname());
12544|      0|            url.update_base_port(base_url->retrieve_base_port());
12545|      0|          }
12546|      0|          state = ada::state::PATH;
12547|      0|          break;
12548|      0|        }
12549|       |
12550|      0|        input_position++;
12551|      0|        break;
12552|      0|      }
12553|  3.85k|      case ada::state::SPECIAL_AUTHORITY_SLASHES: {
  ------------------
  |  Branch (12553:7): [True: 3.85k, False: 38.5k]
  ------------------
12554|  3.85k|        ada_log("SPECIAL_AUTHORITY_SLASHES ",
12555|  3.85k|                helpers::substring(url_data, input_position));
12556|       |
12557|       |        // If c is U+002F (/) and remaining starts with U+002F (/),
12558|       |        // then set state to special authority ignore slashes state and increase
12559|       |        // pointer by 1.
12560|  3.85k|        std::string_view view = helpers::substring(url_data, input_position);
12561|  3.85k|        if (ada::checkers::begins_with(view, "//")) {
  ------------------
  |  Branch (12561:13): [True: 8, False: 3.84k]
  ------------------
12562|      8|          input_position += 2;
12563|      8|        }
12564|       |
12565|  3.85k|        [[fallthrough]];
12566|  3.85k|      }
12567|  3.85k|      case ada::state::SPECIAL_AUTHORITY_IGNORE_SLASHES: {
  ------------------
  |  Branch (12567:7): [True: 0, False: 42.4k]
  ------------------
12568|  3.85k|        ada_log("SPECIAL_AUTHORITY_IGNORE_SLASHES ",
12569|  3.85k|                helpers::substring(url_data, input_position));
12570|       |
12571|       |        // If c is neither U+002F (/) nor U+005C (\), then set state to
12572|       |        // authority state and decrease pointer by 1.
12573|  4.32k|        while ((input_position != input_size) &&
  ------------------
  |  Branch (12573:16): [True: 4.30k, False: 24]
  ------------------
12574|  4.32k|               ((url_data[input_position] == '/') ||
  ------------------
  |  Branch (12574:17): [True: 231, False: 4.07k]
  ------------------
12575|  4.30k|                (url_data[input_position] == '\\'))) {
  ------------------
  |  Branch (12575:17): [True: 237, False: 3.83k]
  ------------------
12576|    468|          input_position++;
12577|    468|        }
12578|  3.85k|        state = ada::state::AUTHORITY;
12579|       |
12580|  3.85k|        break;
12581|  3.85k|      }
12582|    217|      case ada::state::QUERY: {
  ------------------
  |  Branch (12582:7): [True: 217, False: 42.2k]
  ------------------
12583|    217|        ada_log("QUERY ", helpers::substring(url_data, input_position));
12584|       |        // Let queryPercentEncodeSet be the special-query percent-encode set if
12585|       |        // url is special; otherwise the query percent-encode set.
12586|    217|        const uint8_t* query_percent_encode_set =
12587|    217|            url.is_special() ? ada::character_sets::SPECIAL_QUERY_PERCENT_ENCODE
  ------------------
  |  Branch (12587:13): [True: 84, False: 133]
  ------------------
12588|    217|                             : ada::character_sets::QUERY_PERCENT_ENCODE;
12589|       |
12590|       |        // Percent-encode after encoding, with encoding, buffer, and
12591|       |        // queryPercentEncodeSet, and append the result to url's query.
12592|    217|        url.update_base_search(helpers::substring(url_data, input_position),
12593|    217|                               query_percent_encode_set);
12594|    217|        ada_log("QUERY update_base_search completed ");
12595|    217|        if (fragment.has_value()) {
  ------------------
  |  Branch (12595:13): [True: 58, False: 159]
  ------------------
12596|     58|          url.update_unencoded_base_hash(*fragment);
12597|     58|        }
12598|    217|        return url;
12599|  3.85k|      }
12600|  3.99k|      case ada::state::HOST: {
  ------------------
  |  Branch (12600:7): [True: 3.99k, False: 38.4k]
  ------------------
12601|  3.99k|        ada_log("HOST ", helpers::substring(url_data, input_position));
12602|       |
12603|  3.99k|        std::string_view host_view =
12604|  3.99k|            helpers::substring(url_data, input_position);
12605|  3.99k|        auto [location, found_colon] =
12606|  3.99k|            helpers::get_host_delimiter_location(url.is_special(), host_view);
12607|  3.99k|        input_position = (location != std::string_view::npos)
  ------------------
  |  Branch (12607:26): [True: 3.99k, False: 0]
  ------------------
12608|  3.99k|                             ? input_position + location
12609|  3.99k|                             : input_size;
12610|       |        // Otherwise, if c is U+003A (:) and insideBrackets is false, then:
12611|       |        // Note: the 'found_colon' value is true if and only if a colon was
12612|       |        // encountered while not inside brackets.
12613|  3.99k|        if (found_colon) {
  ------------------
  |  Branch (12613:13): [True: 601, False: 3.39k]
  ------------------
12614|       |          // If buffer is the empty string, validation error, return failure.
12615|       |          // Let host be the result of host parsing buffer with url is not
12616|       |          // special.
12617|    601|          ada_log("HOST parsing ", host_view);
12618|    601|          if (!url.parse_host(host_view)) {
  ------------------
  |  Branch (12618:15): [True: 86, False: 515]
  ------------------
12619|     86|            return url;
12620|     86|          }
12621|    515|          ada_log("HOST parsing results in ", url.get_hostname());
12622|       |          // Set url's host to host, buffer to the empty string, and state to
12623|       |          // port state.
12624|    515|          state = ada::state::PORT;
12625|    515|          input_position++;
12626|    515|        }
12627|       |        // Otherwise, if one of the following is true:
12628|       |        // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
12629|       |        // - url is special and c is U+005C (\)
12630|       |        // The get_host_delimiter_location function either brings us to
12631|       |        // the colon outside of the bracket, or to one of those characters.
12632|  3.39k|        else {
12633|       |          // If url is special and host_view is the empty string, validation
12634|       |          // error, return failure.
12635|  3.39k|          if (url.is_special() && host_view.empty()) {
  ------------------
  |  Branch (12635:15): [True: 3.18k, False: 207]
  |  Branch (12635:35): [True: 27, False: 3.15k]
  ------------------
12636|     27|            url.is_valid = false;
12637|     27|            return url;
12638|     27|          }
12639|  3.36k|          ada_log("HOST parsing ", host_view, " href=", url.get_href());
12640|       |          // Let host be the result of host parsing host_view with url is not
12641|       |          // special.
12642|  3.36k|          if (host_view.empty()) {
  ------------------
  |  Branch (12642:15): [True: 15, False: 3.35k]
  ------------------
12643|     15|            url.update_base_hostname("");
12644|  3.35k|          } else if (!url.parse_host(host_view)) {
  ------------------
  |  Branch (12644:22): [True: 814, False: 2.53k]
  ------------------
12645|    814|            return url;
12646|    814|          }
12647|  2.55k|          ada_log("HOST parsing results in ", url.get_hostname(),
12648|  2.55k|                  " href=", url.get_href());
12649|       |
12650|       |          // Set url's host to host, and state to path start state.
12651|  2.55k|          state = ada::state::PATH_START;
12652|  2.55k|        }
12653|       |
12654|  3.06k|        break;
12655|  3.99k|      }
12656|  3.06k|      case ada::state::OPAQUE_PATH: {
  ------------------
  |  Branch (12656:7): [True: 720, False: 41.7k]
  ------------------
12657|    720|        ada_log("OPAQUE_PATH ", helpers::substring(url_data, input_position));
12658|    720|        std::string_view view = helpers::substring(url_data, input_position);
12659|       |        // If c is U+003F (?), then set url's query to the empty string and
12660|       |        // state to query state.
12661|    720|        size_t location = view.find('?');
12662|    720|        if (location != std::string_view::npos) {
  ------------------
  |  Branch (12662:13): [True: 53, False: 667]
  ------------------
12663|     53|          view.remove_suffix(view.size() - location);
12664|     53|          state = ada::state::QUERY;
12665|     53|          input_position += location + 1;
12666|    667|        } else {
12667|    667|          input_position = input_size + 1;
12668|    667|        }
12669|    720|        url.has_opaque_path = true;
12670|       |        // This is a really unlikely scenario in real world. We should not seek
12671|       |        // to optimize it.
12672|    720|        url.update_base_pathname(unicode::percent_encode(
12673|    720|            view, character_sets::C0_CONTROL_PERCENT_ENCODE));
12674|    720|        break;
12675|  3.99k|      }
12676|    515|      case ada::state::PORT: {
  ------------------
  |  Branch (12676:7): [True: 515, False: 41.9k]
  ------------------
12677|    515|        ada_log("PORT ", helpers::substring(url_data, input_position));
12678|    515|        std::string_view port_view =
12679|    515|            helpers::substring(url_data, input_position);
12680|    515|        size_t consumed_bytes = url.parse_port(port_view, true);
12681|    515|        input_position += consumed_bytes;
12682|    515|        if (!url.is_valid) {
  ------------------
  |  Branch (12682:13): [True: 57, False: 458]
  ------------------
12683|     57|          return url;
12684|     57|        }
12685|    458|        state = state::PATH_START;
12686|    458|        [[fallthrough]];
12687|    458|      }
12688|  3.27k|      case ada::state::PATH_START: {
  ------------------
  |  Branch (12688:7): [True: 2.81k, False: 39.6k]
  ------------------
12689|  3.27k|        ada_log("PATH_START ", helpers::substring(url_data, input_position));
12690|       |
12691|       |        // If url is special, then:
12692|  3.27k|        if (url.is_special()) {
  ------------------
  |  Branch (12692:13): [True: 3.07k, False: 194]
  ------------------
12693|       |          // Set state to path state.
12694|  3.07k|          state = ada::state::PATH;
12695|       |
12696|       |          // Optimization: Avoiding going into PATH state improves the
12697|       |          // performance of urls ending with /.
12698|  3.07k|          if (input_position == input_size) {
  ------------------
  |  Branch (12698:15): [True: 2.76k, False: 315]
  ------------------
12699|  2.76k|            url.update_base_pathname("/");
12700|  2.76k|            if (fragment.has_value()) {
  ------------------
  |  Branch (12700:17): [True: 57, False: 2.70k]
  ------------------
12701|     57|              url.update_unencoded_base_hash(*fragment);
12702|     57|            }
12703|  2.76k|            return url;
12704|  2.76k|          }
12705|       |          // If c is neither U+002F (/) nor U+005C (\), then decrease pointer
12706|       |          // by 1. We know that (input_position == input_size) is impossible
12707|       |          // here, because of the previous if-check.
12708|    315|          if ((url_data[input_position] != '/') &&
  ------------------
  |  Branch (12708:15): [True: 76, False: 239]
  ------------------
12709|    315|              (url_data[input_position] != '\\')) {
  ------------------
  |  Branch (12709:15): [True: 67, False: 9]
  ------------------
12710|     67|            break;
12711|     67|          }
12712|    315|        }
12713|       |        // Otherwise, if state override is not given and c is U+003F (?),
12714|       |        // set url's query to the empty string and state to query state.
12715|    194|        else if ((input_position != input_size) &&
  ------------------
  |  Branch (12715:18): [True: 70, False: 124]
  ------------------
12716|    194|                 (url_data[input_position] == '?')) {
  ------------------
  |  Branch (12716:18): [True: 65, False: 5]
  ------------------
12717|     65|          state = ada::state::QUERY;
12718|     65|        }
12719|       |        // Otherwise, if c is not the EOF code point:
12720|    129|        else if (input_position != input_size) {
  ------------------
  |  Branch (12720:18): [True: 5, False: 124]
  ------------------
12721|       |          // Set state to path state.
12722|      5|          state = ada::state::PATH;
12723|       |
12724|       |          // If c is not U+002F (/), then decrease pointer by 1.
12725|      5|          if (url_data[input_position] != '/') {
  ------------------
  |  Branch (12725:15): [True: 0, False: 5]
  ------------------
12726|      0|            break;
12727|      0|          }
12728|      5|        }
12729|       |
12730|    442|        input_position++;
12731|    442|        break;
12732|  3.27k|      }
12733|  2.08k|      case ada::state::PATH: {
  ------------------
  |  Branch (12733:7): [True: 2.08k, False: 40.3k]
  ------------------
12734|  2.08k|        std::string_view view = helpers::substring(url_data, input_position);
12735|  2.08k|        ada_log("PATH ", helpers::substring(url_data, input_position));
12736|       |
12737|       |        // Most time, we do not need percent encoding.
12738|       |        // Furthermore, we can immediately locate the '?'.
12739|  2.08k|        size_t locofquestionmark = view.find('?');
12740|  2.08k|        if (locofquestionmark != std::string_view::npos) {
  ------------------
  |  Branch (12740:13): [True: 99, False: 1.98k]
  ------------------
12741|     99|          state = ada::state::QUERY;
12742|     99|          view.remove_suffix(view.size() - locofquestionmark);
12743|     99|          input_position += locofquestionmark + 1;
12744|  1.98k|        } else {
12745|  1.98k|          input_position = input_size + 1;
12746|  1.98k|        }
12747|  2.08k|        if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12747:23): [Folded - Ignored]
  ------------------
12748|  2.08k|          helpers::parse_prepared_path(view, url.type, url.path);
12749|  2.08k|        } else {
12750|  2.08k|          url.consume_prepared_path(view);
12751|  2.08k|          ADA_ASSERT_TRUE(url.validate());
12752|  2.08k|        }
12753|  2.08k|        break;
12754|  3.27k|      }
12755|    400|      case ada::state::FILE_SLASH: {
  ------------------
  |  Branch (12755:7): [True: 400, False: 42.0k]
  ------------------
12756|    400|        ada_log("FILE_SLASH ", helpers::substring(url_data, input_position));
12757|       |
12758|       |        // If c is U+002F (/) or U+005C (\), then:
12759|    400|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12759:13): [True: 371, False: 29]
  ------------------
12760|    400|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (12760:14): [True: 351, False: 20]
  ------------------
12761|    371|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (12761:14): [True: 2, False: 18]
  ------------------
12762|    353|          ada_log("FILE_SLASH c is U+002F or U+005C");
12763|       |          // Set state to file host state.
12764|    353|          state = ada::state::FILE_HOST;
12765|    353|          input_position++;
12766|    353|        } else {
12767|     47|          ada_log("FILE_SLASH otherwise");
12768|       |          // If base is non-null and base's scheme is "file", then:
12769|       |          // Note: it is unsafe to do base_url->scheme unless you know that
12770|       |          // base_url_has_value() is true.
12771|     47|          if (base_url != nullptr &&
  ------------------
  |  Branch (12771:15): [True: 0, False: 47]
  ------------------
12772|     47|              base_url->type == ada::scheme::type::FILE) {
  ------------------
  |  Branch (12772:15): [True: 0, False: 0]
  ------------------
12773|       |            // Set url's host to base's host.
12774|      0|            if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12774:27): [Folded - Ignored]
  ------------------
12775|      0|              url.host = base_url->host;
12776|      0|            } else {
12777|       |              // TODO: Optimization opportunity.
12778|      0|              url.set_host(base_url->get_host());
12779|      0|            }
12780|       |            // If the code point substring from pointer to the end of input does
12781|       |            // not start with a Windows drive letter and base's path[0] is a
12782|       |            // normalized Windows drive letter, then append base's path[0] to
12783|       |            // url's path.
12784|      0|            if (!base_url->get_pathname().empty()) {
  ------------------
  |  Branch (12784:17): [True: 0, False: 0]
  ------------------
12785|      0|              if (!checkers::is_windows_drive_letter(
  ------------------
  |  Branch (12785:19): [True: 0, False: 0]
  ------------------
12786|      0|                      helpers::substring(url_data, input_position))) {
12787|      0|                std::string_view first_base_url_path =
12788|      0|                    base_url->get_pathname().substr(1);
12789|      0|                size_t loc = first_base_url_path.find('/');
12790|      0|                if (loc != std::string_view::npos) {
  ------------------
  |  Branch (12790:21): [True: 0, False: 0]
  ------------------
12791|      0|                  helpers::resize(first_base_url_path, loc);
12792|      0|                }
12793|      0|                if (checkers::is_normalized_windows_drive_letter(
  ------------------
  |  Branch (12793:21): [True: 0, False: 0]
  ------------------
12794|      0|                        first_base_url_path)) {
12795|      0|                  if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12795:33): [Folded - Ignored]
  ------------------
12796|      0|                    url.path += '/';
12797|      0|                    url.path += first_base_url_path;
12798|      0|                  } else {
12799|      0|                    url.append_base_pathname(
12800|      0|                        helpers::concat("/", first_base_url_path));
12801|      0|                  }
12802|      0|                }
12803|      0|              }
12804|      0|            }
12805|      0|          }
12806|       |
12807|       |          // Set state to path state, and decrease pointer by 1.
12808|     47|          state = ada::state::PATH;
12809|     47|        }
12810|       |
12811|    400|        break;
12812|  3.27k|      }
12813|    353|      case ada::state::FILE_HOST: {
  ------------------
  |  Branch (12813:7): [True: 353, False: 42.0k]
  ------------------
12814|    353|        std::string_view view = helpers::substring(url_data, input_position);
12815|    353|        ada_log("FILE_HOST ", helpers::substring(url_data, input_position));
12816|       |
12817|    353|        size_t location = view.find_first_of("/\\?");
12818|    353|        std::string_view file_host_buffer(
12819|    353|            view.data(),
12820|    353|            (location != std::string_view::npos) ? location : view.size());
  ------------------
  |  Branch (12820:13): [True: 24, False: 329]
  ------------------
12821|       |
12822|    353|        if (checkers::is_windows_drive_letter(file_host_buffer)) {
  ------------------
  |  Branch (12822:13): [True: 5, False: 348]
  ------------------
12823|      5|          state = ada::state::PATH;
12824|    348|        } else if (file_host_buffer.empty()) {
  ------------------
  |  Branch (12824:20): [True: 10, False: 338]
  ------------------
12825|       |          // Set url's host to the empty string.
12826|     10|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12826:25): [Folded - Ignored]
  ------------------
12827|     10|            url.host = "";
12828|     10|          } else {
12829|     10|            url.update_base_hostname("");
12830|     10|          }
12831|       |          // Set state to path start state.
12832|     10|          state = ada::state::PATH_START;
12833|    338|        } else {
12834|    338|          size_t consumed_bytes = file_host_buffer.size();
12835|    338|          input_position += consumed_bytes;
12836|       |          // Let host be the result of host parsing buffer with url is not
12837|       |          // special.
12838|    338|          if (!url.parse_host(file_host_buffer)) {
  ------------------
  |  Branch (12838:15): [True: 87, False: 251]
  ------------------
12839|     87|            return url;
12840|     87|          }
12841|       |
12842|    251|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12842:25): [Folded - Ignored]
  ------------------
12843|       |            // If host is "localhost", then set host to the empty string.
12844|    251|            if (url.host.has_value() && url.host.value() == "localhost") {
  ------------------
  |  Branch (12844:17): [True: 251, False: 0]
  |  Branch (12844:41): [True: 2, False: 249]
  ------------------
12845|      2|              url.host = "";
12846|      2|            }
12847|    251|          } else {
12848|    251|            if (url.get_hostname() == "localhost") {
12849|    251|              url.update_base_hostname("");
12850|    251|            }
12851|    251|          }
12852|       |
12853|       |          // Set buffer to the empty string and state to path start state.
12854|    251|          state = ada::state::PATH_START;
12855|    251|        }
12856|       |
12857|    266|        break;
12858|    353|      }
12859|  1.12k|      case ada::state::FILE: {
  ------------------
  |  Branch (12859:7): [True: 1.12k, False: 41.3k]
  ------------------
12860|  1.12k|        ada_log("FILE ", helpers::substring(url_data, input_position));
12861|  1.12k|        std::string_view file_view =
12862|  1.12k|            helpers::substring(url_data, input_position);
12863|       |
12864|  1.12k|        url.set_protocol_as_file();
12865|  1.12k|        if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12865:23): [Folded - Ignored]
  ------------------
12866|       |          // Set url's host to the empty string.
12867|  1.12k|          url.host = "";
12868|  1.12k|        } else {
12869|  1.12k|          url.update_base_hostname("");
12870|  1.12k|        }
12871|       |        // If c is U+002F (/) or U+005C (\), then:
12872|  1.12k|        if (input_position != input_size &&
  ------------------
  |  Branch (12872:13): [True: 657, False: 463]
  ------------------
12873|  1.12k|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (12873:14): [True: 396, False: 261]
  ------------------
12874|    657|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (12874:14): [True: 4, False: 257]
  ------------------
12875|    400|          ada_log("FILE c is U+002F or U+005C");
12876|       |          // Set state to file slash state.
12877|    400|          state = ada::state::FILE_SLASH;
12878|    400|        }
12879|       |        // Otherwise, if base is non-null and base's scheme is "file":
12880|    720|        else if (base_url != nullptr &&
  ------------------
  |  Branch (12880:18): [True: 0, False: 720]
  ------------------
12881|    720|                 base_url->type == ada::scheme::type::FILE) {
  ------------------
  |  Branch (12881:18): [True: 0, False: 0]
  ------------------
12882|       |          // Set url's host to base's host, url's path to a clone of base's
12883|       |          // path, and url's query to base's query.
12884|      0|          ada_log("FILE base non-null");
12885|      0|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12885:25): [Folded - Ignored]
  ------------------
12886|      0|            url.host = base_url->host;
12887|      0|            url.path = base_url->path;
12888|      0|            url.query = base_url->query;
12889|      0|          } else {
12890|       |            // TODO: Get rid of set_hostname and replace it with
12891|       |            // update_base_hostname
12892|      0|            url.set_hostname(base_url->get_hostname());
12893|      0|            url.update_base_pathname(base_url->get_pathname());
12894|      0|            url.update_base_search(base_url->get_search());
12895|      0|          }
12896|      0|          url.has_opaque_path = base_url->has_opaque_path;
12897|       |
12898|       |          // If c is U+003F (?), then set url's query to the empty string and
12899|       |          // state to query state.
12900|      0|          if (input_position != input_size && url_data[input_position] == '?') {
  ------------------
  |  Branch (12900:15): [True: 0, False: 0]
  |  Branch (12900:47): [True: 0, False: 0]
  ------------------
12901|      0|            state = ada::state::QUERY;
12902|      0|          }
12903|       |          // Otherwise, if c is not the EOF code point:
12904|      0|          else if (input_position != input_size) {
  ------------------
  |  Branch (12904:20): [True: 0, False: 0]
  ------------------
12905|       |            // Set url's query to null.
12906|      0|            url.clear_search();
12907|       |            // If the code point substring from pointer to the end of input does
12908|       |            // not start with a Windows drive letter, then shorten url's path.
12909|      0|            if (!checkers::is_windows_drive_letter(file_view)) {
  ------------------
  |  Branch (12909:17): [True: 0, False: 0]
  ------------------
12910|      0|              if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12910:29): [Folded - Ignored]
  ------------------
12911|      0|                helpers::shorten_path(url.path, url.type);
12912|      0|              } else {
12913|      0|                std::string_view path = url.get_pathname();
12914|      0|                if (helpers::shorten_path(path, url.type)) {
12915|      0|                  url.update_base_pathname(std::string(path));
12916|      0|                }
12917|      0|              }
12918|      0|            }
12919|       |            // Otherwise:
12920|      0|            else {
12921|       |              // Set url's path to an empty list.
12922|      0|              url.clear_pathname();
12923|      0|              url.has_opaque_path = true;
12924|      0|            }
12925|       |
12926|       |            // Set state to path state and decrease pointer by 1.
12927|      0|            state = ada::state::PATH;
12928|      0|            break;
12929|      0|          }
12930|      0|        }
12931|       |        // Otherwise, set state to path state, and decrease pointer by 1.
12932|    720|        else {
12933|    720|          ada_log("FILE go to path");
12934|    720|          state = ada::state::PATH;
12935|    720|          break;
12936|    720|        }
12937|       |
12938|    400|        input_position++;
12939|    400|        break;
12940|  1.12k|      }
12941|      0|      default:
  ------------------
  |  Branch (12941:7): [True: 0, False: 42.4k]
  ------------------
12942|      0|        ada::unreachable();
12943|  42.4k|    }
12944|  42.4k|  }
12945|  2.77k|  if (fragment.has_value()) {
  ------------------
  |  Branch (12945:7): [True: 116, False: 2.65k]
  ------------------
12946|    116|    url.update_unencoded_base_hash(*fragment);
12947|    116|  }
12948|  2.77k|  return url;
12949|  10.1k|}
_ZN3ada6parser9parse_urlINS_14url_aggregatorEEET_NSt3__117basic_string_viewIcNS4_11char_traitsIcEEEEPKS3_:
12057|  31.6k|                      const result_type* base_url) {
12058|       |  // We can specialize the implementation per type.
12059|       |  // Important: result_type_is_ada_url is evaluated at *compile time*. This
12060|       |  // means that doing if constexpr(result_type_is_ada_url) { something } else {
12061|       |  // something else } is free (at runtime). This means that ada::url_aggregator
12062|       |  // and ada::url **do not have to support the exact same API**.
12063|  31.6k|  constexpr bool result_type_is_ada_url =
12064|  31.6k|      std::is_same<ada::url, result_type>::value;
12065|  31.6k|  constexpr bool result_type_is_ada_url_aggregator =
12066|  31.6k|      std::is_same<ada::url_aggregator, result_type>::value;
12067|  31.6k|  static_assert(result_type_is_ada_url ||
12068|  31.6k|                result_type_is_ada_url_aggregator);  // We don't support
12069|       |                                                     // anything else for now.
12070|       |
12071|  31.6k|  ada_log("ada::parser::parse_url('", user_input, "' [", user_input.size(),
12072|  31.6k|          " bytes],", (base_url != nullptr ? base_url->to_string() : "null"),
12073|  31.6k|          ")");
12074|       |
12075|  31.6k|  ada::state state = ada::state::SCHEME_START;
12076|  31.6k|  result_type url{};
12077|       |
12078|       |  // We refuse to parse URL strings that exceed 4GB. Such strings are almost
12079|       |  // surely the result of a bug or are otherwise a security concern.
12080|  31.6k|  if (user_input.size() > std::numeric_limits<uint32_t>::max()) {
  ------------------
  |  Branch (12080:7): [True: 2, False: 31.6k]
  ------------------
12081|      2|    url.is_valid = false;
12082|      2|  }
12083|       |  // Going forward, user_input.size() is in [0,
12084|       |  // std::numeric_limits<uint32_t>::max). If we are provided with an invalid
12085|       |  // base, or the optional_url was invalid, we must return.
12086|  31.6k|  if (base_url != nullptr) {
  ------------------
  |  Branch (12086:7): [True: 1.84k, False: 29.8k]
  ------------------
12087|  1.84k|    url.is_valid &= base_url->is_valid;
12088|  1.84k|  }
12089|  31.6k|  if (!url.is_valid) {
  ------------------
  |  Branch (12089:7): [True: 2, False: 31.6k]
  ------------------
12090|      2|    return url;
12091|      2|  }
12092|  31.6k|  if constexpr (result_type_is_ada_url_aggregator) {
  ------------------
  |  Branch (12092:17): [Folded - Ignored]
  ------------------
12093|       |    // Most of the time, we just need user_input.size().
12094|       |    // In some instances, we may need a bit more.
12095|       |    ///////////////////////////
12096|       |    // This is *very* important. This line should *not* be removed
12097|       |    // hastily. There are principled reasons why reserve is important
12098|       |    // for performance. If you have a benchmark with small inputs,
12099|       |    // it may not matter, but in other instances, it could.
12100|       |    ////
12101|       |    // This rounds up to the next power of two.
12102|       |    // We know that user_input.size() is in [0,
12103|       |    // std::numeric_limits<uint32_t>::max).
12104|  31.6k|    uint32_t reserve_capacity =
12105|  31.6k|        (0xFFFFFFFF >>
12106|  31.6k|         helpers::leading_zeroes(uint32_t(1 | user_input.size()))) +
12107|  31.6k|        1;
12108|  31.6k|    url.reserve(reserve_capacity);
12109|       |    //
12110|       |    //
12111|       |    //
12112|  31.6k|  }
12113|  31.6k|  std::string tmp_buffer;
12114|  31.6k|  std::string_view internal_input;
12115|  31.6k|  if (unicode::has_tabs_or_newline(user_input)) {
  ------------------
  |  Branch (12115:7): [True: 346, False: 31.3k]
  ------------------
12116|    346|    tmp_buffer = user_input;
12117|       |    // Optimization opportunity: Instead of copying and then pruning, we could
12118|       |    // just directly build the string from user_input.
12119|    346|    helpers::remove_ascii_tab_or_newline(tmp_buffer);
12120|    346|    internal_input = tmp_buffer;
12121|  31.3k|  } else {
12122|  31.3k|    internal_input = user_input;
12123|  31.3k|  }
12124|       |
12125|       |  // Leading and trailing control characters are uncommon and easy to deal with
12126|       |  // (no performance concern).
12127|  31.6k|  std::string_view url_data = internal_input;
12128|  31.6k|  helpers::trim_c0_whitespace(url_data);
12129|       |
12130|       |  // Optimization opportunity. Most websites do not have fragment.
12131|  31.6k|  std::optional<std::string_view> fragment = helpers::prune_hash(url_data);
12132|       |  // We add it last so that an implementation like ada::url_aggregator
12133|       |  // can append it last to its internal buffer, thus improving performance.
12134|       |
12135|       |  // Here url_data no longer has its fragment.
12136|       |  // We are going to access the data from url_data (it is immutable).
12137|       |  // At any given time, we are pointing at byte 'input_position' in url_data.
12138|       |  // The input_position variable should range from 0 to input_size.
12139|       |  // It is illegal to access url_data at input_size.
12140|  31.6k|  size_t input_position = 0;
12141|  31.6k|  const size_t input_size = url_data.size();
12142|       |  // Keep running the following state machine by switching on state.
12143|       |  // If after a run pointer points to the EOF code point, go to the next step.
12144|       |  // Otherwise, increase pointer by 1 and continue with the state machine.
12145|       |  // We never decrement input_position.
12146|   124k|  while (input_position <= input_size) {
  ------------------
  |  Branch (12146:10): [True: 116k, False: 7.68k]
  ------------------
12147|   116k|    ada_log("In parsing at ", input_position, " out of ", input_size,
12148|   116k|            " in state ", ada::to_string(state));
12149|   116k|    switch (state) {
12150|  31.6k|      case ada::state::SCHEME_START: {
  ------------------
  |  Branch (12150:7): [True: 31.6k, False: 85.0k]
  ------------------
12151|  31.6k|        ada_log("SCHEME_START ", helpers::substring(url_data, input_position));
12152|       |        // If c is an ASCII alpha, append c, lowercased, to buffer, and set
12153|       |        // state to scheme state.
12154|  31.6k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12154:13): [True: 21.7k, False: 9.95k]
  ------------------
12155|  31.6k|            checkers::is_alpha(url_data[input_position])) {
  ------------------
  |  Branch (12155:13): [True: 18.1k, False: 3.57k]
  ------------------
12156|  18.1k|          state = ada::state::SCHEME;
12157|  18.1k|          input_position++;
12158|  18.1k|        } else {
12159|       |          // Otherwise, if state override is not given, set state to no scheme
12160|       |          // state and decrease pointer by 1.
12161|  13.5k|          state = ada::state::NO_SCHEME;
12162|  13.5k|        }
12163|  31.6k|        break;
12164|      0|      }
12165|  18.1k|      case ada::state::SCHEME: {
  ------------------
  |  Branch (12165:7): [True: 18.1k, False: 98.6k]
  ------------------
12166|  18.1k|        ada_log("SCHEME ", helpers::substring(url_data, input_position));
12167|       |        // If c is an ASCII alphanumeric, U+002B (+), U+002D (-), or U+002E (.),
12168|       |        // append c, lowercased, to buffer.
12169|  58.3k|        while ((input_position != input_size) &&
  ------------------
  |  Branch (12169:16): [True: 57.3k, False: 948]
  ------------------
12170|  58.3k|               (ada::unicode::is_alnum_plus(url_data[input_position]))) {
  ------------------
  |  Branch (12170:16): [True: 40.1k, False: 17.1k]
  ------------------
12171|  40.1k|          input_position++;
12172|  40.1k|        }
12173|       |        // Otherwise, if c is U+003A (:), then:
12174|  18.1k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12174:13): [True: 17.1k, False: 948]
  ------------------
12175|  18.1k|            (url_data[input_position] == ':')) {
  ------------------
  |  Branch (12175:13): [True: 16.5k, False: 603]
  ------------------
12176|  16.5k|          ada_log("SCHEME the scheme should be ",
12177|  16.5k|                  url_data.substr(0, input_position));
12178|  16.5k|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12178:25): [Folded - Ignored]
  ------------------
12179|  16.5k|            if (!url.parse_scheme(url_data.substr(0, input_position))) {
12180|  16.5k|              return url;
12181|  16.5k|            }
12182|  16.5k|          } else {
12183|       |            // we pass the colon along instead of painfully adding it back.
12184|  16.5k|            if (!url.parse_scheme_with_colon(
  ------------------
  |  Branch (12184:17): [True: 0, False: 16.5k]
  ------------------
12185|  16.5k|                    url_data.substr(0, input_position + 1))) {
12186|      0|              return url;
12187|      0|            }
12188|  16.5k|          }
12189|  16.5k|          ada_log("SCHEME the scheme is ", url.get_protocol());
12190|       |
12191|       |          // If url's scheme is "file", then:
12192|  16.5k|          if (url.type == ada::scheme::type::FILE) {
  ------------------
  |  Branch (12192:15): [True: 2.85k, False: 13.7k]
  ------------------
12193|       |            // Set state to file state.
12194|  2.85k|            state = ada::state::FILE;
12195|  2.85k|          }
12196|       |          // Otherwise, if url is special, base is non-null, and base's scheme
12197|       |          // is url's scheme: Note: Doing base_url->scheme is unsafe if base_url
12198|       |          // != nullptr is false.
12199|  13.7k|          else if (url.is_special() && base_url != nullptr &&
  ------------------
  |  Branch (12199:20): [True: 8.77k, False: 4.96k]
  |  Branch (12199:40): [True: 601, False: 8.17k]
  ------------------
12200|  13.7k|                   base_url->type == url.type) {
  ------------------
  |  Branch (12200:20): [True: 67, False: 534]
  ------------------
12201|       |            // Set state to special relative or authority state.
12202|     67|            state = ada::state::SPECIAL_RELATIVE_OR_AUTHORITY;
12203|     67|          }
12204|       |          // Otherwise, if url is special, set state to special authority
12205|       |          // slashes state.
12206|  13.6k|          else if (url.is_special()) {
  ------------------
  |  Branch (12206:20): [True: 8.70k, False: 4.96k]
  ------------------
12207|  8.70k|            state = ada::state::SPECIAL_AUTHORITY_SLASHES;
12208|  8.70k|          }
12209|       |          // Otherwise, if remaining starts with an U+002F (/), set state to
12210|       |          // path or authority state and increase pointer by 1.
12211|  4.96k|          else if (input_position + 1 < input_size &&
  ------------------
  |  Branch (12211:20): [True: 3.59k, False: 1.37k]
  ------------------
12212|  4.96k|                   url_data[input_position + 1] == '/') {
  ------------------
  |  Branch (12212:20): [True: 2.73k, False: 858]
  ------------------
12213|  2.73k|            state = ada::state::PATH_OR_AUTHORITY;
12214|  2.73k|            input_position++;
12215|  2.73k|          }
12216|       |          // Otherwise, set url's path to the empty string and set state to
12217|       |          // opaque path state.
12218|  2.23k|          else {
12219|  2.23k|            state = ada::state::OPAQUE_PATH;
12220|  2.23k|          }
12221|  16.5k|        }
12222|       |        // Otherwise, if state override is not given, set buffer to the empty
12223|       |        // string, state to no scheme state, and start over (from the first code
12224|       |        // point in input).
12225|  1.55k|        else {
12226|  1.55k|          state = ada::state::NO_SCHEME;
12227|  1.55k|          input_position = 0;
12228|  1.55k|          break;
12229|  1.55k|        }
12230|  16.5k|        input_position++;
12231|  16.5k|        break;
12232|  18.1k|      }
12233|  15.0k|      case ada::state::NO_SCHEME: {
  ------------------
  |  Branch (12233:7): [True: 15.0k, False: 101k]
  ------------------
12234|  15.0k|        ada_log("NO_SCHEME ", helpers::substring(url_data, input_position));
12235|       |        // If base is null, or base has an opaque path and c is not U+0023 (#),
12236|       |        // validation error, return failure.
12237|  15.0k|        if (base_url == nullptr ||
  ------------------
  |  Branch (12237:13): [True: 14.1k, False: 911]
  ------------------
12238|  15.0k|            (base_url->has_opaque_path && !fragment.has_value())) {
  ------------------
  |  Branch (12238:14): [True: 89, False: 822]
  |  Branch (12238:43): [True: 32, False: 57]
  ------------------
12239|  14.1k|          ada_log("NO_SCHEME validation error");
12240|  14.1k|          url.is_valid = false;
12241|  14.1k|          return url;
12242|  14.1k|        }
12243|       |        // Otherwise, if base has an opaque path and c is U+0023 (#),
12244|       |        // set url's scheme to base's scheme, url's path to base's path, url's
12245|       |        // query to base's query, and set state to fragment state.
12246|    879|        else if (base_url->has_opaque_path && fragment.has_value() &&
  ------------------
  |  Branch (12246:18): [True: 57, False: 822]
  |  Branch (12246:47): [True: 57, False: 0]
  ------------------
12247|    879|                 input_position == input_size) {
  ------------------
  |  Branch (12247:18): [True: 17, False: 40]
  ------------------
12248|     17|          ada_log("NO_SCHEME opaque base with fragment");
12249|     17|          url.copy_scheme(*base_url);
12250|     17|          url.has_opaque_path = base_url->has_opaque_path;
12251|       |
12252|     17|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12252:25): [Folded - Ignored]
  ------------------
12253|     17|            url.path = base_url->path;
12254|     17|            url.query = base_url->query;
12255|     17|          } else {
12256|     17|            url.update_base_pathname(base_url->get_pathname());
12257|     17|            url.update_base_search(base_url->get_search());
12258|     17|          }
12259|     17|          url.update_unencoded_base_hash(*fragment);
12260|     17|          return url;
12261|     17|        }
12262|       |        // Otherwise, if base's scheme is not "file", set state to relative
12263|       |        // state and decrease pointer by 1.
12264|    862|        else if (base_url->type != ada::scheme::type::FILE) {
  ------------------
  |  Branch (12264:18): [True: 493, False: 369]
  ------------------
12265|    493|          ada_log("NO_SCHEME non-file relative path");
12266|    493|          state = ada::state::RELATIVE_SCHEME;
12267|    493|        }
12268|       |        // Otherwise, set state to file state and decrease pointer by 1.
12269|    369|        else {
12270|    369|          ada_log("NO_SCHEME file base type");
12271|    369|          state = ada::state::FILE;
12272|    369|        }
12273|    862|        break;
12274|  15.0k|      }
12275|  9.34k|      case ada::state::AUTHORITY: {
  ------------------
  |  Branch (12275:7): [True: 9.34k, False: 107k]
  ------------------
12276|  9.34k|        ada_log("AUTHORITY ", helpers::substring(url_data, input_position));
12277|       |        // most URLs have no @. Having no @ tells us that we don't have to worry
12278|       |        // about AUTHORITY. Of course, we could have @ and still not have to
12279|       |        // worry about AUTHORITY.
12280|       |        // TODO: Instead of just collecting a bool, collect the location of the
12281|       |        // '@' and do something useful with it.
12282|       |        // TODO: We could do various processing early on, using a single pass
12283|       |        // over the string to collect information about it, e.g., telling us
12284|       |        // whether there is a @ and if so, where (or how many).
12285|  9.34k|        const bool contains_ampersand =
12286|  9.34k|            (url_data.find('@', input_position) != std::string_view::npos);
12287|       |
12288|  9.34k|        if (!contains_ampersand) {
  ------------------
  |  Branch (12288:13): [True: 8.62k, False: 718]
  ------------------
12289|  8.62k|          state = ada::state::HOST;
12290|  8.62k|          break;
12291|  8.62k|        }
12292|    718|        bool at_sign_seen{false};
12293|    718|        bool password_token_seen{false};
12294|       |        /**
12295|       |         * We expect something of the sort...
12296|       |         * https://user:pass@example.com:1234/foo/bar?baz#quux
12297|       |         * --------^
12298|       |         */
12299|  5.86k|        do {
12300|  5.86k|          std::string_view view = helpers::substring(url_data, input_position);
12301|       |          // The delimiters are @, /, ? \\.
12302|  5.86k|          size_t location =
12303|  5.86k|              url.is_special() ? helpers::find_authority_delimiter_special(view)
  ------------------
  |  Branch (12303:15): [True: 5.15k, False: 711]
  ------------------
12304|  5.86k|                               : helpers::find_authority_delimiter(view);
12305|  5.86k|          std::string_view authority_view(view.data(), location);
12306|  5.86k|          size_t end_of_authority = input_position + authority_view.size();
12307|       |          // If c is U+0040 (@), then:
12308|  5.86k|          if ((end_of_authority != input_size) &&
  ------------------
  |  Branch (12308:15): [True: 5.25k, False: 615]
  ------------------
12309|  5.86k|              (url_data[end_of_authority] == '@')) {
  ------------------
  |  Branch (12309:15): [True: 5.15k, False: 103]
  ------------------
12310|       |            // If atSignSeen is true, then prepend "%40" to buffer.
12311|  5.15k|            if (at_sign_seen) {
  ------------------
  |  Branch (12311:17): [True: 4.47k, False: 680]
  ------------------
12312|  4.47k|              if (password_token_seen) {
  ------------------
  |  Branch (12312:19): [True: 1.31k, False: 3.16k]
  ------------------
12313|  1.31k|                if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12313:31): [Folded - Ignored]
  ------------------
12314|  1.31k|                  url.password += "%40";
12315|  1.31k|                } else {
12316|  1.31k|                  url.append_base_password("%40");
12317|  1.31k|                }
12318|  3.16k|              } else {
12319|  3.16k|                if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12319:31): [Folded - Ignored]
  ------------------
12320|  3.16k|                  url.username += "%40";
12321|  3.16k|                } else {
12322|  3.16k|                  url.append_base_username("%40");
12323|  3.16k|                }
12324|  3.16k|              }
12325|  4.47k|            }
12326|       |
12327|  5.15k|            at_sign_seen = true;
12328|       |
12329|  5.15k|            if (!password_token_seen) {
  ------------------
  |  Branch (12329:17): [True: 3.84k, False: 1.31k]
  ------------------
12330|  3.84k|              size_t password_token_location = authority_view.find(':');
12331|  3.84k|              password_token_seen =
12332|  3.84k|                  password_token_location != std::string_view::npos;
12333|       |
12334|  3.84k|              if (!password_token_seen) {
  ------------------
  |  Branch (12334:19): [True: 3.57k, False: 264]
  ------------------
12335|  3.57k|                if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12335:31): [Folded - Ignored]
  ------------------
12336|  3.57k|                  url.username += unicode::percent_encode(
12337|  3.57k|                      authority_view, character_sets::USERINFO_PERCENT_ENCODE);
12338|  3.57k|                } else {
12339|  3.57k|                  url.append_base_username(unicode::percent_encode(
12340|  3.57k|                      authority_view, character_sets::USERINFO_PERCENT_ENCODE));
12341|  3.57k|                }
12342|  3.57k|              } else {
12343|    264|                if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12343:31): [Folded - Ignored]
  ------------------
12344|    264|                  url.username += unicode::percent_encode(
12345|    264|                      authority_view.substr(0, password_token_location),
12346|    264|                      character_sets::USERINFO_PERCENT_ENCODE);
12347|    264|                  url.password += unicode::percent_encode(
12348|    264|                      authority_view.substr(password_token_location + 1),
12349|    264|                      character_sets::USERINFO_PERCENT_ENCODE);
12350|    264|                } else {
12351|    264|                  url.append_base_username(unicode::percent_encode(
12352|    264|                      authority_view.substr(0, password_token_location),
12353|    264|                      character_sets::USERINFO_PERCENT_ENCODE));
12354|    264|                  url.append_base_password(unicode::percent_encode(
12355|    264|                      authority_view.substr(password_token_location + 1),
12356|    264|                      character_sets::USERINFO_PERCENT_ENCODE));
12357|    264|                }
12358|    264|              }
12359|  3.84k|            } else {
12360|  1.31k|              if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12360:29): [Folded - Ignored]
  ------------------
12361|  1.31k|                url.password += unicode::percent_encode(
12362|  1.31k|                    authority_view, character_sets::USERINFO_PERCENT_ENCODE);
12363|  1.31k|              } else {
12364|  1.31k|                url.append_base_password(unicode::percent_encode(
12365|  1.31k|                    authority_view, character_sets::USERINFO_PERCENT_ENCODE));
12366|  1.31k|              }
12367|  1.31k|            }
12368|  5.15k|          }
12369|       |          // Otherwise, if one of the following is true:
12370|       |          // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
12371|       |          // - url is special and c is U+005C (\)
12372|    718|          else if (end_of_authority == input_size ||
  ------------------
  |  Branch (12372:20): [True: 615, False: 103]
  ------------------
12373|    718|                   url_data[end_of_authority] == '/' ||
  ------------------
  |  Branch (12373:20): [True: 52, False: 51]
  ------------------
12374|    718|                   url_data[end_of_authority] == '?' ||
  ------------------
  |  Branch (12374:20): [True: 45, False: 6]
  ------------------
12375|    718|                   (url.is_special() && url_data[end_of_authority] == '\\')) {
  ------------------
  |  Branch (12375:21): [True: 6, False: 0]
  |  Branch (12375:41): [True: 6, False: 0]
  ------------------
12376|       |            // If atSignSeen is true and authority_view is the empty string,
12377|       |            // validation error, return failure.
12378|    718|            if (at_sign_seen && authority_view.empty()) {
  ------------------
  |  Branch (12378:17): [True: 680, False: 38]
  |  Branch (12378:33): [True: 332, False: 348]
  ------------------
12379|    332|              url.is_valid = false;
12380|    332|              return url;
12381|    332|            }
12382|    386|            state = ada::state::HOST;
12383|    386|            break;
12384|    718|          }
12385|  5.15k|          if (end_of_authority == input_size) {
  ------------------
  |  Branch (12385:15): [True: 0, False: 5.15k]
  ------------------
12386|      0|            if (fragment.has_value()) {
  ------------------
  |  Branch (12386:17): [True: 0, False: 0]
  ------------------
12387|      0|              url.update_unencoded_base_hash(*fragment);
12388|      0|            }
12389|      0|            return url;
12390|      0|          }
12391|  5.15k|          input_position = end_of_authority + 1;
12392|  5.15k|        } while (true);
  ------------------
  |  Branch (12392:18): [Folded - Ignored]
  ------------------
12393|       |
12394|    386|        break;
12395|    718|      }
12396|    386|      case ada::state::SPECIAL_RELATIVE_OR_AUTHORITY: {
  ------------------
  |  Branch (12396:7): [True: 67, False: 116k]
  ------------------
12397|     67|        ada_log("SPECIAL_RELATIVE_OR_AUTHORITY ",
12398|     67|                helpers::substring(url_data, input_position));
12399|       |
12400|       |        // If c is U+002F (/) and remaining starts with U+002F (/),
12401|       |        // then set state to special authority ignore slashes state and increase
12402|       |        // pointer by 1.
12403|     67|        std::string_view view = helpers::substring(url_data, input_position);
12404|     67|        if (ada::checkers::begins_with(view, "//")) {
  ------------------
  |  Branch (12404:13): [True: 1, False: 66]
  ------------------
12405|      1|          state = ada::state::SPECIAL_AUTHORITY_IGNORE_SLASHES;
12406|      1|          input_position += 2;
12407|     66|        } else {
12408|       |          // Otherwise, validation error, set state to relative state and
12409|       |          // decrease pointer by 1.
12410|     66|          state = ada::state::RELATIVE_SCHEME;
12411|     66|        }
12412|       |
12413|     67|        break;
12414|    718|      }
12415|  2.73k|      case ada::state::PATH_OR_AUTHORITY: {
  ------------------
  |  Branch (12415:7): [True: 2.73k, False: 114k]
  ------------------
12416|  2.73k|        ada_log("PATH_OR_AUTHORITY ",
12417|  2.73k|                helpers::substring(url_data, input_position));
12418|       |
12419|       |        // If c is U+002F (/), then set state to authority state.
12420|  2.73k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12420:13): [True: 1.34k, False: 1.38k]
  ------------------
12421|  2.73k|            (url_data[input_position] == '/')) {
  ------------------
  |  Branch (12421:13): [True: 632, False: 713]
  ------------------
12422|    632|          state = ada::state::AUTHORITY;
12423|    632|          input_position++;
12424|  2.10k|        } else {
12425|       |          // Otherwise, set state to path state, and decrease pointer by 1.
12426|  2.10k|          state = ada::state::PATH;
12427|  2.10k|        }
12428|       |
12429|  2.73k|        break;
12430|    718|      }
12431|    559|      case ada::state::RELATIVE_SCHEME: {
  ------------------
  |  Branch (12431:7): [True: 559, False: 116k]
  ------------------
12432|    559|        ada_log("RELATIVE_SCHEME ",
12433|    559|                helpers::substring(url_data, input_position));
12434|       |
12435|       |        // Set url's scheme to base's scheme.
12436|    559|        url.copy_scheme(*base_url);
12437|       |
12438|       |        // If c is U+002F (/), then set state to relative slash state.
12439|    559|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12439:13): [True: 204, False: 355]
  ------------------
12440|    559|            (url_data[input_position] == '/')) {
  ------------------
  |  Branch (12440:13): [True: 29, False: 175]
  ------------------
12441|     29|          ada_log(
12442|     29|              "RELATIVE_SCHEME if c is U+002F (/), then set state to relative "
12443|     29|              "slash state");
12444|     29|          state = ada::state::RELATIVE_SLASH;
12445|    530|        } else if (url.is_special() && (input_position != input_size) &&
  ------------------
  |  Branch (12445:20): [True: 407, False: 123]
  |  Branch (12445:40): [True: 97, False: 310]
  ------------------
12446|    530|                   (url_data[input_position] == '\\')) {
  ------------------
  |  Branch (12446:20): [True: 1, False: 96]
  ------------------
12447|       |          // Otherwise, if url is special and c is U+005C (\), validation error,
12448|       |          // set state to relative slash state.
12449|      1|          ada_log(
12450|      1|              "RELATIVE_SCHEME  if url is special and c is U+005C, validation "
12451|      1|              "error, set state to relative slash state");
12452|      1|          state = ada::state::RELATIVE_SLASH;
12453|    529|        } else {
12454|    529|          ada_log("RELATIVE_SCHEME otherwise");
12455|       |          // Set url's username to base's username, url's password to base's
12456|       |          // password, url's host to base's host, url's port to base's port,
12457|       |          // url's path to a clone of base's path, and url's query to base's
12458|       |          // query.
12459|    529|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12459:25): [Folded - Ignored]
  ------------------
12460|    529|            url.username = base_url->username;
12461|    529|            url.password = base_url->password;
12462|    529|            url.host = base_url->host;
12463|    529|            url.port = base_url->port;
12464|       |            // cloning the base path includes cloning the has_opaque_path flag
12465|    529|            url.has_opaque_path = base_url->has_opaque_path;
12466|    529|            url.path = base_url->path;
12467|    529|            url.query = base_url->query;
12468|    529|          } else {
12469|    529|            url.update_base_authority(base_url->get_href(),
12470|    529|                                      base_url->get_components());
12471|       |            // TODO: Get rid of set_hostname and replace it with
12472|       |            // update_base_hostname
12473|    529|            url.set_hostname(base_url->get_hostname());
12474|    529|            url.update_base_port(base_url->retrieve_base_port());
12475|       |            // cloning the base path includes cloning the has_opaque_path flag
12476|    529|            url.has_opaque_path = base_url->has_opaque_path;
12477|    529|            url.update_base_pathname(base_url->get_pathname());
12478|    529|            url.update_base_search(base_url->get_search());
12479|    529|          }
12480|       |
12481|    529|          url.has_opaque_path = base_url->has_opaque_path;
12482|       |
12483|       |          // If c is U+003F (?), then set url's query to the empty string, and
12484|       |          // state to query state.
12485|    529|          if ((input_position != input_size) &&
  ------------------
  |  Branch (12485:15): [True: 174, False: 355]
  ------------------
12486|    529|              (url_data[input_position] == '?')) {
  ------------------
  |  Branch (12486:15): [True: 6, False: 168]
  ------------------
12487|      6|            state = ada::state::QUERY;
12488|      6|          }
12489|       |          // Otherwise, if c is not the EOF code point:
12490|    523|          else if (input_position != input_size) {
  ------------------
  |  Branch (12490:20): [True: 168, False: 355]
  ------------------
12491|       |            // Set url's query to null.
12492|    168|            url.clear_search();
12493|    168|            if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12493:27): [Folded - Ignored]
  ------------------
12494|       |              // Shorten url's path.
12495|    168|              helpers::shorten_path(url.path, url.type);
12496|    168|            } else {
12497|    168|              std::string_view path = url.get_pathname();
12498|    168|              if (helpers::shorten_path(path, url.type)) {
  ------------------
  |  Branch (12498:19): [True: 135, False: 33]
  ------------------
12499|    135|                url.update_base_pathname(std::string(path));
12500|    135|              }
12501|    168|            }
12502|       |            // Set state to path state and decrease pointer by 1.
12503|    168|            state = ada::state::PATH;
12504|    168|            break;
12505|    168|          }
12506|    529|        }
12507|    391|        input_position++;
12508|    391|        break;
12509|    559|      }
12510|     30|      case ada::state::RELATIVE_SLASH: {
  ------------------
  |  Branch (12510:7): [True: 30, False: 116k]
  ------------------
12511|     30|        ada_log("RELATIVE_SLASH ",
12512|     30|                helpers::substring(url_data, input_position));
12513|       |
12514|       |        // If url is special and c is U+002F (/) or U+005C (\), then:
12515|     30|        if (url.is_special() && (input_position != input_size) &&
  ------------------
  |  Branch (12515:13): [True: 18, False: 12]
  |  Branch (12515:33): [True: 9, False: 9]
  ------------------
12516|     30|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (12516:14): [True: 1, False: 8]
  ------------------
12517|      9|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (12517:14): [True: 1, False: 7]
  ------------------
12518|       |          // Set state to special authority ignore slashes state.
12519|      2|          state = ada::state::SPECIAL_AUTHORITY_IGNORE_SLASHES;
12520|      2|        }
12521|       |        // Otherwise, if c is U+002F (/), then set state to authority state.
12522|     28|        else if ((input_position != input_size) &&
  ------------------
  |  Branch (12522:18): [True: 16, False: 12]
  ------------------
12523|     28|                 (url_data[input_position] == '/')) {
  ------------------
  |  Branch (12523:18): [True: 4, False: 12]
  ------------------
12524|      4|          state = ada::state::AUTHORITY;
12525|      4|        }
12526|       |        // Otherwise, set
12527|       |        // - url's username to base's username,
12528|       |        // - url's password to base's password,
12529|       |        // - url's host to base's host,
12530|       |        // - url's port to base's port,
12531|       |        // - state to path state, and then, decrease pointer by 1.
12532|     24|        else {
12533|     24|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12533:25): [Folded - Ignored]
  ------------------
12534|     24|            url.username = base_url->username;
12535|     24|            url.password = base_url->password;
12536|     24|            url.host = base_url->host;
12537|     24|            url.port = base_url->port;
12538|     24|          } else {
12539|     24|            url.update_base_authority(base_url->get_href(),
12540|     24|                                      base_url->get_components());
12541|       |            // TODO: Get rid of set_hostname and replace it with
12542|       |            // update_base_hostname
12543|     24|            url.set_hostname(base_url->get_hostname());
12544|     24|            url.update_base_port(base_url->retrieve_base_port());
12545|     24|          }
12546|     24|          state = ada::state::PATH;
12547|     24|          break;
12548|     24|        }
12549|       |
12550|      6|        input_position++;
12551|      6|        break;
12552|     30|      }
12553|  8.70k|      case ada::state::SPECIAL_AUTHORITY_SLASHES: {
  ------------------
  |  Branch (12553:7): [True: 8.70k, False: 108k]
  ------------------
12554|  8.70k|        ada_log("SPECIAL_AUTHORITY_SLASHES ",
12555|  8.70k|                helpers::substring(url_data, input_position));
12556|       |
12557|       |        // If c is U+002F (/) and remaining starts with U+002F (/),
12558|       |        // then set state to special authority ignore slashes state and increase
12559|       |        // pointer by 1.
12560|  8.70k|        std::string_view view = helpers::substring(url_data, input_position);
12561|  8.70k|        if (ada::checkers::begins_with(view, "//")) {
  ------------------
  |  Branch (12561:13): [True: 19, False: 8.68k]
  ------------------
12562|     19|          input_position += 2;
12563|     19|        }
12564|       |
12565|  8.70k|        [[fallthrough]];
12566|  8.70k|      }
12567|  8.70k|      case ada::state::SPECIAL_AUTHORITY_IGNORE_SLASHES: {
  ------------------
  |  Branch (12567:7): [True: 3, False: 116k]
  ------------------
12568|  8.70k|        ada_log("SPECIAL_AUTHORITY_IGNORE_SLASHES ",
12569|  8.70k|                helpers::substring(url_data, input_position));
12570|       |
12571|       |        // If c is neither U+002F (/) nor U+005C (\), then set state to
12572|       |        // authority state and decrease pointer by 1.
12573|  9.74k|        while ((input_position != input_size) &&
  ------------------
  |  Branch (12573:16): [True: 9.68k, False: 63]
  ------------------
12574|  9.74k|               ((url_data[input_position] == '/') ||
  ------------------
  |  Branch (12574:17): [True: 524, False: 9.16k]
  ------------------
12575|  9.68k|                (url_data[input_position] == '\\'))) {
  ------------------
  |  Branch (12575:17): [True: 516, False: 8.64k]
  ------------------
12576|  1.04k|          input_position++;
12577|  1.04k|        }
12578|  8.70k|        state = ada::state::AUTHORITY;
12579|       |
12580|  8.70k|        break;
12581|  8.70k|      }
12582|    553|      case ada::state::QUERY: {
  ------------------
  |  Branch (12582:7): [True: 553, False: 116k]
  ------------------
12583|    553|        ada_log("QUERY ", helpers::substring(url_data, input_position));
12584|       |        // Let queryPercentEncodeSet be the special-query percent-encode set if
12585|       |        // url is special; otherwise the query percent-encode set.
12586|    553|        const uint8_t* query_percent_encode_set =
12587|    553|            url.is_special() ? ada::character_sets::SPECIAL_QUERY_PERCENT_ENCODE
  ------------------
  |  Branch (12587:13): [True: 239, False: 314]
  ------------------
12588|    553|                             : ada::character_sets::QUERY_PERCENT_ENCODE;
12589|       |
12590|       |        // Percent-encode after encoding, with encoding, buffer, and
12591|       |        // queryPercentEncodeSet, and append the result to url's query.
12592|    553|        url.update_base_search(helpers::substring(url_data, input_position),
12593|    553|                               query_percent_encode_set);
12594|    553|        ada_log("QUERY update_base_search completed ");
12595|    553|        if (fragment.has_value()) {
  ------------------
  |  Branch (12595:13): [True: 134, False: 419]
  ------------------
12596|    134|          url.update_unencoded_base_hash(*fragment);
12597|    134|        }
12598|    553|        return url;
12599|  8.70k|      }
12600|  9.01k|      case ada::state::HOST: {
  ------------------
  |  Branch (12600:7): [True: 9.01k, False: 107k]
  ------------------
12601|  9.01k|        ada_log("HOST ", helpers::substring(url_data, input_position));
12602|       |
12603|  9.01k|        std::string_view host_view =
12604|  9.01k|            helpers::substring(url_data, input_position);
12605|  9.01k|        auto [location, found_colon] =
12606|  9.01k|            helpers::get_host_delimiter_location(url.is_special(), host_view);
12607|  9.01k|        input_position = (location != std::string_view::npos)
  ------------------
  |  Branch (12607:26): [True: 9.01k, False: 0]
  ------------------
12608|  9.01k|                             ? input_position + location
12609|  9.01k|                             : input_size;
12610|       |        // Otherwise, if c is U+003A (:) and insideBrackets is false, then:
12611|       |        // Note: the 'found_colon' value is true if and only if a colon was
12612|       |        // encountered while not inside brackets.
12613|  9.01k|        if (found_colon) {
  ------------------
  |  Branch (12613:13): [True: 1.35k, False: 7.66k]
  ------------------
12614|       |          // If buffer is the empty string, validation error, return failure.
12615|       |          // Let host be the result of host parsing buffer with url is not
12616|       |          // special.
12617|  1.35k|          ada_log("HOST parsing ", host_view);
12618|  1.35k|          if (!url.parse_host(host_view)) {
  ------------------
  |  Branch (12618:15): [True: 180, False: 1.17k]
  ------------------
12619|    180|            return url;
12620|    180|          }
12621|  1.17k|          ada_log("HOST parsing results in ", url.get_hostname());
12622|       |          // Set url's host to host, buffer to the empty string, and state to
12623|       |          // port state.
12624|  1.17k|          state = ada::state::PORT;
12625|  1.17k|          input_position++;
12626|  1.17k|        }
12627|       |        // Otherwise, if one of the following is true:
12628|       |        // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
12629|       |        // - url is special and c is U+005C (\)
12630|       |        // The get_host_delimiter_location function either brings us to
12631|       |        // the colon outside of the bracket, or to one of those characters.
12632|  7.66k|        else {
12633|       |          // If url is special and host_view is the empty string, validation
12634|       |          // error, return failure.
12635|  7.66k|          if (url.is_special() && host_view.empty()) {
  ------------------
  |  Branch (12635:15): [True: 7.19k, False: 462]
  |  Branch (12635:35): [True: 72, False: 7.12k]
  ------------------
12636|     72|            url.is_valid = false;
12637|     72|            return url;
12638|     72|          }
12639|  7.58k|          ada_log("HOST parsing ", host_view, " href=", url.get_href());
12640|       |          // Let host be the result of host parsing host_view with url is not
12641|       |          // special.
12642|  7.58k|          if (host_view.empty()) {
  ------------------
  |  Branch (12642:15): [True: 47, False: 7.54k]
  ------------------
12643|     47|            url.update_base_hostname("");
12644|  7.54k|          } else if (!url.parse_host(host_view)) {
  ------------------
  |  Branch (12644:22): [True: 1.76k, False: 5.77k]
  ------------------
12645|  1.76k|            return url;
12646|  1.76k|          }
12647|  5.82k|          ada_log("HOST parsing results in ", url.get_hostname(),
12648|  5.82k|                  " href=", url.get_href());
12649|       |
12650|       |          // Set url's host to host, and state to path start state.
12651|  5.82k|          state = ada::state::PATH_START;
12652|  5.82k|        }
12653|       |
12654|  6.99k|        break;
12655|  9.01k|      }
12656|  6.99k|      case ada::state::OPAQUE_PATH: {
  ------------------
  |  Branch (12656:7): [True: 2.23k, False: 114k]
  ------------------
12657|  2.23k|        ada_log("OPAQUE_PATH ", helpers::substring(url_data, input_position));
12658|  2.23k|        std::string_view view = helpers::substring(url_data, input_position);
12659|       |        // If c is U+003F (?), then set url's query to the empty string and
12660|       |        // state to query state.
12661|  2.23k|        size_t location = view.find('?');
12662|  2.23k|        if (location != std::string_view::npos) {
  ------------------
  |  Branch (12662:13): [True: 133, False: 2.10k]
  ------------------
12663|    133|          view.remove_suffix(view.size() - location);
12664|    133|          state = ada::state::QUERY;
12665|    133|          input_position += location + 1;
12666|  2.10k|        } else {
12667|  2.10k|          input_position = input_size + 1;
12668|  2.10k|        }
12669|  2.23k|        url.has_opaque_path = true;
12670|       |        // This is a really unlikely scenario in real world. We should not seek
12671|       |        // to optimize it.
12672|  2.23k|        url.update_base_pathname(unicode::percent_encode(
12673|  2.23k|            view, character_sets::C0_CONTROL_PERCENT_ENCODE));
12674|  2.23k|        break;
12675|  9.01k|      }
12676|  1.17k|      case ada::state::PORT: {
  ------------------
  |  Branch (12676:7): [True: 1.17k, False: 115k]
  ------------------
12677|  1.17k|        ada_log("PORT ", helpers::substring(url_data, input_position));
12678|  1.17k|        std::string_view port_view =
12679|  1.17k|            helpers::substring(url_data, input_position);
12680|  1.17k|        size_t consumed_bytes = url.parse_port(port_view, true);
12681|  1.17k|        input_position += consumed_bytes;
12682|  1.17k|        if (!url.is_valid) {
  ------------------
  |  Branch (12682:13): [True: 123, False: 1.04k]
  ------------------
12683|    123|          return url;
12684|    123|        }
12685|  1.04k|        state = state::PATH_START;
12686|  1.04k|        [[fallthrough]];
12687|  1.04k|      }
12688|  7.79k|      case ada::state::PATH_START: {
  ------------------
  |  Branch (12688:7): [True: 6.74k, False: 110k]
  ------------------
12689|  7.79k|        ada_log("PATH_START ", helpers::substring(url_data, input_position));
12690|       |
12691|       |        // If url is special, then:
12692|  7.79k|        if (url.is_special()) {
  ------------------
  |  Branch (12692:13): [True: 7.34k, False: 444]
  ------------------
12693|       |          // Set state to path state.
12694|  7.34k|          state = ada::state::PATH;
12695|       |
12696|       |          // Optimization: Avoiding going into PATH state improves the
12697|       |          // performance of urls ending with /.
12698|  7.34k|          if (input_position == input_size) {
  ------------------
  |  Branch (12698:15): [True: 6.58k, False: 765]
  ------------------
12699|  6.58k|            url.update_base_pathname("/");
12700|  6.58k|            if (fragment.has_value()) {
  ------------------
  |  Branch (12700:17): [True: 128, False: 6.45k]
  ------------------
12701|    128|              url.update_unencoded_base_hash(*fragment);
12702|    128|            }
12703|  6.58k|            return url;
12704|  6.58k|          }
12705|       |          // If c is neither U+002F (/) nor U+005C (\), then decrease pointer
12706|       |          // by 1. We know that (input_position == input_size) is impossible
12707|       |          // here, because of the previous if-check.
12708|    765|          if ((url_data[input_position] != '/') &&
  ------------------
  |  Branch (12708:15): [True: 197, False: 568]
  ------------------
12709|    765|              (url_data[input_position] != '\\')) {
  ------------------
  |  Branch (12709:15): [True: 172, False: 25]
  ------------------
12710|    172|            break;
12711|    172|          }
12712|    765|        }
12713|       |        // Otherwise, if state override is not given and c is U+003F (?),
12714|       |        // set url's query to the empty string and state to query state.
12715|    444|        else if ((input_position != input_size) &&
  ------------------
  |  Branch (12715:18): [True: 157, False: 287]
  ------------------
12716|    444|                 (url_data[input_position] == '?')) {
  ------------------
  |  Branch (12716:18): [True: 136, False: 21]
  ------------------
12717|    136|          state = ada::state::QUERY;
12718|    136|        }
12719|       |        // Otherwise, if c is not the EOF code point:
12720|    308|        else if (input_position != input_size) {
  ------------------
  |  Branch (12720:18): [True: 21, False: 287]
  ------------------
12721|       |          // Set state to path state.
12722|     21|          state = ada::state::PATH;
12723|       |
12724|       |          // If c is not U+002F (/), then decrease pointer by 1.
12725|     21|          if (url_data[input_position] != '/') {
  ------------------
  |  Branch (12725:15): [True: 0, False: 21]
  ------------------
12726|      0|            break;
12727|      0|          }
12728|     21|        }
12729|       |
12730|  1.03k|        input_position++;
12731|  1.03k|        break;
12732|  7.79k|      }
12733|  5.03k|      case ada::state::PATH: {
  ------------------
  |  Branch (12733:7): [True: 5.03k, False: 111k]
  ------------------
12734|  5.03k|        std::string_view view = helpers::substring(url_data, input_position);
12735|  5.03k|        ada_log("PATH ", helpers::substring(url_data, input_position));
12736|       |
12737|       |        // Most time, we do not need percent encoding.
12738|       |        // Furthermore, we can immediately locate the '?'.
12739|  5.03k|        size_t locofquestionmark = view.find('?');
12740|  5.03k|        if (locofquestionmark != std::string_view::npos) {
  ------------------
  |  Branch (12740:13): [True: 276, False: 4.75k]
  ------------------
12741|    276|          state = ada::state::QUERY;
12742|    276|          view.remove_suffix(view.size() - locofquestionmark);
12743|    276|          input_position += locofquestionmark + 1;
12744|  4.75k|        } else {
12745|  4.75k|          input_position = input_size + 1;
12746|  4.75k|        }
12747|  5.03k|        if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12747:23): [Folded - Ignored]
  ------------------
12748|  5.03k|          helpers::parse_prepared_path(view, url.type, url.path);
12749|  5.03k|        } else {
12750|  5.03k|          url.consume_prepared_path(view);
12751|  5.03k|          ADA_ASSERT_TRUE(url.validate());
12752|  5.03k|        }
12753|  5.03k|        break;
12754|  7.79k|      }
12755|  1.35k|      case ada::state::FILE_SLASH: {
  ------------------
  |  Branch (12755:7): [True: 1.35k, False: 115k]
  ------------------
12756|  1.35k|        ada_log("FILE_SLASH ", helpers::substring(url_data, input_position));
12757|       |
12758|       |        // If c is U+002F (/) or U+005C (\), then:
12759|  1.35k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12759:13): [True: 1.15k, False: 205]
  ------------------
12760|  1.35k|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (12760:14): [True: 1.08k, False: 63]
  ------------------
12761|  1.15k|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (12761:14): [True: 8, False: 55]
  ------------------
12762|  1.09k|          ada_log("FILE_SLASH c is U+002F or U+005C");
12763|       |          // Set state to file host state.
12764|  1.09k|          state = ada::state::FILE_HOST;
12765|  1.09k|          input_position++;
12766|  1.09k|        } else {
12767|    260|          ada_log("FILE_SLASH otherwise");
12768|       |          // If base is non-null and base's scheme is "file", then:
12769|       |          // Note: it is unsafe to do base_url->scheme unless you know that
12770|       |          // base_url_has_value() is true.
12771|    260|          if (base_url != nullptr &&
  ------------------
  |  Branch (12771:15): [True: 168, False: 92]
  ------------------
12772|    260|              base_url->type == ada::scheme::type::FILE) {
  ------------------
  |  Branch (12772:15): [True: 165, False: 3]
  ------------------
12773|       |            // Set url's host to base's host.
12774|    165|            if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12774:27): [Folded - Ignored]
  ------------------
12775|    165|              url.host = base_url->host;
12776|    165|            } else {
12777|       |              // TODO: Optimization opportunity.
12778|    165|              url.set_host(base_url->get_host());
12779|    165|            }
12780|       |            // If the code point substring from pointer to the end of input does
12781|       |            // not start with a Windows drive letter and base's path[0] is a
12782|       |            // normalized Windows drive letter, then append base's path[0] to
12783|       |            // url's path.
12784|    165|            if (!base_url->get_pathname().empty()) {
  ------------------
  |  Branch (12784:17): [True: 165, False: 0]
  ------------------
12785|    165|              if (!checkers::is_windows_drive_letter(
  ------------------
  |  Branch (12785:19): [True: 161, False: 4]
  ------------------
12786|    165|                      helpers::substring(url_data, input_position))) {
12787|    161|                std::string_view first_base_url_path =
12788|    161|                    base_url->get_pathname().substr(1);
12789|    161|                size_t loc = first_base_url_path.find('/');
12790|    161|                if (loc != std::string_view::npos) {
  ------------------
  |  Branch (12790:21): [True: 7, False: 154]
  ------------------
12791|      7|                  helpers::resize(first_base_url_path, loc);
12792|      7|                }
12793|    161|                if (checkers::is_normalized_windows_drive_letter(
  ------------------
  |  Branch (12793:21): [True: 4, False: 157]
  ------------------
12794|    161|                        first_base_url_path)) {
12795|      4|                  if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12795:33): [Folded - Ignored]
  ------------------
12796|      4|                    url.path += '/';
12797|      4|                    url.path += first_base_url_path;
12798|      4|                  } else {
12799|      4|                    url.append_base_pathname(
12800|      4|                        helpers::concat("/", first_base_url_path));
12801|      4|                  }
12802|      4|                }
12803|    161|              }
12804|    165|            }
12805|    165|          }
12806|       |
12807|       |          // Set state to path state, and decrease pointer by 1.
12808|    260|          state = ada::state::PATH;
12809|    260|        }
12810|       |
12811|  1.35k|        break;
12812|  7.79k|      }
12813|  1.09k|      case ada::state::FILE_HOST: {
  ------------------
  |  Branch (12813:7): [True: 1.09k, False: 115k]
  ------------------
12814|  1.09k|        std::string_view view = helpers::substring(url_data, input_position);
12815|  1.09k|        ada_log("FILE_HOST ", helpers::substring(url_data, input_position));
12816|       |
12817|  1.09k|        size_t location = view.find_first_of("/\\?");
12818|  1.09k|        std::string_view file_host_buffer(
12819|  1.09k|            view.data(),
12820|  1.09k|            (location != std::string_view::npos) ? location : view.size());
  ------------------
  |  Branch (12820:13): [True: 70, False: 1.02k]
  ------------------
12821|       |
12822|  1.09k|        if (checkers::is_windows_drive_letter(file_host_buffer)) {
  ------------------
  |  Branch (12822:13): [True: 16, False: 1.08k]
  ------------------
12823|     16|          state = ada::state::PATH;
12824|  1.08k|        } else if (file_host_buffer.empty()) {
  ------------------
  |  Branch (12824:20): [True: 35, False: 1.04k]
  ------------------
12825|       |          // Set url's host to the empty string.
12826|     35|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12826:25): [Folded - Ignored]
  ------------------
12827|     35|            url.host = "";
12828|     35|          } else {
12829|     35|            url.update_base_hostname("");
12830|     35|          }
12831|       |          // Set state to path start state.
12832|     35|          state = ada::state::PATH_START;
12833|  1.04k|        } else {
12834|  1.04k|          size_t consumed_bytes = file_host_buffer.size();
12835|  1.04k|          input_position += consumed_bytes;
12836|       |          // Let host be the result of host parsing buffer with url is not
12837|       |          // special.
12838|  1.04k|          if (!url.parse_host(file_host_buffer)) {
  ------------------
  |  Branch (12838:15): [True: 165, False: 881]
  ------------------
12839|    165|            return url;
12840|    165|          }
12841|       |
12842|    881|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12842:25): [Folded - Ignored]
  ------------------
12843|       |            // If host is "localhost", then set host to the empty string.
12844|    881|            if (url.host.has_value() && url.host.value() == "localhost") {
12845|    881|              url.host = "";
12846|    881|            }
12847|    881|          } else {
12848|    881|            if (url.get_hostname() == "localhost") {
  ------------------
  |  Branch (12848:17): [True: 7, False: 874]
  ------------------
12849|      7|              url.update_base_hostname("");
12850|      7|            }
12851|    881|          }
12852|       |
12853|       |          // Set buffer to the empty string and state to path start state.
12854|    881|          state = ada::state::PATH_START;
12855|    881|        }
12856|       |
12857|    932|        break;
12858|  1.09k|      }
12859|  3.22k|      case ada::state::FILE: {
  ------------------
  |  Branch (12859:7): [True: 3.22k, False: 113k]
  ------------------
12860|  3.22k|        ada_log("FILE ", helpers::substring(url_data, input_position));
12861|  3.22k|        std::string_view file_view =
12862|  3.22k|            helpers::substring(url_data, input_position);
12863|       |
12864|  3.22k|        url.set_protocol_as_file();
12865|  3.22k|        if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12865:23): [Folded - Ignored]
  ------------------
12866|       |          // Set url's host to the empty string.
12867|  3.22k|          url.host = "";
12868|  3.22k|        } else {
12869|  3.22k|          url.update_base_hostname("");
12870|  3.22k|        }
12871|       |        // If c is U+002F (/) or U+005C (\), then:
12872|  3.22k|        if (input_position != input_size &&
  ------------------
  |  Branch (12872:13): [True: 2.06k, False: 1.16k]
  ------------------
12873|  3.22k|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (12873:14): [True: 1.34k, False: 718]
  ------------------
12874|  2.06k|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (12874:14): [True: 12, False: 706]
  ------------------
12875|  1.35k|          ada_log("FILE c is U+002F or U+005C");
12876|       |          // Set state to file slash state.
12877|  1.35k|          state = ada::state::FILE_SLASH;
12878|  1.35k|        }
12879|       |        // Otherwise, if base is non-null and base's scheme is "file":
12880|  1.86k|        else if (base_url != nullptr &&
  ------------------
  |  Branch (12880:18): [True: 308, False: 1.56k]
  ------------------
12881|  1.86k|                 base_url->type == ada::scheme::type::FILE) {
  ------------------
  |  Branch (12881:18): [True: 263, False: 45]
  ------------------
12882|       |          // Set url's host to base's host, url's path to a clone of base's
12883|       |          // path, and url's query to base's query.
12884|    263|          ada_log("FILE base non-null");
12885|    263|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12885:25): [Folded - Ignored]
  ------------------
12886|    263|            url.host = base_url->host;
12887|    263|            url.path = base_url->path;
12888|    263|            url.query = base_url->query;
12889|    263|          } else {
12890|       |            // TODO: Get rid of set_hostname and replace it with
12891|       |            // update_base_hostname
12892|    263|            url.set_hostname(base_url->get_hostname());
12893|    263|            url.update_base_pathname(base_url->get_pathname());
12894|    263|            url.update_base_search(base_url->get_search());
12895|    263|          }
12896|    263|          url.has_opaque_path = base_url->has_opaque_path;
12897|       |
12898|       |          // If c is U+003F (?), then set url's query to the empty string and
12899|       |          // state to query state.
12900|    263|          if (input_position != input_size && url_data[input_position] == '?') {
  ------------------
  |  Branch (12900:15): [True: 77, False: 186]
  |  Branch (12900:47): [True: 2, False: 75]
  ------------------
12901|      2|            state = ada::state::QUERY;
12902|      2|          }
12903|       |          // Otherwise, if c is not the EOF code point:
12904|    261|          else if (input_position != input_size) {
  ------------------
  |  Branch (12904:20): [True: 75, False: 186]
  ------------------
12905|       |            // Set url's query to null.
12906|     75|            url.clear_search();
12907|       |            // If the code point substring from pointer to the end of input does
12908|       |            // not start with a Windows drive letter, then shorten url's path.
12909|     75|            if (!checkers::is_windows_drive_letter(file_view)) {
  ------------------
  |  Branch (12909:17): [True: 64, False: 11]
  ------------------
12910|     64|              if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12910:29): [Folded - Ignored]
  ------------------
12911|     64|                helpers::shorten_path(url.path, url.type);
12912|     64|              } else {
12913|     64|                std::string_view path = url.get_pathname();
12914|     64|                if (helpers::shorten_path(path, url.type)) {
  ------------------
  |  Branch (12914:21): [True: 62, False: 2]
  ------------------
12915|     62|                  url.update_base_pathname(std::string(path));
12916|     62|                }
12917|     64|              }
12918|     64|            }
12919|       |            // Otherwise:
12920|     11|            else {
12921|       |              // Set url's path to an empty list.
12922|     11|              url.clear_pathname();
12923|     11|              url.has_opaque_path = true;
12924|     11|            }
12925|       |
12926|       |            // Set state to path state and decrease pointer by 1.
12927|     75|            state = ada::state::PATH;
12928|     75|            break;
12929|     75|          }
12930|    263|        }
12931|       |        // Otherwise, set state to path state, and decrease pointer by 1.
12932|  1.60k|        else {
12933|  1.60k|          ada_log("FILE go to path");
12934|  1.60k|          state = ada::state::PATH;
12935|  1.60k|          break;
12936|  1.60k|        }
12937|       |
12938|  1.54k|        input_position++;
12939|  1.54k|        break;
12940|  3.22k|      }
12941|      0|      default:
  ------------------
  |  Branch (12941:7): [True: 0, False: 116k]
  ------------------
12942|      0|        ada::unreachable();
12943|   116k|    }
12944|   116k|  }
12945|  7.68k|  if (fragment.has_value()) {
  ------------------
  |  Branch (12945:7): [True: 304, False: 7.38k]
  ------------------
12946|    304|    url.update_unencoded_base_hash(*fragment);
12947|    304|  }
12948|  7.68k|  return url;
12949|  31.6k|}
_ZN3ada14url_aggregator12set_protocolENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13283|  5.68k|bool url_aggregator::set_protocol(const std::string_view input) {
13284|  5.68k|  ada_log("url_aggregator::set_protocol ", input);
13285|  5.68k|  ADA_ASSERT_TRUE(validate());
13286|  5.68k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13287|  5.68k|  std::string view(input);
13288|  5.68k|  helpers::remove_ascii_tab_or_newline(view);
13289|  5.68k|  if (view.empty()) {
  ------------------
  |  Branch (13289:7): [True: 4.63k, False: 1.05k]
  ------------------
13290|  4.63k|    return true;
13291|  4.63k|  }
13292|       |
13293|       |  // Schemes should start with alpha values.
13294|  1.05k|  if (!checkers::is_alpha(view[0])) {
  ------------------
  |  Branch (13294:7): [True: 731, False: 320]
  ------------------
13295|    731|    return false;
13296|    731|  }
13297|       |
13298|    320|  view.append(":");
13299|       |
13300|    320|  std::string::iterator pointer =
13301|    320|      std::find_if_not(view.begin(), view.end(), unicode::is_alnum_plus);
13302|       |
13303|    320|  if (pointer != view.end() && *pointer == ':') {
  ------------------
  |  Branch (13303:7): [True: 320, False: 0]
  |  Branch (13303:7): [True: 256, False: 64]
  |  Branch (13303:32): [True: 256, False: 64]
  ------------------
13304|    256|    return parse_scheme_with_colon<true>(
13305|    256|        std::string_view(view.data(), pointer - view.begin() + 1));
13306|    256|  }
13307|     64|  return false;
13308|    320|}
_ZN3ada14url_aggregator12set_usernameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13310|  5.68k|bool url_aggregator::set_username(const std::string_view input) {
13311|  5.68k|  ada_log("url_aggregator::set_username '", input, "' ");
13312|  5.68k|  ADA_ASSERT_TRUE(validate());
13313|  5.68k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13314|  5.68k|  if (cannot_have_credentials_or_port()) {
  ------------------
  |  Branch (13314:7): [True: 2.73k, False: 2.94k]
  ------------------
13315|  2.73k|    return false;
13316|  2.73k|  }
13317|  2.94k|  size_t idx = ada::unicode::percent_encode_index(
13318|  2.94k|      input, character_sets::USERINFO_PERCENT_ENCODE);
13319|  2.94k|  if (idx == input.size()) {
  ------------------
  |  Branch (13319:7): [True: 2.57k, False: 376]
  ------------------
13320|  2.57k|    update_base_username(input);
13321|  2.57k|  } else {
13322|       |    // We only create a temporary string if we have to!
13323|    376|    update_base_username(ada::unicode::percent_encode(
13324|    376|        input, character_sets::USERINFO_PERCENT_ENCODE, idx));
13325|    376|  }
13326|  2.94k|  ADA_ASSERT_TRUE(validate());
13327|  2.94k|  return true;
13328|  5.68k|}
_ZN3ada14url_aggregator12set_passwordENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13330|  5.68k|bool url_aggregator::set_password(const std::string_view input) {
13331|  5.68k|  ada_log("url_aggregator::set_password '", input, "'");
13332|  5.68k|  ADA_ASSERT_TRUE(validate());
13333|  5.68k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13334|  5.68k|  if (cannot_have_credentials_or_port()) {
  ------------------
  |  Branch (13334:7): [True: 2.74k, False: 2.94k]
  ------------------
13335|  2.74k|    return false;
13336|  2.74k|  }
13337|  2.94k|  size_t idx = ada::unicode::percent_encode_index(
13338|  2.94k|      input, character_sets::USERINFO_PERCENT_ENCODE);
13339|  2.94k|  if (idx == input.size()) {
  ------------------
  |  Branch (13339:7): [True: 2.56k, False: 376]
  ------------------
13340|  2.56k|    update_base_password(input);
13341|  2.56k|  } else {
13342|       |    // We only create a temporary string if we have to!
13343|    376|    update_base_password(ada::unicode::percent_encode(
13344|    376|        input, character_sets::USERINFO_PERCENT_ENCODE, idx));
13345|    376|  }
13346|  2.94k|  ADA_ASSERT_TRUE(validate());
13347|  2.94k|  return true;
13348|  5.68k|}
_ZN3ada14url_aggregator8set_portENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13350|  5.81k|bool url_aggregator::set_port(const std::string_view input) {
13351|  5.81k|  ada_log("url_aggregator::set_port ", input);
13352|  5.81k|  ADA_ASSERT_TRUE(validate());
13353|  5.81k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13354|  5.81k|  if (cannot_have_credentials_or_port()) {
  ------------------
  |  Branch (13354:7): [True: 2.72k, False: 3.09k]
  ------------------
13355|  2.72k|    return false;
13356|  2.72k|  }
13357|  3.09k|  std::string trimmed(input);
13358|  3.09k|  helpers::remove_ascii_tab_or_newline(trimmed);
13359|  3.09k|  if (trimmed.empty()) {
  ------------------
  |  Branch (13359:7): [True: 2.26k, False: 823]
  ------------------
13360|  2.26k|    clear_port();
13361|  2.26k|    return true;
13362|  2.26k|  }
13363|       |  // Input should not start with control characters.
13364|    823|  if (ada::unicode::is_c0_control_or_space(trimmed.front())) {
  ------------------
  |  Branch (13364:7): [True: 52, False: 771]
  ------------------
13365|     52|    return false;
13366|     52|  }
13367|       |  // Input should contain at least one ascii digit.
13368|    771|  if (input.find_first_of("0123456789") == std::string_view::npos) {
  ------------------
  |  Branch (13368:7): [True: 380, False: 391]
  ------------------
13369|    380|    return false;
13370|    380|  }
13371|       |
13372|       |  // Revert changes if parse_port fails.
13373|    391|  uint32_t previous_port = components.port;
13374|    391|  parse_port(trimmed);
13375|    391|  if (is_valid) {
  ------------------
  |  Branch (13375:7): [True: 287, False: 104]
  ------------------
13376|    287|    return true;
13377|    287|  }
13378|    104|  update_base_port(previous_port);
13379|    104|  is_valid = true;
13380|    104|  ADA_ASSERT_TRUE(validate());
13381|    104|  return false;
13382|    391|}
_ZN3ada14url_aggregator12set_pathnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13384|  5.68k|bool url_aggregator::set_pathname(const std::string_view input) {
13385|  5.68k|  ada_log("url_aggregator::set_pathname ", input);
13386|  5.68k|  ADA_ASSERT_TRUE(validate());
13387|  5.68k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13388|  5.68k|  if (has_opaque_path) {
  ------------------
  |  Branch (13388:7): [True: 709, False: 4.97k]
  ------------------
13389|    709|    return false;
13390|    709|  }
13391|  4.97k|  clear_pathname();
13392|  4.97k|  parse_path(input);
13393|  4.97k|  if (checkers::begins_with(input, "//") && !has_authority() &&
  ------------------
  |  Branch (13393:7): [True: 21, False: 4.95k]
  |  Branch (13393:45): [True: 16, False: 5]
  ------------------
13394|  4.97k|      !has_dash_dot()) {
  ------------------
  |  Branch (13394:7): [True: 3, False: 13]
  ------------------
13395|      3|    buffer.insert(components.pathname_start, "/.");
13396|      3|    components.pathname_start += 2;
13397|      3|  }
13398|  4.97k|  ADA_ASSERT_TRUE(validate());
13399|  4.97k|  return true;
13400|  5.68k|}
_ZN3ada14url_aggregator10set_searchENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13443|  5.68k|void url_aggregator::set_search(const std::string_view input) {
13444|  5.68k|  ada_log("url_aggregator::set_search ", input);
13445|  5.68k|  ADA_ASSERT_TRUE(validate());
13446|  5.68k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13447|  5.68k|  if (input.empty()) {
  ------------------
  |  Branch (13447:7): [True: 4.59k, False: 1.08k]
  ------------------
13448|  4.59k|    clear_search();
13449|  4.59k|    helpers::strip_trailing_spaces_from_opaque_path(*this);
13450|  4.59k|    return;
13451|  4.59k|  }
13452|       |
13453|  1.08k|  std::string new_value;
13454|  1.08k|  new_value = input[0] == '?' ? input.substr(1) : input;
  ------------------
  |  Branch (13454:15): [True: 2, False: 1.08k]
  ------------------
13455|  1.08k|  helpers::remove_ascii_tab_or_newline(new_value);
13456|       |
13457|  1.08k|  auto query_percent_encode_set =
13458|  1.08k|      is_special() ? ada::character_sets::SPECIAL_QUERY_PERCENT_ENCODE
  ------------------
  |  Branch (13458:7): [True: 694, False: 395]
  ------------------
13459|  1.08k|                   : ada::character_sets::QUERY_PERCENT_ENCODE;
13460|       |
13461|  1.08k|  update_base_search(new_value, query_percent_encode_set);
13462|  1.08k|  ADA_ASSERT_TRUE(validate());
13463|  1.08k|}
_ZN3ada14url_aggregator8set_hashENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13465|  5.68k|void url_aggregator::set_hash(const std::string_view input) {
13466|  5.68k|  ada_log("url_aggregator::set_hash ", input);
13467|  5.68k|  ADA_ASSERT_TRUE(validate());
13468|  5.68k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13469|  5.68k|  if (input.empty()) {
  ------------------
  |  Branch (13469:7): [True: 4.59k, False: 1.08k]
  ------------------
13470|  4.59k|    if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (13470:9): [True: 104, False: 4.49k]
  ------------------
13471|    104|      buffer.resize(components.hash_start);
13472|    104|      components.hash_start = url_components::omitted;
13473|    104|    }
13474|  4.59k|    helpers::strip_trailing_spaces_from_opaque_path(*this);
13475|  4.59k|    return;
13476|  4.59k|  }
13477|       |
13478|  1.08k|  std::string new_value;
13479|  1.08k|  new_value = input[0] == '#' ? input.substr(1) : input;
  ------------------
  |  Branch (13479:15): [True: 1, False: 1.08k]
  ------------------
13480|  1.08k|  helpers::remove_ascii_tab_or_newline(new_value);
13481|  1.08k|  update_unencoded_base_hash(new_value);
13482|  1.08k|  ADA_ASSERT_TRUE(validate());
13483|  1.08k|}
_ZN3ada14url_aggregator8set_hostENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13680|  5.85k|bool url_aggregator::set_host(const std::string_view input) {
13681|  5.85k|  ada_log("url_aggregator::set_host '", input, "'");
13682|  5.85k|  ADA_ASSERT_TRUE(validate());
13683|  5.85k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13684|  5.85k|  return set_host_or_hostname<false>(input);
13685|  5.85k|}
_ZN3ada14url_aggregator12set_hostnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13687|  6.50k|bool url_aggregator::set_hostname(const std::string_view input) {
13688|  6.50k|  ada_log("url_aggregator::set_hostname '", input, "'");
13689|  6.50k|  ADA_ASSERT_TRUE(validate());
13690|  6.50k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13691|  6.50k|  return set_host_or_hostname<true>(input);
13692|  6.50k|}
_ZNK3ada14url_aggregator10get_originEv:
13694|  5.68k|[[nodiscard]] std::string url_aggregator::get_origin() const noexcept {
13695|  5.68k|  ada_log("url_aggregator::get_origin");
13696|  5.68k|  if (is_special()) {
  ------------------
  |  Branch (13696:7): [True: 3.82k, False: 1.86k]
  ------------------
13697|       |    // Return a new opaque origin.
13698|  3.82k|    if (type == scheme::FILE) {
  ------------------
  |  Branch (13698:9): [True: 1.02k, False: 2.79k]
  ------------------
13699|  1.02k|      return "null";
13700|  1.02k|    }
13701|       |
13702|  2.79k|    return helpers::concat(get_protocol(), "//", get_host());
13703|  3.82k|  }
13704|       |
13705|  1.86k|  if (get_protocol() == "blob:") {
  ------------------
  |  Branch (13705:7): [True: 257, False: 1.60k]
  ------------------
13706|    257|    std::string_view path = get_pathname();
13707|    257|    if (!path.empty()) {
  ------------------
  |  Branch (13707:9): [True: 255, False: 2]
  ------------------
13708|    255|      auto out = ada::parse<ada::url_aggregator>(path);
13709|    255|      if (out && (out->type == scheme::HTTP || out->type == scheme::HTTPS)) {
  ------------------
  |  Branch (13709:11): [True: 65, False: 190]
  |  Branch (13709:19): [True: 4, False: 61]
  |  Branch (13709:48): [True: 1, False: 60]
  ------------------
13710|       |        // If pathURL's scheme is not "http" and not "https", then return a
13711|       |        // new opaque origin.
13712|      5|        return helpers::concat(out->get_protocol(), "//", out->get_host());
13713|      5|      }
13714|    255|    }
13715|    257|  }
13716|       |
13717|       |  // Return a new opaque origin.
13718|  1.85k|  return "null";
13719|  1.86k|}
_ZNK3ada14url_aggregator12get_usernameEv:
13721|  5.68k|[[nodiscard]] std::string_view url_aggregator::get_username() const noexcept {
13722|  5.68k|  ada_log("url_aggregator::get_username");
13723|  5.68k|  if (has_non_empty_username()) {
  ------------------
  |  Branch (13723:7): [True: 638, False: 5.04k]
  ------------------
13724|    638|    return helpers::substring(buffer, components.protocol_end + 2,
13725|    638|                              components.username_end);
13726|    638|  }
13727|  5.04k|  return "";
13728|  5.68k|}
_ZNK3ada14url_aggregator12get_passwordEv:
13730|  5.68k|[[nodiscard]] std::string_view url_aggregator::get_password() const noexcept {
13731|  5.68k|  ada_log("url_aggregator::get_password");
13732|  5.68k|  if (has_non_empty_password()) {
  ------------------
  |  Branch (13732:7): [True: 638, False: 5.04k]
  ------------------
13733|    638|    return helpers::substring(buffer, components.username_end + 1,
13734|    638|                              components.host_start);
13735|    638|  }
13736|  5.04k|  return "";
13737|  5.68k|}
_ZNK3ada14url_aggregator8get_portEv:
13739|  5.68k|[[nodiscard]] std::string_view url_aggregator::get_port() const noexcept {
13740|  5.68k|  ada_log("url_aggregator::get_port");
13741|  5.68k|  if (components.port == url_components::omitted) {
  ------------------
  |  Branch (13741:7): [True: 5.46k, False: 216]
  ------------------
13742|  5.46k|    return "";
13743|  5.46k|  }
13744|    216|  return helpers::substring(buffer, components.host_end + 1,
13745|    216|                            components.pathname_start);
13746|  5.68k|}
_ZNK3ada14url_aggregator8get_hashEv:
13748|  5.68k|[[nodiscard]] std::string_view url_aggregator::get_hash() const noexcept {
13749|  5.68k|  ada_log("url_aggregator::get_hash");
13750|       |  // If this's URL's fragment is either null or the empty string, then return
13751|       |  // the empty string. Return U+0023 (#), followed by this's URL's fragment.
13752|  5.68k|  if (components.hash_start == url_components::omitted) {
  ------------------
  |  Branch (13752:7): [True: 4.59k, False: 1.08k]
  ------------------
13753|  4.59k|    return "";
13754|  4.59k|  }
13755|  1.08k|  if (buffer.size() - components.hash_start <= 1) {
  ------------------
  |  Branch (13755:7): [True: 39, False: 1.05k]
  ------------------
13756|     39|    return "";
13757|     39|  }
13758|  1.05k|  return helpers::substring(buffer, components.hash_start);
13759|  1.08k|}
_ZNK3ada14url_aggregator8get_hostEv:
13761|  8.65k|[[nodiscard]] std::string_view url_aggregator::get_host() const noexcept {
13762|  8.65k|  ada_log("url_aggregator::get_host");
13763|       |  // Technically, we should check if there is a hostname, but
13764|       |  // the code below works even if there isn't.
13765|       |  // if(!has_hostname()) { return ""; }
13766|  8.65k|  size_t start = components.host_start;
13767|  8.65k|  if (components.host_end > components.host_start &&
  ------------------
  |  Branch (13767:7): [True: 6.00k, False: 2.64k]
  ------------------
13768|  8.65k|      buffer[components.host_start] == '@') {
  ------------------
  |  Branch (13768:7): [True: 1.17k, False: 4.83k]
  ------------------
13769|  1.17k|    start++;
13770|  1.17k|  }
13771|       |  // if we have an empty host, then the space between components.host_end and
13772|       |  // components.pathname_start may be occupied by /.
13773|  8.65k|  if (start == components.host_end) {
  ------------------
  |  Branch (13773:7): [True: 2.65k, False: 5.99k]
  ------------------
13774|  2.65k|    return std::string_view();
13775|  2.65k|  }
13776|  5.99k|  return helpers::substring(buffer, start, components.pathname_start);
13777|  8.65k|}
_ZNK3ada14url_aggregator12get_hostnameEv:
13779|  31.2k|[[nodiscard]] std::string_view url_aggregator::get_hostname() const noexcept {
13780|  31.2k|  ada_log("url_aggregator::get_hostname");
13781|       |  // Technically, we should check if there is a hostname, but
13782|       |  // the code below works even if there isn't.
13783|       |  // if(!has_hostname()) { return ""; }
13784|  31.2k|  size_t start = components.host_start;
13785|       |  // So host_start is not where the host begins.
13786|  31.2k|  if (components.host_end > components.host_start &&
  ------------------
  |  Branch (13786:7): [True: 19.4k, False: 11.8k]
  ------------------
13787|  31.2k|      buffer[components.host_start] == '@') {
  ------------------
  |  Branch (13787:7): [True: 3.27k, False: 16.1k]
  ------------------
13788|  3.27k|    start++;
13789|  3.27k|  }
13790|  31.2k|  return helpers::substring(buffer, start, components.host_end);
13791|  31.2k|}
_ZNK3ada14url_aggregator12get_pathnameEv:
13793|  10.9k|[[nodiscard]] std::string_view url_aggregator::get_pathname() const noexcept {
13794|  10.9k|  ada_log("url_aggregator::get_pathname pathname_start = ",
13795|  10.9k|          components.pathname_start, " buffer.size() = ", buffer.size(),
13796|  10.9k|          " components.search_start = ", components.search_start,
13797|  10.9k|          " components.hash_start = ", components.hash_start);
13798|  10.9k|  uint32_t ending_index = uint32_t(buffer.size());
13799|  10.9k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (13799:7): [True: 1.26k, False: 9.64k]
  ------------------
13800|  1.26k|    ending_index = components.search_start;
13801|  9.64k|  } else if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (13801:14): [True: 94, False: 9.54k]
  ------------------
13802|     94|    ending_index = components.hash_start;
13803|     94|  }
13804|  10.9k|  return helpers::substring(buffer, components.pathname_start, ending_index);
13805|  10.9k|}
_ZNK3ada14url_aggregator10get_searchEv:
13807|  6.49k|[[nodiscard]] std::string_view url_aggregator::get_search() const noexcept {
13808|  6.49k|  ada_log("url_aggregator::get_search");
13809|       |  // If this's URL's query is either null or the empty string, then return the
13810|       |  // empty string. Return U+003F (?), followed by this's URL's query.
13811|  6.49k|  if (components.search_start == url_components::omitted) {
  ------------------
  |  Branch (13811:7): [True: 5.34k, False: 1.14k]
  ------------------
13812|  5.34k|    return "";
13813|  5.34k|  }
13814|  1.14k|  uint32_t ending_index = uint32_t(buffer.size());
13815|  1.14k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (13815:7): [True: 1.10k, False: 44]
  ------------------
13816|  1.10k|    ending_index = components.hash_start;
13817|  1.10k|  }
13818|  1.14k|  if (ending_index - components.search_start <= 1) {
  ------------------
  |  Branch (13818:7): [True: 67, False: 1.07k]
  ------------------
13819|     67|    return "";
13820|     67|  }
13821|  1.07k|  return helpers::substring(buffer, components.search_start, ending_index);
13822|  1.14k|}
_ZNK3ada14url_aggregator12get_protocolEv:
13824|  10.9k|[[nodiscard]] std::string_view url_aggregator::get_protocol() const noexcept {
13825|  10.9k|  ada_log("url_aggregator::get_protocol");
13826|  10.9k|  return helpers::substring(buffer, 0, components.protocol_end);
13827|  10.9k|}
_ZN3ada14url_aggregator10parse_ipv4ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13929|  2.96k|bool url_aggregator::parse_ipv4(std::string_view input) {
13930|  2.96k|  ada_log("parse_ipv4 ", input, "[", input.size(),
13931|  2.96k|          " bytes], overlaps with buffer: ",
13932|  2.96k|          helpers::overlaps(input, buffer) ? "yes" : "no");
13933|  2.96k|  ADA_ASSERT_TRUE(validate());
13934|  2.96k|  const bool trailing_dot = (input.back() == '.');
13935|  2.96k|  if (trailing_dot) {
  ------------------
  |  Branch (13935:7): [True: 60, False: 2.90k]
  ------------------
13936|     60|    input.remove_suffix(1);
13937|     60|  }
13938|  2.96k|  size_t digit_count{0};
13939|  2.96k|  int pure_decimal_count = 0;  // entries that are decimal
13940|  2.96k|  uint64_t ipv4{0};
13941|       |  // we could unroll for better performance?
13942|  3.93k|  for (; (digit_count < 4) && !(input.empty()); digit_count++) {
  ------------------
  |  Branch (13942:10): [True: 3.91k, False: 24]
  |  Branch (13942:31): [True: 3.91k, False: 0]
  ------------------
13943|  3.91k|    uint32_t
13944|  3.91k|        segment_result{};  // If any number exceeds 32 bits, we have an error.
13945|  3.91k|    bool is_hex = checkers::has_hex_prefix(input);
13946|  3.91k|    if (is_hex && ((input.length() == 2) ||
  ------------------
  |  Branch (13946:9): [True: 843, False: 3.06k]
  |  Branch (13946:20): [True: 61, False: 782]
  ------------------
13947|    843|                   ((input.length() > 2) && (input[2] == '.')))) {
  ------------------
  |  Branch (13947:21): [True: 782, False: 0]
  |  Branch (13947:45): [True: 24, False: 758]
  ------------------
13948|       |      // special case
13949|     85|      segment_result = 0;
13950|     85|      input.remove_prefix(2);
13951|  3.82k|    } else {
13952|  3.82k|      std::from_chars_result r;
13953|  3.82k|      if (is_hex) {
  ------------------
  |  Branch (13953:11): [True: 758, False: 3.06k]
  ------------------
13954|    758|        r = std::from_chars(input.data() + 2, input.data() + input.size(),
13955|    758|                            segment_result, 16);
13956|  3.06k|      } else if ((input.length() >= 2) && input[0] == '0' &&
  ------------------
  |  Branch (13956:18): [True: 1.58k, False: 1.48k]
  |  Branch (13956:43): [True: 838, False: 744]
  ------------------
13957|  3.06k|                 checkers::is_digit(input[1])) {
  ------------------
  |  Branch (13957:18): [True: 407, False: 431]
  ------------------
13958|    407|        r = std::from_chars(input.data() + 1, input.data() + input.size(),
13959|    407|                            segment_result, 8);
13960|  2.66k|      } else {
13961|  2.66k|        pure_decimal_count++;
13962|  2.66k|        r = std::from_chars(input.data(), input.data() + input.size(),
13963|  2.66k|                            segment_result, 10);
13964|  2.66k|      }
13965|  3.82k|      if (r.ec != std::errc()) {
  ------------------
  |  Branch (13965:11): [True: 455, False: 3.37k]
  ------------------
13966|    455|        return is_valid = false;
13967|    455|      }
13968|  3.37k|      input.remove_prefix(r.ptr - input.data());
13969|  3.37k|    }
13970|  3.45k|    if (input.empty()) {
  ------------------
  |  Branch (13970:9): [True: 2.33k, False: 1.12k]
  ------------------
13971|       |      // We have the last value.
13972|       |      // At this stage, ipv4 contains digit_count*8 bits.
13973|       |      // So we have 32-digit_count*8 bits left.
13974|  2.33k|      if (segment_result > (uint64_t(1) << (32 - digit_count * 8))) {
  ------------------
  |  Branch (13974:11): [True: 18, False: 2.31k]
  ------------------
13975|     18|        return is_valid = false;
13976|     18|      }
13977|  2.31k|      ipv4 <<= (32 - digit_count * 8);
13978|  2.31k|      ipv4 |= segment_result;
13979|  2.31k|      goto final;
13980|  2.33k|    } else {
13981|       |      // There is more, so that the value must no be larger than 255
13982|       |      // and we must have a '.'.
13983|  1.12k|      if ((segment_result > 255) || (input[0] != '.')) {
  ------------------
  |  Branch (13983:11): [True: 68, False: 1.05k]
  |  Branch (13983:37): [True: 85, False: 968]
  ------------------
13984|    153|        return is_valid = false;
13985|    153|      }
13986|    968|      ipv4 <<= 8;
13987|    968|      ipv4 |= segment_result;
13988|    968|      input.remove_prefix(1);  // remove '.'
13989|    968|    }
13990|  3.45k|  }
13991|     24|  if ((digit_count != 4) || (!input.empty())) {
  ------------------
  |  Branch (13991:7): [True: 0, False: 24]
  |  Branch (13991:29): [True: 24, False: 0]
  ------------------
13992|     24|    return is_valid = false;
13993|     24|  }
13994|  2.31k|final:
13995|  2.31k|  ada_log("url_aggregator::parse_ipv4 completed ", get_href(),
13996|  2.31k|          " host: ", get_host());
13997|       |
13998|       |  // We could also check r.ptr to see where the parsing ended.
13999|  2.31k|  if (pure_decimal_count == 4 && !trailing_dot) {
  ------------------
  |  Branch (13999:7): [True: 179, False: 2.13k]
  |  Branch (13999:34): [True: 170, False: 9]
  ------------------
14000|       |    // The original input was already all decimal and we validated it. So we
14001|       |    // don't need to do anything.
14002|  2.14k|  } else {
14003|       |    // Optimization opportunity: Get rid of unnecessary string return in ipv4
14004|       |    // serializer.
14005|       |    // TODO: This is likely a bug because it goes back update_base_hostname, not
14006|       |    // what we want to do.
14007|  2.14k|    update_base_hostname(
14008|  2.14k|        ada::serializers::ipv4(ipv4));  // We have to reserialize the address.
14009|  2.14k|  }
14010|  2.31k|  host_type = IPV4;
14011|  2.31k|  ADA_ASSERT_TRUE(validate());
14012|  2.31k|  return true;
14013|     24|}
_ZN3ada14url_aggregator10parse_ipv6ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
14015|    657|bool url_aggregator::parse_ipv6(std::string_view input) {
14016|       |  // TODO: Find a way to merge parse_ipv6 with url.cpp implementation.
14017|    657|  ada_log("parse_ipv6 ", input, "[", input.size(), " bytes]");
14018|    657|  ADA_ASSERT_TRUE(validate());
14019|    657|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
14020|    657|  if (input.empty()) {
  ------------------
  |  Branch (14020:7): [True: 38, False: 619]
  ------------------
14021|     38|    return is_valid = false;
14022|     38|  }
14023|       |  // Let address be a new IPv6 address whose IPv6 pieces are all 0.
14024|    619|  std::array<uint16_t, 8> address{};
14025|       |
14026|       |  // Let pieceIndex be 0.
14027|    619|  int piece_index = 0;
14028|       |
14029|       |  // Let compress be null.
14030|    619|  std::optional<int> compress{};
14031|       |
14032|       |  // Let pointer be a pointer for input.
14033|    619|  std::string_view::iterator pointer = input.begin();
14034|       |
14035|       |  // If c is U+003A (:), then:
14036|    619|  if (input[0] == ':') {
  ------------------
  |  Branch (14036:7): [True: 194, False: 425]
  ------------------
14037|       |    // If remaining does not start with U+003A (:), validation error, return
14038|       |    // failure.
14039|    194|    if (input.size() == 1 || input[1] != ':') {
  ------------------
  |  Branch (14039:9): [True: 3, False: 191]
  |  Branch (14039:30): [True: 15, False: 176]
  ------------------
14040|     18|      ada_log("parse_ipv6 starts with : but the rest does not start with :");
14041|     18|      return is_valid = false;
14042|     18|    }
14043|       |
14044|       |    // Increase pointer by 2.
14045|    176|    pointer += 2;
14046|       |
14047|       |    // Increase pieceIndex by 1 and then set compress to pieceIndex.
14048|    176|    compress = ++piece_index;
14049|    176|  }
14050|       |
14051|       |  // While c is not the EOF code point:
14052|  1.89k|  while (pointer != input.end()) {
  ------------------
  |  Branch (14052:10): [True: 1.54k, False: 353]
  ------------------
14053|       |    // If pieceIndex is 8, validation error, return failure.
14054|  1.54k|    if (piece_index == 8) {
  ------------------
  |  Branch (14054:9): [True: 7, False: 1.53k]
  ------------------
14055|      7|      ada_log("parse_ipv6 piece_index == 8");
14056|      7|      return is_valid = false;
14057|      7|    }
14058|       |
14059|       |    // If c is U+003A (:), then:
14060|  1.53k|    if (*pointer == ':') {
  ------------------
  |  Branch (14060:9): [True: 130, False: 1.40k]
  ------------------
14061|       |      // If compress is non-null, validation error, return failure.
14062|    130|      if (compress.has_value()) {
  ------------------
  |  Branch (14062:11): [True: 6, False: 124]
  ------------------
14063|      6|        ada_log("parse_ipv6 compress is non-null");
14064|      6|        return is_valid = false;
14065|      6|      }
14066|       |
14067|       |      // Increase pointer and pieceIndex by 1, set compress to pieceIndex, and
14068|       |      // then continue.
14069|    124|      pointer++;
14070|    124|      compress = ++piece_index;
14071|    124|      continue;
14072|    130|    }
14073|       |
14074|       |    // Let value and length be 0.
14075|  1.40k|    uint16_t value = 0, length = 0;
14076|       |
14077|       |    // While length is less than 4 and c is an ASCII hex digit,
14078|       |    // set value to value times 0x10 + c interpreted as hexadecimal number, and
14079|       |    // increase pointer and length by 1.
14080|  3.77k|    while (length < 4 && pointer != input.end() &&
  ------------------
  |  Branch (14080:12): [True: 3.52k, False: 259]
  |  Branch (14080:26): [True: 3.32k, False: 192]
  ------------------
14081|  3.77k|           unicode::is_ascii_hex_digit(*pointer)) {
  ------------------
  |  Branch (14081:12): [True: 2.37k, False: 954]
  ------------------
14082|       |      // https://stackoverflow.com/questions/39060852/why-does-the-addition-of-two-shorts-return-an-int
14083|  2.37k|      value = uint16_t(value * 0x10 + unicode::convert_hex_to_binary(*pointer));
14084|  2.37k|      pointer++;
14085|  2.37k|      length++;
14086|  2.37k|    }
14087|       |
14088|       |    // If c is U+002E (.), then:
14089|  1.40k|    if (pointer != input.end() && *pointer == '.') {
  ------------------
  |  Branch (14089:9): [True: 1.15k, False: 252]
  |  Branch (14089:35): [True: 116, False: 1.03k]
  ------------------
14090|       |      // If length is 0, validation error, return failure.
14091|    116|      if (length == 0) {
  ------------------
  |  Branch (14091:11): [True: 1, False: 115]
  ------------------
14092|      1|        ada_log("parse_ipv6 length is 0");
14093|      1|        return is_valid = false;
14094|      1|      }
14095|       |
14096|       |      // Decrease pointer by length.
14097|    115|      pointer -= length;
14098|       |
14099|       |      // If pieceIndex is greater than 6, validation error, return failure.
14100|    115|      if (piece_index > 6) {
  ------------------
  |  Branch (14100:11): [True: 5, False: 110]
  ------------------
14101|      5|        ada_log("parse_ipv6 piece_index > 6");
14102|      5|        return is_valid = false;
14103|      5|      }
14104|       |
14105|       |      // Let numbersSeen be 0.
14106|    110|      int numbers_seen = 0;
14107|       |
14108|       |      // While c is not the EOF code point:
14109|    338|      while (pointer != input.end()) {
  ------------------
  |  Branch (14109:14): [True: 299, False: 39]
  ------------------
14110|       |        // Let ipv4Piece be null.
14111|    299|        std::optional<uint16_t> ipv4_piece{};
14112|       |
14113|       |        // If numbersSeen is greater than 0, then:
14114|    299|        if (numbers_seen > 0) {
  ------------------
  |  Branch (14114:13): [True: 189, False: 110]
  ------------------
14115|       |          // If c is a U+002E (.) and numbersSeen is less than 4, then increase
14116|       |          // pointer by 1.
14117|    189|          if (*pointer == '.' && numbers_seen < 4) {
  ------------------
  |  Branch (14117:15): [True: 171, False: 18]
  |  Branch (14117:34): [True: 168, False: 3]
  ------------------
14118|    168|            pointer++;
14119|    168|          } else {
14120|       |            // Otherwise, validation error, return failure.
14121|     21|            ada_log("parse_ipv6 Otherwise, validation error, return failure");
14122|     21|            return is_valid = false;
14123|     21|          }
14124|    189|        }
14125|       |
14126|       |        // If c is not an ASCII digit, validation error, return failure.
14127|    278|        if (pointer == input.end() || !checkers::is_digit(*pointer)) {
  ------------------
  |  Branch (14127:13): [True: 22, False: 256]
  |  Branch (14127:39): [True: 12, False: 244]
  ------------------
14128|     34|          ada_log(
14129|     34|              "parse_ipv6 If c is not an ASCII digit, validation error, return "
14130|     34|              "failure");
14131|     34|          return is_valid = false;
14132|     34|        }
14133|       |
14134|       |        // While c is an ASCII digit:
14135|    567|        while (pointer != input.end() && checkers::is_digit(*pointer)) {
  ------------------
  |  Branch (14135:16): [True: 528, False: 39]
  |  Branch (14135:42): [True: 339, False: 189]
  ------------------
14136|       |          // Let number be c interpreted as decimal number.
14137|    339|          int number = *pointer - '0';
14138|       |
14139|       |          // If ipv4Piece is null, then set ipv4Piece to number.
14140|    339|          if (!ipv4_piece.has_value()) {
  ------------------
  |  Branch (14140:15): [True: 244, False: 95]
  ------------------
14141|    244|            ipv4_piece = number;
14142|    244|          }
14143|       |          // Otherwise, if ipv4Piece is 0, validation error, return failure.
14144|     95|          else if (ipv4_piece == 0) {
  ------------------
  |  Branch (14144:20): [True: 8, False: 87]
  ------------------
14145|      8|            ada_log("parse_ipv6 if ipv4Piece is 0, validation error");
14146|      8|            return is_valid = false;
14147|      8|          }
14148|       |          // Otherwise, set ipv4Piece to ipv4Piece times 10 + number.
14149|     87|          else {
14150|     87|            ipv4_piece = *ipv4_piece * 10 + number;
14151|     87|          }
14152|       |
14153|       |          // If ipv4Piece is greater than 255, validation error, return failure.
14154|    331|          if (ipv4_piece > 255) {
  ------------------
  |  Branch (14154:15): [True: 8, False: 323]
  ------------------
14155|      8|            ada_log("parse_ipv6 ipv4_piece > 255");
14156|      8|            return is_valid = false;
14157|      8|          }
14158|       |
14159|       |          // Increase pointer by 1.
14160|    323|          pointer++;
14161|    323|        }
14162|       |
14163|       |        // Set address[pieceIndex] to address[pieceIndex] times 0x100 +
14164|       |        // ipv4Piece.
14165|       |        // https://stackoverflow.com/questions/39060852/why-does-the-addition-of-two-shorts-return-an-int
14166|    228|        address[piece_index] =
14167|    228|            uint16_t(address[piece_index] * 0x100 + *ipv4_piece);
14168|       |
14169|       |        // Increase numbersSeen by 1.
14170|    228|        numbers_seen++;
14171|       |
14172|       |        // If numbersSeen is 2 or 4, then increase pieceIndex by 1.
14173|    228|        if (numbers_seen == 2 || numbers_seen == 4) {
  ------------------
  |  Branch (14173:13): [True: 64, False: 164]
  |  Branch (14173:34): [True: 31, False: 133]
  ------------------
14174|     95|          piece_index++;
14175|     95|        }
14176|    228|      }
14177|       |
14178|       |      // If numbersSeen is not 4, validation error, return failure.
14179|     39|      if (numbers_seen != 4) {
  ------------------
  |  Branch (14179:11): [True: 11, False: 28]
  ------------------
14180|     11|        return is_valid = false;
14181|     11|      }
14182|       |
14183|       |      // Break.
14184|     28|      break;
14185|     39|    }
14186|       |    // Otherwise, if c is U+003A (:):
14187|  1.28k|    else if ((pointer != input.end()) && (*pointer == ':')) {
  ------------------
  |  Branch (14187:14): [True: 1.03k, False: 252]
  |  Branch (14187:42): [True: 924, False: 113]
  ------------------
14188|       |      // Increase pointer by 1.
14189|    924|      pointer++;
14190|       |
14191|       |      // If c is the EOF code point, validation error, return failure.
14192|    924|      if (pointer == input.end()) {
  ------------------
  |  Branch (14192:11): [True: 6, False: 918]
  ------------------
14193|      6|        ada_log(
14194|      6|            "parse_ipv6 If c is the EOF code point, validation error, return "
14195|      6|            "failure");
14196|      6|        return is_valid = false;
14197|      6|      }
14198|    924|    }
14199|       |    // Otherwise, if c is not the EOF code point, validation error, return
14200|       |    // failure.
14201|    365|    else if (pointer != input.end()) {
  ------------------
  |  Branch (14201:14): [True: 113, False: 252]
  ------------------
14202|    113|      ada_log(
14203|    113|          "parse_ipv6 Otherwise, if c is not the EOF code point, validation "
14204|    113|          "error, return failure");
14205|    113|      return is_valid = false;
14206|    113|    }
14207|       |
14208|       |    // Set address[pieceIndex] to value.
14209|  1.17k|    address[piece_index] = value;
14210|       |
14211|       |    // Increase pieceIndex by 1.
14212|  1.17k|    piece_index++;
14213|  1.17k|  }
14214|       |
14215|       |  // If compress is non-null, then:
14216|    381|  if (compress.has_value()) {
  ------------------
  |  Branch (14216:7): [True: 281, False: 100]
  ------------------
14217|       |    // Let swaps be pieceIndex - compress.
14218|    281|    int swaps = piece_index - *compress;
14219|       |
14220|       |    // Set pieceIndex to 7.
14221|    281|    piece_index = 7;
14222|       |
14223|       |    // While pieceIndex is not 0 and swaps is greater than 0,
14224|       |    // swap address[pieceIndex] with address[compress + swaps - 1], and then
14225|       |    // decrease both pieceIndex and swaps by 1.
14226|    794|    while (piece_index != 0 && swaps > 0) {
  ------------------
  |  Branch (14226:12): [True: 784, False: 10]
  |  Branch (14226:32): [True: 513, False: 271]
  ------------------
14227|    513|      std::swap(address[piece_index], address[*compress + swaps - 1]);
14228|    513|      piece_index--;
14229|    513|      swaps--;
14230|    513|    }
14231|    281|  }
14232|       |  // Otherwise, if compress is null and pieceIndex is not 8, validation error,
14233|       |  // return failure.
14234|    100|  else if (piece_index != 8) {
  ------------------
  |  Branch (14234:12): [True: 65, False: 35]
  ------------------
14235|     65|    ada_log(
14236|     65|        "parse_ipv6 if compress is null and pieceIndex is not 8, validation "
14237|     65|        "error, return failure");
14238|     65|    return is_valid = false;
14239|     65|  }
14240|       |  // TODO: Optimization opportunity: Get rid of unnecessary string creation.
14241|       |  // TODO: This is likely a bug because it goes back update_base_hostname, not
14242|       |  // what we want to do.
14243|    316|  update_base_hostname(ada::serializers::ipv6(address));
14244|    316|  ada_log("parse_ipv6 ", get_hostname());
14245|    316|  ADA_ASSERT_TRUE(validate());
14246|    316|  host_type = IPV6;
14247|    316|  return true;
14248|    381|}
_ZN3ada14url_aggregator17parse_opaque_hostENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
14250|    775|bool url_aggregator::parse_opaque_host(std::string_view input) {
14251|    775|  ada_log("parse_opaque_host ", input, "[", input.size(), " bytes]");
14252|    775|  ADA_ASSERT_TRUE(validate());
14253|    775|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
14254|    775|  if (std::any_of(input.begin(), input.end(),
  ------------------
  |  Branch (14254:7): [True: 82, False: 693]
  ------------------
14255|    775|                  ada::unicode::is_forbidden_host_code_point)) {
14256|     82|    return is_valid = false;
14257|     82|  }
14258|       |
14259|       |  // Return the result of running UTF-8 percent-encode on input using the C0
14260|       |  // control percent-encode set.
14261|    693|  size_t idx = ada::unicode::percent_encode_index(
14262|    693|      input, character_sets::C0_CONTROL_PERCENT_ENCODE);
14263|    693|  if (idx == input.size()) {
  ------------------
  |  Branch (14263:7): [True: 304, False: 389]
  ------------------
14264|    304|    update_base_hostname(input);
14265|    389|  } else {
14266|       |    // We only create a temporary string if we need to.
14267|    389|    update_base_hostname(ada::unicode::percent_encode(
14268|    389|        input, character_sets::C0_CONTROL_PERCENT_ENCODE, idx));
14269|    389|  }
14270|    693|  ADA_ASSERT_TRUE(validate());
14271|    693|  return true;
14272|    775|}
_ZN3ada14url_aggregator15delete_dash_dotEv:
14601|     89|void url_aggregator::delete_dash_dot() {
14602|     89|  ada_log("url_aggregator::delete_dash_dot");
14603|     89|  ADA_ASSERT_TRUE(validate());
14604|     89|  ADA_ASSERT_TRUE(has_dash_dot());
14605|     89|  buffer.erase(components.host_end, 2);
14606|     89|  components.pathname_start -= 2;
14607|     89|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (14607:7): [True: 57, False: 32]
  ------------------
14608|     57|    components.search_start -= 2;
14609|     57|  }
14610|     89|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (14610:7): [True: 49, False: 40]
  ------------------
14611|     49|    components.hash_start -= 2;
14612|     49|  }
14613|     89|  ADA_ASSERT_TRUE(validate());
14614|     89|  ADA_ASSERT_TRUE(!has_dash_dot());
14615|     89|}
parse.cc:_ZZN3ada4idna9ascii_mapEPcmENK3$_2clEh:
 2763|  30.8k|  auto broadcast = [](uint8_t v) -> uint64_t {
 2764|  30.8k|    return 0x101010101010101ull * v;
 2765|  30.8k|  };
parse.cc:_ZN3ada4idnaL19char_to_digit_valueEc:
 7961|  67.4k|static constexpr int32_t char_to_digit_value(char value) {
 7962|  67.4k|  if (value >= 'a' && value <= 'z') return value - 'a';
  ------------------
  |  Branch (7962:7): [True: 48.5k, False: 18.8k]
  |  Branch (7962:23): [True: 48.4k, False: 62]
  ------------------
 7963|  18.9k|  if (value >= '0' && value <= '9') return value - '0' + 26;
  ------------------
  |  Branch (7963:7): [True: 18.8k, False: 97]
  |  Branch (7963:23): [True: 18.4k, False: 360]
  ------------------
 7964|    457|  return -1;
 7965|  18.9k|}
parse.cc:_ZN3ada4idnaL5adaptEiib:
 7971|   123k|static constexpr int32_t adapt(int32_t d, int32_t n, bool firsttime) {
 7972|   123k|  if (firsttime) {
  ------------------
  |  Branch (7972:7): [True: 23.5k, False: 99.5k]
  ------------------
 7973|  23.5k|    d = d / damp;
 7974|  99.5k|  } else {
 7975|  99.5k|    d = d / 2;
 7976|  99.5k|  }
 7977|   123k|  d += d / n;
 7978|   123k|  int32_t k = 0;
 7979|   181k|  while (d > ((base - tmin) * tmax) / 2) {
  ------------------
  |  Branch (7979:10): [True: 58.6k, False: 123k]
  ------------------
 7980|  58.6k|    d /= base - tmin;
 7981|  58.6k|    k += base;
 7982|  58.6k|  }
 7983|   123k|  return k + (((base - tmin + 1) * d) / (d + skew));
 7984|   123k|}
parse.cc:_ZN3ada4idnaL13digit_to_charEi:
 7967|   254k|static constexpr char digit_to_char(int32_t digit) {
 7968|   254k|  return digit < 26 ? char(digit + 97) : char(digit + 22);
  ------------------
  |  Branch (7968:10): [True: 171k, False: 83.4k]
  ------------------
 7969|   254k|}
parse.cc:_ZN3ada4idnaL20find_last_not_of_nsmENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 8953|  22.7k|    const std::u32string_view label) noexcept {
 8954|  23.4k|  for (int i = label.size() - 1; i >= 0; i--)
  ------------------
  |  Branch (8954:34): [True: 23.4k, False: 0]
  ------------------
 8955|  23.4k|    if (find_direction(label[i]) != direction::NSM) return i;
  ------------------
  |  Branch (8955:9): [True: 22.7k, False: 728]
  ------------------
 8956|       |
 8957|      0|  return std::u32string_view::npos;
 8958|  22.7k|}
parse.cc:_ZN3ada4idnaL12is_rtl_labelENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 8962|  22.7k|inline static bool is_rtl_label(const std::u32string_view label) noexcept {
 8963|  22.7k|  const size_t mask =
 8964|  22.7k|      (1u << direction::R) | (1u << direction::AL) | (1u << direction::AN);
 8965|       |
 8966|  22.7k|  size_t directions = 0;
 8967|   159k|  for (size_t i = 0; i < label.size(); i++) {
  ------------------
  |  Branch (8967:22): [True: 136k, False: 22.7k]
  ------------------
 8968|   136k|    directions |= 1u << find_direction(label[i]);
 8969|   136k|  }
 8970|  22.7k|  return (directions & mask) != 0;
 8971|  22.7k|}
parse.cc:_ZN3ada4idnaL14find_directionEj:
 8936|   168k|inline static direction find_direction(uint32_t code_point) noexcept {
 8937|   168k|  auto it = std::lower_bound(
 8938|   168k|      std::begin(dir_table), std::end(dir_table), code_point,
 8939|   168k|      [](const directions& d, uint32_t c) { return d.final_code < c; });
 8940|       |
 8941|       |  // next check is almost surely in vain, but we use it for safety.
 8942|   168k|  if (it == std::end(dir_table)) {
  ------------------
  |  Branch (8942:7): [True: 0, False: 168k]
  ------------------
 8943|      0|    return direction::NONE;
 8944|      0|  }
 8945|       |  // We have that d.final_code >= c.
 8946|   168k|  if (code_point >= it->start_code) {
  ------------------
  |  Branch (8946:7): [True: 167k, False: 869]
  ------------------
 8947|   167k|    return it->direct;
 8948|   167k|  }
 8949|    869|  return direction::NONE;
 8950|   168k|}
parse.cc:_ZZN3ada4idnaL14find_directionEjENKUlRKNS0_10directionsEjE_clES3_j:
 8939|  1.72M|      [](const directions& d, uint32_t c) { return d.final_code < c; });
_ZN3ada4idna8is_asciiENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9532|  18.8k|bool constexpr is_ascii(std::string_view view) {
 9533|   238k|  for (uint8_t c : view) {
  ------------------
  |  Branch (9533:18): [True: 238k, False: 11.7k]
  ------------------
 9534|   238k|    if (c >= 0x80) {
  ------------------
  |  Branch (9534:9): [True: 7.02k, False: 231k]
  ------------------
 9535|  7.02k|      return false;
 9536|  7.02k|    }
 9537|   238k|  }
 9538|  11.7k|  return true;
 9539|  18.8k|}
parse.cc:_ZN3ada4idnaL19from_ascii_to_asciiENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9566|  10.2k|static std::string from_ascii_to_ascii(std::string_view ut8_string) {
 9567|  10.2k|  static const std::string error = "";
 9568|       |  // copy and map
 9569|       |  // we could be more efficient by avoiding the copy when unnecessary.
 9570|  10.2k|  std::string mapped_string = std::string(ut8_string);
 9571|  10.2k|  ascii_map(mapped_string.data(), mapped_string.size());
 9572|  10.2k|  std::string out;
 9573|  10.2k|  size_t label_start = 0;
 9574|       |
 9575|  31.3k|  while (label_start != mapped_string.size()) {
  ------------------
  |  Branch (9575:10): [True: 21.5k, False: 9.70k]
  ------------------
 9576|  21.5k|    size_t loc_dot = mapped_string.find('.', label_start);
 9577|  21.5k|    bool is_last_label = (loc_dot == std::string_view::npos);
 9578|  21.5k|    size_t label_size = is_last_label ? mapped_string.size() - label_start
  ------------------
  |  Branch (9578:25): [True: 8.64k, False: 12.9k]
  ------------------
 9579|  21.5k|                                      : loc_dot - label_start;
 9580|  21.5k|    size_t label_size_with_dot = is_last_label ? label_size : label_size + 1;
  ------------------
  |  Branch (9580:34): [True: 8.64k, False: 12.9k]
  ------------------
 9581|  21.5k|    std::string_view label_view(mapped_string.data() + label_start, label_size);
 9582|  21.5k|    label_start += label_size_with_dot;
 9583|  21.5k|    if (label_size == 0) {
  ------------------
  |  Branch (9583:9): [True: 3.36k, False: 18.2k]
  ------------------
 9584|       |      // empty label? Nothing to do.
 9585|  18.2k|    } else if (begins_with(label_view, "xn--")) {
  ------------------
  |  Branch (9585:16): [True: 5.54k, False: 12.6k]
  ------------------
 9586|       |      // The xn-- part is the expensive game.
 9587|  5.54k|      out.append(label_view);
 9588|  5.54k|      std::string_view puny_segment_ascii(
 9589|  5.54k|          out.data() + out.size() - label_view.size() + 4,
 9590|  5.54k|          label_view.size() - 4);
 9591|  5.54k|      std::u32string tmp_buffer;
 9592|  5.54k|      bool is_ok = ada::idna::punycode_to_utf32(puny_segment_ascii, tmp_buffer);
 9593|  5.54k|      if (!is_ok) {
  ------------------
  |  Branch (9593:11): [True: 153, False: 5.39k]
  ------------------
 9594|    153|        return error;
 9595|    153|      }
 9596|  5.39k|      std::u32string post_map = ada::idna::map(tmp_buffer);
 9597|  5.39k|      if (tmp_buffer != post_map) {
  ------------------
  |  Branch (9597:11): [True: 274, False: 5.12k]
  ------------------
 9598|    274|        return error;
 9599|    274|      }
 9600|  5.12k|      std::u32string pre_normal = post_map;
 9601|  5.12k|      normalize(post_map);
 9602|  5.12k|      if (post_map != pre_normal) {
  ------------------
  |  Branch (9602:11): [True: 47, False: 5.07k]
  ------------------
 9603|     47|        return error;
 9604|     47|      }
 9605|  5.07k|      if (post_map.empty()) {
  ------------------
  |  Branch (9605:11): [True: 89, False: 4.98k]
  ------------------
 9606|     89|        return error;
 9607|     89|      }
 9608|  4.98k|      if (!is_label_valid(post_map)) {
  ------------------
  |  Branch (9608:11): [True: 12, False: 4.97k]
  ------------------
 9609|     12|        return error;
 9610|     12|      }
 9611|  12.6k|    } else {
 9612|  12.6k|      out.append(label_view);
 9613|  12.6k|    }
 9614|  21.0k|    if (!is_last_label) {
  ------------------
  |  Branch (9614:9): [True: 12.8k, False: 8.12k]
  ------------------
 9615|  12.8k|      out.push_back('.');
 9616|  12.8k|    }
 9617|  21.0k|  }
 9618|  9.70k|  return out;
 9619|  10.2k|}
_ZN3ada4idna11begins_withENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEES5_:
 9509|  21.3k|                           std::u32string_view prefix) {
 9510|  21.3k|  if (view.size() < prefix.size()) {
  ------------------
  |  Branch (9510:7): [True: 4.91k, False: 16.4k]
  ------------------
 9511|  4.91k|    return false;
 9512|  4.91k|  }
 9513|  16.4k|  return std::equal(prefix.begin(), prefix.end(), view.begin());
 9514|  21.3k|}
_ZN3ada4idna8is_asciiENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 9523|  19.9k|bool constexpr is_ascii(std::u32string_view view) {
 9524|  41.6k|  for (uint32_t c : view) {
  ------------------
  |  Branch (9524:19): [True: 41.6k, False: 1.94k]
  ------------------
 9525|  41.6k|    if (c >= 0x80) {
  ------------------
  |  Branch (9525:9): [True: 18.0k, False: 23.6k]
  ------------------
 9526|  18.0k|      return false;
 9527|  18.0k|    }
 9528|  41.6k|  }
 9529|  1.94k|  return true;
 9530|  19.9k|}
_ZN3ada4idna11begins_withENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_:
 9516|  40.8k|bool constexpr begins_with(std::string_view view, std::string_view prefix) {
 9517|  40.8k|  if (view.size() < prefix.size()) {
  ------------------
  |  Branch (9517:7): [True: 20.0k, False: 20.8k]
  ------------------
 9518|  20.0k|    return false;
 9519|  20.0k|  }
 9520|  20.8k|  return std::equal(prefix.begin(), prefix.end(), view.begin());
 9521|  40.8k|}
_ZN3ada7unicode18is_ascii_hex_digitEc:
10057|  27.0k|ada_really_inline constexpr bool is_ascii_hex_digit(const char c) noexcept {
10058|  27.0k|  return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') ||
  ------------------
  |  Branch (10058:11): [True: 25.6k, False: 1.38k]
  |  Branch (10058:23): [True: 12.3k, False: 13.2k]
  |  Branch (10058:37): [True: 12.1k, False: 2.54k]
  |  Branch (10058:49): [True: 9.71k, False: 2.41k]
  ------------------
10059|  27.0k|         (c >= 'a' && c <= 'f');
  ------------------
  |  Branch (10059:11): [True: 2.28k, False: 2.66k]
  |  Branch (10059:23): [True: 2.20k, False: 79]
  ------------------
10060|  27.0k|}
_ZN3ada7unicode21convert_hex_to_binaryEc:
10136|  23.6k|unsigned constexpr convert_hex_to_binary(const char c) noexcept {
10137|  23.6k|  return hex_to_binary_table[c - '0'];
10138|  23.6k|}
_ZN3ada7unicode36contains_forbidden_domain_code_pointEPKcm:
 9953|  11.3k|    const char* input, size_t length) noexcept {
 9954|  11.3k|  size_t i = 0;
 9955|  11.3k|  uint8_t accumulator{};
 9956|   130k|  for (; i + 4 <= length; i += 4) {
  ------------------
  |  Branch (9956:10): [True: 119k, False: 11.3k]
  ------------------
 9957|   119k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i])];
 9958|   119k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 1])];
 9959|   119k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 2])];
 9960|   119k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 3])];
 9961|   119k|  }
 9962|  28.2k|  for (; i < length; i++) {
  ------------------
  |  Branch (9962:10): [True: 16.9k, False: 11.3k]
  ------------------
 9963|  16.9k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i])];
 9964|  16.9k|  }
 9965|  11.3k|  return accumulator;
 9966|  11.3k|}
_ZN3ada7unicode19has_tabs_or_newlineENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9835|  61.5k|    std::string_view user_input) noexcept {
 9836|  61.5k|  size_t i = 0;
 9837|  61.5k|  const __m128i mask1 = _mm_set1_epi8('\r');
 9838|  61.5k|  const __m128i mask2 = _mm_set1_epi8('\n');
 9839|  61.5k|  const __m128i mask3 = _mm_set1_epi8('\t');
 9840|  61.5k|  __m128i running{0};
 9841|   105k|  for (; i + 15 < user_input.size(); i += 16) {
  ------------------
  |  Branch (9841:10): [True: 43.4k, False: 61.5k]
  ------------------
 9842|  43.4k|    __m128i word = _mm_loadu_si128((const __m128i*)(user_input.data() + i));
 9843|  43.4k|    running = _mm_or_si128(
 9844|  43.4k|        _mm_or_si128(running, _mm_or_si128(_mm_cmpeq_epi8(word, mask1),
 9845|  43.4k|                                           _mm_cmpeq_epi8(word, mask2))),
 9846|  43.4k|        _mm_cmpeq_epi8(word, mask3));
 9847|  43.4k|  }
 9848|  61.5k|  if (i < user_input.size()) {
  ------------------
  |  Branch (9848:7): [True: 41.4k, False: 20.1k]
  ------------------
 9849|  41.4k|    alignas(16) uint8_t buffer[16]{};
 9850|  41.4k|    memcpy(buffer, user_input.data() + i, user_input.size() - i);
 9851|  41.4k|    __m128i word = _mm_load_si128((const __m128i*)buffer);
 9852|  41.4k|    running = _mm_or_si128(
 9853|  41.4k|        _mm_or_si128(running, _mm_or_si128(_mm_cmpeq_epi8(word, mask1),
 9854|  41.4k|                                           _mm_cmpeq_epi8(word, mask2))),
 9855|  41.4k|        _mm_cmpeq_epi8(word, mask3));
 9856|  41.4k|  }
 9857|  61.5k|  return _mm_movemask_epi8(running) != 0;
 9858|  61.5k|}
_ZN3ada7helpers27remove_ascii_tab_or_newlineERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
10576|  45.5k|    std::string& input) noexcept {
10577|       |  // if this ever becomes a performance issue, we could use an approach similar
10578|       |  // to has_tabs_or_newline
10579|  45.5k|  input.erase(std::remove_if(input.begin(), input.end(),
10580|  45.5k|                             [](char c) {
10581|  45.5k|                               return ada::unicode::is_ascii_tab_or_newline(c);
10582|  45.5k|                             }),
10583|  45.5k|              input.end());
10584|  45.5k|}
_ZZN3ada7helpers27remove_ascii_tab_or_newlineERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEENKUlcE_clEc:
10580|   613k|                             [](char c) {
10581|   613k|                               return ada::unicode::is_ascii_tab_or_newline(c);
10582|   613k|                             }),
_ZN3ada7unicode23is_ascii_tab_or_newlineEc:
10067|   613k|    const char c) noexcept {
10068|   613k|  return c == '\t' || c == '\n' || c == '\r';
  ------------------
  |  Branch (10068:10): [True: 5.49k, False: 608k]
  |  Branch (10068:23): [True: 9.83k, False: 598k]
  |  Branch (10068:36): [True: 2.00k, False: 596k]
  ------------------
10069|   613k|}
_ZN3ada7helpers19parse_prepared_pathENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEENS_6scheme4typeERNS1_12basic_stringIcS4_NS1_9allocatorIcEEEE:
10841|  13.0k|                                           std::string& path) {
10842|  13.0k|  ada_log("parse_prepared_path ", input);
10843|  13.0k|  uint8_t accumulator = checkers::path_signature(input);
10844|       |  // Let us first detect a trivial case.
10845|       |  // If it is special, we check that we have no dot, no %,  no \ and no
10846|       |  // character needing percent encoding. Otherwise, we check that we have no %,
10847|       |  // no dot, and no character needing percent encoding.
10848|  13.0k|  constexpr uint8_t need_encoding = 1;
10849|  13.0k|  constexpr uint8_t backslash_char = 2;
10850|  13.0k|  constexpr uint8_t dot_char = 4;
10851|  13.0k|  constexpr uint8_t percent_char = 8;
10852|  13.0k|  bool special = type != ada::scheme::NOT_SPECIAL;
10853|  13.0k|  bool may_need_slow_file_handling = (type == ada::scheme::type::FILE &&
  ------------------
  |  Branch (10853:39): [True: 10.2k, False: 2.79k]
  ------------------
10854|  13.0k|                                      checkers::is_windows_drive_letter(input));
  ------------------
  |  Branch (10854:39): [True: 1.55k, False: 8.68k]
  ------------------
10855|  13.0k|  bool trivial_path =
10856|  13.0k|      (special ? (accumulator == 0)
  ------------------
  |  Branch (10856:7): [True: 5.85k, False: 7.18k]
  |  Branch (10856:8): [True: 11.5k, False: 1.53k]
  ------------------
10857|  13.0k|               : ((accumulator & (need_encoding | dot_char | percent_char)) ==
10858|  1.53k|                  0)) &&
10859|  13.0k|      (!may_need_slow_file_handling);
  ------------------
  |  Branch (10859:7): [True: 4.85k, False: 1.00k]
  ------------------
10860|  13.0k|  if (accumulator == dot_char && !may_need_slow_file_handling) {
  ------------------
  |  Branch (10860:7): [True: 1.85k, False: 11.1k]
  |  Branch (10860:34): [True: 1.75k, False: 104]
  ------------------
10861|       |    // '4' means that we have at least one dot, but nothing that requires
10862|       |    // percent encoding or decoding. The only part that is not trivial is
10863|       |    // that we may have single dots and double dots path segments.
10864|       |    // If we have such segments, then we either have a path that begins
10865|       |    // with '.' (easy to check), or we have the sequence './'.
10866|       |    // Note: input cannot be empty, it must at least contain one character ('.')
10867|       |    // Note: we know that '\' is not present.
10868|  1.75k|    if (input[0] != '.') {
  ------------------
  |  Branch (10868:9): [True: 1.35k, False: 397]
  ------------------
10869|  1.35k|      size_t slashdot = input.find("/.");
10870|  1.35k|      if (slashdot == std::string_view::npos) {  // common case
  ------------------
  |  Branch (10870:11): [True: 790, False: 564]
  ------------------
10871|    790|        trivial_path = true;
10872|    790|      } else {  // uncommon
10873|       |        // only three cases matter: /./, /.. or a final /
10874|    564|        trivial_path =
10875|    564|            !(slashdot + 2 == input.size() || input[slashdot + 2] == '.' ||
  ------------------
  |  Branch (10875:15): [True: 190, False: 374]
  |  Branch (10875:47): [True: 256, False: 118]
  ------------------
10876|    564|              input[slashdot + 2] == '/');
  ------------------
  |  Branch (10876:15): [True: 54, False: 64]
  ------------------
10877|    564|      }
10878|  1.35k|    }
10879|  1.75k|  }
10880|  13.0k|  if (trivial_path) {
  ------------------
  |  Branch (10880:7): [True: 5.70k, False: 7.33k]
  ------------------
10881|  5.70k|    ada_log("parse_path trivial");
10882|  5.70k|    path += '/';
10883|  5.70k|    path += input;
10884|  5.70k|    return;
10885|  5.70k|  }
10886|       |  // We are going to need to look a bit at the path, but let us see if we can
10887|       |  // ignore percent encoding *and* backslashes *and* percent characters.
10888|       |  // Except for the trivial case, this is likely to capture 99% of paths out
10889|       |  // there.
10890|  7.33k|  bool fast_path =
10891|  7.33k|      (special &&
  ------------------
  |  Branch (10891:8): [True: 6.63k, False: 699]
  ------------------
10892|  7.33k|       (accumulator & (need_encoding | backslash_char | percent_char)) == 0) &&
  ------------------
  |  Branch (10892:8): [True: 1.86k, False: 4.76k]
  ------------------
10893|  7.33k|      (type != ada::scheme::type::FILE);
  ------------------
  |  Branch (10893:7): [True: 344, False: 1.52k]
  ------------------
10894|  7.33k|  if (fast_path) {
  ------------------
  |  Branch (10894:7): [True: 344, False: 6.98k]
  ------------------
10895|    344|    ada_log("parse_prepared_path fast");
10896|       |    // Here we don't need to worry about \ or percent encoding.
10897|       |    // We also do not have a file protocol. We might have dots, however,
10898|       |    // but dots must as appear as '.', and they cannot be encoded because
10899|       |    // the symbol '%' is not present.
10900|    344|    size_t previous_location = 0;  // We start at 0.
10901|  3.71k|    do {
10902|  3.71k|      size_t new_location = input.find('/', previous_location);
10903|       |      // std::string_view path_view = input;
10904|       |      //  We process the last segment separately:
10905|  3.71k|      if (new_location == std::string_view::npos) {
  ------------------
  |  Branch (10905:11): [True: 344, False: 3.37k]
  ------------------
10906|    344|        std::string_view path_view = input.substr(previous_location);
10907|    344|        if (path_view == "..") {  // The path ends with ..
  ------------------
  |  Branch (10907:13): [True: 35, False: 309]
  ------------------
10908|       |          // e.g., if you receive ".." with an empty path, you go to "/".
10909|     35|          if (path.empty()) {
  ------------------
  |  Branch (10909:15): [True: 11, False: 24]
  ------------------
10910|     11|            path = '/';
10911|     11|            return;
10912|     11|          }
10913|       |          // Fast case where we have nothing to do:
10914|     24|          if (path.back() == '/') {
  ------------------
  |  Branch (10914:15): [True: 9, False: 15]
  ------------------
10915|      9|            return;
10916|      9|          }
10917|       |          // If you have the path "/joe/myfriend",
10918|       |          // then you delete 'myfriend'.
10919|     15|          path.resize(path.rfind('/') + 1);
10920|     15|          return;
10921|     24|        }
10922|    309|        path += '/';
10923|    309|        if (path_view != ".") {
  ------------------
  |  Branch (10923:13): [True: 208, False: 101]
  ------------------
10924|    208|          path.append(path_view);
10925|    208|        }
10926|    309|        return;
10927|  3.37k|      } else {
10928|       |        // This is a non-final segment.
10929|  3.37k|        std::string_view path_view =
10930|  3.37k|            input.substr(previous_location, new_location - previous_location);
10931|  3.37k|        previous_location = new_location + 1;
10932|  3.37k|        if (path_view == "..") {
  ------------------
  |  Branch (10932:13): [True: 526, False: 2.84k]
  ------------------
10933|    526|          size_t last_delimiter = path.rfind('/');
10934|    526|          if (last_delimiter != std::string::npos) {
  ------------------
  |  Branch (10934:15): [True: 260, False: 266]
  ------------------
10935|    260|            path.erase(last_delimiter);
10936|    260|          }
10937|  2.84k|        } else if (path_view != ".") {
  ------------------
  |  Branch (10937:20): [True: 2.47k, False: 374]
  ------------------
10938|  2.47k|          path += '/';
10939|  2.47k|          path.append(path_view);
10940|  2.47k|        }
10941|  3.37k|      }
10942|  3.71k|    } while (true);
  ------------------
  |  Branch (10942:14): [Folded - Ignored]
  ------------------
10943|  6.98k|  } else {
10944|  6.98k|    ada_log("parse_path slow");
10945|       |    // we have reached the general case
10946|  6.98k|    bool needs_percent_encoding = (accumulator & 1);
10947|  6.98k|    std::string path_buffer_tmp;
10948|  40.3k|    do {
10949|  40.3k|      size_t location = (special && (accumulator & 2))
  ------------------
  |  Branch (10949:26): [True: 33.3k, False: 6.99k]
  |  Branch (10949:37): [True: 5.32k, False: 28.0k]
  ------------------
10950|  40.3k|                            ? input.find_first_of("/\\")
10951|  40.3k|                            : input.find('/');
10952|  40.3k|      std::string_view path_view = input;
10953|  40.3k|      if (location != std::string_view::npos) {
  ------------------
  |  Branch (10953:11): [True: 33.3k, False: 6.98k]
  ------------------
10954|  33.3k|        path_view.remove_suffix(path_view.size() - location);
10955|  33.3k|        input.remove_prefix(location + 1);
10956|  33.3k|      }
10957|       |      // path_buffer is either path_view or it might point at a percent encoded
10958|       |      // temporary file.
10959|  40.3k|      std::string_view path_buffer =
10960|  40.3k|          (needs_percent_encoding &&
  ------------------
  |  Branch (10960:12): [True: 21.9k, False: 18.4k]
  ------------------
10961|  40.3k|           ada::unicode::percent_encode<false>(
  ------------------
  |  Branch (10961:12): [True: 10.1k, False: 11.7k]
  ------------------
10962|  21.9k|               path_view, character_sets::PATH_PERCENT_ENCODE, path_buffer_tmp))
10963|  40.3k|              ? path_buffer_tmp
10964|  40.3k|              : path_view;
10965|  40.3k|      if (unicode::is_double_dot_path_segment(path_buffer)) {
  ------------------
  |  Branch (10965:11): [True: 6.53k, False: 33.8k]
  ------------------
10966|  6.53k|        if ((helpers::shorten_path(path, type) || special) &&
  ------------------
  |  Branch (10966:14): [True: 3.25k, False: 3.28k]
  |  Branch (10966:51): [True: 2.92k, False: 364]
  ------------------
10967|  6.53k|            location == std::string_view::npos) {
  ------------------
  |  Branch (10967:13): [True: 421, False: 5.75k]
  ------------------
10968|    421|          path += '/';
10969|    421|        }
10970|  33.8k|      } else if (unicode::is_single_dot_path_segment(path_buffer) &&
  ------------------
  |  Branch (10970:18): [True: 3.12k, False: 30.6k]
  ------------------
10971|  33.8k|                 (location == std::string_view::npos)) {
  ------------------
  |  Branch (10971:18): [True: 235, False: 2.89k]
  ------------------
10972|    235|        path += '/';
10973|    235|      }
10974|       |      // Otherwise, if path_buffer is not a single-dot path segment, then:
10975|  33.5k|      else if (!unicode::is_single_dot_path_segment(path_buffer)) {
  ------------------
  |  Branch (10975:16): [True: 30.6k, False: 2.89k]
  ------------------
10976|       |        // If url's scheme is "file", url's path is empty, and path_buffer is a
10977|       |        // Windows drive letter, then replace the second code point in
10978|       |        // path_buffer with U+003A (:).
10979|  30.6k|        if (type == ada::scheme::type::FILE && path.empty() &&
  ------------------
  |  Branch (10979:13): [True: 20.6k, False: 10.0k]
  |  Branch (10979:48): [True: 7.65k, False: 12.9k]
  ------------------
10980|  30.6k|            checkers::is_windows_drive_letter(path_buffer)) {
  ------------------
  |  Branch (10980:13): [True: 1.50k, False: 6.14k]
  ------------------
10981|  1.50k|          path += '/';
10982|  1.50k|          path += path_buffer[0];
10983|  1.50k|          path += ':';
10984|  1.50k|          path_buffer.remove_prefix(2);
10985|  1.50k|          path.append(path_buffer);
10986|  29.1k|        } else {
10987|       |          // Append path_buffer to url's path.
10988|  29.1k|          path += '/';
10989|  29.1k|          path.append(path_buffer);
10990|  29.1k|        }
10991|  30.6k|      }
10992|  40.3k|      if (location == std::string_view::npos) {
  ------------------
  |  Branch (10992:11): [True: 6.98k, False: 33.3k]
  ------------------
10993|  6.98k|        return;
10994|  6.98k|      }
10995|  40.3k|    } while (true);
  ------------------
  |  Branch (10995:14): [Folded - Ignored]
  ------------------
10996|  6.98k|  }
10997|  7.33k|}
_ZN3ada8checkers14path_signatureENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
   68|  19.0k|    std::string_view input) noexcept {
   69|       |  // The path percent-encode set is the query percent-encode set and U+003F (?),
   70|       |  // U+0060 (`), U+007B ({), and U+007D (}). The query percent-encode set is the
   71|       |  // C0 control percent-encode set and U+0020 SPACE, U+0022 ("), U+0023 (#),
   72|       |  // U+003C (<), and U+003E (>). The C0 control percent-encode set are the C0
   73|       |  // controls and all code points greater than U+007E (~).
   74|  19.0k|  size_t i = 0;
   75|  19.0k|  uint8_t accumulator{};
   76|  56.4k|  for (; i + 7 < input.size(); i += 8) {
  ------------------
  |  Branch (76:10): [True: 37.4k, False: 19.0k]
  ------------------
   77|  37.4k|    accumulator |= uint8_t(path_signature_table[uint8_t(input[i])] |
   78|  37.4k|                           path_signature_table[uint8_t(input[i + 1])] |
   79|  37.4k|                           path_signature_table[uint8_t(input[i + 2])] |
   80|  37.4k|                           path_signature_table[uint8_t(input[i + 3])] |
   81|  37.4k|                           path_signature_table[uint8_t(input[i + 4])] |
   82|  37.4k|                           path_signature_table[uint8_t(input[i + 5])] |
   83|  37.4k|                           path_signature_table[uint8_t(input[i + 6])] |
   84|  37.4k|                           path_signature_table[uint8_t(input[i + 7])]);
   85|  37.4k|  }
   86|  67.7k|  for (; i < input.size(); i++) {
  ------------------
  |  Branch (86:10): [True: 48.7k, False: 19.0k]
  ------------------
   87|  48.7k|    accumulator |= uint8_t(path_signature_table[uint8_t(input[i])]);
   88|  48.7k|  }
   89|  19.0k|  return accumulator;
   90|  19.0k|}
_ZN3ada7unicode14percent_encodeILb0EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKhRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEE:
10203|  31.7k|                    std::string& out) {
10204|  31.7k|  ada_log("percent_encode ", input, " to output string while ",
10205|  31.7k|          append ? "appending" : "overwriting");
10206|  31.7k|  auto pointer =
10207|  31.7k|      std::find_if(input.begin(), input.end(), [character_set](const char c) {
10208|  31.7k|        return character_sets::bit_at(character_set, c);
10209|  31.7k|      });
10210|  31.7k|  ada_log("percent_encode done checking, moved to ",
10211|  31.7k|          std::distance(input.begin(), pointer));
10212|       |
10213|       |  // Optimization: Don't iterate if percent encode is not required
10214|  31.7k|  if (pointer == input.end()) {
  ------------------
  |  Branch (10214:7): [True: 17.5k, False: 14.2k]
  ------------------
10215|  17.5k|    ada_log("percent_encode encoding not needed.");
10216|  17.5k|    return false;
10217|  17.5k|  }
10218|  14.2k|  if (!append) {
  ------------------
  |  Branch (10218:7): [Folded - Ignored]
  ------------------
10219|  14.2k|    out.clear();
10220|  14.2k|  }
10221|  14.2k|  ada_log("percent_encode appending ", std::distance(input.begin(), pointer),
10222|  14.2k|          " bytes");
10223|  14.2k|  out.append(input.data(), std::distance(input.begin(), pointer));
10224|  14.2k|  ada_log("percent_encode processing ", std::distance(pointer, input.end()),
10225|  14.2k|          " bytes");
10226|   154k|  for (; pointer != input.end(); pointer++) {
  ------------------
  |  Branch (10226:10): [True: 139k, False: 14.2k]
  ------------------
10227|   139k|    if (character_sets::bit_at(character_set, *pointer)) {
  ------------------
  |  Branch (10227:9): [True: 112k, False: 27.0k]
  ------------------
10228|   112k|      out.append(character_sets::hex + uint8_t(*pointer) * 4, 3);
10229|   112k|    } else {
10230|  27.0k|      out += *pointer;
10231|  27.0k|    }
10232|   139k|  }
10233|  14.2k|  return true;
10234|  31.7k|}
_ZZN3ada7unicode14percent_encodeILb0EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKhRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEEENKUlcE_clEc:
10207|  59.2k|      std::find_if(input.begin(), input.end(), [character_set](const char c) {
10208|  59.2k|        return character_sets::bit_at(character_set, c);
10209|  59.2k|      });
_ZN3ada7unicode26is_double_dot_path_segmentENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
10075|  56.1k|    std::string_view input) noexcept {
10076|       |  // This will catch most cases:
10077|       |  // The length must be 2,4 or 6.
10078|       |  // We divide by two and require
10079|       |  // that the result be between 1 and 3 inclusively.
10080|  56.1k|  uint64_t half_length = uint64_t(input.size()) / 2;
10081|  56.1k|  if (half_length - 1 > 2) {
  ------------------
  |  Branch (10081:7): [True: 29.6k, False: 26.5k]
  ------------------
10082|  29.6k|    return false;
10083|  29.6k|  }
10084|       |  // We have a string of length 2, 4 or 6.
10085|       |  // We now check the first character:
10086|  26.5k|  if ((input[0] != '.') && (input[0] != '%')) {
  ------------------
  |  Branch (10086:7): [True: 14.2k, False: 12.2k]
  |  Branch (10086:28): [True: 5.83k, False: 8.46k]
  ------------------
10087|  5.83k|    return false;
10088|  5.83k|  }
10089|       |  // We are unlikely the get beyond this point.
10090|  20.7k|  int hash_value = (input.size() + (unsigned)(input[0])) & 3;
10091|  20.7k|  const std::string_view target = table_is_double_dot_path_segment[hash_value];
10092|  20.7k|  if (target.size() != input.size()) {
  ------------------
  |  Branch (10092:7): [True: 6.60k, False: 14.1k]
  ------------------
10093|  6.60k|    return false;
10094|  6.60k|  }
10095|       |  // We almost never get here.
10096|       |  // Optimizing the rest is relatively unimportant.
10097|  14.1k|  auto prefix_equal_unsafe = [](std::string_view a, std::string_view b) {
10098|  14.1k|    uint16_t A, B;
10099|  14.1k|    memcpy(&A, a.data(), sizeof(A));
10100|  14.1k|    memcpy(&B, b.data(), sizeof(B));
10101|  14.1k|    return A == B;
10102|  14.1k|  };
10103|  14.1k|  if (!prefix_equal_unsafe(input, target)) {
  ------------------
  |  Branch (10103:7): [True: 1.30k, False: 12.7k]
  ------------------
10104|  1.30k|    return false;
10105|  1.30k|  }
10106|  16.6k|  for (size_t i = 2; i < input.size(); i++) {
  ------------------
  |  Branch (10106:22): [True: 6.53k, False: 10.1k]
  ------------------
10107|  6.53k|    char c = input[i];
10108|  6.53k|    if ((uint8_t((c | 0x20) - 0x61) <= 25 ? (c | 0x20) : c) != target[i]) {
  ------------------
  |  Branch (10108:9): [True: 2.65k, False: 3.88k]
  |  Branch (10108:10): [True: 2.46k, False: 4.07k]
  ------------------
10109|  2.65k|      return false;
10110|  2.65k|    }
10111|  6.53k|  }
10112|  10.1k|  return true;
10113|       |  // The above code might be a bit better than the code below. Compilers
10114|       |  // are not stupid and may use the fact that these strings have length 2,4 and
10115|       |  // 6 and other tricks.
10116|       |  // return input == ".." ||
10117|       |  //  input == ".%2e" || input == ".%2E" ||
10118|       |  //  input == "%2e." || input == "%2E." ||
10119|       |  //  input == "%2e%2e" || input == "%2E%2E" || input == "%2E%2e" || input ==
10120|       |  //  "%2e%2E";
10121|  12.7k|}
_ZZN3ada7unicode26is_double_dot_path_segmentENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlS5_S5_E_clES5_S5_:
10097|  14.1k|  auto prefix_equal_unsafe = [](std::string_view a, std::string_view b) {
10098|  14.1k|    uint16_t A, B;
10099|  14.1k|    memcpy(&A, a.data(), sizeof(A));
10100|  14.1k|    memcpy(&B, b.data(), sizeof(B));
10101|  14.1k|    return A == B;
10102|  14.1k|  };
_ZN3ada7unicode26is_single_dot_path_segmentENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
10124|  91.6k|    std::string_view input) noexcept {
10125|  91.6k|  return input == "." || input == "%2e" || input == "%2E";
  ------------------
  |  Branch (10125:10): [True: 4.61k, False: 87.0k]
  |  Branch (10125:26): [True: 1.50k, False: 85.5k]
  |  Branch (10125:44): [True: 1.49k, False: 84.0k]
  ------------------
10126|  91.6k|}
_ZN3ada7unicode28is_forbidden_host_code_pointEc:
 9909|  23.2k|    const char c) noexcept {
 9910|  23.2k|  return is_forbidden_host_code_point_table[uint8_t(c)];
 9911|  23.2k|}
_ZN3ada7unicode22is_c0_control_or_spaceEc:
10062|  69.4k|ada_really_inline constexpr bool is_c0_control_or_space(const char c) noexcept {
10063|  69.4k|  return (unsigned char)c <= ' ';
10064|  69.4k|}
_ZN3ada3url10parse_pathENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11618|  4.97k|ada_really_inline void url::parse_path(std::string_view input) {
11619|  4.97k|  ada_log("parse_path ", input);
11620|  4.97k|  std::string tmp_buffer;
11621|  4.97k|  std::string_view internal_input;
11622|  4.97k|  if (unicode::has_tabs_or_newline(input)) {
  ------------------
  |  Branch (11622:7): [True: 63, False: 4.91k]
  ------------------
11623|     63|    tmp_buffer = input;
11624|       |    // Optimization opportunity: Instead of copying and then pruning, we could
11625|       |    // just directly build the string from user_input.
11626|     63|    helpers::remove_ascii_tab_or_newline(tmp_buffer);
11627|     63|    internal_input = tmp_buffer;
11628|  4.91k|  } else {
11629|  4.91k|    internal_input = input;
11630|  4.91k|  }
11631|       |
11632|       |  // If url is special, then:
11633|  4.97k|  if (is_special()) {
  ------------------
  |  Branch (11633:7): [True: 3.82k, False: 1.15k]
  ------------------
11634|  3.82k|    if (internal_input.empty()) {
  ------------------
  |  Branch (11634:9): [True: 2.43k, False: 1.38k]
  ------------------
11635|  2.43k|      path = "/";
11636|  2.43k|    } else if ((internal_input[0] == '/') || (internal_input[0] == '\\')) {
  ------------------
  |  Branch (11636:16): [True: 341, False: 1.04k]
  |  Branch (11636:46): [True: 2, False: 1.04k]
  ------------------
11637|    343|      helpers::parse_prepared_path(internal_input.substr(1), type, path);
11638|    343|      return;
11639|  1.04k|    } else {
11640|  1.04k|      helpers::parse_prepared_path(internal_input, type, path);
11641|  1.04k|      return;
11642|  1.04k|    }
11643|  3.82k|  } else if (!internal_input.empty()) {
  ------------------
  |  Branch (11643:14): [True: 539, False: 614]
  ------------------
11644|    539|    if (internal_input[0] == '/') {
  ------------------
  |  Branch (11644:9): [True: 191, False: 348]
  ------------------
11645|    191|      helpers::parse_prepared_path(internal_input.substr(1), type, path);
11646|    191|      return;
11647|    348|    } else {
11648|    348|      helpers::parse_prepared_path(internal_input, type, path);
11649|    348|      return;
11650|    348|    }
11651|    614|  } else {
11652|    614|    if (!host.has_value()) {
  ------------------
  |  Branch (11652:9): [True: 0, False: 614]
  ------------------
11653|      0|      path = "/";
11654|      0|    }
11655|    614|  }
11656|  3.05k|  return;
11657|  4.97k|}
_ZN3ada7unicode13is_alnum_plusEc:
10043|  89.9k|ada_really_inline constexpr bool is_alnum_plus(const char c) noexcept {
10044|  89.9k|  return is_alnum_plus_table[uint8_t(c)];
10045|       |  // A table is almost surely much faster than the
10046|       |  // following under most compilers: return
10047|       |  // return (std::isalnum(c) || c == '+' || c == '-' || c == '.');
10048|  89.9k|}
_ZN3ada7helpers18trim_c0_whitespaceERNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
10829|  41.7k|ada_really_inline void trim_c0_whitespace(std::string_view& input) noexcept {
10830|  44.8k|  while (!input.empty() &&
  ------------------
  |  Branch (10830:10): [True: 34.0k, False: 10.7k]
  ------------------
10831|  44.8k|         ada::unicode::is_c0_control_or_space(input.front())) {
  ------------------
  |  Branch (10831:10): [True: 3.04k, False: 31.0k]
  ------------------
10832|  3.04k|    input.remove_prefix(1);
10833|  3.04k|  }
10834|  43.9k|  while (!input.empty() && ada::unicode::is_c0_control_or_space(input.back())) {
  ------------------
  |  Branch (10834:10): [True: 33.2k, False: 10.7k]
  |  Branch (10834:28): [True: 2.21k, False: 31.0k]
  ------------------
10835|  2.21k|    input.remove_suffix(1);
10836|  2.21k|  }
10837|  41.7k|}
_ZN3ada7helpers10prune_hashERNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
10510|  41.7k|    std::string_view& input) noexcept {
10511|       |  // compiles down to 20--30 instructions including a class to memchr (C
10512|       |  // function). this function should be quite fast.
10513|  41.7k|  size_t location_of_first = input.find('#');
10514|  41.7k|  if (location_of_first == std::string_view::npos) {
  ------------------
  |  Branch (10514:7): [True: 40.6k, False: 1.09k]
  ------------------
10515|  40.6k|    return std::nullopt;
10516|  40.6k|  }
10517|  1.09k|  std::string_view hash = input;
10518|  1.09k|  hash.remove_prefix(location_of_first + 1);
10519|  1.09k|  input.remove_suffix(input.size() - location_of_first);
10520|  1.09k|  return hash;
10521|  41.7k|}
_ZN3ada7helpers9substringENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEm:
10587|  58.5k|                                             size_t pos) noexcept {
10588|  58.5k|  ADA_ASSERT_TRUE(pos <= input.size());
10589|       |  // The following is safer but unneeded if we have the above line:
10590|       |  // return pos > input.size() ? std::string_view() : input.substr(pos);
10591|  58.5k|  return input.substr(pos);
10592|  58.5k|}
_ZN3ada7helpers32find_authority_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11023|  7.40k|find_authority_delimiter_special(std::string_view view) noexcept {
11024|  7.40k|  auto has_zero_byte = [](uint64_t v) {
11025|  7.40k|    return ((v - 0x0101010101010101) & ~(v)&0x8080808080808080);
11026|  7.40k|  };
11027|  7.40k|  auto index_of_first_set_byte = [](uint64_t v) {
11028|  7.40k|    return ((((v - 1) & 0x101010101010101) * 0x101010101010101) >> 56) - 1;
11029|  7.40k|  };
11030|  7.40k|  auto broadcast = [](uint8_t v) -> uint64_t {
11031|  7.40k|    return 0x101010101010101ull * v;
11032|  7.40k|  };
11033|  7.40k|  size_t i = 0;
11034|  7.40k|  uint64_t mask1 = broadcast('@');
11035|  7.40k|  uint64_t mask2 = broadcast('/');
11036|  7.40k|  uint64_t mask3 = broadcast('?');
11037|  7.40k|  uint64_t mask4 = broadcast('\\');
11038|       |
11039|  11.2k|  for (; i + 7 < view.size(); i += 8) {
  ------------------
  |  Branch (11039:10): [True: 8.71k, False: 2.52k]
  ------------------
11040|  8.71k|    uint64_t word{};
11041|  8.71k|    memcpy(&word, view.data() + i, sizeof(word));
11042|  8.71k|    word = swap_bytes_if_big_endian(word);
11043|  8.71k|    uint64_t xor1 = word ^ mask1;
11044|  8.71k|    uint64_t xor2 = word ^ mask2;
11045|  8.71k|    uint64_t xor3 = word ^ mask3;
11046|  8.71k|    uint64_t xor4 = word ^ mask4;
11047|  8.71k|    uint64_t is_match = has_zero_byte(xor1) | has_zero_byte(xor2) |
11048|  8.71k|                        has_zero_byte(xor3) | has_zero_byte(xor4);
11049|  8.71k|    if (is_match) {
  ------------------
  |  Branch (11049:9): [True: 4.88k, False: 3.82k]
  ------------------
11050|  4.88k|      return size_t(i + index_of_first_set_byte(is_match));
11051|  4.88k|    }
11052|  8.71k|  }
11053|       |
11054|  2.52k|  if (i < view.size()) {
  ------------------
  |  Branch (11054:7): [True: 2.10k, False: 411]
  ------------------
11055|  2.10k|    uint64_t word{};
11056|  2.10k|    memcpy(&word, view.data() + i, view.size() - i);
11057|  2.10k|    word = swap_bytes_if_big_endian(word);
11058|  2.10k|    uint64_t xor1 = word ^ mask1;
11059|  2.10k|    uint64_t xor2 = word ^ mask2;
11060|  2.10k|    uint64_t xor3 = word ^ mask3;
11061|  2.10k|    uint64_t xor4 = word ^ mask4;
11062|  2.10k|    uint64_t is_match = has_zero_byte(xor1) | has_zero_byte(xor2) |
11063|  2.10k|                        has_zero_byte(xor3) | has_zero_byte(xor4);
11064|  2.10k|    if (is_match) {
  ------------------
  |  Branch (11064:9): [True: 1.74k, False: 368]
  ------------------
11065|  1.74k|      return size_t(i + index_of_first_set_byte(is_match));
11066|  1.74k|    }
11067|  2.10k|  }
11068|       |
11069|    779|  return view.size();
11070|  2.52k|}
_ZZN3ada7helpers32find_authority_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlhE_clEh:
11030|  29.6k|  auto broadcast = [](uint8_t v) -> uint64_t {
11031|  29.6k|    return 0x101010101010101ull * v;
11032|  29.6k|  };
_ZN3ada7helpers24swap_bytes_if_big_endianEm:
10612|  64.4k|ada_really_inline uint64_t swap_bytes_if_big_endian(uint64_t val) noexcept {
10613|       |  // performance: under little-endian systems (most systems), this function
10614|       |  // is free (just returns the input).
10615|       |#if ADA_IS_BIG_ENDIAN
10616|       |  return swap_bytes(val);
10617|       |#else
10618|  64.4k|  return val;  // unchanged (trivial)
10619|  64.4k|#endif
10620|  64.4k|}
_ZZN3ada7helpers32find_authority_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlmE_clEm:
11024|  43.3k|  auto has_zero_byte = [](uint64_t v) {
11025|  43.3k|    return ((v - 0x0101010101010101) & ~(v)&0x8080808080808080);
11026|  43.3k|  };
_ZZN3ada7helpers32find_authority_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlmE0_clEm:
11027|  6.63k|  auto index_of_first_set_byte = [](uint64_t v) {
11028|  6.63k|    return ((((v - 1) & 0x101010101010101) * 0x101010101010101) >> 56) - 1;
11029|  6.63k|  };
_ZN3ada7helpers24find_authority_delimiterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11073|  1.05k|find_authority_delimiter(std::string_view view) noexcept {
11074|  1.05k|  auto has_zero_byte = [](uint64_t v) {
11075|  1.05k|    return ((v - 0x0101010101010101) & ~(v)&0x8080808080808080);
11076|  1.05k|  };
11077|  1.05k|  auto index_of_first_set_byte = [](uint64_t v) {
11078|  1.05k|    return ((((v - 1) & 0x101010101010101) * 0x101010101010101) >> 56) - 1;
11079|  1.05k|  };
11080|  1.05k|  auto broadcast = [](uint8_t v) -> uint64_t {
11081|  1.05k|    return 0x101010101010101ull * v;
11082|  1.05k|  };
11083|  1.05k|  size_t i = 0;
11084|  1.05k|  uint64_t mask1 = broadcast('@');
11085|  1.05k|  uint64_t mask2 = broadcast('/');
11086|  1.05k|  uint64_t mask3 = broadcast('?');
11087|       |
11088|  1.68k|  for (; i + 7 < view.size(); i += 8) {
  ------------------
  |  Branch (11088:10): [True: 1.34k, False: 336]
  ------------------
11089|  1.34k|    uint64_t word{};
11090|  1.34k|    memcpy(&word, view.data() + i, sizeof(word));
11091|  1.34k|    word = swap_bytes_if_big_endian(word);
11092|  1.34k|    uint64_t xor1 = word ^ mask1;
11093|  1.34k|    uint64_t xor2 = word ^ mask2;
11094|  1.34k|    uint64_t xor3 = word ^ mask3;
11095|  1.34k|    uint64_t is_match =
11096|  1.34k|        has_zero_byte(xor1) | has_zero_byte(xor2) | has_zero_byte(xor3);
11097|  1.34k|    if (is_match) {
  ------------------
  |  Branch (11097:9): [True: 717, False: 631]
  ------------------
11098|    717|      return size_t(i + index_of_first_set_byte(is_match));
11099|    717|    }
11100|  1.34k|  }
11101|       |
11102|    336|  if (i < view.size()) {
  ------------------
  |  Branch (11102:7): [True: 270, False: 66]
  ------------------
11103|    270|    uint64_t word{};
11104|    270|    memcpy(&word, view.data() + i, view.size() - i);
11105|    270|    word = swap_bytes_if_big_endian(word);
11106|    270|    uint64_t xor1 = word ^ mask1;
11107|    270|    uint64_t xor2 = word ^ mask2;
11108|    270|    uint64_t xor3 = word ^ mask3;
11109|    270|    uint64_t is_match =
11110|    270|        has_zero_byte(xor1) | has_zero_byte(xor2) | has_zero_byte(xor3);
11111|    270|    if (is_match) {
  ------------------
  |  Branch (11111:9): [True: 219, False: 51]
  ------------------
11112|    219|      return size_t(i + index_of_first_set_byte(is_match));
11113|    219|    }
11114|    270|  }
11115|       |
11116|    117|  return view.size();
11117|    336|}
_ZZN3ada7helpers24find_authority_delimiterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlhE_clEh:
11080|  3.15k|  auto broadcast = [](uint8_t v) -> uint64_t {
11081|  3.15k|    return 0x101010101010101ull * v;
11082|  3.15k|  };
_ZZN3ada7helpers24find_authority_delimiterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlmE_clEm:
11074|  4.85k|  auto has_zero_byte = [](uint64_t v) {
11075|  4.85k|    return ((v - 0x0101010101010101) & ~(v)&0x8080808080808080);
11076|  4.85k|  };
_ZZN3ada7helpers24find_authority_delimiterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlmE0_clEm:
11077|    936|  auto index_of_first_set_byte = [](uint64_t v) {
11078|    936|    return ((((v - 1) & 0x101010101010101) * 0x101010101010101) >> 56) - 1;
11079|    936|  };
_ZN3ada7helpers12shorten_pathERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS_6scheme4typeE:
10524|  10.1k|                                    ada::scheme::type type) noexcept {
10525|  10.1k|  size_t first_delimiter = path.find_first_of('/', 1);
10526|       |
10527|       |  // Let path be url's path.
10528|       |  // If url's scheme is "file", path's size is 1, and path[0] is a normalized
10529|       |  // Windows drive letter, then return.
10530|  10.1k|  if (type == ada::scheme::type::FILE &&
  ------------------
  |  Branch (10530:7): [True: 8.26k, False: 1.87k]
  ------------------
10531|  10.1k|      first_delimiter == std::string_view::npos && !path.empty()) {
  ------------------
  |  Branch (10531:7): [True: 7.11k, False: 1.14k]
  |  Branch (10531:52): [True: 4.88k, False: 2.23k]
  ------------------
10532|  4.88k|    if (checkers::is_normalized_windows_drive_letter(
  ------------------
  |  Branch (10532:9): [True: 1.46k, False: 3.42k]
  ------------------
10533|  4.88k|            helpers::substring(path, 1))) {
10534|  1.46k|      return false;
10535|  1.46k|    }
10536|  4.88k|  }
10537|       |
10538|       |  // Remove path's last item, if any.
10539|  8.68k|  size_t last_delimiter = path.rfind('/');
10540|  8.68k|  if (last_delimiter != std::string::npos) {
  ------------------
  |  Branch (10540:7): [True: 5.03k, False: 3.64k]
  ------------------
10541|  5.03k|    path.erase(last_delimiter);
10542|  5.03k|    return true;
10543|  5.03k|  }
10544|       |
10545|  3.64k|  return false;
10546|  8.68k|}
_ZN3ada7helpers27get_host_delimiter_locationEbRNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
10750|  29.3k|    const bool is_special, std::string_view& view) noexcept {
10751|       |  /**
10752|       |   * The spec at https://url.spec.whatwg.org/#hostname-state expects us to
10753|       |   * compute a variable called insideBrackets but this variable is only used
10754|       |   * once, to check whether a ':' character was found outside brackets. Exact
10755|       |   * text: "Otherwise, if c is U+003A (:) and insideBrackets is false, then:".
10756|       |   * It is conceptually simpler and arguably more efficient to just return a
10757|       |   * Boolean indicating whether ':' was found outside brackets.
10758|       |   */
10759|  29.3k|  const size_t view_size = view.size();
10760|  29.3k|  size_t location = 0;
10761|  29.3k|  bool found_colon = false;
10762|       |  /**
10763|       |   * Performance analysis:
10764|       |   *
10765|       |   * We are basically seeking the end of the hostname which can be indicated
10766|       |   * by the end of the view, or by one of the characters ':', '/', '?', '\\'
10767|       |   * (where '\\' is only applicable for special URLs). However, these must
10768|       |   * appear outside a bracket range. E.g., if you have [something?]fd: then the
10769|       |   * '?' does not count.
10770|       |   *
10771|       |   * So we can skip ahead to the next delimiter, as long as we include '[' in
10772|       |   * the set of delimiters, and that we handle it first.
10773|       |   *
10774|       |   * So the trick is to have a fast function that locates the next delimiter.
10775|       |   * Unless we find '[', then it only needs to be called once! Ideally, such a
10776|       |   * function would be provided by the C++ standard library, but it seems that
10777|       |   * find_first_of is not very fast, so we are forced to roll our own.
10778|       |   *
10779|       |   * We do not break into two loops for speed, but for clarity.
10780|       |   */
10781|  29.3k|  if (is_special) {
  ------------------
  |  Branch (10781:7): [True: 23.7k, False: 5.60k]
  ------------------
10782|       |    // We move to the next delimiter.
10783|  23.7k|    location = find_next_host_delimiter_special(view, location);
10784|       |    // Unless we find '[' then we are going only going to have to call
10785|       |    // find_next_host_delimiter_special once.
10786|  27.4k|    for (; location < view_size;
  ------------------
  |  Branch (10786:12): [True: 7.81k, False: 19.6k]
  ------------------
10787|  23.7k|         location = find_next_host_delimiter_special(view, location)) {
10788|  7.81k|      if (view[location] == '[') {
  ------------------
  |  Branch (10788:11): [True: 3.91k, False: 3.90k]
  ------------------
10789|  3.91k|        location = view.find(']', location);
10790|  3.91k|        if (location == std::string_view::npos) {
  ------------------
  |  Branch (10790:13): [True: 228, False: 3.68k]
  ------------------
10791|       |          // performance: view.find might get translated to a memchr, which
10792|       |          // has no notion of std::string_view::npos, so the code does not
10793|       |          // reflect the assembly.
10794|    228|          location = view_size;
10795|    228|          break;
10796|    228|        }
10797|  3.91k|      } else {
10798|  3.90k|        found_colon = view[location] == ':';
10799|  3.90k|        break;
10800|  3.90k|      }
10801|  7.81k|    }
10802|  23.7k|  } else {
10803|       |    // We move to the next delimiter.
10804|  5.60k|    location = find_next_host_delimiter(view, location);
10805|       |    // Unless we find '[' then we are going only going to have to call
10806|       |    // find_next_host_delimiter_special once.
10807|  8.24k|    for (; location < view_size;
  ------------------
  |  Branch (10807:12): [True: 4.00k, False: 4.24k]
  ------------------
10808|  5.60k|         location = find_next_host_delimiter(view, location)) {
10809|  4.00k|      if (view[location] == '[') {
  ------------------
  |  Branch (10809:11): [True: 2.79k, False: 1.20k]
  ------------------
10810|  2.79k|        location = view.find(']', location);
10811|  2.79k|        if (location == std::string_view::npos) {
  ------------------
  |  Branch (10811:13): [True: 158, False: 2.64k]
  ------------------
10812|       |          // performance: view.find might get translated to a memchr, which
10813|       |          // has no notion of std::string_view::npos, so the code does not
10814|       |          // reflect the assembly.
10815|    158|          location = view_size;
10816|    158|          break;
10817|    158|        }
10818|  2.79k|      } else {
10819|  1.20k|        found_colon = view[location] == ':';
10820|  1.20k|        break;
10821|  1.20k|      }
10822|  4.00k|    }
10823|  5.60k|  }
10824|       |  // performance: remove_suffix may translate into a single instruction.
10825|  29.3k|  view.remove_suffix(view_size - location);
10826|  29.3k|  return {location, found_colon};
10827|  29.3k|}
_ZN3ada7helpers32find_next_host_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEm:
10626|  27.4k|    std::string_view view, size_t location) noexcept {
10627|       |  // performance: if you plan to call find_next_host_delimiter more than once,
10628|       |  // you *really* want find_next_host_delimiter to be inlined, because
10629|       |  // otherwise, the constants may get reloaded each time (bad).
10630|  27.4k|  auto has_zero_byte = [](uint64_t v) {
10631|  27.4k|    return ((v - 0x0101010101010101) & ~(v)&0x8080808080808080);
10632|  27.4k|  };
10633|  27.4k|  auto index_of_first_set_byte = [](uint64_t v) {
10634|  27.4k|    return ((((v - 1) & 0x101010101010101) * 0x101010101010101) >> 56) - 1;
10635|  27.4k|  };
10636|  27.4k|  auto broadcast = [](uint8_t v) -> uint64_t {
10637|  27.4k|    return 0x101010101010101ull * v;
10638|  27.4k|  };
10639|  27.4k|  size_t i = location;
10640|  27.4k|  uint64_t mask1 = broadcast(':');
10641|  27.4k|  uint64_t mask2 = broadcast('/');
10642|  27.4k|  uint64_t mask3 = broadcast('\\');
10643|  27.4k|  uint64_t mask4 = broadcast('?');
10644|  27.4k|  uint64_t mask5 = broadcast('[');
10645|       |  // This loop will get autovectorized under many optimizing compilers,
10646|       |  // so you get actually SIMD!
10647|  51.8k|  for (; i + 7 < view.size(); i += 8) {
  ------------------
  |  Branch (10647:10): [True: 28.5k, False: 23.2k]
  ------------------
10648|  28.5k|    uint64_t word{};
10649|       |    // performance: the next memcpy translates into a single CPU instruction.
10650|  28.5k|    memcpy(&word, view.data() + i, sizeof(word));
10651|       |    // performance: on little-endian systems (most systems), this next line is
10652|       |    // free.
10653|  28.5k|    word = swap_bytes_if_big_endian(word);
10654|  28.5k|    uint64_t xor1 = word ^ mask1;
10655|  28.5k|    uint64_t xor2 = word ^ mask2;
10656|  28.5k|    uint64_t xor3 = word ^ mask3;
10657|  28.5k|    uint64_t xor4 = word ^ mask4;
10658|  28.5k|    uint64_t xor5 = word ^ mask5;
10659|  28.5k|    uint64_t is_match = has_zero_byte(xor1) | has_zero_byte(xor2) |
10660|  28.5k|                        has_zero_byte(xor3) | has_zero_byte(xor4) |
10661|  28.5k|                        has_zero_byte(xor5);
10662|  28.5k|    if (is_match) {
  ------------------
  |  Branch (10662:9): [True: 4.16k, False: 24.4k]
  ------------------
10663|  4.16k|      return size_t(i + index_of_first_set_byte(is_match));
10664|  4.16k|    }
10665|  28.5k|  }
10666|  23.2k|  if (i < view.size()) {
  ------------------
  |  Branch (10666:7): [True: 14.3k, False: 8.88k]
  ------------------
10667|  14.3k|    uint64_t word{};
10668|       |    // performance: the next memcpy translates into a function call, but
10669|       |    // that is difficult to avoid. Might be a bit expensive.
10670|  14.3k|    memcpy(&word, view.data() + i, view.size() - i);
10671|  14.3k|    word = swap_bytes_if_big_endian(word);
10672|  14.3k|    uint64_t xor1 = word ^ mask1;
10673|  14.3k|    uint64_t xor2 = word ^ mask2;
10674|  14.3k|    uint64_t xor3 = word ^ mask3;
10675|  14.3k|    uint64_t xor4 = word ^ mask4;
10676|  14.3k|    uint64_t xor5 = word ^ mask5;
10677|  14.3k|    uint64_t is_match = has_zero_byte(xor1) | has_zero_byte(xor2) |
10678|  14.3k|                        has_zero_byte(xor3) | has_zero_byte(xor4) |
10679|  14.3k|                        has_zero_byte(xor5);
10680|  14.3k|    if (is_match) {
  ------------------
  |  Branch (10680:9): [True: 3.64k, False: 10.7k]
  ------------------
10681|  3.64k|      return size_t(i + index_of_first_set_byte(is_match));
10682|  3.64k|    }
10683|  14.3k|  }
10684|  19.6k|  return view.size();
10685|  23.2k|}
_ZZN3ada7helpers32find_next_host_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEmENKUlhE_clEh:
10636|   137k|  auto broadcast = [](uint8_t v) -> uint64_t {
10637|   137k|    return 0x101010101010101ull * v;
10638|   137k|  };
_ZZN3ada7helpers32find_next_host_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEmENKUlmE_clEm:
10630|   214k|  auto has_zero_byte = [](uint64_t v) {
10631|   214k|    return ((v - 0x0101010101010101) & ~(v)&0x8080808080808080);
10632|   214k|  };
_ZZN3ada7helpers32find_next_host_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEmENKUlmE0_clEm:
10633|  7.81k|  auto index_of_first_set_byte = [](uint64_t v) {
10634|  7.81k|    return ((((v - 1) & 0x101010101010101) * 0x101010101010101) >> 56) - 1;
10635|  7.81k|  };
_ZN3ada7helpers24find_next_host_delimiterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEm:
10691|  8.24k|                                                  size_t location) noexcept {
10692|       |  // performance: if you plan to call find_next_host_delimiter more than once,
10693|       |  // you *really* want find_next_host_delimiter to be inlined, because
10694|       |  // otherwise, the constants may get reloaded each time (bad).
10695|  8.24k|  auto has_zero_byte = [](uint64_t v) {
10696|  8.24k|    return ((v - 0x0101010101010101) & ~(v)&0x8080808080808080);
10697|  8.24k|  };
10698|  8.24k|  auto index_of_first_set_byte = [](uint64_t v) {
10699|  8.24k|    return ((((v - 1) & 0x101010101010101) * 0x101010101010101) >> 56) - 1;
10700|  8.24k|  };
10701|  8.24k|  auto broadcast = [](uint8_t v) -> uint64_t {
10702|  8.24k|    return 0x101010101010101ull * v;
10703|  8.24k|  };
10704|  8.24k|  size_t i = location;
10705|  8.24k|  uint64_t mask1 = broadcast(':');
10706|  8.24k|  uint64_t mask2 = broadcast('/');
10707|  8.24k|  uint64_t mask4 = broadcast('?');
10708|  8.24k|  uint64_t mask5 = broadcast('[');
10709|       |  // This loop will get autovectorized under many optimizing compilers,
10710|       |  // so you get actually SIMD!
10711|  12.3k|  for (; i + 7 < view.size(); i += 8) {
  ------------------
  |  Branch (10711:10): [True: 6.90k, False: 5.44k]
  ------------------
10712|  6.90k|    uint64_t word{};
10713|       |    // performance: the next memcpy translates into a single CPU instruction.
10714|  6.90k|    memcpy(&word, view.data() + i, sizeof(word));
10715|       |    // performance: on little-endian systems (most systems), this next line is
10716|       |    // free.
10717|  6.90k|    word = swap_bytes_if_big_endian(word);
10718|  6.90k|    uint64_t xor1 = word ^ mask1;
10719|  6.90k|    uint64_t xor2 = word ^ mask2;
10720|  6.90k|    uint64_t xor4 = word ^ mask4;
10721|  6.90k|    uint64_t xor5 = word ^ mask5;
10722|  6.90k|    uint64_t is_match = has_zero_byte(xor1) | has_zero_byte(xor2) |
10723|  6.90k|                        has_zero_byte(xor4) | has_zero_byte(xor5);
10724|  6.90k|    if (is_match) {
  ------------------
  |  Branch (10724:9): [True: 2.79k, False: 4.10k]
  ------------------
10725|  2.79k|      return size_t(i + index_of_first_set_byte(is_match));
10726|  2.79k|    }
10727|  6.90k|  }
10728|  5.44k|  if (i < view.size()) {
  ------------------
  |  Branch (10728:7): [True: 2.15k, False: 3.29k]
  ------------------
10729|  2.15k|    uint64_t word{};
10730|       |    // performance: the next memcpy translates into a function call, but
10731|       |    // that is difficult to avoid. Might be a bit expensive.
10732|  2.15k|    memcpy(&word, view.data() + i, view.size() - i);
10733|       |    // performance: on little-endian systems (most systems), this next line is
10734|       |    // free.
10735|  2.15k|    word = swap_bytes_if_big_endian(word);
10736|  2.15k|    uint64_t xor1 = word ^ mask1;
10737|  2.15k|    uint64_t xor2 = word ^ mask2;
10738|  2.15k|    uint64_t xor4 = word ^ mask4;
10739|  2.15k|    uint64_t xor5 = word ^ mask5;
10740|  2.15k|    uint64_t is_match = has_zero_byte(xor1) | has_zero_byte(xor2) |
10741|  2.15k|                        has_zero_byte(xor4) | has_zero_byte(xor5);
10742|  2.15k|    if (is_match) {
  ------------------
  |  Branch (10742:9): [True: 1.20k, False: 948]
  ------------------
10743|  1.20k|      return size_t(i + index_of_first_set_byte(is_match));
10744|  1.20k|    }
10745|  2.15k|  }
10746|  4.24k|  return view.size();
10747|  5.44k|}
_ZZN3ada7helpers24find_next_host_delimiterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEmENKUlhE_clEh:
10701|  32.9k|  auto broadcast = [](uint8_t v) -> uint64_t {
10702|  32.9k|    return 0x101010101010101ull * v;
10703|  32.9k|  };
_ZZN3ada7helpers24find_next_host_delimiterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEmENKUlmE_clEm:
10695|  36.2k|  auto has_zero_byte = [](uint64_t v) {
10696|  36.2k|    return ((v - 0x0101010101010101) & ~(v)&0x8080808080808080);
10697|  36.2k|  };
_ZZN3ada7helpers24find_next_host_delimiterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEmENKUlmE0_clEm:
10698|  4.00k|  auto index_of_first_set_byte = [](uint64_t v) {
10699|  4.00k|    return ((((v - 1) & 0x101010101010101) * 0x101010101010101) >> 56) - 1;
10700|  4.00k|  };
_ZN3ada3url10parse_hostENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11548|  6.97k|ada_really_inline bool url::parse_host(std::string_view input) {
11549|  6.97k|  ada_log("parse_host ", input, "[", input.size(), " bytes]");
11550|  6.97k|  if (input.empty()) {
  ------------------
  |  Branch (11550:7): [True: 26, False: 6.94k]
  ------------------
11551|     26|    return is_valid = false;
11552|     26|  }  // technically unnecessary.
11553|       |  // If input starts with U+005B ([), then:
11554|  6.94k|  if (input[0] == '[') {
  ------------------
  |  Branch (11554:7): [True: 593, False: 6.35k]
  ------------------
11555|       |    // If input does not end with U+005D (]), validation error, return failure.
11556|    593|    if (input.back() != ']') {
  ------------------
  |  Branch (11556:9): [True: 218, False: 375]
  ------------------
11557|    218|      return is_valid = false;
11558|    218|    }
11559|    375|    ada_log("parse_host ipv6");
11560|       |
11561|       |    // Return the result of IPv6 parsing input with its leading U+005B ([) and
11562|       |    // trailing U+005D (]) removed.
11563|    375|    input.remove_prefix(1);
11564|    375|    input.remove_suffix(1);
11565|    375|    return parse_ipv6(input);
11566|    593|  }
11567|       |
11568|       |  // If isNotSpecial is true, then return the result of opaque-host parsing
11569|       |  // input.
11570|  6.35k|  if (!is_special()) {
  ------------------
  |  Branch (11570:7): [True: 706, False: 5.64k]
  ------------------
11571|    706|    return parse_opaque_host(input);
11572|    706|  }
11573|       |  // Let domain be the result of running UTF-8 decode without BOM on the
11574|       |  // percent-decoding of input. Let asciiDomain be the result of running domain
11575|       |  // to ASCII with domain and false. The most common case is an ASCII input, in
11576|       |  // which case we do not need to call the expensive 'to_ascii' if a few
11577|       |  // conditions are met: no '%' and no 'xn-' subsequence.
11578|  5.64k|  std::string buffer = std::string(input);
11579|       |  // This next function checks that the result is ascii, but we are going to
11580|       |  // to check anyhow with is_forbidden.
11581|       |  // bool is_ascii =
11582|  5.64k|  unicode::to_lower_ascii(buffer.data(), buffer.size());
11583|  5.64k|  bool is_forbidden = unicode::contains_forbidden_domain_code_point(
11584|  5.64k|      buffer.data(), buffer.size());
11585|  5.64k|  if (is_forbidden == 0 && buffer.find("xn-") == std::string_view::npos) {
  ------------------
  |  Branch (11585:7): [True: 3.66k, False: 1.98k]
  |  Branch (11585:28): [True: 3.45k, False: 204]
  ------------------
11586|       |    // fast path
11587|  3.45k|    host = std::move(buffer);
11588|  3.45k|    if (checkers::is_ipv4(host.value())) {
  ------------------
  |  Branch (11588:9): [True: 1.39k, False: 2.06k]
  ------------------
11589|  1.39k|      ada_log("parse_host fast path ipv4");
11590|  1.39k|      return parse_ipv4(host.value());
11591|  1.39k|    }
11592|  2.06k|    ada_log("parse_host fast path ", *host);
11593|  2.06k|    return true;
11594|  3.45k|  }
11595|  2.19k|  ada_log("parse_host calling to_ascii");
11596|  2.19k|  is_valid = ada::unicode::to_ascii(host, input, input.find('%'));
11597|  2.19k|  if (!is_valid) {
  ------------------
  |  Branch (11597:7): [True: 1.02k, False: 1.16k]
  ------------------
11598|  1.02k|    ada_log("parse_host to_ascii returns false");
11599|  1.02k|    return is_valid = false;
11600|  1.02k|  }
11601|       |
11602|  1.16k|  if (std::any_of(host.value().begin(), host.value().end(),
  ------------------
  |  Branch (11602:7): [True: 0, False: 1.16k]
  ------------------
11603|  1.16k|                  ada::unicode::is_forbidden_domain_code_point)) {
11604|      0|    host = std::nullopt;
11605|      0|    return is_valid = false;
11606|      0|  }
11607|       |
11608|       |  // If asciiDomain ends in a number, then return the result of IPv4 parsing
11609|       |  // asciiDomain.
11610|  1.16k|  if (checkers::is_ipv4(host.value())) {
  ------------------
  |  Branch (11610:7): [True: 156, False: 1.01k]
  ------------------
11611|    156|    ada_log("parse_host got ipv4", *host);
11612|    156|    return parse_ipv4(host.value());
11613|    156|  }
11614|       |
11615|  1.01k|  return true;
11616|  1.16k|}
_ZN3ada7unicode14to_lower_asciiEPcm:
 9784|  19.8k|constexpr bool to_lower_ascii(char* input, size_t length) noexcept {
 9785|  19.8k|  uint64_t broadcast_80 = broadcast(0x80);
 9786|  19.8k|  uint64_t broadcast_Ap = broadcast(128 - 'A');
 9787|  19.8k|  uint64_t broadcast_Zp = broadcast(128 - 'Z' - 1);
 9788|  19.8k|  uint64_t non_ascii = 0;
 9789|  19.8k|  size_t i = 0;
 9790|       |
 9791|  31.6k|  for (; i + 7 < length; i += 8) {
  ------------------
  |  Branch (9791:10): [True: 11.7k, False: 19.8k]
  ------------------
 9792|  11.7k|    uint64_t word{};
 9793|  11.7k|    memcpy(&word, input + i, sizeof(word));
 9794|  11.7k|    non_ascii |= (word & broadcast_80);
 9795|  11.7k|    word ^=
 9796|  11.7k|        (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
 9797|  11.7k|    memcpy(input + i, &word, sizeof(word));
 9798|  11.7k|  }
 9799|  19.8k|  if (i < length) {
  ------------------
  |  Branch (9799:7): [True: 19.4k, False: 381]
  ------------------
 9800|  19.4k|    uint64_t word{};
 9801|  19.4k|    memcpy(&word, input + i, length - i);
 9802|  19.4k|    non_ascii |= (word & broadcast_80);
 9803|  19.4k|    word ^=
 9804|  19.4k|        (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
 9805|  19.4k|    memcpy(input + i, &word, length - i);
 9806|  19.4k|  }
 9807|  19.8k|  return non_ascii == 0;
 9808|  19.8k|}
_ZN3ada7unicode9broadcastEh:
 9780|  59.6k|constexpr uint64_t broadcast(uint8_t v) noexcept {
 9781|  59.6k|  return 0x101010101010101ull * v;
 9782|  59.6k|}
_ZN3ada8checkers7is_ipv4ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
    9|  13.9k|ada_really_inline ada_constexpr bool is_ipv4(std::string_view view) noexcept {
   10|  13.9k|  size_t last_dot = view.rfind('.');
   11|  13.9k|  if (last_dot == view.size() - 1) {
  ------------------
  |  Branch (11:7): [True: 1.72k, False: 12.2k]
  ------------------
   12|  1.72k|    view.remove_suffix(1);
   13|  1.72k|    last_dot = view.rfind('.');
   14|  1.72k|  }
   15|  13.9k|  std::string_view number =
   16|  13.9k|      (last_dot == std::string_view::npos) ? view : view.substr(last_dot + 1);
  ------------------
  |  Branch (16:7): [True: 11.1k, False: 2.84k]
  ------------------
   17|  13.9k|  if (number.empty()) {
  ------------------
  |  Branch (17:7): [True: 1.13k, False: 12.8k]
  ------------------
   18|  1.13k|    return false;
   19|  1.13k|  }
   20|       |  /** Optimization opportunity: we have basically identified the last number of
   21|       |     the ipv4 if we return true here. We might as well parse it and have at
   22|       |     least one number parsed when we get to parse_ipv4. */
   23|  12.8k|  if (std::all_of(number.begin(), number.end(), ada::checkers::is_digit)) {
  ------------------
  |  Branch (23:7): [True: 3.55k, False: 9.28k]
  ------------------
   24|  3.55k|    return true;
   25|  3.55k|  }
   26|  9.28k|  return (checkers::has_hex_prefix(number) &&
  ------------------
  |  Branch (26:11): [True: 1.65k, False: 7.63k]
  ------------------
   27|  9.28k|          std::all_of(number.begin() + 2, number.end(),
  ------------------
  |  Branch (27:11): [True: 959, False: 691]
  ------------------
   28|  1.65k|                      ada::unicode::is_lowercase_hex));
   29|  12.8k|}
_ZN3ada7unicode16is_lowercase_hexEc:
10128|  22.6k|ada_really_inline constexpr bool is_lowercase_hex(const char c) noexcept {
10129|  22.6k|  return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f');
  ------------------
  |  Branch (10129:11): [True: 22.4k, False: 183]
  |  Branch (10129:23): [True: 9.03k, False: 13.4k]
  |  Branch (10129:37): [True: 13.4k, False: 226]
  |  Branch (10129:49): [True: 12.9k, False: 465]
  ------------------
10130|  22.6k|}
_ZN3ada7unicode30is_forbidden_domain_code_pointEc:
 9948|   377k|    const char c) noexcept {
 9949|   377k|  return is_forbidden_domain_code_point_table[uint8_t(c)];
 9950|   377k|}
_ZN3ada7helpers6resizeERNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEm:
10594|      7|ada_really_inline void resize(std::string_view& input, size_t pos) noexcept {
10595|      7|  ADA_ASSERT_TRUE(pos <= input.size());
10596|      7|  input.remove_suffix(input.size() - pos);
10597|      7|}
_ZN3ada7unicode14percent_encodeILb1EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKhRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEE:
10203|  3.18k|                    std::string& out) {
10204|  3.18k|  ada_log("percent_encode ", input, " to output string while ",
10205|  3.18k|          append ? "appending" : "overwriting");
10206|  3.18k|  auto pointer =
10207|  3.18k|      std::find_if(input.begin(), input.end(), [character_set](const char c) {
10208|  3.18k|        return character_sets::bit_at(character_set, c);
10209|  3.18k|      });
10210|  3.18k|  ada_log("percent_encode done checking, moved to ",
10211|  3.18k|          std::distance(input.begin(), pointer));
10212|       |
10213|       |  // Optimization: Don't iterate if percent encode is not required
10214|  3.18k|  if (pointer == input.end()) {
  ------------------
  |  Branch (10214:7): [True: 2.24k, False: 947]
  ------------------
10215|  2.24k|    ada_log("percent_encode encoding not needed.");
10216|  2.24k|    return false;
10217|  2.24k|  }
10218|    947|  if (!append) {
  ------------------
  |  Branch (10218:7): [Folded - Ignored]
  ------------------
10219|      0|    out.clear();
10220|      0|  }
10221|    947|  ada_log("percent_encode appending ", std::distance(input.begin(), pointer),
10222|    947|          " bytes");
10223|    947|  out.append(input.data(), std::distance(input.begin(), pointer));
10224|    947|  ada_log("percent_encode processing ", std::distance(pointer, input.end()),
10225|    947|          " bytes");
10226|  41.5k|  for (; pointer != input.end(); pointer++) {
  ------------------
  |  Branch (10226:10): [True: 40.5k, False: 947]
  ------------------
10227|  40.5k|    if (character_sets::bit_at(character_set, *pointer)) {
  ------------------
  |  Branch (10227:9): [True: 30.1k, False: 10.3k]
  ------------------
10228|  30.1k|      out.append(character_sets::hex + uint8_t(*pointer) * 4, 3);
10229|  30.1k|    } else {
10230|  10.3k|      out += *pointer;
10231|  10.3k|    }
10232|  40.5k|  }
10233|    947|  return true;
10234|  3.18k|}
_ZZN3ada7unicode14percent_encodeILb1EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKhRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEEENKUlcE_clEc:
10207|  23.1k|      std::find_if(input.begin(), input.end(), [character_set](const char c) {
10208|  23.1k|        return character_sets::bit_at(character_set, c);
10209|  23.1k|      });
_ZN3ada7helpers12shorten_pathERNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEENS_6scheme4typeE:
10549|    232|                                    ada::scheme::type type) noexcept {
10550|    232|  size_t first_delimiter = path.find_first_of('/', 1);
10551|       |
10552|       |  // Let path be url's path.
10553|       |  // If url's scheme is "file", path's size is 1, and path[0] is a normalized
10554|       |  // Windows drive letter, then return.
10555|    232|  if (type == ada::scheme::type::FILE &&
  ------------------
  |  Branch (10555:7): [True: 64, False: 168]
  ------------------
10556|    232|      first_delimiter == std::string_view::npos && !path.empty()) {
  ------------------
  |  Branch (10556:7): [True: 46, False: 18]
  |  Branch (10556:52): [True: 46, False: 0]
  ------------------
10557|     46|    if (checkers::is_normalized_windows_drive_letter(
  ------------------
  |  Branch (10557:9): [True: 2, False: 44]
  ------------------
10558|     46|            helpers::substring(path, 1))) {
10559|      2|      return false;
10560|      2|    }
10561|     46|  }
10562|       |
10563|       |  // Remove path's last item, if any.
10564|    230|  if (!path.empty()) {
  ------------------
  |  Branch (10564:7): [True: 219, False: 11]
  ------------------
10565|    219|    size_t slash_loc = path.rfind('/');
10566|    219|    if (slash_loc != std::string_view::npos) {
  ------------------
  |  Branch (10566:9): [True: 197, False: 22]
  ------------------
10567|    197|      path.remove_suffix(path.size() - slash_loc);
10568|    197|      return true;
10569|    197|    }
10570|    219|  }
10571|       |
10572|     33|  return false;
10573|    230|}
_ZN3ada14url_aggregator11copy_schemeERKS0_:
13187|    576|inline void url_aggregator::copy_scheme(const url_aggregator& u) noexcept {
13188|    576|  ada_log("url_aggregator::copy_scheme ", u.buffer);
13189|    576|  ADA_ASSERT_TRUE(validate());
13190|       |  // next line could overflow but unsigned arithmetic has well-defined
13191|       |  // overflows.
13192|    576|  uint32_t new_difference = u.components.protocol_end - components.protocol_end;
13193|    576|  type = u.type;
13194|    576|  buffer.erase(0, components.protocol_end);
13195|    576|  buffer.insert(0, u.get_protocol());
13196|    576|  components.protocol_end = u.components.protocol_end;
13197|       |
13198|       |  // No need to update the components
13199|    576|  if (new_difference == 0) {
  ------------------
  |  Branch (13199:7): [True: 66, False: 510]
  ------------------
13200|     66|    return;
13201|     66|  }
13202|       |
13203|       |  // Update the rest of the components.
13204|    510|  components.username_end += new_difference;
13205|    510|  components.host_start += new_difference;
13206|    510|  components.host_end += new_difference;
13207|    510|  components.pathname_start += new_difference;
13208|    510|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (13208:7): [True: 0, False: 510]
  ------------------
13209|      0|    components.search_start += new_difference;
13210|      0|  }
13211|    510|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (13211:7): [True: 0, False: 510]
  ------------------
13212|      0|    components.hash_start += new_difference;
13213|      0|  }
13214|    510|  ADA_ASSERT_TRUE(validate());
13215|    510|}
_ZN3ada14url_aggregator10parse_pathENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13402|  4.97k|ada_really_inline void url_aggregator::parse_path(std::string_view input) {
13403|  4.97k|  ada_log("url_aggregator::parse_path ", input);
13404|  4.97k|  ADA_ASSERT_TRUE(validate());
13405|  4.97k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13406|  4.97k|  std::string tmp_buffer;
13407|  4.97k|  std::string_view internal_input;
13408|  4.97k|  if (unicode::has_tabs_or_newline(input)) {
  ------------------
  |  Branch (13408:7): [True: 85, False: 4.89k]
  ------------------
13409|     85|    tmp_buffer = input;
13410|       |    // Optimization opportunity: Instead of copying and then pruning, we could
13411|       |    // just directly build the string from user_input.
13412|     85|    helpers::remove_ascii_tab_or_newline(tmp_buffer);
13413|     85|    internal_input = tmp_buffer;
13414|  4.89k|  } else {
13415|  4.89k|    internal_input = input;
13416|  4.89k|  }
13417|       |
13418|       |  // If url is special, then:
13419|  4.97k|  if (is_special()) {
  ------------------
  |  Branch (13419:7): [True: 3.82k, False: 1.15k]
  ------------------
13420|  3.82k|    if (internal_input.empty()) {
  ------------------
  |  Branch (13420:9): [True: 3.13k, False: 685]
  ------------------
13421|  3.13k|      update_base_pathname("/");
13422|  3.13k|    } else if ((internal_input[0] == '/') || (internal_input[0] == '\\')) {
  ------------------
  |  Branch (13422:16): [True: 11, False: 674]
  |  Branch (13422:46): [True: 1, False: 673]
  ------------------
13423|     12|      consume_prepared_path(internal_input.substr(1));
13424|    673|    } else {
13425|    673|      consume_prepared_path(internal_input);
13426|    673|    }
13427|  3.82k|  } else if (!internal_input.empty()) {
  ------------------
  |  Branch (13427:14): [True: 255, False: 898]
  ------------------
13428|    255|    if (internal_input[0] == '/') {
  ------------------
  |  Branch (13428:9): [True: 19, False: 236]
  ------------------
13429|     19|      consume_prepared_path(internal_input.substr(1));
13430|    236|    } else {
13431|    236|      consume_prepared_path(internal_input);
13432|    236|    }
13433|    898|  } else {
13434|       |    // Non-special URLs with an empty host can have their paths erased
13435|       |    // Path-only URLs cannot have their paths erased
13436|    898|    if (components.host_start == components.host_end && !has_authority()) {
  ------------------
  |  Branch (13436:9): [True: 890, False: 8]
  |  Branch (13436:57): [True: 803, False: 87]
  ------------------
13437|    803|      update_base_pathname("/");
13438|    803|    }
13439|    898|  }
13440|  4.97k|  ADA_ASSERT_TRUE(validate());
13441|  4.97k|}
_ZN3ada14url_aggregator10parse_hostENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13500|  12.3k|ada_really_inline bool url_aggregator::parse_host(std::string_view input) {
13501|  12.3k|  ada_log("url_aggregator:parse_host ", input, "[", input.size(), " bytes]");
13502|  12.3k|  ADA_ASSERT_TRUE(validate());
13503|  12.3k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13504|  12.3k|  if (input.empty()) {
  ------------------
  |  Branch (13504:7): [True: 46, False: 12.2k]
  ------------------
13505|     46|    return is_valid = false;
13506|     46|  }  // technically unnecessary.
13507|       |  // If input starts with U+005B ([), then:
13508|  12.2k|  if (input[0] == '[') {
  ------------------
  |  Branch (13508:7): [True: 942, False: 11.3k]
  ------------------
13509|       |    // If input does not end with U+005D (]), validation error, return failure.
13510|    942|    if (input.back() != ']') {
  ------------------
  |  Branch (13510:9): [True: 285, False: 657]
  ------------------
13511|    285|      return is_valid = false;
13512|    285|    }
13513|    657|    ada_log("parse_host ipv6");
13514|       |
13515|       |    // Return the result of IPv6 parsing input with its leading U+005B ([) and
13516|       |    // trailing U+005D (]) removed.
13517|    657|    input.remove_prefix(1);
13518|    657|    input.remove_suffix(1);
13519|    657|    return parse_ipv6(input);
13520|    942|  }
13521|       |
13522|       |  // If isNotSpecial is true, then return the result of opaque-host parsing
13523|       |  // input.
13524|  11.3k|  if (!is_special()) {
  ------------------
  |  Branch (13524:7): [True: 775, False: 10.5k]
  ------------------
13525|    775|    return parse_opaque_host(input);
13526|    775|  }
13527|       |  // Let domain be the result of running UTF-8 decode without BOM on the
13528|       |  // percent-decoding of input. Let asciiDomain be the result of running domain
13529|       |  // to ASCII with domain and false. The most common case is an ASCII input, in
13530|       |  // which case we do not need to call the expensive 'to_ascii' if a few
13531|       |  // conditions are met: no '%' and no 'xn-' subsequence.
13532|       |
13533|       |  // Often, the input does not contain any forbidden code points, and no upper
13534|       |  // case ASCII letter, then we can just copy it to the buffer. We want to
13535|       |  // optimize for such a common case.
13536|  10.5k|  uint8_t is_forbidden_or_upper =
13537|  10.5k|      unicode::contains_forbidden_domain_code_point_or_upper(input.data(),
13538|  10.5k|                                                             input.size());
13539|       |  // Minor optimization opportunity:
13540|       |  // contains_forbidden_domain_code_point_or_upper could be extend to check for
13541|       |  // the presence of characters that cannot appear in the ipv4 address and we
13542|       |  // could also check whether x and n and - are present, and so we could skip
13543|       |  // some of the checks below. However, the gains are likely to be small, and
13544|       |  // the code would be more complex.
13545|  10.5k|  if (is_forbidden_or_upper == 0 &&
  ------------------
  |  Branch (13545:7): [True: 6.06k, False: 4.50k]
  ------------------
13546|  10.5k|      input.find("xn-") == std::string_view::npos) {
  ------------------
  |  Branch (13546:7): [True: 5.52k, False: 533]
  ------------------
13547|       |    // fast path
13548|  5.52k|    update_base_hostname(input);
13549|  5.52k|    if (checkers::is_ipv4(get_hostname())) {
  ------------------
  |  Branch (13549:9): [True: 2.36k, False: 3.16k]
  ------------------
13550|  2.36k|      ada_log("parse_host fast path ipv4");
13551|  2.36k|      return parse_ipv4(get_hostname());
13552|  2.36k|    }
13553|  3.16k|    ada_log("parse_host fast path ", get_hostname());
13554|  3.16k|    return true;
13555|  5.52k|  }
13556|       |  // We have encountered at least one forbidden code point or the input contains
13557|       |  // 'xn-' (case insensitive), so we need to call 'to_ascii' to perform the full
13558|       |  // conversion.
13559|       |
13560|  5.03k|  ada_log("parse_host calling to_ascii");
13561|  5.03k|  std::optional<std::string> host = std::string(get_hostname());
13562|  5.03k|  is_valid = ada::unicode::to_ascii(host, input, input.find('%'));
13563|  5.03k|  if (!is_valid) {
  ------------------
  |  Branch (13563:7): [True: 1.21k, False: 3.82k]
  ------------------
13564|  1.21k|    ada_log("parse_host to_ascii returns false");
13565|  1.21k|    return is_valid = false;
13566|  1.21k|  }
13567|       |
13568|  3.82k|  if (std::any_of(host.value().begin(), host.value().end(),
  ------------------
  |  Branch (13568:7): [True: 0, False: 3.82k]
  ------------------
13569|  3.82k|                  ada::unicode::is_forbidden_domain_code_point)) {
13570|      0|    return is_valid = false;
13571|      0|  }
13572|       |
13573|       |  // If asciiDomain ends in a number, then return the result of IPv4 parsing
13574|       |  // asciiDomain.
13575|  3.82k|  if (checkers::is_ipv4(host.value())) {
  ------------------
  |  Branch (13575:7): [True: 601, False: 3.22k]
  ------------------
13576|    601|    ada_log("parse_host got ipv4", *host);
13577|    601|    return parse_ipv4(host.value());
13578|    601|  }
13579|       |
13580|  3.22k|  update_base_hostname(host.value());
13581|  3.22k|  ADA_ASSERT_TRUE(validate());
13582|  3.22k|  return true;
13583|  3.82k|}
_ZN3ada7unicode45contains_forbidden_domain_code_point_or_upperEPKcm:
 9987|  10.5k|                                              size_t length) noexcept {
 9988|  10.5k|  size_t i = 0;
 9989|  10.5k|  uint8_t accumulator{};
 9990|  62.1k|  for (; i + 4 <= length; i += 4) {
  ------------------
  |  Branch (9990:10): [True: 51.5k, False: 10.5k]
  ------------------
 9991|  51.5k|    accumulator |=
 9992|  51.5k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i])];
 9993|  51.5k|    accumulator |=
 9994|  51.5k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 1])];
 9995|  51.5k|    accumulator |=
 9996|  51.5k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 2])];
 9997|  51.5k|    accumulator |=
 9998|  51.5k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 3])];
 9999|  51.5k|  }
10000|  25.5k|  for (; i < length; i++) {
  ------------------
  |  Branch (10000:10): [True: 15.0k, False: 10.5k]
  ------------------
10001|  15.0k|    accumulator |=
10002|  15.0k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i])];
10003|  15.0k|  }
10004|  10.5k|  return accumulator;
10005|  10.5k|}
_ZN3ada14url_aggregator21consume_prepared_pathENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
14617|  5.97k|inline void url_aggregator::consume_prepared_path(std::string_view input) {
14618|  5.97k|  ada_log("url_aggregator::consume_prepared_path ", input);
14619|       |  /***
14620|       |   * This is largely duplicated code from helpers::parse_prepared_path, which is
14621|       |   * unfortunate. This particular function is nearly identical, except that it
14622|       |   * is a method on url_aggregator. The idea is that the trivial path (which is
14623|       |   * very common) merely appends to the buffer. This is the same trivial path as
14624|       |   * with helpers::parse_prepared_path, except that we have the additional check
14625|       |   * for is_at_path(). Otherwise, we grab a copy of the current path and we
14626|       |   * modify it, and then insert it back into the buffer.
14627|       |   */
14628|  5.97k|  uint8_t accumulator = checkers::path_signature(input);
14629|       |  // Let us first detect a trivial case.
14630|       |  // If it is special, we check that we have no dot, no %,  no \ and no
14631|       |  // character needing percent encoding. Otherwise, we check that we have no %,
14632|       |  // no dot, and no character needing percent encoding.
14633|  5.97k|  constexpr uint8_t need_encoding = 1;
14634|  5.97k|  constexpr uint8_t backslash_char = 2;
14635|  5.97k|  constexpr uint8_t dot_char = 4;
14636|  5.97k|  constexpr uint8_t percent_char = 8;
14637|  5.97k|  bool special = type != ada::scheme::NOT_SPECIAL;
14638|  5.97k|  bool may_need_slow_file_handling = (type == ada::scheme::type::FILE &&
  ------------------
  |  Branch (14638:39): [True: 2.16k, False: 3.80k]
  ------------------
14639|  5.97k|                                      checkers::is_windows_drive_letter(input));
  ------------------
  |  Branch (14639:39): [True: 106, False: 2.06k]
  ------------------
14640|  5.97k|  bool trivial_path =
14641|  5.97k|      (special ? (accumulator == 0)
  ------------------
  |  Branch (14641:7): [True: 3.56k, False: 2.41k]
  |  Branch (14641:8): [True: 3.51k, False: 2.45k]
  ------------------
14642|  5.97k|               : ((accumulator & (need_encoding | dot_char | percent_char)) ==
14643|  2.45k|                  0)) &&
14644|  5.97k|      (!may_need_slow_file_handling);
  ------------------
  |  Branch (14644:7): [True: 3.50k, False: 56]
  ------------------
14645|  5.97k|  if (accumulator == dot_char && !may_need_slow_file_handling) {
  ------------------
  |  Branch (14645:7): [True: 792, False: 5.18k]
  |  Branch (14645:34): [True: 766, False: 26]
  ------------------
14646|       |    // '4' means that we have at least one dot, but nothing that requires
14647|       |    // percent encoding or decoding. The only part that is not trivial is
14648|       |    // that we may have single dots and double dots path segments.
14649|       |    // If we have such segments, then we either have a path that begins
14650|       |    // with '.' (easy to check), or we have the sequence './'.
14651|       |    // Note: input cannot be empty, it must at least contain one character ('.')
14652|       |    // Note: we know that '\' is not present.
14653|    766|    if (input[0] != '.') {
  ------------------
  |  Branch (14653:9): [True: 383, False: 383]
  ------------------
14654|    383|      size_t slashdot = input.find("/.");
14655|    383|      if (slashdot == std::string_view::npos) {  // common case
  ------------------
  |  Branch (14655:11): [True: 87, False: 296]
  ------------------
14656|     87|        trivial_path = true;
14657|    296|      } else {  // uncommon
14658|       |        // only three cases matter: /./, /.. or a final /
14659|    296|        trivial_path =
14660|    296|            !(slashdot + 2 == input.size() || input[slashdot + 2] == '.' ||
  ------------------
  |  Branch (14660:15): [True: 114, False: 182]
  |  Branch (14660:47): [True: 147, False: 35]
  ------------------
14661|    296|              input[slashdot + 2] == '/');
  ------------------
  |  Branch (14661:15): [True: 21, False: 14]
  ------------------
14662|    296|      }
14663|    383|    }
14664|    766|  }
14665|  5.97k|  if (trivial_path && is_at_path()) {
  ------------------
  |  Branch (14665:7): [True: 3.60k, False: 2.36k]
  |  Branch (14665:23): [True: 3.51k, False: 96]
  ------------------
14666|  3.51k|    ada_log("parse_path trivial");
14667|  3.51k|    buffer += '/';
14668|  3.51k|    buffer += input;
14669|  3.51k|    return;
14670|  3.51k|  }
14671|  2.46k|  std::string path = std::string(get_pathname());
14672|       |  // We are going to need to look a bit at the path, but let us see if we can
14673|       |  // ignore percent encoding *and* backslashes *and* percent characters.
14674|       |  // Except for the trivial case, this is likely to capture 99% of paths out
14675|       |  // there.
14676|  2.46k|  bool fast_path =
14677|  2.46k|      (special &&
  ------------------
  |  Branch (14677:8): [True: 1.56k, False: 900]
  ------------------
14678|  2.46k|       (accumulator & (need_encoding | backslash_char | percent_char)) == 0) &&
  ------------------
  |  Branch (14678:8): [True: 642, False: 922]
  ------------------
14679|  2.46k|      (type != ada::scheme::type::FILE);
  ------------------
  |  Branch (14679:7): [True: 427, False: 215]
  ------------------
14680|  2.46k|  if (fast_path) {
  ------------------
  |  Branch (14680:7): [True: 427, False: 2.03k]
  ------------------
14681|    427|    ada_log("parse_prepared_path fast");
14682|       |    // Here we don't need to worry about \ or percent encoding.
14683|       |    // We also do not have a file protocol. We might have dots, however,
14684|       |    // but dots must as appear as '.', and they cannot be encoded because
14685|       |    // the symbol '%' is not present.
14686|    427|    size_t previous_location = 0;  // We start at 0.
14687|  3.37k|    do {
14688|  3.37k|      size_t new_location = input.find('/', previous_location);
14689|       |      // std::string_view path_view = input;
14690|       |      //  We process the last segment separately:
14691|  3.37k|      if (new_location == std::string_view::npos) {
  ------------------
  |  Branch (14691:11): [True: 427, False: 2.95k]
  ------------------
14692|    427|        std::string_view path_view = input.substr(previous_location);
14693|    427|        if (path_view == "..") {  // The path ends with ..
  ------------------
  |  Branch (14693:13): [True: 69, False: 358]
  ------------------
14694|       |          // e.g., if you receive ".." with an empty path, you go to "/".
14695|     69|          if (path.empty()) {
  ------------------
  |  Branch (14695:15): [True: 24, False: 45]
  ------------------
14696|     24|            path = '/';
14697|     24|            update_base_pathname(path);
14698|     24|            return;
14699|     24|          }
14700|       |          // Fast case where we have nothing to do:
14701|     45|          if (path.back() == '/') {
  ------------------
  |  Branch (14701:15): [True: 17, False: 28]
  ------------------
14702|     17|            update_base_pathname(path);
14703|     17|            return;
14704|     17|          }
14705|       |          // If you have the path "/joe/myfriend",
14706|       |          // then you delete 'myfriend'.
14707|     28|          path.resize(path.rfind('/') + 1);
14708|     28|          update_base_pathname(path);
14709|     28|          return;
14710|     45|        }
14711|    358|        path += '/';
14712|    358|        if (path_view != ".") {
  ------------------
  |  Branch (14712:13): [True: 267, False: 91]
  ------------------
14713|    267|          path.append(path_view);
14714|    267|        }
14715|    358|        update_base_pathname(path);
14716|    358|        return;
14717|  2.95k|      } else {
14718|       |        // This is a non-final segment.
14719|  2.95k|        std::string_view path_view =
14720|  2.95k|            input.substr(previous_location, new_location - previous_location);
14721|  2.95k|        previous_location = new_location + 1;
14722|  2.95k|        if (path_view == "..") {
  ------------------
  |  Branch (14722:13): [True: 662, False: 2.28k]
  ------------------
14723|    662|          size_t last_delimiter = path.rfind('/');
14724|    662|          if (last_delimiter != std::string::npos) {
  ------------------
  |  Branch (14724:15): [True: 344, False: 318]
  ------------------
14725|    344|            path.erase(last_delimiter);
14726|    344|          }
14727|  2.28k|        } else if (path_view != ".") {
  ------------------
  |  Branch (14727:20): [True: 2.10k, False: 188]
  ------------------
14728|  2.10k|          path += '/';
14729|  2.10k|          path.append(path_view);
14730|  2.10k|        }
14731|  2.95k|      }
14732|  3.37k|    } while (true);
  ------------------
  |  Branch (14732:14): [Folded - Ignored]
  ------------------
14733|  2.03k|  } else {
14734|  2.03k|    ada_log("parse_path slow");
14735|       |    // we have reached the general case
14736|  2.03k|    bool needs_percent_encoding = (accumulator & 1);
14737|  2.03k|    std::string path_buffer_tmp;
14738|  15.8k|    do {
14739|  15.8k|      size_t location = (special && (accumulator & 2))
  ------------------
  |  Branch (14739:26): [True: 9.68k, False: 6.13k]
  |  Branch (14739:37): [True: 1.65k, False: 8.02k]
  ------------------
14740|  15.8k|                            ? input.find_first_of("/\\")
14741|  15.8k|                            : input.find('/');
14742|  15.8k|      std::string_view path_view = input;
14743|  15.8k|      if (location != std::string_view::npos) {
  ------------------
  |  Branch (14743:11): [True: 13.7k, False: 2.03k]
  ------------------
14744|  13.7k|        path_view.remove_suffix(path_view.size() - location);
14745|  13.7k|        input.remove_prefix(location + 1);
14746|  13.7k|      }
14747|       |      // path_buffer is either path_view or it might point at a percent encoded
14748|       |      // temporary string.
14749|  15.8k|      std::string_view path_buffer =
14750|  15.8k|          (needs_percent_encoding &&
  ------------------
  |  Branch (14750:12): [True: 9.83k, False: 5.97k]
  ------------------
14751|  15.8k|           ada::unicode::percent_encode<false>(
  ------------------
  |  Branch (14751:12): [True: 4.05k, False: 5.78k]
  ------------------
14752|  9.83k|               path_view, character_sets::PATH_PERCENT_ENCODE, path_buffer_tmp))
14753|  15.8k|              ? path_buffer_tmp
14754|  15.8k|              : path_view;
14755|  15.8k|      if (unicode::is_double_dot_path_segment(path_buffer)) {
  ------------------
  |  Branch (14755:11): [True: 3.61k, False: 12.2k]
  ------------------
14756|  3.61k|        if ((helpers::shorten_path(path, type) || special) &&
  ------------------
  |  Branch (14756:14): [True: 1.78k, False: 1.82k]
  |  Branch (14756:51): [True: 1.44k, False: 382]
  ------------------
14757|  3.61k|            location == std::string_view::npos) {
  ------------------
  |  Branch (14757:13): [True: 209, False: 3.01k]
  ------------------
14758|    209|          path += '/';
14759|    209|        }
14760|  12.2k|      } else if (unicode::is_single_dot_path_segment(path_buffer) &&
  ------------------
  |  Branch (14760:18): [True: 852, False: 11.3k]
  ------------------
14761|  12.2k|                 (location == std::string_view::npos)) {
  ------------------
  |  Branch (14761:18): [True: 106, False: 746]
  ------------------
14762|    106|        path += '/';
14763|    106|      }
14764|       |      // Otherwise, if path_buffer is not a single-dot path segment, then:
14765|  12.1k|      else if (!unicode::is_single_dot_path_segment(path_buffer)) {
  ------------------
  |  Branch (14765:16): [True: 11.3k, False: 746]
  ------------------
14766|       |        // If url's scheme is "file", url's path is empty, and path_buffer is a
14767|       |        // Windows drive letter, then replace the second code point in
14768|       |        // path_buffer with U+003A (:).
14769|  11.3k|        if (type == ada::scheme::type::FILE && path.empty() &&
  ------------------
  |  Branch (14769:13): [True: 3.68k, False: 7.67k]
  |  Branch (14769:48): [True: 1.89k, False: 1.78k]
  ------------------
14770|  11.3k|            checkers::is_windows_drive_letter(path_buffer)) {
  ------------------
  |  Branch (14770:13): [True: 108, False: 1.78k]
  ------------------
14771|    108|          path += '/';
14772|    108|          path += path_buffer[0];
14773|    108|          path += ':';
14774|    108|          path_buffer.remove_prefix(2);
14775|    108|          path.append(path_buffer);
14776|  11.2k|        } else {
14777|       |          // Append path_buffer to url's path.
14778|  11.2k|          path += '/';
14779|  11.2k|          path.append(path_buffer);
14780|  11.2k|        }
14781|  11.3k|      }
14782|  15.8k|      if (location == std::string_view::npos) {
  ------------------
  |  Branch (14782:11): [True: 2.03k, False: 13.7k]
  ------------------
14783|  2.03k|        update_base_pathname(path);
14784|  2.03k|        return;
14785|  2.03k|      }
14786|  15.8k|    } while (true);
  ------------------
  |  Branch (14786:14): [Folded - Ignored]
  ------------------
14787|  2.03k|  }
14788|  2.46k|}
parse.cc:_ZZN3ada4idna22utf32_length_from_utf8EPKcmENK3$_0clEa:
  241|   229k|  return std::count_if(p, std::next(p, len), [](int8_t c) {
  242|       |    // -65 is 0b10111111, anything larger in two-complement's
  243|       |    // should start a new code point.
  244|   229k|    return c > -65;
  245|   229k|  });
parse.cc:_ZZN3ada4idna14is_label_validENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEEENK3$_3clEj:
 9373|  1.30k|      auto is_l_or_d = [](uint32_t code) {
 9374|  1.30k|        return std::binary_search(std::begin(L), std::end(L), code) ||
  ------------------
  |  Branch (9374:16): [True: 60, False: 1.24k]
  ------------------
 9375|  1.30k|               std::binary_search(std::begin(D), std::end(D), code);
  ------------------
  |  Branch (9375:16): [True: 580, False: 666]
  ------------------
 9376|  1.30k|      };
parse.cc:_ZZN3ada4idna14is_label_validENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEEENK3$_4clEj:
 9377|  1.51k|      auto is_r_or_d = [](uint32_t code) {
 9378|  1.51k|        return std::binary_search(std::begin(R), std::end(R), code) ||
  ------------------
  |  Branch (9378:16): [True: 322, False: 1.19k]
  ------------------
 9379|  1.51k|               std::binary_search(std::begin(D), std::end(D), code);
  ------------------
  |  Branch (9379:16): [True: 191, False: 1.00k]
  ------------------
 9380|  1.51k|      };
parse.cc:_ZZN3ada7unicode14percent_encodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKhENK3$_5clEc:
10177|   202k|      std::find_if(input.begin(), input.end(), [character_set](const char c) {
10178|   202k|        return character_sets::bit_at(character_set, c);
10179|   202k|      });
_ZN3ada3url20set_host_or_hostnameILb0EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE:
11823|  5.68k|bool url::set_host_or_hostname(const std::string_view input) {
11824|  5.68k|  if (has_opaque_path) {
  ------------------
  |  Branch (11824:7): [True: 709, False: 4.97k]
  ------------------
11825|    709|    return false;
11826|    709|  }
11827|       |
11828|  4.97k|  std::optional<std::string> previous_host = host;
11829|  4.97k|  std::optional<uint16_t> previous_port = port;
11830|       |
11831|  4.97k|  size_t host_end_pos = input.find('#');
11832|  4.97k|  std::string _host(input.data(), host_end_pos != std::string_view::npos
  ------------------
  |  Branch (11832:35): [True: 32, False: 4.94k]
  ------------------
11833|  4.97k|                                      ? host_end_pos
11834|  4.97k|                                      : input.size());
11835|  4.97k|  helpers::remove_ascii_tab_or_newline(_host);
11836|  4.97k|  std::string_view new_host(_host);
11837|       |
11838|       |  // If url's scheme is "file", then set state to file host state, instead of
11839|       |  // host state.
11840|  4.97k|  if (type != ada::scheme::type::FILE) {
  ------------------
  |  Branch (11840:7): [True: 3.94k, False: 1.03k]
  ------------------
11841|  3.94k|    std::string_view host_view(_host.data(), _host.length());
11842|  3.94k|    auto [location, found_colon] =
11843|  3.94k|        helpers::get_host_delimiter_location(is_special(), host_view);
11844|       |
11845|       |    // Otherwise, if c is U+003A (:) and insideBrackets is false, then:
11846|       |    // Note: the 'found_colon' value is true if and only if a colon was
11847|       |    // encountered while not inside brackets.
11848|  3.94k|    if (found_colon) {
  ------------------
  |  Branch (11848:9): [True: 81, False: 3.86k]
  ------------------
11849|     81|      if (override_hostname) {
  ------------------
  |  Branch (11849:11): [Folded - Ignored]
  ------------------
11850|      0|        return false;
11851|      0|      }
11852|     81|      std::string_view buffer = new_host.substr(location + 1);
11853|     81|      if (!buffer.empty()) {
  ------------------
  |  Branch (11853:11): [True: 72, False: 9]
  ------------------
11854|     72|        set_port(buffer);
11855|     72|      }
11856|     81|    }
11857|       |    // If url is special and host_view is the empty string, validation error,
11858|       |    // return failure. Otherwise, if state override is given, host_view is the
11859|       |    // empty string, and either url includes credentials or url's port is
11860|       |    // non-null, return.
11861|  3.86k|    else if (host_view.empty() &&
  ------------------
  |  Branch (11861:14): [True: 2.87k, False: 982]
  ------------------
11862|  3.86k|             (is_special() || has_credentials() || port.has_value())) {
  ------------------
  |  Branch (11862:15): [True: 2.07k, False: 807]
  |  Branch (11862:31): [True: 5, False: 802]
  |  Branch (11862:52): [True: 47, False: 755]
  ------------------
11863|  2.12k|      return false;
11864|  2.12k|    }
11865|       |
11866|       |    // Let host be the result of host parsing host_view with url is not special.
11867|  1.81k|    if (host_view.empty() && !is_special()) {
  ------------------
  |  Branch (11867:9): [True: 787, False: 1.03k]
  |  Branch (11867:30): [True: 767, False: 20]
  ------------------
11868|    767|      host = "";
11869|    767|      return true;
11870|    767|    }
11871|       |
11872|  1.05k|    bool succeeded = parse_host(host_view);
11873|  1.05k|    if (!succeeded) {
  ------------------
  |  Branch (11873:9): [True: 374, False: 677]
  ------------------
11874|    374|      host = previous_host;
11875|    374|      update_base_port(previous_port);
11876|    374|    }
11877|  1.05k|    return succeeded;
11878|  1.81k|  }
11879|       |
11880|  1.03k|  size_t location = new_host.find_first_of("/\\?");
11881|  1.03k|  if (location != std::string_view::npos) {
  ------------------
  |  Branch (11881:7): [True: 191, False: 844]
  ------------------
11882|    191|    new_host.remove_suffix(new_host.length() - location);
11883|    191|  }
11884|       |
11885|  1.03k|  if (new_host.empty()) {
  ------------------
  |  Branch (11885:7): [True: 710, False: 325]
  ------------------
11886|       |    // Set url's host to the empty string.
11887|    710|    host = "";
11888|    710|  } else {
11889|       |    // Let host be the result of host parsing buffer with url is not special.
11890|    325|    if (!parse_host(new_host)) {
  ------------------
  |  Branch (11890:9): [True: 132, False: 193]
  ------------------
11891|    132|      host = previous_host;
11892|    132|      update_base_port(previous_port);
11893|    132|      return false;
11894|    132|    }
11895|       |
11896|       |    // If host is "localhost", then set host to the empty string.
11897|    193|    if (host.has_value() && host.value() == "localhost") {
  ------------------
  |  Branch (11897:9): [True: 193, False: 0]
  |  Branch (11897:29): [True: 1, False: 192]
  ------------------
11898|      1|      host = "";
11899|      1|    }
11900|    193|  }
11901|    903|  return true;
11902|  1.03k|}
_ZN3ada3url20set_host_or_hostnameILb1EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE:
11823|  5.68k|bool url::set_host_or_hostname(const std::string_view input) {
11824|  5.68k|  if (has_opaque_path) {
  ------------------
  |  Branch (11824:7): [True: 709, False: 4.97k]
  ------------------
11825|    709|    return false;
11826|    709|  }
11827|       |
11828|  4.97k|  std::optional<std::string> previous_host = host;
11829|  4.97k|  std::optional<uint16_t> previous_port = port;
11830|       |
11831|  4.97k|  size_t host_end_pos = input.find('#');
11832|  4.97k|  std::string _host(input.data(), host_end_pos != std::string_view::npos
  ------------------
  |  Branch (11832:35): [True: 32, False: 4.94k]
  ------------------
11833|  4.97k|                                      ? host_end_pos
11834|  4.97k|                                      : input.size());
11835|  4.97k|  helpers::remove_ascii_tab_or_newline(_host);
11836|  4.97k|  std::string_view new_host(_host);
11837|       |
11838|       |  // If url's scheme is "file", then set state to file host state, instead of
11839|       |  // host state.
11840|  4.97k|  if (type != ada::scheme::type::FILE) {
  ------------------
  |  Branch (11840:7): [True: 3.94k, False: 1.03k]
  ------------------
11841|  3.94k|    std::string_view host_view(_host.data(), _host.length());
11842|  3.94k|    auto [location, found_colon] =
11843|  3.94k|        helpers::get_host_delimiter_location(is_special(), host_view);
11844|       |
11845|       |    // Otherwise, if c is U+003A (:) and insideBrackets is false, then:
11846|       |    // Note: the 'found_colon' value is true if and only if a colon was
11847|       |    // encountered while not inside brackets.
11848|  3.94k|    if (found_colon) {
  ------------------
  |  Branch (11848:9): [True: 81, False: 3.86k]
  ------------------
11849|     81|      if (override_hostname) {
  ------------------
  |  Branch (11849:11): [Folded - Ignored]
  ------------------
11850|     81|        return false;
11851|     81|      }
11852|      0|      std::string_view buffer = new_host.substr(location + 1);
11853|      0|      if (!buffer.empty()) {
  ------------------
  |  Branch (11853:11): [True: 0, False: 0]
  ------------------
11854|      0|        set_port(buffer);
11855|      0|      }
11856|      0|    }
11857|       |    // If url is special and host_view is the empty string, validation error,
11858|       |    // return failure. Otherwise, if state override is given, host_view is the
11859|       |    // empty string, and either url includes credentials or url's port is
11860|       |    // non-null, return.
11861|  3.86k|    else if (host_view.empty() &&
  ------------------
  |  Branch (11861:14): [True: 2.87k, False: 982]
  ------------------
11862|  3.86k|             (is_special() || has_credentials() || port.has_value())) {
  ------------------
  |  Branch (11862:15): [True: 2.07k, False: 807]
  |  Branch (11862:31): [True: 5, False: 802]
  |  Branch (11862:52): [True: 47, False: 755]
  ------------------
11863|  2.12k|      return false;
11864|  2.12k|    }
11865|       |
11866|       |    // Let host be the result of host parsing host_view with url is not special.
11867|  1.73k|    if (host_view.empty() && !is_special()) {
  ------------------
  |  Branch (11867:9): [True: 755, False: 982]
  |  Branch (11867:30): [True: 755, False: 0]
  ------------------
11868|    755|      host = "";
11869|    755|      return true;
11870|    755|    }
11871|       |
11872|    982|    bool succeeded = parse_host(host_view);
11873|    982|    if (!succeeded) {
  ------------------
  |  Branch (11873:9): [True: 345, False: 637]
  ------------------
11874|    345|      host = previous_host;
11875|    345|      update_base_port(previous_port);
11876|    345|    }
11877|    982|    return succeeded;
11878|  1.73k|  }
11879|       |
11880|  1.03k|  size_t location = new_host.find_first_of("/\\?");
11881|  1.03k|  if (location != std::string_view::npos) {
  ------------------
  |  Branch (11881:7): [True: 191, False: 844]
  ------------------
11882|    191|    new_host.remove_suffix(new_host.length() - location);
11883|    191|  }
11884|       |
11885|  1.03k|  if (new_host.empty()) {
  ------------------
  |  Branch (11885:7): [True: 710, False: 325]
  ------------------
11886|       |    // Set url's host to the empty string.
11887|    710|    host = "";
11888|    710|  } else {
11889|       |    // Let host be the result of host parsing buffer with url is not special.
11890|    325|    if (!parse_host(new_host)) {
  ------------------
  |  Branch (11890:9): [True: 132, False: 193]
  ------------------
11891|    132|      host = previous_host;
11892|    132|      update_base_port(previous_port);
11893|    132|      return false;
11894|    132|    }
11895|       |
11896|       |    // If host is "localhost", then set host to the empty string.
11897|    193|    if (host.has_value() && host.value() == "localhost") {
  ------------------
  |  Branch (11897:9): [True: 193, False: 0]
  |  Branch (11897:29): [True: 1, False: 192]
  ------------------
11898|      1|      host = "";
11899|      1|    }
11900|    193|  }
11901|    903|  return true;
11902|  1.03k|}
_ZN3ada7helpers38strip_trailing_spaces_from_opaque_pathINS_3urlEEEvRT_:
11009|  7.24k|    url_type& url) noexcept {
11010|  7.24k|  ada_log("helpers::strip_trailing_spaces_from_opaque_path");
11011|  7.24k|  if (!url.has_opaque_path) return;
  ------------------
  |  Branch (11011:7): [True: 6.06k, False: 1.18k]
  ------------------
11012|  1.18k|  if (url.has_hash()) return;
  ------------------
  |  Branch (11012:7): [True: 63, False: 1.12k]
  ------------------
11013|  1.12k|  if (url.has_search()) return;
  ------------------
  |  Branch (11013:7): [True: 0, False: 1.12k]
  ------------------
11014|       |
11015|  1.12k|  auto path = std::string(url.get_pathname());
11016|  1.71k|  while (!path.empty() && path.back() == ' ') {
  ------------------
  |  Branch (11016:10): [True: 1.24k, False: 474]
  |  Branch (11016:27): [True: 590, False: 651]
  ------------------
11017|    590|    path.resize(path.size() - 1);
11018|    590|  }
11019|  1.12k|  url.update_base_pathname(path);
11020|  1.12k|}
_ZN3ada3url12parse_schemeILb1EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE:
11455|    222|ada_really_inline bool url::parse_scheme(const std::string_view input) {
11456|    222|  auto parsed_type = ada::scheme::get_scheme_type(input);
11457|    222|  bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL);
11458|       |  /**
11459|       |   * In the common case, we will immediately recognize a special scheme (e.g.,
11460|       |   *http, https), in which case, we can go really fast.
11461|       |   **/
11462|    222|  if (is_input_special) {  // fast path!!!
  ------------------
  |  Branch (11462:7): [True: 26, False: 196]
  ------------------
11463|     26|    if (has_state_override) {
  ------------------
  |  Branch (11463:9): [Folded - Ignored]
  ------------------
11464|       |      // If url's scheme is not a special scheme and buffer is a special scheme,
11465|       |      // then return.
11466|     26|      if (is_special() != is_input_special) {
  ------------------
  |  Branch (11466:11): [True: 2, False: 24]
  ------------------
11467|      2|        return true;
11468|      2|      }
11469|       |
11470|       |      // If url includes credentials or has a non-null port, and buffer is
11471|       |      // "file", then return.
11472|     24|      if ((has_credentials() || port.has_value()) &&
  ------------------
  |  Branch (11472:12): [True: 4, False: 20]
  |  Branch (11472:33): [True: 3, False: 17]
  ------------------
11473|     24|          parsed_type == ada::scheme::type::FILE) {
  ------------------
  |  Branch (11473:11): [True: 1, False: 6]
  ------------------
11474|      1|        return true;
11475|      1|      }
11476|       |
11477|       |      // If url's scheme is "file" and its host is an empty host, then return.
11478|       |      // An empty host is the empty string.
11479|     23|      if (type == ada::scheme::type::FILE && host.has_value() &&
  ------------------
  |  Branch (11479:11): [True: 5, False: 18]
  |  Branch (11479:46): [True: 5, False: 0]
  ------------------
11480|     23|          host.value().empty()) {
  ------------------
  |  Branch (11480:11): [True: 3, False: 2]
  ------------------
11481|      3|        return true;
11482|      3|      }
11483|     23|    }
11484|       |
11485|     20|    type = parsed_type;
11486|       |
11487|     20|    if (has_state_override) {
  ------------------
  |  Branch (11487:9): [Folded - Ignored]
  ------------------
11488|       |      // This is uncommon.
11489|     20|      uint16_t urls_scheme_port = get_special_port();
11490|       |
11491|     20|      if (urls_scheme_port) {
  ------------------
  |  Branch (11491:11): [True: 11, False: 9]
  ------------------
11492|       |        // If url's port is url's scheme's default port, then set url's port to
11493|       |        // null.
11494|     11|        if (port.has_value() && *port == urls_scheme_port) {
  ------------------
  |  Branch (11494:13): [True: 2, False: 9]
  |  Branch (11494:33): [True: 1, False: 1]
  ------------------
11495|      1|          port = std::nullopt;
11496|      1|        }
11497|     11|      }
11498|     20|    }
11499|    196|  } else {  // slow path
11500|    196|    std::string _buffer = std::string(input);
11501|       |    // Next function is only valid if the input is ASCII and returns false
11502|       |    // otherwise, but it seems that we always have ascii content so we do not
11503|       |    // need to check the return value.
11504|       |    // bool is_ascii =
11505|    196|    unicode::to_lower_ascii(_buffer.data(), _buffer.size());
11506|       |
11507|    196|    if (has_state_override) {
  ------------------
  |  Branch (11507:9): [Folded - Ignored]
  ------------------
11508|       |      // If url's scheme is a special scheme and buffer is not a special scheme,
11509|       |      // then return. If url's scheme is not a special scheme and buffer is a
11510|       |      // special scheme, then return.
11511|    196|      if (is_special() != ada::scheme::is_special(_buffer)) {
  ------------------
  |  Branch (11511:11): [True: 91, False: 105]
  ------------------
11512|     91|        return true;
11513|     91|      }
11514|       |
11515|       |      // If url includes credentials or has a non-null port, and buffer is
11516|       |      // "file", then return.
11517|    105|      if ((has_credentials() || port.has_value()) && _buffer == "file") {
  ------------------
  |  Branch (11517:12): [True: 4, False: 101]
  |  Branch (11517:33): [True: 13, False: 88]
  |  Branch (11517:54): [True: 1, False: 16]
  ------------------
11518|      1|        return true;
11519|      1|      }
11520|       |
11521|       |      // If url's scheme is "file" and its host is an empty host, then return.
11522|       |      // An empty host is the empty string.
11523|    104|      if (type == ada::scheme::type::FILE && host.has_value() &&
  ------------------
  |  Branch (11523:11): [True: 3, False: 101]
  |  Branch (11523:46): [True: 3, False: 0]
  ------------------
11524|    104|          host.value().empty()) {
  ------------------
  |  Branch (11524:11): [True: 1, False: 2]
  ------------------
11525|      1|        return true;
11526|      1|      }
11527|    104|    }
11528|       |
11529|    103|    set_scheme(std::move(_buffer));
11530|       |
11531|    103|    if (has_state_override) {
  ------------------
  |  Branch (11531:9): [Folded - Ignored]
  ------------------
11532|       |      // This is uncommon.
11533|    103|      uint16_t urls_scheme_port = get_special_port();
11534|       |
11535|    103|      if (urls_scheme_port) {
  ------------------
  |  Branch (11535:11): [True: 17, False: 86]
  ------------------
11536|       |        // If url's port is url's scheme's default port, then set url's port to
11537|       |        // null.
11538|     17|        if (port.has_value() && *port == urls_scheme_port) {
  ------------------
  |  Branch (11538:13): [True: 12, False: 5]
  |  Branch (11538:33): [True: 1, False: 11]
  ------------------
11539|      1|          port = std::nullopt;
11540|      1|        }
11541|     17|      }
11542|    103|    }
11543|    103|  }
11544|       |
11545|    123|  return true;
11546|    222|}
_ZN3ada3url12parse_schemeILb0EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE:
11455|  6.97k|ada_really_inline bool url::parse_scheme(const std::string_view input) {
11456|  6.97k|  auto parsed_type = ada::scheme::get_scheme_type(input);
11457|  6.97k|  bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL);
11458|       |  /**
11459|       |   * In the common case, we will immediately recognize a special scheme (e.g.,
11460|       |   *http, https), in which case, we can go really fast.
11461|       |   **/
11462|  6.97k|  if (is_input_special) {  // fast path!!!
  ------------------
  |  Branch (11462:7): [True: 2.90k, False: 4.06k]
  ------------------
11463|  2.90k|    if (has_state_override) {
  ------------------
  |  Branch (11463:9): [Folded - Ignored]
  ------------------
11464|       |      // If url's scheme is not a special scheme and buffer is a special scheme,
11465|       |      // then return.
11466|      0|      if (is_special() != is_input_special) {
  ------------------
  |  Branch (11466:11): [True: 0, False: 0]
  ------------------
11467|      0|        return true;
11468|      0|      }
11469|       |
11470|       |      // If url includes credentials or has a non-null port, and buffer is
11471|       |      // "file", then return.
11472|      0|      if ((has_credentials() || port.has_value()) &&
  ------------------
  |  Branch (11472:12): [True: 0, False: 0]
  |  Branch (11472:33): [True: 0, False: 0]
  ------------------
11473|      0|          parsed_type == ada::scheme::type::FILE) {
  ------------------
  |  Branch (11473:11): [True: 0, False: 0]
  ------------------
11474|      0|        return true;
11475|      0|      }
11476|       |
11477|       |      // If url's scheme is "file" and its host is an empty host, then return.
11478|       |      // An empty host is the empty string.
11479|      0|      if (type == ada::scheme::type::FILE && host.has_value() &&
  ------------------
  |  Branch (11479:11): [True: 0, False: 0]
  |  Branch (11479:46): [True: 0, False: 0]
  ------------------
11480|      0|          host.value().empty()) {
  ------------------
  |  Branch (11480:11): [True: 0, False: 0]
  ------------------
11481|      0|        return true;
11482|      0|      }
11483|      0|    }
11484|       |
11485|  2.90k|    type = parsed_type;
11486|       |
11487|  2.90k|    if (has_state_override) {
  ------------------
  |  Branch (11487:9): [Folded - Ignored]
  ------------------
11488|       |      // This is uncommon.
11489|      0|      uint16_t urls_scheme_port = get_special_port();
11490|       |
11491|      0|      if (urls_scheme_port) {
  ------------------
  |  Branch (11491:11): [True: 0, False: 0]
  ------------------
11492|       |        // If url's port is url's scheme's default port, then set url's port to
11493|       |        // null.
11494|      0|        if (port.has_value() && *port == urls_scheme_port) {
  ------------------
  |  Branch (11494:13): [True: 0, False: 0]
  |  Branch (11494:33): [True: 0, False: 0]
  ------------------
11495|      0|          port = std::nullopt;
11496|      0|        }
11497|      0|      }
11498|      0|    }
11499|  4.06k|  } else {  // slow path
11500|  4.06k|    std::string _buffer = std::string(input);
11501|       |    // Next function is only valid if the input is ASCII and returns false
11502|       |    // otherwise, but it seems that we always have ascii content so we do not
11503|       |    // need to check the return value.
11504|       |    // bool is_ascii =
11505|  4.06k|    unicode::to_lower_ascii(_buffer.data(), _buffer.size());
11506|       |
11507|  4.06k|    if (has_state_override) {
  ------------------
  |  Branch (11507:9): [Folded - Ignored]
  ------------------
11508|       |      // If url's scheme is a special scheme and buffer is not a special scheme,
11509|       |      // then return. If url's scheme is not a special scheme and buffer is a
11510|       |      // special scheme, then return.
11511|      0|      if (is_special() != ada::scheme::is_special(_buffer)) {
  ------------------
  |  Branch (11511:11): [True: 0, False: 0]
  ------------------
11512|      0|        return true;
11513|      0|      }
11514|       |
11515|       |      // If url includes credentials or has a non-null port, and buffer is
11516|       |      // "file", then return.
11517|      0|      if ((has_credentials() || port.has_value()) && _buffer == "file") {
  ------------------
  |  Branch (11517:12): [True: 0, False: 0]
  |  Branch (11517:33): [True: 0, False: 0]
  |  Branch (11517:54): [True: 0, False: 0]
  ------------------
11518|      0|        return true;
11519|      0|      }
11520|       |
11521|       |      // If url's scheme is "file" and its host is an empty host, then return.
11522|       |      // An empty host is the empty string.
11523|      0|      if (type == ada::scheme::type::FILE && host.has_value() &&
  ------------------
  |  Branch (11523:11): [True: 0, False: 0]
  |  Branch (11523:46): [True: 0, False: 0]
  ------------------
11524|      0|          host.value().empty()) {
  ------------------
  |  Branch (11524:11): [True: 0, False: 0]
  ------------------
11525|      0|        return true;
11526|      0|      }
11527|      0|    }
11528|       |
11529|  4.06k|    set_scheme(std::move(_buffer));
11530|       |
11531|  4.06k|    if (has_state_override) {
  ------------------
  |  Branch (11531:9): [Folded - Ignored]
  ------------------
11532|       |      // This is uncommon.
11533|      0|      uint16_t urls_scheme_port = get_special_port();
11534|       |
11535|      0|      if (urls_scheme_port) {
  ------------------
  |  Branch (11535:11): [True: 0, False: 0]
  ------------------
11536|       |        // If url's port is url's scheme's default port, then set url's port to
11537|       |        // null.
11538|      0|        if (port.has_value() && *port == urls_scheme_port) {
  ------------------
  |  Branch (11538:13): [True: 0, False: 0]
  |  Branch (11538:33): [True: 0, False: 0]
  ------------------
11539|      0|          port = std::nullopt;
11540|      0|        }
11541|      0|      }
11542|      0|    }
11543|  4.06k|  }
11544|       |
11545|  6.97k|  return true;
11546|  6.97k|}
_ZN3ada14url_aggregator23parse_scheme_with_colonILb0EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE:
13092|  16.5k|    const std::string_view input_with_colon) {
13093|  16.5k|  ada_log("url_aggregator::parse_scheme_with_colon ", input_with_colon);
13094|  16.5k|  ADA_ASSERT_TRUE(validate());
13095|  16.5k|  ADA_ASSERT_TRUE(!helpers::overlaps(input_with_colon, buffer));
13096|  16.5k|  std::string_view input{input_with_colon};
13097|  16.5k|  input.remove_suffix(1);
13098|  16.5k|  auto parsed_type = ada::scheme::get_scheme_type(input);
13099|  16.5k|  bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL);
13100|       |  /**
13101|       |   * In the common case, we will immediately recognize a special scheme (e.g.,
13102|       |   *http, https), in which case, we can go really fast.
13103|       |   **/
13104|  16.5k|  if (is_input_special) {  // fast path!!!
  ------------------
  |  Branch (13104:7): [True: 6.84k, False: 9.75k]
  ------------------
13105|  6.84k|    if (has_state_override) {
  ------------------
  |  Branch (13105:9): [Folded - Ignored]
  ------------------
13106|       |      // If url's scheme is not a special scheme and buffer is a special scheme,
13107|       |      // then return.
13108|      0|      if (is_special() != is_input_special) {
  ------------------
  |  Branch (13108:11): [True: 0, False: 0]
  ------------------
13109|      0|        return true;
13110|      0|      }
13111|       |
13112|       |      // If url includes credentials or has a non-null port, and buffer is
13113|       |      // "file", then return.
13114|      0|      if ((has_credentials() || components.port != url_components::omitted) &&
  ------------------
  |  Branch (13114:12): [True: 0, False: 0]
  |  Branch (13114:33): [True: 0, False: 0]
  ------------------
13115|      0|          parsed_type == ada::scheme::type::FILE) {
  ------------------
  |  Branch (13115:11): [True: 0, False: 0]
  ------------------
13116|      0|        return true;
13117|      0|      }
13118|       |
13119|       |      // If url's scheme is "file" and its host is an empty host, then return.
13120|       |      // An empty host is the empty string.
13121|      0|      if (type == ada::scheme::type::FILE &&
  ------------------
  |  Branch (13121:11): [True: 0, False: 0]
  ------------------
13122|      0|          components.host_start == components.host_end) {
  ------------------
  |  Branch (13122:11): [True: 0, False: 0]
  ------------------
13123|      0|        return true;
13124|      0|      }
13125|      0|    }
13126|       |
13127|  6.84k|    type = parsed_type;
13128|  6.84k|    set_scheme_from_view_with_colon(input_with_colon);
13129|       |
13130|  6.84k|    if (has_state_override) {
  ------------------
  |  Branch (13130:9): [Folded - Ignored]
  ------------------
13131|       |      // This is uncommon.
13132|      0|      uint16_t urls_scheme_port = get_special_port();
13133|       |
13134|       |      // If url's port is url's scheme's default port, then set url's port to
13135|       |      // null.
13136|      0|      if (components.port == urls_scheme_port) {
  ------------------
  |  Branch (13136:11): [True: 0, False: 0]
  ------------------
13137|      0|        clear_port();
13138|      0|      }
13139|      0|    }
13140|  9.75k|  } else {  // slow path
13141|  9.75k|    std::string _buffer = std::string(input);
13142|       |    // Next function is only valid if the input is ASCII and returns false
13143|       |    // otherwise, but it seems that we always have ascii content so we do not
13144|       |    // need to check the return value.
13145|  9.75k|    unicode::to_lower_ascii(_buffer.data(), _buffer.size());
13146|       |
13147|  9.75k|    if (has_state_override) {
  ------------------
  |  Branch (13147:9): [Folded - Ignored]
  ------------------
13148|       |      // If url's scheme is a special scheme and buffer is not a special scheme,
13149|       |      // then return. If url's scheme is not a special scheme and buffer is a
13150|       |      // special scheme, then return.
13151|      0|      if (is_special() != ada::scheme::is_special(_buffer)) {
  ------------------
  |  Branch (13151:11): [True: 0, False: 0]
  ------------------
13152|      0|        return true;
13153|      0|      }
13154|       |
13155|       |      // If url includes credentials or has a non-null port, and buffer is
13156|       |      // "file", then return.
13157|      0|      if ((has_credentials() || components.port != url_components::omitted) &&
  ------------------
  |  Branch (13157:12): [True: 0, False: 0]
  |  Branch (13157:33): [True: 0, False: 0]
  ------------------
13158|      0|          _buffer == "file") {
  ------------------
  |  Branch (13158:11): [True: 0, False: 0]
  ------------------
13159|      0|        return true;
13160|      0|      }
13161|       |
13162|       |      // If url's scheme is "file" and its host is an empty host, then return.
13163|       |      // An empty host is the empty string.
13164|      0|      if (type == ada::scheme::type::FILE &&
  ------------------
  |  Branch (13164:11): [True: 0, False: 0]
  ------------------
13165|      0|          components.host_start == components.host_end) {
  ------------------
  |  Branch (13165:11): [True: 0, False: 0]
  ------------------
13166|      0|        return true;
13167|      0|      }
13168|      0|    }
13169|       |
13170|  9.75k|    set_scheme(_buffer);
13171|       |
13172|  9.75k|    if (has_state_override) {
  ------------------
  |  Branch (13172:9): [Folded - Ignored]
  ------------------
13173|       |      // This is uncommon.
13174|      0|      uint16_t urls_scheme_port = get_special_port();
13175|       |
13176|       |      // If url's port is url's scheme's default port, then set url's port to
13177|       |      // null.
13178|      0|      if (components.port == urls_scheme_port) {
  ------------------
  |  Branch (13178:11): [True: 0, False: 0]
  ------------------
13179|      0|        clear_port();
13180|      0|      }
13181|      0|    }
13182|  9.75k|  }
13183|  16.5k|  ADA_ASSERT_TRUE(validate());
13184|  16.5k|  return true;
13185|  16.5k|}
_ZN3ada14url_aggregator31set_scheme_from_view_with_colonENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13218|  6.88k|    std::string_view new_scheme_with_colon) noexcept {
13219|  6.88k|  ada_log("url_aggregator::set_scheme_from_view_with_colon ",
13220|  6.88k|          new_scheme_with_colon);
13221|  6.88k|  ADA_ASSERT_TRUE(validate());
13222|  6.88k|  ADA_ASSERT_TRUE(!new_scheme_with_colon.empty() &&
13223|  6.88k|                  new_scheme_with_colon.back() == ':');
13224|       |  // next line could overflow but unsigned arithmetic has well-defined
13225|       |  // overflows.
13226|  6.88k|  uint32_t new_difference =
13227|  6.88k|      uint32_t(new_scheme_with_colon.size()) - components.protocol_end;
13228|       |
13229|  6.88k|  if (buffer.empty()) {
  ------------------
  |  Branch (13229:7): [True: 6.84k, False: 40]
  ------------------
13230|  6.84k|    buffer.append(new_scheme_with_colon);
13231|  6.84k|  } else {
13232|     40|    buffer.erase(0, components.protocol_end);
13233|     40|    buffer.insert(0, new_scheme_with_colon);
13234|     40|  }
13235|  6.88k|  components.protocol_end += new_difference;
13236|       |
13237|       |  // Update the rest of the components.
13238|  6.88k|  components.username_end += new_difference;
13239|  6.88k|  components.host_start += new_difference;
13240|  6.88k|  components.host_end += new_difference;
13241|  6.88k|  components.pathname_start += new_difference;
13242|  6.88k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (13242:7): [True: 3, False: 6.88k]
  ------------------
13243|      3|    components.search_start += new_difference;
13244|      3|  }
13245|  6.88k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (13245:7): [True: 10, False: 6.87k]
  ------------------
13246|     10|    components.hash_start += new_difference;
13247|     10|  }
13248|  6.88k|  ADA_ASSERT_TRUE(validate());
13249|  6.88k|}
_ZN3ada14url_aggregator10set_schemeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13251|  9.85k|inline void url_aggregator::set_scheme(std::string_view new_scheme) noexcept {
13252|  9.85k|  ada_log("url_aggregator::set_scheme ", new_scheme);
13253|  9.85k|  ADA_ASSERT_TRUE(validate());
13254|  9.85k|  ADA_ASSERT_TRUE(new_scheme.empty() || new_scheme.back() != ':');
13255|       |  // next line could overflow but unsigned arithmetic has well-defined
13256|       |  // overflows.
13257|  9.85k|  uint32_t new_difference =
13258|  9.85k|      uint32_t(new_scheme.size()) - components.protocol_end + 1;
13259|       |
13260|  9.85k|  type = ada::scheme::get_scheme_type(new_scheme);
13261|  9.85k|  if (buffer.empty()) {
  ------------------
  |  Branch (13261:7): [True: 9.75k, False: 107]
  ------------------
13262|  9.75k|    buffer.append(helpers::concat(new_scheme, ":"));
13263|  9.75k|  } else {
13264|    107|    buffer.erase(0, components.protocol_end);
13265|    107|    buffer.insert(0, helpers::concat(new_scheme, ":"));
13266|    107|  }
13267|  9.85k|  components.protocol_end = uint32_t(new_scheme.size() + 1);
13268|       |
13269|       |  // Update the rest of the components.
13270|  9.85k|  components.username_end += new_difference;
13271|  9.85k|  components.host_start += new_difference;
13272|  9.85k|  components.host_end += new_difference;
13273|  9.85k|  components.pathname_start += new_difference;
13274|  9.85k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (13274:7): [True: 6, False: 9.85k]
  ------------------
13275|      6|    components.search_start += new_difference;
13276|      6|  }
13277|  9.85k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (13277:7): [True: 19, False: 9.83k]
  ------------------
13278|     19|    components.hash_start += new_difference;
13279|     19|  }
13280|  9.85k|  ADA_ASSERT_TRUE(validate());
13281|  9.85k|}
_ZN3ada14url_aggregator23parse_scheme_with_colonILb1EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE:
13092|    256|    const std::string_view input_with_colon) {
13093|    256|  ada_log("url_aggregator::parse_scheme_with_colon ", input_with_colon);
13094|    256|  ADA_ASSERT_TRUE(validate());
13095|    256|  ADA_ASSERT_TRUE(!helpers::overlaps(input_with_colon, buffer));
13096|    256|  std::string_view input{input_with_colon};
13097|    256|  input.remove_suffix(1);
13098|    256|  auto parsed_type = ada::scheme::get_scheme_type(input);
13099|    256|  bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL);
13100|       |  /**
13101|       |   * In the common case, we will immediately recognize a special scheme (e.g.,
13102|       |   *http, https), in which case, we can go really fast.
13103|       |   **/
13104|    256|  if (is_input_special) {  // fast path!!!
  ------------------
  |  Branch (13104:7): [True: 44, False: 212]
  ------------------
13105|     44|    if (has_state_override) {
  ------------------
  |  Branch (13105:9): [Folded - Ignored]
  ------------------
13106|       |      // If url's scheme is not a special scheme and buffer is a special scheme,
13107|       |      // then return.
13108|     44|      if (is_special() != is_input_special) {
  ------------------
  |  Branch (13108:11): [True: 2, False: 42]
  ------------------
13109|      2|        return true;
13110|      2|      }
13111|       |
13112|       |      // If url includes credentials or has a non-null port, and buffer is
13113|       |      // "file", then return.
13114|     42|      if ((has_credentials() || components.port != url_components::omitted) &&
  ------------------
  |  Branch (13114:12): [True: 11, False: 31]
  |  Branch (13114:33): [True: 21, False: 10]
  ------------------
13115|     42|          parsed_type == ada::scheme::type::FILE) {
  ------------------
  |  Branch (13115:11): [True: 1, False: 31]
  ------------------
13116|      1|        return true;
13117|      1|      }
13118|       |
13119|       |      // If url's scheme is "file" and its host is an empty host, then return.
13120|       |      // An empty host is the empty string.
13121|     41|      if (type == ada::scheme::type::FILE &&
  ------------------
  |  Branch (13121:11): [True: 2, False: 39]
  ------------------
13122|     41|          components.host_start == components.host_end) {
  ------------------
  |  Branch (13122:11): [True: 1, False: 1]
  ------------------
13123|      1|        return true;
13124|      1|      }
13125|     41|    }
13126|       |
13127|     40|    type = parsed_type;
13128|     40|    set_scheme_from_view_with_colon(input_with_colon);
13129|       |
13130|     40|    if (has_state_override) {
  ------------------
  |  Branch (13130:9): [Folded - Ignored]
  ------------------
13131|       |      // This is uncommon.
13132|     40|      uint16_t urls_scheme_port = get_special_port();
13133|       |
13134|       |      // If url's port is url's scheme's default port, then set url's port to
13135|       |      // null.
13136|     40|      if (components.port == urls_scheme_port) {
  ------------------
  |  Branch (13136:11): [True: 10, False: 30]
  ------------------
13137|     10|        clear_port();
13138|     10|      }
13139|     40|    }
13140|    212|  } else {  // slow path
13141|    212|    std::string _buffer = std::string(input);
13142|       |    // Next function is only valid if the input is ASCII and returns false
13143|       |    // otherwise, but it seems that we always have ascii content so we do not
13144|       |    // need to check the return value.
13145|    212|    unicode::to_lower_ascii(_buffer.data(), _buffer.size());
13146|       |
13147|    212|    if (has_state_override) {
  ------------------
  |  Branch (13147:9): [Folded - Ignored]
  ------------------
13148|       |      // If url's scheme is a special scheme and buffer is not a special scheme,
13149|       |      // then return. If url's scheme is not a special scheme and buffer is a
13150|       |      // special scheme, then return.
13151|    212|      if (is_special() != ada::scheme::is_special(_buffer)) {
  ------------------
  |  Branch (13151:11): [True: 103, False: 109]
  ------------------
13152|    103|        return true;
13153|    103|      }
13154|       |
13155|       |      // If url includes credentials or has a non-null port, and buffer is
13156|       |      // "file", then return.
13157|    109|      if ((has_credentials() || components.port != url_components::omitted) &&
  ------------------
  |  Branch (13157:12): [True: 3, False: 106]
  |  Branch (13157:33): [True: 26, False: 80]
  ------------------
13158|    109|          _buffer == "file") {
  ------------------
  |  Branch (13158:11): [True: 1, False: 28]
  ------------------
13159|      1|        return true;
13160|      1|      }
13161|       |
13162|       |      // If url's scheme is "file" and its host is an empty host, then return.
13163|       |      // An empty host is the empty string.
13164|    108|      if (type == ada::scheme::type::FILE &&
  ------------------
  |  Branch (13164:11): [True: 1, False: 107]
  ------------------
13165|    108|          components.host_start == components.host_end) {
  ------------------
  |  Branch (13165:11): [True: 1, False: 0]
  ------------------
13166|      1|        return true;
13167|      1|      }
13168|    108|    }
13169|       |
13170|    107|    set_scheme(_buffer);
13171|       |
13172|    107|    if (has_state_override) {
  ------------------
  |  Branch (13172:9): [Folded - Ignored]
  ------------------
13173|       |      // This is uncommon.
13174|    107|      uint16_t urls_scheme_port = get_special_port();
13175|       |
13176|       |      // If url's port is url's scheme's default port, then set url's port to
13177|       |      // null.
13178|    107|      if (components.port == urls_scheme_port) {
  ------------------
  |  Branch (13178:11): [True: 11, False: 96]
  ------------------
13179|     11|        clear_port();
13180|     11|      }
13181|    107|    }
13182|    107|  }
13183|    147|  ADA_ASSERT_TRUE(validate());
13184|    147|  return true;
13185|    256|}
_ZN3ada7helpers38strip_trailing_spaces_from_opaque_pathINS_14url_aggregatorEEEvRT_:
11009|  9.19k|    url_type& url) noexcept {
11010|  9.19k|  ada_log("helpers::strip_trailing_spaces_from_opaque_path");
11011|  9.19k|  if (!url.has_opaque_path) return;
  ------------------
  |  Branch (11011:7): [True: 8.01k, False: 1.17k]
  ------------------
11012|  1.17k|  if (url.has_hash()) return;
  ------------------
  |  Branch (11012:7): [True: 48, False: 1.13k]
  ------------------
11013|  1.13k|  if (url.has_search()) return;
  ------------------
  |  Branch (11013:7): [True: 0, False: 1.13k]
  ------------------
11014|       |
11015|  1.13k|  auto path = std::string(url.get_pathname());
11016|  1.72k|  while (!path.empty() && path.back() == ' ') {
  ------------------
  |  Branch (11016:10): [True: 1.24k, False: 477]
  |  Branch (11016:27): [True: 590, False: 653]
  ------------------
11017|    590|    path.resize(path.size() - 1);
11018|    590|  }
11019|  1.13k|  url.update_base_pathname(path);
11020|  1.13k|}
_ZN3ada14url_aggregator20set_host_or_hostnameILb0EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE:
13586|  5.85k|bool url_aggregator::set_host_or_hostname(const std::string_view input) {
13587|  5.85k|  ada_log("url_aggregator::set_host_or_hostname ", input);
13588|  5.85k|  ADA_ASSERT_TRUE(validate());
13589|  5.85k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13590|  5.85k|  if (has_opaque_path) {
  ------------------
  |  Branch (13590:7): [True: 709, False: 5.14k]
  ------------------
13591|    709|    return false;
13592|    709|  }
13593|       |
13594|  5.14k|  std::string previous_host = std::string(get_hostname());
13595|  5.14k|  uint32_t previous_port = components.port;
13596|       |
13597|  5.14k|  size_t host_end_pos = input.find('#');
13598|  5.14k|  std::string _host(input.data(), host_end_pos != std::string_view::npos
  ------------------
  |  Branch (13598:35): [True: 10, False: 5.13k]
  ------------------
13599|  5.14k|                                      ? host_end_pos
13600|  5.14k|                                      : input.size());
13601|  5.14k|  helpers::remove_ascii_tab_or_newline(_host);
13602|  5.14k|  std::string_view new_host(_host);
13603|       |
13604|       |  // If url's scheme is "file", then set state to file host state, instead of
13605|       |  // host state.
13606|  5.14k|  if (type != ada::scheme::type::FILE) {
  ------------------
  |  Branch (13606:7): [True: 3.94k, False: 1.19k]
  ------------------
13607|  3.94k|    std::string_view host_view(_host.data(), _host.length());
13608|  3.94k|    auto [location, found_colon] =
13609|  3.94k|        helpers::get_host_delimiter_location(is_special(), host_view);
13610|       |
13611|       |    // Otherwise, if c is U+003A (:) and insideBrackets is false, then:
13612|       |    // Note: the 'found_colon' value is true if and only if a colon was
13613|       |    // encountered while not inside brackets.
13614|  3.94k|    if (found_colon) {
  ------------------
  |  Branch (13614:9): [True: 150, False: 3.79k]
  ------------------
13615|    150|      if (override_hostname) {
  ------------------
  |  Branch (13615:11): [Folded - Ignored]
  ------------------
13616|      0|        return false;
13617|      0|      }
13618|    150|      std::string_view sub_buffer = new_host.substr(location + 1);
13619|    150|      if (!sub_buffer.empty()) {
  ------------------
  |  Branch (13619:11): [True: 130, False: 20]
  ------------------
13620|    130|        set_port(sub_buffer);
13621|    130|      }
13622|    150|    }
13623|       |    // If url is special and host_view is the empty string, validation error,
13624|       |    // return failure. Otherwise, if state override is given, host_view is the
13625|       |    // empty string, and either url includes credentials or url's port is
13626|       |    // non-null, return.
13627|  3.79k|    else if (host_view.empty() &&
  ------------------
  |  Branch (13627:14): [True: 3.19k, False: 606]
  ------------------
13628|  3.79k|             (is_special() || has_credentials() || has_port())) {
  ------------------
  |  Branch (13628:15): [True: 2.27k, False: 917]
  |  Branch (13628:31): [True: 4, False: 913]
  |  Branch (13628:52): [True: 6, False: 907]
  ------------------
13629|  2.28k|      return false;
13630|  2.28k|    }
13631|       |
13632|       |    // Let host be the result of host parsing host_view with url is not special.
13633|  1.66k|    if (host_view.empty() && !is_special()) {
  ------------------
  |  Branch (13633:9): [True: 952, False: 711]
  |  Branch (13633:30): [True: 921, False: 31]
  ------------------
13634|    921|      if (has_hostname()) {
  ------------------
  |  Branch (13634:11): [True: 97, False: 824]
  ------------------
13635|     97|        clear_hostname();  // easy!
13636|    824|      } else if (has_dash_dot()) {
  ------------------
  |  Branch (13636:18): [True: 0, False: 824]
  ------------------
13637|      0|        add_authority_slashes_if_needed();
13638|      0|        delete_dash_dot();
13639|      0|      }
13640|    921|      return true;
13641|    921|    }
13642|       |
13643|    742|    bool succeeded = parse_host(host_view);
13644|    742|    if (!succeeded) {
  ------------------
  |  Branch (13644:9): [True: 251, False: 491]
  ------------------
13645|    251|      update_base_hostname(previous_host);
13646|    251|      update_base_port(previous_port);
13647|    491|    } else if (has_dash_dot()) {
  ------------------
  |  Branch (13647:16): [True: 23, False: 468]
  ------------------
13648|       |      // Should remove dash_dot from pathname
13649|     23|      delete_dash_dot();
13650|     23|    }
13651|    742|    return succeeded;
13652|  1.66k|  }
13653|       |
13654|  1.19k|  size_t location = new_host.find_first_of("/\\?");
13655|  1.19k|  if (location != std::string_view::npos) {
  ------------------
  |  Branch (13655:7): [True: 14, False: 1.17k]
  ------------------
13656|     14|    new_host.remove_suffix(new_host.length() - location);
13657|     14|  }
13658|       |
13659|  1.19k|  if (new_host.empty()) {
  ------------------
  |  Branch (13659:7): [True: 917, False: 275]
  ------------------
13660|       |    // Set url's host to the empty string.
13661|    917|    clear_hostname();
13662|    917|  } else {
13663|       |    // Let host be the result of host parsing buffer with url is not special.
13664|    275|    if (!parse_host(new_host)) {
  ------------------
  |  Branch (13664:9): [True: 35, False: 240]
  ------------------
13665|     35|      update_base_hostname(previous_host);
13666|     35|      update_base_port(previous_port);
13667|     35|      return false;
13668|     35|    }
13669|       |
13670|       |    // If host is "localhost", then set host to the empty string.
13671|    240|    if (helpers::substring(buffer, components.host_start,
  ------------------
  |  Branch (13671:9): [True: 6, False: 234]
  ------------------
13672|    240|                           components.host_end) == "localhost") {
13673|      6|      clear_hostname();
13674|      6|    }
13675|    240|  }
13676|  1.15k|  ADA_ASSERT_TRUE(validate());
13677|  1.15k|  return true;
13678|  1.19k|}
_ZN3ada14url_aggregator20set_host_or_hostnameILb1EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE:
13586|  6.50k|bool url_aggregator::set_host_or_hostname(const std::string_view input) {
13587|  6.50k|  ada_log("url_aggregator::set_host_or_hostname ", input);
13588|  6.50k|  ADA_ASSERT_TRUE(validate());
13589|  6.50k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13590|  6.50k|  if (has_opaque_path) {
  ------------------
  |  Branch (13590:7): [True: 709, False: 5.79k]
  ------------------
13591|    709|    return false;
13592|    709|  }
13593|       |
13594|  5.79k|  std::string previous_host = std::string(get_hostname());
13595|  5.79k|  uint32_t previous_port = components.port;
13596|       |
13597|  5.79k|  size_t host_end_pos = input.find('#');
13598|  5.79k|  std::string _host(input.data(), host_end_pos != std::string_view::npos
  ------------------
  |  Branch (13598:35): [True: 10, False: 5.78k]
  ------------------
13599|  5.79k|                                      ? host_end_pos
13600|  5.79k|                                      : input.size());
13601|  5.79k|  helpers::remove_ascii_tab_or_newline(_host);
13602|  5.79k|  std::string_view new_host(_host);
13603|       |
13604|       |  // If url's scheme is "file", then set state to file host state, instead of
13605|       |  // host state.
13606|  5.79k|  if (type != ada::scheme::type::FILE) {
  ------------------
  |  Branch (13606:7): [True: 4.50k, False: 1.29k]
  ------------------
13607|  4.50k|    std::string_view host_view(_host.data(), _host.length());
13608|  4.50k|    auto [location, found_colon] =
13609|  4.50k|        helpers::get_host_delimiter_location(is_special(), host_view);
13610|       |
13611|       |    // Otherwise, if c is U+003A (:) and insideBrackets is false, then:
13612|       |    // Note: the 'found_colon' value is true if and only if a colon was
13613|       |    // encountered while not inside brackets.
13614|  4.50k|    if (found_colon) {
  ------------------
  |  Branch (13614:9): [True: 150, False: 4.35k]
  ------------------
13615|    150|      if (override_hostname) {
  ------------------
  |  Branch (13615:11): [Folded - Ignored]
  ------------------
13616|    150|        return false;
13617|    150|      }
13618|      0|      std::string_view sub_buffer = new_host.substr(location + 1);
13619|      0|      if (!sub_buffer.empty()) {
  ------------------
  |  Branch (13619:11): [True: 0, False: 0]
  ------------------
13620|      0|        set_port(sub_buffer);
13621|      0|      }
13622|      0|    }
13623|       |    // If url is special and host_view is the empty string, validation error,
13624|       |    // return failure. Otherwise, if state override is given, host_view is the
13625|       |    // empty string, and either url includes credentials or url's port is
13626|       |    // non-null, return.
13627|  4.35k|    else if (host_view.empty() &&
  ------------------
  |  Branch (13627:14): [True: 3.30k, False: 1.04k]
  ------------------
13628|  4.35k|             (is_special() || has_credentials() || has_port())) {
  ------------------
  |  Branch (13628:15): [True: 2.27k, False: 1.02k]
  |  Branch (13628:31): [True: 4, False: 1.02k]
  |  Branch (13628:52): [True: 6, False: 1.01k]
  ------------------
13629|  2.28k|      return false;
13630|  2.28k|    }
13631|       |
13632|       |    // Let host be the result of host parsing host_view with url is not special.
13633|  2.06k|    if (host_view.empty() && !is_special()) {
  ------------------
  |  Branch (13633:9): [True: 1.01k, False: 1.04k]
  |  Branch (13633:30): [True: 1.01k, False: 0]
  ------------------
13634|  1.01k|      if (has_hostname()) {
  ------------------
  |  Branch (13634:11): [True: 71, False: 943]
  ------------------
13635|     71|        clear_hostname();  // easy!
13636|    943|      } else if (has_dash_dot()) {
  ------------------
  |  Branch (13636:18): [True: 21, False: 922]
  ------------------
13637|     21|        add_authority_slashes_if_needed();
13638|     21|        delete_dash_dot();
13639|     21|      }
13640|  1.01k|      return true;
13641|  1.01k|    }
13642|       |
13643|  1.04k|    bool succeeded = parse_host(host_view);
13644|  1.04k|    if (!succeeded) {
  ------------------
  |  Branch (13644:9): [True: 193, False: 856]
  ------------------
13645|    193|      update_base_hostname(previous_host);
13646|    193|      update_base_port(previous_port);
13647|    856|    } else if (has_dash_dot()) {
  ------------------
  |  Branch (13647:16): [True: 12, False: 844]
  ------------------
13648|       |      // Should remove dash_dot from pathname
13649|     12|      delete_dash_dot();
13650|     12|    }
13651|  1.04k|    return succeeded;
13652|  2.06k|  }
13653|       |
13654|  1.29k|  size_t location = new_host.find_first_of("/\\?");
13655|  1.29k|  if (location != std::string_view::npos) {
  ------------------
  |  Branch (13655:7): [True: 14, False: 1.27k]
  ------------------
13656|     14|    new_host.remove_suffix(new_host.length() - location);
13657|     14|  }
13658|       |
13659|  1.29k|  if (new_host.empty()) {
  ------------------
  |  Branch (13659:7): [True: 965, False: 325]
  ------------------
13660|       |    // Set url's host to the empty string.
13661|    965|    clear_hostname();
13662|    965|  } else {
13663|       |    // Let host be the result of host parsing buffer with url is not special.
13664|    325|    if (!parse_host(new_host)) {
  ------------------
  |  Branch (13664:9): [True: 35, False: 290]
  ------------------
13665|     35|      update_base_hostname(previous_host);
13666|     35|      update_base_port(previous_port);
13667|     35|      return false;
13668|     35|    }
13669|       |
13670|       |    // If host is "localhost", then set host to the empty string.
13671|    290|    if (helpers::substring(buffer, components.host_start,
  ------------------
  |  Branch (13671:9): [True: 6, False: 284]
  ------------------
13672|    290|                           components.host_end) == "localhost") {
13673|      6|      clear_hostname();
13674|      6|    }
13675|    290|  }
13676|  1.25k|  ADA_ASSERT_TRUE(validate());
13677|  1.25k|  return true;
13678|  1.29k|}

_ZN3ada14character_sets6bit_atEPKhh:
  994|   828k|ada_really_inline bool bit_at(const uint8_t a[], const uint8_t i) {
  995|   828k|  return !!(a[i >> 3] & (1 << (i & 7)));
  996|   828k|}
_ZN2tl10unexpectedIN3ada6errorsEEC2EOS2_:
 1928|  42.3k|  constexpr explicit unexpected(E &&e) : m_val(std::move(e)) {}
_ZN2tl8expectedIN3ada3urlENS1_6errorsEEC2IS3_LPv0ELS6_0EEEONS_10unexpectedIT_EE:
 3418|  4.36k|        ctor_base(detail::default_constructor_tag{}) {}
_ZNR2tl10unexpectedIN3ada6errorsEE5valueEv:
 1942|  21.1k|  TL_EXPECTED_11_CONSTEXPR E &value() & { return m_val; }
_ZN2tl6detail21expected_storage_baseIN3ada3urlENS2_6errorsELb0ELb1EEC2IJS4_ELPv0EEENS_10unexpect_tEDpOT_:
 2400|  4.36k|      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
_ZN2tl6detail26expected_default_ctor_baseIN3ada3urlENS2_6errorsELb1EEC2ENS0_23default_constructor_tagE:
 3016|  10.1k|  constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
_ZN2tl8expectedIN3ada3urlENS1_6errorsEEC2IS2_LPv0ELS6_0EEEOT_:
 3505|  5.75k|      : expected(in_place, std::forward<U>(v)) {}
_ZN2tl8expectedIN3ada3urlENS1_6errorsEEC2IJS2_ELPv0EEENS_10in_place_tEDpOT_:
 3375|  5.75k|        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl6detail21expected_storage_baseIN3ada3urlENS2_6errorsELb0ELb1EEC2IJS3_ELPv0EEENS_10in_place_tEDpOT_:
 2388|  5.75k|      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
_ZN3ada3urlC2EOS0_:
 5093|  5.75k|  url(url &&u) noexcept = default;
_ZN3ada8url_baseD2Ev:
 1440|  82.0k|  virtual ~url_base() = default;
_ZN3ada3urlD2Ev:
 5096|  15.8k|  ~url() = default;
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEC2IS3_LPv0ELS6_0EEEONS_10unexpectedIT_EE:
 3418|  16.8k|        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl6detail21expected_storage_baseIN3ada14url_aggregatorENS2_6errorsELb0ELb1EEC2IJS4_ELPv0EEENS_10unexpect_tEDpOT_:
 2400|  16.8k|      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
_ZN2tl6detail26expected_default_ctor_baseIN3ada14url_aggregatorENS2_6errorsELb1EEC2ENS0_23default_constructor_tagE:
 3016|  31.6k|  constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEC2IS2_LPv0ELS6_0EEEOT_:
 3505|  14.8k|      : expected(in_place, std::forward<U>(v)) {}
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEC2IJS2_ELPv0EEENS_10in_place_tEDpOT_:
 3375|  14.8k|        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl6detail21expected_storage_baseIN3ada14url_aggregatorENS2_6errorsELb0ELb1EEC2IJS3_ELPv0EEENS_10in_place_tEDpOT_:
 2388|  14.8k|      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
_ZN3ada14url_aggregatorC2EOS0_:
 4674|  14.8k|  url_aggregator(url_aggregator &&u) noexcept = default;
_ZN3ada14url_aggregatorD2Ev:
 4677|  66.2k|  ~url_aggregator() = default;
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEC2Ev:
 3364|  19.7k|  constexpr expected() = default;
_ZN2tl6detail25expected_move_assign_baseIN3ada14url_aggregatorENS2_6errorsELb0EEC2Ev:
 2867|  19.7k|  expected_move_assign_base() = default;
_ZN2tl6detail25expected_copy_assign_baseIN3ada14url_aggregatorENS2_6errorsELb0EEC2Ev:
 2828|  19.7k|  expected_copy_assign_base() = default;
_ZN2tl6detail18expected_move_baseIN3ada14url_aggregatorENS2_6errorsELb0EEC2Ev:
 2795|  19.7k|  expected_move_base() = default;
_ZN2tl6detail18expected_copy_baseIN3ada14url_aggregatorENS2_6errorsELb0EEC2Ev:
 2760|  19.7k|  expected_copy_base() = default;
_ZN2tl6detail21expected_storage_baseIN3ada14url_aggregatorENS2_6errorsELb0ELb1EEC2Ev:
 2381|  19.7k|  constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEaSEOS4_:
 3368|  9.85k|  expected &operator=(expected &&rhs) = default;
_ZN2tl6detail25expected_move_assign_baseIN3ada14url_aggregatorENS2_6errorsELb0EEaSEOS5_:
 2878|  9.85k|          &&std::is_nothrow_move_assignable<T>::value) {
 2879|  9.85k|    this->assign(std::move(rhs));
 2880|  9.85k|    return *this;
 2881|  9.85k|  }
_ZN2tl6detail24expected_operations_baseIN3ada14url_aggregatorENS2_6errorsEE6assignIS3_LPv0EEEvOS5_:
 2589|  9.85k|  void assign(expected_operations_base &&rhs) noexcept {
 2590|  9.85k|    if (!this->m_has_val && rhs.m_has_val) {
  ------------------
  |  Branch (2590:9): [True: 0, False: 9.85k]
  |  Branch (2590:29): [True: 0, False: 0]
  ------------------
 2591|      0|      geterr().~unexpected<E>();
 2592|      0|      construct(std::move(rhs).get());
 2593|  9.85k|    } else {
 2594|  9.85k|      assign_common(std::move(rhs));
 2595|  9.85k|    }
 2596|  9.85k|  }
_ZNO2tl6detail24expected_operations_baseIN3ada14url_aggregatorENS2_6errorsEE3getEv:
 2664|  1.84k|  TL_EXPECTED_11_CONSTEXPR T &&get() && { return std::move(this->m_val); }
_ZN2tl6detail24expected_operations_baseIN3ada14url_aggregatorENS2_6errorsEE13assign_commonIS5_EEvOT_:
 2645|  9.85k|  void assign_common(Rhs &&rhs) {
 2646|  9.85k|    if (this->m_has_val) {
  ------------------
  |  Branch (2646:9): [True: 9.85k, False: 0]
  ------------------
 2647|  9.85k|      if (rhs.m_has_val) {
  ------------------
  |  Branch (2647:11): [True: 1.84k, False: 8.01k]
  ------------------
 2648|  1.84k|        get() = std::forward<Rhs>(rhs).get();
 2649|  8.01k|      } else {
 2650|  8.01k|        destroy_val();
 2651|  8.01k|        construct_error(std::forward<Rhs>(rhs).geterr());
 2652|  8.01k|      }
 2653|  9.85k|    } else {
 2654|      0|      if (!rhs.m_has_val) {
  ------------------
  |  Branch (2654:11): [True: 0, False: 0]
  ------------------
 2655|      0|        geterr() = std::forward<Rhs>(rhs).geterr();
 2656|      0|      }
 2657|      0|    }
 2658|  9.85k|  }
_ZNR2tl6detail24expected_operations_baseIN3ada14url_aggregatorENS2_6errorsEE3getEv:
 2662|  9.85k|  TL_EXPECTED_11_CONSTEXPR T &get() & { return this->m_val; }
_ZN3ada14url_aggregatoraSEOS0_:
 4675|  1.84k|  url_aggregator &operator=(url_aggregator &&u) noexcept = default;
_ZN2tl6detail24expected_operations_baseIN3ada14url_aggregatorENS2_6errorsEE11destroy_valEv:
 2682|  8.01k|  TL_EXPECTED_11_CONSTEXPR void destroy_val() { get().~T(); }
_ZN2tl6detail24expected_operations_baseIN3ada14url_aggregatorENS2_6errorsEE15construct_errorIJNS_10unexpectedIS4_EEEEEvDpOT_:
 2514|  8.01k|  void construct_error(Args &&...args) noexcept {
 2515|  8.01k|    new (std::addressof(this->m_unexpect))
 2516|  8.01k|        unexpected<E>(std::forward<Args>(args)...);
 2517|  8.01k|    this->m_has_val = false;
 2518|  8.01k|  }
_ZNO2tl6detail24expected_operations_baseIN3ada14url_aggregatorENS2_6errorsEE6geterrEv:
 2673|  8.01k|  TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
 2674|  8.01k|    return std::move(this->m_unexpect);
 2675|  8.01k|  }
_ZN2tl6detail21expected_storage_baseIN3ada14url_aggregatorENS2_6errorsELb0ELb1EED2Ev:
 2410|  51.3k|  ~expected_storage_base() {
 2411|  51.3k|    if (m_has_val) {
  ------------------
  |  Branch (2411:9): [True: 26.5k, False: 24.8k]
  ------------------
 2412|  26.5k|      m_val.~T();
 2413|  26.5k|    }
 2414|  51.3k|  }
_ZNK2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEcvbEv:
 3819|  19.9k|  constexpr explicit operator bool() const noexcept { return this->m_has_val; }
_ZNR2tl8expectedIN3ada14url_aggregatorENS1_6errorsEE5valueIS2_LPv0EEERT_v:
 3830|  1.84k|  TL_EXPECTED_11_CONSTEXPR U &value() & {
 3831|  1.84k|    if (!has_value())
  ------------------
  |  Branch (3831:9): [True: 0, False: 1.84k]
  ------------------
 3832|      0|      detail::throw_exception(bad_expected_access<E>(err().value()));
 3833|  1.84k|    return val();
 3834|  1.84k|  }
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEE3valIS2_LPv0EEERT_v:
 3085|  1.84k|  TL_EXPECTED_11_CONSTEXPR U &val() {
 3086|  1.84k|    return this->m_val;
 3087|  1.84k|  }
_ZNK2tl8expectedIN3ada14url_aggregatorENS1_6errorsEE9has_valueEv:
 3818|   138k|  constexpr bool has_value() const noexcept { return this->m_has_val; }
_ZN3ada8checkers14has_hex_prefixENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 1034|  15.1k|inline bool has_hex_prefix(std::string_view input) {
 1035|  15.1k|  return input.size() >= 2 && has_hex_prefix_unsafe(input);
  ------------------
  |  Branch (1035:10): [True: 9.47k, False: 5.64k]
  |  Branch (1035:31): [True: 2.96k, False: 6.50k]
  ------------------
 1036|  15.1k|}
_ZN3ada8checkers21has_hex_prefix_unsafeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 1017|  9.47k|inline bool has_hex_prefix_unsafe(std::string_view input) {
 1018|       |  // This is actually efficient code, see has_hex_prefix for the assembly.
 1019|  9.47k|  uint32_t value_one = 1;
 1020|  9.47k|  bool is_little_endian = (reinterpret_cast<char*>(&value_one)[0] == 1);
 1021|  9.47k|  uint16_t word0x{};
 1022|  9.47k|  std::memcpy(&word0x, "0x", 2);  // we would use bit_cast in C++20 and the
 1023|       |                                  // function could be constexpr.
 1024|  9.47k|  uint16_t two_first_bytes{};
 1025|  9.47k|  std::memcpy(&two_first_bytes, input.data(), 2);
 1026|  9.47k|  if (is_little_endian) {
  ------------------
  |  Branch (1026:7): [True: 9.47k, False: 0]
  ------------------
 1027|  9.47k|    two_first_bytes |= 0x2000;
 1028|  9.47k|  } else {
 1029|      0|    two_first_bytes |= 0x020;
 1030|      0|  }
 1031|  9.47k|  return two_first_bytes == word0x;
 1032|  9.47k|}
_ZN3ada8checkers8is_digitEc:
 1038|  30.8k|constexpr bool is_digit(char x) noexcept { return (x >= '0') & (x <= '9'); }
_ZNK3ada3url15has_credentialsEv:
 5506|  1.74k|[[nodiscard]] ada_really_inline bool url::has_credentials() const noexcept {
 5507|  1.74k|  return !username.empty() || !password.empty();
  ------------------
  |  Branch (5507:10): [True: 16, False: 1.72k]
  |  Branch (5507:31): [True: 2, False: 1.72k]
  ------------------
 5508|  1.74k|}
_ZNK3ada8url_base10is_specialEv:
 5473|   171k|[[nodiscard]] ada_really_inline bool url_base::is_special() const noexcept {
 5474|   171k|  return type != ada::scheme::NOT_SPECIAL;
 5475|   171k|}
_ZNK2tl8expectedIN3ada3urlENS1_6errorsEEcvbEv:
 3819|  10.1k|  constexpr explicit operator bool() const noexcept { return this->m_has_val; }
_ZN2tl8expectedIN3ada3urlENS1_6errorsEEptEv:
 3788|   108k|  TL_EXPECTED_11_CONSTEXPR T *operator->() {
 3789|   108k|    TL_ASSERT(has_value());
  ------------------
  |  | 1835|   108k|#define TL_ASSERT(x) assert(x)
  ------------------
 3790|      0|    return valptr();
 3791|   108k|  }
_ZN2tl8expectedIN3ada3urlENS1_6errorsEE6valptrEv:
 3076|   108k|  T *valptr() { return std::addressof(this->m_val); }
_ZN2tl6detail21expected_storage_baseIN3ada3urlENS2_6errorsELb0ELb1EED2Ev:
 2410|  10.1k|  ~expected_storage_base() {
 2411|  10.1k|    if (m_has_val) {
  ------------------
  |  Branch (2411:9): [True: 5.75k, False: 4.36k]
  ------------------
 2412|  5.75k|      m_val.~T();
 2413|  5.75k|    }
 2414|  10.1k|  }
_ZNK3ada3url31cannot_have_credentials_or_portEv:
 5512|  17.1k|[[nodiscard]] inline bool url::cannot_have_credentials_or_port() const {
 5513|  17.1k|  return !host.has_value() || host.value().empty() ||
  ------------------
  |  Branch (5513:10): [True: 4.19k, False: 12.9k]
  |  Branch (5513:31): [True: 3.16k, False: 9.77k]
  ------------------
 5514|  17.1k|         type == ada::scheme::type::FILE;
  ------------------
  |  Branch (5514:10): [True: 744, False: 9.03k]
  ------------------
 5515|  17.1k|}
_ZN3ada8checkers8is_alphaEc:
 1042|  58.3k|constexpr bool is_alpha(char x) noexcept {
 1043|  58.3k|  return (to_lower(x) >= 'a') && (to_lower(x) <= 'z');
  ------------------
  |  Branch (1043:10): [True: 44.3k, False: 14.0k]
  |  Branch (1043:34): [True: 43.8k, False: 507]
  ------------------
 1044|  58.3k|}
_ZN3ada8checkers8to_lowerEc:
 1040|   102k|constexpr char to_lower(char x) noexcept { return (x | 0x20); }
_ZNK2tl8expectedIN3ada3urlENS1_6errorsEE9has_valueEv:
 3818|   108k|  constexpr bool has_value() const noexcept { return this->m_has_val; }
_ZN3ada3urlC2Ev:
 5091|  10.1k|  url() = default;
_ZN3ada3url26update_unencoded_base_hashENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 5605|    231|inline void url::update_unencoded_base_hash(std::string_view input) {
 5606|       |  // We do the percent encoding
 5607|    231|  hash = unicode::percent_encode(input,
 5608|    231|                                 ada::character_sets::FRAGMENT_PERCENT_ENCODE);
 5609|    231|}
_ZN3ada8checkers11begins_withENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_:
 1059|  35.5k|                                   std::string_view prefix) {
 1060|       |  // in C++20, you have view.begins_with(prefix)
 1061|       |  // std::equal is constexpr in C++20
 1062|  35.5k|  return view.size() >= prefix.size() &&
  ------------------
  |  Branch (1062:10): [True: 13.7k, False: 21.7k]
  ------------------
 1063|  35.5k|         std::equal(prefix.begin(), prefix.end(), view.begin());
  ------------------
  |  Branch (1063:10): [True: 746, False: 12.9k]
  ------------------
 1064|  35.5k|}
_ZN3ada3url18update_base_searchENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKh:
 5612|    217|                                    const uint8_t query_percent_encode_set[]) {
 5613|    217|  query = ada::unicode::percent_encode(input, query_percent_encode_set);
 5614|    217|}
_ZN3ada3url20update_base_hostnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 5603|     15|inline void url::update_base_hostname(std::string_view input) { host = input; }
_ZN3ada3url20update_base_pathnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 5620|  4.60k|inline void url::update_base_pathname(const std::string_view input) {
 5621|  4.60k|  path = input;
 5622|  4.60k|}
_ZN3ada3url10parse_portENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEb:
 5701|  1.04k|                                         bool check_trailing_content) noexcept {
 5702|  1.04k|  ada_log("parse_port('", view, "') ", view.size());
 5703|  1.04k|  uint16_t parsed_port{};
 5704|  1.04k|  auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port);
 5705|  1.04k|  if (r.ec == std::errc::result_out_of_range) {
  ------------------
  |  Branch (5705:7): [True: 61, False: 982]
  ------------------
 5706|     61|    ada_log("parse_port: std::errc::result_out_of_range");
 5707|     61|    is_valid = false;
 5708|     61|    return 0;
 5709|     61|  }
 5710|    982|  ada_log("parse_port: ", parsed_port);
 5711|    982|  const size_t consumed = size_t(r.ptr - view.data());
 5712|    982|  ada_log("parse_port: consumed ", consumed);
 5713|    982|  if (check_trailing_content) {
  ------------------
  |  Branch (5713:7): [True: 498, False: 484]
  ------------------
 5714|    498|    is_valid &=
 5715|    498|        (consumed == view.size() || view[consumed] == '/' ||
  ------------------
  |  Branch (5715:10): [True: 391, False: 107]
  |  Branch (5715:37): [True: 19, False: 88]
  ------------------
 5716|    498|         view[consumed] == '?' || (is_special() && view[consumed] == '\\'));
  ------------------
  |  Branch (5716:10): [True: 47, False: 41]
  |  Branch (5716:36): [True: 38, False: 3]
  |  Branch (5716:52): [True: 1, False: 37]
  ------------------
 5717|    498|  }
 5718|    982|  ada_log("parse_port: is_valid = ", is_valid);
 5719|    982|  if (is_valid) {
  ------------------
  |  Branch (5719:7): [True: 856, False: 126]
  ------------------
 5720|       |    // scheme_default_port can return 0, and we should allow 0 as a base port.
 5721|    856|    auto default_port = scheme_default_port();
 5722|    856|    bool is_port_valid = (default_port == 0 && parsed_port == 0) ||
  ------------------
  |  Branch (5722:27): [True: 154, False: 702]
  |  Branch (5722:48): [True: 90, False: 64]
  ------------------
 5723|    856|                         (default_port != parsed_port);
  ------------------
  |  Branch (5723:26): [True: 761, False: 5]
  ------------------
 5724|    856|    port = (r.ec == std::errc() && is_port_valid)
  ------------------
  |  Branch (5724:13): [True: 366, False: 490]
  |  Branch (5724:36): [True: 361, False: 5]
  ------------------
 5725|    856|               ? std::optional<uint16_t>(parsed_port)
 5726|    856|               : std::nullopt;
 5727|    856|  }
 5728|    982|  return consumed;
 5729|  1.04k|}
_ZNK3ada8url_base19scheme_default_portEv:
 5482|  2.19k|url_base::scheme_default_port() const noexcept {
 5483|  2.19k|  return scheme::get_special_port(type);
 5484|  2.19k|}
_ZN3ada6scheme16get_special_portENS0_4typeE:
 4367|  2.46k|constexpr uint16_t get_special_port(ada::scheme::type type) noexcept {
 4368|  2.46k|  return details::special_ports[int(type)];
 4369|  2.46k|}
_ZN3ada8checkers23is_windows_drive_letterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 1046|  23.6k|inline constexpr bool is_windows_drive_letter(std::string_view input) noexcept {
 1047|  23.6k|  return input.size() >= 2 &&
  ------------------
  |  Branch (1047:10): [True: 20.0k, False: 3.59k]
  ------------------
 1048|  23.6k|         (is_alpha(input[0]) && ((input[1] == ':') || (input[1] == '|'))) &&
  ------------------
  |  Branch (1048:11): [True: 14.2k, False: 5.81k]
  |  Branch (1048:34): [True: 3.69k, False: 10.5k]
  |  Branch (1048:55): [True: 1.29k, False: 9.24k]
  ------------------
 1049|  23.6k|         ((input.size() == 2) || (input[2] == '/' || input[2] == '\\' ||
  ------------------
  |  Branch (1049:11): [True: 1.93k, False: 3.06k]
  |  Branch (1049:35): [True: 1.28k, False: 1.77k]
  |  Branch (1049:54): [True: 24, False: 1.75k]
  ------------------
 1050|  3.06k|                                  input[2] == '?' || input[2] == '#'));
  ------------------
  |  Branch (1050:35): [True: 35, False: 1.71k]
  |  Branch (1050:54): [True: 33, False: 1.68k]
  ------------------
 1051|  23.6k|}
_ZN3ada8checkers34is_normalized_windows_drive_letterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 1054|  5.09k|    std::string_view input) noexcept {
 1055|  5.09k|  return input.size() >= 2 && (is_alpha(input[0]) && (input[1] == ':'));
  ------------------
  |  Branch (1055:10): [True: 4.24k, False: 845]
  |  Branch (1055:32): [True: 3.04k, False: 1.20k]
  |  Branch (1055:54): [True: 1.46k, False: 1.57k]
  ------------------
 1056|  5.09k|}
_ZN3ada3url20set_protocol_as_fileEv:
 5648|  1.12k|inline void url::set_protocol_as_file() { type = ada::scheme::type::FILE; }
_ZN3ada14url_aggregatorC2Ev:
 4672|  51.3k|  url_aggregator() = default;
_ZN3ada7helpers14leading_zeroesEj:
 1727|  31.6k|inline int leading_zeroes(uint32_t input_num) noexcept {
 1728|       |#if ADA_REGULAR_VISUAL_STUDIO
 1729|       |  unsigned long leading_zero(0);
 1730|       |  unsigned long in(input_num);
 1731|       |  return _BitScanReverse(&leading_zero, in) ? int(31 - leading_zero) : 32;
 1732|       |#else
 1733|  31.6k|  return __builtin_clz(input_num);
 1734|  31.6k|#endif  // ADA_REGULAR_VISUAL_STUDIO
 1735|  31.6k|}
_ZN3ada14url_aggregator7reserveEj:
 6521|  31.6k|inline void ada::url_aggregator::reserve(uint32_t capacity) {
 6522|  31.6k|  buffer.reserve(capacity);
 6523|  31.6k|}
_ZN3ada14url_aggregator20update_base_pathnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6015|  17.3k|inline void url_aggregator::update_base_pathname(const std::string_view input) {
 6016|  17.3k|  ada_log("url_aggregator::update_base_pathname '", input, "' [", input.size(),
 6017|  17.3k|          " bytes] \n", to_diagram());
 6018|  17.3k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 6019|  17.3k|  ADA_ASSERT_TRUE(validate());
 6020|       |
 6021|  17.3k|  const bool begins_with_dashdash = checkers::begins_with(input, "//");
 6022|  17.3k|  if (!begins_with_dashdash && has_dash_dot()) {
  ------------------
  |  Branch (6022:7): [True: 17.1k, False: 249]
  |  Branch (6022:32): [True: 33, False: 17.0k]
  ------------------
 6023|     33|    ada_log("url_aggregator::update_base_pathname has /.: \n", to_diagram());
 6024|       |    // We must delete the ./
 6025|     33|    delete_dash_dot();
 6026|     33|  }
 6027|       |
 6028|  17.3k|  if (begins_with_dashdash && !has_opaque_path && !has_authority() &&
  ------------------
  |  Branch (6028:7): [True: 249, False: 17.1k]
  |  Branch (6028:31): [True: 248, False: 1]
  |  Branch (6028:51): [True: 95, False: 153]
  ------------------
 6029|  17.3k|      !has_dash_dot()) {
  ------------------
  |  Branch (6029:7): [True: 84, False: 11]
  ------------------
 6030|       |    // If url's host is null, url does not have an opaque path, url's path's
 6031|       |    // size is greater than 1, then append U+002F (/) followed by U+002E (.) to
 6032|       |    // output.
 6033|     84|    buffer.insert(components.pathname_start, "/.");
 6034|     84|    components.pathname_start += 2;
 6035|     84|  }
 6036|       |
 6037|  17.3k|  uint32_t difference = replace_and_resize(
 6038|  17.3k|      components.pathname_start,
 6039|  17.3k|      components.pathname_start + get_pathname_length(), input);
 6040|  17.3k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6040:7): [True: 147, False: 17.2k]
  ------------------
 6041|    147|    components.search_start += difference;
 6042|    147|  }
 6043|  17.3k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6043:7): [True: 151, False: 17.2k]
  ------------------
 6044|    151|    components.hash_start += difference;
 6045|    151|  }
 6046|  17.3k|  ada_log("url_aggregator::update_base_pathname end '", input, "' [",
 6047|  17.3k|          input.size(), " bytes] \n", to_diagram());
 6048|  17.3k|  ADA_ASSERT_TRUE(validate());
 6049|  17.3k|}
_ZN3ada14url_aggregator18replace_and_resizeEjjNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 5858|  38.3k|    uint32_t start, uint32_t end, std::string_view input) {
 5859|  38.3k|  uint32_t current_length = end - start;
 5860|  38.3k|  uint32_t input_size = uint32_t(input.size());
 5861|  38.3k|  uint32_t new_difference = input_size - current_length;
 5862|       |
 5863|  38.3k|  if (current_length == 0) {
  ------------------
  |  Branch (5863:7): [True: 33.8k, False: 4.49k]
  ------------------
 5864|  33.8k|    buffer.insert(start, input);
 5865|  33.8k|  } else if (input_size == current_length) {
  ------------------
  |  Branch (5865:14): [True: 1.06k, False: 3.42k]
  ------------------
 5866|  1.06k|    buffer.replace(start, input_size, input);
 5867|  3.42k|  } else if (input_size < current_length) {
  ------------------
  |  Branch (5867:14): [True: 1.27k, False: 2.15k]
  ------------------
 5868|  1.27k|    buffer.erase(start, current_length - input_size);
 5869|  1.27k|    buffer.replace(start, input_size, input);
 5870|  2.15k|  } else {
 5871|  2.15k|    buffer.replace(start, current_length, input.substr(0, current_length));
 5872|  2.15k|    buffer.insert(start + current_length, input.substr(current_length));
 5873|  2.15k|  }
 5874|       |
 5875|  38.3k|  return new_difference;
 5876|  38.3k|}
_ZNK3ada14url_aggregator19get_pathname_lengthEv:
 5907|  17.3k|url_aggregator::get_pathname_length() const noexcept {
 5908|  17.3k|  ada_log("url_aggregator::get_pathname_length");
 5909|  17.3k|  uint32_t ending_index = uint32_t(buffer.size());
 5910|  17.3k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (5910:7): [True: 147, False: 17.2k]
  ------------------
 5911|    147|    ending_index = components.search_start;
 5912|  17.2k|  } else if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (5912:14): [True: 100, False: 17.1k]
  ------------------
 5913|    100|    ending_index = components.hash_start;
 5914|    100|  }
 5915|  17.3k|  return ending_index - components.pathname_start;
 5916|  17.3k|}
_ZN3ada14url_aggregator18update_base_searchENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 5923|    809|inline void url_aggregator::update_base_search(std::string_view input) {
 5924|    809|  ada_log("url_aggregator::update_base_search ", input);
 5925|    809|  ADA_ASSERT_TRUE(validate());
 5926|    809|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 5927|    809|  if (input.empty()) {
  ------------------
  |  Branch (5927:7): [True: 779, False: 30]
  ------------------
 5928|    779|    clear_search();
 5929|    779|    return;
 5930|    779|  }
 5931|       |
 5932|     30|  if (input[0] == '?') {
  ------------------
  |  Branch (5932:7): [True: 30, False: 0]
  ------------------
 5933|     30|    input.remove_prefix(1);
 5934|     30|  }
 5935|       |
 5936|     30|  if (components.hash_start == url_components::omitted) {
  ------------------
  |  Branch (5936:7): [True: 30, False: 0]
  ------------------
 5937|     30|    if (components.search_start == url_components::omitted) {
  ------------------
  |  Branch (5937:9): [True: 30, False: 0]
  ------------------
 5938|     30|      components.search_start = uint32_t(buffer.size());
 5939|     30|      buffer += "?";
 5940|     30|    } else {
 5941|      0|      buffer.resize(components.search_start + 1);
 5942|      0|    }
 5943|       |
 5944|     30|    buffer.append(input);
 5945|     30|  } else {
 5946|      0|    if (components.search_start == url_components::omitted) {
  ------------------
  |  Branch (5946:9): [True: 0, False: 0]
  ------------------
 5947|      0|      components.search_start = components.hash_start;
 5948|      0|    } else {
 5949|      0|      buffer.erase(components.search_start,
 5950|      0|                   components.hash_start - components.search_start);
 5951|      0|      components.hash_start = components.search_start;
 5952|      0|    }
 5953|       |
 5954|      0|    buffer.insert(components.search_start, "?");
 5955|      0|    buffer.insert(components.search_start + 1, input);
 5956|      0|    components.hash_start += uint32_t(input.size() + 1);  // Do not forget `?`
 5957|      0|  }
 5958|       |
 5959|     30|  ADA_ASSERT_TRUE(validate());
 5960|     30|}
_ZN3ada14url_aggregator26update_unencoded_base_hashENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 5834|  1.67k|inline void url_aggregator::update_unencoded_base_hash(std::string_view input) {
 5835|  1.67k|  ada_log("url_aggregator::update_unencoded_base_hash ", input, " [",
 5836|  1.67k|          input.size(), " bytes], buffer is '", buffer, "' [", buffer.size(),
 5837|  1.67k|          " bytes] components.hash_start = ", components.hash_start);
 5838|  1.67k|  ADA_ASSERT_TRUE(validate());
 5839|  1.67k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 5840|  1.67k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (5840:7): [True: 127, False: 1.54k]
  ------------------
 5841|    127|    buffer.resize(components.hash_start);
 5842|    127|  }
 5843|  1.67k|  components.hash_start = uint32_t(buffer.size());
 5844|  1.67k|  buffer += "#";
 5845|  1.67k|  bool encoding_required = unicode::percent_encode<true>(
 5846|  1.67k|      input, ada::character_sets::FRAGMENT_PERCENT_ENCODE, buffer);
 5847|       |  // When encoding_required is false, then buffer is left unchanged, and percent
 5848|       |  // encoding was not deemed required.
 5849|  1.67k|  if (!encoding_required) {
  ------------------
  |  Branch (5849:7): [True: 1.19k, False: 481]
  ------------------
 5850|  1.19k|    buffer.append(input);
 5851|  1.19k|  }
 5852|  1.67k|  ada_log("url_aggregator::update_unencoded_base_hash final buffer is '",
 5853|  1.67k|          buffer, "' [", buffer.size(), " bytes]");
 5854|  1.67k|  ADA_ASSERT_TRUE(validate());
 5855|  1.67k|}
_ZN3ada14url_aggregator20append_base_passwordENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6240|  2.88k|inline void url_aggregator::append_base_password(const std::string_view input) {
 6241|  2.88k|  ada_log("url_aggregator::append_base_password ", input, " ", to_string(),
 6242|  2.88k|          "\n", to_diagram());
 6243|  2.88k|  ADA_ASSERT_TRUE(validate());
 6244|  2.88k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 6245|       |#if ADA_DEVELOPMENT_CHECKS
 6246|       |  // computing the expected password.
 6247|       |  std::string password_expected = std::string(get_password());
 6248|       |  password_expected.append(input);
 6249|       |#endif  // ADA_DEVELOPMENT_CHECKS
 6250|  2.88k|  add_authority_slashes_if_needed();
 6251|       |
 6252|       |  // If input is empty, do nothing.
 6253|  2.88k|  if (input.empty()) {
  ------------------
  |  Branch (6253:7): [True: 1.18k, False: 1.70k]
  ------------------
 6254|  1.18k|    return;
 6255|  1.18k|  }
 6256|       |
 6257|  1.70k|  uint32_t difference = uint32_t(input.size());
 6258|  1.70k|  if (has_password()) {
  ------------------
  |  Branch (6258:7): [True: 1.46k, False: 238]
  ------------------
 6259|  1.46k|    buffer.insert(components.host_start, input);
 6260|  1.46k|  } else {
 6261|    238|    difference++;  // Increment for ":"
 6262|    238|    buffer.insert(components.username_end, ":");
 6263|    238|    buffer.insert(components.username_end + 1, input);
 6264|    238|  }
 6265|  1.70k|  components.host_start += difference;
 6266|       |
 6267|       |  // The following line is required to add "@" to hostname. When updating
 6268|       |  // password if hostname does not start with "@", it is "append_base_password"s
 6269|       |  // responsibility to set it.
 6270|  1.70k|  if (buffer[components.host_start] != '@') {
  ------------------
  |  Branch (6270:7): [True: 172, False: 1.53k]
  ------------------
 6271|    172|    buffer.insert(components.host_start, "@");
 6272|    172|    difference++;
 6273|    172|  }
 6274|       |
 6275|  1.70k|  components.host_end += difference;
 6276|  1.70k|  components.pathname_start += difference;
 6277|  1.70k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6277:7): [True: 0, False: 1.70k]
  ------------------
 6278|      0|    components.search_start += difference;
 6279|      0|  }
 6280|  1.70k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6280:7): [True: 0, False: 1.70k]
  ------------------
 6281|      0|    components.hash_start += difference;
 6282|      0|  }
 6283|       |#if ADA_DEVELOPMENT_CHECKS
 6284|       |  std::string password_after = std::string(get_password());
 6285|       |  ADA_ASSERT_EQUAL(
 6286|       |      password_expected, password_after,
 6287|       |      "append_base_password problem after inserting " + std::string(input));
 6288|       |#endif  // ADA_DEVELOPMENT_CHECKS
 6289|  1.70k|  ADA_ASSERT_TRUE(validate());
 6290|  1.70k|}
_ZN3ada14url_aggregator31add_authority_slashes_if_neededEv:
 6495|  33.8k|inline void ada::url_aggregator::add_authority_slashes_if_needed() noexcept {
 6496|  33.8k|  ada_log("url_aggregator::add_authority_slashes_if_needed");
 6497|  33.8k|  ADA_ASSERT_TRUE(validate());
 6498|       |  // Protocol setter will insert `http:` to the URL. It is up to hostname setter
 6499|       |  // to insert
 6500|       |  // `//` initially to the buffer, since it depends on the hostname existence.
 6501|  33.8k|  if (has_authority()) {
  ------------------
  |  Branch (6501:7): [True: 22.7k, False: 11.0k]
  ------------------
 6502|  22.7k|    return;
 6503|  22.7k|  }
 6504|       |  // Performance: the common case is components.protocol_end == buffer.size()
 6505|       |  // Optimization opportunity: in many cases, the "//" is part of the input and
 6506|       |  // the insert could be fused with another insert.
 6507|  11.0k|  buffer.insert(components.protocol_end, "//");
 6508|  11.0k|  components.username_end += 2;
 6509|  11.0k|  components.host_start += 2;
 6510|  11.0k|  components.host_end += 2;
 6511|  11.0k|  components.pathname_start += 2;
 6512|  11.0k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6512:7): [True: 10, False: 11.0k]
  ------------------
 6513|     10|    components.search_start += 2;
 6514|     10|  }
 6515|  11.0k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6515:7): [True: 16, False: 11.0k]
  ------------------
 6516|     16|    components.hash_start += 2;
 6517|     16|  }
 6518|  11.0k|  ADA_ASSERT_TRUE(validate());
 6519|  11.0k|}
_ZN3ada14url_aggregator20append_base_usernameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6122|  7.00k|inline void url_aggregator::append_base_username(const std::string_view input) {
 6123|  7.00k|  ada_log("url_aggregator::append_base_username ", input);
 6124|  7.00k|  ADA_ASSERT_TRUE(validate());
 6125|  7.00k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 6126|       |#if ADA_DEVELOPMENT_CHECKS
 6127|       |  // computing the expected password.
 6128|       |  std::string username_expected = std::string(get_username());
 6129|       |  username_expected.append(input);
 6130|       |#endif  // ADA_DEVELOPMENT_CHECKS
 6131|  7.00k|  add_authority_slashes_if_needed();
 6132|       |
 6133|       |  // If input is empty, do nothing.
 6134|  7.00k|  if (input.empty()) {
  ------------------
  |  Branch (6134:7): [True: 2.92k, False: 4.07k]
  ------------------
 6135|  2.92k|    return;
 6136|  2.92k|  }
 6137|       |
 6138|  4.07k|  uint32_t difference = uint32_t(input.size());
 6139|  4.07k|  buffer.insert(components.username_end, input);
 6140|  4.07k|  components.username_end += difference;
 6141|  4.07k|  components.host_start += difference;
 6142|       |
 6143|  4.07k|  if (buffer[components.host_start] != '@' &&
  ------------------
  |  Branch (6143:7): [True: 454, False: 3.62k]
  ------------------
 6144|  4.07k|      components.host_start != components.host_end) {
  ------------------
  |  Branch (6144:7): [True: 454, False: 0]
  ------------------
 6145|    454|    buffer.insert(components.host_start, "@");
 6146|    454|    difference++;
 6147|    454|  }
 6148|       |
 6149|  4.07k|  components.host_end += difference;
 6150|  4.07k|  components.pathname_start += difference;
 6151|  4.07k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6151:7): [True: 0, False: 4.07k]
  ------------------
 6152|      0|    components.search_start += difference;
 6153|      0|  }
 6154|  4.07k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6154:7): [True: 0, False: 4.07k]
  ------------------
 6155|      0|    components.hash_start += difference;
 6156|      0|  }
 6157|       |#if ADA_DEVELOPMENT_CHECKS
 6158|       |  std::string username_after = std::string(get_username());
 6159|       |  ADA_ASSERT_EQUAL(
 6160|       |      username_expected, username_after,
 6161|       |      "append_base_username problem after inserting " + std::string(input));
 6162|       |#endif  // ADA_DEVELOPMENT_CHECKS
 6163|  4.07k|  ADA_ASSERT_TRUE(validate());
 6164|  4.07k|}
_ZN3ada14url_aggregator21update_base_authorityENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEERKNS_14url_componentsE:
 5776|    553|    std::string_view base_buffer, const ada::url_components &base) {
 5777|    553|  std::string_view input = base_buffer.substr(
 5778|    553|      base.protocol_end, base.host_start - base.protocol_end);
 5779|    553|  ada_log("url_aggregator::update_base_authority ", input);
 5780|       |
 5781|    553|  bool input_starts_with_dash = checkers::begins_with(input, "//");
 5782|    553|  uint32_t diff = components.host_start - components.protocol_end;
 5783|       |
 5784|    553|  buffer.erase(components.protocol_end,
 5785|    553|               components.host_start - components.protocol_end);
 5786|    553|  components.username_end = components.protocol_end;
 5787|       |
 5788|    553|  if (input_starts_with_dash) {
  ------------------
  |  Branch (5788:7): [True: 448, False: 105]
  ------------------
 5789|    448|    input.remove_prefix(2);
 5790|    448|    diff += 2;  // add "//"
 5791|    448|    buffer.insert(components.protocol_end, "//");
 5792|    448|    components.username_end += 2;
 5793|    448|  }
 5794|       |
 5795|    553|  size_t password_delimiter = input.find(':');
 5796|       |
 5797|       |  // Check if input contains both username and password by checking the
 5798|       |  // delimiter: ":" A typical input that contains authority would be "user:pass"
 5799|    553|  if (password_delimiter != std::string_view::npos) {
  ------------------
  |  Branch (5799:7): [True: 20, False: 533]
  ------------------
 5800|       |    // Insert both username and password
 5801|     20|    std::string_view username = input.substr(0, password_delimiter);
 5802|     20|    std::string_view password = input.substr(password_delimiter + 1);
 5803|       |
 5804|     20|    buffer.insert(components.protocol_end + diff, username);
 5805|     20|    diff += uint32_t(username.size());
 5806|     20|    buffer.insert(components.protocol_end + diff, ":");
 5807|     20|    components.username_end = components.protocol_end + diff;
 5808|     20|    buffer.insert(components.protocol_end + diff + 1, password);
 5809|     20|    diff += uint32_t(password.size()) + 1;
 5810|    533|  } else if (!input.empty()) {
  ------------------
  |  Branch (5810:14): [True: 11, False: 522]
  ------------------
 5811|       |    // Insert only username
 5812|     11|    buffer.insert(components.protocol_end + diff, input);
 5813|     11|    components.username_end =
 5814|     11|        components.protocol_end + diff + uint32_t(input.size());
 5815|     11|    diff += uint32_t(input.size());
 5816|     11|  }
 5817|       |
 5818|    553|  components.host_start += diff;
 5819|       |
 5820|    553|  if (buffer.size() > base.host_start && buffer[base.host_start] != '@') {
  ------------------
  |  Branch (5820:7): [True: 0, False: 553]
  |  Branch (5820:42): [True: 0, False: 0]
  ------------------
 5821|      0|    buffer.insert(components.host_start, "@");
 5822|      0|    diff++;
 5823|      0|  }
 5824|    553|  components.host_end += diff;
 5825|    553|  components.pathname_start += diff;
 5826|    553|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (5826:7): [True: 0, False: 553]
  ------------------
 5827|      0|    components.search_start += diff;
 5828|      0|  }
 5829|    553|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (5829:7): [True: 0, False: 553]
  ------------------
 5830|      0|    components.hash_start += diff;
 5831|      0|  }
 5832|    553|}
_ZNK3ada14url_aggregator8get_hrefEv:
 6587|    553|inline std::string_view url_aggregator::get_href() const noexcept {
 6588|    553|  ada_log("url_aggregator::get_href");
 6589|    553|  return buffer;
 6590|    553|}
_ZNK3ada14url_aggregator14get_componentsEv:
 6482|    553|url_aggregator::get_components() const noexcept {
 6483|    553|  return components;
 6484|    553|}
_ZN3ada14url_aggregator16update_base_portEj:
 6292|  1.77k|inline void url_aggregator::update_base_port(uint32_t input) {
 6293|  1.77k|  ada_log("url_aggregator::update_base_port");
 6294|  1.77k|  ADA_ASSERT_TRUE(validate());
 6295|  1.77k|  if (input == url_components::omitted) {
  ------------------
  |  Branch (6295:7): [True: 1.10k, False: 668]
  ------------------
 6296|  1.10k|    clear_port();
 6297|  1.10k|    return;
 6298|  1.10k|  }
 6299|       |  // calling std::to_string(input.value()) is unfortunate given that the port
 6300|       |  // value is probably already available as a string.
 6301|    668|  std::string value = helpers::concat(":", std::to_string(input));
 6302|    668|  uint32_t difference = uint32_t(value.size());
 6303|       |
 6304|    668|  if (components.port != url_components::omitted) {
  ------------------
  |  Branch (6304:7): [True: 88, False: 580]
  ------------------
 6305|     88|    difference -= components.pathname_start - components.host_end;
 6306|     88|    buffer.erase(components.host_end,
 6307|     88|                 components.pathname_start - components.host_end);
 6308|     88|  }
 6309|       |
 6310|    668|  buffer.insert(components.host_end, value);
 6311|    668|  components.pathname_start += difference;
 6312|    668|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6312:7): [True: 187, False: 481]
  ------------------
 6313|    187|    components.search_start += difference;
 6314|    187|  }
 6315|    668|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6315:7): [True: 189, False: 479]
  ------------------
 6316|    189|    components.hash_start += difference;
 6317|    189|  }
 6318|    668|  components.port = input;
 6319|    668|  ADA_ASSERT_TRUE(validate());
 6320|    668|}
_ZN3ada7helpers6concatIJPKcNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEEEESA_DpT_:
 1718|    668|std::string concat(Args... args) {
 1719|    668|  std::string answer;
 1720|    668|  inner_concat(answer, args...);
 1721|    668|  return answer;
 1722|    668|}
_ZN3ada7helpers12inner_concatIPKcJNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEEEEvRSA_T_DpT0_:
 1708|  3.46k|inline void inner_concat(std::string& buffer, T t, Args... args) {
 1709|  3.46k|  buffer.append(t);
 1710|  3.46k|  return inner_concat(buffer, args...);
 1711|  3.46k|}
_ZN3ada7helpers12inner_concatINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEJEEEvRS8_T_:
 1700|  3.46k|inline void inner_concat(std::string& buffer, T t) {
 1701|  3.46k|  buffer.append(t);
 1702|  3.46k|}
_ZNK3ada14url_aggregator18retrieve_base_portEv:
 6341|    553|inline uint32_t url_aggregator::retrieve_base_port() const {
 6342|    553|  ada_log("url_aggregator::retrieve_base_port");
 6343|    553|  return components.port;
 6344|    553|}
_ZN3ada14url_aggregator12clear_searchEv:
 6346|  11.3k|inline void url_aggregator::clear_search() {
 6347|  11.3k|  ada_log("url_aggregator::clear_search");
 6348|  11.3k|  ADA_ASSERT_TRUE(validate());
 6349|  11.3k|  if (components.search_start == url_components::omitted) {
  ------------------
  |  Branch (6349:7): [True: 10.0k, False: 1.21k]
  ------------------
 6350|  10.0k|    return;
 6351|  10.0k|  }
 6352|       |
 6353|  1.21k|  if (components.hash_start == url_components::omitted) {
  ------------------
  |  Branch (6353:7): [True: 117, False: 1.10k]
  ------------------
 6354|    117|    buffer.resize(components.search_start);
 6355|  1.10k|  } else {
 6356|  1.10k|    buffer.erase(components.search_start,
 6357|  1.10k|                 components.hash_start - components.search_start);
 6358|  1.10k|    components.hash_start = components.search_start;
 6359|  1.10k|  }
 6360|       |
 6361|  1.21k|  components.search_start = url_components::omitted;
 6362|       |
 6363|       |#if ADA_DEVELOPMENT_CHECKS
 6364|       |  ADA_ASSERT_EQUAL(get_search(), "",
 6365|       |                   "search should have been cleared on buffer=" + buffer +
 6366|       |                       " with " + components.to_string() + "\n" + to_diagram());
 6367|       |#endif
 6368|  1.21k|  ADA_ASSERT_TRUE(validate());
 6369|  1.21k|}
_ZN3ada14url_aggregator18update_base_searchENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKh:
 5963|  1.64k|    std::string_view input, const uint8_t query_percent_encode_set[]) {
 5964|  1.64k|  ada_log("url_aggregator::update_base_search ", input,
 5965|  1.64k|          " with encoding parameter ", to_string(), "\n", to_diagram());
 5966|  1.64k|  ADA_ASSERT_TRUE(validate());
 5967|  1.64k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 5968|       |
 5969|  1.64k|  if (components.hash_start == url_components::omitted) {
  ------------------
  |  Branch (5969:7): [True: 1.51k, False: 127]
  ------------------
 5970|  1.51k|    if (components.search_start == url_components::omitted) {
  ------------------
  |  Branch (5970:9): [True: 1.45k, False: 56]
  ------------------
 5971|  1.45k|      components.search_start = uint32_t(buffer.size());
 5972|  1.45k|      buffer += "?";
 5973|  1.45k|    } else {
 5974|     56|      buffer.resize(components.search_start + 1);
 5975|     56|    }
 5976|       |
 5977|  1.51k|    bool encoding_required =
 5978|  1.51k|        unicode::percent_encode<true>(input, query_percent_encode_set, buffer);
 5979|       |    // When encoding_required is false, then buffer is left unchanged, and
 5980|       |    // percent encoding was not deemed required.
 5981|  1.51k|    if (!encoding_required) {
  ------------------
  |  Branch (5981:9): [True: 1.04k, False: 466]
  ------------------
 5982|  1.04k|      buffer.append(input);
 5983|  1.04k|    }
 5984|  1.51k|  } else {
 5985|    127|    if (components.search_start == url_components::omitted) {
  ------------------
  |  Branch (5985:9): [True: 82, False: 45]
  ------------------
 5986|     82|      components.search_start = components.hash_start;
 5987|     82|    } else {
 5988|     45|      buffer.erase(components.search_start,
 5989|     45|                   components.hash_start - components.search_start);
 5990|     45|      components.hash_start = components.search_start;
 5991|     45|    }
 5992|       |
 5993|    127|    buffer.insert(components.search_start, "?");
 5994|    127|    size_t idx =
 5995|    127|        ada::unicode::percent_encode_index(input, query_percent_encode_set);
 5996|    127|    if (idx == input.size()) {
  ------------------
  |  Branch (5996:9): [True: 50, False: 77]
  ------------------
 5997|     50|      buffer.insert(components.search_start + 1, input);
 5998|     50|      components.hash_start += uint32_t(input.size() + 1);  // Do not forget `?`
 5999|     77|    } else {
 6000|     77|      buffer.insert(components.search_start + 1, input, 0, idx);
 6001|     77|      input.remove_prefix(idx);
 6002|       |      // We only create a temporary string if we need percent encoding and
 6003|       |      // we attempt to create as small a temporary string as we can.
 6004|     77|      std::string encoded =
 6005|     77|          ada::unicode::percent_encode(input, query_percent_encode_set);
 6006|     77|      buffer.insert(components.search_start + idx + 1, encoded);
 6007|     77|      components.hash_start +=
 6008|     77|          uint32_t(encoded.size() + idx + 1);  // Do not forget `?`
 6009|     77|    }
 6010|    127|  }
 6011|       |
 6012|  1.64k|  ADA_ASSERT_TRUE(validate());
 6013|  1.64k|}
_ZN3ada14url_aggregator20update_base_hostnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 5878|  15.7k|inline void url_aggregator::update_base_hostname(const std::string_view input) {
 5879|  15.7k|  ada_log("url_aggregator::update_base_hostname ", input, " [", input.size(),
 5880|  15.7k|          " bytes], buffer is '", buffer, "' [", buffer.size(), " bytes]");
 5881|  15.7k|  ADA_ASSERT_TRUE(validate());
 5882|  15.7k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 5883|       |
 5884|       |  // This next line is required for when parsing a URL like `foo://`
 5885|  15.7k|  add_authority_slashes_if_needed();
 5886|       |
 5887|  15.7k|  bool has_credentials = components.protocol_end + 2 < components.host_start;
 5888|  15.7k|  uint32_t new_difference =
 5889|  15.7k|      replace_and_resize(components.host_start, components.host_end, input);
 5890|       |
 5891|  15.7k|  if (has_credentials) {
  ------------------
  |  Branch (5891:7): [True: 1.59k, False: 14.1k]
  ------------------
 5892|  1.59k|    buffer.insert(components.host_start, "@");
 5893|  1.59k|    new_difference++;
 5894|  1.59k|  }
 5895|  15.7k|  components.host_end += new_difference;
 5896|  15.7k|  components.pathname_start += new_difference;
 5897|  15.7k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (5897:7): [True: 146, False: 15.5k]
  ------------------
 5898|    146|    components.search_start += new_difference;
 5899|    146|  }
 5900|  15.7k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (5900:7): [True: 173, False: 15.5k]
  ------------------
 5901|    173|    components.hash_start += new_difference;
 5902|    173|  }
 5903|  15.7k|  ADA_ASSERT_TRUE(validate());
 5904|  15.7k|}
_ZN3ada14url_aggregator10parse_portENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEb:
 6593|  1.56k|    std::string_view view, bool check_trailing_content) noexcept {
 6594|  1.56k|  ada_log("url_aggregator::parse_port('", view, "') ", view.size());
 6595|  1.56k|  uint16_t parsed_port{};
 6596|  1.56k|  auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port);
 6597|  1.56k|  if (r.ec == std::errc::result_out_of_range) {
  ------------------
  |  Branch (6597:7): [True: 56, False: 1.50k]
  ------------------
 6598|     56|    ada_log("parse_port: std::errc::result_out_of_range");
 6599|     56|    is_valid = false;
 6600|     56|    return 0;
 6601|     56|  }
 6602|  1.50k|  ada_log("parse_port: ", parsed_port);
 6603|  1.50k|  const size_t consumed = size_t(r.ptr - view.data());
 6604|  1.50k|  ada_log("parse_port: consumed ", consumed);
 6605|  1.50k|  if (check_trailing_content) {
  ------------------
  |  Branch (6605:7): [True: 1.13k, False: 371]
  ------------------
 6606|  1.13k|    is_valid &=
 6607|  1.13k|        (consumed == view.size() || view[consumed] == '/' ||
  ------------------
  |  Branch (6607:10): [True: 898, False: 238]
  |  Branch (6607:37): [True: 47, False: 191]
  ------------------
 6608|  1.13k|         view[consumed] == '?' || (is_special() && view[consumed] == '\\'));
  ------------------
  |  Branch (6608:10): [True: 102, False: 89]
  |  Branch (6608:36): [True: 83, False: 6]
  |  Branch (6608:52): [True: 2, False: 81]
  ------------------
 6609|  1.13k|  }
 6610|  1.50k|  ada_log("parse_port: is_valid = ", is_valid);
 6611|  1.50k|  if (is_valid) {
  ------------------
  |  Branch (6611:7): [True: 1.33k, False: 171]
  ------------------
 6612|  1.33k|    ada_log("parse_port", r.ec == std::errc());
 6613|       |    // scheme_default_port can return 0, and we should allow 0 as a base port.
 6614|  1.33k|    auto default_port = scheme_default_port();
 6615|  1.33k|    bool is_port_valid = (default_port == 0 && parsed_port == 0) ||
  ------------------
  |  Branch (6615:27): [True: 197, False: 1.13k]
  |  Branch (6615:48): [True: 84, False: 113]
  ------------------
 6616|  1.33k|                         (default_port != parsed_port);
  ------------------
  |  Branch (6616:26): [True: 1.24k, False: 8]
  ------------------
 6617|  1.33k|    if (r.ec == std::errc() && is_port_valid) {
  ------------------
  |  Branch (6617:9): [True: 609, False: 727]
  |  Branch (6617:32): [True: 601, False: 8]
  ------------------
 6618|    601|      update_base_port(parsed_port);
 6619|    735|    } else {
 6620|    735|      clear_port();
 6621|    735|    }
 6622|  1.33k|  }
 6623|  1.50k|  return consumed;
 6624|  1.56k|}
_ZN3ada14url_aggregator20append_base_pathnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6051|      4|inline void url_aggregator::append_base_pathname(const std::string_view input) {
 6052|      4|  ada_log("url_aggregator::append_base_pathname ", input, " ", to_string(),
 6053|      4|          "\n", to_diagram());
 6054|      4|  ADA_ASSERT_TRUE(validate());
 6055|      4|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 6056|       |#if ADA_DEVELOPMENT_CHECKS
 6057|       |  // computing the expected password.
 6058|       |  std::string path_expected = std::string(get_pathname());
 6059|       |  path_expected.append(input);
 6060|       |#endif  // ADA_DEVELOPMENT_CHECKS
 6061|      4|  uint32_t ending_index = uint32_t(buffer.size());
 6062|      4|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6062:7): [True: 0, False: 4]
  ------------------
 6063|      0|    ending_index = components.search_start;
 6064|      4|  } else if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6064:14): [True: 0, False: 4]
  ------------------
 6065|      0|    ending_index = components.hash_start;
 6066|      0|  }
 6067|      4|  buffer.insert(ending_index, input);
 6068|       |
 6069|      4|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6069:7): [True: 0, False: 4]
  ------------------
 6070|      0|    components.search_start += uint32_t(input.size());
 6071|      0|  }
 6072|      4|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6072:7): [True: 0, False: 4]
  ------------------
 6073|      0|    components.hash_start += uint32_t(input.size());
 6074|      0|  }
 6075|       |#if ADA_DEVELOPMENT_CHECKS
 6076|       |  std::string path_after = std::string(get_pathname());
 6077|       |  ADA_ASSERT_EQUAL(
 6078|       |      path_expected, path_after,
 6079|       |      "append_base_pathname problem after inserting " + std::string(input));
 6080|       |#endif  // ADA_DEVELOPMENT_CHECKS
 6081|      4|  ADA_ASSERT_TRUE(validate());
 6082|      4|}
_ZN3ada14url_aggregator20set_protocol_as_fileEv:
 6626|  3.22k|inline void url_aggregator::set_protocol_as_file() {
 6627|  3.22k|  ada_log("url_aggregator::set_protocol_as_file ");
 6628|  3.22k|  ADA_ASSERT_TRUE(validate());
 6629|  3.22k|  type = ada::scheme::type::FILE;
 6630|       |  // next line could overflow but unsigned arithmetic has well-defined
 6631|       |  // overflows.
 6632|  3.22k|  uint32_t new_difference = 5 - components.protocol_end;
 6633|       |
 6634|  3.22k|  if (buffer.empty()) {
  ------------------
  |  Branch (6634:7): [True: 369, False: 2.85k]
  ------------------
 6635|    369|    buffer.append("file:");
 6636|  2.85k|  } else {
 6637|  2.85k|    buffer.erase(0, components.protocol_end);
 6638|  2.85k|    buffer.insert(0, "file:");
 6639|  2.85k|  }
 6640|  3.22k|  components.protocol_end = 5;
 6641|       |
 6642|       |  // Update the rest of the components.
 6643|  3.22k|  components.username_end += new_difference;
 6644|  3.22k|  components.host_start += new_difference;
 6645|  3.22k|  components.host_end += new_difference;
 6646|  3.22k|  components.pathname_start += new_difference;
 6647|  3.22k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6647:7): [True: 0, False: 3.22k]
  ------------------
 6648|      0|    components.search_start += new_difference;
 6649|      0|  }
 6650|  3.22k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6650:7): [True: 0, False: 3.22k]
  ------------------
 6651|      0|    components.hash_start += new_difference;
 6652|      0|  }
 6653|  3.22k|  ADA_ASSERT_TRUE(validate());
 6654|  3.22k|}
_ZN3ada14url_aggregator14clear_pathnameEv:
 6388|  4.98k|inline void url_aggregator::clear_pathname() {
 6389|  4.98k|  ada_log("url_aggregator::clear_pathname");
 6390|  4.98k|  ADA_ASSERT_TRUE(validate());
 6391|  4.98k|  uint32_t ending_index = uint32_t(buffer.size());
 6392|  4.98k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6392:7): [True: 164, False: 4.82k]
  ------------------
 6393|    164|    ending_index = components.search_start;
 6394|  4.82k|  } else if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6394:14): [True: 112, False: 4.71k]
  ------------------
 6395|    112|    ending_index = components.hash_start;
 6396|    112|  }
 6397|  4.98k|  uint32_t pathname_length = ending_index - components.pathname_start;
 6398|  4.98k|  buffer.erase(components.pathname_start, pathname_length);
 6399|  4.98k|  uint32_t difference = pathname_length;
 6400|  4.98k|  if (components.pathname_start == components.host_end + 2 &&
  ------------------
  |  Branch (6400:7): [True: 83, False: 4.90k]
  ------------------
 6401|  4.98k|      buffer[components.host_end] == '/' &&
  ------------------
  |  Branch (6401:7): [True: 2, False: 81]
  ------------------
 6402|  4.98k|      buffer[components.host_end + 1] == '.') {
  ------------------
  |  Branch (6402:7): [True: 2, False: 0]
  ------------------
 6403|      2|    components.pathname_start -= 2;
 6404|      2|    buffer.erase(components.host_end, 2);
 6405|      2|    difference += 2;
 6406|      2|  }
 6407|  4.98k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6407:7): [True: 164, False: 4.82k]
  ------------------
 6408|    164|    components.search_start -= difference;
 6409|    164|  }
 6410|  4.98k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6410:7): [True: 165, False: 4.82k]
  ------------------
 6411|    165|    components.hash_start -= difference;
 6412|    165|  }
 6413|  4.98k|  ada_log("url_aggregator::clear_pathname completed, running checks...");
 6414|       |#if ADA_DEVELOPMENT_CHECKS
 6415|       |  ADA_ASSERT_EQUAL(get_pathname(), "",
 6416|       |                   "pathname should have been cleared on buffer=" + buffer +
 6417|       |                       " with " + components.to_string() + "\n" + to_diagram());
 6418|       |#endif
 6419|  4.98k|  ADA_ASSERT_TRUE(validate());
 6420|  4.98k|  ada_log("url_aggregator::clear_pathname completed, running checks... ok");
 6421|  4.98k|}
_ZNK3ada14url_aggregator31cannot_have_credentials_or_portEv:
 6475|  17.1k|inline bool url_aggregator::cannot_have_credentials_or_port() const {
 6476|  17.1k|  ada_log("url_aggregator::cannot_have_credentials_or_port");
 6477|  17.1k|  return type == ada::scheme::type::FILE ||
  ------------------
  |  Branch (6477:10): [True: 3.08k, False: 14.1k]
  ------------------
 6478|  17.1k|         components.host_start == components.host_end;
  ------------------
  |  Branch (6478:10): [True: 5.12k, False: 8.98k]
  ------------------
 6479|  17.1k|}
_ZN3ada7unicode20percent_encode_indexENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKh:
 5758|  6.71k|                                              const uint8_t character_set[]) {
 5759|  6.71k|  return std::distance(
 5760|  6.71k|      input.begin(),
 5761|  6.71k|      std::find_if(input.begin(), input.end(), [character_set](const char c) {
 5762|  6.71k|        return character_sets::bit_at(character_set, c);
 5763|  6.71k|      }));
 5764|  6.71k|}
_ZZN3ada7unicode20percent_encode_indexENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKhENKUlcE_clEc:
 5761|  17.1k|      std::find_if(input.begin(), input.end(), [character_set](const char c) {
 5762|  17.1k|        return character_sets::bit_at(character_set, c);
 5763|  17.1k|      }));
_ZN3ada14url_aggregator20update_base_usernameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6084|  5.25k|inline void url_aggregator::update_base_username(const std::string_view input) {
 6085|  5.25k|  ada_log("url_aggregator::update_base_username '", input, "' ", to_string(),
 6086|  5.25k|          "\n", to_diagram());
 6087|  5.25k|  ADA_ASSERT_TRUE(validate());
 6088|  5.25k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 6089|       |
 6090|  5.25k|  add_authority_slashes_if_needed();
 6091|       |
 6092|  5.25k|  bool has_password = has_non_empty_password();
 6093|  5.25k|  bool host_starts_with_at = buffer.size() > components.host_start &&
  ------------------
  |  Branch (6093:30): [True: 5.25k, False: 0]
  ------------------
 6094|  5.25k|                             buffer[components.host_start] == '@';
  ------------------
  |  Branch (6094:30): [True: 140, False: 5.11k]
  ------------------
 6095|  5.25k|  uint32_t diff = replace_and_resize(components.protocol_end + 2,
 6096|  5.25k|                                     components.username_end, input);
 6097|       |
 6098|  5.25k|  components.username_end += diff;
 6099|  5.25k|  components.host_start += diff;
 6100|       |
 6101|  5.25k|  if (!input.empty() && !host_starts_with_at) {
  ------------------
  |  Branch (6101:7): [True: 638, False: 4.61k]
  |  Branch (6101:25): [True: 605, False: 33]
  ------------------
 6102|    605|    buffer.insert(components.host_start, "@");
 6103|    605|    diff++;
 6104|  4.64k|  } else if (input.empty() && host_starts_with_at && !has_password) {
  ------------------
  |  Branch (6104:14): [True: 4.61k, False: 33]
  |  Branch (6104:31): [True: 107, False: 4.50k]
  |  Branch (6104:54): [True: 71, False: 36]
  ------------------
 6105|       |    // Input is empty, there is no password, and we need to remove "@" from
 6106|       |    // hostname
 6107|     71|    buffer.erase(components.host_start, 1);
 6108|     71|    diff--;
 6109|     71|  }
 6110|       |
 6111|  5.25k|  components.host_end += diff;
 6112|  5.25k|  components.pathname_start += diff;
 6113|  5.25k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6113:7): [True: 171, False: 5.08k]
  ------------------
 6114|    171|    components.search_start += diff;
 6115|    171|  }
 6116|  5.25k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6116:7): [True: 160, False: 5.09k]
  ------------------
 6117|    160|    components.hash_start += diff;
 6118|    160|  }
 6119|  5.25k|  ADA_ASSERT_TRUE(validate());
 6120|  5.25k|}
_ZN3ada14url_aggregator20update_base_passwordENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6186|  2.94k|inline void url_aggregator::update_base_password(const std::string_view input) {
 6187|  2.94k|  ada_log("url_aggregator::update_base_password ", input);
 6188|  2.94k|  ADA_ASSERT_TRUE(validate());
 6189|  2.94k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 6190|       |
 6191|  2.94k|  add_authority_slashes_if_needed();
 6192|       |
 6193|       |  // TODO: Optimization opportunity. Merge the following removal functions.
 6194|  2.94k|  if (input.empty()) {
  ------------------
  |  Branch (6194:7): [True: 2.30k, False: 638]
  ------------------
 6195|  2.30k|    clear_password();
 6196|       |
 6197|       |    // Remove username too, if it is empty.
 6198|  2.30k|    if (!has_non_empty_username()) {
  ------------------
  |  Branch (6198:9): [True: 2.30k, False: 0]
  ------------------
 6199|  2.30k|      update_base_username("");
 6200|  2.30k|    }
 6201|       |
 6202|  2.30k|    return;
 6203|  2.30k|  }
 6204|       |
 6205|    638|  bool password_exists = has_password();
 6206|    638|  uint32_t difference = uint32_t(input.size());
 6207|       |
 6208|    638|  if (password_exists) {
  ------------------
  |  Branch (6208:7): [True: 8, False: 630]
  ------------------
 6209|      8|    uint32_t current_length =
 6210|      8|        components.host_start - components.username_end - 1;
 6211|      8|    buffer.erase(components.username_end + 1, current_length);
 6212|      8|    difference -= current_length;
 6213|    630|  } else {
 6214|    630|    buffer.insert(components.username_end, ":");
 6215|    630|    difference++;
 6216|    630|  }
 6217|       |
 6218|    638|  buffer.insert(components.username_end + 1, input);
 6219|    638|  components.host_start += difference;
 6220|       |
 6221|       |  // The following line is required to add "@" to hostname. When updating
 6222|       |  // password if hostname does not start with "@", it is "update_base_password"s
 6223|       |  // responsibility to set it.
 6224|    638|  if (buffer[components.host_start] != '@') {
  ------------------
  |  Branch (6224:7): [True: 0, False: 638]
  ------------------
 6225|      0|    buffer.insert(components.host_start, "@");
 6226|      0|    difference++;
 6227|      0|  }
 6228|       |
 6229|    638|  components.host_end += difference;
 6230|    638|  components.pathname_start += difference;
 6231|    638|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6231:7): [True: 81, False: 557]
  ------------------
 6232|     81|    components.search_start += difference;
 6233|     81|  }
 6234|    638|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6234:7): [True: 90, False: 548]
  ------------------
 6235|     90|    components.hash_start += difference;
 6236|     90|  }
 6237|    638|  ADA_ASSERT_TRUE(validate());
 6238|    638|}
_ZN3ada14url_aggregator14clear_passwordEv:
 6166|  2.30k|inline void url_aggregator::clear_password() {
 6167|  2.30k|  ada_log("url_aggregator::clear_password ", to_string(), "\n", to_diagram());
 6168|  2.30k|  ADA_ASSERT_TRUE(validate());
 6169|  2.30k|  if (!has_password()) {
  ------------------
  |  Branch (6169:7): [True: 2.27k, False: 36]
  ------------------
 6170|  2.27k|    return;
 6171|  2.27k|  }
 6172|       |
 6173|     36|  uint32_t diff = components.host_start - components.username_end;
 6174|     36|  buffer.erase(components.username_end, diff);
 6175|     36|  components.host_start -= diff;
 6176|     36|  components.host_end -= diff;
 6177|     36|  components.pathname_start -= diff;
 6178|     36|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6178:7): [True: 10, False: 26]
  ------------------
 6179|     10|    components.search_start -= diff;
 6180|     10|  }
 6181|     36|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6181:7): [True: 9, False: 27]
  ------------------
 6182|      9|    components.hash_start -= diff;
 6183|      9|  }
 6184|     36|}
_ZN3ada14url_aggregator10clear_portEv:
 6322|  9.81k|inline void url_aggregator::clear_port() {
 6323|  9.81k|  ada_log("url_aggregator::clear_port");
 6324|  9.81k|  ADA_ASSERT_TRUE(validate());
 6325|  9.81k|  if (components.port == url_components::omitted) {
  ------------------
  |  Branch (6325:7): [True: 9.45k, False: 361]
  ------------------
 6326|  9.45k|    return;
 6327|  9.45k|  }
 6328|    361|  uint32_t length = components.pathname_start - components.host_end;
 6329|    361|  buffer.erase(components.host_end, length);
 6330|    361|  components.pathname_start -= length;
 6331|    361|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6331:7): [True: 263, False: 98]
  ------------------
 6332|    263|    components.search_start -= length;
 6333|    263|  }
 6334|    361|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6334:7): [True: 279, False: 82]
  ------------------
 6335|    279|    components.hash_start -= length;
 6336|    279|  }
 6337|    361|  components.port = url_components::omitted;
 6338|    361|  ADA_ASSERT_TRUE(validate());
 6339|    361|}
_ZNK3ada14url_aggregator13has_authorityEv:
 6486|  40.9k|[[nodiscard]] inline bool ada::url_aggregator::has_authority() const noexcept {
 6487|  40.9k|  ada_log("url_aggregator::has_authority");
 6488|       |  // Performance: instead of doing this potentially expensive check, we could
 6489|       |  // have a boolean in the struct.
 6490|  40.9k|  return components.protocol_end + 2 <= components.host_start &&
  ------------------
  |  Branch (6490:10): [True: 25.4k, False: 15.5k]
  ------------------
 6491|  40.9k|         helpers::substring(buffer, components.protocol_end,
  ------------------
  |  Branch (6491:10): [True: 25.4k, False: 0]
  ------------------
 6492|  25.4k|                            components.protocol_end + 2) == "//";
 6493|  40.9k|}
_ZNK3ada14url_aggregator12has_dash_dotEv:
 6566|  20.3k|inline bool url_aggregator::has_dash_dot() const noexcept {
 6567|       |  // If url's host is null, url does not have an opaque path, url's path's size
 6568|       |  // is greater than 1, and url's path[0] is the empty string, then append
 6569|       |  // U+002F (/) followed by U+002E (.) to output.
 6570|  20.3k|  ada_log("url_aggregator::has_dash_dot");
 6571|       |  // Performance: instead of doing this potentially expensive check, we could
 6572|       |  // just have a boolean value in the structure.
 6573|       |#if ADA_DEVELOPMENT_CHECKS
 6574|       |  if (components.pathname_start + 1 < buffer.size() &&
 6575|       |      components.pathname_start == components.host_end + 2) {
 6576|       |    ADA_ASSERT_TRUE(buffer[components.host_end] == '/');
 6577|       |    ADA_ASSERT_TRUE(buffer[components.host_end + 1] == '.');
 6578|       |    ADA_ASSERT_TRUE(buffer[components.pathname_start] == '/');
 6579|       |    ADA_ASSERT_TRUE(buffer[components.pathname_start + 1] == '/');
 6580|       |  }
 6581|       |#endif
 6582|  20.3k|  return !has_opaque_path &&
  ------------------
  |  Branch (6582:10): [True: 16.8k, False: 3.46k]
  ------------------
 6583|  20.3k|         components.pathname_start == components.host_end + 2 &&
  ------------------
  |  Branch (6583:10): [True: 260, False: 16.6k]
  ------------------
 6584|  20.3k|         components.pathname_start + 1 < buffer.size();
  ------------------
  |  Branch (6584:10): [True: 113, False: 147]
  ------------------
 6585|  20.3k|}
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEptEv:
 3788|   125k|  TL_EXPECTED_11_CONSTEXPR T *operator->() {
 3789|   125k|    TL_ASSERT(has_value());
  ------------------
  |  | 1835|   125k|#define TL_ASSERT(x) assert(x)
  ------------------
 3790|      0|    return valptr();
 3791|   125k|  }
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEE6valptrEv:
 3076|   125k|  T *valptr() { return std::addressof(this->m_val); }
_ZNK3ada14url_aggregator22has_non_empty_usernameEv:
 6525|  10.0k|inline bool url_aggregator::has_non_empty_username() const noexcept {
 6526|  10.0k|  ada_log("url_aggregator::has_non_empty_username");
 6527|  10.0k|  return components.protocol_end + 2 < components.username_end;
 6528|  10.0k|}
_ZN3ada7helpers9substringERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEmm:
 1628|  87.5k|                                             size_t pos2) noexcept {
 1629|       |#if ADA_DEVELOPMENT_CHECKS
 1630|       |  if (pos2 < pos1) {
 1631|       |    std::cerr << "Negative-length substring: [" << pos1 << " to " << pos2 << ")"
 1632|       |              << std::endl;
 1633|       |    abort();
 1634|       |  }
 1635|       |#endif
 1636|  87.5k|  return std::string_view(input.data() + pos1, pos2 - pos1);
 1637|  87.5k|}
_ZNK3ada14url_aggregator22has_non_empty_passwordEv:
 6530|  13.0k|inline bool url_aggregator::has_non_empty_password() const noexcept {
 6531|  13.0k|  ada_log("url_aggregator::has_non_empty_password");
 6532|  13.0k|  return components.host_start - components.username_end > 0;
 6533|  13.0k|}
_ZNK3ada14url_aggregator15has_credentialsEv:
 6470|  2.09k|ada_really_inline bool url_aggregator::has_credentials() const noexcept {
 6471|  2.09k|  ada_log("url_aggregator::has_credentials");
 6472|  2.09k|  return has_non_empty_username() || has_non_empty_password();
  ------------------
  |  Branch (6472:10): [True: 18, False: 2.07k]
  |  Branch (6472:38): [True: 4, False: 2.07k]
  ------------------
 6473|  2.09k|}
_ZNK3ada14url_aggregator10is_at_pathEv:
 5919|  3.60k|    const noexcept {
 5920|  3.60k|  return buffer.size() == components.pathname_start;
 5921|  3.60k|}
_ZN3ada14url_aggregator10clear_hashEv:
 6371|  5.68k|inline void url_aggregator::clear_hash() {
 6372|  5.68k|  ada_log("url_aggregator::clear_hash");
 6373|  5.68k|  ADA_ASSERT_TRUE(validate());
 6374|  5.68k|  if (components.hash_start == url_components::omitted) {
  ------------------
  |  Branch (6374:7): [True: 4.59k, False: 1.08k]
  ------------------
 6375|  4.59k|    return;
 6376|  4.59k|  }
 6377|  1.08k|  buffer.resize(components.hash_start);
 6378|  1.08k|  components.hash_start = url_components::omitted;
 6379|       |
 6380|       |#if ADA_DEVELOPMENT_CHECKS
 6381|       |  ADA_ASSERT_EQUAL(get_hash(), "",
 6382|       |                   "hash should have been cleared on buffer=" + buffer +
 6383|       |                       " with " + components.to_string() + "\n" + to_diagram());
 6384|       |#endif
 6385|  1.08k|  ADA_ASSERT_TRUE(validate());
 6386|  1.08k|}
_ZNK3ada14url_aggregator12has_hostnameEv:
 6555|  3.86k|inline bool url_aggregator::has_hostname() const noexcept {
 6556|  3.86k|  return has_authority();
 6557|  3.86k|}
_ZNK3ada14url_aggregator8has_portEv:
 6559|  1.93k|inline bool url_aggregator::has_port() const noexcept {
 6560|  1.93k|  ada_log("url_aggregator::has_port");
 6561|       |  // A URL cannot have a username/password/port if its host is null or the empty
 6562|       |  // string, or its scheme is "file".
 6563|  1.93k|  return has_hostname() && components.pathname_start != components.host_end;
  ------------------
  |  Branch (6563:10): [True: 170, False: 1.76k]
  |  Branch (6563:28): [True: 12, False: 158]
  ------------------
 6564|  1.93k|}
_ZNK3ada14url_aggregator12has_passwordEv:
 6535|  4.64k|inline bool url_aggregator::has_password() const noexcept {
 6536|  4.64k|  ada_log("url_aggregator::has_password");
 6537|       |  // This function does not care about the length of the password
 6538|  4.64k|  return components.host_start > components.username_end &&
  ------------------
  |  Branch (6538:10): [True: 1.50k, False: 3.13k]
  ------------------
 6539|  4.64k|         buffer[components.username_end] == ':';
  ------------------
  |  Branch (6539:10): [True: 1.50k, False: 0]
  ------------------
 6540|  4.64k|}
_ZN3ada17url_search_paramsC2ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6689|  9.85k|  url_search_params(const std::string_view input) { initialize(input); }
_ZN3ada17url_search_params10initializeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6771|  9.85k|inline void url_search_params::initialize(std::string_view input) {
 6772|  9.85k|  if (!input.empty() && input.front() == '?') {
  ------------------
  |  Branch (6772:7): [True: 2.24k, False: 7.61k]
  |  Branch (6772:25): [True: 1, False: 2.24k]
  ------------------
 6773|      1|    input.remove_prefix(1);
 6774|      1|  }
 6775|       |
 6776|  9.85k|  auto process_key_value = [&](const std::string_view current) {
 6777|  9.85k|    auto equal = current.find('=');
 6778|       |
 6779|  9.85k|    if (equal == std::string_view::npos) {
 6780|  9.85k|      auto name = std::string(current);
 6781|  9.85k|      std::replace(name.begin(), name.end(), '+', ' ');
 6782|  9.85k|      params.emplace_back(unicode::percent_decode(name, name.find('%')), "");
 6783|  9.85k|    } else {
 6784|  9.85k|      auto name = std::string(current.substr(0, equal));
 6785|  9.85k|      auto value = std::string(current.substr(equal + 1));
 6786|       |
 6787|  9.85k|      std::replace(name.begin(), name.end(), '+', ' ');
 6788|  9.85k|      std::replace(value.begin(), value.end(), '+', ' ');
 6789|       |
 6790|  9.85k|      params.emplace_back(unicode::percent_decode(name, name.find('%')),
 6791|  9.85k|                          unicode::percent_decode(value, value.find('%')));
 6792|  9.85k|    }
 6793|  9.85k|  };
 6794|       |
 6795|  11.1k|  while (!input.empty()) {
  ------------------
  |  Branch (6795:10): [True: 3.51k, False: 7.64k]
  ------------------
 6796|  3.51k|    auto ampersand_index = input.find('&');
 6797|       |
 6798|  3.51k|    if (ampersand_index == std::string_view::npos) {
  ------------------
  |  Branch (6798:9): [True: 2.21k, False: 1.30k]
  ------------------
 6799|  2.21k|      if (!input.empty()) {
  ------------------
  |  Branch (6799:11): [True: 2.21k, False: 0]
  ------------------
 6800|  2.21k|        process_key_value(input);
 6801|  2.21k|      }
 6802|  2.21k|      break;
 6803|  2.21k|    } else if (ampersand_index != 0) {
  ------------------
  |  Branch (6803:16): [True: 1.10k, False: 196]
  ------------------
 6804|  1.10k|      process_key_value(input.substr(0, ampersand_index));
 6805|  1.10k|    }
 6806|       |
 6807|  1.30k|    input.remove_prefix(ampersand_index + 1);
 6808|  1.30k|  }
 6809|  9.85k|}
_ZZN3ada17url_search_params10initializeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlS5_E_clES5_:
 6776|  3.32k|  auto process_key_value = [&](const std::string_view current) {
 6777|  3.32k|    auto equal = current.find('=');
 6778|       |
 6779|  3.32k|    if (equal == std::string_view::npos) {
  ------------------
  |  Branch (6779:9): [True: 2.65k, False: 661]
  ------------------
 6780|  2.65k|      auto name = std::string(current);
 6781|  2.65k|      std::replace(name.begin(), name.end(), '+', ' ');
 6782|  2.65k|      params.emplace_back(unicode::percent_decode(name, name.find('%')), "");
 6783|  2.65k|    } else {
 6784|    661|      auto name = std::string(current.substr(0, equal));
 6785|    661|      auto value = std::string(current.substr(equal + 1));
 6786|       |
 6787|    661|      std::replace(name.begin(), name.end(), '+', ' ');
 6788|    661|      std::replace(value.begin(), value.end(), '+', ' ');
 6789|       |
 6790|    661|      params.emplace_back(unicode::percent_decode(name, name.find('%')),
 6791|    661|                          unicode::percent_decode(value, value.find('%')));
 6792|    661|    }
 6793|  3.32k|  };
_ZN3ada17url_search_paramsC2Ev:
 6683|  9.85k|  url_search_params() = default;
_ZN3ada17url_search_params6appendENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_:
 6812|  19.6k|                                      const std::string_view value) {
 6813|  19.6k|  params.emplace_back(key, value);
 6814|  19.6k|}
_ZN3ada17url_search_params3setENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_:
 6880|  9.85k|                                   const std::string_view value) {
 6881|  9.85k|  const auto find = [&key](auto &param) { return param.first == key; };
 6882|       |
 6883|  9.85k|  auto it = std::find_if(params.begin(), params.end(), find);
 6884|       |
 6885|  9.85k|  if (it == params.end()) {
  ------------------
  |  Branch (6885:7): [True: 0, False: 9.85k]
  ------------------
 6886|      0|    params.emplace_back(key, value);
 6887|  9.85k|  } else {
 6888|  9.85k|    it->second = value;
 6889|  9.85k|    params.erase(std::remove_if(std::next(it), params.end(), find),
 6890|  9.85k|                 params.end());
 6891|  9.85k|  }
 6892|  9.85k|}
_ZZN3ada17url_search_params3setENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_ENKUlRT_E_clINS1_4pairINS1_12basic_stringIcS4_NS1_9allocatorIcEEEESE_EEEEDaS7_:
 6881|  9.85k|  const auto find = [&key](auto &param) { return param.first == key; };
_ZN3ada17url_search_params9to_stringEv:
 6858|  9.85k|inline std::string url_search_params::to_string() {
 6859|  9.85k|  auto character_set = ada::character_sets::WWW_FORM_URLENCODED_PERCENT_ENCODE;
 6860|  9.85k|  std::string out{};
 6861|  19.7k|  for (size_t i = 0; i < params.size(); i++) {
  ------------------
  |  Branch (6861:22): [True: 9.85k, False: 9.85k]
  ------------------
 6862|  9.85k|    auto key = ada::unicode::percent_encode(params[i].first, character_set);
 6863|  9.85k|    auto value = ada::unicode::percent_encode(params[i].second, character_set);
 6864|       |
 6865|       |    // Performance optimization: Move this inside percent_encode.
 6866|  9.85k|    std::replace(key.begin(), key.end(), ' ', '+');
 6867|  9.85k|    std::replace(value.begin(), value.end(), ' ', '+');
 6868|       |
 6869|  9.85k|    if (i != 0) {
  ------------------
  |  Branch (6869:9): [True: 0, False: 9.85k]
  ------------------
 6870|      0|      out += "&";
 6871|      0|    }
 6872|  9.85k|    out.append(key);
 6873|  9.85k|    out += "=";
 6874|  9.85k|    out.append(value);
 6875|  9.85k|  }
 6876|  9.85k|  return out;
 6877|  9.85k|}
_ZN3ada17url_search_params3hasENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6843|  9.85k|inline bool url_search_params::has(const std::string_view key) noexcept {
 6844|  9.85k|  auto entry = std::find_if(params.begin(), params.end(),
 6845|  9.85k|                            [&key](auto &param) { return param.first == key; });
 6846|  9.85k|  return entry != params.end();
 6847|  9.85k|}
_ZZN3ada17url_search_params3hasENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlRT_E_clINS1_4pairINS1_12basic_stringIcS4_NS1_9allocatorIcEEEESE_EEEEDaS7_:
 6845|  9.85k|                            [&key](auto &param) { return param.first == key; });
_ZN3ada17url_search_params6removeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6894|  19.6k|inline void url_search_params::remove(const std::string_view key) {
 6895|  19.6k|  params.erase(
 6896|  19.6k|      std::remove_if(params.begin(), params.end(),
 6897|  19.6k|                     [&key](auto &param) { return param.first == key; }),
 6898|  19.6k|      params.end());
 6899|  19.6k|}
_ZZN3ada17url_search_params6removeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlRT_E_clINS1_4pairINS1_12basic_stringIcS4_NS1_9allocatorIcEEEESE_EEEEDaS7_:
 6897|  29.4k|                     [&key](auto &param) { return param.first == key; }),
_ZN3ada17url_search_params6removeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_:
 6902|  19.6k|                                      const std::string_view value) {
 6903|  19.6k|  params.erase(std::remove_if(params.begin(), params.end(),
 6904|  19.6k|                              [&key, &value](auto &param) {
 6905|  19.6k|                                return param.first == key &&
 6906|  19.6k|                                       param.second == value;
 6907|  19.6k|                              }),
 6908|  19.6k|               params.end());
 6909|  19.6k|}
_ZZN3ada17url_search_params6removeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_ENKUlRT_E_clINS1_4pairINS1_12basic_stringIcS4_NS1_9allocatorIcEEEESE_EEEEDaS7_:
 6904|  9.81k|                              [&key, &value](auto &param) {
 6905|  9.81k|                                return param.first == key &&
  ------------------
  |  Branch (6905:40): [True: 0, False: 9.81k]
  ------------------
 6906|  9.81k|                                       param.second == value;
  ------------------
  |  Branch (6906:40): [True: 0, False: 0]
  ------------------
 6907|  9.81k|                              }),
_ZN3ada17url_search_params3hasENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_:
 6850|  9.85k|                                   std::string_view value) noexcept {
 6851|  9.85k|  auto entry =
 6852|  9.85k|      std::find_if(params.begin(), params.end(), [&key, &value](auto &param) {
 6853|  9.85k|        return param.first == key && param.second == value;
 6854|  9.85k|      });
 6855|  9.85k|  return entry != params.end();
 6856|  9.85k|}
_ZZN3ada17url_search_params3hasENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_ENKUlRT_E_clINS1_4pairINS1_12basic_stringIcS4_NS1_9allocatorIcEEEESE_EEEEDaS7_:
 6852|  9.81k|      std::find_if(params.begin(), params.end(), [&key, &value](auto &param) {
 6853|  9.81k|        return param.first == key && param.second == value;
  ------------------
  |  Branch (6853:16): [True: 9.81k, False: 0]
  |  Branch (6853:38): [True: 9.81k, False: 0]
  ------------------
 6854|  9.81k|      });
_ZN3ada17url_search_paramsD2Ev:
 6695|  19.7k|  ~url_search_params() = default;
_ZNK3ada3url8has_hashEv:
 5640|  1.18k|[[nodiscard]] inline bool url::has_hash() const noexcept {
 5641|  1.18k|  return hash.has_value();
 5642|  1.18k|}
_ZNK3ada3url10has_searchEv:
 5644|  1.12k|[[nodiscard]] inline bool url::has_search() const noexcept {
 5645|  1.12k|  return query.has_value();
 5646|  1.12k|}
_ZNK3ada14url_aggregator8has_hashEv:
 6460|  1.17k|[[nodiscard]] inline bool url_aggregator::has_hash() const noexcept {
 6461|  1.17k|  ada_log("url_aggregator::has_hash");
 6462|  1.17k|  return components.hash_start != url_components::omitted;
 6463|  1.17k|}
_ZNK3ada14url_aggregator10has_searchEv:
 6465|  1.13k|[[nodiscard]] inline bool url_aggregator::has_search() const noexcept {
 6466|  1.13k|  ada_log("url_aggregator::has_search");
 6467|  1.13k|  return components.search_start != url_components::omitted;
 6468|  1.13k|}
_ZN3ada7helpers6concatIJNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPKcS8_EEES8_DpT_:
 1718|  2.79k|std::string concat(Args... args) {
 1719|  2.79k|  std::string answer;
 1720|  2.79k|  inner_concat(answer, args...);
 1721|  2.79k|  return answer;
 1722|  2.79k|}
_ZN3ada7helpers12inner_concatINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEJPKcS8_EEEvRS8_T_DpT0_:
 1708|  2.79k|inline void inner_concat(std::string& buffer, T t, Args... args) {
 1709|  2.79k|  buffer.append(t);
 1710|  2.79k|  return inner_concat(buffer, args...);
 1711|  2.79k|}
_ZN3ada7helpers6concatIJNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKcEEENS2_12basic_stringIcS5_NS2_9allocatorIcEEEEDpT_:
 1718|  16.4k|std::string concat(Args... args) {
 1719|  16.4k|  std::string answer;
 1720|  16.4k|  inner_concat(answer, args...);
 1721|  16.4k|  return answer;
 1722|  16.4k|}
_ZN3ada7helpers12inner_concatINSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEJPKcEEEvRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEET_DpT0_:
 1708|  16.4k|inline void inner_concat(std::string& buffer, T t, Args... args) {
 1709|  16.4k|  buffer.append(t);
 1710|  16.4k|  return inner_concat(buffer, args...);
 1711|  16.4k|}
_ZN3ada7helpers12inner_concatIPKcJEEEvRNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEET_:
 1700|  18.3k|inline void inner_concat(std::string& buffer, T t) {
 1701|  18.3k|  buffer.append(t);
 1702|  18.3k|}
_ZN3ada7helpers6concatIJNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPKcEEES8_DpT_:
 1718|  1.86k|std::string concat(Args... args) {
 1719|  1.86k|  std::string answer;
 1720|  1.86k|  inner_concat(answer, args...);
 1721|  1.86k|  return answer;
 1722|  1.86k|}
_ZN3ada7helpers12inner_concatINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEJPKcEEEvRS8_T_DpT0_:
 1708|  1.86k|inline void inner_concat(std::string& buffer, T t, Args... args) {
 1709|  1.86k|  buffer.append(t);
 1710|  1.86k|  return inner_concat(buffer, args...);
 1711|  1.86k|}
_ZN3ada3url16update_base_portENSt3__18optionalItEE:
 5632|    983|inline void url::update_base_port(std::optional<uint16_t> input) {
 5633|    983|  port = input;
 5634|    983|}
_ZN3ada6scheme15get_scheme_typeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 4370|  38.0k|constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept {
 4371|  38.0k|  if (scheme.empty()) {
  ------------------
  |  Branch (4371:7): [True: 0, False: 38.0k]
  ------------------
 4372|      0|    return ada::scheme::NOT_SPECIAL;
 4373|      0|  }
 4374|  38.0k|  int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
 4375|  38.0k|  const std::string_view target = details::is_special_list[hash_value];
 4376|  38.0k|  if ((target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1))) {
  ------------------
  |  Branch (4376:7): [True: 19.7k, False: 18.3k]
  |  Branch (4376:35): [True: 16.7k, False: 3.01k]
  ------------------
 4377|  16.7k|    return ada::scheme::type(hash_value);
 4378|  21.3k|  } else {
 4379|  21.3k|    return ada::scheme::NOT_SPECIAL;
 4380|  21.3k|  }
 4381|  38.0k|}
_ZNK3ada8url_base16get_special_portEv:
 5477|    270|[[nodiscard]] inline uint16_t url_base::get_special_port() const noexcept {
 5478|    270|  return ada::scheme::get_special_port(type);
 5479|    270|}
_ZN3ada6scheme10is_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 4347|    408|ada_really_inline constexpr bool is_special(std::string_view scheme) {
 4348|    408|  if (scheme.empty()) {
  ------------------
  |  Branch (4348:7): [True: 0, False: 408]
  ------------------
 4349|      0|    return false;
 4350|      0|  }
 4351|    408|  int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
 4352|    408|  const std::string_view target = details::is_special_list[hash_value];
 4353|    408|  return (target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1));
  ------------------
  |  Branch (4353:10): [True: 138, False: 270]
  |  Branch (4353:38): [True: 54, False: 84]
  ------------------
 4354|    408|}
_ZN3ada3url10set_schemeEONSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
 5650|  4.17k|inline void url::set_scheme(std::string &&new_scheme) noexcept {
 5651|  4.17k|  type = ada::scheme::get_scheme_type(new_scheme);
 5652|       |  // We only move the 'scheme' if it is non-special.
 5653|  4.17k|  if (!is_special()) {
  ------------------
  |  Branch (5653:7): [True: 2.07k, False: 2.09k]
  ------------------
 5654|  2.07k|    non_special_scheme = new_scheme;
 5655|  2.07k|  }
 5656|  4.17k|}
_ZN3ada7helpers6concatIJPKcNSt3__117basic_string_viewIcNS4_11char_traitsIcEEEEEEENS4_12basic_stringIcS7_NS4_9allocatorIcEEEEDpT_:
 1718|      4|std::string concat(Args... args) {
 1719|      4|  std::string answer;
 1720|      4|  inner_concat(answer, args...);
 1721|      4|  return answer;
 1722|      4|}
_ZN3ada7helpers12inner_concatIPKcJNSt3__117basic_string_viewIcNS4_11char_traitsIcEEEEEEEvRNS4_12basic_stringIcS7_NS4_9allocatorIcEEEET_DpT0_:
 1708|  2.80k|inline void inner_concat(std::string& buffer, T t, Args... args) {
 1709|  2.80k|  buffer.append(t);
 1710|  2.80k|  return inner_concat(buffer, args...);
 1711|  2.80k|}
_ZN3ada7helpers12inner_concatINSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEJEEEvRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEET_:
 1700|  2.80k|inline void inner_concat(std::string& buffer, T t) {
 1701|  2.80k|  buffer.append(t);
 1702|  2.80k|}
_ZN3ada14url_aggregator14clear_hostnameEv:
 6423|  2.06k|inline void url_aggregator::clear_hostname() {
 6424|  2.06k|  ada_log("url_aggregator::clear_hostname");
 6425|  2.06k|  ADA_ASSERT_TRUE(validate());
 6426|  2.06k|  if (!has_authority()) {
  ------------------
  |  Branch (6426:7): [True: 0, False: 2.06k]
  ------------------
 6427|      0|    return;
 6428|      0|  }
 6429|  2.06k|  ADA_ASSERT_TRUE(has_authority());
 6430|       |
 6431|  2.06k|  uint32_t hostname_length = components.host_end - components.host_start;
 6432|  2.06k|  uint32_t start = components.host_start;
 6433|       |
 6434|       |  // If hostname starts with "@", we should not remove that character.
 6435|  2.06k|  if (hostname_length > 0 && buffer[start] == '@') {
  ------------------
  |  Branch (6435:7): [True: 309, False: 1.75k]
  |  Branch (6435:30): [True: 10, False: 299]
  ------------------
 6436|     10|    start++;
 6437|     10|    hostname_length--;
 6438|     10|  }
 6439|  2.06k|  buffer.erase(start, hostname_length);
 6440|  2.06k|  components.host_end = start;
 6441|  2.06k|  components.pathname_start -= hostname_length;
 6442|  2.06k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6442:7): [True: 61, False: 2.00k]
  ------------------
 6443|     61|    components.search_start -= hostname_length;
 6444|     61|  }
 6445|  2.06k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6445:7): [True: 51, False: 2.01k]
  ------------------
 6446|     51|    components.hash_start -= hostname_length;
 6447|     51|  }
 6448|       |#if ADA_DEVELOPMENT_CHECKS
 6449|       |  ADA_ASSERT_EQUAL(get_hostname(), "",
 6450|       |                   "hostname should have been cleared on buffer=" + buffer +
 6451|       |                       " with " + components.to_string() + "\n" + to_diagram());
 6452|       |#endif
 6453|  2.06k|  ADA_ASSERT_TRUE(has_authority());
 6454|  2.06k|  ADA_ASSERT_EQUAL(has_empty_hostname(), true,
 6455|  2.06k|                   "hostname should have been cleared on buffer=" + buffer +
 6456|  2.06k|                       " with " + components.to_string() + "\n" + to_diagram());
 6457|  2.06k|  ADA_ASSERT_TRUE(validate());
 6458|  2.06k|}
_ZN3ada7helpers6concatIJNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKcS6_EEENS2_12basic_stringIcS5_NS2_9allocatorIcEEEEDpT_:
 1718|  2.80k|std::string concat(Args... args) {
 1719|  2.80k|  std::string answer;
 1720|  2.80k|  inner_concat(answer, args...);
 1721|  2.80k|  return answer;
 1722|  2.80k|}
_ZN3ada7helpers12inner_concatINSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEJPKcS6_EEEvRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEET_DpT0_:
 1708|  2.80k|inline void inner_concat(std::string& buffer, T t, Args... args) {
 1709|  2.80k|  buffer.append(t);
 1710|  2.80k|  return inner_concat(buffer, args...);
 1711|  2.80k|}

LLVMFuzzerTestOneInput:
    8|  9.85k|extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    9|  9.85k|  FuzzedDataProvider fdp(data, size);
   10|  9.85k|  std::string source = fdp.ConsumeRandomLengthString(256);
   11|  9.85k|  std::string base_source = fdp.ConsumeRandomLengthString(256);
   12|       |
   13|       |  /**
   14|       |   * ada::parse<ada::url>
   15|       |   */
   16|  9.85k|  auto out_url = ada::parse<ada::url>(source);
   17|       |
   18|  9.85k|  if (out_url) {
  ------------------
  |  Branch (18:7): [True: 5.68k, False: 4.17k]
  ------------------
   19|  5.68k|    std::string input = fdp.ConsumeRandomLengthString(256);
   20|  5.68k|    out_url->set_protocol(input);
   21|  5.68k|    out_url->set_username(input);
   22|  5.68k|    out_url->set_password(input);
   23|  5.68k|    out_url->set_hostname(input);
   24|  5.68k|    out_url->set_host(input);
   25|  5.68k|    out_url->set_pathname(input);
   26|  5.68k|    out_url->set_search(input);
   27|  5.68k|    out_url->set_hash(input);
   28|  5.68k|    out_url->set_port(input);
   29|       |
   30|       |    // volatile forces the compiler to store the results without undue
   31|       |    // optimizations
   32|  5.68k|    volatile size_t length = 0;
   33|       |
   34|       |    // getters
   35|  5.68k|    length += out_url->get_protocol().size();
   36|  5.68k|    length += out_url->get_username().size();
   37|  5.68k|    length += out_url->get_password().size();
   38|  5.68k|    length += out_url->get_hostname().size();
   39|  5.68k|    length += out_url->get_host().size();
   40|  5.68k|    length += out_url->get_pathname().size();
   41|  5.68k|    length += out_url->get_search().size();
   42|  5.68k|    length += out_url->get_hash().size();
   43|  5.68k|    length += out_url->get_origin().size();
   44|  5.68k|    length += out_url->get_port().size();
   45|  5.68k|  }
   46|       |
   47|       |  /**
   48|       |   * ada::parse<ada::url_aggregator>
   49|       |   */
   50|  9.85k|  auto out_aggregator = ada::parse<ada::url_aggregator>(source);
   51|       |
   52|  9.85k|  if (out_aggregator) {
  ------------------
  |  Branch (52:7): [True: 5.68k, False: 4.17k]
  ------------------
   53|  5.68k|    std::string input = fdp.ConsumeRandomLengthString(256);
   54|  5.68k|    out_aggregator->set_protocol(input);
   55|  5.68k|    out_aggregator->set_username(input);
   56|  5.68k|    out_aggregator->set_password(input);
   57|  5.68k|    out_aggregator->set_hostname(input);
   58|  5.68k|    out_aggregator->set_host(input);
   59|  5.68k|    out_aggregator->set_pathname(input);
   60|  5.68k|    out_aggregator->set_search(input);
   61|  5.68k|    out_aggregator->set_hash(input);
   62|  5.68k|    out_aggregator->set_port(input);
   63|       |
   64|       |    // volatile forces the compiler to store the results without undue
   65|       |    // optimizations
   66|  5.68k|    volatile size_t length = 0;
   67|       |
   68|       |    // getters
   69|  5.68k|    length += out_aggregator->get_protocol().size();
   70|  5.68k|    length += out_aggregator->get_username().size();
   71|  5.68k|    length += out_aggregator->get_password().size();
   72|  5.68k|    length += out_aggregator->get_hostname().size();
   73|  5.68k|    length += out_aggregator->get_host().size();
   74|  5.68k|    length += out_aggregator->get_pathname().size();
   75|  5.68k|    length += out_aggregator->get_search().size();
   76|  5.68k|    length += out_aggregator->get_hash().size();
   77|  5.68k|    length += out_aggregator->get_origin().size();
   78|  5.68k|    length += out_aggregator->get_port().size();
   79|       |
   80|       |    // clear methods
   81|  5.68k|    out_aggregator->clear_port();
   82|  5.68k|    out_aggregator->clear_search();
   83|  5.68k|    out_aggregator->clear_hash();
   84|  5.68k|  }
   85|       |
   86|       |  /**
   87|       |   * ada::can_parse
   88|       |   */
   89|  9.85k|  auto base_source_view =
   90|  9.85k|      std::string_view(base_source.data(), base_source.length());
   91|  9.85k|  ada::can_parse(source);
   92|  9.85k|  ada::can_parse(source, &base_source_view);
   93|       |
   94|       |  /**
   95|       |   * ada::idna
   96|       |   */
   97|  9.85k|  ada::idna::to_ascii(source);
   98|  9.85k|  ada::idna::to_unicode(source);
   99|       |
  100|       |  /**
  101|       |   * Node.js specific
  102|       |   */
  103|  9.85k|  ada::href_from_file(source);
  104|       |
  105|       |  /**
  106|       |   * ada::url_search_params
  107|       |   */
  108|  9.85k|  auto initialized = ada::url_search_params(base_source_view);
  109|       |
  110|  9.85k|  auto search_params = ada::url_search_params();
  111|  9.85k|  search_params.append(source, base_source);
  112|  9.85k|  search_params.set(source, base_source);
  113|  9.85k|  search_params.to_string();
  114|  9.85k|  if (!search_params.has(base_source)) {
  ------------------
  |  Branch (114:7): [True: 9.81k, False: 40]
  ------------------
  115|  9.81k|    search_params.append(base_source, source);
  116|  9.81k|  }
  117|  9.85k|  search_params.remove(source);
  118|  9.85k|  search_params.remove(source, base_source);
  119|  9.85k|  if (search_params.has(base_source, source)) {
  ------------------
  |  Branch (119:7): [True: 9.81k, False: 40]
  ------------------
  120|  9.81k|    search_params.remove(base_source);
  121|  9.81k|    search_params.remove(base_source, source);
  122|  9.81k|  }
  123|       |
  124|  9.85k|  return 0;
  125|  9.85k|}  // extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {

