_ZN3ada4idna13utf8_to_utf32EPKcmPDi:
  128|  9.77k|size_t utf8_to_utf32(const char* buf, size_t len, char32_t* utf32_output) {
  129|  9.77k|  const uint8_t* data = reinterpret_cast<const uint8_t*>(buf);
  130|  9.77k|  size_t pos = 0;
  131|  9.77k|  char32_t* start{utf32_output};
  132|   125k|  while (pos < len) {
  ------------------
  |  Branch (132:10): [True: 118k, False: 6.75k]
  ------------------
  133|       |    // try to convert the next block of 16 ASCII bytes
  134|   118k|    if (pos + 16 <= len) {  // if it is safe to read 16 more
  ------------------
  |  Branch (134:9): [True: 75.9k, False: 42.4k]
  ------------------
  135|       |                            // bytes, check that they are ascii
  136|  75.9k|      uint64_t v1;
  137|  75.9k|      std::memcpy(&v1, data + pos, sizeof(uint64_t));
  138|  75.9k|      uint64_t v2;
  139|  75.9k|      std::memcpy(&v2, data + pos + sizeof(uint64_t), sizeof(uint64_t));
  140|  75.9k|      uint64_t v{v1 | v2};
  141|  75.9k|      if ((v & 0x8080808080808080) == 0) {
  ------------------
  |  Branch (141:11): [True: 3.00k, False: 72.9k]
  ------------------
  142|  3.00k|        size_t final_pos = pos + 16;
  143|  51.0k|        while (pos < final_pos) {
  ------------------
  |  Branch (143:16): [True: 48.0k, False: 3.00k]
  ------------------
  144|  48.0k|          *utf32_output++ = char32_t(buf[pos]);
  145|  48.0k|          pos++;
  146|  48.0k|        }
  147|  3.00k|        continue;
  148|  3.00k|      }
  149|  75.9k|    }
  150|   115k|    uint8_t leading_byte = data[pos];  // leading byte
  151|   115k|    if (leading_byte < 0b10000000) {
  ------------------
  |  Branch (151:9): [True: 70.5k, False: 44.8k]
  ------------------
  152|       |      // converting one ASCII byte !!!
  153|  70.5k|      *utf32_output++ = char32_t(leading_byte);
  154|  70.5k|      pos++;
  155|  70.5k|    } else if ((leading_byte & 0b11100000) == 0b11000000) {
  ------------------
  |  Branch (155:16): [True: 11.6k, False: 33.2k]
  ------------------
  156|       |      // We have a two-byte UTF-8
  157|  11.6k|      if (pos + 1 >= len) {
  ------------------
  |  Branch (157:11): [True: 249, False: 11.3k]
  ------------------
  158|    249|        return 0;
  159|    249|      }  // minimal bound checking
  160|  11.3k|      if ((data[pos + 1] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (160:11): [True: 328, False: 11.0k]
  ------------------
  161|    328|        return 0;
  162|    328|      }
  163|       |      // range check
  164|  11.0k|      uint32_t code_point =
  165|  11.0k|          (leading_byte & 0b00011111) << 6 | (data[pos + 1] & 0b00111111);
  166|  11.0k|      if (code_point < 0x80 || 0x7ff < code_point) {
  ------------------
  |  Branch (166:11): [True: 27, False: 10.9k]
  |  Branch (166:32): [True: 0, False: 10.9k]
  ------------------
  167|     27|        return 0;
  168|     27|      }
  169|  10.9k|      *utf32_output++ = char32_t(code_point);
  170|  10.9k|      pos += 2;
  171|  33.2k|    } else if ((leading_byte & 0b11110000) == 0b11100000) {
  ------------------
  |  Branch (171:16): [True: 30.5k, False: 2.68k]
  ------------------
  172|       |      // We have a three-byte UTF-8
  173|  30.5k|      if (pos + 2 >= len) {
  ------------------
  |  Branch (173:11): [True: 111, False: 30.4k]
  ------------------
  174|    111|        return 0;
  175|    111|      }  // minimal bound checking
  176|       |
  177|  30.4k|      if ((data[pos + 1] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (177:11): [True: 165, False: 30.3k]
  ------------------
  178|    165|        return 0;
  179|    165|      }
  180|  30.3k|      if ((data[pos + 2] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (180:11): [True: 32, False: 30.2k]
  ------------------
  181|     32|        return 0;
  182|     32|      }
  183|       |      // range check
  184|  30.2k|      uint32_t code_point = (leading_byte & 0b00001111) << 12 |
  185|  30.2k|                            (data[pos + 1] & 0b00111111) << 6 |
  186|  30.2k|                            (data[pos + 2] & 0b00111111);
  187|  30.2k|      if (code_point < 0x800 || 0xffff < code_point ||
  ------------------
  |  Branch (187:11): [True: 20, False: 30.2k]
  |  Branch (187:33): [True: 0, False: 30.2k]
  ------------------
  188|  30.2k|          (0xd7ff < code_point && code_point < 0xe000)) {
  ------------------
  |  Branch (188:12): [True: 4.19k, False: 26.0k]
  |  Branch (188:35): [True: 23, False: 4.17k]
  ------------------
  189|     43|        return 0;
  190|     43|      }
  191|  30.2k|      *utf32_output++ = char32_t(code_point);
  192|  30.2k|      pos += 3;
  193|  30.2k|    } else if ((leading_byte & 0b11111000) == 0b11110000) {  // 0b11110000
  ------------------
  |  Branch (193:16): [True: 871, False: 1.81k]
  ------------------
  194|       |      // we have a 4-byte UTF-8 word.
  195|    871|      if (pos + 3 >= len) {
  ------------------
  |  Branch (195:11): [True: 84, False: 787]
  ------------------
  196|     84|        return 0;
  197|     84|      }  // minimal bound checking
  198|    787|      if ((data[pos + 1] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (198:11): [True: 92, False: 695]
  ------------------
  199|     92|        return 0;
  200|     92|      }
  201|    695|      if ((data[pos + 2] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (201:11): [True: 11, False: 684]
  ------------------
  202|     11|        return 0;
  203|     11|      }
  204|    684|      if ((data[pos + 3] & 0b11000000) != 0b10000000) {
  ------------------
  |  Branch (204:11): [True: 20, False: 664]
  ------------------
  205|     20|        return 0;
  206|     20|      }
  207|       |
  208|       |      // range check
  209|    664|      uint32_t code_point = (leading_byte & 0b00000111) << 18 |
  210|    664|                            (data[pos + 1] & 0b00111111) << 12 |
  211|    664|                            (data[pos + 2] & 0b00111111) << 6 |
  212|    664|                            (data[pos + 3] & 0b00111111);
  213|    664|      if (code_point <= 0xffff || 0x10ffff < code_point) {
  ------------------
  |  Branch (213:11): [True: 24, False: 640]
  |  Branch (213:35): [True: 16, False: 624]
  ------------------
  214|     40|        return 0;
  215|     40|      }
  216|    624|      *utf32_output++ = char32_t(code_point);
  217|    624|      pos += 4;
  218|  1.81k|    } else {
  219|  1.81k|      return 0;
  220|  1.81k|    }
  221|   115k|  }
  222|  6.75k|  return utf32_output - start;
  223|  9.77k|}
_ZN3ada4idna22utf8_length_from_utf32EPKDim:
  225|  1.43k|size_t utf8_length_from_utf32(const char32_t* buf, size_t len) {
  226|       |  // We are not BOM aware.
  227|  1.43k|  const uint32_t* p = reinterpret_cast<const uint32_t*>(buf);
  228|  1.43k|  size_t counter{0};
  229|  7.25k|  for (size_t i = 0; i < len; i++) {
  ------------------
  |  Branch (229:22): [True: 5.82k, False: 1.43k]
  ------------------
  230|       |    /** ASCII **/
  231|  5.82k|    if (p[i] <= 0x7F) {
  ------------------
  |  Branch (231:9): [True: 1.97k, False: 3.84k]
  ------------------
  232|  1.97k|      counter++;
  233|  1.97k|    }
  234|       |    /** two-byte **/
  235|  3.84k|    else if (p[i] <= 0x7FF) {
  ------------------
  |  Branch (235:14): [True: 804, False: 3.04k]
  ------------------
  236|    804|      counter += 2;
  237|    804|    }
  238|       |    /** three-byte **/
  239|  3.04k|    else if (p[i] <= 0xFFFF) {
  ------------------
  |  Branch (239:14): [True: 1.91k, False: 1.12k]
  ------------------
  240|  1.91k|      counter += 3;
  241|  1.91k|    }
  242|       |    /** four-bytes **/
  243|  1.12k|    else {
  244|  1.12k|      counter += 4;
  245|  1.12k|    }
  246|  5.82k|  }
  247|  1.43k|  return counter;
  248|  1.43k|}
_ZN3ada4idna22utf32_length_from_utf8EPKcm:
  250|  9.77k|size_t utf32_length_from_utf8(const char* buf, size_t len) {
  251|  9.77k|  const int8_t* p = reinterpret_cast<const int8_t*>(buf);
  252|  9.77k|  size_t counter{0};
  253|   330k|  for (size_t i = 0; i < len; i++) {
  ------------------
  |  Branch (253:22): [True: 320k, False: 9.77k]
  ------------------
  254|       |    // -65 is 0b10111111, anything larger in two-complement's
  255|       |    // should start a new code point.
  256|   320k|    if (p[i] > -65) {
  ------------------
  |  Branch (256:9): [True: 233k, False: 86.9k]
  ------------------
  257|   233k|      counter++;
  258|   233k|    }
  259|   320k|  }
  260|  9.77k|  return counter;
  261|  9.77k|}
_ZN3ada4idna13utf32_to_utf8EPKDimPc:
  263|  1.43k|size_t utf32_to_utf8(const char32_t* buf, size_t len, char* utf8_output) {
  264|  1.43k|  const uint32_t* data = reinterpret_cast<const uint32_t*>(buf);
  265|  1.43k|  size_t pos = 0;
  266|  1.43k|  char* start{utf8_output};
  267|  6.22k|  while (pos < len) {
  ------------------
  |  Branch (267:10): [True: 4.95k, False: 1.26k]
  ------------------
  268|       |    // try to convert the next block of 2 ASCII characters
  269|  4.95k|    if (pos + 2 <= len) {  // if it is safe to read 8 more
  ------------------
  |  Branch (269:9): [True: 3.85k, False: 1.10k]
  ------------------
  270|       |                           // bytes, check that they are ascii
  271|  3.85k|      uint64_t v;
  272|  3.85k|      std::memcpy(&v, data + pos, sizeof(uint64_t));
  273|  3.85k|      if ((v & 0xFFFFFF80FFFFFF80) == 0) {
  ------------------
  |  Branch (273:11): [True: 755, False: 3.09k]
  ------------------
  274|    755|        *utf8_output++ = char(buf[pos]);
  275|    755|        *utf8_output++ = char(buf[pos + 1]);
  276|    755|        pos += 2;
  277|    755|        continue;
  278|    755|      }
  279|  3.85k|    }
  280|  4.20k|    uint32_t word = data[pos];
  281|  4.20k|    if ((word & 0xFFFFFF80) == 0) {
  ------------------
  |  Branch (281:9): [True: 467, False: 3.73k]
  ------------------
  282|       |      // will generate one UTF-8 bytes
  283|    467|      *utf8_output++ = char(word);
  284|    467|      pos++;
  285|  3.73k|    } else if ((word & 0xFFFFF800) == 0) {
  ------------------
  |  Branch (285:16): [True: 796, False: 2.94k]
  ------------------
  286|       |      // will generate two UTF-8 bytes
  287|       |      // we have 0b110XXXXX 0b10XXXXXX
  288|    796|      *utf8_output++ = char((word >> 6) | 0b11000000);
  289|    796|      *utf8_output++ = char((word & 0b111111) | 0b10000000);
  290|    796|      pos++;
  291|  2.94k|    } else if ((word & 0xFFFF0000) == 0) {
  ------------------
  |  Branch (291:16): [True: 1.91k, False: 1.02k]
  ------------------
  292|       |      // will generate three UTF-8 bytes
  293|       |      // we have 0b1110XXXX 0b10XXXXXX 0b10XXXXXX
  294|  1.91k|      if (word >= 0xD800 && word <= 0xDFFF) {
  ------------------
  |  Branch (294:11): [True: 256, False: 1.65k]
  |  Branch (294:29): [True: 42, False: 214]
  ------------------
  295|     42|        return 0;
  296|     42|      }
  297|  1.86k|      *utf8_output++ = char((word >> 12) | 0b11100000);
  298|  1.86k|      *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000);
  299|  1.86k|      *utf8_output++ = char((word & 0b111111) | 0b10000000);
  300|  1.86k|      pos++;
  301|  1.86k|    } else {
  302|       |      // will generate four UTF-8 bytes
  303|       |      // we have 0b11110XXX 0b10XXXXXX 0b10XXXXXX
  304|       |      // 0b10XXXXXX
  305|  1.02k|      if (word > 0x10FFFF) {
  ------------------
  |  Branch (305:11): [True: 129, False: 900]
  ------------------
  306|    129|        return 0;
  307|    129|      }
  308|    900|      *utf8_output++ = char((word >> 18) | 0b11110000);
  309|    900|      *utf8_output++ = char(((word >> 12) & 0b111111) | 0b10000000);
  310|    900|      *utf8_output++ = char(((word >> 6) & 0b111111) | 0b10000000);
  311|    900|      *utf8_output++ = char((word & 0b111111) | 0b10000000);
  312|    900|      pos++;
  313|    900|    }
  314|  4.20k|  }
  315|  1.26k|  return utf8_output - start;
  316|  1.43k|}
_ZN3ada4idna16find_range_indexEj:
 2731|   183k|uint32_t find_range_index(uint32_t key) {
 2732|       |  ////////////////
 2733|       |  // This could be implemented with std::lower_bound, but we roll our own
 2734|       |  // because we want to allow further optimizations in the future.
 2735|       |  ////////////////
 2736|   183k|  uint32_t len = std::size(table);
 2737|   183k|  uint32_t low = 0;
 2738|   183k|  uint32_t high = len - 1;
 2739|  2.44M|  while (low <= high) {
  ------------------
  |  Branch (2739:10): [True: 2.31M, False: 130k]
  ------------------
 2740|  2.31M|    uint32_t middle_index = (low + high) >> 1;  // cannot overflow
 2741|  2.31M|    uint32_t middle_value = table[middle_index][0];
 2742|  2.31M|    if (middle_value < key) {
  ------------------
  |  Branch (2742:9): [True: 646k, False: 1.67M]
  ------------------
 2743|   646k|      low = middle_index + 1;
 2744|  1.67M|    } else if (middle_value > key) {
  ------------------
  |  Branch (2744:16): [True: 1.61M, False: 52.4k]
  ------------------
 2745|  1.61M|      high = middle_index - 1;
 2746|  1.61M|    } else {
 2747|  52.4k|      return middle_index;  // perfect match
 2748|  52.4k|    }
 2749|  2.31M|  }
 2750|   130k|  return low == 0 ? 0 : low - 1;
  ------------------
  |  Branch (2750:10): [True: 0, False: 130k]
  ------------------
 2751|   183k|}
_ZN3ada4idna9ascii_mapEPcm:
 2777|  15.0k|void ascii_map(char* input, size_t length) {
 2778|  15.0k|  auto broadcast = [](uint8_t v) -> uint64_t {
 2779|  15.0k|    return 0x101010101010101ull * v;
 2780|  15.0k|  };
 2781|  15.0k|  uint64_t broadcast_80 = broadcast(0x80);
 2782|  15.0k|  uint64_t broadcast_Ap = broadcast(128 - 'A');
 2783|  15.0k|  uint64_t broadcast_Zp = broadcast(128 - 'Z' - 1);
 2784|  15.0k|  size_t i = 0;
 2785|       |
 2786|  40.9k|  for (; i + 7 < length; i += 8) {
  ------------------
  |  Branch (2786:10): [True: 25.9k, False: 15.0k]
  ------------------
 2787|  25.9k|    uint64_t word{};
 2788|  25.9k|    memcpy(&word, input + i, sizeof(word));
 2789|  25.9k|    word ^=
 2790|  25.9k|        (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
 2791|  25.9k|    memcpy(input + i, &word, sizeof(word));
 2792|  25.9k|  }
 2793|  15.0k|  if (i < length) {
  ------------------
  |  Branch (2793:7): [True: 13.1k, False: 1.88k]
  ------------------
 2794|  13.1k|    uint64_t word{};
 2795|  13.1k|    memcpy(&word, input + i, length - i);
 2796|  13.1k|    word ^=
 2797|  13.1k|        (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
 2798|  13.1k|    memcpy(input + i, &word, length - i);
 2799|  13.1k|  }
 2800|  15.0k|}
_ZN3ada4idna3mapENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 2803|  16.5k|std::u32string map(std::u32string_view input) {
 2804|       |  //  [Map](https://www.unicode.org/reports/tr46/#ProcessingStepMap).
 2805|       |  //  For each code point in the domain_name string, look up the status
 2806|       |  //  value in Section 5, [IDNA Mapping
 2807|       |  //  Table](https://www.unicode.org/reports/tr46/#IDNA_Mapping_Table),
 2808|       |  //  and take the following actions:
 2809|       |  //    * disallowed: Leave the code point unchanged in the string, and
 2810|       |  //    record that there was an error.
 2811|       |  //    * ignored: Remove the code point from the string. This is
 2812|       |  //    equivalent to mapping the code point to an empty string.
 2813|       |  //    * mapped: Replace the code point in the string by the value for
 2814|       |  //    the mapping in Section 5, [IDNA Mapping
 2815|       |  //    Table](https://www.unicode.org/reports/tr46/#IDNA_Mapping_Table).
 2816|       |  //    * valid: Leave the code point unchanged in the string.
 2817|  16.5k|  static std::u32string error = U"";
 2818|  16.5k|  std::u32string answer;
 2819|  16.5k|  answer.reserve(input.size());
 2820|   183k|  for (char32_t x : input) {
  ------------------
  |  Branch (2820:19): [True: 183k, False: 16.1k]
  ------------------
 2821|   183k|    size_t index = find_range_index(x);
 2822|   183k|    uint32_t descriptor = table[index][1];
 2823|   183k|    uint8_t code = uint8_t(descriptor);
 2824|   183k|    switch (code) {
 2825|    218|      case 0:
  ------------------
  |  Branch (2825:7): [True: 218, False: 182k]
  ------------------
 2826|    218|        break;  // nothing to do, ignored
 2827|   138k|      case 1:
  ------------------
  |  Branch (2827:7): [True: 138k, False: 45.1k]
  ------------------
 2828|   138k|        answer.push_back(x);  // valid, we just copy it to output
 2829|   138k|        break;
 2830|    393|      case 2:
  ------------------
  |  Branch (2830:7): [True: 393, False: 182k]
  ------------------
 2831|    393|        return error;  // disallowed
 2832|      0|        break;
 2833|       |
 2834|       |      // case 3 :
 2835|  44.5k|      default:
  ------------------
  |  Branch (2835:7): [True: 44.5k, False: 138k]
  ------------------
 2836|       |        // We have a mapping
 2837|  44.5k|        {
 2838|  44.5k|          size_t char_count = (descriptor >> 24);
 2839|  44.5k|          uint16_t char_index = uint16_t(descriptor >> 8);
 2840|   252k|          for (size_t idx = char_index; idx < char_index + char_count; idx++) {
  ------------------
  |  Branch (2840:41): [True: 208k, False: 44.5k]
  ------------------
 2841|   208k|            answer.push_back(mappings[idx]);
 2842|   208k|          }
 2843|  44.5k|        }
 2844|   183k|    }
 2845|   183k|  }
 2846|  16.1k|  return answer;
 2847|  16.5k|}
_ZN3ada4idna28compute_decomposition_lengthENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 7766|  16.0k|    const std::u32string_view input) noexcept {
 7767|  16.0k|  bool decomposition_needed{false};
 7768|  16.0k|  size_t additional_elements{0};
 7769|   318k|  for (char32_t current_character : input) {
  ------------------
  |  Branch (7769:35): [True: 318k, False: 16.0k]
  ------------------
 7770|   318k|    size_t decomposition_length{0};
 7771|       |
 7772|   318k|    if (current_character >= hangul_sbase &&
  ------------------
  |  Branch (7772:9): [True: 7.14k, False: 311k]
  ------------------
 7773|   318k|        current_character < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (7773:9): [True: 4.81k, False: 2.32k]
  ------------------
 7774|  4.81k|      decomposition_length = 2;
 7775|  4.81k|      if ((current_character - hangul_sbase) % hangul_tcount) {
  ------------------
  |  Branch (7775:11): [True: 2.92k, False: 1.89k]
  ------------------
 7776|  2.92k|        decomposition_length = 3;
 7777|  2.92k|      }
 7778|   313k|    } else if (current_character < 0x110000) {
  ------------------
  |  Branch (7778:16): [True: 313k, False: 0]
  ------------------
 7779|   313k|      const uint8_t di = decomposition_index[current_character >> 8];
 7780|   313k|      const uint16_t* const decomposition =
 7781|   313k|          decomposition_block[di] + (current_character % 256);
 7782|   313k|      decomposition_length = (decomposition[1] >> 2) - (decomposition[0] >> 2);
 7783|   313k|      if ((decomposition_length > 0) && (decomposition[0] & 1)) {
  ------------------
  |  Branch (7783:11): [True: 6.34k, False: 307k]
  |  Branch (7783:41): [True: 0, False: 6.34k]
  ------------------
 7784|      0|        decomposition_length = 0;
 7785|      0|      }
 7786|   313k|    }
 7787|   318k|    if (decomposition_length != 0) {
  ------------------
  |  Branch (7787:9): [True: 11.1k, False: 307k]
  ------------------
 7788|  11.1k|      decomposition_needed = true;
 7789|  11.1k|      additional_elements += decomposition_length - 1;
 7790|  11.1k|    }
 7791|   318k|  }
 7792|  16.0k|  return {decomposition_needed, additional_elements};
 7793|  16.0k|}
_ZN3ada4idna9decomposeERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEEm:
 7795|  4.17k|void decompose(std::u32string& input, size_t additional_elements) {
 7796|  4.17k|  input.resize(input.size() + additional_elements);
 7797|  4.17k|  for (size_t descending_idx = input.size(),
 7798|  4.17k|              input_count = descending_idx - additional_elements;
 7799|  78.1k|       input_count--;) {
  ------------------
  |  Branch (7799:8): [True: 74.0k, False: 4.17k]
  ------------------
 7800|  74.0k|    if (input[input_count] >= hangul_sbase &&
  ------------------
  |  Branch (7800:9): [True: 5.31k, False: 68.6k]
  ------------------
 7801|  74.0k|        input[input_count] < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (7801:9): [True: 4.81k, False: 500]
  ------------------
 7802|       |      // Hangul decomposition.
 7803|  4.81k|      char32_t s_index = input[input_count] - hangul_sbase;
 7804|  4.81k|      if (s_index % hangul_tcount != 0) {
  ------------------
  |  Branch (7804:11): [True: 2.92k, False: 1.89k]
  ------------------
 7805|  2.92k|        input[--descending_idx] = hangul_tbase + s_index % hangul_tcount;
 7806|  2.92k|      }
 7807|  4.81k|      input[--descending_idx] =
 7808|  4.81k|          hangul_vbase + (s_index % hangul_ncount) / hangul_tcount;
 7809|  4.81k|      input[--descending_idx] = hangul_lbase + s_index / hangul_ncount;
 7810|  69.1k|    } else if (input[input_count] < 0x110000) {
  ------------------
  |  Branch (7810:16): [True: 69.1k, False: 0]
  ------------------
 7811|       |      // Check decomposition_data.
 7812|  69.1k|      const uint16_t* decomposition =
 7813|  69.1k|          decomposition_block[decomposition_index[input[input_count] >> 8]] +
 7814|  69.1k|          (input[input_count] % 256);
 7815|  69.1k|      uint16_t decomposition_length =
 7816|  69.1k|          (decomposition[1] >> 2) - (decomposition[0] >> 2);
 7817|  69.1k|      if (decomposition_length > 0 && (decomposition[0] & 1)) {
  ------------------
  |  Branch (7817:11): [True: 6.34k, False: 62.8k]
  |  Branch (7817:39): [True: 0, False: 6.34k]
  ------------------
 7818|      0|        decomposition_length = 0;
 7819|      0|      }
 7820|  69.1k|      if (decomposition_length > 0) {
  ------------------
  |  Branch (7820:11): [True: 6.34k, False: 62.8k]
  ------------------
 7821|       |        // Non-recursive decomposition.
 7822|  20.2k|        while (decomposition_length-- > 0) {
  ------------------
  |  Branch (7822:16): [True: 13.9k, False: 6.34k]
  ------------------
 7823|  13.9k|          input[--descending_idx] = decomposition_data[(decomposition[0] >> 2) +
 7824|  13.9k|                                                       decomposition_length];
 7825|  13.9k|        }
 7826|  62.8k|      } else {
 7827|       |        // No decomposition.
 7828|  62.8k|        input[--descending_idx] = input[input_count];
 7829|  62.8k|      }
 7830|  69.1k|    } else {
 7831|       |      // Non-Unicode character.
 7832|      0|      input[--descending_idx] = input[input_count];
 7833|      0|    }
 7834|  74.0k|  }
 7835|  4.17k|}
_ZN3ada4idna7get_cccEDi:
 7837|   636k|uint8_t get_ccc(char32_t c) noexcept {
 7838|   636k|  return c < 0x110000 ? canonical_combining_class_block
  ------------------
  |  Branch (7838:10): [True: 636k, False: 0]
  ------------------
 7839|   636k|                            [canonical_combining_class_index[c >> 8]][c % 256]
 7840|   636k|                      : 0;
 7841|   636k|}
_ZN3ada4idna10sort_marksERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEE:
 7843|  16.0k|void sort_marks(std::u32string& input) {
 7844|   334k|  for (size_t idx = 1; idx < input.size(); idx++) {
  ------------------
  |  Branch (7844:24): [True: 318k, False: 16.0k]
  ------------------
 7845|   318k|    uint8_t ccc = get_ccc(input[idx]);
 7846|   318k|    if (ccc == 0) {
  ------------------
  |  Branch (7846:9): [True: 306k, False: 11.7k]
  ------------------
 7847|   306k|      continue;
 7848|   306k|    }  // Skip non-combining characters.
 7849|  11.7k|    auto current_character = input[idx];
 7850|  11.7k|    size_t back_idx = idx;
 7851|  12.8k|    while (back_idx != 0 && get_ccc(input[back_idx - 1]) > ccc) {
  ------------------
  |  Branch (7851:12): [True: 12.6k, False: 145]
  |  Branch (7851:29): [True: 1.06k, False: 11.6k]
  ------------------
 7852|  1.06k|      input[back_idx] = input[back_idx - 1];
 7853|  1.06k|      back_idx--;
 7854|  1.06k|    }
 7855|  11.7k|    input[back_idx] = current_character;
 7856|  11.7k|  }
 7857|  16.0k|}
_ZN3ada4idna13decompose_nfcERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEE:
 7859|  16.0k|void decompose_nfc(std::u32string& input) {
 7860|       |  /**
 7861|       |   * Decompose the domain_name string to Unicode Normalization Form C.
 7862|       |   * @see https://www.unicode.org/reports/tr46/#ProcessingStepDecompose
 7863|       |   */
 7864|  16.0k|  auto [decomposition_needed, additional_elements] =
 7865|  16.0k|      compute_decomposition_length(input);
 7866|  16.0k|  if (decomposition_needed) {
  ------------------
  |  Branch (7866:7): [True: 4.17k, False: 11.9k]
  ------------------
 7867|  4.17k|    decompose(input, additional_elements);
 7868|  4.17k|  }
 7869|  16.0k|  sort_marks(input);
 7870|  16.0k|}
_ZN3ada4idna7composeERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEE:
 7872|  16.0k|void compose(std::u32string& input) {
 7873|       |  /**
 7874|       |   * Compose the domain_name string to Unicode Normalization Form C.
 7875|       |   * @see https://www.unicode.org/reports/tr46/#ProcessingStepCompose
 7876|       |   */
 7877|  16.0k|  size_t input_count{0};
 7878|  16.0k|  size_t composition_count{0};
 7879|   330k|  for (; input_count < input.size(); input_count++, composition_count++) {
  ------------------
  |  Branch (7879:10): [True: 314k, False: 16.0k]
  ------------------
 7880|   314k|    input[composition_count] = input[input_count];
 7881|   314k|    if (input[input_count] >= hangul_lbase &&
  ------------------
  |  Branch (7881:9): [True: 117k, False: 196k]
  ------------------
 7882|   314k|        input[input_count] < hangul_lbase + hangul_lcount) {
  ------------------
  |  Branch (7882:9): [True: 6.16k, False: 111k]
  ------------------
 7883|  6.16k|      if (input_count + 1 < input.size() &&
  ------------------
  |  Branch (7883:11): [True: 5.78k, False: 382]
  ------------------
 7884|  6.16k|          input[input_count + 1] >= hangul_vbase &&
  ------------------
  |  Branch (7884:11): [True: 5.02k, False: 759]
  ------------------
 7885|  6.16k|          input[input_count + 1] < hangul_vbase + hangul_vcount) {
  ------------------
  |  Branch (7885:11): [True: 4.81k, False: 208]
  ------------------
 7886|  4.81k|        input[composition_count] =
 7887|  4.81k|            hangul_sbase +
 7888|  4.81k|            ((input[input_count] - hangul_lbase) * hangul_vcount +
 7889|  4.81k|             input[input_count + 1] - hangul_vbase) *
 7890|  4.81k|                hangul_tcount;
 7891|  4.81k|        input_count++;
 7892|  4.81k|        if (input_count + 1 < input.size() &&
  ------------------
  |  Branch (7892:13): [True: 4.48k, False: 339]
  ------------------
 7893|  4.81k|            input[input_count + 1] > hangul_tbase &&
  ------------------
  |  Branch (7893:13): [True: 3.20k, False: 1.27k]
  ------------------
 7894|  4.81k|            input[input_count + 1] < hangul_tbase + hangul_tcount) {
  ------------------
  |  Branch (7894:13): [True: 2.92k, False: 276]
  ------------------
 7895|  2.92k|          input[composition_count] += input[++input_count] - hangul_tbase;
 7896|  2.92k|        }
 7897|  4.81k|      }
 7898|   308k|    } else if (input[input_count] >= hangul_sbase &&
  ------------------
  |  Branch (7898:16): [True: 1.80k, False: 306k]
  ------------------
 7899|   308k|               input[input_count] < hangul_sbase + hangul_scount) {
  ------------------
  |  Branch (7899:16): [True: 0, False: 1.80k]
  ------------------
 7900|      0|      if ((input[input_count] - hangul_sbase) % hangul_tcount &&
  ------------------
  |  Branch (7900:11): [True: 0, False: 0]
  ------------------
 7901|      0|          input_count + 1 < input.size() &&
  ------------------
  |  Branch (7901:11): [True: 0, False: 0]
  ------------------
 7902|      0|          input[input_count + 1] > hangul_tbase &&
  ------------------
  |  Branch (7902:11): [True: 0, False: 0]
  ------------------
 7903|      0|          input[input_count + 1] < hangul_tbase + hangul_tcount) {
  ------------------
  |  Branch (7903:11): [True: 0, False: 0]
  ------------------
 7904|      0|        input[composition_count] += input[++input_count] - hangul_tbase;
 7905|      0|      }
 7906|   308k|    } else if (input[input_count] < 0x110000) {
  ------------------
  |  Branch (7906:16): [True: 308k, False: 0]
  ------------------
 7907|   308k|      const uint16_t* composition =
 7908|   308k|          &composition_block[composition_index[input[input_count] >> 8]]
 7909|   308k|                            [input[input_count] % 256];
 7910|   308k|      size_t initial_composition_count = composition_count;
 7911|   319k|      for (int32_t previous_ccc = -1; input_count + 1 < input.size();
  ------------------
  |  Branch (7911:39): [True: 305k, False: 14.3k]
  ------------------
 7912|   308k|           input_count++) {
 7913|   305k|        uint8_t ccc = get_ccc(input[input_count + 1]);
 7914|       |
 7915|   305k|        if (composition[1] != composition[0] && previous_ccc < ccc) {
  ------------------
  |  Branch (7915:13): [True: 63.0k, False: 242k]
  |  Branch (7915:49): [True: 62.1k, False: 818]
  ------------------
 7916|       |          // Try finding a composition.
 7917|  62.1k|          uint16_t left = composition[0];
 7918|  62.1k|          uint16_t right = composition[1];
 7919|   149k|          while (left + 2 < right) {
  ------------------
  |  Branch (7919:18): [True: 87.2k, False: 62.1k]
  ------------------
 7920|       |            // mean without overflow
 7921|  87.2k|            uint16_t middle = left + (((right - left) >> 1) & ~1);
 7922|  87.2k|            if (composition_data[middle] <= input[input_count + 1]) {
  ------------------
  |  Branch (7922:17): [True: 12.8k, False: 74.4k]
  ------------------
 7923|  12.8k|              left = middle;
 7924|  12.8k|            }
 7925|  87.2k|            if (composition_data[middle] >= input[input_count + 1]) {
  ------------------
  |  Branch (7925:17): [True: 78.4k, False: 8.74k]
  ------------------
 7926|  78.4k|              right = middle;
 7927|  78.4k|            }
 7928|  87.2k|          }
 7929|  62.1k|          if (composition_data[left] == input[input_count + 1]) {
  ------------------
  |  Branch (7929:15): [True: 7.60k, False: 54.5k]
  ------------------
 7930|  7.60k|            input[initial_composition_count] = composition_data[left + 1];
 7931|  7.60k|            composition =
 7932|  7.60k|                &composition_block
 7933|  7.60k|                    [composition_index[composition_data[left + 1] >> 8]]
 7934|  7.60k|                    [composition_data[left + 1] % 256];
 7935|  7.60k|            continue;
 7936|  7.60k|          }
 7937|  62.1k|        }
 7938|       |
 7939|   298k|        if (ccc == 0) {
  ------------------
  |  Branch (7939:13): [True: 293k, False: 4.35k]
  ------------------
 7940|   293k|          break;
 7941|   293k|        }  // Not a combining character.
 7942|  4.35k|        previous_ccc = ccc;
 7943|  4.35k|        input[++composition_count] = input[input_count + 1];
 7944|  4.35k|      }
 7945|   308k|    }
 7946|   314k|  }
 7947|       |
 7948|  16.0k|  if (composition_count < input_count) {
  ------------------
  |  Branch (7948:7): [True: 4.19k, False: 11.8k]
  ------------------
 7949|  4.19k|    input.resize(composition_count);
 7950|  4.19k|  }
 7951|  16.0k|}
_ZN3ada4idna9normalizeERNSt3__112basic_stringIDiNS1_11char_traitsIDiEENS1_9allocatorIDiEEEE:
 7953|  16.0k|void normalize(std::u32string& input) {
 7954|       |  /**
 7955|       |   * Normalize the domain_name string to Unicode Normalization Form C.
 7956|       |   * @see https://www.unicode.org/reports/tr46/#ProcessingStepNormalize
 7957|       |   */
 7958|  16.0k|  decompose_nfc(input);
 7959|  16.0k|  compose(input);
 7960|  16.0k|}
_ZN3ada4idna17punycode_to_utf32ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEERNS1_12basic_stringIDiNS3_IDiEENS1_9allocatorIDiEEEE:
 8003|  11.4k|bool punycode_to_utf32(std::string_view input, std::u32string &out) {
 8004|  11.4k|  int32_t written_out{0};
 8005|  11.4k|  out.reserve(out.size() + input.size());
 8006|  11.4k|  uint32_t n = initial_n;
 8007|  11.4k|  int32_t i = 0;
 8008|  11.4k|  int32_t bias = initial_bias;
 8009|       |  // grab ascii content
 8010|  11.4k|  size_t end_of_ascii = input.find_last_of('-');
 8011|  11.4k|  if (end_of_ascii != std::string_view::npos) {
  ------------------
  |  Branch (8011:7): [True: 3.96k, False: 7.51k]
  ------------------
 8012|  14.4k|    for (uint8_t c : input.substr(0, end_of_ascii)) {
  ------------------
  |  Branch (8012:20): [True: 14.4k, False: 3.96k]
  ------------------
 8013|  14.4k|      if (c >= 0x80) {
  ------------------
  |  Branch (8013:11): [True: 0, False: 14.4k]
  ------------------
 8014|      0|        return false;
 8015|      0|      }
 8016|  14.4k|      out.push_back(c);
 8017|  14.4k|      written_out++;
 8018|  14.4k|    }
 8019|  3.96k|    input.remove_prefix(end_of_ascii + 1);
 8020|  3.96k|  }
 8021|  50.2k|  while (!input.empty()) {
  ------------------
  |  Branch (8021:10): [True: 39.0k, False: 11.2k]
  ------------------
 8022|  39.0k|    int32_t oldi = i;
 8023|  39.0k|    int32_t w = 1;
 8024|  83.5k|    for (int32_t k = base;; k += base) {
 8025|  83.5k|      if (input.empty()) {
  ------------------
  |  Branch (8025:11): [True: 112, False: 83.4k]
  ------------------
 8026|    112|        return false;
 8027|    112|      }
 8028|  83.4k|      uint8_t code_point = input.front();
 8029|  83.4k|      input.remove_prefix(1);
 8030|  83.4k|      int32_t digit = char_to_digit_value(code_point);
 8031|  83.4k|      if (digit < 0) {
  ------------------
  |  Branch (8031:11): [True: 102, False: 83.3k]
  ------------------
 8032|    102|        return false;
 8033|    102|      }
 8034|  83.3k|      if (digit > (0x7fffffff - i) / w) {
  ------------------
  |  Branch (8034:11): [True: 25, False: 83.2k]
  ------------------
 8035|     25|        return false;
 8036|     25|      }
 8037|  83.2k|      i = i + digit * w;
 8038|  83.2k|      int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias;
  ------------------
  |  Branch (8038:19): [True: 24.6k, False: 58.6k]
  |  Branch (8038:38): [True: 47.2k, False: 11.3k]
  ------------------
 8039|  83.2k|      if (digit < t) {
  ------------------
  |  Branch (8039:11): [True: 38.8k, False: 44.4k]
  ------------------
 8040|  38.8k|        break;
 8041|  38.8k|      }
 8042|  44.4k|      if (w > 0x7fffffff / (base - t)) {
  ------------------
  |  Branch (8042:11): [True: 0, False: 44.4k]
  ------------------
 8043|      0|        return false;
 8044|      0|      }
 8045|  44.4k|      w = w * (base - t);
 8046|  44.4k|    }
 8047|  38.8k|    bias = adapt(i - oldi, written_out + 1, oldi == 0);
 8048|  38.8k|    if (i / (written_out + 1) > int32_t(0x7fffffff - n)) {
  ------------------
  |  Branch (8048:9): [True: 38, False: 38.7k]
  ------------------
 8049|     38|      return false;
 8050|     38|    }
 8051|  38.7k|    n = n + i / (written_out + 1);
 8052|  38.7k|    i = i % (written_out + 1);
 8053|  38.7k|    if (n < 0x80) {
  ------------------
  |  Branch (8053:9): [True: 0, False: 38.7k]
  ------------------
 8054|      0|      return false;
 8055|      0|    }
 8056|  38.7k|    out.insert(out.begin() + i, n);
 8057|  38.7k|    written_out++;
 8058|  38.7k|    ++i;
 8059|  38.7k|  }
 8060|       |
 8061|  11.2k|  return true;
 8062|  11.4k|}
_ZN3ada4idna15verify_punycodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 8064|  2.32k|bool verify_punycode(std::string_view input) {
 8065|  2.32k|  size_t written_out{0};
 8066|  2.32k|  uint32_t n = initial_n;
 8067|  2.32k|  int32_t i = 0;
 8068|  2.32k|  int32_t bias = initial_bias;
 8069|       |  // grab ascii content
 8070|  2.32k|  size_t end_of_ascii = input.find_last_of('-');
 8071|  2.32k|  if (end_of_ascii != std::string_view::npos) {
  ------------------
  |  Branch (8071:7): [True: 650, False: 1.67k]
  ------------------
 8072|  2.15k|    for (uint8_t c : input.substr(0, end_of_ascii)) {
  ------------------
  |  Branch (8072:20): [True: 2.15k, False: 650]
  ------------------
 8073|  2.15k|      if (c >= 0x80) {
  ------------------
  |  Branch (8073:11): [True: 0, False: 2.15k]
  ------------------
 8074|      0|        return false;
 8075|      0|      }
 8076|  2.15k|      written_out++;
 8077|  2.15k|    }
 8078|    650|    input.remove_prefix(end_of_ascii + 1);
 8079|    650|  }
 8080|  6.73k|  while (!input.empty()) {
  ------------------
  |  Branch (8080:10): [True: 5.30k, False: 1.43k]
  ------------------
 8081|  5.30k|    int32_t oldi = i;
 8082|  5.30k|    int32_t w = 1;
 8083|  10.4k|    for (int32_t k = base;; k += base) {
 8084|  10.4k|      if (input.empty()) {
  ------------------
  |  Branch (8084:11): [True: 128, False: 10.3k]
  ------------------
 8085|    128|        return false;
 8086|    128|      }
 8087|  10.3k|      uint8_t code_point = input.front();
 8088|  10.3k|      input.remove_prefix(1);
 8089|  10.3k|      int32_t digit = char_to_digit_value(code_point);
 8090|  10.3k|      if (digit < 0) {
  ------------------
  |  Branch (8090:11): [True: 663, False: 9.65k]
  ------------------
 8091|    663|        return false;
 8092|    663|      }
 8093|  9.65k|      if (digit > (0x7fffffff - i) / w) {
  ------------------
  |  Branch (8093:11): [True: 44, False: 9.61k]
  ------------------
 8094|     44|        return false;
 8095|     44|      }
 8096|  9.61k|      i = i + digit * w;
 8097|  9.61k|      int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias;
  ------------------
  |  Branch (8097:19): [True: 3.56k, False: 6.05k]
  |  Branch (8097:38): [True: 5.59k, False: 453]
  ------------------
 8098|  9.61k|      if (digit < t) {
  ------------------
  |  Branch (8098:11): [True: 4.46k, False: 5.14k]
  ------------------
 8099|  4.46k|        break;
 8100|  4.46k|      }
 8101|  5.14k|      if (w > 0x7fffffff / (base - t)) {
  ------------------
  |  Branch (8101:11): [True: 0, False: 5.14k]
  ------------------
 8102|      0|        return false;
 8103|      0|      }
 8104|  5.14k|      w = w * (base - t);
 8105|  5.14k|    }
 8106|  4.46k|    bias = adapt(i - oldi, int32_t(written_out + 1), oldi == 0);
 8107|  4.46k|    if (i / (written_out + 1) > 0x7fffffff - n) {
  ------------------
  |  Branch (8107:9): [True: 57, False: 4.41k]
  ------------------
 8108|     57|      return false;
 8109|     57|    }
 8110|  4.41k|    n = n + i / int32_t(written_out + 1);
 8111|  4.41k|    i = i % int32_t(written_out + 1);
 8112|  4.41k|    if (n < 0x80) {
  ------------------
  |  Branch (8112:9): [True: 0, False: 4.41k]
  ------------------
 8113|      0|      return false;
 8114|      0|    }
 8115|  4.41k|    written_out++;
 8116|  4.41k|    ++i;
 8117|  4.41k|  }
 8118|       |
 8119|  1.43k|  return true;
 8120|  2.32k|}
_ZN3ada4idna17utf32_to_punycodeENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEERNS1_12basic_stringIcNS3_IcEENS1_9allocatorIcEEEE:
 8122|  24.4k|bool utf32_to_punycode(std::u32string_view input, std::string &out) {
 8123|  24.4k|  out.reserve(input.size() + out.size());
 8124|  24.4k|  uint32_t n = initial_n;
 8125|  24.4k|  int32_t d = 0;
 8126|  24.4k|  int32_t bias = initial_bias;
 8127|  24.4k|  size_t h = 0;
 8128|       |  // first push the ascii content
 8129|   169k|  for (uint32_t c : input) {
  ------------------
  |  Branch (8129:19): [True: 169k, False: 24.4k]
  ------------------
 8130|   169k|    if (c < 0x80) {
  ------------------
  |  Branch (8130:9): [True: 37.5k, False: 132k]
  ------------------
 8131|  37.5k|      ++h;
 8132|  37.5k|      out.push_back(char(c));
 8133|  37.5k|    }
 8134|   169k|    if (c > 0x10ffff || (c >= 0xd880 && c < 0xe000)) {
  ------------------
  |  Branch (8134:9): [True: 0, False: 169k]
  |  Branch (8134:26): [True: 1.05k, False: 168k]
  |  Branch (8134:41): [True: 0, False: 1.05k]
  ------------------
 8135|      0|      return false;
 8136|      0|    }
 8137|   169k|  }
 8138|  24.4k|  size_t b = h;
 8139|  24.4k|  if (b > 0) {
  ------------------
  |  Branch (8139:7): [True: 7.16k, False: 17.3k]
  ------------------
 8140|  7.16k|    out.push_back('-');
 8141|  7.16k|  }
 8142|   109k|  while (h < input.size()) {
  ------------------
  |  Branch (8142:10): [True: 84.6k, False: 24.4k]
  ------------------
 8143|  84.6k|    uint32_t m = 0x10FFFF;
 8144|  1.30M|    for (auto code_point : input) {
  ------------------
  |  Branch (8144:26): [True: 1.30M, False: 84.6k]
  ------------------
 8145|  1.30M|      if (code_point >= n && code_point < m) m = code_point;
  ------------------
  |  Branch (8145:11): [True: 518k, False: 781k]
  |  Branch (8145:30): [True: 147k, False: 371k]
  ------------------
 8146|  1.30M|    }
 8147|       |
 8148|  84.6k|    if ((m - n) > (0x7fffffff - d) / (h + 1)) {
  ------------------
  |  Branch (8148:9): [True: 0, False: 84.6k]
  ------------------
 8149|      0|      return false;
 8150|      0|    }
 8151|  84.6k|    d = d + int32_t((m - n) * (h + 1));
 8152|  84.6k|    n = m;
 8153|  1.30M|    for (auto c : input) {
  ------------------
  |  Branch (8153:17): [True: 1.30M, False: 84.6k]
  ------------------
 8154|  1.30M|      if (c < n) {
  ------------------
  |  Branch (8154:11): [True: 781k, False: 518k]
  ------------------
 8155|   781k|        if (d == 0x7fffffff) {
  ------------------
  |  Branch (8155:13): [True: 0, False: 781k]
  ------------------
 8156|      0|          return false;
 8157|      0|        }
 8158|   781k|        ++d;
 8159|   781k|      }
 8160|  1.30M|      if (c == n) {
  ------------------
  |  Branch (8160:11): [True: 132k, False: 1.16M]
  ------------------
 8161|   132k|        int32_t q = d;
 8162|   336k|        for (int32_t k = base;; k += base) {
 8163|   336k|          int32_t t = k <= bias ? tmin : k >= bias + tmax ? tmax : k - bias;
  ------------------
  |  Branch (8163:23): [True: 89.7k, False: 246k]
  |  Branch (8163:42): [True: 188k, False: 57.8k]
  ------------------
 8164|       |
 8165|   336k|          if (q < t) {
  ------------------
  |  Branch (8165:15): [True: 132k, False: 204k]
  ------------------
 8166|   132k|            break;
 8167|   132k|          }
 8168|   204k|          out.push_back(digit_to_char(t + ((q - t) % (base - t))));
 8169|   204k|          q = (q - t) / (base - t);
 8170|   204k|        }
 8171|   132k|        out.push_back(digit_to_char(q));
 8172|   132k|        bias = adapt(d, int32_t(h + 1), h == b);
 8173|   132k|        d = 0;
 8174|   132k|        ++h;
 8175|   132k|      }
 8176|  1.30M|    }
 8177|  84.6k|    ++d;
 8178|  84.6k|    ++n;
 8179|  84.6k|  }
 8180|  24.4k|  return true;
 8181|  24.4k|}
_ZN3ada4idna14is_label_validENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 8990|  34.4k|bool is_label_valid(const std::u32string_view label) {
 8991|  34.4k|  if (label.empty()) {
  ------------------
  |  Branch (8991:7): [True: 0, False: 34.4k]
  ------------------
 8992|      0|    return true;
 8993|      0|  }
 8994|       |
 8995|       |  ///////////////
 8996|       |  // We have a normalization step which ensures that we are in NFC.
 8997|       |  // If we receive punycode, we normalize and check that the normalized
 8998|       |  // version matches the original.
 8999|       |  // --------------------------------------
 9000|       |  // The label must be in Unicode Normalization Form NFC.
 9001|       |
 9002|       |  // Current URL standard indicatest that CheckHyphens is set to false.
 9003|       |  // ---------------------------------------
 9004|       |  // If CheckHyphens, the label must not contain a U+002D HYPHEN-MINUS character
 9005|       |  // in both the third and fourth positions. If CheckHyphens, the label must
 9006|       |  // neither begin nor end with a U+002D HYPHEN-MINUS character.
 9007|       |
 9008|       |  // This is not necessary because we segment the
 9009|       |  // labels by '.'.
 9010|       |  // ---------------------------------------
 9011|       |  // The label must not contain a U+002E ( . ) FULL STOP.
 9012|       |  // if (label.find('.') != std::string_view::npos) return false;
 9013|       |
 9014|       |  // The label must not begin with a combining mark, that is:
 9015|       |  // General_Category=Mark.
 9016|  34.4k|  constexpr static uint32_t combining[] = {
 9017|  34.4k|      0x300,   0x301,   0x302,   0x303,   0x304,   0x305,   0x306,   0x307,
 9018|  34.4k|      0x308,   0x309,   0x30a,   0x30b,   0x30c,   0x30d,   0x30e,   0x30f,
 9019|  34.4k|      0x310,   0x311,   0x312,   0x313,   0x314,   0x315,   0x316,   0x317,
 9020|  34.4k|      0x318,   0x319,   0x31a,   0x31b,   0x31c,   0x31d,   0x31e,   0x31f,
 9021|  34.4k|      0x320,   0x321,   0x322,   0x323,   0x324,   0x325,   0x326,   0x327,
 9022|  34.4k|      0x328,   0x329,   0x32a,   0x32b,   0x32c,   0x32d,   0x32e,   0x32f,
 9023|  34.4k|      0x330,   0x331,   0x332,   0x333,   0x334,   0x335,   0x336,   0x337,
 9024|  34.4k|      0x338,   0x339,   0x33a,   0x33b,   0x33c,   0x33d,   0x33e,   0x33f,
 9025|  34.4k|      0x340,   0x341,   0x342,   0x343,   0x344,   0x345,   0x346,   0x347,
 9026|  34.4k|      0x348,   0x349,   0x34a,   0x34b,   0x34c,   0x34d,   0x34e,   0x34f,
 9027|  34.4k|      0x350,   0x351,   0x352,   0x353,   0x354,   0x355,   0x356,   0x357,
 9028|  34.4k|      0x358,   0x359,   0x35a,   0x35b,   0x35c,   0x35d,   0x35e,   0x35f,
 9029|  34.4k|      0x360,   0x361,   0x362,   0x363,   0x364,   0x365,   0x366,   0x367,
 9030|  34.4k|      0x368,   0x369,   0x36a,   0x36b,   0x36c,   0x36d,   0x36e,   0x36f,
 9031|  34.4k|      0x483,   0x484,   0x485,   0x486,   0x487,   0x488,   0x489,   0x591,
 9032|  34.4k|      0x592,   0x593,   0x594,   0x595,   0x596,   0x597,   0x598,   0x599,
 9033|  34.4k|      0x59a,   0x59b,   0x59c,   0x59d,   0x59e,   0x59f,   0x5a0,   0x5a1,
 9034|  34.4k|      0x5a2,   0x5a3,   0x5a4,   0x5a5,   0x5a6,   0x5a7,   0x5a8,   0x5a9,
 9035|  34.4k|      0x5aa,   0x5ab,   0x5ac,   0x5ad,   0x5ae,   0x5af,   0x5b0,   0x5b1,
 9036|  34.4k|      0x5b2,   0x5b3,   0x5b4,   0x5b5,   0x5b6,   0x5b7,   0x5b8,   0x5b9,
 9037|  34.4k|      0x5ba,   0x5bb,   0x5bc,   0x5bd,   0x5bf,   0x5c1,   0x5c2,   0x5c4,
 9038|  34.4k|      0x5c5,   0x5c7,   0x610,   0x611,   0x612,   0x613,   0x614,   0x615,
 9039|  34.4k|      0x616,   0x617,   0x618,   0x619,   0x61a,   0x64b,   0x64c,   0x64d,
 9040|  34.4k|      0x64e,   0x64f,   0x650,   0x651,   0x652,   0x653,   0x654,   0x655,
 9041|  34.4k|      0x656,   0x657,   0x658,   0x659,   0x65a,   0x65b,   0x65c,   0x65d,
 9042|  34.4k|      0x65e,   0x65f,   0x670,   0x6d6,   0x6d7,   0x6d8,   0x6d9,   0x6da,
 9043|  34.4k|      0x6db,   0x6dc,   0x6df,   0x6e0,   0x6e1,   0x6e2,   0x6e3,   0x6e4,
 9044|  34.4k|      0x6e7,   0x6e8,   0x6ea,   0x6eb,   0x6ec,   0x6ed,   0x711,   0x730,
 9045|  34.4k|      0x731,   0x732,   0x733,   0x734,   0x735,   0x736,   0x737,   0x738,
 9046|  34.4k|      0x739,   0x73a,   0x73b,   0x73c,   0x73d,   0x73e,   0x73f,   0x740,
 9047|  34.4k|      0x741,   0x742,   0x743,   0x744,   0x745,   0x746,   0x747,   0x748,
 9048|  34.4k|      0x749,   0x74a,   0x7a6,   0x7a7,   0x7a8,   0x7a9,   0x7aa,   0x7ab,
 9049|  34.4k|      0x7ac,   0x7ad,   0x7ae,   0x7af,   0x7b0,   0x7eb,   0x7ec,   0x7ed,
 9050|  34.4k|      0x7ee,   0x7ef,   0x7f0,   0x7f1,   0x7f2,   0x7f3,   0x7fd,   0x816,
 9051|  34.4k|      0x817,   0x818,   0x819,   0x81b,   0x81c,   0x81d,   0x81e,   0x81f,
 9052|  34.4k|      0x820,   0x821,   0x822,   0x823,   0x825,   0x826,   0x827,   0x829,
 9053|  34.4k|      0x82a,   0x82b,   0x82c,   0x82d,   0x859,   0x85a,   0x85b,   0x8d3,
 9054|  34.4k|      0x8d4,   0x8d5,   0x8d6,   0x8d7,   0x8d8,   0x8d9,   0x8da,   0x8db,
 9055|  34.4k|      0x8dc,   0x8dd,   0x8de,   0x8df,   0x8e0,   0x8e1,   0x8e3,   0x8e4,
 9056|  34.4k|      0x8e5,   0x8e6,   0x8e7,   0x8e8,   0x8e9,   0x8ea,   0x8eb,   0x8ec,
 9057|  34.4k|      0x8ed,   0x8ee,   0x8ef,   0x8f0,   0x8f1,   0x8f2,   0x8f3,   0x8f4,
 9058|  34.4k|      0x8f5,   0x8f6,   0x8f7,   0x8f8,   0x8f9,   0x8fa,   0x8fb,   0x8fc,
 9059|  34.4k|      0x8fd,   0x8fe,   0x8ff,   0x900,   0x901,   0x902,   0x903,   0x93a,
 9060|  34.4k|      0x93b,   0x93c,   0x93e,   0x93f,   0x940,   0x941,   0x942,   0x943,
 9061|  34.4k|      0x944,   0x945,   0x946,   0x947,   0x948,   0x949,   0x94a,   0x94b,
 9062|  34.4k|      0x94c,   0x94d,   0x94e,   0x94f,   0x951,   0x952,   0x953,   0x954,
 9063|  34.4k|      0x955,   0x956,   0x957,   0x962,   0x963,   0x981,   0x982,   0x983,
 9064|  34.4k|      0x9bc,   0x9be,   0x9bf,   0x9c0,   0x9c1,   0x9c2,   0x9c3,   0x9c4,
 9065|  34.4k|      0x9c7,   0x9c8,   0x9cb,   0x9cc,   0x9cd,   0x9d7,   0x9e2,   0x9e3,
 9066|  34.4k|      0x9fe,   0xa01,   0xa02,   0xa03,   0xa3c,   0xa3e,   0xa3f,   0xa40,
 9067|  34.4k|      0xa41,   0xa42,   0xa47,   0xa48,   0xa4b,   0xa4c,   0xa4d,   0xa51,
 9068|  34.4k|      0xa70,   0xa71,   0xa75,   0xa81,   0xa82,   0xa83,   0xabc,   0xabe,
 9069|  34.4k|      0xabf,   0xac0,   0xac1,   0xac2,   0xac3,   0xac4,   0xac5,   0xac7,
 9070|  34.4k|      0xac8,   0xac9,   0xacb,   0xacc,   0xacd,   0xae2,   0xae3,   0xafa,
 9071|  34.4k|      0xafb,   0xafc,   0xafd,   0xafe,   0xaff,   0xb01,   0xb02,   0xb03,
 9072|  34.4k|      0xb3c,   0xb3e,   0xb3f,   0xb40,   0xb41,   0xb42,   0xb43,   0xb44,
 9073|  34.4k|      0xb47,   0xb48,   0xb4b,   0xb4c,   0xb4d,   0xb55,   0xb56,   0xb57,
 9074|  34.4k|      0xb62,   0xb63,   0xb82,   0xbbe,   0xbbf,   0xbc0,   0xbc1,   0xbc2,
 9075|  34.4k|      0xbc6,   0xbc7,   0xbc8,   0xbca,   0xbcb,   0xbcc,   0xbcd,   0xbd7,
 9076|  34.4k|      0xc00,   0xc01,   0xc02,   0xc03,   0xc04,   0xc3e,   0xc3f,   0xc40,
 9077|  34.4k|      0xc41,   0xc42,   0xc43,   0xc44,   0xc46,   0xc47,   0xc48,   0xc4a,
 9078|  34.4k|      0xc4b,   0xc4c,   0xc4d,   0xc55,   0xc56,   0xc62,   0xc63,   0xc81,
 9079|  34.4k|      0xc82,   0xc83,   0xcbc,   0xcbe,   0xcbf,   0xcc0,   0xcc1,   0xcc2,
 9080|  34.4k|      0xcc3,   0xcc4,   0xcc6,   0xcc7,   0xcc8,   0xcca,   0xccb,   0xccc,
 9081|  34.4k|      0xccd,   0xcd5,   0xcd6,   0xce2,   0xce3,   0xd00,   0xd01,   0xd02,
 9082|  34.4k|      0xd03,   0xd3b,   0xd3c,   0xd3e,   0xd3f,   0xd40,   0xd41,   0xd42,
 9083|  34.4k|      0xd43,   0xd44,   0xd46,   0xd47,   0xd48,   0xd4a,   0xd4b,   0xd4c,
 9084|  34.4k|      0xd4d,   0xd57,   0xd62,   0xd63,   0xd81,   0xd82,   0xd83,   0xdca,
 9085|  34.4k|      0xdcf,   0xdd0,   0xdd1,   0xdd2,   0xdd3,   0xdd4,   0xdd6,   0xdd8,
 9086|  34.4k|      0xdd9,   0xdda,   0xddb,   0xddc,   0xddd,   0xdde,   0xddf,   0xdf2,
 9087|  34.4k|      0xdf3,   0xe31,   0xe34,   0xe35,   0xe36,   0xe37,   0xe38,   0xe39,
 9088|  34.4k|      0xe3a,   0xe47,   0xe48,   0xe49,   0xe4a,   0xe4b,   0xe4c,   0xe4d,
 9089|  34.4k|      0xe4e,   0xeb1,   0xeb4,   0xeb5,   0xeb6,   0xeb7,   0xeb8,   0xeb9,
 9090|  34.4k|      0xeba,   0xebb,   0xebc,   0xec8,   0xec9,   0xeca,   0xecb,   0xecc,
 9091|  34.4k|      0xecd,   0xf18,   0xf19,   0xf35,   0xf37,   0xf39,   0xf3e,   0xf3f,
 9092|  34.4k|      0xf71,   0xf72,   0xf73,   0xf74,   0xf75,   0xf76,   0xf77,   0xf78,
 9093|  34.4k|      0xf79,   0xf7a,   0xf7b,   0xf7c,   0xf7d,   0xf7e,   0xf7f,   0xf80,
 9094|  34.4k|      0xf81,   0xf82,   0xf83,   0xf84,   0xf86,   0xf87,   0xf8d,   0xf8e,
 9095|  34.4k|      0xf8f,   0xf90,   0xf91,   0xf92,   0xf93,   0xf94,   0xf95,   0xf96,
 9096|  34.4k|      0xf97,   0xf99,   0xf9a,   0xf9b,   0xf9c,   0xf9d,   0xf9e,   0xf9f,
 9097|  34.4k|      0xfa0,   0xfa1,   0xfa2,   0xfa3,   0xfa4,   0xfa5,   0xfa6,   0xfa7,
 9098|  34.4k|      0xfa8,   0xfa9,   0xfaa,   0xfab,   0xfac,   0xfad,   0xfae,   0xfaf,
 9099|  34.4k|      0xfb0,   0xfb1,   0xfb2,   0xfb3,   0xfb4,   0xfb5,   0xfb6,   0xfb7,
 9100|  34.4k|      0xfb8,   0xfb9,   0xfba,   0xfbb,   0xfbc,   0xfc6,   0x102b,  0x102c,
 9101|  34.4k|      0x102d,  0x102e,  0x102f,  0x1030,  0x1031,  0x1032,  0x1033,  0x1034,
 9102|  34.4k|      0x1035,  0x1036,  0x1037,  0x1038,  0x1039,  0x103a,  0x103b,  0x103c,
 9103|  34.4k|      0x103d,  0x103e,  0x1056,  0x1057,  0x1058,  0x1059,  0x105e,  0x105f,
 9104|  34.4k|      0x1060,  0x1062,  0x1063,  0x1064,  0x1067,  0x1068,  0x1069,  0x106a,
 9105|  34.4k|      0x106b,  0x106c,  0x106d,  0x1071,  0x1072,  0x1073,  0x1074,  0x1082,
 9106|  34.4k|      0x1083,  0x1084,  0x1085,  0x1086,  0x1087,  0x1088,  0x1089,  0x108a,
 9107|  34.4k|      0x108b,  0x108c,  0x108d,  0x108f,  0x109a,  0x109b,  0x109c,  0x109d,
 9108|  34.4k|      0x135d,  0x135e,  0x135f,  0x1712,  0x1713,  0x1714,  0x1732,  0x1733,
 9109|  34.4k|      0x1734,  0x1752,  0x1753,  0x1772,  0x1773,  0x17b4,  0x17b5,  0x17b6,
 9110|  34.4k|      0x17b7,  0x17b8,  0x17b9,  0x17ba,  0x17bb,  0x17bc,  0x17bd,  0x17be,
 9111|  34.4k|      0x17bf,  0x17c0,  0x17c1,  0x17c2,  0x17c3,  0x17c4,  0x17c5,  0x17c6,
 9112|  34.4k|      0x17c7,  0x17c8,  0x17c9,  0x17ca,  0x17cb,  0x17cc,  0x17cd,  0x17ce,
 9113|  34.4k|      0x17cf,  0x17d0,  0x17d1,  0x17d2,  0x17d3,  0x17dd,  0x180b,  0x180c,
 9114|  34.4k|      0x180d,  0x1885,  0x1886,  0x18a9,  0x1920,  0x1921,  0x1922,  0x1923,
 9115|  34.4k|      0x1924,  0x1925,  0x1926,  0x1927,  0x1928,  0x1929,  0x192a,  0x192b,
 9116|  34.4k|      0x1930,  0x1931,  0x1932,  0x1933,  0x1934,  0x1935,  0x1936,  0x1937,
 9117|  34.4k|      0x1938,  0x1939,  0x193a,  0x193b,  0x1a17,  0x1a18,  0x1a19,  0x1a1a,
 9118|  34.4k|      0x1a1b,  0x1a55,  0x1a56,  0x1a57,  0x1a58,  0x1a59,  0x1a5a,  0x1a5b,
 9119|  34.4k|      0x1a5c,  0x1a5d,  0x1a5e,  0x1a60,  0x1a61,  0x1a62,  0x1a63,  0x1a64,
 9120|  34.4k|      0x1a65,  0x1a66,  0x1a67,  0x1a68,  0x1a69,  0x1a6a,  0x1a6b,  0x1a6c,
 9121|  34.4k|      0x1a6d,  0x1a6e,  0x1a6f,  0x1a70,  0x1a71,  0x1a72,  0x1a73,  0x1a74,
 9122|  34.4k|      0x1a75,  0x1a76,  0x1a77,  0x1a78,  0x1a79,  0x1a7a,  0x1a7b,  0x1a7c,
 9123|  34.4k|      0x1a7f,  0x1ab0,  0x1ab1,  0x1ab2,  0x1ab3,  0x1ab4,  0x1ab5,  0x1ab6,
 9124|  34.4k|      0x1ab7,  0x1ab8,  0x1ab9,  0x1aba,  0x1abb,  0x1abc,  0x1abd,  0x1abe,
 9125|  34.4k|      0x1abf,  0x1ac0,  0x1b00,  0x1b01,  0x1b02,  0x1b03,  0x1b04,  0x1b34,
 9126|  34.4k|      0x1b35,  0x1b36,  0x1b37,  0x1b38,  0x1b39,  0x1b3a,  0x1b3b,  0x1b3c,
 9127|  34.4k|      0x1b3d,  0x1b3e,  0x1b3f,  0x1b40,  0x1b41,  0x1b42,  0x1b43,  0x1b44,
 9128|  34.4k|      0x1b6b,  0x1b6c,  0x1b6d,  0x1b6e,  0x1b6f,  0x1b70,  0x1b71,  0x1b72,
 9129|  34.4k|      0x1b73,  0x1b80,  0x1b81,  0x1b82,  0x1ba1,  0x1ba2,  0x1ba3,  0x1ba4,
 9130|  34.4k|      0x1ba5,  0x1ba6,  0x1ba7,  0x1ba8,  0x1ba9,  0x1baa,  0x1bab,  0x1bac,
 9131|  34.4k|      0x1bad,  0x1be6,  0x1be7,  0x1be8,  0x1be9,  0x1bea,  0x1beb,  0x1bec,
 9132|  34.4k|      0x1bed,  0x1bee,  0x1bef,  0x1bf0,  0x1bf1,  0x1bf2,  0x1bf3,  0x1c24,
 9133|  34.4k|      0x1c25,  0x1c26,  0x1c27,  0x1c28,  0x1c29,  0x1c2a,  0x1c2b,  0x1c2c,
 9134|  34.4k|      0x1c2d,  0x1c2e,  0x1c2f,  0x1c30,  0x1c31,  0x1c32,  0x1c33,  0x1c34,
 9135|  34.4k|      0x1c35,  0x1c36,  0x1c37,  0x1cd0,  0x1cd1,  0x1cd2,  0x1cd4,  0x1cd5,
 9136|  34.4k|      0x1cd6,  0x1cd7,  0x1cd8,  0x1cd9,  0x1cda,  0x1cdb,  0x1cdc,  0x1cdd,
 9137|  34.4k|      0x1cde,  0x1cdf,  0x1ce0,  0x1ce1,  0x1ce2,  0x1ce3,  0x1ce4,  0x1ce5,
 9138|  34.4k|      0x1ce6,  0x1ce7,  0x1ce8,  0x1ced,  0x1cf4,  0x1cf7,  0x1cf8,  0x1cf9,
 9139|  34.4k|      0x1dc0,  0x1dc1,  0x1dc2,  0x1dc3,  0x1dc4,  0x1dc5,  0x1dc6,  0x1dc7,
 9140|  34.4k|      0x1dc8,  0x1dc9,  0x1dca,  0x1dcb,  0x1dcc,  0x1dcd,  0x1dce,  0x1dcf,
 9141|  34.4k|      0x1dd0,  0x1dd1,  0x1dd2,  0x1dd3,  0x1dd4,  0x1dd5,  0x1dd6,  0x1dd7,
 9142|  34.4k|      0x1dd8,  0x1dd9,  0x1dda,  0x1ddb,  0x1ddc,  0x1ddd,  0x1dde,  0x1ddf,
 9143|  34.4k|      0x1de0,  0x1de1,  0x1de2,  0x1de3,  0x1de4,  0x1de5,  0x1de6,  0x1de7,
 9144|  34.4k|      0x1de8,  0x1de9,  0x1dea,  0x1deb,  0x1dec,  0x1ded,  0x1dee,  0x1def,
 9145|  34.4k|      0x1df0,  0x1df1,  0x1df2,  0x1df3,  0x1df4,  0x1df5,  0x1df6,  0x1df7,
 9146|  34.4k|      0x1df8,  0x1df9,  0x1dfb,  0x1dfc,  0x1dfd,  0x1dfe,  0x1dff,  0x20d0,
 9147|  34.4k|      0x20d1,  0x20d2,  0x20d3,  0x20d4,  0x20d5,  0x20d6,  0x20d7,  0x20d8,
 9148|  34.4k|      0x20d9,  0x20da,  0x20db,  0x20dc,  0x20dd,  0x20de,  0x20df,  0x20e0,
 9149|  34.4k|      0x20e1,  0x20e2,  0x20e3,  0x20e4,  0x20e5,  0x20e6,  0x20e7,  0x20e8,
 9150|  34.4k|      0x20e9,  0x20ea,  0x20eb,  0x20ec,  0x20ed,  0x20ee,  0x20ef,  0x20f0,
 9151|  34.4k|      0x2cef,  0x2cf0,  0x2cf1,  0x2d7f,  0x2de0,  0x2de1,  0x2de2,  0x2de3,
 9152|  34.4k|      0x2de4,  0x2de5,  0x2de6,  0x2de7,  0x2de8,  0x2de9,  0x2dea,  0x2deb,
 9153|  34.4k|      0x2dec,  0x2ded,  0x2dee,  0x2def,  0x2df0,  0x2df1,  0x2df2,  0x2df3,
 9154|  34.4k|      0x2df4,  0x2df5,  0x2df6,  0x2df7,  0x2df8,  0x2df9,  0x2dfa,  0x2dfb,
 9155|  34.4k|      0x2dfc,  0x2dfd,  0x2dfe,  0x2dff,  0x302a,  0x302b,  0x302c,  0x302d,
 9156|  34.4k|      0x302e,  0x302f,  0x3099,  0x309a,  0xa66f,  0xa670,  0xa671,  0xa672,
 9157|  34.4k|      0xa674,  0xa675,  0xa676,  0xa677,  0xa678,  0xa679,  0xa67a,  0xa67b,
 9158|  34.4k|      0xa67c,  0xa67d,  0xa69e,  0xa69f,  0xa6f0,  0xa6f1,  0xa802,  0xa806,
 9159|  34.4k|      0xa80b,  0xa823,  0xa824,  0xa825,  0xa826,  0xa827,  0xa82c,  0xa880,
 9160|  34.4k|      0xa881,  0xa8b4,  0xa8b5,  0xa8b6,  0xa8b7,  0xa8b8,  0xa8b9,  0xa8ba,
 9161|  34.4k|      0xa8bb,  0xa8bc,  0xa8bd,  0xa8be,  0xa8bf,  0xa8c0,  0xa8c1,  0xa8c2,
 9162|  34.4k|      0xa8c3,  0xa8c4,  0xa8c5,  0xa8e0,  0xa8e1,  0xa8e2,  0xa8e3,  0xa8e4,
 9163|  34.4k|      0xa8e5,  0xa8e6,  0xa8e7,  0xa8e8,  0xa8e9,  0xa8ea,  0xa8eb,  0xa8ec,
 9164|  34.4k|      0xa8ed,  0xa8ee,  0xa8ef,  0xa8f0,  0xa8f1,  0xa8ff,  0xa926,  0xa927,
 9165|  34.4k|      0xa928,  0xa929,  0xa92a,  0xa92b,  0xa92c,  0xa92d,  0xa947,  0xa948,
 9166|  34.4k|      0xa949,  0xa94a,  0xa94b,  0xa94c,  0xa94d,  0xa94e,  0xa94f,  0xa950,
 9167|  34.4k|      0xa951,  0xa952,  0xa953,  0xa980,  0xa981,  0xa982,  0xa983,  0xa9b3,
 9168|  34.4k|      0xa9b4,  0xa9b5,  0xa9b6,  0xa9b7,  0xa9b8,  0xa9b9,  0xa9ba,  0xa9bb,
 9169|  34.4k|      0xa9bc,  0xa9bd,  0xa9be,  0xa9bf,  0xa9c0,  0xa9e5,  0xaa29,  0xaa2a,
 9170|  34.4k|      0xaa2b,  0xaa2c,  0xaa2d,  0xaa2e,  0xaa2f,  0xaa30,  0xaa31,  0xaa32,
 9171|  34.4k|      0xaa33,  0xaa34,  0xaa35,  0xaa36,  0xaa43,  0xaa4c,  0xaa4d,  0xaa7b,
 9172|  34.4k|      0xaa7c,  0xaa7d,  0xaab0,  0xaab2,  0xaab3,  0xaab4,  0xaab7,  0xaab8,
 9173|  34.4k|      0xaabe,  0xaabf,  0xaac1,  0xaaeb,  0xaaec,  0xaaed,  0xaaee,  0xaaef,
 9174|  34.4k|      0xaaf5,  0xaaf6,  0xabe3,  0xabe4,  0xabe5,  0xabe6,  0xabe7,  0xabe8,
 9175|  34.4k|      0xabe9,  0xabea,  0xabec,  0xabed,  0xfb1e,  0xfe00,  0xfe01,  0xfe02,
 9176|  34.4k|      0xfe03,  0xfe04,  0xfe05,  0xfe06,  0xfe07,  0xfe08,  0xfe09,  0xfe0a,
 9177|  34.4k|      0xfe0b,  0xfe0c,  0xfe0d,  0xfe0e,  0xfe0f,  0xfe20,  0xfe21,  0xfe22,
 9178|  34.4k|      0xfe23,  0xfe24,  0xfe25,  0xfe26,  0xfe27,  0xfe28,  0xfe29,  0xfe2a,
 9179|  34.4k|      0xfe2b,  0xfe2c,  0xfe2d,  0xfe2e,  0xfe2f,  0x101fd, 0x102e0, 0x10376,
 9180|  34.4k|      0x10377, 0x10378, 0x10379, 0x1037a, 0x10a01, 0x10a02, 0x10a03, 0x10a05,
 9181|  34.4k|      0x10a06, 0x10a0c, 0x10a0d, 0x10a0e, 0x10a0f, 0x10a38, 0x10a39, 0x10a3a,
 9182|  34.4k|      0x10a3f, 0x10ae5, 0x10ae6, 0x10d24, 0x10d25, 0x10d26, 0x10d27, 0x10eab,
 9183|  34.4k|      0x10eac, 0x10f46, 0x10f47, 0x10f48, 0x10f49, 0x10f4a, 0x10f4b, 0x10f4c,
 9184|  34.4k|      0x10f4d, 0x10f4e, 0x10f4f, 0x10f50, 0x11000, 0x11001, 0x11002, 0x11038,
 9185|  34.4k|      0x11039, 0x1103a, 0x1103b, 0x1103c, 0x1103d, 0x1103e, 0x1103f, 0x11040,
 9186|  34.4k|      0x11041, 0x11042, 0x11043, 0x11044, 0x11045, 0x11046, 0x1107f, 0x11080,
 9187|  34.4k|      0x11081, 0x11082, 0x110b0, 0x110b1, 0x110b2, 0x110b3, 0x110b4, 0x110b5,
 9188|  34.4k|      0x110b6, 0x110b7, 0x110b8, 0x110b9, 0x110ba, 0x11100, 0x11101, 0x11102,
 9189|  34.4k|      0x11127, 0x11128, 0x11129, 0x1112a, 0x1112b, 0x1112c, 0x1112d, 0x1112e,
 9190|  34.4k|      0x1112f, 0x11130, 0x11131, 0x11132, 0x11133, 0x11134, 0x11145, 0x11146,
 9191|  34.4k|      0x11173, 0x11180, 0x11181, 0x11182, 0x111b3, 0x111b4, 0x111b5, 0x111b6,
 9192|  34.4k|      0x111b7, 0x111b8, 0x111b9, 0x111ba, 0x111bb, 0x111bc, 0x111bd, 0x111be,
 9193|  34.4k|      0x111bf, 0x111c0, 0x111c9, 0x111ca, 0x111cb, 0x111cc, 0x111ce, 0x111cf,
 9194|  34.4k|      0x1122c, 0x1122d, 0x1122e, 0x1122f, 0x11230, 0x11231, 0x11232, 0x11233,
 9195|  34.4k|      0x11234, 0x11235, 0x11236, 0x11237, 0x1123e, 0x112df, 0x112e0, 0x112e1,
 9196|  34.4k|      0x112e2, 0x112e3, 0x112e4, 0x112e5, 0x112e6, 0x112e7, 0x112e8, 0x112e9,
 9197|  34.4k|      0x112ea, 0x11300, 0x11301, 0x11302, 0x11303, 0x1133b, 0x1133c, 0x1133e,
 9198|  34.4k|      0x1133f, 0x11340, 0x11341, 0x11342, 0x11343, 0x11344, 0x11347, 0x11348,
 9199|  34.4k|      0x1134b, 0x1134c, 0x1134d, 0x11357, 0x11362, 0x11363, 0x11366, 0x11367,
 9200|  34.4k|      0x11368, 0x11369, 0x1136a, 0x1136b, 0x1136c, 0x11370, 0x11371, 0x11372,
 9201|  34.4k|      0x11373, 0x11374, 0x11435, 0x11436, 0x11437, 0x11438, 0x11439, 0x1143a,
 9202|  34.4k|      0x1143b, 0x1143c, 0x1143d, 0x1143e, 0x1143f, 0x11440, 0x11441, 0x11442,
 9203|  34.4k|      0x11443, 0x11444, 0x11445, 0x11446, 0x1145e, 0x114b0, 0x114b1, 0x114b2,
 9204|  34.4k|      0x114b3, 0x114b4, 0x114b5, 0x114b6, 0x114b7, 0x114b8, 0x114b9, 0x114ba,
 9205|  34.4k|      0x114bb, 0x114bc, 0x114bd, 0x114be, 0x114bf, 0x114c0, 0x114c1, 0x114c2,
 9206|  34.4k|      0x114c3, 0x115af, 0x115b0, 0x115b1, 0x115b2, 0x115b3, 0x115b4, 0x115b5,
 9207|  34.4k|      0x115b8, 0x115b9, 0x115ba, 0x115bb, 0x115bc, 0x115bd, 0x115be, 0x115bf,
 9208|  34.4k|      0x115c0, 0x115dc, 0x115dd, 0x11630, 0x11631, 0x11632, 0x11633, 0x11634,
 9209|  34.4k|      0x11635, 0x11636, 0x11637, 0x11638, 0x11639, 0x1163a, 0x1163b, 0x1163c,
 9210|  34.4k|      0x1163d, 0x1163e, 0x1163f, 0x11640, 0x116ab, 0x116ac, 0x116ad, 0x116ae,
 9211|  34.4k|      0x116af, 0x116b0, 0x116b1, 0x116b2, 0x116b3, 0x116b4, 0x116b5, 0x116b6,
 9212|  34.4k|      0x116b7, 0x1171d, 0x1171e, 0x1171f, 0x11720, 0x11721, 0x11722, 0x11723,
 9213|  34.4k|      0x11724, 0x11725, 0x11726, 0x11727, 0x11728, 0x11729, 0x1172a, 0x1172b,
 9214|  34.4k|      0x1182c, 0x1182d, 0x1182e, 0x1182f, 0x11830, 0x11831, 0x11832, 0x11833,
 9215|  34.4k|      0x11834, 0x11835, 0x11836, 0x11837, 0x11838, 0x11839, 0x1183a, 0x11930,
 9216|  34.4k|      0x11931, 0x11932, 0x11933, 0x11934, 0x11935, 0x11937, 0x11938, 0x1193b,
 9217|  34.4k|      0x1193c, 0x1193d, 0x1193e, 0x11940, 0x11942, 0x11943, 0x119d1, 0x119d2,
 9218|  34.4k|      0x119d3, 0x119d4, 0x119d5, 0x119d6, 0x119d7, 0x119da, 0x119db, 0x119dc,
 9219|  34.4k|      0x119dd, 0x119de, 0x119df, 0x119e0, 0x119e4, 0x11a01, 0x11a02, 0x11a03,
 9220|  34.4k|      0x11a04, 0x11a05, 0x11a06, 0x11a07, 0x11a08, 0x11a09, 0x11a0a, 0x11a33,
 9221|  34.4k|      0x11a34, 0x11a35, 0x11a36, 0x11a37, 0x11a38, 0x11a39, 0x11a3b, 0x11a3c,
 9222|  34.4k|      0x11a3d, 0x11a3e, 0x11a47, 0x11a51, 0x11a52, 0x11a53, 0x11a54, 0x11a55,
 9223|  34.4k|      0x11a56, 0x11a57, 0x11a58, 0x11a59, 0x11a5a, 0x11a5b, 0x11a8a, 0x11a8b,
 9224|  34.4k|      0x11a8c, 0x11a8d, 0x11a8e, 0x11a8f, 0x11a90, 0x11a91, 0x11a92, 0x11a93,
 9225|  34.4k|      0x11a94, 0x11a95, 0x11a96, 0x11a97, 0x11a98, 0x11a99, 0x11c2f, 0x11c30,
 9226|  34.4k|      0x11c31, 0x11c32, 0x11c33, 0x11c34, 0x11c35, 0x11c36, 0x11c38, 0x11c39,
 9227|  34.4k|      0x11c3a, 0x11c3b, 0x11c3c, 0x11c3d, 0x11c3e, 0x11c3f, 0x11c92, 0x11c93,
 9228|  34.4k|      0x11c94, 0x11c95, 0x11c96, 0x11c97, 0x11c98, 0x11c99, 0x11c9a, 0x11c9b,
 9229|  34.4k|      0x11c9c, 0x11c9d, 0x11c9e, 0x11c9f, 0x11ca0, 0x11ca1, 0x11ca2, 0x11ca3,
 9230|  34.4k|      0x11ca4, 0x11ca5, 0x11ca6, 0x11ca7, 0x11ca9, 0x11caa, 0x11cab, 0x11cac,
 9231|  34.4k|      0x11cad, 0x11cae, 0x11caf, 0x11cb0, 0x11cb1, 0x11cb2, 0x11cb3, 0x11cb4,
 9232|  34.4k|      0x11cb5, 0x11cb6, 0x11d31, 0x11d32, 0x11d33, 0x11d34, 0x11d35, 0x11d36,
 9233|  34.4k|      0x11d3a, 0x11d3c, 0x11d3d, 0x11d3f, 0x11d40, 0x11d41, 0x11d42, 0x11d43,
 9234|  34.4k|      0x11d44, 0x11d45, 0x11d47, 0x11d8a, 0x11d8b, 0x11d8c, 0x11d8d, 0x11d8e,
 9235|  34.4k|      0x11d90, 0x11d91, 0x11d93, 0x11d94, 0x11d95, 0x11d96, 0x11d97, 0x11ef3,
 9236|  34.4k|      0x11ef4, 0x11ef5, 0x11ef6, 0x16af0, 0x16af1, 0x16af2, 0x16af3, 0x16af4,
 9237|  34.4k|      0x16b30, 0x16b31, 0x16b32, 0x16b33, 0x16b34, 0x16b35, 0x16b36, 0x16f4f,
 9238|  34.4k|      0x16f51, 0x16f52, 0x16f53, 0x16f54, 0x16f55, 0x16f56, 0x16f57, 0x16f58,
 9239|  34.4k|      0x16f59, 0x16f5a, 0x16f5b, 0x16f5c, 0x16f5d, 0x16f5e, 0x16f5f, 0x16f60,
 9240|  34.4k|      0x16f61, 0x16f62, 0x16f63, 0x16f64, 0x16f65, 0x16f66, 0x16f67, 0x16f68,
 9241|  34.4k|      0x16f69, 0x16f6a, 0x16f6b, 0x16f6c, 0x16f6d, 0x16f6e, 0x16f6f, 0x16f70,
 9242|  34.4k|      0x16f71, 0x16f72, 0x16f73, 0x16f74, 0x16f75, 0x16f76, 0x16f77, 0x16f78,
 9243|  34.4k|      0x16f79, 0x16f7a, 0x16f7b, 0x16f7c, 0x16f7d, 0x16f7e, 0x16f7f, 0x16f80,
 9244|  34.4k|      0x16f81, 0x16f82, 0x16f83, 0x16f84, 0x16f85, 0x16f86, 0x16f87, 0x16f8f,
 9245|  34.4k|      0x16f90, 0x16f91, 0x16f92, 0x16fe4, 0x16ff0, 0x16ff1, 0x1bc9d, 0x1bc9e,
 9246|  34.4k|      0x1d165, 0x1d166, 0x1d167, 0x1d168, 0x1d169, 0x1d16d, 0x1d16e, 0x1d16f,
 9247|  34.4k|      0x1d170, 0x1d171, 0x1d172, 0x1d17b, 0x1d17c, 0x1d17d, 0x1d17e, 0x1d17f,
 9248|  34.4k|      0x1d180, 0x1d181, 0x1d182, 0x1d185, 0x1d186, 0x1d187, 0x1d188, 0x1d189,
 9249|  34.4k|      0x1d18a, 0x1d18b, 0x1d1aa, 0x1d1ab, 0x1d1ac, 0x1d1ad, 0x1d242, 0x1d243,
 9250|  34.4k|      0x1d244, 0x1da00, 0x1da01, 0x1da02, 0x1da03, 0x1da04, 0x1da05, 0x1da06,
 9251|  34.4k|      0x1da07, 0x1da08, 0x1da09, 0x1da0a, 0x1da0b, 0x1da0c, 0x1da0d, 0x1da0e,
 9252|  34.4k|      0x1da0f, 0x1da10, 0x1da11, 0x1da12, 0x1da13, 0x1da14, 0x1da15, 0x1da16,
 9253|  34.4k|      0x1da17, 0x1da18, 0x1da19, 0x1da1a, 0x1da1b, 0x1da1c, 0x1da1d, 0x1da1e,
 9254|  34.4k|      0x1da1f, 0x1da20, 0x1da21, 0x1da22, 0x1da23, 0x1da24, 0x1da25, 0x1da26,
 9255|  34.4k|      0x1da27, 0x1da28, 0x1da29, 0x1da2a, 0x1da2b, 0x1da2c, 0x1da2d, 0x1da2e,
 9256|  34.4k|      0x1da2f, 0x1da30, 0x1da31, 0x1da32, 0x1da33, 0x1da34, 0x1da35, 0x1da36,
 9257|  34.4k|      0x1da3b, 0x1da3c, 0x1da3d, 0x1da3e, 0x1da3f, 0x1da40, 0x1da41, 0x1da42,
 9258|  34.4k|      0x1da43, 0x1da44, 0x1da45, 0x1da46, 0x1da47, 0x1da48, 0x1da49, 0x1da4a,
 9259|  34.4k|      0x1da4b, 0x1da4c, 0x1da4d, 0x1da4e, 0x1da4f, 0x1da50, 0x1da51, 0x1da52,
 9260|  34.4k|      0x1da53, 0x1da54, 0x1da55, 0x1da56, 0x1da57, 0x1da58, 0x1da59, 0x1da5a,
 9261|  34.4k|      0x1da5b, 0x1da5c, 0x1da5d, 0x1da5e, 0x1da5f, 0x1da60, 0x1da61, 0x1da62,
 9262|  34.4k|      0x1da63, 0x1da64, 0x1da65, 0x1da66, 0x1da67, 0x1da68, 0x1da69, 0x1da6a,
 9263|  34.4k|      0x1da6b, 0x1da6c, 0x1da75, 0x1da84, 0x1da9b, 0x1da9c, 0x1da9d, 0x1da9e,
 9264|  34.4k|      0x1da9f, 0x1daa1, 0x1daa2, 0x1daa3, 0x1daa4, 0x1daa5, 0x1daa6, 0x1daa7,
 9265|  34.4k|      0x1daa8, 0x1daa9, 0x1daaa, 0x1daab, 0x1daac, 0x1daad, 0x1daae, 0x1daaf,
 9266|  34.4k|      0x1e000, 0x1e001, 0x1e002, 0x1e003, 0x1e004, 0x1e005, 0x1e006, 0x1e008,
 9267|  34.4k|      0x1e009, 0x1e00a, 0x1e00b, 0x1e00c, 0x1e00d, 0x1e00e, 0x1e00f, 0x1e010,
 9268|  34.4k|      0x1e011, 0x1e012, 0x1e013, 0x1e014, 0x1e015, 0x1e016, 0x1e017, 0x1e018,
 9269|  34.4k|      0x1e01b, 0x1e01c, 0x1e01d, 0x1e01e, 0x1e01f, 0x1e020, 0x1e021, 0x1e023,
 9270|  34.4k|      0x1e024, 0x1e026, 0x1e027, 0x1e028, 0x1e029, 0x1e02a, 0x1e130, 0x1e131,
 9271|  34.4k|      0x1e132, 0x1e133, 0x1e134, 0x1e135, 0x1e136, 0x1e2ec, 0x1e2ed, 0x1e2ee,
 9272|  34.4k|      0x1e2ef, 0x1e8d0, 0x1e8d1, 0x1e8d2, 0x1e8d3, 0x1e8d4, 0x1e8d5, 0x1e8d6,
 9273|  34.4k|      0x1e944, 0x1e945, 0x1e946, 0x1e947, 0x1e948, 0x1e949, 0x1e94a, 0xe0100,
 9274|  34.4k|      0xe0101, 0xe0102, 0xe0103, 0xe0104, 0xe0105, 0xe0106, 0xe0107, 0xe0108,
 9275|  34.4k|      0xe0109, 0xe010a, 0xe010b, 0xe010c, 0xe010d, 0xe010e, 0xe010f, 0xe0110,
 9276|  34.4k|      0xe0111, 0xe0112, 0xe0113, 0xe0114, 0xe0115, 0xe0116, 0xe0117, 0xe0118,
 9277|  34.4k|      0xe0119, 0xe011a, 0xe011b, 0xe011c, 0xe011d, 0xe011e, 0xe011f, 0xe0120,
 9278|  34.4k|      0xe0121, 0xe0122, 0xe0123, 0xe0124, 0xe0125, 0xe0126, 0xe0127, 0xe0128,
 9279|  34.4k|      0xe0129, 0xe012a, 0xe012b, 0xe012c, 0xe012d, 0xe012e, 0xe012f, 0xe0130,
 9280|  34.4k|      0xe0131, 0xe0132, 0xe0133, 0xe0134, 0xe0135, 0xe0136, 0xe0137, 0xe0138,
 9281|  34.4k|      0xe0139, 0xe013a, 0xe013b, 0xe013c, 0xe013d, 0xe013e, 0xe013f, 0xe0140,
 9282|  34.4k|      0xe0141, 0xe0142, 0xe0143, 0xe0144, 0xe0145, 0xe0146, 0xe0147, 0xe0148,
 9283|  34.4k|      0xe0149, 0xe014a, 0xe014b, 0xe014c, 0xe014d, 0xe014e, 0xe014f, 0xe0150,
 9284|  34.4k|      0xe0151, 0xe0152, 0xe0153, 0xe0154, 0xe0155, 0xe0156, 0xe0157, 0xe0158,
 9285|  34.4k|      0xe0159, 0xe015a, 0xe015b, 0xe015c, 0xe015d, 0xe015e, 0xe015f, 0xe0160,
 9286|  34.4k|      0xe0161, 0xe0162, 0xe0163, 0xe0164, 0xe0165, 0xe0166, 0xe0167, 0xe0168,
 9287|  34.4k|      0xe0169, 0xe016a, 0xe016b, 0xe016c, 0xe016d, 0xe016e, 0xe016f, 0xe0170,
 9288|  34.4k|      0xe0171, 0xe0172, 0xe0173, 0xe0174, 0xe0175, 0xe0176, 0xe0177, 0xe0178,
 9289|  34.4k|      0xe0179, 0xe017a, 0xe017b, 0xe017c, 0xe017d, 0xe017e, 0xe017f, 0xe0180,
 9290|  34.4k|      0xe0181, 0xe0182, 0xe0183, 0xe0184, 0xe0185, 0xe0186, 0xe0187, 0xe0188,
 9291|  34.4k|      0xe0189, 0xe018a, 0xe018b, 0xe018c, 0xe018d, 0xe018e, 0xe018f, 0xe0190,
 9292|  34.4k|      0xe0191, 0xe0192, 0xe0193, 0xe0194, 0xe0195, 0xe0196, 0xe0197, 0xe0198,
 9293|  34.4k|      0xe0199, 0xe019a, 0xe019b, 0xe019c, 0xe019d, 0xe019e, 0xe019f, 0xe01a0,
 9294|  34.4k|      0xe01a1, 0xe01a2, 0xe01a3, 0xe01a4, 0xe01a5, 0xe01a6, 0xe01a7, 0xe01a8,
 9295|  34.4k|      0xe01a9, 0xe01aa, 0xe01ab, 0xe01ac, 0xe01ad, 0xe01ae, 0xe01af, 0xe01b0,
 9296|  34.4k|      0xe01b1, 0xe01b2, 0xe01b3, 0xe01b4, 0xe01b5, 0xe01b6, 0xe01b7, 0xe01b8,
 9297|  34.4k|      0xe01b9, 0xe01ba, 0xe01bb, 0xe01bc, 0xe01bd, 0xe01be, 0xe01bf, 0xe01c0,
 9298|  34.4k|      0xe01c1, 0xe01c2, 0xe01c3, 0xe01c4, 0xe01c5, 0xe01c6, 0xe01c7, 0xe01c8,
 9299|  34.4k|      0xe01c9, 0xe01ca, 0xe01cb, 0xe01cc, 0xe01cd, 0xe01ce, 0xe01cf, 0xe01d0,
 9300|  34.4k|      0xe01d1, 0xe01d2, 0xe01d3, 0xe01d4, 0xe01d5, 0xe01d6, 0xe01d7, 0xe01d8,
 9301|  34.4k|      0xe01d9, 0xe01da, 0xe01db, 0xe01dc, 0xe01dd, 0xe01de, 0xe01df, 0xe01e0,
 9302|  34.4k|      0xe01e1, 0xe01e2, 0xe01e3, 0xe01e4, 0xe01e5, 0xe01e6, 0xe01e7, 0xe01e8,
 9303|  34.4k|      0xe01e9, 0xe01ea, 0xe01eb, 0xe01ec, 0xe01ed, 0xe01ee, 0xe01ef};
 9304|  34.4k|  if (std::binary_search(std::begin(combining), std::end(combining),
  ------------------
  |  Branch (9304:7): [True: 76, False: 34.3k]
  ------------------
 9305|  34.4k|                         label.front())) {
 9306|     76|    return false;
 9307|     76|  }
 9308|       |  // We verify this next step as part of the mapping:
 9309|       |  // ---------------------------------------------
 9310|       |  // Each code point in the label must only have certain status values
 9311|       |  // according to Section 5, IDNA Mapping Table:
 9312|       |  // - For Transitional Processing, each value must be valid.
 9313|       |  // - For Nontransitional Processing, each value must be either valid or
 9314|       |  // deviation.
 9315|       |
 9316|       |  // If CheckJoiners, the label must satisfy the ContextJ rules from Appendix
 9317|       |  // A, in The Unicode Code Points and Internationalized Domain Names for
 9318|       |  // Applications (IDNA) [IDNA2008].
 9319|  34.3k|  constexpr static uint32_t virama[] = {
 9320|  34.3k|      0x094D,  0x09CD,  0x0A4D,  0x0ACD,  0x0B4D,  0x0BCD,  0x0C4D,  0x0CCD,
 9321|  34.3k|      0x0D3B,  0x0D3C,  0x0D4D,  0x0DCA,  0x0E3A,  0x0EBA,  0x0F84,  0x1039,
 9322|  34.3k|      0x103A,  0x1714,  0x1734,  0x17D2,  0x1A60,  0x1B44,  0x1BAA,  0x1BAB,
 9323|  34.3k|      0x1BF2,  0x1BF3,  0x2D7F,  0xA806,  0xA82C,  0xA8C4,  0xA953,  0xA9C0,
 9324|  34.3k|      0xAAF6,  0xABED,  0x10A3F, 0x11046, 0x1107F, 0x110B9, 0x11133, 0x11134,
 9325|  34.3k|      0x111C0, 0x11235, 0x112EA, 0x1134D, 0x11442, 0x114C2, 0x115BF, 0x1163F,
 9326|  34.3k|      0x116B6, 0x1172B, 0x11839, 0x1193D, 0x1193E, 0x119E0, 0x11A34, 0x11A47,
 9327|  34.3k|      0x11A99, 0x11C3F, 0x11D44, 0x11D45, 0x11D97};
 9328|  34.3k|  constexpr static uint32_t R[] = {
 9329|  34.3k|      0x622, 0x623, 0x624, 0x625, 0x627, 0x629, 0x62f, 0x630, 0x631,
 9330|  34.3k|      0x632, 0x648, 0x671, 0x672, 0x673, 0x675, 0x676, 0x677, 0x688,
 9331|  34.3k|      0x689, 0x68a, 0x68b, 0x68c, 0x68d, 0x68e, 0x68f, 0x690, 0x691,
 9332|  34.3k|      0x692, 0x693, 0x694, 0x695, 0x696, 0x697, 0x698, 0x699, 0x6c0,
 9333|  34.3k|      0x6c3, 0x6c4, 0x6c5, 0x6c6, 0x6c7, 0x6c8, 0x6c9, 0x6ca, 0x6cb,
 9334|  34.3k|      0x6cd, 0x6cf, 0x6d2, 0x6d3, 0x6d5, 0x6ee, 0x6ef, 0x710, 0x715,
 9335|  34.3k|      0x716, 0x717, 0x718, 0x719, 0x71e, 0x728, 0x72a, 0x72c, 0x72f,
 9336|  34.3k|      0x74d, 0x759, 0x75a, 0x75b, 0x854, 0x8aa, 0x8ab, 0x8ac};
 9337|  34.3k|  constexpr static uint32_t L[] = {0xa872};
 9338|  34.3k|  constexpr static uint32_t D[] = {
 9339|  34.3k|      0x620,  0x626,  0x628,  0x62a,  0x62b,  0x62c,  0x62d,  0x62e,  0x633,
 9340|  34.3k|      0x634,  0x635,  0x636,  0x637,  0x638,  0x639,  0x63a,  0x63b,  0x63c,
 9341|  34.3k|      0x63d,  0x63e,  0x63f,  0x641,  0x642,  0x643,  0x644,  0x645,  0x646,
 9342|  34.3k|      0x647,  0x649,  0x64a,  0x66e,  0x66f,  0x678,  0x679,  0x67a,  0x67b,
 9343|  34.3k|      0x67c,  0x67d,  0x67e,  0x67f,  0x680,  0x681,  0x682,  0x683,  0x684,
 9344|  34.3k|      0x685,  0x686,  0x687,  0x69a,  0x69b,  0x69c,  0x69d,  0x69e,  0x69f,
 9345|  34.3k|      0x6a0,  0x6a1,  0x6a2,  0x6a3,  0x6a4,  0x6a5,  0x6a6,  0x6a7,  0x6a8,
 9346|  34.3k|      0x6a9,  0x6aa,  0x6ab,  0x6ac,  0x6ad,  0x6ae,  0x6af,  0x6b0,  0x6b1,
 9347|  34.3k|      0x6b2,  0x6b3,  0x6b4,  0x6b5,  0x6b6,  0x6b7,  0x6b8,  0x6b9,  0x6ba,
 9348|  34.3k|      0x6bb,  0x6bc,  0x6bd,  0x6be,  0x6bf,  0x6c1,  0x6c2,  0x6cc,  0x6ce,
 9349|  34.3k|      0x6d0,  0x6d1,  0x6fa,  0x6fb,  0x6fc,  0x6ff,  0x712,  0x713,  0x714,
 9350|  34.3k|      0x71a,  0x71b,  0x71c,  0x71d,  0x71f,  0x720,  0x721,  0x722,  0x723,
 9351|  34.3k|      0x724,  0x725,  0x726,  0x727,  0x729,  0x72b,  0x72d,  0x72e,  0x74e,
 9352|  34.3k|      0x74f,  0x750,  0x751,  0x752,  0x753,  0x754,  0x755,  0x756,  0x757,
 9353|  34.3k|      0x758,  0x75c,  0x75d,  0x75e,  0x75f,  0x760,  0x761,  0x762,  0x763,
 9354|  34.3k|      0x764,  0x765,  0x766,  0x850,  0x851,  0x852,  0x853,  0x855,  0x8a0,
 9355|  34.3k|      0x8a2,  0x8a3,  0x8a4,  0x8a5,  0x8a6,  0x8a7,  0x8a8,  0x8a9,  0x1807,
 9356|  34.3k|      0x1820, 0x1821, 0x1822, 0x1823, 0x1824, 0x1825, 0x1826, 0x1827, 0x1828,
 9357|  34.3k|      0x1829, 0x182a, 0x182b, 0x182c, 0x182d, 0x182e, 0x182f, 0x1830, 0x1831,
 9358|  34.3k|      0x1832, 0x1833, 0x1834, 0x1835, 0x1836, 0x1837, 0x1838, 0x1839, 0x183a,
 9359|  34.3k|      0x183b, 0x183c, 0x183d, 0x183e, 0x183f, 0x1840, 0x1841, 0x1842, 0x1843,
 9360|  34.3k|      0x1844, 0x1845, 0x1846, 0x1847, 0x1848, 0x1849, 0x184a, 0x184b, 0x184c,
 9361|  34.3k|      0x184d, 0x184e, 0x184f, 0x1850, 0x1851, 0x1852, 0x1853, 0x1854, 0x1855,
 9362|  34.3k|      0x1856, 0x1857, 0x1858, 0x1859, 0x185a, 0x185b, 0x185c, 0x185d, 0x185e,
 9363|  34.3k|      0x185f, 0x1860, 0x1861, 0x1862, 0x1863, 0x1864, 0x1865, 0x1866, 0x1867,
 9364|  34.3k|      0x1868, 0x1869, 0x186a, 0x186b, 0x186c, 0x186d, 0x186e, 0x186f, 0x1870,
 9365|  34.3k|      0x1871, 0x1872, 0x1873, 0x1874, 0x1875, 0x1876, 0x1877, 0x1887, 0x1888,
 9366|  34.3k|      0x1889, 0x188a, 0x188b, 0x188c, 0x188d, 0x188e, 0x188f, 0x1890, 0x1891,
 9367|  34.3k|      0x1892, 0x1893, 0x1894, 0x1895, 0x1896, 0x1897, 0x1898, 0x1899, 0x189a,
 9368|  34.3k|      0x189b, 0x189c, 0x189d, 0x189e, 0x189f, 0x18a0, 0x18a1, 0x18a2, 0x18a3,
 9369|  34.3k|      0x18a4, 0x18a5, 0x18a6, 0x18a7, 0x18a8, 0x18aa, 0xa840, 0xa841, 0xa842,
 9370|  34.3k|      0xa843, 0xa844, 0xa845, 0xa846, 0xa847, 0xa848, 0xa849, 0xa84a, 0xa84b,
 9371|  34.3k|      0xa84c, 0xa84d, 0xa84e, 0xa84f, 0xa850, 0xa851, 0xa852, 0xa853, 0xa854,
 9372|  34.3k|      0xa855, 0xa856, 0xa857, 0xa858, 0xa859, 0xa85a, 0xa85b, 0xa85c, 0xa85d,
 9373|  34.3k|      0xa85e, 0xa85f, 0xa860, 0xa861, 0xa862, 0xa863, 0xa864, 0xa865, 0xa866,
 9374|  34.3k|      0xa867, 0xa868, 0xa869, 0xa86a, 0xa86b, 0xa86c, 0xa86d, 0xa86e, 0xa86f,
 9375|  34.3k|      0xa870, 0xa871};
 9376|       |
 9377|   247k|  for (size_t i = 0; i < label.size(); i++) {
  ------------------
  |  Branch (9377:22): [True: 215k, False: 32.2k]
  ------------------
 9378|   215k|    uint32_t c = label[i];
 9379|   215k|    if (c == 0x200c) {
  ------------------
  |  Branch (9379:9): [True: 1.43k, False: 213k]
  ------------------
 9380|  1.43k|      if (i > 0) {
  ------------------
  |  Branch (9380:11): [True: 1.41k, False: 20]
  ------------------
 9381|  1.41k|        if (std::binary_search(std::begin(virama), std::end(virama),
  ------------------
  |  Branch (9381:13): [True: 247, False: 1.16k]
  ------------------
 9382|  1.41k|                               label[i - 1])) {
 9383|    247|          return true;
 9384|    247|        }
 9385|  1.41k|      }
 9386|  1.18k|      if ((i == 0) || (i + 1 >= label.size())) {
  ------------------
  |  Branch (9386:11): [True: 20, False: 1.16k]
  |  Branch (9386:23): [True: 111, False: 1.05k]
  ------------------
 9387|    131|        return false;
 9388|    131|      }
 9389|       |      // we go backward looking for L or D
 9390|  1.05k|      auto is_l_or_d = [](uint32_t code) {
 9391|  1.05k|        return std::binary_search(std::begin(L), std::end(L), code) ||
 9392|  1.05k|               std::binary_search(std::begin(D), std::end(D), code);
 9393|  1.05k|      };
 9394|  1.05k|      auto is_r_or_d = [](uint32_t code) {
 9395|  1.05k|        return std::binary_search(std::begin(R), std::end(R), code) ||
 9396|  1.05k|               std::binary_search(std::begin(D), std::end(D), code);
 9397|  1.05k|      };
 9398|  1.05k|      std::u32string_view before = label.substr(0, i);
 9399|  1.05k|      std::u32string_view after = label.substr(i + 1);
 9400|  1.05k|      return (std::find_if(before.begin(), before.end(), is_l_or_d) !=
  ------------------
  |  Branch (9400:14): [True: 926, False: 128]
  ------------------
 9401|  1.05k|              before.end()) &&
 9402|  1.05k|             (std::find_if(after.begin(), after.end(), is_r_or_d) !=
  ------------------
  |  Branch (9402:14): [True: 753, False: 173]
  ------------------
 9403|    926|              after.end());
 9404|   213k|    } else if (c == 0x200d) {
  ------------------
  |  Branch (9404:16): [True: 689, False: 213k]
  ------------------
 9405|    689|      if (i > 0) {
  ------------------
  |  Branch (9405:11): [True: 675, False: 14]
  ------------------
 9406|    675|        if (std::binary_search(std::begin(virama), std::end(virama),
  ------------------
  |  Branch (9406:13): [True: 583, False: 92]
  ------------------
 9407|    675|                               label[i - 1])) {
 9408|    583|          return true;
 9409|    583|        }
 9410|    675|      }
 9411|    106|      return false;
 9412|    689|    }
 9413|   215k|  }
 9414|       |
 9415|       |  // If CheckBidi, and if the domain name is a  Bidi domain name, then the label
 9416|       |  // must satisfy all six of the numbered conditions in [IDNA2008] RFC 5893,
 9417|       |  // Section 2.
 9418|       |
 9419|       |  // The following rule, consisting of six conditions, applies to labels
 9420|       |  // in Bidi domain names.  The requirements that this rule satisfies are
 9421|       |  // described in Section 3.  All of the conditions must be satisfied for
 9422|       |  // the rule to be satisfied.
 9423|       |  //
 9424|       |  //  1.  The first character must be a character with Bidi property L, R,
 9425|       |  //     or AL.  If it has the R or AL property, it is an RTL label; if it
 9426|       |  //     has the L property, it is an LTR label.
 9427|       |  //
 9428|       |  //  2.  In an RTL label, only characters with the Bidi properties R, AL,
 9429|       |  //      AN, EN, ES, CS, ET, ON, BN, or NSM are allowed.
 9430|       |  //
 9431|       |  //   3.  In an RTL label, the end of the label must be a character with
 9432|       |  //       Bidi property R, AL, EN, or AN, followed by zero or more
 9433|       |  //       characters with Bidi property NSM.
 9434|       |  //
 9435|       |  //   4.  In an RTL label, if an EN is present, no AN may be present, and
 9436|       |  //       vice versa.
 9437|       |  //
 9438|       |  //  5.  In an LTR label, only characters with the Bidi properties L, EN,
 9439|       |  //       ES, CS, ET, ON, BN, or NSM are allowed.
 9440|       |  //
 9441|       |  //   6.  In an LTR label, the end of the label must be a character with
 9442|       |  //       Bidi property L or EN, followed by zero or more characters with
 9443|       |  //       Bidi property NSM.
 9444|       |
 9445|  32.2k|  size_t last_non_nsm_char = find_last_not_of_nsm(label);
 9446|  32.2k|  if (last_non_nsm_char == std::u32string_view::npos) {
  ------------------
  |  Branch (9446:7): [True: 0, False: 32.2k]
  ------------------
 9447|      0|    return false;
 9448|      0|  }
 9449|       |
 9450|       |  // A "Bidi domain name" is a domain name that contains at least one RTL label.
 9451|       |  // The following rule, consisting of six conditions, applies to labels in Bidi
 9452|       |  // domain names.
 9453|  32.2k|  if (is_rtl_label(label)) {
  ------------------
  |  Branch (9453:7): [True: 2.75k, False: 29.5k]
  ------------------
 9454|       |    // The first character must be a character with Bidi property L, R,
 9455|       |    // or AL. If it has the R or AL property, it is an RTL label; if it
 9456|       |    // has the L property, it is an LTR label.
 9457|       |
 9458|  2.75k|    if (find_direction(label[0]) == direction::L) {
  ------------------
  |  Branch (9458:9): [True: 598, False: 2.15k]
  ------------------
 9459|       |      // Eval as LTR
 9460|       |
 9461|       |      // In an LTR label, only characters with the Bidi properties L, EN,
 9462|       |      // ES, CS, ET, ON, BN, or NSM are allowed.
 9463|  3.79k|      for (size_t i = 0; i < last_non_nsm_char; i++) {
  ------------------
  |  Branch (9463:26): [True: 3.32k, False: 461]
  ------------------
 9464|  3.32k|        const direction d = find_direction(label[i]);
 9465|  3.32k|        if (!(d == direction::L || d == direction::EN || d == direction::ES ||
  ------------------
  |  Branch (9465:15): [True: 1.13k, False: 2.19k]
  |  Branch (9465:36): [True: 375, False: 1.81k]
  |  Branch (9465:58): [True: 303, False: 1.51k]
  ------------------
 9466|  3.32k|              d == direction::CS || d == direction::ET || d == direction::ON ||
  ------------------
  |  Branch (9466:15): [True: 347, False: 1.16k]
  |  Branch (9466:37): [True: 205, False: 960]
  |  Branch (9466:59): [True: 342, False: 618]
  ------------------
 9467|  3.32k|              d == direction::BN || d == direction::NSM)) {
  ------------------
  |  Branch (9467:15): [True: 276, False: 342]
  |  Branch (9467:37): [True: 205, False: 137]
  ------------------
 9468|    137|          return false;
 9469|    137|        }
 9470|       |
 9471|  3.19k|        if ((i == last_non_nsm_char) &&
  ------------------
  |  Branch (9471:13): [True: 0, False: 3.19k]
  ------------------
 9472|  3.19k|            !(d == direction::L || d == direction::EN)) {
  ------------------
  |  Branch (9472:15): [True: 0, False: 0]
  |  Branch (9472:36): [True: 0, False: 0]
  ------------------
 9473|      0|          return false;
 9474|      0|        }
 9475|  3.19k|      }
 9476|       |
 9477|    461|      return true;
 9478|       |
 9479|  2.15k|    } else {
 9480|       |      // Eval as RTL
 9481|       |
 9482|  2.15k|      bool has_an = false;
 9483|  2.15k|      bool has_en = false;
 9484|  7.48k|      for (size_t i = 0; i <= last_non_nsm_char; i++) {
  ------------------
  |  Branch (9484:26): [True: 5.57k, False: 1.90k]
  ------------------
 9485|  5.57k|        const direction d = find_direction(label[i]);
 9486|       |
 9487|       |        // In an RTL label, if an EN is present, no AN may be present, and vice
 9488|       |        // versa.
 9489|  5.57k|        if ((d == direction::EN && ((has_en = true) && has_an)) ||
  ------------------
  |  Branch (9489:14): [True: 618, False: 4.95k]
  |  Branch (9489:37): [True: 618, False: 0]
  |  Branch (9489:56): [True: 10, False: 608]
  ------------------
 9490|  5.57k|            (d == direction::AN && ((has_an = true) && has_en))) {
  ------------------
  |  Branch (9490:14): [True: 710, False: 4.85k]
  |  Branch (9490:37): [True: 710, False: 0]
  |  Branch (9490:56): [True: 10, False: 700]
  ------------------
 9491|     20|          return false;
 9492|     20|        }
 9493|       |
 9494|  5.55k|        if (!(d == direction::R || d == direction::AL || d == direction::AN ||
  ------------------
  |  Branch (9494:15): [True: 870, False: 4.68k]
  |  Branch (9494:36): [True: 1.55k, False: 3.13k]
  |  Branch (9494:58): [True: 700, False: 2.43k]
  ------------------
 9495|  5.55k|              d == direction::EN || d == direction::ES || d == direction::CS ||
  ------------------
  |  Branch (9495:15): [True: 608, False: 1.82k]
  |  Branch (9495:37): [True: 343, False: 1.48k]
  |  Branch (9495:59): [True: 268, False: 1.21k]
  ------------------
 9496|  5.55k|              d == direction::ET || d == direction::ON || d == direction::BN ||
  ------------------
  |  Branch (9496:15): [True: 211, False: 1.00k]
  |  Branch (9496:37): [True: 260, False: 741]
  |  Branch (9496:59): [True: 331, False: 410]
  ------------------
 9497|  5.55k|              d == direction::NSM)) {
  ------------------
  |  Branch (9497:15): [True: 246, False: 164]
  ------------------
 9498|    164|          return false;
 9499|    164|        }
 9500|       |
 9501|  5.39k|        if (i == last_non_nsm_char &&
  ------------------
  |  Branch (9501:13): [True: 1.97k, False: 3.41k]
  ------------------
 9502|  5.39k|            !(d == direction::R || d == direction::AL || d == direction::AN ||
  ------------------
  |  Branch (9502:15): [True: 329, False: 1.64k]
  |  Branch (9502:36): [True: 894, False: 750]
  |  Branch (9502:58): [True: 434, False: 316]
  ------------------
 9503|  1.97k|              d == direction::EN)) {
  ------------------
  |  Branch (9503:15): [True: 251, False: 65]
  ------------------
 9504|     65|          return false;
 9505|     65|        }
 9506|  5.39k|      }
 9507|       |
 9508|  1.90k|      return true;
 9509|  2.15k|    }
 9510|  2.75k|  }
 9511|       |
 9512|  29.5k|  return true;
 9513|  32.2k|}
_ZN3ada4idna8to_asciiENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9639|  24.8k|std::string to_ascii(std::string_view ut8_string) {
 9640|  24.8k|  if (is_ascii(ut8_string)) {
  ------------------
  |  Branch (9640:7): [True: 15.0k, False: 9.77k]
  ------------------
 9641|  15.0k|    return from_ascii_to_ascii(ut8_string);
 9642|  15.0k|  }
 9643|  9.77k|  static const std::string error = "";
 9644|       |  // We convert to UTF-32
 9645|  9.77k|  size_t utf32_length =
 9646|  9.77k|      ada::idna::utf32_length_from_utf8(ut8_string.data(), ut8_string.size());
 9647|  9.77k|  std::u32string utf32(utf32_length, '\0');
 9648|  9.77k|  size_t actual_utf32_length = ada::idna::utf8_to_utf32(
 9649|  9.77k|      ut8_string.data(), ut8_string.size(), utf32.data());
 9650|  9.77k|  if (actual_utf32_length == 0) {
  ------------------
  |  Branch (9650:7): [True: 3.02k, False: 6.75k]
  ------------------
 9651|  3.02k|    return error;
 9652|  3.02k|  }
 9653|       |  // mapping
 9654|  6.75k|  utf32 = ada::idna::map(utf32);
 9655|  6.75k|  normalize(utf32);
 9656|  6.75k|  std::string out;
 9657|  6.75k|  size_t label_start = 0;
 9658|       |
 9659|  39.7k|  while (label_start != utf32.size()) {
  ------------------
  |  Branch (9659:10): [True: 34.2k, False: 5.52k]
  ------------------
 9660|  34.2k|    size_t loc_dot = utf32.find('.', label_start);
 9661|  34.2k|    bool is_last_label = (loc_dot == std::string_view::npos);
 9662|  34.2k|    size_t label_size =
 9663|  34.2k|        is_last_label ? utf32.size() - label_start : loc_dot - label_start;
  ------------------
  |  Branch (9663:9): [True: 6.22k, False: 28.0k]
  ------------------
 9664|  34.2k|    size_t label_size_with_dot = is_last_label ? label_size : label_size + 1;
  ------------------
  |  Branch (9664:34): [True: 6.22k, False: 28.0k]
  ------------------
 9665|  34.2k|    std::u32string_view label_view(utf32.data() + label_start, label_size);
 9666|  34.2k|    label_start += label_size_with_dot;
 9667|  34.2k|    if (label_size == 0) {
  ------------------
  |  Branch (9667:9): [True: 3.61k, False: 30.6k]
  ------------------
 9668|       |      // empty label? Nothing to do.
 9669|  30.6k|    } else if (begins_with(label_view, U"xn--")) {
  ------------------
  |  Branch (9669:16): [True: 2.03k, False: 28.5k]
  ------------------
 9670|       |      // we do not need to check, e.g., Xn-- because mapping goes to lower case
 9671|  21.4k|      for (char32_t c : label_view) {
  ------------------
  |  Branch (9671:23): [True: 21.4k, False: 2.01k]
  ------------------
 9672|  21.4k|        if (c >= 0x80) {
  ------------------
  |  Branch (9672:13): [True: 28, False: 21.4k]
  ------------------
 9673|     28|          return error;
 9674|     28|        }
 9675|  21.4k|        out += (unsigned char)(c);
 9676|  21.4k|      }
 9677|  2.01k|      std::string_view puny_segment_ascii(
 9678|  2.01k|          out.data() + out.size() - label_view.size() + 4,
 9679|  2.01k|          label_view.size() - 4);
 9680|  2.01k|      std::u32string tmp_buffer;
 9681|  2.01k|      bool is_ok = ada::idna::punycode_to_utf32(puny_segment_ascii, tmp_buffer);
 9682|  2.01k|      if (!is_ok) {
  ------------------
  |  Branch (9682:11): [True: 69, False: 1.94k]
  ------------------
 9683|     69|        return error;
 9684|     69|      }
 9685|  1.94k|      std::u32string post_map = ada::idna::map(tmp_buffer);
 9686|  1.94k|      if (tmp_buffer != post_map) {
  ------------------
  |  Branch (9686:11): [True: 70, False: 1.87k]
  ------------------
 9687|     70|        return error;
 9688|     70|      }
 9689|  1.87k|      std::u32string pre_normal = post_map;
 9690|  1.87k|      normalize(post_map);
 9691|  1.87k|      if (post_map != pre_normal) {
  ------------------
  |  Branch (9691:11): [True: 36, False: 1.83k]
  ------------------
 9692|     36|        return error;
 9693|     36|      }
 9694|  1.83k|      if (post_map.empty()) {
  ------------------
  |  Branch (9694:11): [True: 59, False: 1.77k]
  ------------------
 9695|     59|        return error;
 9696|     59|      }
 9697|  1.77k|      if (!is_label_valid(post_map)) {
  ------------------
  |  Branch (9697:11): [True: 12, False: 1.76k]
  ------------------
 9698|     12|        return error;
 9699|     12|      }
 9700|  28.5k|    } else {
 9701|       |      // The fast path here is an ascii label.
 9702|  28.5k|      if (is_ascii(label_view)) {
  ------------------
  |  Branch (9702:11): [True: 3.15k, False: 25.4k]
  ------------------
 9703|       |        // no validation needed.
 9704|  21.6k|        for (char32_t c : label_view) {
  ------------------
  |  Branch (9704:25): [True: 21.6k, False: 3.15k]
  ------------------
 9705|  21.6k|          out += (unsigned char)(c);
 9706|  21.6k|        }
 9707|  25.4k|      } else {
 9708|       |        // slow path.
 9709|       |        // first check validity.
 9710|  25.4k|        if (!is_label_valid(label_view)) {
  ------------------
  |  Branch (9710:13): [True: 961, False: 24.4k]
  ------------------
 9711|    961|          return error;
 9712|    961|        }
 9713|       |        // It is valid! So now we must encode it as punycode...
 9714|  24.4k|        out.append("xn--");
 9715|  24.4k|        bool is_ok = ada::idna::utf32_to_punycode(label_view, out);
 9716|  24.4k|        if (!is_ok) {
  ------------------
  |  Branch (9716:13): [True: 0, False: 24.4k]
  ------------------
 9717|      0|          return error;
 9718|      0|        }
 9719|  24.4k|      }
 9720|  28.5k|    }
 9721|  33.0k|    if (!is_last_label) {
  ------------------
  |  Branch (9721:9): [True: 27.9k, False: 5.03k]
  ------------------
 9722|  27.9k|      out.push_back('.');
 9723|  27.9k|    }
 9724|  33.0k|  }
 9725|  5.52k|  return out;
 9726|  6.75k|}
_ZN3ada4idna10to_unicodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9736|  14.1k|std::string to_unicode(std::string_view input) {
 9737|  14.1k|  std::string output;
 9738|  14.1k|  output.reserve(input.size());
 9739|       |
 9740|  14.1k|  size_t label_start = 0;
 9741|  44.5k|  while (label_start < input.size()) {
  ------------------
  |  Branch (9741:10): [True: 30.4k, False: 14.1k]
  ------------------
 9742|  30.4k|    size_t loc_dot = input.find('.', label_start);
 9743|  30.4k|    bool is_last_label = (loc_dot == std::string_view::npos);
 9744|  30.4k|    size_t label_size =
 9745|  30.4k|        is_last_label ? input.size() - label_start : loc_dot - label_start;
  ------------------
  |  Branch (9745:9): [True: 12.2k, False: 18.2k]
  ------------------
 9746|  30.4k|    auto label_view = std::string_view(input.data() + label_start, label_size);
 9747|       |
 9748|  30.4k|    if (ada::idna::begins_with(label_view, "xn--") &&
  ------------------
  |  Branch (9748:9): [True: 2.48k, False: 27.9k]
  ------------------
 9749|  30.4k|        ada::idna::is_ascii(label_view)) {
  ------------------
  |  Branch (9749:9): [True: 2.32k, False: 162]
  ------------------
 9750|  2.32k|      label_view.remove_prefix(4);
 9751|  2.32k|      if (ada::idna::verify_punycode(label_view)) {
  ------------------
  |  Branch (9751:11): [True: 1.43k, False: 892]
  ------------------
 9752|  1.43k|        std::u32string tmp_buffer;
 9753|  1.43k|        if (ada::idna::punycode_to_utf32(label_view, tmp_buffer)) {
  ------------------
  |  Branch (9753:13): [True: 1.43k, False: 0]
  ------------------
 9754|  1.43k|          auto utf8_size = ada::idna::utf8_length_from_utf32(tmp_buffer.data(),
 9755|  1.43k|                                                             tmp_buffer.size());
 9756|  1.43k|          std::string final_utf8(utf8_size, '\0');
 9757|  1.43k|          ada::idna::utf32_to_utf8(tmp_buffer.data(), tmp_buffer.size(),
 9758|  1.43k|                                   final_utf8.data());
 9759|  1.43k|          output.append(final_utf8);
 9760|  1.43k|        } else {
 9761|       |          // ToUnicode never fails.  If any step fails, then the original input
 9762|       |          // sequence is returned immediately in that step.
 9763|      0|          output.append(
 9764|      0|              std::string_view(input.data() + label_start, label_size));
 9765|      0|        }
 9766|  1.43k|      } else {
 9767|    892|        output.append(std::string_view(input.data() + label_start, label_size));
 9768|    892|      }
 9769|  28.1k|    } else {
 9770|  28.1k|      output.append(label_view);
 9771|  28.1k|    }
 9772|       |
 9773|  30.4k|    if (!is_last_label) {
  ------------------
  |  Branch (9773:9): [True: 18.2k, False: 12.2k]
  ------------------
 9774|  18.2k|      output.push_back('.');
 9775|  18.2k|    }
 9776|       |
 9777|  30.4k|    label_start += label_size + 1;
 9778|  30.4k|  }
 9779|       |
 9780|  14.1k|  return output;
 9781|  14.1k|}
_ZN3ada7unicode14percent_decodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEm:
10160|  1.15k|std::string percent_decode(const std::string_view input, size_t first_percent) {
10161|       |  // next line is for safety only, we expect users to avoid calling
10162|       |  // percent_decode when first_percent is outside the range.
10163|  1.15k|  if (first_percent == std::string_view::npos) {
  ------------------
  |  Branch (10163:7): [True: 0, False: 1.15k]
  ------------------
10164|      0|    return std::string(input);
10165|      0|  }
10166|  1.15k|  std::string dest(input.substr(0, first_percent));
10167|  1.15k|  dest.reserve(input.length());
10168|  1.15k|  const char* pointer = input.data() + first_percent;
10169|  1.15k|  const char* end = input.data() + input.size();
10170|       |  // Optimization opportunity: if the following code gets
10171|       |  // called often, it can be optimized quite a bit.
10172|  26.9k|  while (pointer < end) {
  ------------------
  |  Branch (10172:10): [True: 25.7k, False: 1.15k]
  ------------------
10173|  25.7k|    const char ch = pointer[0];
10174|  25.7k|    size_t remaining = end - pointer - 1;
10175|  25.7k|    if (ch != '%' || remaining < 2 ||
  ------------------
  |  Branch (10175:9): [True: 9.69k, False: 16.0k]
  |  Branch (10175:22): [True: 267, False: 15.8k]
  ------------------
10176|  25.7k|        (  // ch == '%' && // It is unnecessary to check that ch == '%'.
10177|  15.8k|            (!is_ascii_hex_digit(pointer[1]) ||
  ------------------
  |  Branch (10177:14): [True: 618, False: 15.2k]
  ------------------
10178|  15.8k|             !is_ascii_hex_digit(pointer[2])))) {
  ------------------
  |  Branch (10178:14): [True: 580, False: 14.6k]
  ------------------
10179|  11.1k|      dest += ch;
10180|  11.1k|      pointer++;
10181|  11.1k|      continue;
10182|  14.6k|    } else {
10183|  14.6k|      unsigned a = convert_hex_to_binary(pointer[1]);
10184|  14.6k|      unsigned b = convert_hex_to_binary(pointer[2]);
10185|  14.6k|      char c = static_cast<char>(a * 16 + b);
10186|  14.6k|      dest += c;
10187|  14.6k|      pointer += 3;
10188|  14.6k|    }
10189|  25.7k|  }
10190|  1.15k|  return dest;
10191|  1.15k|}
_ZN3ada7unicode14percent_encodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKh:
10194|  30.2k|                           const uint8_t character_set[]) {
10195|  30.2k|  auto pointer =
10196|  30.2k|      std::find_if(input.begin(), input.end(), [character_set](const char c) {
10197|  30.2k|        return character_sets::bit_at(character_set, c);
10198|  30.2k|      });
10199|       |  // Optimization: Don't iterate if percent encode is not required
10200|  30.2k|  if (pointer == input.end()) {
  ------------------
  |  Branch (10200:7): [True: 21.9k, False: 8.31k]
  ------------------
10201|  21.9k|    return std::string(input);
10202|  21.9k|  }
10203|       |
10204|  8.31k|  std::string result(input.substr(0, std::distance(input.begin(), pointer)));
10205|  8.31k|  result.reserve(input.length());  // in the worst case, percent encoding might
10206|       |                                   // produce 3 characters.
10207|       |
10208|   237k|  for (; pointer != input.end(); pointer++) {
  ------------------
  |  Branch (10208:10): [True: 229k, False: 8.31k]
  ------------------
10209|   229k|    if (character_sets::bit_at(character_set, *pointer)) {
  ------------------
  |  Branch (10209:9): [True: 165k, False: 64.0k]
  ------------------
10210|   165k|      result.append(character_sets::hex + uint8_t(*pointer) * 4, 3);
10211|   165k|    } else {
10212|  64.0k|      result += *pointer;
10213|  64.0k|    }
10214|   229k|  }
10215|       |
10216|  8.31k|  return result;
10217|  30.2k|}
_ZN3ada7unicode8to_asciiERNSt3__18optionalINS1_12basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEEENS1_17basic_string_viewIcS5_EEm:
10255|  10.7k|              size_t first_percent) {
10256|  10.7k|  std::string percent_decoded_buffer;
10257|  10.7k|  std::string_view input = plain;
10258|  10.7k|  if (first_percent != std::string_view::npos) {
  ------------------
  |  Branch (10258:7): [True: 1.15k, False: 9.56k]
  ------------------
10259|  1.15k|    percent_decoded_buffer = unicode::percent_decode(plain, first_percent);
10260|  1.15k|    input = percent_decoded_buffer;
10261|  1.15k|  }
10262|       |  // input is a non-empty UTF-8 string, must be percent decoded
10263|  10.7k|  std::string idna_ascii = ada::idna::to_ascii(input);
10264|  10.7k|  if (idna_ascii.empty() || contains_forbidden_domain_code_point(
  ------------------
  |  Branch (10264:7): [True: 2.33k, False: 8.39k]
  |  Branch (10264:29): [True: 1.22k, False: 7.16k]
  ------------------
10265|  8.39k|                                idna_ascii.data(), idna_ascii.size())) {
10266|  3.55k|    return false;
10267|  3.55k|  }
10268|  7.16k|  out = std::move(idna_ascii);
10269|  7.16k|  return true;
10270|  10.7k|}
_ZN3ada7unicode14percent_encodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKhm:
10273|  1.56k|                           const uint8_t character_set[], size_t index) {
10274|  1.56k|  std::string out;
10275|  1.56k|  out.append(input.data(), index);
10276|  1.56k|  auto pointer = input.begin() + index;
10277|  66.7k|  for (; pointer != input.end(); pointer++) {
  ------------------
  |  Branch (10277:10): [True: 65.1k, False: 1.56k]
  ------------------
10278|  65.1k|    if (character_sets::bit_at(character_set, *pointer)) {
  ------------------
  |  Branch (10278:9): [True: 55.5k, False: 9.63k]
  ------------------
10279|  55.5k|      out.append(character_sets::hex + uint8_t(*pointer) * 4, 3);
10280|  55.5k|    } else {
10281|  9.63k|      out += *pointer;
10282|  9.63k|    }
10283|  65.1k|  }
10284|  1.56k|  return out;
10285|  1.56k|}
_ZN3ada11serializers36find_longest_sequence_of_ipv6_piecesERKNSt3__15arrayItLm8EEERmS6_:
10302|    600|    size_t& compress_length) noexcept {
10303|  2.33k|  for (size_t i = 0; i < 8; i++) {
  ------------------
  |  Branch (10303:22): [True: 1.93k, False: 398]
  ------------------
10304|  1.93k|    if (address[i] == 0) {
  ------------------
  |  Branch (10304:9): [True: 751, False: 1.18k]
  ------------------
10305|    751|      size_t next = i + 1;
10306|  3.34k|      while (next != 8 && address[next] == 0) ++next;
  ------------------
  |  Branch (10306:14): [True: 3.01k, False: 328]
  |  Branch (10306:27): [True: 2.59k, False: 423]
  ------------------
10307|    751|      const size_t count = next - i;
10308|    751|      if (compress_length < count) {
  ------------------
  |  Branch (10308:11): [True: 564, False: 187]
  ------------------
10309|    564|        compress_length = count;
10310|    564|        compress = i;
10311|    564|        if (next == 8) break;
  ------------------
  |  Branch (10311:13): [True: 202, False: 362]
  ------------------
10312|    362|        i = next;
10313|    362|      }
10314|    751|    }
10315|  1.93k|  }
10316|    600|}
_ZN3ada11serializers4ipv6ERKNSt3__15arrayItLm8EEE:
10318|    600|std::string ipv6(const std::array<uint16_t, 8>& address) noexcept {
10319|    600|  size_t compress_length = 0;  // The length of a long sequence of zeros.
10320|    600|  size_t compress = 0;         // The start of a long sequence of zeros.
10321|    600|  find_longest_sequence_of_ipv6_pieces(address, compress, compress_length);
10322|       |
10323|    600|  if (compress_length <= 1) {
  ------------------
  |  Branch (10323:7): [True: 112, False: 488]
  ------------------
10324|       |    // Optimization opportunity: Find a faster way then snprintf for imploding
10325|       |    // and return here.
10326|    112|    compress = compress_length = 8;
10327|    112|  }
10328|       |
10329|    600|  std::string output(4 * 8 + 7 + 2, '\0');
10330|    600|  size_t piece_index = 0;
10331|    600|  char* point = output.data();
10332|    600|  char* point_end = output.data() + output.size();
10333|    600|  *point++ = '[';
10334|  2.01k|  while (true) {
  ------------------
  |  Branch (10334:10): [Folded - Ignored]
  ------------------
10335|  2.01k|    if (piece_index == compress) {
  ------------------
  |  Branch (10335:9): [True: 488, False: 1.52k]
  ------------------
10336|    488|      *point++ = ':';
10337|       |      // If we skip a value initially, we need to write '::', otherwise
10338|       |      // a single ':' will do since it follows a previous ':'.
10339|    488|      if (piece_index == 0) {
  ------------------
  |  Branch (10339:11): [True: 301, False: 187]
  ------------------
10340|    301|        *point++ = ':';
10341|    301|      }
10342|    488|      piece_index += compress_length;
10343|    488|      if (piece_index == 8) {
  ------------------
  |  Branch (10343:11): [True: 198, False: 290]
  ------------------
10344|    198|        break;
10345|    198|      }
10346|    488|    }
10347|  1.81k|    point = std::to_chars(point, point_end, address[piece_index], 16).ptr;
10348|  1.81k|    piece_index++;
10349|  1.81k|    if (piece_index == 8) {
  ------------------
  |  Branch (10349:9): [True: 402, False: 1.41k]
  ------------------
10350|    402|      break;
10351|    402|    }
10352|  1.41k|    *point++ = ':';
10353|  1.41k|  }
10354|    600|  *point++ = ']';
10355|    600|  output.resize(point - output.data());
10356|    600|  return output;
10357|    600|}
_ZN3ada11serializers4ipv4Em:
10359|  4.37k|std::string ipv4(const uint64_t address) noexcept {
10360|  4.37k|  std::string output(15, '\0');
10361|  4.37k|  char* point = output.data();
10362|  4.37k|  char* point_end = output.data() + output.size();
10363|  4.37k|  point = std::to_chars(point, point_end, uint8_t(address >> 24)).ptr;
10364|  17.4k|  for (int i = 2; i >= 0; i--) {
  ------------------
  |  Branch (10364:19): [True: 13.1k, False: 4.37k]
  ------------------
10365|  13.1k|    *point++ = '.';
10366|  13.1k|    point = std::to_chars(point, point_end, uint8_t(address >> (i * 8))).ptr;
10367|  13.1k|  }
10368|  4.37k|  output.resize(point - output.data());
10369|  4.37k|  return output;
10370|  4.37k|}
_ZN3ada5parseINS_3urlEEEN2tl8expectedIT_NS_6errorsEEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEPKS4_:
10382|  14.5k|    std::string_view input, const result_type* base_url) {
10383|  14.5k|  result_type u = ada::parser::parse_url<result_type>(input, base_url);
10384|  14.5k|  if (!u.is_valid) {
  ------------------
  |  Branch (10384:7): [True: 6.10k, False: 8.40k]
  ------------------
10385|  6.10k|    return tl::unexpected(errors::generic_error);
10386|  6.10k|  }
10387|  8.40k|  return u;
10388|  14.5k|}
_ZN3ada5parseINS_14url_aggregatorEEEN2tl8expectedIT_NS_6errorsEEENSt3__117basic_string_viewIcNS7_11char_traitsIcEEEEPKS4_:
10382|  45.4k|    std::string_view input, const result_type* base_url) {
10383|  45.4k|  result_type u = ada::parser::parse_url<result_type>(input, base_url);
10384|  45.4k|  if (!u.is_valid) {
  ------------------
  |  Branch (10384:7): [True: 23.8k, False: 21.5k]
  ------------------
10385|  23.8k|    return tl::unexpected(errors::generic_error);
10386|  23.8k|  }
10387|  21.5k|  return u;
10388|  45.4k|}
_ZN3ada14href_from_fileENSt3__117basic_string_viewIcNS0_11char_traitsIcEEEE:
10395|  14.1k|std::string href_from_file(std::string_view input) {
10396|       |  // This is going to be much faster than constructing a URL.
10397|  14.1k|  std::string tmp_buffer;
10398|  14.1k|  std::string_view internal_input;
10399|  14.1k|  if (unicode::has_tabs_or_newline(input)) {
  ------------------
  |  Branch (10399:7): [True: 202, False: 13.9k]
  ------------------
10400|    202|    tmp_buffer = input;
10401|    202|    helpers::remove_ascii_tab_or_newline(tmp_buffer);
10402|    202|    internal_input = tmp_buffer;
10403|  13.9k|  } else {
10404|  13.9k|    internal_input = input;
10405|  13.9k|  }
10406|  14.1k|  std::string path;
10407|  14.1k|  if (internal_input.empty()) {
  ------------------
  |  Branch (10407:7): [True: 969, False: 13.1k]
  ------------------
10408|    969|    path = "/";
10409|  13.1k|  } else if ((internal_input[0] == '/') || (internal_input[0] == '\\')) {
  ------------------
  |  Branch (10409:14): [True: 766, False: 12.3k]
  |  Branch (10409:44): [True: 10, False: 12.3k]
  ------------------
10410|    776|    helpers::parse_prepared_path(internal_input.substr(1),
10411|    776|                                 ada::scheme::type::FILE, path);
10412|  12.3k|  } else {
10413|  12.3k|    helpers::parse_prepared_path(internal_input, ada::scheme::type::FILE, path);
10414|  12.3k|  }
10415|  14.1k|  return "file://" + path;
10416|  14.1k|}
_ZN3ada9can_parseENSt3__117basic_string_viewIcNS0_11char_traitsIcEEEEPKS4_:
10418|  28.2k|bool can_parse(std::string_view input, const std::string_view* base_input) {
10419|  28.2k|  ada::result<ada::url_aggregator> base;
10420|  28.2k|  ada::url_aggregator* base_pointer = nullptr;
10421|  28.2k|  if (base_input != nullptr) {
  ------------------
  |  Branch (10421:7): [True: 14.1k, False: 14.1k]
  ------------------
10422|  14.1k|    base = ada::parse<url_aggregator>(*base_input);
10423|  14.1k|    if (!base) {
  ------------------
  |  Branch (10423:9): [True: 11.4k, False: 2.66k]
  ------------------
10424|  11.4k|      return false;
10425|  11.4k|    }
10426|  2.66k|    base_pointer = &base.value();
10427|  2.66k|  }
10428|  16.7k|  return ada::parse<url_aggregator>(input, base_pointer).has_value();
10429|  28.2k|}
_ZN3ada3url17parse_opaque_hostENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11153|  1.00k|bool url::parse_opaque_host(std::string_view input) {
11154|  1.00k|  ada_log("parse_opaque_host ", input, "[", input.size(), " bytes]");
11155|  1.00k|  if (std::any_of(input.begin(), input.end(),
  ------------------
  |  Branch (11155:7): [True: 132, False: 876]
  ------------------
11156|  1.00k|                  ada::unicode::is_forbidden_host_code_point)) {
11157|    132|    return is_valid = false;
11158|    132|  }
11159|       |
11160|       |  // Return the result of running UTF-8 percent-encode on input using the C0
11161|       |  // control percent-encode set.
11162|    876|  host = ada::unicode::percent_encode(
11163|    876|      input, ada::character_sets::C0_CONTROL_PERCENT_ENCODE);
11164|    876|  return true;
11165|  1.00k|}
_ZN3ada3url10parse_ipv4ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11167|  2.15k|bool url::parse_ipv4(std::string_view input) {
11168|  2.15k|  ada_log("parse_ipv4 ", input, "[", input.size(), " bytes]");
11169|  2.15k|  if (input.back() == '.') {
  ------------------
  |  Branch (11169:7): [True: 34, False: 2.12k]
  ------------------
11170|     34|    input.remove_suffix(1);
11171|     34|  }
11172|  2.15k|  size_t digit_count{0};
11173|  2.15k|  int pure_decimal_count = 0;  // entries that are decimal
11174|  2.15k|  std::string_view original_input =
11175|  2.15k|      input;  // we might use this if pure_decimal_count == 4.
11176|  2.15k|  uint64_t ipv4{0};
11177|       |  // we could unroll for better performance?
11178|  2.67k|  for (; (digit_count < 4) && !(input.empty()); digit_count++) {
  ------------------
  |  Branch (11178:10): [True: 2.65k, False: 26]
  |  Branch (11178:31): [True: 2.65k, False: 0]
  ------------------
11179|  2.65k|    uint32_t
11180|  2.65k|        segment_result{};  // If any number exceeds 32 bits, we have an error.
11181|  2.65k|    bool is_hex = checkers::has_hex_prefix(input);
11182|  2.65k|    if (is_hex && ((input.length() == 2) ||
  ------------------
  |  Branch (11182:9): [True: 691, False: 1.96k]
  |  Branch (11182:20): [True: 33, False: 658]
  ------------------
11183|    691|                   ((input.length() > 2) && (input[2] == '.')))) {
  ------------------
  |  Branch (11183:21): [True: 658, False: 0]
  |  Branch (11183:45): [True: 26, False: 632]
  ------------------
11184|       |      // special case
11185|     59|      segment_result = 0;
11186|     59|      input.remove_prefix(2);
11187|  2.59k|    } else {
11188|  2.59k|      std::from_chars_result r;
11189|  2.59k|      if (is_hex) {
  ------------------
  |  Branch (11189:11): [True: 632, False: 1.96k]
  ------------------
11190|    632|        r = std::from_chars(input.data() + 2, input.data() + input.size(),
11191|    632|                            segment_result, 16);
11192|  1.96k|      } else if ((input.length() >= 2) && input[0] == '0' &&
  ------------------
  |  Branch (11192:18): [True: 1.04k, False: 919]
  |  Branch (11192:43): [True: 460, False: 582]
  ------------------
11193|  1.96k|                 checkers::is_digit(input[1])) {
  ------------------
  |  Branch (11193:18): [True: 347, False: 113]
  ------------------
11194|    347|        r = std::from_chars(input.data() + 1, input.data() + input.size(),
11195|    347|                            segment_result, 8);
11196|  1.61k|      } else {
11197|  1.61k|        pure_decimal_count++;
11198|  1.61k|        r = std::from_chars(input.data(), input.data() + input.size(),
11199|  1.61k|                            segment_result, 10);
11200|  1.61k|      }
11201|  2.59k|      if (r.ec != std::errc()) {
  ------------------
  |  Branch (11201:11): [True: 436, False: 2.15k]
  ------------------
11202|    436|        return is_valid = false;
11203|    436|      }
11204|  2.15k|      input.remove_prefix(r.ptr - input.data());
11205|  2.15k|    }
11206|  2.21k|    if (input.empty()) {
  ------------------
  |  Branch (11206:9): [True: 1.57k, False: 645]
  ------------------
11207|       |      // We have the last value.
11208|       |      // At this stage, ipv4 contains digit_count*8 bits.
11209|       |      // So we have 32-digit_count*8 bits left.
11210|  1.57k|      if (segment_result > (uint64_t(1) << (32 - digit_count * 8))) {
  ------------------
  |  Branch (11210:11): [True: 13, False: 1.55k]
  ------------------
11211|     13|        return is_valid = false;
11212|     13|      }
11213|  1.55k|      ipv4 <<= (32 - digit_count * 8);
11214|  1.55k|      ipv4 |= segment_result;
11215|  1.55k|      goto final;
11216|  1.57k|    } else {
11217|       |      // There is more, so that the value must no be larger than 255
11218|       |      // and we must have a '.'.
11219|    645|      if ((segment_result > 255) || (input[0] != '.')) {
  ------------------
  |  Branch (11219:11): [True: 66, False: 579]
  |  Branch (11219:37): [True: 57, False: 522]
  ------------------
11220|    123|        return is_valid = false;
11221|    123|      }
11222|    522|      ipv4 <<= 8;
11223|    522|      ipv4 |= segment_result;
11224|    522|      input.remove_prefix(1);  // remove '.'
11225|    522|    }
11226|  2.21k|  }
11227|     26|  if ((digit_count != 4) || (!input.empty())) {
  ------------------
  |  Branch (11227:7): [True: 0, False: 26]
  |  Branch (11227:29): [True: 26, False: 0]
  ------------------
11228|     26|    return is_valid = false;
11229|     26|  }
11230|  1.55k|final:
11231|       |  // We could also check r.ptr to see where the parsing ended.
11232|  1.55k|  if (pure_decimal_count == 4) {
  ------------------
  |  Branch (11232:7): [True: 43, False: 1.51k]
  ------------------
11233|     43|    host = original_input;  // The original input was already all decimal and we
11234|       |                            // validated it.
11235|  1.51k|  } else {
11236|  1.51k|    host = ada::serializers::ipv4(ipv4);  // We have to reserialize the address.
11237|  1.51k|  }
11238|  1.55k|  return true;
11239|     26|}
_ZN3ada3url10parse_ipv6ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11241|    532|bool url::parse_ipv6(std::string_view input) {
11242|    532|  ada_log("parse_ipv6 ", input, "[", input.size(), " bytes]");
11243|       |
11244|    532|  if (input.empty()) {
  ------------------
  |  Branch (11244:7): [True: 24, False: 508]
  ------------------
11245|     24|    return is_valid = false;
11246|     24|  }
11247|       |  // Let address be a new IPv6 address whose IPv6 pieces are all 0.
11248|    508|  std::array<uint16_t, 8> address{};
11249|       |
11250|       |  // Let pieceIndex be 0.
11251|    508|  int piece_index = 0;
11252|       |
11253|       |  // Let compress be null.
11254|    508|  std::optional<int> compress{};
11255|       |
11256|       |  // Let pointer be a pointer for input.
11257|    508|  std::string_view::iterator pointer = input.begin();
11258|       |
11259|       |  // If c is U+003A (:), then:
11260|    508|  if (input[0] == ':') {
  ------------------
  |  Branch (11260:7): [True: 119, False: 389]
  ------------------
11261|       |    // If remaining does not start with U+003A (:), validation error, return
11262|       |    // failure.
11263|    119|    if (input.size() == 1 || input[1] != ':') {
  ------------------
  |  Branch (11263:9): [True: 4, False: 115]
  |  Branch (11263:30): [True: 6, False: 109]
  ------------------
11264|     10|      ada_log("parse_ipv6 starts with : but the rest does not start with :");
11265|     10|      return is_valid = false;
11266|     10|    }
11267|       |
11268|       |    // Increase pointer by 2.
11269|    109|    pointer += 2;
11270|       |
11271|       |    // Increase pieceIndex by 1 and then set compress to pieceIndex.
11272|    109|    compress = ++piece_index;
11273|    109|  }
11274|       |
11275|       |  // While c is not the EOF code point:
11276|  1.41k|  while (pointer != input.end()) {
  ------------------
  |  Branch (11276:10): [True: 1.17k, False: 241]
  ------------------
11277|       |    // If pieceIndex is 8, validation error, return failure.
11278|  1.17k|    if (piece_index == 8) {
  ------------------
  |  Branch (11278:9): [True: 7, False: 1.17k]
  ------------------
11279|      7|      ada_log("parse_ipv6 piece_index == 8");
11280|      7|      return is_valid = false;
11281|      7|    }
11282|       |
11283|       |    // If c is U+003A (:), then:
11284|  1.17k|    if (*pointer == ':') {
  ------------------
  |  Branch (11284:9): [True: 82, False: 1.08k]
  ------------------
11285|       |      // If compress is non-null, validation error, return failure.
11286|     82|      if (compress.has_value()) {
  ------------------
  |  Branch (11286:11): [True: 6, False: 76]
  ------------------
11287|      6|        ada_log("parse_ipv6 compress is non-null");
11288|      6|        return is_valid = false;
11289|      6|      }
11290|       |
11291|       |      // Increase pointer and pieceIndex by 1, set compress to pieceIndex, and
11292|       |      // then continue.
11293|     76|      pointer++;
11294|     76|      compress = ++piece_index;
11295|     76|      continue;
11296|     82|    }
11297|       |
11298|       |    // Let value and length be 0.
11299|  1.08k|    uint16_t value = 0, length = 0;
11300|       |
11301|       |    // While length is less than 4 and c is an ASCII hex digit,
11302|       |    // set value to value × 0x10 + c interpreted as hexadecimal number, and
11303|       |    // increase pointer and length by 1.
11304|  2.84k|    while (length < 4 && pointer != input.end() &&
  ------------------
  |  Branch (11304:12): [True: 2.64k, False: 193]
  |  Branch (11304:26): [True: 2.52k, False: 126]
  ------------------
11305|  2.84k|           unicode::is_ascii_hex_digit(*pointer)) {
  ------------------
  |  Branch (11305:12): [True: 1.75k, False: 770]
  ------------------
11306|       |      // https://stackoverflow.com/questions/39060852/why-does-the-addition-of-two-shorts-return-an-int
11307|  1.75k|      value = uint16_t(value * 0x10 + unicode::convert_hex_to_binary(*pointer));
11308|  1.75k|      pointer++;
11309|  1.75k|      length++;
11310|  1.75k|    }
11311|       |
11312|       |    // If c is U+002E (.), then:
11313|  1.08k|    if (pointer != input.end() && *pointer == '.') {
  ------------------
  |  Branch (11313:9): [True: 907, False: 182]
  |  Branch (11313:35): [True: 119, False: 788]
  ------------------
11314|       |      // If length is 0, validation error, return failure.
11315|    119|      if (length == 0) {
  ------------------
  |  Branch (11315:11): [True: 6, False: 113]
  ------------------
11316|      6|        ada_log("parse_ipv6 length is 0");
11317|      6|        return is_valid = false;
11318|      6|      }
11319|       |
11320|       |      // Decrease pointer by length.
11321|    113|      pointer -= length;
11322|       |
11323|       |      // If pieceIndex is greater than 6, validation error, return failure.
11324|    113|      if (piece_index > 6) {
  ------------------
  |  Branch (11324:11): [True: 4, False: 109]
  ------------------
11325|      4|        ada_log("parse_ipv6 piece_index > 6");
11326|      4|        return is_valid = false;
11327|      4|      }
11328|       |
11329|       |      // Let numbersSeen be 0.
11330|    109|      int numbers_seen = 0;
11331|       |
11332|       |      // While c is not the EOF code point:
11333|    341|      while (pointer != input.end()) {
  ------------------
  |  Branch (11333:14): [True: 300, False: 41]
  ------------------
11334|       |        // Let ipv4Piece be null.
11335|    300|        std::optional<uint16_t> ipv4_piece{};
11336|       |
11337|       |        // If numbersSeen is greater than 0, then:
11338|    300|        if (numbers_seen > 0) {
  ------------------
  |  Branch (11338:13): [True: 191, False: 109]
  ------------------
11339|       |          // If c is a U+002E (.) and numbersSeen is less than 4, then increase
11340|       |          // pointer by 1.
11341|    191|          if (*pointer == '.' && numbers_seen < 4) {
  ------------------
  |  Branch (11341:15): [True: 175, False: 16]
  |  Branch (11341:34): [True: 169, False: 6]
  ------------------
11342|    169|            pointer++;
11343|    169|          }
11344|       |          // Otherwise, validation error, return failure.
11345|     22|          else {
11346|     22|            ada_log("parse_ipv6 Otherwise, validation error, return failure");
11347|     22|            return is_valid = false;
11348|     22|          }
11349|    191|        }
11350|       |
11351|       |        // If c is not an ASCII digit, validation error, return failure.
11352|    278|        if (pointer == input.end() || !checkers::is_digit(*pointer)) {
  ------------------
  |  Branch (11352:13): [True: 20, False: 258]
  |  Branch (11352:39): [True: 8, False: 250]
  ------------------
11353|     28|          ada_log(
11354|     28|              "parse_ipv6 If c is not an ASCII digit, validation error, return "
11355|     28|              "failure");
11356|     28|          return is_valid = false;
11357|     28|        }
11358|       |
11359|       |        // While c is an ASCII digit:
11360|    615|        while (pointer != input.end() && checkers::is_digit(*pointer)) {
  ------------------
  |  Branch (11360:16): [True: 574, False: 41]
  |  Branch (11360:42): [True: 383, False: 191]
  ------------------
11361|       |          // Let number be c interpreted as decimal number.
11362|    383|          int number = *pointer - '0';
11363|       |
11364|       |          // If ipv4Piece is null, then set ipv4Piece to number.
11365|    383|          if (!ipv4_piece.has_value()) {
  ------------------
  |  Branch (11365:15): [True: 250, False: 133]
  ------------------
11366|    250|            ipv4_piece = number;
11367|    250|          }
11368|       |          // Otherwise, if ipv4Piece is 0, validation error, return failure.
11369|    133|          else if (ipv4_piece == 0) {
  ------------------
  |  Branch (11369:20): [True: 4, False: 129]
  ------------------
11370|      4|            ada_log("parse_ipv6 if ipv4Piece is 0, validation error");
11371|      4|            return is_valid = false;
11372|      4|          }
11373|       |          // Otherwise, set ipv4Piece to ipv4Piece × 10 + number.
11374|    129|          else {
11375|    129|            ipv4_piece = *ipv4_piece * 10 + number;
11376|    129|          }
11377|       |
11378|       |          // If ipv4Piece is greater than 255, validation error, return failure.
11379|    379|          if (ipv4_piece > 255) {
  ------------------
  |  Branch (11379:15): [True: 14, False: 365]
  ------------------
11380|     14|            ada_log("parse_ipv6 ipv4_piece > 255");
11381|     14|            return is_valid = false;
11382|     14|          }
11383|       |
11384|       |          // Increase pointer by 1.
11385|    365|          pointer++;
11386|    365|        }
11387|       |
11388|       |        // Set address[pieceIndex] to address[pieceIndex] × 0x100 + ipv4Piece.
11389|       |        // https://stackoverflow.com/questions/39060852/why-does-the-addition-of-two-shorts-return-an-int
11390|    232|        address[piece_index] =
11391|    232|            uint16_t(address[piece_index] * 0x100 + *ipv4_piece);
11392|       |
11393|       |        // Increase numbersSeen by 1.
11394|    232|        numbers_seen++;
11395|       |
11396|       |        // If numbersSeen is 2 or 4, then increase pieceIndex by 1.
11397|    232|        if (numbers_seen == 2 || numbers_seen == 4) {
  ------------------
  |  Branch (11397:13): [True: 65, False: 167]
  |  Branch (11397:34): [True: 32, False: 135]
  ------------------
11398|     97|          piece_index++;
11399|     97|        }
11400|    232|      }
11401|       |
11402|       |      // If numbersSeen is not 4, validation error, return failure.
11403|     41|      if (numbers_seen != 4) {
  ------------------
  |  Branch (11403:11): [True: 15, False: 26]
  ------------------
11404|     15|        return is_valid = false;
11405|     15|      }
11406|       |
11407|       |      // Break.
11408|     26|      break;
11409|     41|    }
11410|       |    // Otherwise, if c is U+003A (:):
11411|    970|    else if ((pointer != input.end()) && (*pointer == ':')) {
  ------------------
  |  Branch (11411:14): [True: 788, False: 182]
  |  Branch (11411:42): [True: 671, False: 117]
  ------------------
11412|       |      // Increase pointer by 1.
11413|    671|      pointer++;
11414|       |
11415|       |      // If c is the EOF code point, validation error, return failure.
11416|    671|      if (pointer == input.end()) {
  ------------------
  |  Branch (11416:11): [True: 8, False: 663]
  ------------------
11417|      8|        ada_log(
11418|      8|            "parse_ipv6 If c is the EOF code point, validation error, return "
11419|      8|            "failure");
11420|      8|        return is_valid = false;
11421|      8|      }
11422|    671|    }
11423|       |    // Otherwise, if c is not the EOF code point, validation error, return
11424|       |    // failure.
11425|    299|    else if (pointer != input.end()) {
  ------------------
  |  Branch (11425:14): [True: 117, False: 182]
  ------------------
11426|    117|      ada_log(
11427|    117|          "parse_ipv6 Otherwise, if c is not the EOF code point, validation "
11428|    117|          "error, return failure");
11429|    117|      return is_valid = false;
11430|    117|    }
11431|       |
11432|       |    // Set address[pieceIndex] to value.
11433|    845|    address[piece_index] = value;
11434|       |
11435|       |    // Increase pieceIndex by 1.
11436|    845|    piece_index++;
11437|    845|  }
11438|       |
11439|       |  // If compress is non-null, then:
11440|    267|  if (compress.has_value()) {
  ------------------
  |  Branch (11440:7): [True: 167, False: 100]
  ------------------
11441|       |    // Let swaps be pieceIndex − compress.
11442|    167|    int swaps = piece_index - *compress;
11443|       |
11444|       |    // Set pieceIndex to 7.
11445|    167|    piece_index = 7;
11446|       |
11447|       |    // While pieceIndex is not 0 and swaps is greater than 0,
11448|       |    // swap address[pieceIndex] with address[compress + swaps − 1], and then
11449|       |    // decrease both pieceIndex and swaps by 1.
11450|    460|    while (piece_index != 0 && swaps > 0) {
  ------------------
  |  Branch (11450:12): [True: 449, False: 11]
  |  Branch (11450:32): [True: 293, False: 156]
  ------------------
11451|    293|      std::swap(address[piece_index], address[*compress + swaps - 1]);
11452|    293|      piece_index--;
11453|    293|      swaps--;
11454|    293|    }
11455|    167|  }
11456|       |  // Otherwise, if compress is null and pieceIndex is not 8, validation error,
11457|       |  // return failure.
11458|    100|  else if (piece_index != 8) {
  ------------------
  |  Branch (11458:12): [True: 79, False: 21]
  ------------------
11459|     79|    ada_log(
11460|     79|        "parse_ipv6 if compress is null and pieceIndex is not 8, validation "
11461|     79|        "error, return failure");
11462|     79|    return is_valid = false;
11463|     79|  }
11464|    188|  host = ada::serializers::ipv6(address);
11465|    188|  ada_log("parse_ipv6 ", *host);
11466|    188|  return true;
11467|    267|}
_ZNK3ada3url10get_originEv:
11742|  8.27k|[[nodiscard]] std::string url::get_origin() const noexcept {
11743|  8.27k|  if (is_special()) {
  ------------------
  |  Branch (11743:7): [True: 5.52k, False: 2.74k]
  ------------------
11744|       |    // Return a new opaque origin.
11745|  5.52k|    if (type == scheme::FILE) {
  ------------------
  |  Branch (11745:9): [True: 1.48k, False: 4.03k]
  ------------------
11746|  1.48k|      return "null";
11747|  1.48k|    }
11748|  4.03k|    return ada::helpers::concat(get_protocol(), "//", get_host());
11749|  5.52k|  }
11750|       |
11751|  2.74k|  if (non_special_scheme == "blob") {
  ------------------
  |  Branch (11751:7): [True: 398, False: 2.35k]
  ------------------
11752|    398|    if (!path.empty()) {
  ------------------
  |  Branch (11752:9): [True: 385, False: 13]
  ------------------
11753|    385|      auto result = ada::parse<ada::url>(path);
11754|    385|      if (result &&
  ------------------
  |  Branch (11754:11): [True: 130, False: 255]
  ------------------
11755|    385|          (result->type == scheme::HTTP || result->type == scheme::HTTPS)) {
  ------------------
  |  Branch (11755:12): [True: 9, False: 121]
  |  Branch (11755:44): [True: 1, False: 120]
  ------------------
11756|       |        // If pathURL’s scheme is not "http" and not "https", then return a
11757|       |        // new opaque origin.
11758|     10|        return ada::helpers::concat(result->get_protocol(), "//",
11759|     10|                                    result->get_host());
11760|     10|      }
11761|    385|    }
11762|    398|  }
11763|       |
11764|       |  // Return a new opaque origin.
11765|  2.73k|  return "null";
11766|  2.74k|}
_ZNK3ada3url12get_protocolEv:
11768|  12.3k|[[nodiscard]] std::string url::get_protocol() const noexcept {
11769|  12.3k|  if (is_special()) {
  ------------------
  |  Branch (11769:7): [True: 9.57k, False: 2.74k]
  ------------------
11770|  9.57k|    return helpers::concat(ada::scheme::details::is_special_list[type], ":");
11771|  9.57k|  }
11772|       |  // We only move the 'scheme' if it is non-special.
11773|  2.74k|  return helpers::concat(non_special_scheme, ":");
11774|  12.3k|}
_ZNK3ada3url8get_hostEv:
11776|  12.3k|[[nodiscard]] std::string url::get_host() const noexcept {
11777|       |  // If url’s host is null, then return the empty string.
11778|       |  // If url’s port is null, return url’s host, serialized.
11779|       |  // Return url’s host, serialized, followed by U+003A (:) and url’s port,
11780|       |  // serialized.
11781|  12.3k|  if (!host.has_value()) {
  ------------------
  |  Branch (11781:7): [True: 1.21k, False: 11.1k]
  ------------------
11782|  1.21k|    return "";
11783|  1.21k|  }
11784|  11.1k|  if (port.has_value()) {
  ------------------
  |  Branch (11784:7): [True: 467, False: 10.6k]
  ------------------
11785|    467|    return host.value() + ":" + get_port();
11786|    467|  }
11787|  10.6k|  return host.value();
11788|  11.1k|}
_ZNK3ada3url12get_hostnameEv:
11790|  8.27k|[[nodiscard]] std::string url::get_hostname() const noexcept {
11791|  8.27k|  return host.value_or("");
11792|  8.27k|}
_ZNK3ada3url12get_pathnameEv:
11794|  10.0k|[[nodiscard]] const std::string_view url::get_pathname() const noexcept {
11795|  10.0k|  return path;
11796|  10.0k|}
_ZNK3ada3url10get_searchEv:
11798|  8.27k|[[nodiscard]] std::string url::get_search() const noexcept {
11799|       |  // If this’s URL’s query is either null or the empty string, then return the
11800|       |  // empty string. Return U+003F (?), followed by this’s URL’s query.
11801|  8.27k|  return (!query.has_value() || (query.value().empty())) ? ""
  ------------------
  |  Branch (11801:11): [True: 5.24k, False: 3.02k]
  |  Branch (11801:33): [True: 57, False: 2.97k]
  ------------------
11802|  8.27k|                                                         : "?" + query.value();
11803|  8.27k|}
_ZNK3ada3url12get_usernameEv:
11805|  8.27k|[[nodiscard]] const std::string& url::get_username() const noexcept {
11806|  8.27k|  return username;
11807|  8.27k|}
_ZNK3ada3url12get_passwordEv:
11809|  8.27k|[[nodiscard]] const std::string& url::get_password() const noexcept {
11810|  8.27k|  return password;
11811|  8.27k|}
_ZNK3ada3url8get_portEv:
11813|  8.73k|[[nodiscard]] std::string url::get_port() const noexcept {
11814|  8.73k|  return port.has_value() ? std::to_string(port.value()) : "";
  ------------------
  |  Branch (11814:10): [True: 725, False: 8.01k]
  ------------------
11815|  8.73k|}
_ZNK3ada3url8get_hashEv:
11817|  8.27k|[[nodiscard]] std::string url::get_hash() const noexcept {
11818|       |  // If this’s URL’s fragment is either null or the empty string, then return
11819|       |  // the empty string. Return U+0023 (#), followed by this’s URL’s fragment.
11820|  8.27k|  return (!hash.has_value() || (hash.value().empty())) ? ""
  ------------------
  |  Branch (11820:11): [True: 5.24k, False: 3.02k]
  |  Branch (11820:32): [True: 56, False: 2.97k]
  ------------------
11821|  8.27k|                                                       : "#" + hash.value();
11822|  8.27k|}
_ZN3ada3url8set_hostENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11919|  8.27k|bool url::set_host(const std::string_view input) {
11920|  8.27k|  return set_host_or_hostname<false>(input);
11921|  8.27k|}
_ZN3ada3url12set_hostnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11923|  8.27k|bool url::set_hostname(const std::string_view input) {
11924|  8.27k|  return set_host_or_hostname<true>(input);
11925|  8.27k|}
_ZN3ada3url12set_usernameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11927|  8.27k|bool url::set_username(const std::string_view input) {
11928|  8.27k|  if (cannot_have_credentials_or_port()) {
  ------------------
  |  Branch (11928:7): [True: 4.03k, False: 4.23k]
  ------------------
11929|  4.03k|    return false;
11930|  4.03k|  }
11931|  4.23k|  username = ada::unicode::percent_encode(
11932|  4.23k|      input, character_sets::USERINFO_PERCENT_ENCODE);
11933|  4.23k|  return true;
11934|  8.27k|}
_ZN3ada3url12set_passwordENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11936|  8.27k|bool url::set_password(const std::string_view input) {
11937|  8.27k|  if (cannot_have_credentials_or_port()) {
  ------------------
  |  Branch (11937:7): [True: 4.03k, False: 4.23k]
  ------------------
11938|  4.03k|    return false;
11939|  4.03k|  }
11940|  4.23k|  password = ada::unicode::percent_encode(
11941|  4.23k|      input, character_sets::USERINFO_PERCENT_ENCODE);
11942|  4.23k|  return true;
11943|  8.27k|}
_ZN3ada3url8set_portENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11945|  8.37k|bool url::set_port(const std::string_view input) {
11946|  8.37k|  if (cannot_have_credentials_or_port()) {
  ------------------
  |  Branch (11946:7): [True: 3.87k, False: 4.49k]
  ------------------
11947|  3.87k|    return false;
11948|  3.87k|  }
11949|  4.49k|  std::string trimmed(input);
11950|  4.49k|  helpers::remove_ascii_tab_or_newline(trimmed);
11951|  4.49k|  if (trimmed.empty()) {
  ------------------
  |  Branch (11951:7): [True: 2.65k, False: 1.84k]
  ------------------
11952|  2.65k|    port = std::nullopt;
11953|  2.65k|    return true;
11954|  2.65k|  }
11955|       |  // Input should not start with control characters.
11956|  1.84k|  if (ada::unicode::is_c0_control_or_space(trimmed.front())) {
  ------------------
  |  Branch (11956:7): [True: 79, False: 1.76k]
  ------------------
11957|     79|    return false;
11958|     79|  }
11959|       |  // Input should contain at least one ascii digit.
11960|  1.76k|  if (input.find_first_of("0123456789") == std::string_view::npos) {
  ------------------
  |  Branch (11960:7): [True: 1.05k, False: 712]
  ------------------
11961|  1.05k|    return false;
11962|  1.05k|  }
11963|       |
11964|       |  // Revert changes if parse_port fails.
11965|    712|  std::optional<uint16_t> previous_port = port;
11966|    712|  parse_port(trimmed);
11967|    712|  if (is_valid) {
  ------------------
  |  Branch (11967:7): [True: 522, False: 190]
  ------------------
11968|    522|    return true;
11969|    522|  }
11970|    190|  port = previous_port;
11971|    190|  is_valid = true;
11972|    190|  return false;
11973|    712|}
_ZN3ada3url8set_hashENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11975|  8.27k|void url::set_hash(const std::string_view input) {
11976|  8.27k|  if (input.empty()) {
  ------------------
  |  Branch (11976:7): [True: 5.24k, False: 3.02k]
  ------------------
11977|  5.24k|    hash = std::nullopt;
11978|  5.24k|    helpers::strip_trailing_spaces_from_opaque_path(*this);
11979|  5.24k|    return;
11980|  5.24k|  }
11981|       |
11982|  3.02k|  std::string new_value;
11983|  3.02k|  new_value = input[0] == '#' ? input.substr(1) : input;
  ------------------
  |  Branch (11983:15): [True: 7, False: 3.02k]
  ------------------
11984|  3.02k|  helpers::remove_ascii_tab_or_newline(new_value);
11985|  3.02k|  hash = unicode::percent_encode(new_value,
11986|  3.02k|                                 ada::character_sets::FRAGMENT_PERCENT_ENCODE);
11987|  3.02k|  return;
11988|  8.27k|}
_ZN3ada3url10set_searchENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11990|  8.27k|void url::set_search(const std::string_view input) {
11991|  8.27k|  if (input.empty()) {
  ------------------
  |  Branch (11991:7): [True: 5.24k, False: 3.02k]
  ------------------
11992|  5.24k|    query = std::nullopt;
11993|  5.24k|    helpers::strip_trailing_spaces_from_opaque_path(*this);
11994|  5.24k|    return;
11995|  5.24k|  }
11996|       |
11997|  3.02k|  std::string new_value;
11998|  3.02k|  new_value = input[0] == '?' ? input.substr(1) : input;
  ------------------
  |  Branch (11998:15): [True: 4, False: 3.02k]
  ------------------
11999|  3.02k|  helpers::remove_ascii_tab_or_newline(new_value);
12000|       |
12001|  3.02k|  auto query_percent_encode_set =
12002|  3.02k|      is_special() ? ada::character_sets::SPECIAL_QUERY_PERCENT_ENCODE
  ------------------
  |  Branch (12002:7): [True: 2.07k, False: 950]
  ------------------
12003|  3.02k|                   : ada::character_sets::QUERY_PERCENT_ENCODE;
12004|       |
12005|  3.02k|  query = ada::unicode::percent_encode(std::string_view(new_value),
12006|  3.02k|                                       query_percent_encode_set);
12007|  3.02k|}
_ZN3ada3url12set_pathnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
12009|  8.27k|bool url::set_pathname(const std::string_view input) {
12010|  8.27k|  if (has_opaque_path) {
  ------------------
  |  Branch (12010:7): [True: 1.06k, False: 7.20k]
  ------------------
12011|  1.06k|    return false;
12012|  1.06k|  }
12013|  7.20k|  path = "";
12014|  7.20k|  parse_path(input);
12015|  7.20k|  return true;
12016|  8.27k|}
_ZN3ada3url12set_protocolENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
12018|  8.27k|bool url::set_protocol(const std::string_view input) {
12019|  8.27k|  std::string view(input);
12020|  8.27k|  helpers::remove_ascii_tab_or_newline(view);
12021|  8.27k|  if (view.empty()) {
  ------------------
  |  Branch (12021:7): [True: 5.29k, False: 2.97k]
  ------------------
12022|  5.29k|    return true;
12023|  5.29k|  }
12024|       |
12025|       |  // Schemes should start with alpha values.
12026|  2.97k|  if (!checkers::is_alpha(view[0])) {
  ------------------
  |  Branch (12026:7): [True: 2.41k, False: 564]
  ------------------
12027|  2.41k|    return false;
12028|  2.41k|  }
12029|       |
12030|    564|  view.append(":");
12031|       |
12032|    564|  std::string::iterator pointer =
12033|    564|      std::find_if_not(view.begin(), view.end(), unicode::is_alnum_plus);
12034|       |
12035|    564|  if (pointer != view.end() && *pointer == ':') {
  ------------------
  |  Branch (12035:7): [True: 564, False: 0]
  |  Branch (12035:7): [True: 360, False: 204]
  |  Branch (12035:32): [True: 360, False: 204]
  ------------------
12036|    360|    return parse_scheme<true>(
12037|    360|        std::string_view(view.data(), pointer - view.begin()));
12038|    360|  }
12039|    204|  return false;
12040|    564|}
_ZN3ada6parser9parse_urlINS_3urlEEET_NSt3__117basic_string_viewIcNS4_11char_traitsIcEEEEPKS3_:
12072|  14.5k|                      const result_type* base_url) {
12073|       |  // We can specialize the implementation per type.
12074|       |  // Important: result_type_is_ada_url is evaluated at *compile time*. This
12075|       |  // means that doing if constexpr(result_type_is_ada_url) { something } else {
12076|       |  // something else } is free (at runtime). This means that ada::url_aggregator
12077|       |  // and ada::url **do not have to support the exact same API**.
12078|  14.5k|  constexpr bool result_type_is_ada_url =
12079|  14.5k|      std::is_same<ada::url, result_type>::value;
12080|  14.5k|  constexpr bool result_type_is_ada_url_aggregator =
12081|  14.5k|      std::is_same<ada::url_aggregator, result_type>::value;
12082|  14.5k|  static_assert(result_type_is_ada_url ||
12083|  14.5k|                result_type_is_ada_url_aggregator);  // We don't support
12084|       |                                                     // anything else for now.
12085|       |
12086|  14.5k|  ada_log("ada::parser::parse_url('", user_input, "' [", user_input.size(),
12087|  14.5k|          " bytes],", (base_url != nullptr ? base_url->to_string() : "null"),
12088|  14.5k|          ")");
12089|       |
12090|  14.5k|  ada::state state = ada::state::SCHEME_START;
12091|  14.5k|  result_type url{};
12092|       |
12093|       |  // We refuse to parse URL strings that exceed 4GB. Such strings are almost
12094|       |  // surely the result of a bug or are otherwise a security concern.
12095|  14.5k|  if (user_input.size() > std::numeric_limits<uint32_t>::max()) {
  ------------------
  |  Branch (12095:7): [True: 0, False: 14.5k]
  ------------------
12096|      0|    url.is_valid = false;
12097|      0|  }
12098|       |  // Going forward, user_input.size() is in [0,
12099|       |  // std::numeric_limits<uint32_t>::max). If we are provided with an invalid
12100|       |  // base, or the optional_url was invalid, we must return.
12101|  14.5k|  if (base_url != nullptr) {
  ------------------
  |  Branch (12101:7): [True: 0, False: 14.5k]
  ------------------
12102|      0|    url.is_valid &= base_url->is_valid;
12103|      0|  }
12104|  14.5k|  if (!url.is_valid) {
  ------------------
  |  Branch (12104:7): [True: 0, False: 14.5k]
  ------------------
12105|      0|    return url;
12106|      0|  }
12107|  14.5k|  if constexpr (result_type_is_ada_url_aggregator) {
  ------------------
  |  Branch (12107:17): [Folded - Ignored]
  ------------------
12108|       |    // Most of the time, we just need user_input.size().
12109|       |    // In some instances, we may need a bit more.
12110|       |    ///////////////////////////
12111|       |    // This is *very* important. This line should be removed
12112|       |    // hastily. There are principled reasons why reserve is important
12113|       |    // for performance. If you have a benchmark with small inputs,
12114|       |    // it may not matter, but in other instances, it could.
12115|       |    ////
12116|       |    // This rounds up to the next power of two.
12117|       |    // We know that user_input.size() is in [0,
12118|       |    // std::numeric_limits<uint32_t>::max).
12119|  14.5k|    uint32_t reserve_capacity =
12120|  14.5k|        (0xFFFFFFFF >>
12121|  14.5k|         helpers::leading_zeroes(uint32_t(1 | user_input.size()))) +
12122|  14.5k|        1;
12123|  14.5k|    url.reserve(reserve_capacity);
12124|       |    //
12125|       |    //
12126|       |    //
12127|  14.5k|  }
12128|  14.5k|  std::string tmp_buffer;
12129|  14.5k|  std::string_view internal_input;
12130|  14.5k|  if (unicode::has_tabs_or_newline(user_input)) {
  ------------------
  |  Branch (12130:7): [True: 202, False: 14.3k]
  ------------------
12131|    202|    tmp_buffer = user_input;
12132|       |    // Optimization opportunity: Instead of copying and then pruning, we could
12133|       |    // just directly build the string from user_input.
12134|    202|    helpers::remove_ascii_tab_or_newline(tmp_buffer);
12135|    202|    internal_input = tmp_buffer;
12136|  14.3k|  } else {
12137|  14.3k|    internal_input = user_input;
12138|  14.3k|  }
12139|       |
12140|       |  // Leading and trailing control characters are uncommon and easy to deal with
12141|       |  // (no performance concern).
12142|  14.5k|  std::string_view url_data = internal_input;
12143|  14.5k|  helpers::trim_c0_whitespace(url_data);
12144|       |
12145|       |  // Optimization opportunity. Most websites do not have fragment.
12146|  14.5k|  std::optional<std::string_view> fragment = helpers::prune_hash(url_data);
12147|       |  // We add it last so that an implementation like ada::url_aggregator
12148|       |  // can append it last to its internal buffer, thus improving performance.
12149|       |
12150|       |  // Here url_data no longer has its fragment.
12151|       |  // We are going to access the data from url_data (it is immutable).
12152|       |  // At any given time, we are pointing at byte 'input_position' in url_data.
12153|       |  // The input_position variable should range from 0 to input_size.
12154|       |  // It is illegal to access url_data at input_size.
12155|  14.5k|  size_t input_position = 0;
12156|  14.5k|  const size_t input_size = url_data.size();
12157|       |  // Keep running the following state machine by switching on state.
12158|       |  // If after a run pointer points to the EOF code point, go to the next step.
12159|       |  // Otherwise, increase pointer by 1 and continue with the state machine.
12160|       |  // We never decrement input_position.
12161|  65.3k|  while (input_position <= input_size) {
  ------------------
  |  Branch (12161:10): [True: 61.2k, False: 4.07k]
  ------------------
12162|  61.2k|    ada_log("In parsing at ", input_position, " out of ", input_size,
12163|  61.2k|            " in state ", ada::to_string(state));
12164|  61.2k|    switch (state) {
12165|  14.5k|      case ada::state::SCHEME_START: {
  ------------------
  |  Branch (12165:7): [True: 14.5k, False: 46.7k]
  ------------------
12166|  14.5k|        ada_log("SCHEME_START ", helpers::substring(url_data, input_position));
12167|       |        // If c is an ASCII alpha, append c, lowercased, to buffer, and set
12168|       |        // state to scheme state.
12169|  14.5k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12169:13): [True: 13.4k, False: 1.04k]
  ------------------
12170|  14.5k|            checkers::is_alpha(url_data[input_position])) {
  ------------------
  |  Branch (12170:13): [True: 11.2k, False: 2.22k]
  ------------------
12171|  11.2k|          state = ada::state::SCHEME;
12172|  11.2k|          input_position++;
12173|  11.2k|        } else {
12174|       |          // Otherwise, if state override is not given, set state to no scheme
12175|       |          // state and decrease pointer by 1.
12176|  3.27k|          state = ada::state::NO_SCHEME;
12177|  3.27k|        }
12178|  14.5k|        break;
12179|      0|      }
12180|  11.2k|      case ada::state::SCHEME: {
  ------------------
  |  Branch (12180:7): [True: 11.2k, False: 50.0k]
  ------------------
12181|  11.2k|        ada_log("SCHEME ", helpers::substring(url_data, input_position));
12182|       |        // If c is an ASCII alphanumeric, U+002B (+), U+002D (-), or U+002E (.),
12183|       |        // append c, lowercased, to buffer.
12184|  38.6k|        while ((input_position != input_size) &&
  ------------------
  |  Branch (12184:16): [True: 38.0k, False: 575]
  ------------------
12185|  38.6k|               (ada::unicode::is_alnum_plus(url_data[input_position]))) {
  ------------------
  |  Branch (12185:16): [True: 27.3k, False: 10.6k]
  ------------------
12186|  27.3k|          input_position++;
12187|  27.3k|        }
12188|       |        // Otherwise, if c is U+003A (:), then:
12189|  11.2k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12189:13): [True: 10.6k, False: 575]
  ------------------
12190|  11.2k|            (url_data[input_position] == ':')) {
  ------------------
  |  Branch (12190:13): [True: 10.2k, False: 433]
  ------------------
12191|  10.2k|          ada_log("SCHEME the scheme should be ",
12192|  10.2k|                  url_data.substr(0, input_position));
12193|  10.2k|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12193:25): [Folded - Ignored]
  ------------------
12194|  10.2k|            if (!url.parse_scheme(url_data.substr(0, input_position))) {
  ------------------
  |  Branch (12194:17): [True: 0, False: 10.2k]
  ------------------
12195|      0|              return url;
12196|      0|            }
12197|  10.2k|          } else {
12198|       |            // we pass the colon along instead of painfully adding it back.
12199|  10.2k|            if (!url.parse_scheme_with_colon(
12200|  10.2k|                    url_data.substr(0, input_position + 1))) {
12201|  10.2k|              return url;
12202|  10.2k|            }
12203|  10.2k|          }
12204|  10.2k|          ada_log("SCHEME the scheme is ", url.get_protocol());
12205|       |
12206|       |          // If url’s scheme is "file", then:
12207|  10.2k|          if (url.type == ada::scheme::type::FILE) {
  ------------------
  |  Branch (12207:15): [True: 1.61k, False: 8.60k]
  ------------------
12208|       |            // Set state to file state.
12209|  1.61k|            state = ada::state::FILE;
12210|  1.61k|          }
12211|       |          // Otherwise, if url is special, base is non-null, and base’s scheme
12212|       |          // is url’s scheme: Note: Doing base_url->scheme is unsafe if base_url
12213|       |          // != nullptr is false.
12214|  8.60k|          else if (url.is_special() && base_url != nullptr &&
  ------------------
  |  Branch (12214:20): [True: 5.66k, False: 2.94k]
  |  Branch (12214:40): [True: 0, False: 5.66k]
  ------------------
12215|  8.60k|                   base_url->type == url.type) {
  ------------------
  |  Branch (12215:20): [True: 0, False: 0]
  ------------------
12216|       |            // Set state to special relative or authority state.
12217|      0|            state = ada::state::SPECIAL_RELATIVE_OR_AUTHORITY;
12218|      0|          }
12219|       |          // Otherwise, if url is special, set state to special authority
12220|       |          // slashes state.
12221|  8.60k|          else if (url.is_special()) {
  ------------------
  |  Branch (12221:20): [True: 5.66k, False: 2.94k]
  ------------------
12222|  5.66k|            state = ada::state::SPECIAL_AUTHORITY_SLASHES;
12223|  5.66k|          }
12224|       |          // Otherwise, if remaining starts with an U+002F (/), set state to
12225|       |          // path or authority state and increase pointer by 1.
12226|  2.94k|          else if (input_position + 1 < input_size &&
  ------------------
  |  Branch (12226:20): [True: 2.48k, False: 463]
  ------------------
12227|  2.94k|                   url_data[input_position + 1] == '/') {
  ------------------
  |  Branch (12227:20): [True: 1.85k, False: 632]
  ------------------
12228|  1.85k|            state = ada::state::PATH_OR_AUTHORITY;
12229|  1.85k|            input_position++;
12230|  1.85k|          }
12231|       |          // Otherwise, set url’s path to the empty string and set state to
12232|       |          // opaque path state.
12233|  1.09k|          else {
12234|  1.09k|            state = ada::state::OPAQUE_PATH;
12235|  1.09k|          }
12236|  10.2k|        }
12237|       |        // Otherwise, if state override is not given, set buffer to the empty
12238|       |        // string, state to no scheme state, and start over (from the first code
12239|       |        // point in input).
12240|  1.00k|        else {
12241|  1.00k|          state = ada::state::NO_SCHEME;
12242|  1.00k|          input_position = 0;
12243|  1.00k|          break;
12244|  1.00k|        }
12245|  10.2k|        input_position++;
12246|  10.2k|        break;
12247|  11.2k|      }
12248|  4.28k|      case ada::state::NO_SCHEME: {
  ------------------
  |  Branch (12248:7): [True: 4.28k, False: 56.9k]
  ------------------
12249|  4.28k|        ada_log("NO_SCHEME ", helpers::substring(url_data, input_position));
12250|       |        // If base is null, or base has an opaque path and c is not U+0023 (#),
12251|       |        // validation error, return failure.
12252|  4.28k|        if (base_url == nullptr ||
  ------------------
  |  Branch (12252:13): [True: 4.28k, False: 0]
  ------------------
12253|  4.28k|            (base_url->has_opaque_path && !fragment.has_value())) {
  ------------------
  |  Branch (12253:14): [True: 0, False: 0]
  |  Branch (12253:43): [True: 0, False: 0]
  ------------------
12254|  4.28k|          ada_log("NO_SCHEME validation error");
12255|  4.28k|          url.is_valid = false;
12256|  4.28k|          return url;
12257|  4.28k|        }
12258|       |        // Otherwise, if base has an opaque path and c is U+0023 (#),
12259|       |        // set url’s scheme to base’s scheme, url’s path to base’s path, url’s
12260|       |        // query to base’s query, and set state to fragment state.
12261|      0|        else if (base_url->has_opaque_path && fragment.has_value() &&
  ------------------
  |  Branch (12261:18): [True: 0, False: 0]
  |  Branch (12261:47): [True: 0, False: 0]
  ------------------
12262|      0|                 input_position == input_size) {
  ------------------
  |  Branch (12262:18): [True: 0, False: 0]
  ------------------
12263|      0|          ada_log("NO_SCHEME opaque base with fragment");
12264|      0|          url.copy_scheme(*base_url);
12265|      0|          url.has_opaque_path = base_url->has_opaque_path;
12266|       |
12267|      0|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12267:25): [Folded - Ignored]
  ------------------
12268|      0|            url.path = base_url->path;
12269|      0|            url.query = base_url->query;
12270|      0|          } else {
12271|      0|            url.update_base_pathname(base_url->get_pathname());
12272|      0|            url.update_base_search(base_url->get_search());
12273|      0|          }
12274|      0|          url.update_unencoded_base_hash(*fragment);
12275|      0|          return url;
12276|      0|        }
12277|       |        // Otherwise, if base’s scheme is not "file", set state to relative
12278|       |        // state and decrease pointer by 1.
12279|      0|        else if (base_url->type != ada::scheme::type::FILE) {
  ------------------
  |  Branch (12279:18): [True: 0, False: 0]
  ------------------
12280|      0|          ada_log("NO_SCHEME non-file relative path");
12281|      0|          state = ada::state::RELATIVE_SCHEME;
12282|      0|        }
12283|       |        // Otherwise, set state to file state and decrease pointer by 1.
12284|      0|        else {
12285|      0|          ada_log("NO_SCHEME file base type");
12286|      0|          state = ada::state::FILE;
12287|      0|        }
12288|      0|        break;
12289|  4.28k|      }
12290|  6.03k|      case ada::state::AUTHORITY: {
  ------------------
  |  Branch (12290:7): [True: 6.03k, False: 55.2k]
  ------------------
12291|  6.03k|        ada_log("AUTHORITY ", helpers::substring(url_data, input_position));
12292|       |        // most URLs have no @. Having no @ tells us that we don't have to worry
12293|       |        // about AUTHORITY. Of course, we could have @ and still not have to
12294|       |        // worry about AUTHORITY.
12295|       |        // TODO: Instead of just collecting a bool, collect the location of the
12296|       |        // '@' and do something useful with it.
12297|       |        // TODO: We could do various processing early on, using a single pass
12298|       |        // over the string to collect information about it, e.g., telling us
12299|       |        // whether there is a @ and if so, where (or how many).
12300|  6.03k|        const bool contains_ampersand =
12301|  6.03k|            (url_data.find('@', input_position) != std::string_view::npos);
12302|       |
12303|  6.03k|        if (!contains_ampersand) {
  ------------------
  |  Branch (12303:13): [True: 5.60k, False: 431]
  ------------------
12304|  5.60k|          state = ada::state::HOST;
12305|  5.60k|          break;
12306|  5.60k|        }
12307|    431|        bool at_sign_seen{false};
12308|    431|        bool password_token_seen{false};
12309|       |        /**
12310|       |         * We expect something of the sort...
12311|       |         * https://user:pass@example.com:1234/foo/bar?baz#quux
12312|       |         * --------^
12313|       |         */
12314|  3.23k|        do {
12315|  3.23k|          std::string_view view = helpers::substring(url_data, input_position);
12316|       |          // The delimiters are @, /, ? \\.
12317|  3.23k|          size_t location =
12318|  3.23k|              url.is_special() ? helpers::find_authority_delimiter_special(view)
  ------------------
  |  Branch (12318:15): [True: 2.70k, False: 525]
  ------------------
12319|  3.23k|                               : helpers::find_authority_delimiter(view);
12320|  3.23k|          std::string_view authority_view(view.data(), location);
12321|  3.23k|          size_t end_of_authority = input_position + authority_view.size();
12322|       |          // If c is U+0040 (@), then:
12323|  3.23k|          if ((end_of_authority != input_size) &&
  ------------------
  |  Branch (12323:15): [True: 2.86k, False: 369]
  ------------------
12324|  3.23k|              (url_data[end_of_authority] == '@')) {
  ------------------
  |  Branch (12324:15): [True: 2.80k, False: 62]
  ------------------
12325|       |            // If atSignSeen is true, then prepend "%40" to buffer.
12326|  2.80k|            if (at_sign_seen) {
  ------------------
  |  Branch (12326:17): [True: 2.39k, False: 413]
  ------------------
12327|  2.39k|              if (password_token_seen) {
  ------------------
  |  Branch (12327:19): [True: 580, False: 1.81k]
  ------------------
12328|    580|                if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12328:31): [Folded - Ignored]
  ------------------
12329|    580|                  url.password += "%40";
12330|    580|                } else {
12331|    580|                  url.append_base_password("%40");
12332|    580|                }
12333|  1.81k|              } else {
12334|  1.81k|                if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12334:31): [Folded - Ignored]
  ------------------
12335|  1.81k|                  url.username += "%40";
12336|  1.81k|                } else {
12337|  1.81k|                  url.append_base_username("%40");
12338|  1.81k|                }
12339|  1.81k|              }
12340|  2.39k|            }
12341|       |
12342|  2.80k|            at_sign_seen = true;
12343|       |
12344|  2.80k|            if (!password_token_seen) {
  ------------------
  |  Branch (12344:17): [True: 2.22k, False: 580]
  ------------------
12345|  2.22k|              size_t password_token_location = authority_view.find(':');
12346|  2.22k|              password_token_seen =
12347|  2.22k|                  password_token_location != std::string_view::npos;
12348|       |
12349|  2.22k|              if (!password_token_seen) {
  ------------------
  |  Branch (12349:19): [True: 2.08k, False: 140]
  ------------------
12350|  2.08k|                if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12350:31): [Folded - Ignored]
  ------------------
12351|  2.08k|                  url.username += unicode::percent_encode(
12352|  2.08k|                      authority_view, character_sets::USERINFO_PERCENT_ENCODE);
12353|  2.08k|                } else {
12354|  2.08k|                  url.append_base_username(unicode::percent_encode(
12355|  2.08k|                      authority_view, character_sets::USERINFO_PERCENT_ENCODE));
12356|  2.08k|                }
12357|  2.08k|              } else {
12358|    140|                if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12358:31): [Folded - Ignored]
  ------------------
12359|    140|                  url.username += unicode::percent_encode(
12360|    140|                      authority_view.substr(0, password_token_location),
12361|    140|                      character_sets::USERINFO_PERCENT_ENCODE);
12362|    140|                  url.password += unicode::percent_encode(
12363|    140|                      authority_view.substr(password_token_location + 1),
12364|    140|                      character_sets::USERINFO_PERCENT_ENCODE);
12365|    140|                } else {
12366|    140|                  url.append_base_username(unicode::percent_encode(
12367|    140|                      authority_view.substr(0, password_token_location),
12368|    140|                      character_sets::USERINFO_PERCENT_ENCODE));
12369|    140|                  url.append_base_password(unicode::percent_encode(
12370|    140|                      authority_view.substr(password_token_location + 1),
12371|    140|                      character_sets::USERINFO_PERCENT_ENCODE));
12372|    140|                }
12373|    140|              }
12374|  2.22k|            } else {
12375|    580|              if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12375:29): [Folded - Ignored]
  ------------------
12376|    580|                url.password += unicode::percent_encode(
12377|    580|                    authority_view, character_sets::USERINFO_PERCENT_ENCODE);
12378|    580|              } else {
12379|    580|                url.append_base_password(unicode::percent_encode(
12380|    580|                    authority_view, character_sets::USERINFO_PERCENT_ENCODE));
12381|    580|              }
12382|    580|            }
12383|  2.80k|          }
12384|       |          // Otherwise, if one of the following is true:
12385|       |          // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
12386|       |          // - url is special and c is U+005C (\)
12387|    431|          else if (end_of_authority == input_size ||
  ------------------
  |  Branch (12387:20): [True: 369, False: 62]
  ------------------
12388|    431|                   url_data[end_of_authority] == '/' ||
  ------------------
  |  Branch (12388:20): [True: 36, False: 26]
  ------------------
12389|    431|                   url_data[end_of_authority] == '?' ||
  ------------------
  |  Branch (12389:20): [True: 23, False: 3]
  ------------------
12390|    431|                   (url.is_special() && url_data[end_of_authority] == '\\')) {
  ------------------
  |  Branch (12390:21): [True: 3, False: 0]
  |  Branch (12390:41): [True: 3, False: 0]
  ------------------
12391|       |            // If atSignSeen is true and authority_view is the empty string,
12392|       |            // validation error, return failure.
12393|    431|            if (at_sign_seen && authority_view.empty()) {
  ------------------
  |  Branch (12393:17): [True: 413, False: 18]
  |  Branch (12393:33): [True: 232, False: 181]
  ------------------
12394|    232|              url.is_valid = false;
12395|    232|              return url;
12396|    232|            }
12397|    199|            state = ada::state::HOST;
12398|    199|            break;
12399|    431|          }
12400|  2.80k|          if (end_of_authority == input_size) {
  ------------------
  |  Branch (12400:15): [True: 0, False: 2.80k]
  ------------------
12401|      0|            if (fragment.has_value()) {
  ------------------
  |  Branch (12401:17): [True: 0, False: 0]
  ------------------
12402|      0|              url.update_unencoded_base_hash(*fragment);
12403|      0|            }
12404|      0|            return url;
12405|      0|          }
12406|  2.80k|          input_position = end_of_authority + 1;
12407|  2.80k|        } while (true);
  ------------------
  |  Branch (12407:18): [Folded - Ignored]
  ------------------
12408|       |
12409|    199|        break;
12410|    431|      }
12411|    199|      case ada::state::SPECIAL_RELATIVE_OR_AUTHORITY: {
  ------------------
  |  Branch (12411:7): [True: 0, False: 61.2k]
  ------------------
12412|      0|        ada_log("SPECIAL_RELATIVE_OR_AUTHORITY ",
12413|      0|                helpers::substring(url_data, input_position));
12414|       |
12415|       |        // If c is U+002F (/) and remaining starts with U+002F (/),
12416|       |        // then set state to special authority ignore slashes state and increase
12417|       |        // pointer by 1.
12418|      0|        std::string_view view = helpers::substring(url_data, input_position);
12419|      0|        if (ada::checkers::begins_with(view, "//")) {
  ------------------
  |  Branch (12419:13): [True: 0, False: 0]
  ------------------
12420|      0|          state = ada::state::SPECIAL_AUTHORITY_IGNORE_SLASHES;
12421|      0|          input_position += 2;
12422|      0|        } else {
12423|       |          // Otherwise, validation error, set state to relative state and
12424|       |          // decrease pointer by 1.
12425|      0|          state = ada::state::RELATIVE_SCHEME;
12426|      0|        }
12427|       |
12428|      0|        break;
12429|    431|      }
12430|  1.85k|      case ada::state::PATH_OR_AUTHORITY: {
  ------------------
  |  Branch (12430:7): [True: 1.85k, False: 59.3k]
  ------------------
12431|  1.85k|        ada_log("PATH_OR_AUTHORITY ",
12432|  1.85k|                helpers::substring(url_data, input_position));
12433|       |
12434|       |        // If c is U+002F (/), then set state to authority state.
12435|  1.85k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12435:13): [True: 847, False: 1.00k]
  ------------------
12436|  1.85k|            (url_data[input_position] == '/')) {
  ------------------
  |  Branch (12436:13): [True: 372, False: 475]
  ------------------
12437|    372|          state = ada::state::AUTHORITY;
12438|    372|          input_position++;
12439|  1.47k|        } else {
12440|       |          // Otherwise, set state to path state, and decrease pointer by 1.
12441|  1.47k|          state = ada::state::PATH;
12442|  1.47k|        }
12443|       |
12444|  1.85k|        break;
12445|    431|      }
12446|      0|      case ada::state::RELATIVE_SCHEME: {
  ------------------
  |  Branch (12446:7): [True: 0, False: 61.2k]
  ------------------
12447|      0|        ada_log("RELATIVE_SCHEME ",
12448|      0|                helpers::substring(url_data, input_position));
12449|       |
12450|       |        // Set url’s scheme to base’s scheme.
12451|      0|        url.copy_scheme(*base_url);
12452|       |
12453|       |        // If c is U+002F (/), then set state to relative slash state.
12454|      0|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12454:13): [True: 0, False: 0]
  ------------------
12455|      0|            (url_data[input_position] == '/')) {
  ------------------
  |  Branch (12455:13): [True: 0, False: 0]
  ------------------
12456|      0|          ada_log(
12457|      0|              "RELATIVE_SCHEME if c is U+002F (/), then set state to relative "
12458|      0|              "slash state");
12459|      0|          state = ada::state::RELATIVE_SLASH;
12460|      0|        } else if (url.is_special() && (input_position != input_size) &&
  ------------------
  |  Branch (12460:20): [True: 0, False: 0]
  |  Branch (12460:40): [True: 0, False: 0]
  ------------------
12461|      0|                   (url_data[input_position] == '\\')) {
  ------------------
  |  Branch (12461:20): [True: 0, False: 0]
  ------------------
12462|       |          // Otherwise, if url is special and c is U+005C (\), validation error,
12463|       |          // set state to relative slash state.
12464|      0|          ada_log(
12465|      0|              "RELATIVE_SCHEME  if url is special and c is U+005C, validation "
12466|      0|              "error, set state to relative slash state");
12467|      0|          state = ada::state::RELATIVE_SLASH;
12468|      0|        } else {
12469|      0|          ada_log("RELATIVE_SCHEME otherwise");
12470|       |          // Set url’s username to base’s username, url’s password to base’s
12471|       |          // password, url’s host to base’s host, url’s port to base’s port,
12472|       |          // url’s path to a clone of base’s path, and url’s query to base’s
12473|       |          // query.
12474|      0|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12474:25): [Folded - Ignored]
  ------------------
12475|      0|            url.username = base_url->username;
12476|      0|            url.password = base_url->password;
12477|      0|            url.host = base_url->host;
12478|      0|            url.port = base_url->port;
12479|       |            // cloning the base path includes cloning the has_opaque_path flag
12480|      0|            url.has_opaque_path = base_url->has_opaque_path;
12481|      0|            url.path = base_url->path;
12482|      0|            url.query = base_url->query;
12483|      0|          } else {
12484|      0|            url.update_base_authority(base_url->get_href(),
12485|      0|                                      base_url->get_components());
12486|       |            // TODO: Get rid of set_hostname and replace it with
12487|       |            // update_base_hostname
12488|      0|            url.set_hostname(base_url->get_hostname());
12489|      0|            url.update_base_port(base_url->retrieve_base_port());
12490|       |            // cloning the base path includes cloning the has_opaque_path flag
12491|      0|            url.has_opaque_path = base_url->has_opaque_path;
12492|      0|            url.update_base_pathname(base_url->get_pathname());
12493|      0|            url.update_base_search(base_url->get_search());
12494|      0|          }
12495|       |
12496|      0|          url.has_opaque_path = base_url->has_opaque_path;
12497|       |
12498|       |          // If c is U+003F (?), then set url’s query to the empty string, and
12499|       |          // state to query state.
12500|      0|          if ((input_position != input_size) &&
  ------------------
  |  Branch (12500:15): [True: 0, False: 0]
  ------------------
12501|      0|              (url_data[input_position] == '?')) {
  ------------------
  |  Branch (12501:15): [True: 0, False: 0]
  ------------------
12502|      0|            state = ada::state::QUERY;
12503|      0|          }
12504|       |          // Otherwise, if c is not the EOF code point:
12505|      0|          else if (input_position != input_size) {
  ------------------
  |  Branch (12505:20): [True: 0, False: 0]
  ------------------
12506|       |            // Set url’s query to null.
12507|      0|            url.clear_search();
12508|      0|            if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12508:27): [Folded - Ignored]
  ------------------
12509|       |              // Shorten url’s path.
12510|      0|              helpers::shorten_path(url.path, url.type);
12511|      0|            } else {
12512|      0|              std::string_view path = url.get_pathname();
12513|      0|              if (helpers::shorten_path(path, url.type)) {
12514|      0|                url.update_base_pathname(std::string(path));
12515|      0|              }
12516|      0|            }
12517|       |            // Set state to path state and decrease pointer by 1.
12518|      0|            state = ada::state::PATH;
12519|      0|            break;
12520|      0|          }
12521|      0|        }
12522|      0|        input_position++;
12523|      0|        break;
12524|      0|      }
12525|      0|      case ada::state::RELATIVE_SLASH: {
  ------------------
  |  Branch (12525:7): [True: 0, False: 61.2k]
  ------------------
12526|      0|        ada_log("RELATIVE_SLASH ",
12527|      0|                helpers::substring(url_data, input_position));
12528|       |
12529|       |        // If url is special and c is U+002F (/) or U+005C (\), then:
12530|      0|        if (url.is_special() && (input_position != input_size) &&
  ------------------
  |  Branch (12530:13): [True: 0, False: 0]
  |  Branch (12530:33): [True: 0, False: 0]
  ------------------
12531|      0|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (12531:14): [True: 0, False: 0]
  ------------------
12532|      0|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (12532:14): [True: 0, False: 0]
  ------------------
12533|       |          // Set state to special authority ignore slashes state.
12534|      0|          state = ada::state::SPECIAL_AUTHORITY_IGNORE_SLASHES;
12535|      0|        }
12536|       |        // Otherwise, if c is U+002F (/), then set state to authority state.
12537|      0|        else if ((input_position != input_size) &&
  ------------------
  |  Branch (12537:18): [True: 0, False: 0]
  ------------------
12538|      0|                 (url_data[input_position] == '/')) {
  ------------------
  |  Branch (12538:18): [True: 0, False: 0]
  ------------------
12539|      0|          state = ada::state::AUTHORITY;
12540|      0|        }
12541|       |        // Otherwise, set
12542|       |        // - url’s username to base’s username,
12543|       |        // - url’s password to base’s password,
12544|       |        // - url’s host to base’s host,
12545|       |        // - url’s port to base’s port,
12546|       |        // - state to path state, and then, decrease pointer by 1.
12547|      0|        else {
12548|      0|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12548:25): [Folded - Ignored]
  ------------------
12549|      0|            url.username = base_url->username;
12550|      0|            url.password = base_url->password;
12551|      0|            url.host = base_url->host;
12552|      0|            url.port = base_url->port;
12553|      0|          } else {
12554|      0|            url.update_base_authority(base_url->get_href(),
12555|      0|                                      base_url->get_components());
12556|       |            // TODO: Get rid of set_hostname and replace it with
12557|       |            // update_base_hostname
12558|      0|            url.set_hostname(base_url->get_hostname());
12559|      0|            url.update_base_port(base_url->retrieve_base_port());
12560|      0|          }
12561|      0|          state = ada::state::PATH;
12562|      0|          break;
12563|      0|        }
12564|       |
12565|      0|        input_position++;
12566|      0|        break;
12567|      0|      }
12568|  5.66k|      case ada::state::SPECIAL_AUTHORITY_SLASHES: {
  ------------------
  |  Branch (12568:7): [True: 5.66k, False: 55.5k]
  ------------------
12569|  5.66k|        ada_log("SPECIAL_AUTHORITY_SLASHES ",
12570|  5.66k|                helpers::substring(url_data, input_position));
12571|       |
12572|       |        // If c is U+002F (/) and remaining starts with U+002F (/),
12573|       |        // then set state to special authority ignore slashes state and increase
12574|       |        // pointer by 1.
12575|  5.66k|        state = ada::state::SPECIAL_AUTHORITY_IGNORE_SLASHES;
12576|  5.66k|        std::string_view view = helpers::substring(url_data, input_position);
12577|  5.66k|        if (ada::checkers::begins_with(view, "//")) {
  ------------------
  |  Branch (12577:13): [True: 14, False: 5.64k]
  ------------------
12578|     14|          input_position += 2;
12579|     14|        }
12580|       |
12581|  5.66k|        [[fallthrough]];
12582|  5.66k|      }
12583|  5.66k|      case ada::state::SPECIAL_AUTHORITY_IGNORE_SLASHES: {
  ------------------
  |  Branch (12583:7): [True: 0, False: 61.2k]
  ------------------
12584|  5.66k|        ada_log("SPECIAL_AUTHORITY_IGNORE_SLASHES ",
12585|  5.66k|                helpers::substring(url_data, input_position));
12586|       |
12587|       |        // If c is neither U+002F (/) nor U+005C (\), then set state to
12588|       |        // authority state and decrease pointer by 1.
12589|  6.18k|        while ((input_position != input_size) &&
  ------------------
  |  Branch (12589:16): [True: 6.15k, False: 34]
  ------------------
12590|  6.18k|               ((url_data[input_position] == '/') ||
  ------------------
  |  Branch (12590:17): [True: 279, False: 5.87k]
  ------------------
12591|  6.15k|                (url_data[input_position] == '\\'))) {
  ------------------
  |  Branch (12591:17): [True: 247, False: 5.62k]
  ------------------
12592|    526|          input_position++;
12593|    526|        }
12594|  5.66k|        state = ada::state::AUTHORITY;
12595|       |
12596|  5.66k|        break;
12597|  5.66k|      }
12598|    268|      case ada::state::QUERY: {
  ------------------
  |  Branch (12598:7): [True: 268, False: 60.9k]
  ------------------
12599|    268|        ada_log("QUERY ", helpers::substring(url_data, input_position));
12600|       |        // Let queryPercentEncodeSet be the special-query percent-encode set if
12601|       |        // url is special; otherwise the query percent-encode set.
12602|    268|        const uint8_t* query_percent_encode_set =
12603|    268|            url.is_special() ? ada::character_sets::SPECIAL_QUERY_PERCENT_ENCODE
  ------------------
  |  Branch (12603:13): [True: 120, False: 148]
  ------------------
12604|    268|                             : ada::character_sets::QUERY_PERCENT_ENCODE;
12605|       |
12606|       |        // Percent-encode after encoding, with encoding, buffer, and
12607|       |        // queryPercentEncodeSet, and append the result to url’s query.
12608|    268|        url.update_base_search(helpers::substring(url_data, input_position),
12609|    268|                               query_percent_encode_set);
12610|    268|        ada_log("QUERY update_base_search completed ");
12611|    268|        if (fragment.has_value()) {
  ------------------
  |  Branch (12611:13): [True: 26, False: 242]
  ------------------
12612|     26|          url.update_unencoded_base_hash(*fragment);
12613|     26|        }
12614|    268|        return url;
12615|  5.66k|      }
12616|  5.80k|      case ada::state::HOST: {
  ------------------
  |  Branch (12616:7): [True: 5.80k, False: 55.4k]
  ------------------
12617|  5.80k|        ada_log("HOST ", helpers::substring(url_data, input_position));
12618|       |
12619|  5.80k|        std::string_view host_view =
12620|  5.80k|            helpers::substring(url_data, input_position);
12621|  5.80k|        auto [location, found_colon] =
12622|  5.80k|            helpers::get_host_delimiter_location(url.is_special(), host_view);
12623|  5.80k|        input_position = (location != std::string_view::npos)
  ------------------
  |  Branch (12623:26): [True: 5.80k, False: 0]
  ------------------
12624|  5.80k|                             ? input_position + location
12625|  5.80k|                             : input_size;
12626|       |        // Otherwise, if c is U+003A (:) and insideBrackets is false, then:
12627|       |        // Note: the 'found_colon' value is true if and only if a colon was
12628|       |        // encountered while not inside brackets.
12629|  5.80k|        if (found_colon) {
  ------------------
  |  Branch (12629:13): [True: 867, False: 4.93k]
  ------------------
12630|       |          // If buffer is the empty string, validation error, return failure.
12631|       |          // Let host be the result of host parsing buffer with url is not
12632|       |          // special.
12633|    867|          ada_log("HOST parsing ", host_view);
12634|    867|          if (!url.parse_host(host_view)) {
  ------------------
  |  Branch (12634:15): [True: 139, False: 728]
  ------------------
12635|    139|            return url;
12636|    139|          }
12637|    728|          ada_log("HOST parsing results in ", url.get_hostname());
12638|       |          // Set url’s host to host, buffer to the empty string, and state to
12639|       |          // port state.
12640|    728|          state = ada::state::PORT;
12641|    728|          input_position++;
12642|    728|        }
12643|       |        // Otherwise, if one of the following is true:
12644|       |        // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
12645|       |        // - url is special and c is U+005C (\)
12646|       |        // The get_host_delimiter_location function either brings us to
12647|       |        // the colon outside of the bracket, or to one of those characters.
12648|  4.93k|        else {
12649|       |          // If url is special and host_view is the empty string, validation
12650|       |          // error, return failure.
12651|  4.93k|          if (url.is_special() && host_view.empty()) {
  ------------------
  |  Branch (12651:15): [True: 4.68k, False: 246]
  |  Branch (12651:35): [True: 40, False: 4.64k]
  ------------------
12652|     40|            url.is_valid = false;
12653|     40|            return url;
12654|     40|          }
12655|  4.89k|          ada_log("HOST parsing ", host_view, " href=", url.get_href());
12656|       |          // Let host be the result of host parsing host_view with url is not
12657|       |          // special.
12658|  4.89k|          if (host_view.empty()) {
  ------------------
  |  Branch (12658:15): [True: 28, False: 4.86k]
  ------------------
12659|     28|            url.update_base_hostname("");
12660|  4.86k|          } else if (!url.parse_host(host_view)) {
  ------------------
  |  Branch (12660:22): [True: 1.19k, False: 3.67k]
  ------------------
12661|  1.19k|            return url;
12662|  1.19k|          }
12663|  3.70k|          ada_log("HOST parsing results in ", url.get_hostname(),
12664|  3.70k|                  " href=", url.get_href());
12665|       |
12666|       |          // Set url’s host to host, and state to path start state.
12667|  3.70k|          state = ada::state::PATH_START;
12668|  3.70k|        }
12669|       |
12670|  4.42k|        break;
12671|  5.80k|      }
12672|  4.42k|      case ada::state::OPAQUE_PATH: {
  ------------------
  |  Branch (12672:7): [True: 1.09k, False: 60.1k]
  ------------------
12673|  1.09k|        ada_log("OPAQUE_PATH ", helpers::substring(url_data, input_position));
12674|  1.09k|        std::string_view view = helpers::substring(url_data, input_position);
12675|       |        // If c is U+003F (?), then set url’s query to the empty string and
12676|       |        // state to query state.
12677|  1.09k|        size_t location = view.find('?');
12678|  1.09k|        if (location != std::string_view::npos) {
  ------------------
  |  Branch (12678:13): [True: 86, False: 1.00k]
  ------------------
12679|     86|          view.remove_suffix(view.size() - location);
12680|     86|          state = ada::state::QUERY;
12681|     86|          input_position += location + 1;
12682|  1.00k|        } else {
12683|  1.00k|          input_position = input_size + 1;
12684|  1.00k|        }
12685|  1.09k|        url.has_opaque_path = true;
12686|       |        // This is a really unlikely scenario in real world. We should not seek
12687|       |        // to optimize it.
12688|  1.09k|        url.update_base_pathname(unicode::percent_encode(
12689|  1.09k|            view, character_sets::C0_CONTROL_PERCENT_ENCODE));
12690|  1.09k|        break;
12691|  5.80k|      }
12692|    728|      case ada::state::PORT: {
  ------------------
  |  Branch (12692:7): [True: 728, False: 60.5k]
  ------------------
12693|    728|        ada_log("PORT ", helpers::substring(url_data, input_position));
12694|    728|        std::string_view port_view =
12695|    728|            helpers::substring(url_data, input_position);
12696|    728|        size_t consumed_bytes = url.parse_port(port_view, true);
12697|    728|        input_position += consumed_bytes;
12698|    728|        if (!url.is_valid) {
  ------------------
  |  Branch (12698:13): [True: 84, False: 644]
  ------------------
12699|     84|          return url;
12700|     84|        }
12701|    644|        state = state::PATH_START;
12702|    644|        [[fallthrough]];
12703|    644|      }
12704|  4.72k|      case ada::state::PATH_START: {
  ------------------
  |  Branch (12704:7): [True: 4.07k, False: 57.1k]
  ------------------
12705|  4.72k|        ada_log("PATH_START ", helpers::substring(url_data, input_position));
12706|       |
12707|       |        // If url is special, then:
12708|  4.72k|        if (url.is_special()) {
  ------------------
  |  Branch (12708:13): [True: 4.46k, False: 259]
  ------------------
12709|       |          // Set state to path state.
12710|  4.46k|          state = ada::state::PATH;
12711|       |
12712|       |          // Optimization: Avoiding going into PATH state improves the
12713|       |          // performance of urls ending with /.
12714|  4.46k|          if (input_position == input_size) {
  ------------------
  |  Branch (12714:15): [True: 4.05k, False: 404]
  ------------------
12715|  4.05k|            url.update_base_pathname("/");
12716|  4.05k|            if (fragment.has_value()) {
  ------------------
  |  Branch (12716:17): [True: 80, False: 3.97k]
  ------------------
12717|     80|              url.update_unencoded_base_hash(*fragment);
12718|     80|            }
12719|  4.05k|            return url;
12720|  4.05k|          }
12721|       |          // If c is neither U+002F (/) nor U+005C (\), then decrease pointer
12722|       |          // by 1. We know that (input_position == input_size) is impossible
12723|       |          // here, because of the previous if-check.
12724|    404|          if ((url_data[input_position] != '/') &&
  ------------------
  |  Branch (12724:15): [True: 96, False: 308]
  ------------------
12725|    404|              (url_data[input_position] != '\\')) {
  ------------------
  |  Branch (12725:15): [True: 87, False: 9]
  ------------------
12726|     87|            break;
12727|     87|          }
12728|    404|        }
12729|       |        // Otherwise, if state override is not given and c is U+003F (?),
12730|       |        // set url’s query to the empty string and state to query state.
12731|    259|        else if ((input_position != input_size) &&
  ------------------
  |  Branch (12731:18): [True: 56, False: 203]
  ------------------
12732|    259|                 (url_data[input_position] == '?')) {
  ------------------
  |  Branch (12732:18): [True: 27, False: 29]
  ------------------
12733|     27|          state = ada::state::QUERY;
12734|     27|        }
12735|       |        // Otherwise, if c is not the EOF code point:
12736|    232|        else if (input_position != input_size) {
  ------------------
  |  Branch (12736:18): [True: 29, False: 203]
  ------------------
12737|       |          // Set state to path state.
12738|     29|          state = ada::state::PATH;
12739|       |
12740|       |          // If c is not U+002F (/), then decrease pointer by 1.
12741|     29|          if (url_data[input_position] != '/') {
  ------------------
  |  Branch (12741:15): [True: 0, False: 29]
  ------------------
12742|      0|            break;
12743|      0|          }
12744|     29|        }
12745|       |
12746|    576|        input_position++;
12747|    576|        break;
12748|  4.72k|      }
12749|  3.01k|      case ada::state::PATH: {
  ------------------
  |  Branch (12749:7): [True: 3.01k, False: 58.2k]
  ------------------
12750|  3.01k|        std::string_view view = helpers::substring(url_data, input_position);
12751|  3.01k|        ada_log("PATH ", helpers::substring(url_data, input_position));
12752|       |
12753|       |        // Most time, we do not need percent encoding.
12754|       |        // Furthermore, we can immediately locate the '?'.
12755|  3.01k|        size_t locofquestionmark = view.find('?');
12756|  3.01k|        if (locofquestionmark != std::string_view::npos) {
  ------------------
  |  Branch (12756:13): [True: 155, False: 2.86k]
  ------------------
12757|    155|          state = ada::state::QUERY;
12758|    155|          view.remove_suffix(view.size() - locofquestionmark);
12759|    155|          input_position += locofquestionmark + 1;
12760|  2.86k|        } else {
12761|  2.86k|          input_position = input_size + 1;
12762|  2.86k|        }
12763|  3.01k|        if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12763:23): [Folded - Ignored]
  ------------------
12764|  3.01k|          helpers::parse_prepared_path(view, url.type, url.path);
12765|  3.01k|        } else {
12766|  3.01k|          url.consume_prepared_path(view);
12767|  3.01k|          ADA_ASSERT_TRUE(url.validate());
12768|  3.01k|        }
12769|  3.01k|        break;
12770|  4.72k|      }
12771|    570|      case ada::state::FILE_SLASH: {
  ------------------
  |  Branch (12771:7): [True: 570, False: 60.6k]
  ------------------
12772|    570|        ada_log("FILE_SLASH ", helpers::substring(url_data, input_position));
12773|       |
12774|       |        // If c is U+002F (/) or U+005C (\), then:
12775|    570|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12775:13): [True: 533, False: 37]
  ------------------
12776|    570|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (12776:14): [True: 512, False: 21]
  ------------------
12777|    533|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (12777:14): [True: 5, False: 16]
  ------------------
12778|    517|          ada_log("FILE_SLASH c is U+002F or U+005C");
12779|       |          // Set state to file host state.
12780|    517|          state = ada::state::FILE_HOST;
12781|    517|          input_position++;
12782|    517|        } else {
12783|     53|          ada_log("FILE_SLASH otherwise");
12784|       |          // If base is non-null and base’s scheme is "file", then:
12785|       |          // Note: it is unsafe to do base_url->scheme unless you know that
12786|       |          // base_url_has_value() is true.
12787|     53|          if (base_url != nullptr &&
  ------------------
  |  Branch (12787:15): [True: 0, False: 53]
  ------------------
12788|     53|              base_url->type == ada::scheme::type::FILE) {
  ------------------
  |  Branch (12788:15): [True: 0, False: 0]
  ------------------
12789|       |            // Set url’s host to base’s host.
12790|      0|            if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12790:27): [Folded - Ignored]
  ------------------
12791|      0|              url.host = base_url->host;
12792|      0|            } else {
12793|       |              // TODO: Optimization opportunity.
12794|      0|              url.set_host(base_url->get_host());
12795|      0|            }
12796|       |            // If the code point substring from pointer to the end of input does
12797|       |            // not start with a Windows drive letter and base’s path[0] is a
12798|       |            // normalized Windows drive letter, then append base’s path[0] to
12799|       |            // url’s path.
12800|      0|            if (!base_url->get_pathname().empty()) {
  ------------------
  |  Branch (12800:17): [True: 0, False: 0]
  ------------------
12801|      0|              if (!checkers::is_windows_drive_letter(
  ------------------
  |  Branch (12801:19): [True: 0, False: 0]
  ------------------
12802|      0|                      helpers::substring(url_data, input_position))) {
12803|      0|                std::string_view first_base_url_path =
12804|      0|                    base_url->get_pathname().substr(1);
12805|      0|                size_t loc = first_base_url_path.find('/');
12806|      0|                if (loc != std::string_view::npos) {
  ------------------
  |  Branch (12806:21): [True: 0, False: 0]
  ------------------
12807|      0|                  helpers::resize(first_base_url_path, loc);
12808|      0|                }
12809|      0|                if (checkers::is_normalized_windows_drive_letter(
  ------------------
  |  Branch (12809:21): [True: 0, False: 0]
  ------------------
12810|      0|                        first_base_url_path)) {
12811|      0|                  if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12811:33): [Folded - Ignored]
  ------------------
12812|      0|                    url.path += '/';
12813|      0|                    url.path += first_base_url_path;
12814|      0|                  } else {
12815|      0|                    url.append_base_pathname(
12816|      0|                        helpers::concat("/", first_base_url_path));
12817|      0|                  }
12818|      0|                }
12819|      0|              }
12820|      0|            }
12821|      0|          }
12822|       |
12823|       |          // Set state to path state, and decrease pointer by 1.
12824|     53|          state = ada::state::PATH;
12825|     53|        }
12826|       |
12827|    570|        break;
12828|  4.72k|      }
12829|    517|      case ada::state::FILE_HOST: {
  ------------------
  |  Branch (12829:7): [True: 517, False: 60.7k]
  ------------------
12830|    517|        std::string_view view = helpers::substring(url_data, input_position);
12831|    517|        ada_log("FILE_HOST ", helpers::substring(url_data, input_position));
12832|       |
12833|    517|        size_t location = view.find_first_of("/\\?");
12834|    517|        std::string_view file_host_buffer(
12835|    517|            view.data(),
12836|    517|            (location != std::string_view::npos) ? location : view.size());
  ------------------
  |  Branch (12836:13): [True: 24, False: 493]
  ------------------
12837|       |
12838|    517|        if (checkers::is_windows_drive_letter(file_host_buffer)) {
  ------------------
  |  Branch (12838:13): [True: 7, False: 510]
  ------------------
12839|      7|          state = ada::state::PATH;
12840|    510|        } else if (file_host_buffer.empty()) {
  ------------------
  |  Branch (12840:20): [True: 14, False: 496]
  ------------------
12841|       |          // Set url’s host to the empty string.
12842|     14|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12842:25): [Folded - Ignored]
  ------------------
12843|     14|            url.host = "";
12844|     14|          } else {
12845|     14|            url.update_base_hostname("");
12846|     14|          }
12847|       |          // Set state to path start state.
12848|     14|          state = ada::state::PATH_START;
12849|    496|        } else {
12850|    496|          size_t consumed_bytes = file_host_buffer.size();
12851|    496|          input_position += consumed_bytes;
12852|       |          // Let host be the result of host parsing buffer with url is not
12853|       |          // special.
12854|    496|          if (!url.parse_host(file_host_buffer)) {
  ------------------
  |  Branch (12854:15): [True: 133, False: 363]
  ------------------
12855|    133|            return url;
12856|    133|          }
12857|       |
12858|    363|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12858:25): [Folded - Ignored]
  ------------------
12859|       |            // If host is "localhost", then set host to the empty string.
12860|    363|            if (url.host.has_value() && url.host.value() == "localhost") {
  ------------------
  |  Branch (12860:17): [True: 363, False: 0]
  |  Branch (12860:41): [True: 3, False: 360]
  ------------------
12861|      3|              url.host = "";
12862|      3|            }
12863|    363|          } else {
12864|    363|            if (url.get_hostname() == "localhost") {
12865|    363|              url.update_base_hostname("");
12866|    363|            }
12867|    363|          }
12868|       |
12869|       |          // Set buffer to the empty string and state to path start state.
12870|    363|          state = ada::state::PATH_START;
12871|    363|        }
12872|       |
12873|    384|        break;
12874|    517|      }
12875|  1.61k|      case ada::state::FILE: {
  ------------------
  |  Branch (12875:7): [True: 1.61k, False: 59.6k]
  ------------------
12876|  1.61k|        ada_log("FILE ", helpers::substring(url_data, input_position));
12877|  1.61k|        std::string_view file_view =
12878|  1.61k|            helpers::substring(url_data, input_position);
12879|       |
12880|  1.61k|        url.set_protocol_as_file();
12881|  1.61k|        if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12881:23): [Folded - Ignored]
  ------------------
12882|       |          // Set url’s host to the empty string.
12883|  1.61k|          url.host = "";
12884|  1.61k|        } else {
12885|  1.61k|          url.update_base_hostname("");
12886|  1.61k|        }
12887|       |        // If c is U+002F (/) or U+005C (\), then:
12888|  1.61k|        if (input_position != input_size &&
  ------------------
  |  Branch (12888:13): [True: 909, False: 708]
  ------------------
12889|  1.61k|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (12889:14): [True: 564, False: 345]
  ------------------
12890|    909|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (12890:14): [True: 6, False: 339]
  ------------------
12891|    570|          ada_log("FILE c is U+002F or U+005C");
12892|       |          // Set state to file slash state.
12893|    570|          state = ada::state::FILE_SLASH;
12894|    570|        }
12895|       |        // Otherwise, if base is non-null and base’s scheme is "file":
12896|  1.04k|        else if (base_url != nullptr &&
  ------------------
  |  Branch (12896:18): [True: 0, False: 1.04k]
  ------------------
12897|  1.04k|                 base_url->type == ada::scheme::type::FILE) {
  ------------------
  |  Branch (12897:18): [True: 0, False: 0]
  ------------------
12898|       |          // Set url’s host to base’s host, url’s path to a clone of base’s
12899|       |          // path, and url’s query to base’s query.
12900|      0|          ada_log("FILE base non-null");
12901|      0|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12901:25): [Folded - Ignored]
  ------------------
12902|      0|            url.host = base_url->host;
12903|      0|            url.path = base_url->path;
12904|      0|            url.query = base_url->query;
12905|      0|          } else {
12906|       |            // TODO: Get rid of set_hostname and replace it with
12907|       |            // update_base_hostname
12908|      0|            url.set_hostname(base_url->get_hostname());
12909|      0|            url.update_base_pathname(base_url->get_pathname());
12910|      0|            url.update_base_search(base_url->get_search());
12911|      0|          }
12912|      0|          url.has_opaque_path = base_url->has_opaque_path;
12913|       |
12914|       |          // If c is U+003F (?), then set url’s query to the empty string and
12915|       |          // state to query state.
12916|      0|          if (input_position != input_size && url_data[input_position] == '?') {
  ------------------
  |  Branch (12916:15): [True: 0, False: 0]
  |  Branch (12916:47): [True: 0, False: 0]
  ------------------
12917|      0|            state = ada::state::QUERY;
12918|      0|          }
12919|       |          // Otherwise, if c is not the EOF code point:
12920|      0|          else if (input_position != input_size) {
  ------------------
  |  Branch (12920:20): [True: 0, False: 0]
  ------------------
12921|       |            // Set url’s query to null.
12922|      0|            url.clear_search();
12923|       |            // If the code point substring from pointer to the end of input does
12924|       |            // not start with a Windows drive letter, then shorten url’s path.
12925|      0|            if (!checkers::is_windows_drive_letter(file_view)) {
  ------------------
  |  Branch (12925:17): [True: 0, False: 0]
  ------------------
12926|      0|              if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12926:29): [Folded - Ignored]
  ------------------
12927|      0|                helpers::shorten_path(url.path, url.type);
12928|      0|              } else {
12929|      0|                std::string_view path = url.get_pathname();
12930|      0|                if (helpers::shorten_path(path, url.type)) {
12931|      0|                  url.update_base_pathname(std::string(path));
12932|      0|                }
12933|      0|              }
12934|      0|            }
12935|       |            // Otherwise:
12936|      0|            else {
12937|       |              // Set url’s path to an empty list.
12938|      0|              url.clear_pathname();
12939|      0|              url.has_opaque_path = true;
12940|      0|            }
12941|       |
12942|       |            // Set state to path state and decrease pointer by 1.
12943|      0|            state = ada::state::PATH;
12944|      0|            break;
12945|      0|          }
12946|      0|        }
12947|       |        // Otherwise, set state to path state, and decrease pointer by 1.
12948|  1.04k|        else {
12949|  1.04k|          ada_log("FILE go to path");
12950|  1.04k|          state = ada::state::PATH;
12951|  1.04k|          break;
12952|  1.04k|        }
12953|       |
12954|    570|        input_position++;
12955|    570|        break;
12956|  1.61k|      }
12957|      0|      default:
  ------------------
  |  Branch (12957:7): [True: 0, False: 61.2k]
  ------------------
12958|      0|        ada::unreachable();
12959|  61.2k|    }
12960|  61.2k|  }
12961|  4.07k|  if (fragment.has_value()) {
  ------------------
  |  Branch (12961:7): [True: 157, False: 3.91k]
  ------------------
12962|    157|    url.update_unencoded_base_hash(*fragment);
12963|    157|  }
12964|  4.07k|  return url;
12965|  14.5k|}
_ZN3ada6parser9parse_urlINS_14url_aggregatorEEET_NSt3__117basic_string_viewIcNS4_11char_traitsIcEEEEPKS3_:
12072|  45.4k|                      const result_type* base_url) {
12073|       |  // We can specialize the implementation per type.
12074|       |  // Important: result_type_is_ada_url is evaluated at *compile time*. This
12075|       |  // means that doing if constexpr(result_type_is_ada_url) { something } else {
12076|       |  // something else } is free (at runtime). This means that ada::url_aggregator
12077|       |  // and ada::url **do not have to support the exact same API**.
12078|  45.4k|  constexpr bool result_type_is_ada_url =
12079|  45.4k|      std::is_same<ada::url, result_type>::value;
12080|  45.4k|  constexpr bool result_type_is_ada_url_aggregator =
12081|  45.4k|      std::is_same<ada::url_aggregator, result_type>::value;
12082|  45.4k|  static_assert(result_type_is_ada_url ||
12083|  45.4k|                result_type_is_ada_url_aggregator);  // We don't support
12084|       |                                                     // anything else for now.
12085|       |
12086|  45.4k|  ada_log("ada::parser::parse_url('", user_input, "' [", user_input.size(),
12087|  45.4k|          " bytes],", (base_url != nullptr ? base_url->to_string() : "null"),
12088|  45.4k|          ")");
12089|       |
12090|  45.4k|  ada::state state = ada::state::SCHEME_START;
12091|  45.4k|  result_type url{};
12092|       |
12093|       |  // We refuse to parse URL strings that exceed 4GB. Such strings are almost
12094|       |  // surely the result of a bug or are otherwise a security concern.
12095|  45.4k|  if (user_input.size() > std::numeric_limits<uint32_t>::max()) {
  ------------------
  |  Branch (12095:7): [True: 2, False: 45.4k]
  ------------------
12096|      2|    url.is_valid = false;
12097|      2|  }
12098|       |  // Going forward, user_input.size() is in [0,
12099|       |  // std::numeric_limits<uint32_t>::max). If we are provided with an invalid
12100|       |  // base, or the optional_url was invalid, we must return.
12101|  45.4k|  if (base_url != nullptr) {
  ------------------
  |  Branch (12101:7): [True: 2.66k, False: 42.7k]
  ------------------
12102|  2.66k|    url.is_valid &= base_url->is_valid;
12103|  2.66k|  }
12104|  45.4k|  if (!url.is_valid) {
  ------------------
  |  Branch (12104:7): [True: 2, False: 45.4k]
  ------------------
12105|      2|    return url;
12106|      2|  }
12107|  45.4k|  if constexpr (result_type_is_ada_url_aggregator) {
  ------------------
  |  Branch (12107:17): [Folded - Ignored]
  ------------------
12108|       |    // Most of the time, we just need user_input.size().
12109|       |    // In some instances, we may need a bit more.
12110|       |    ///////////////////////////
12111|       |    // This is *very* important. This line should be removed
12112|       |    // hastily. There are principled reasons why reserve is important
12113|       |    // for performance. If you have a benchmark with small inputs,
12114|       |    // it may not matter, but in other instances, it could.
12115|       |    ////
12116|       |    // This rounds up to the next power of two.
12117|       |    // We know that user_input.size() is in [0,
12118|       |    // std::numeric_limits<uint32_t>::max).
12119|  45.4k|    uint32_t reserve_capacity =
12120|  45.4k|        (0xFFFFFFFF >>
12121|  45.4k|         helpers::leading_zeroes(uint32_t(1 | user_input.size()))) +
12122|  45.4k|        1;
12123|  45.4k|    url.reserve(reserve_capacity);
12124|       |    //
12125|       |    //
12126|       |    //
12127|  45.4k|  }
12128|  45.4k|  std::string tmp_buffer;
12129|  45.4k|  std::string_view internal_input;
12130|  45.4k|  if (unicode::has_tabs_or_newline(user_input)) {
  ------------------
  |  Branch (12130:7): [True: 468, False: 44.9k]
  ------------------
12131|    468|    tmp_buffer = user_input;
12132|       |    // Optimization opportunity: Instead of copying and then pruning, we could
12133|       |    // just directly build the string from user_input.
12134|    468|    helpers::remove_ascii_tab_or_newline(tmp_buffer);
12135|    468|    internal_input = tmp_buffer;
12136|  44.9k|  } else {
12137|  44.9k|    internal_input = user_input;
12138|  44.9k|  }
12139|       |
12140|       |  // Leading and trailing control characters are uncommon and easy to deal with
12141|       |  // (no performance concern).
12142|  45.4k|  std::string_view url_data = internal_input;
12143|  45.4k|  helpers::trim_c0_whitespace(url_data);
12144|       |
12145|       |  // Optimization opportunity. Most websites do not have fragment.
12146|  45.4k|  std::optional<std::string_view> fragment = helpers::prune_hash(url_data);
12147|       |  // We add it last so that an implementation like ada::url_aggregator
12148|       |  // can append it last to its internal buffer, thus improving performance.
12149|       |
12150|       |  // Here url_data no longer has its fragment.
12151|       |  // We are going to access the data from url_data (it is immutable).
12152|       |  // At any given time, we are pointing at byte 'input_position' in url_data.
12153|       |  // The input_position variable should range from 0 to input_size.
12154|       |  // It is illegal to access url_data at input_size.
12155|  45.4k|  size_t input_position = 0;
12156|  45.4k|  const size_t input_size = url_data.size();
12157|       |  // Keep running the following state machine by switching on state.
12158|       |  // If after a run pointer points to the EOF code point, go to the next step.
12159|       |  // Otherwise, increase pointer by 1 and continue with the state machine.
12160|       |  // We never decrement input_position.
12161|   179k|  while (input_position <= input_size) {
  ------------------
  |  Branch (12161:10): [True: 168k, False: 11.1k]
  ------------------
12162|   168k|    ada_log("In parsing at ", input_position, " out of ", input_size,
12163|   168k|            " in state ", ada::to_string(state));
12164|   168k|    switch (state) {
12165|  45.4k|      case ada::state::SCHEME_START: {
  ------------------
  |  Branch (12165:7): [True: 45.4k, False: 122k]
  ------------------
12166|  45.4k|        ada_log("SCHEME_START ", helpers::substring(url_data, input_position));
12167|       |        // If c is an ASCII alpha, append c, lowercased, to buffer, and set
12168|       |        // state to scheme state.
12169|  45.4k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12169:13): [True: 31.3k, False: 14.0k]
  ------------------
12170|  45.4k|            checkers::is_alpha(url_data[input_position])) {
  ------------------
  |  Branch (12170:13): [True: 26.4k, False: 4.90k]
  ------------------
12171|  26.4k|          state = ada::state::SCHEME;
12172|  26.4k|          input_position++;
12173|  26.4k|        } else {
12174|       |          // Otherwise, if state override is not given, set state to no scheme
12175|       |          // state and decrease pointer by 1.
12176|  18.9k|          state = ada::state::NO_SCHEME;
12177|  18.9k|        }
12178|  45.4k|        break;
12179|      0|      }
12180|  26.4k|      case ada::state::SCHEME: {
  ------------------
  |  Branch (12180:7): [True: 26.4k, False: 141k]
  ------------------
12181|  26.4k|        ada_log("SCHEME ", helpers::substring(url_data, input_position));
12182|       |        // If c is an ASCII alphanumeric, U+002B (+), U+002D (-), or U+002E (.),
12183|       |        // append c, lowercased, to buffer.
12184|  87.0k|        while ((input_position != input_size) &&
  ------------------
  |  Branch (12184:16): [True: 85.8k, False: 1.23k]
  ------------------
12185|  87.0k|               (ada::unicode::is_alnum_plus(url_data[input_position]))) {
  ------------------
  |  Branch (12185:16): [True: 60.6k, False: 25.1k]
  ------------------
12186|  60.6k|          input_position++;
12187|  60.6k|        }
12188|       |        // Otherwise, if c is U+003A (:), then:
12189|  26.4k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12189:13): [True: 25.1k, False: 1.23k]
  ------------------
12190|  26.4k|            (url_data[input_position] == ':')) {
  ------------------
  |  Branch (12190:13): [True: 24.2k, False: 919]
  ------------------
12191|  24.2k|          ada_log("SCHEME the scheme should be ",
12192|  24.2k|                  url_data.substr(0, input_position));
12193|  24.2k|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12193:25): [Folded - Ignored]
  ------------------
12194|  24.2k|            if (!url.parse_scheme(url_data.substr(0, input_position))) {
12195|  24.2k|              return url;
12196|  24.2k|            }
12197|  24.2k|          } else {
12198|       |            // we pass the colon along instead of painfully adding it back.
12199|  24.2k|            if (!url.parse_scheme_with_colon(
  ------------------
  |  Branch (12199:17): [True: 0, False: 24.2k]
  ------------------
12200|  24.2k|                    url_data.substr(0, input_position + 1))) {
12201|      0|              return url;
12202|      0|            }
12203|  24.2k|          }
12204|  24.2k|          ada_log("SCHEME the scheme is ", url.get_protocol());
12205|       |
12206|       |          // If url’s scheme is "file", then:
12207|  24.2k|          if (url.type == ada::scheme::type::FILE) {
  ------------------
  |  Branch (12207:15): [True: 4.13k, False: 20.1k]
  ------------------
12208|       |            // Set state to file state.
12209|  4.13k|            state = ada::state::FILE;
12210|  4.13k|          }
12211|       |          // Otherwise, if url is special, base is non-null, and base’s scheme
12212|       |          // is url’s scheme: Note: Doing base_url->scheme is unsafe if base_url
12213|       |          // != nullptr is false.
12214|  20.1k|          else if (url.is_special() && base_url != nullptr &&
  ------------------
  |  Branch (12214:20): [True: 12.8k, False: 7.25k]
  |  Branch (12214:40): [True: 903, False: 11.9k]
  ------------------
12215|  20.1k|                   base_url->type == url.type) {
  ------------------
  |  Branch (12215:20): [True: 120, False: 783]
  ------------------
12216|       |            // Set state to special relative or authority state.
12217|    120|            state = ada::state::SPECIAL_RELATIVE_OR_AUTHORITY;
12218|    120|          }
12219|       |          // Otherwise, if url is special, set state to special authority
12220|       |          // slashes state.
12221|  20.0k|          else if (url.is_special()) {
  ------------------
  |  Branch (12221:20): [True: 12.7k, False: 7.25k]
  ------------------
12222|  12.7k|            state = ada::state::SPECIAL_AUTHORITY_SLASHES;
12223|  12.7k|          }
12224|       |          // Otherwise, if remaining starts with an U+002F (/), set state to
12225|       |          // path or authority state and increase pointer by 1.
12226|  7.25k|          else if (input_position + 1 < input_size &&
  ------------------
  |  Branch (12226:20): [True: 5.25k, False: 1.99k]
  ------------------
12227|  7.25k|                   url_data[input_position + 1] == '/') {
  ------------------
  |  Branch (12227:20): [True: 3.91k, False: 1.34k]
  ------------------
12228|  3.91k|            state = ada::state::PATH_OR_AUTHORITY;
12229|  3.91k|            input_position++;
12230|  3.91k|          }
12231|       |          // Otherwise, set url’s path to the empty string and set state to
12232|       |          // opaque path state.
12233|  3.34k|          else {
12234|  3.34k|            state = ada::state::OPAQUE_PATH;
12235|  3.34k|          }
12236|  24.2k|        }
12237|       |        // Otherwise, if state override is not given, set buffer to the empty
12238|       |        // string, state to no scheme state, and start over (from the first code
12239|       |        // point in input).
12240|  2.15k|        else {
12241|  2.15k|          state = ada::state::NO_SCHEME;
12242|  2.15k|          input_position = 0;
12243|  2.15k|          break;
12244|  2.15k|        }
12245|  24.2k|        input_position++;
12246|  24.2k|        break;
12247|  26.4k|      }
12248|  21.1k|      case ada::state::NO_SCHEME: {
  ------------------
  |  Branch (12248:7): [True: 21.1k, False: 146k]
  ------------------
12249|  21.1k|        ada_log("NO_SCHEME ", helpers::substring(url_data, input_position));
12250|       |        // If base is null, or base has an opaque path and c is not U+0023 (#),
12251|       |        // validation error, return failure.
12252|  21.1k|        if (base_url == nullptr ||
  ------------------
  |  Branch (12252:13): [True: 19.8k, False: 1.28k]
  ------------------
12253|  21.1k|            (base_url->has_opaque_path && !fragment.has_value())) {
  ------------------
  |  Branch (12253:14): [True: 114, False: 1.17k]
  |  Branch (12253:43): [True: 42, False: 72]
  ------------------
12254|  19.8k|          ada_log("NO_SCHEME validation error");
12255|  19.8k|          url.is_valid = false;
12256|  19.8k|          return url;
12257|  19.8k|        }
12258|       |        // Otherwise, if base has an opaque path and c is U+0023 (#),
12259|       |        // set url’s scheme to base’s scheme, url’s path to base’s path, url’s
12260|       |        // query to base’s query, and set state to fragment state.
12261|  1.24k|        else if (base_url->has_opaque_path && fragment.has_value() &&
  ------------------
  |  Branch (12261:18): [True: 72, False: 1.17k]
  |  Branch (12261:47): [True: 72, False: 0]
  ------------------
12262|  1.24k|                 input_position == input_size) {
  ------------------
  |  Branch (12262:18): [True: 28, False: 44]
  ------------------
12263|     28|          ada_log("NO_SCHEME opaque base with fragment");
12264|     28|          url.copy_scheme(*base_url);
12265|     28|          url.has_opaque_path = base_url->has_opaque_path;
12266|       |
12267|     28|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12267:25): [Folded - Ignored]
  ------------------
12268|     28|            url.path = base_url->path;
12269|     28|            url.query = base_url->query;
12270|     28|          } else {
12271|     28|            url.update_base_pathname(base_url->get_pathname());
12272|     28|            url.update_base_search(base_url->get_search());
12273|     28|          }
12274|     28|          url.update_unencoded_base_hash(*fragment);
12275|     28|          return url;
12276|     28|        }
12277|       |        // Otherwise, if base’s scheme is not "file", set state to relative
12278|       |        // state and decrease pointer by 1.
12279|  1.21k|        else if (base_url->type != ada::scheme::type::FILE) {
  ------------------
  |  Branch (12279:18): [True: 657, False: 562]
  ------------------
12280|    657|          ada_log("NO_SCHEME non-file relative path");
12281|    657|          state = ada::state::RELATIVE_SCHEME;
12282|    657|        }
12283|       |        // Otherwise, set state to file state and decrease pointer by 1.
12284|    562|        else {
12285|    562|          ada_log("NO_SCHEME file base type");
12286|    562|          state = ada::state::FILE;
12287|    562|        }
12288|  1.21k|        break;
12289|  21.1k|      }
12290|  13.5k|      case ada::state::AUTHORITY: {
  ------------------
  |  Branch (12290:7): [True: 13.5k, False: 154k]
  ------------------
12291|  13.5k|        ada_log("AUTHORITY ", helpers::substring(url_data, input_position));
12292|       |        // most URLs have no @. Having no @ tells us that we don't have to worry
12293|       |        // about AUTHORITY. Of course, we could have @ and still not have to
12294|       |        // worry about AUTHORITY.
12295|       |        // TODO: Instead of just collecting a bool, collect the location of the
12296|       |        // '@' and do something useful with it.
12297|       |        // TODO: We could do various processing early on, using a single pass
12298|       |        // over the string to collect information about it, e.g., telling us
12299|       |        // whether there is a @ and if so, where (or how many).
12300|  13.5k|        const bool contains_ampersand =
12301|  13.5k|            (url_data.find('@', input_position) != std::string_view::npos);
12302|       |
12303|  13.5k|        if (!contains_ampersand) {
  ------------------
  |  Branch (12303:13): [True: 12.6k, False: 970]
  ------------------
12304|  12.6k|          state = ada::state::HOST;
12305|  12.6k|          break;
12306|  12.6k|        }
12307|    970|        bool at_sign_seen{false};
12308|    970|        bool password_token_seen{false};
12309|       |        /**
12310|       |         * We expect something of the sort...
12311|       |         * https://user:pass@example.com:1234/foo/bar?baz#quux
12312|       |         * --------^
12313|       |         */
12314|  7.52k|        do {
12315|  7.52k|          std::string_view view = helpers::substring(url_data, input_position);
12316|       |          // The delimiters are @, /, ? \\.
12317|  7.52k|          size_t location =
12318|  7.52k|              url.is_special() ? helpers::find_authority_delimiter_special(view)
  ------------------
  |  Branch (12318:15): [True: 6.32k, False: 1.20k]
  ------------------
12319|  7.52k|                               : helpers::find_authority_delimiter(view);
12320|  7.52k|          std::string_view authority_view(view.data(), location);
12321|  7.52k|          size_t end_of_authority = input_position + authority_view.size();
12322|       |          // If c is U+0040 (@), then:
12323|  7.52k|          if ((end_of_authority != input_size) &&
  ------------------
  |  Branch (12323:15): [True: 6.68k, False: 841]
  ------------------
12324|  7.52k|              (url_data[end_of_authority] == '@')) {
  ------------------
  |  Branch (12324:15): [True: 6.55k, False: 129]
  ------------------
12325|       |            // If atSignSeen is true, then prepend "%40" to buffer.
12326|  6.55k|            if (at_sign_seen) {
  ------------------
  |  Branch (12326:17): [True: 5.62k, False: 931]
  ------------------
12327|  5.62k|              if (password_token_seen) {
  ------------------
  |  Branch (12327:19): [True: 1.37k, False: 4.25k]
  ------------------
12328|  1.37k|                if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12328:31): [Folded - Ignored]
  ------------------
12329|  1.37k|                  url.password += "%40";
12330|  1.37k|                } else {
12331|  1.37k|                  url.append_base_password("%40");
12332|  1.37k|                }
12333|  4.25k|              } else {
12334|  4.25k|                if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12334:31): [Folded - Ignored]
  ------------------
12335|  4.25k|                  url.username += "%40";
12336|  4.25k|                } else {
12337|  4.25k|                  url.append_base_username("%40");
12338|  4.25k|                }
12339|  4.25k|              }
12340|  5.62k|            }
12341|       |
12342|  6.55k|            at_sign_seen = true;
12343|       |
12344|  6.55k|            if (!password_token_seen) {
  ------------------
  |  Branch (12344:17): [True: 5.18k, False: 1.37k]
  ------------------
12345|  5.18k|              size_t password_token_location = authority_view.find(':');
12346|  5.18k|              password_token_seen =
12347|  5.18k|                  password_token_location != std::string_view::npos;
12348|       |
12349|  5.18k|              if (!password_token_seen) {
  ------------------
  |  Branch (12349:19): [True: 4.85k, False: 325]
  ------------------
12350|  4.85k|                if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12350:31): [Folded - Ignored]
  ------------------
12351|  4.85k|                  url.username += unicode::percent_encode(
12352|  4.85k|                      authority_view, character_sets::USERINFO_PERCENT_ENCODE);
12353|  4.85k|                } else {
12354|  4.85k|                  url.append_base_username(unicode::percent_encode(
12355|  4.85k|                      authority_view, character_sets::USERINFO_PERCENT_ENCODE));
12356|  4.85k|                }
12357|  4.85k|              } else {
12358|    325|                if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12358:31): [Folded - Ignored]
  ------------------
12359|    325|                  url.username += unicode::percent_encode(
12360|    325|                      authority_view.substr(0, password_token_location),
12361|    325|                      character_sets::USERINFO_PERCENT_ENCODE);
12362|    325|                  url.password += unicode::percent_encode(
12363|    325|                      authority_view.substr(password_token_location + 1),
12364|    325|                      character_sets::USERINFO_PERCENT_ENCODE);
12365|    325|                } else {
12366|    325|                  url.append_base_username(unicode::percent_encode(
12367|    325|                      authority_view.substr(0, password_token_location),
12368|    325|                      character_sets::USERINFO_PERCENT_ENCODE));
12369|    325|                  url.append_base_password(unicode::percent_encode(
12370|    325|                      authority_view.substr(password_token_location + 1),
12371|    325|                      character_sets::USERINFO_PERCENT_ENCODE));
12372|    325|                }
12373|    325|              }
12374|  5.18k|            } else {
12375|  1.37k|              if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12375:29): [Folded - Ignored]
  ------------------
12376|  1.37k|                url.password += unicode::percent_encode(
12377|  1.37k|                    authority_view, character_sets::USERINFO_PERCENT_ENCODE);
12378|  1.37k|              } else {
12379|  1.37k|                url.append_base_password(unicode::percent_encode(
12380|  1.37k|                    authority_view, character_sets::USERINFO_PERCENT_ENCODE));
12381|  1.37k|              }
12382|  1.37k|            }
12383|  6.55k|          }
12384|       |          // Otherwise, if one of the following is true:
12385|       |          // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
12386|       |          // - url is special and c is U+005C (\)
12387|    970|          else if (end_of_authority == input_size ||
  ------------------
  |  Branch (12387:20): [True: 841, False: 129]
  ------------------
12388|    970|                   url_data[end_of_authority] == '/' ||
  ------------------
  |  Branch (12388:20): [True: 67, False: 62]
  ------------------
12389|    970|                   url_data[end_of_authority] == '?' ||
  ------------------
  |  Branch (12389:20): [True: 52, False: 10]
  ------------------
12390|    970|                   (url.is_special() && url_data[end_of_authority] == '\\')) {
  ------------------
  |  Branch (12390:21): [True: 10, False: 0]
  |  Branch (12390:41): [True: 10, False: 0]
  ------------------
12391|       |            // If atSignSeen is true and authority_view is the empty string,
12392|       |            // validation error, return failure.
12393|    970|            if (at_sign_seen && authority_view.empty()) {
  ------------------
  |  Branch (12393:17): [True: 931, False: 39]
  |  Branch (12393:33): [True: 513, False: 418]
  ------------------
12394|    513|              url.is_valid = false;
12395|    513|              return url;
12396|    513|            }
12397|    457|            state = ada::state::HOST;
12398|    457|            break;
12399|    970|          }
12400|  6.55k|          if (end_of_authority == input_size) {
  ------------------
  |  Branch (12400:15): [True: 0, False: 6.55k]
  ------------------
12401|      0|            if (fragment.has_value()) {
  ------------------
  |  Branch (12401:17): [True: 0, False: 0]
  ------------------
12402|      0|              url.update_unencoded_base_hash(*fragment);
12403|      0|            }
12404|      0|            return url;
12405|      0|          }
12406|  6.55k|          input_position = end_of_authority + 1;
12407|  6.55k|        } while (true);
  ------------------
  |  Branch (12407:18): [Folded - Ignored]
  ------------------
12408|       |
12409|    457|        break;
12410|    970|      }
12411|    457|      case ada::state::SPECIAL_RELATIVE_OR_AUTHORITY: {
  ------------------
  |  Branch (12411:7): [True: 120, False: 167k]
  ------------------
12412|    120|        ada_log("SPECIAL_RELATIVE_OR_AUTHORITY ",
12413|    120|                helpers::substring(url_data, input_position));
12414|       |
12415|       |        // If c is U+002F (/) and remaining starts with U+002F (/),
12416|       |        // then set state to special authority ignore slashes state and increase
12417|       |        // pointer by 1.
12418|    120|        std::string_view view = helpers::substring(url_data, input_position);
12419|    120|        if (ada::checkers::begins_with(view, "//")) {
  ------------------
  |  Branch (12419:13): [True: 2, False: 118]
  ------------------
12420|      2|          state = ada::state::SPECIAL_AUTHORITY_IGNORE_SLASHES;
12421|      2|          input_position += 2;
12422|    118|        } else {
12423|       |          // Otherwise, validation error, set state to relative state and
12424|       |          // decrease pointer by 1.
12425|    118|          state = ada::state::RELATIVE_SCHEME;
12426|    118|        }
12427|       |
12428|    120|        break;
12429|    970|      }
12430|  3.91k|      case ada::state::PATH_OR_AUTHORITY: {
  ------------------
  |  Branch (12430:7): [True: 3.91k, False: 164k]
  ------------------
12431|  3.91k|        ada_log("PATH_OR_AUTHORITY ",
12432|  3.91k|                helpers::substring(url_data, input_position));
12433|       |
12434|       |        // If c is U+002F (/), then set state to authority state.
12435|  3.91k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12435:13): [True: 1.87k, False: 2.03k]
  ------------------
12436|  3.91k|            (url_data[input_position] == '/')) {
  ------------------
  |  Branch (12436:13): [True: 800, False: 1.07k]
  ------------------
12437|    800|          state = ada::state::AUTHORITY;
12438|    800|          input_position++;
12439|  3.11k|        } else {
12440|       |          // Otherwise, set state to path state, and decrease pointer by 1.
12441|  3.11k|          state = ada::state::PATH;
12442|  3.11k|        }
12443|       |
12444|  3.91k|        break;
12445|    970|      }
12446|    775|      case ada::state::RELATIVE_SCHEME: {
  ------------------
  |  Branch (12446:7): [True: 775, False: 167k]
  ------------------
12447|    775|        ada_log("RELATIVE_SCHEME ",
12448|    775|                helpers::substring(url_data, input_position));
12449|       |
12450|       |        // Set url’s scheme to base’s scheme.
12451|    775|        url.copy_scheme(*base_url);
12452|       |
12453|       |        // If c is U+002F (/), then set state to relative slash state.
12454|    775|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12454:13): [True: 282, False: 493]
  ------------------
12455|    775|            (url_data[input_position] == '/')) {
  ------------------
  |  Branch (12455:13): [True: 43, False: 239]
  ------------------
12456|     43|          ada_log(
12457|     43|              "RELATIVE_SCHEME if c is U+002F (/), then set state to relative "
12458|     43|              "slash state");
12459|     43|          state = ada::state::RELATIVE_SLASH;
12460|    732|        } else if (url.is_special() && (input_position != input_size) &&
  ------------------
  |  Branch (12460:20): [True: 590, False: 142]
  |  Branch (12460:40): [True: 153, False: 437]
  ------------------
12461|    732|                   (url_data[input_position] == '\\')) {
  ------------------
  |  Branch (12461:20): [True: 1, False: 152]
  ------------------
12462|       |          // Otherwise, if url is special and c is U+005C (\), validation error,
12463|       |          // set state to relative slash state.
12464|      1|          ada_log(
12465|      1|              "RELATIVE_SCHEME  if url is special and c is U+005C, validation "
12466|      1|              "error, set state to relative slash state");
12467|      1|          state = ada::state::RELATIVE_SLASH;
12468|    731|        } else {
12469|    731|          ada_log("RELATIVE_SCHEME otherwise");
12470|       |          // Set url’s username to base’s username, url’s password to base’s
12471|       |          // password, url’s host to base’s host, url’s port to base’s port,
12472|       |          // url’s path to a clone of base’s path, and url’s query to base’s
12473|       |          // query.
12474|    731|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12474:25): [Folded - Ignored]
  ------------------
12475|    731|            url.username = base_url->username;
12476|    731|            url.password = base_url->password;
12477|    731|            url.host = base_url->host;
12478|    731|            url.port = base_url->port;
12479|       |            // cloning the base path includes cloning the has_opaque_path flag
12480|    731|            url.has_opaque_path = base_url->has_opaque_path;
12481|    731|            url.path = base_url->path;
12482|    731|            url.query = base_url->query;
12483|    731|          } else {
12484|    731|            url.update_base_authority(base_url->get_href(),
12485|    731|                                      base_url->get_components());
12486|       |            // TODO: Get rid of set_hostname and replace it with
12487|       |            // update_base_hostname
12488|    731|            url.set_hostname(base_url->get_hostname());
12489|    731|            url.update_base_port(base_url->retrieve_base_port());
12490|       |            // cloning the base path includes cloning the has_opaque_path flag
12491|    731|            url.has_opaque_path = base_url->has_opaque_path;
12492|    731|            url.update_base_pathname(base_url->get_pathname());
12493|    731|            url.update_base_search(base_url->get_search());
12494|    731|          }
12495|       |
12496|    731|          url.has_opaque_path = base_url->has_opaque_path;
12497|       |
12498|       |          // If c is U+003F (?), then set url’s query to the empty string, and
12499|       |          // state to query state.
12500|    731|          if ((input_position != input_size) &&
  ------------------
  |  Branch (12500:15): [True: 238, False: 493]
  ------------------
12501|    731|              (url_data[input_position] == '?')) {
  ------------------
  |  Branch (12501:15): [True: 5, False: 233]
  ------------------
12502|      5|            state = ada::state::QUERY;
12503|      5|          }
12504|       |          // Otherwise, if c is not the EOF code point:
12505|    726|          else if (input_position != input_size) {
  ------------------
  |  Branch (12505:20): [True: 233, False: 493]
  ------------------
12506|       |            // Set url’s query to null.
12507|    233|            url.clear_search();
12508|    233|            if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12508:27): [Folded - Ignored]
  ------------------
12509|       |              // Shorten url’s path.
12510|    233|              helpers::shorten_path(url.path, url.type);
12511|    233|            } else {
12512|    233|              std::string_view path = url.get_pathname();
12513|    233|              if (helpers::shorten_path(path, url.type)) {
  ------------------
  |  Branch (12513:19): [True: 197, False: 36]
  ------------------
12514|    197|                url.update_base_pathname(std::string(path));
12515|    197|              }
12516|    233|            }
12517|       |            // Set state to path state and decrease pointer by 1.
12518|    233|            state = ada::state::PATH;
12519|    233|            break;
12520|    233|          }
12521|    731|        }
12522|    542|        input_position++;
12523|    542|        break;
12524|    775|      }
12525|     44|      case ada::state::RELATIVE_SLASH: {
  ------------------
  |  Branch (12525:7): [True: 44, False: 168k]
  ------------------
12526|     44|        ada_log("RELATIVE_SLASH ",
12527|     44|                helpers::substring(url_data, input_position));
12528|       |
12529|       |        // If url is special and c is U+002F (/) or U+005C (\), then:
12530|     44|        if (url.is_special() && (input_position != input_size) &&
  ------------------
  |  Branch (12530:13): [True: 26, False: 18]
  |  Branch (12530:33): [True: 18, False: 8]
  ------------------
12531|     44|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (12531:14): [True: 2, False: 16]
  ------------------
12532|     18|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (12532:14): [True: 1, False: 15]
  ------------------
12533|       |          // Set state to special authority ignore slashes state.
12534|      3|          state = ada::state::SPECIAL_AUTHORITY_IGNORE_SLASHES;
12535|      3|        }
12536|       |        // Otherwise, if c is U+002F (/), then set state to authority state.
12537|     41|        else if ((input_position != input_size) &&
  ------------------
  |  Branch (12537:18): [True: 31, False: 10]
  ------------------
12538|     41|                 (url_data[input_position] == '/')) {
  ------------------
  |  Branch (12538:18): [True: 5, False: 26]
  ------------------
12539|      5|          state = ada::state::AUTHORITY;
12540|      5|        }
12541|       |        // Otherwise, set
12542|       |        // - url’s username to base’s username,
12543|       |        // - url’s password to base’s password,
12544|       |        // - url’s host to base’s host,
12545|       |        // - url’s port to base’s port,
12546|       |        // - state to path state, and then, decrease pointer by 1.
12547|     36|        else {
12548|     36|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12548:25): [Folded - Ignored]
  ------------------
12549|     36|            url.username = base_url->username;
12550|     36|            url.password = base_url->password;
12551|     36|            url.host = base_url->host;
12552|     36|            url.port = base_url->port;
12553|     36|          } else {
12554|     36|            url.update_base_authority(base_url->get_href(),
12555|     36|                                      base_url->get_components());
12556|       |            // TODO: Get rid of set_hostname and replace it with
12557|       |            // update_base_hostname
12558|     36|            url.set_hostname(base_url->get_hostname());
12559|     36|            url.update_base_port(base_url->retrieve_base_port());
12560|     36|          }
12561|     36|          state = ada::state::PATH;
12562|     36|          break;
12563|     36|        }
12564|       |
12565|      8|        input_position++;
12566|      8|        break;
12567|     44|      }
12568|  12.7k|      case ada::state::SPECIAL_AUTHORITY_SLASHES: {
  ------------------
  |  Branch (12568:7): [True: 12.7k, False: 155k]
  ------------------
12569|  12.7k|        ada_log("SPECIAL_AUTHORITY_SLASHES ",
12570|  12.7k|                helpers::substring(url_data, input_position));
12571|       |
12572|       |        // If c is U+002F (/) and remaining starts with U+002F (/),
12573|       |        // then set state to special authority ignore slashes state and increase
12574|       |        // pointer by 1.
12575|  12.7k|        state = ada::state::SPECIAL_AUTHORITY_IGNORE_SLASHES;
12576|  12.7k|        std::string_view view = helpers::substring(url_data, input_position);
12577|  12.7k|        if (ada::checkers::begins_with(view, "//")) {
  ------------------
  |  Branch (12577:13): [True: 34, False: 12.7k]
  ------------------
12578|     34|          input_position += 2;
12579|     34|        }
12580|       |
12581|  12.7k|        [[fallthrough]];
12582|  12.7k|      }
12583|  12.7k|      case ada::state::SPECIAL_AUTHORITY_IGNORE_SLASHES: {
  ------------------
  |  Branch (12583:7): [True: 5, False: 168k]
  ------------------
12584|  12.7k|        ada_log("SPECIAL_AUTHORITY_IGNORE_SLASHES ",
12585|  12.7k|                helpers::substring(url_data, input_position));
12586|       |
12587|       |        // If c is neither U+002F (/) nor U+005C (\), then set state to
12588|       |        // authority state and decrease pointer by 1.
12589|  13.9k|        while ((input_position != input_size) &&
  ------------------
  |  Branch (12589:16): [True: 13.8k, False: 88]
  ------------------
12590|  13.9k|               ((url_data[input_position] == '/') ||
  ------------------
  |  Branch (12590:17): [True: 613, False: 13.2k]
  ------------------
12591|  13.8k|                (url_data[input_position] == '\\'))) {
  ------------------
  |  Branch (12591:17): [True: 548, False: 12.6k]
  ------------------
12592|  1.16k|          input_position++;
12593|  1.16k|        }
12594|  12.7k|        state = ada::state::AUTHORITY;
12595|       |
12596|  12.7k|        break;
12597|  12.7k|      }
12598|    687|      case ada::state::QUERY: {
  ------------------
  |  Branch (12598:7): [True: 687, False: 167k]
  ------------------
12599|    687|        ada_log("QUERY ", helpers::substring(url_data, input_position));
12600|       |        // Let queryPercentEncodeSet be the special-query percent-encode set if
12601|       |        // url is special; otherwise the query percent-encode set.
12602|    687|        const uint8_t* query_percent_encode_set =
12603|    687|            url.is_special() ? ada::character_sets::SPECIAL_QUERY_PERCENT_ENCODE
  ------------------
  |  Branch (12603:13): [True: 319, False: 368]
  ------------------
12604|    687|                             : ada::character_sets::QUERY_PERCENT_ENCODE;
12605|       |
12606|       |        // Percent-encode after encoding, with encoding, buffer, and
12607|       |        // queryPercentEncodeSet, and append the result to url’s query.
12608|    687|        url.update_base_search(helpers::substring(url_data, input_position),
12609|    687|                               query_percent_encode_set);
12610|    687|        ada_log("QUERY update_base_search completed ");
12611|    687|        if (fragment.has_value()) {
  ------------------
  |  Branch (12611:13): [True: 80, False: 607]
  ------------------
12612|     80|          url.update_unencoded_base_hash(*fragment);
12613|     80|        }
12614|    687|        return url;
12615|  12.7k|      }
12616|  13.0k|      case ada::state::HOST: {
  ------------------
  |  Branch (12616:7): [True: 13.0k, False: 155k]
  ------------------
12617|  13.0k|        ada_log("HOST ", helpers::substring(url_data, input_position));
12618|       |
12619|  13.0k|        std::string_view host_view =
12620|  13.0k|            helpers::substring(url_data, input_position);
12621|  13.0k|        auto [location, found_colon] =
12622|  13.0k|            helpers::get_host_delimiter_location(url.is_special(), host_view);
12623|  13.0k|        input_position = (location != std::string_view::npos)
  ------------------
  |  Branch (12623:26): [True: 13.0k, False: 0]
  ------------------
12624|  13.0k|                             ? input_position + location
12625|  13.0k|                             : input_size;
12626|       |        // Otherwise, if c is U+003A (:) and insideBrackets is false, then:
12627|       |        // Note: the 'found_colon' value is true if and only if a colon was
12628|       |        // encountered while not inside brackets.
12629|  13.0k|        if (found_colon) {
  ------------------
  |  Branch (12629:13): [True: 1.94k, False: 11.1k]
  ------------------
12630|       |          // If buffer is the empty string, validation error, return failure.
12631|       |          // Let host be the result of host parsing buffer with url is not
12632|       |          // special.
12633|  1.94k|          ada_log("HOST parsing ", host_view);
12634|  1.94k|          if (!url.parse_host(host_view)) {
  ------------------
  |  Branch (12634:15): [True: 295, False: 1.64k]
  ------------------
12635|    295|            return url;
12636|    295|          }
12637|  1.64k|          ada_log("HOST parsing results in ", url.get_hostname());
12638|       |          // Set url’s host to host, buffer to the empty string, and state to
12639|       |          // port state.
12640|  1.64k|          state = ada::state::PORT;
12641|  1.64k|          input_position++;
12642|  1.64k|        }
12643|       |        // Otherwise, if one of the following is true:
12644|       |        // - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#)
12645|       |        // - url is special and c is U+005C (\)
12646|       |        // The get_host_delimiter_location function either brings us to
12647|       |        // the colon outside of the bracket, or to one of those characters.
12648|  11.1k|        else {
12649|       |          // If url is special and host_view is the empty string, validation
12650|       |          // error, return failure.
12651|  11.1k|          if (url.is_special() && host_view.empty()) {
  ------------------
  |  Branch (12651:15): [True: 10.5k, False: 536]
  |  Branch (12651:35): [True: 103, False: 10.4k]
  ------------------
12652|    103|            url.is_valid = false;
12653|    103|            return url;
12654|    103|          }
12655|  11.0k|          ada_log("HOST parsing ", host_view, " href=", url.get_href());
12656|       |          // Let host be the result of host parsing host_view with url is not
12657|       |          // special.
12658|  11.0k|          if (host_view.empty()) {
  ------------------
  |  Branch (12658:15): [True: 75, False: 10.9k]
  ------------------
12659|     75|            url.update_base_hostname("");
12660|  10.9k|          } else if (!url.parse_host(host_view)) {
  ------------------
  |  Branch (12660:22): [True: 2.60k, False: 8.33k]
  ------------------
12661|  2.60k|            return url;
12662|  2.60k|          }
12663|  8.40k|          ada_log("HOST parsing results in ", url.get_hostname(),
12664|  8.40k|                  " href=", url.get_href());
12665|       |
12666|       |          // Set url’s host to host, and state to path start state.
12667|  8.40k|          state = ada::state::PATH_START;
12668|  8.40k|        }
12669|       |
12670|  10.0k|        break;
12671|  13.0k|      }
12672|  10.0k|      case ada::state::OPAQUE_PATH: {
  ------------------
  |  Branch (12672:7): [True: 3.34k, False: 164k]
  ------------------
12673|  3.34k|        ada_log("OPAQUE_PATH ", helpers::substring(url_data, input_position));
12674|  3.34k|        std::string_view view = helpers::substring(url_data, input_position);
12675|       |        // If c is U+003F (?), then set url’s query to the empty string and
12676|       |        // state to query state.
12677|  3.34k|        size_t location = view.find('?');
12678|  3.34k|        if (location != std::string_view::npos) {
  ------------------
  |  Branch (12678:13): [True: 224, False: 3.11k]
  ------------------
12679|    224|          view.remove_suffix(view.size() - location);
12680|    224|          state = ada::state::QUERY;
12681|    224|          input_position += location + 1;
12682|  3.11k|        } else {
12683|  3.11k|          input_position = input_size + 1;
12684|  3.11k|        }
12685|  3.34k|        url.has_opaque_path = true;
12686|       |        // This is a really unlikely scenario in real world. We should not seek
12687|       |        // to optimize it.
12688|  3.34k|        url.update_base_pathname(unicode::percent_encode(
12689|  3.34k|            view, character_sets::C0_CONTROL_PERCENT_ENCODE));
12690|  3.34k|        break;
12691|  13.0k|      }
12692|  1.64k|      case ada::state::PORT: {
  ------------------
  |  Branch (12692:7): [True: 1.64k, False: 166k]
  ------------------
12693|  1.64k|        ada_log("PORT ", helpers::substring(url_data, input_position));
12694|  1.64k|        std::string_view port_view =
12695|  1.64k|            helpers::substring(url_data, input_position);
12696|  1.64k|        size_t consumed_bytes = url.parse_port(port_view, true);
12697|  1.64k|        input_position += consumed_bytes;
12698|  1.64k|        if (!url.is_valid) {
  ------------------
  |  Branch (12698:13): [True: 187, False: 1.46k]
  ------------------
12699|    187|          return url;
12700|    187|        }
12701|  1.46k|        state = state::PATH_START;
12702|  1.46k|        [[fallthrough]];
12703|  1.46k|      }
12704|  11.1k|      case ada::state::PATH_START: {
  ------------------
  |  Branch (12704:7): [True: 9.71k, False: 158k]
  ------------------
12705|  11.1k|        ada_log("PATH_START ", helpers::substring(url_data, input_position));
12706|       |
12707|       |        // If url is special, then:
12708|  11.1k|        if (url.is_special()) {
  ------------------
  |  Branch (12708:13): [True: 10.6k, False: 570]
  ------------------
12709|       |          // Set state to path state.
12710|  10.6k|          state = ada::state::PATH;
12711|       |
12712|       |          // Optimization: Avoiding going into PATH state improves the
12713|       |          // performance of urls ending with /.
12714|  10.6k|          if (input_position == input_size) {
  ------------------
  |  Branch (12714:15): [True: 9.64k, False: 961]
  ------------------
12715|  9.64k|            url.update_base_pathname("/");
12716|  9.64k|            if (fragment.has_value()) {
  ------------------
  |  Branch (12716:17): [True: 176, False: 9.47k]
  ------------------
12717|    176|              url.update_unencoded_base_hash(*fragment);
12718|    176|            }
12719|  9.64k|            return url;
12720|  9.64k|          }
12721|       |          // If c is neither U+002F (/) nor U+005C (\), then decrease pointer
12722|       |          // by 1. We know that (input_position == input_size) is impossible
12723|       |          // here, because of the previous if-check.
12724|    961|          if ((url_data[input_position] != '/') &&
  ------------------
  |  Branch (12724:15): [True: 228, False: 733]
  ------------------
12725|    961|              (url_data[input_position] != '\\')) {
  ------------------
  |  Branch (12725:15): [True: 202, False: 26]
  ------------------
12726|    202|            break;
12727|    202|          }
12728|    961|        }
12729|       |        // Otherwise, if state override is not given and c is U+003F (?),
12730|       |        // set url’s query to the empty string and state to query state.
12731|    570|        else if ((input_position != input_size) &&
  ------------------
  |  Branch (12731:18): [True: 123, False: 447]
  ------------------
12732|    570|                 (url_data[input_position] == '?')) {
  ------------------
  |  Branch (12732:18): [True: 59, False: 64]
  ------------------
12733|     59|          state = ada::state::QUERY;
12734|     59|        }
12735|       |        // Otherwise, if c is not the EOF code point:
12736|    511|        else if (input_position != input_size) {
  ------------------
  |  Branch (12736:18): [True: 64, False: 447]
  ------------------
12737|       |          // Set state to path state.
12738|     64|          state = ada::state::PATH;
12739|       |
12740|       |          // If c is not U+002F (/), then decrease pointer by 1.
12741|     64|          if (url_data[input_position] != '/') {
  ------------------
  |  Branch (12741:15): [True: 0, False: 64]
  ------------------
12742|      0|            break;
12743|      0|          }
12744|     64|        }
12745|       |
12746|  1.32k|        input_position++;
12747|  1.32k|        break;
12748|  11.1k|      }
12749|  7.26k|      case ada::state::PATH: {
  ------------------
  |  Branch (12749:7): [True: 7.26k, False: 160k]
  ------------------
12750|  7.26k|        std::string_view view = helpers::substring(url_data, input_position);
12751|  7.26k|        ada_log("PATH ", helpers::substring(url_data, input_position));
12752|       |
12753|       |        // Most time, we do not need percent encoding.
12754|       |        // Furthermore, we can immediately locate the '?'.
12755|  7.26k|        size_t locofquestionmark = view.find('?');
12756|  7.26k|        if (locofquestionmark != std::string_view::npos) {
  ------------------
  |  Branch (12756:13): [True: 397, False: 6.86k]
  ------------------
12757|    397|          state = ada::state::QUERY;
12758|    397|          view.remove_suffix(view.size() - locofquestionmark);
12759|    397|          input_position += locofquestionmark + 1;
12760|  6.86k|        } else {
12761|  6.86k|          input_position = input_size + 1;
12762|  6.86k|        }
12763|  7.26k|        if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12763:23): [Folded - Ignored]
  ------------------
12764|  7.26k|          helpers::parse_prepared_path(view, url.type, url.path);
12765|  7.26k|        } else {
12766|  7.26k|          url.consume_prepared_path(view);
12767|  7.26k|          ADA_ASSERT_TRUE(url.validate());
12768|  7.26k|        }
12769|  7.26k|        break;
12770|  11.1k|      }
12771|  1.96k|      case ada::state::FILE_SLASH: {
  ------------------
  |  Branch (12771:7): [True: 1.96k, False: 166k]
  ------------------
12772|  1.96k|        ada_log("FILE_SLASH ", helpers::substring(url_data, input_position));
12773|       |
12774|       |        // If c is U+002F (/) or U+005C (\), then:
12775|  1.96k|        if ((input_position != input_size) &&
  ------------------
  |  Branch (12775:13): [True: 1.67k, False: 292]
  ------------------
12776|  1.96k|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (12776:14): [True: 1.57k, False: 97]
  ------------------
12777|  1.67k|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (12777:14): [True: 13, False: 84]
  ------------------
12778|  1.58k|          ada_log("FILE_SLASH c is U+002F or U+005C");
12779|       |          // Set state to file host state.
12780|  1.58k|          state = ada::state::FILE_HOST;
12781|  1.58k|          input_position++;
12782|  1.58k|        } else {
12783|    376|          ada_log("FILE_SLASH otherwise");
12784|       |          // If base is non-null and base’s scheme is "file", then:
12785|       |          // Note: it is unsafe to do base_url->scheme unless you know that
12786|       |          // base_url_has_value() is true.
12787|    376|          if (base_url != nullptr &&
  ------------------
  |  Branch (12787:15): [True: 264, False: 112]
  ------------------
12788|    376|              base_url->type == ada::scheme::type::FILE) {
  ------------------
  |  Branch (12788:15): [True: 261, False: 3]
  ------------------
12789|       |            // Set url’s host to base’s host.
12790|    261|            if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12790:27): [Folded - Ignored]
  ------------------
12791|    261|              url.host = base_url->host;
12792|    261|            } else {
12793|       |              // TODO: Optimization opportunity.
12794|    261|              url.set_host(base_url->get_host());
12795|    261|            }
12796|       |            // If the code point substring from pointer to the end of input does
12797|       |            // not start with a Windows drive letter and base’s path[0] is a
12798|       |            // normalized Windows drive letter, then append base’s path[0] to
12799|       |            // url’s path.
12800|    261|            if (!base_url->get_pathname().empty()) {
  ------------------
  |  Branch (12800:17): [True: 261, False: 0]
  ------------------
12801|    261|              if (!checkers::is_windows_drive_letter(
  ------------------
  |  Branch (12801:19): [True: 256, False: 5]
  ------------------
12802|    261|                      helpers::substring(url_data, input_position))) {
12803|    256|                std::string_view first_base_url_path =
12804|    256|                    base_url->get_pathname().substr(1);
12805|    256|                size_t loc = first_base_url_path.find('/');
12806|    256|                if (loc != std::string_view::npos) {
  ------------------
  |  Branch (12806:21): [True: 12, False: 244]
  ------------------
12807|     12|                  helpers::resize(first_base_url_path, loc);
12808|     12|                }
12809|    256|                if (checkers::is_normalized_windows_drive_letter(
  ------------------
  |  Branch (12809:21): [True: 3, False: 253]
  ------------------
12810|    256|                        first_base_url_path)) {
12811|      3|                  if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12811:33): [Folded - Ignored]
  ------------------
12812|      3|                    url.path += '/';
12813|      3|                    url.path += first_base_url_path;
12814|      3|                  } else {
12815|      3|                    url.append_base_pathname(
12816|      3|                        helpers::concat("/", first_base_url_path));
12817|      3|                  }
12818|      3|                }
12819|    256|              }
12820|    261|            }
12821|    261|          }
12822|       |
12823|       |          // Set state to path state, and decrease pointer by 1.
12824|    376|          state = ada::state::PATH;
12825|    376|        }
12826|       |
12827|  1.96k|        break;
12828|  11.1k|      }
12829|  1.58k|      case ada::state::FILE_HOST: {
  ------------------
  |  Branch (12829:7): [True: 1.58k, False: 166k]
  ------------------
12830|  1.58k|        std::string_view view = helpers::substring(url_data, input_position);
12831|  1.58k|        ada_log("FILE_HOST ", helpers::substring(url_data, input_position));
12832|       |
12833|  1.58k|        size_t location = view.find_first_of("/\\?");
12834|  1.58k|        std::string_view file_host_buffer(
12835|  1.58k|            view.data(),
12836|  1.58k|            (location != std::string_view::npos) ? location : view.size());
  ------------------
  |  Branch (12836:13): [True: 60, False: 1.52k]
  ------------------
12837|       |
12838|  1.58k|        if (checkers::is_windows_drive_letter(file_host_buffer)) {
  ------------------
  |  Branch (12838:13): [True: 22, False: 1.56k]
  ------------------
12839|     22|          state = ada::state::PATH;
12840|  1.56k|        } else if (file_host_buffer.empty()) {
  ------------------
  |  Branch (12840:20): [True: 43, False: 1.52k]
  ------------------
12841|       |          // Set url’s host to the empty string.
12842|     43|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12842:25): [Folded - Ignored]
  ------------------
12843|     43|            url.host = "";
12844|     43|          } else {
12845|     43|            url.update_base_hostname("");
12846|     43|          }
12847|       |          // Set state to path start state.
12848|     43|          state = ada::state::PATH_START;
12849|  1.52k|        } else {
12850|  1.52k|          size_t consumed_bytes = file_host_buffer.size();
12851|  1.52k|          input_position += consumed_bytes;
12852|       |          // Let host be the result of host parsing buffer with url is not
12853|       |          // special.
12854|  1.52k|          if (!url.parse_host(file_host_buffer)) {
  ------------------
  |  Branch (12854:15): [True: 259, False: 1.26k]
  ------------------
12855|    259|            return url;
12856|    259|          }
12857|       |
12858|  1.26k|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12858:25): [Folded - Ignored]
  ------------------
12859|       |            // If host is "localhost", then set host to the empty string.
12860|  1.26k|            if (url.host.has_value() && url.host.value() == "localhost") {
12861|  1.26k|              url.host = "";
12862|  1.26k|            }
12863|  1.26k|          } else {
12864|  1.26k|            if (url.get_hostname() == "localhost") {
  ------------------
  |  Branch (12864:17): [True: 10, False: 1.25k]
  ------------------
12865|     10|              url.update_base_hostname("");
12866|     10|            }
12867|  1.26k|          }
12868|       |
12869|       |          // Set buffer to the empty string and state to path start state.
12870|  1.26k|          state = ada::state::PATH_START;
12871|  1.26k|        }
12872|       |
12873|  1.33k|        break;
12874|  1.58k|      }
12875|  4.69k|      case ada::state::FILE: {
  ------------------
  |  Branch (12875:7): [True: 4.69k, False: 163k]
  ------------------
12876|  4.69k|        ada_log("FILE ", helpers::substring(url_data, input_position));
12877|  4.69k|        std::string_view file_view =
12878|  4.69k|            helpers::substring(url_data, input_position);
12879|       |
12880|  4.69k|        url.set_protocol_as_file();
12881|  4.69k|        if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12881:23): [Folded - Ignored]
  ------------------
12882|       |          // Set url’s host to the empty string.
12883|  4.69k|          url.host = "";
12884|  4.69k|        } else {
12885|  4.69k|          url.update_base_hostname("");
12886|  4.69k|        }
12887|       |        // If c is U+002F (/) or U+005C (\), then:
12888|  4.69k|        if (input_position != input_size &&
  ------------------
  |  Branch (12888:13): [True: 2.92k, False: 1.76k]
  ------------------
12889|  4.69k|            (url_data[input_position] == '/' ||
  ------------------
  |  Branch (12889:14): [True: 1.94k, False: 981]
  ------------------
12890|  2.92k|             url_data[input_position] == '\\')) {
  ------------------
  |  Branch (12890:14): [True: 18, False: 963]
  ------------------
12891|  1.96k|          ada_log("FILE c is U+002F or U+005C");
12892|       |          // Set state to file slash state.
12893|  1.96k|          state = ada::state::FILE_SLASH;
12894|  1.96k|        }
12895|       |        // Otherwise, if base is non-null and base’s scheme is "file":
12896|  2.72k|        else if (base_url != nullptr &&
  ------------------
  |  Branch (12896:18): [True: 445, False: 2.28k]
  ------------------
12897|  2.72k|                 base_url->type == ada::scheme::type::FILE) {
  ------------------
  |  Branch (12897:18): [True: 380, False: 65]
  ------------------
12898|       |          // Set url’s host to base’s host, url’s path to a clone of base’s
12899|       |          // path, and url’s query to base’s query.
12900|    380|          ada_log("FILE base non-null");
12901|    380|          if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12901:25): [Folded - Ignored]
  ------------------
12902|    380|            url.host = base_url->host;
12903|    380|            url.path = base_url->path;
12904|    380|            url.query = base_url->query;
12905|    380|          } else {
12906|       |            // TODO: Get rid of set_hostname and replace it with
12907|       |            // update_base_hostname
12908|    380|            url.set_hostname(base_url->get_hostname());
12909|    380|            url.update_base_pathname(base_url->get_pathname());
12910|    380|            url.update_base_search(base_url->get_search());
12911|    380|          }
12912|    380|          url.has_opaque_path = base_url->has_opaque_path;
12913|       |
12914|       |          // If c is U+003F (?), then set url’s query to the empty string and
12915|       |          // state to query state.
12916|    380|          if (input_position != input_size && url_data[input_position] == '?') {
  ------------------
  |  Branch (12916:15): [True: 107, False: 273]
  |  Branch (12916:47): [True: 2, False: 105]
  ------------------
12917|      2|            state = ada::state::QUERY;
12918|      2|          }
12919|       |          // Otherwise, if c is not the EOF code point:
12920|    378|          else if (input_position != input_size) {
  ------------------
  |  Branch (12920:20): [True: 105, False: 273]
  ------------------
12921|       |            // Set url’s query to null.
12922|    105|            url.clear_search();
12923|       |            // If the code point substring from pointer to the end of input does
12924|       |            // not start with a Windows drive letter, then shorten url’s path.
12925|    105|            if (!checkers::is_windows_drive_letter(file_view)) {
  ------------------
  |  Branch (12925:17): [True: 93, False: 12]
  ------------------
12926|     93|              if constexpr (result_type_is_ada_url) {
  ------------------
  |  Branch (12926:29): [Folded - Ignored]
  ------------------
12927|     93|                helpers::shorten_path(url.path, url.type);
12928|     93|              } else {
12929|     93|                std::string_view path = url.get_pathname();
12930|     93|                if (helpers::shorten_path(path, url.type)) {
  ------------------
  |  Branch (12930:21): [True: 85, False: 8]
  ------------------
12931|     85|                  url.update_base_pathname(std::string(path));
12932|     85|                }
12933|     93|              }
12934|     93|            }
12935|       |            // Otherwise:
12936|     12|            else {
12937|       |              // Set url’s path to an empty list.
12938|     12|              url.clear_pathname();
12939|     12|              url.has_opaque_path = true;
12940|     12|            }
12941|       |
12942|       |            // Set state to path state and decrease pointer by 1.
12943|    105|            state = ada::state::PATH;
12944|    105|            break;
12945|    105|          }
12946|    380|        }
12947|       |        // Otherwise, set state to path state, and decrease pointer by 1.
12948|  2.34k|        else {
12949|  2.34k|          ada_log("FILE go to path");
12950|  2.34k|          state = ada::state::PATH;
12951|  2.34k|          break;
12952|  2.34k|        }
12953|       |
12954|  2.24k|        input_position++;
12955|  2.24k|        break;
12956|  4.69k|      }
12957|      0|      default:
  ------------------
  |  Branch (12957:7): [True: 0, False: 168k]
  ------------------
12958|      0|        ada::unreachable();
12959|   168k|    }
12960|   168k|  }
12961|  11.1k|  if (fragment.has_value()) {
  ------------------
  |  Branch (12961:7): [True: 408, False: 10.7k]
  ------------------
12962|    408|    url.update_unencoded_base_hash(*fragment);
12963|    408|  }
12964|  11.1k|  return url;
12965|  45.4k|}
_ZN3ada14url_aggregator12set_protocolENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13299|  8.27k|bool url_aggregator::set_protocol(const std::string_view input) {
13300|  8.27k|  ada_log("url_aggregator::set_protocol ", input);
13301|  8.27k|  ADA_ASSERT_TRUE(validate());
13302|  8.27k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13303|  8.27k|  std::string view(input);
13304|  8.27k|  helpers::remove_ascii_tab_or_newline(view);
13305|  8.27k|  if (view.empty()) {
  ------------------
  |  Branch (13305:7): [True: 6.74k, False: 1.52k]
  ------------------
13306|  6.74k|    return true;
13307|  6.74k|  }
13308|       |
13309|       |  // Schemes should start with alpha values.
13310|  1.52k|  if (!checkers::is_alpha(view[0])) {
  ------------------
  |  Branch (13310:7): [True: 1.08k, False: 437]
  ------------------
13311|  1.08k|    return false;
13312|  1.08k|  }
13313|       |
13314|    437|  view.append(":");
13315|       |
13316|    437|  std::string::iterator pointer =
13317|    437|      std::find_if_not(view.begin(), view.end(), unicode::is_alnum_plus);
13318|       |
13319|    437|  if (pointer != view.end() && *pointer == ':') {
  ------------------
  |  Branch (13319:7): [True: 437, False: 0]
  |  Branch (13319:7): [True: 353, False: 84]
  |  Branch (13319:32): [True: 353, False: 84]
  ------------------
13320|    353|    return parse_scheme_with_colon<true>(
13321|    353|        std::string_view(view.data(), pointer - view.begin() + 1));
13322|    353|  }
13323|     84|  return false;
13324|    437|}
_ZN3ada14url_aggregator12set_usernameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13326|  8.27k|bool url_aggregator::set_username(const std::string_view input) {
13327|  8.27k|  ada_log("url_aggregator::set_username '", input, "' ");
13328|  8.27k|  ADA_ASSERT_TRUE(validate());
13329|  8.27k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13330|  8.27k|  if (cannot_have_credentials_or_port()) {
  ------------------
  |  Branch (13330:7): [True: 4.04k, False: 4.22k]
  ------------------
13331|  4.04k|    return false;
13332|  4.04k|  }
13333|  4.22k|  size_t idx = ada::unicode::percent_encode_index(
13334|  4.22k|      input, character_sets::USERINFO_PERCENT_ENCODE);
13335|  4.22k|  if (idx == input.size()) {
  ------------------
  |  Branch (13335:7): [True: 3.66k, False: 558]
  ------------------
13336|  3.66k|    update_base_username(input);
13337|  3.66k|  } else {
13338|       |    // We only create a temporary string if we have to!
13339|    558|    update_base_username(ada::unicode::percent_encode(
13340|    558|        input, character_sets::USERINFO_PERCENT_ENCODE, idx));
13341|    558|  }
13342|  4.22k|  ADA_ASSERT_TRUE(validate());
13343|  4.22k|  return true;
13344|  8.27k|}
_ZN3ada14url_aggregator12set_passwordENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13346|  8.27k|bool url_aggregator::set_password(const std::string_view input) {
13347|  8.27k|  ada_log("url_aggregator::set_password '", input, "'");
13348|  8.27k|  ADA_ASSERT_TRUE(validate());
13349|  8.27k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13350|  8.27k|  if (cannot_have_credentials_or_port()) {
  ------------------
  |  Branch (13350:7): [True: 4.04k, False: 4.22k]
  ------------------
13351|  4.04k|    return false;
13352|  4.04k|  }
13353|  4.22k|  size_t idx = ada::unicode::percent_encode_index(
13354|  4.22k|      input, character_sets::USERINFO_PERCENT_ENCODE);
13355|  4.22k|  if (idx == input.size()) {
  ------------------
  |  Branch (13355:7): [True: 3.66k, False: 558]
  ------------------
13356|  3.66k|    update_base_password(input);
13357|  3.66k|  } else {
13358|       |    // We only create a temporary string if we have to!
13359|    558|    update_base_password(ada::unicode::percent_encode(
13360|    558|        input, character_sets::USERINFO_PERCENT_ENCODE, idx));
13361|    558|  }
13362|  4.22k|  ADA_ASSERT_TRUE(validate());
13363|  4.22k|  return true;
13364|  8.27k|}
_ZN3ada14url_aggregator8set_portENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13366|  8.44k|bool url_aggregator::set_port(const std::string_view input) {
13367|  8.44k|  ada_log("url_aggregator::set_port ", input);
13368|  8.44k|  ADA_ASSERT_TRUE(validate());
13369|  8.44k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13370|  8.44k|  if (cannot_have_credentials_or_port()) {
  ------------------
  |  Branch (13370:7): [True: 4.00k, False: 4.44k]
  ------------------
13371|  4.00k|    return false;
13372|  4.00k|  }
13373|  4.44k|  std::string trimmed(input);
13374|  4.44k|  helpers::remove_ascii_tab_or_newline(trimmed);
13375|  4.44k|  if (trimmed.empty()) {
  ------------------
  |  Branch (13375:7): [True: 3.28k, False: 1.16k]
  ------------------
13376|  3.28k|    clear_port();
13377|  3.28k|    return true;
13378|  3.28k|  }
13379|       |  // Input should not start with control characters.
13380|  1.16k|  if (ada::unicode::is_c0_control_or_space(trimmed.front())) {
  ------------------
  |  Branch (13380:7): [True: 63, False: 1.09k]
  ------------------
13381|     63|    return false;
13382|     63|  }
13383|       |  // Input should contain at least one ascii digit.
13384|  1.09k|  if (input.find_first_of("0123456789") == std::string_view::npos) {
  ------------------
  |  Branch (13384:7): [True: 523, False: 575]
  ------------------
13385|    523|    return false;
13386|    523|  }
13387|       |
13388|       |  // Revert changes if parse_port fails.
13389|    575|  uint32_t previous_port = components.port;
13390|    575|  parse_port(trimmed);
13391|    575|  if (is_valid) {
  ------------------
  |  Branch (13391:7): [True: 425, False: 150]
  ------------------
13392|    425|    return true;
13393|    425|  }
13394|    150|  update_base_port(previous_port);
13395|    150|  is_valid = true;
13396|    150|  ADA_ASSERT_TRUE(validate());
13397|    150|  return false;
13398|    575|}
_ZN3ada14url_aggregator12set_pathnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13400|  8.27k|bool url_aggregator::set_pathname(const std::string_view input) {
13401|  8.27k|  ada_log("url_aggregator::set_pathname ", input);
13402|  8.27k|  ADA_ASSERT_TRUE(validate());
13403|  8.27k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13404|  8.27k|  if (has_opaque_path) {
  ------------------
  |  Branch (13404:7): [True: 1.06k, False: 7.20k]
  ------------------
13405|  1.06k|    return false;
13406|  1.06k|  }
13407|  7.20k|  clear_pathname();
13408|  7.20k|  parse_path(input);
13409|  7.20k|  if (checkers::begins_with(input, "//") && !has_authority() &&
  ------------------
  |  Branch (13409:7): [True: 33, False: 7.17k]
  |  Branch (13409:45): [True: 19, False: 14]
  ------------------
13410|  7.20k|      !has_dash_dot()) {
  ------------------
  |  Branch (13410:7): [True: 3, False: 16]
  ------------------
13411|      3|    buffer.insert(components.pathname_start, "/.");
13412|      3|    components.pathname_start += 2;
13413|      3|  }
13414|  7.20k|  ADA_ASSERT_TRUE(validate());
13415|  7.20k|  return true;
13416|  8.27k|}
_ZN3ada14url_aggregator10set_searchENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13459|  8.27k|void url_aggregator::set_search(const std::string_view input) {
13460|  8.27k|  ada_log("url_aggregator::set_search ", input);
13461|  8.27k|  ADA_ASSERT_TRUE(validate());
13462|  8.27k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13463|  8.27k|  if (input.empty()) {
  ------------------
  |  Branch (13463:7): [True: 6.67k, False: 1.60k]
  ------------------
13464|  6.67k|    clear_search();
13465|  6.67k|    helpers::strip_trailing_spaces_from_opaque_path(*this);
13466|  6.67k|    return;
13467|  6.67k|  }
13468|       |
13469|  1.60k|  std::string new_value;
13470|  1.60k|  new_value = input[0] == '?' ? input.substr(1) : input;
  ------------------
  |  Branch (13470:15): [True: 3, False: 1.59k]
  ------------------
13471|  1.60k|  helpers::remove_ascii_tab_or_newline(new_value);
13472|       |
13473|  1.60k|  auto query_percent_encode_set =
13474|  1.60k|      is_special() ? ada::character_sets::SPECIAL_QUERY_PERCENT_ENCODE
  ------------------
  |  Branch (13474:7): [True: 1.05k, False: 551]
  ------------------
13475|  1.60k|                   : ada::character_sets::QUERY_PERCENT_ENCODE;
13476|       |
13477|  1.60k|  update_base_search(new_value, query_percent_encode_set);
13478|  1.60k|  ADA_ASSERT_TRUE(validate());
13479|  1.60k|}
_ZN3ada14url_aggregator8set_hashENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13481|  8.27k|void url_aggregator::set_hash(const std::string_view input) {
13482|  8.27k|  ada_log("url_aggregator::set_hash ", input);
13483|  8.27k|  ADA_ASSERT_TRUE(validate());
13484|  8.27k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13485|  8.27k|  if (input.empty()) {
  ------------------
  |  Branch (13485:7): [True: 6.67k, False: 1.60k]
  ------------------
13486|  6.67k|    if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (13486:9): [True: 126, False: 6.54k]
  ------------------
13487|    126|      buffer.resize(components.hash_start);
13488|    126|      components.hash_start = url_components::omitted;
13489|    126|    }
13490|  6.67k|    helpers::strip_trailing_spaces_from_opaque_path(*this);
13491|  6.67k|    return;
13492|  6.67k|  }
13493|       |
13494|  1.60k|  std::string new_value;
13495|  1.60k|  new_value = input[0] == '#' ? input.substr(1) : input;
  ------------------
  |  Branch (13495:15): [True: 4, False: 1.59k]
  ------------------
13496|  1.60k|  helpers::remove_ascii_tab_or_newline(new_value);
13497|  1.60k|  update_unencoded_base_hash(new_value);
13498|  1.60k|  ADA_ASSERT_TRUE(validate());
13499|  1.60k|}
_ZN3ada14url_aggregator8set_hostENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13697|  8.53k|bool url_aggregator::set_host(const std::string_view input) {
13698|  8.53k|  ada_log("url_aggregator::set_host '", input, "'");
13699|  8.53k|  ADA_ASSERT_TRUE(validate());
13700|  8.53k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13701|  8.53k|  return set_host_or_hostname<false>(input);
13702|  8.53k|}
_ZN3ada14url_aggregator12set_hostnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13704|  9.41k|bool url_aggregator::set_hostname(const std::string_view input) {
13705|  9.41k|  ada_log("url_aggregator::set_hostname '", input, "'");
13706|  9.41k|  ADA_ASSERT_TRUE(validate());
13707|  9.41k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13708|  9.41k|  return set_host_or_hostname<true>(input);
13709|  9.41k|}
_ZNK3ada14url_aggregator10get_originEv:
13711|  8.27k|[[nodiscard]] std::string url_aggregator::get_origin() const noexcept {
13712|  8.27k|  ada_log("url_aggregator::get_origin");
13713|  8.27k|  if (is_special()) {
  ------------------
  |  Branch (13713:7): [True: 5.52k, False: 2.74k]
  ------------------
13714|       |    // Return a new opaque origin.
13715|  5.52k|    if (type == scheme::FILE) {
  ------------------
  |  Branch (13715:9): [True: 1.48k, False: 4.04k]
  ------------------
13716|  1.48k|      return "null";
13717|  1.48k|    }
13718|       |
13719|  4.04k|    return helpers::concat(get_protocol(), "//", get_host());
13720|  5.52k|  }
13721|       |
13722|  2.74k|  if (get_protocol() == "blob:") {
  ------------------
  |  Branch (13722:7): [True: 395, False: 2.35k]
  ------------------
13723|    395|    std::string_view path = get_pathname();
13724|    395|    if (!path.empty()) {
  ------------------
  |  Branch (13724:9): [True: 393, False: 2]
  ------------------
13725|    393|      auto out = ada::parse<ada::url_aggregator>(path);
13726|    393|      if (out && (out->type == scheme::HTTP || out->type == scheme::HTTPS)) {
  ------------------
  |  Branch (13726:11): [True: 126, False: 267]
  |  Branch (13726:19): [True: 9, False: 117]
  |  Branch (13726:48): [True: 1, False: 116]
  ------------------
13727|       |        // If pathURL’s scheme is not "http" and not "https", then return a
13728|       |        // new opaque origin.
13729|     10|        return helpers::concat(out->get_protocol(), "//", out->get_host());
13730|     10|      }
13731|    393|    }
13732|    395|  }
13733|       |
13734|       |  // Return a new opaque origin.
13735|  2.73k|  return "null";
13736|  2.74k|}
_ZNK3ada14url_aggregator12get_usernameEv:
13738|  8.27k|[[nodiscard]] std::string_view url_aggregator::get_username() const noexcept {
13739|  8.27k|  ada_log("url_aggregator::get_username");
13740|  8.27k|  if (has_non_empty_username()) {
  ------------------
  |  Branch (13740:7): [True: 902, False: 7.37k]
  ------------------
13741|    902|    return helpers::substring(buffer, components.protocol_end + 2,
13742|    902|                              components.username_end);
13743|    902|  }
13744|  7.37k|  return "";
13745|  8.27k|}
_ZNK3ada14url_aggregator12get_passwordEv:
13747|  8.27k|[[nodiscard]] std::string_view url_aggregator::get_password() const noexcept {
13748|  8.27k|  ada_log("url_aggregator::get_password");
13749|  8.27k|  if (has_non_empty_password()) {
  ------------------
  |  Branch (13749:7): [True: 902, False: 7.37k]
  ------------------
13750|    902|    return helpers::substring(buffer, components.username_end + 1,
13751|    902|                              components.host_start);
13752|    902|  }
13753|  7.37k|  return "";
13754|  8.27k|}
_ZNK3ada14url_aggregator8get_portEv:
13756|  8.27k|[[nodiscard]] std::string_view url_aggregator::get_port() const noexcept {
13757|  8.27k|  ada_log("url_aggregator::get_port");
13758|  8.27k|  if (components.port == url_components::omitted) {
  ------------------
  |  Branch (13758:7): [True: 8.03k, False: 241]
  ------------------
13759|  8.03k|    return "";
13760|  8.03k|  }
13761|    241|  return helpers::substring(buffer, components.host_end + 1,
13762|    241|                            components.pathname_start);
13763|  8.27k|}
_ZNK3ada14url_aggregator8get_hashEv:
13765|  8.27k|[[nodiscard]] std::string_view url_aggregator::get_hash() const noexcept {
13766|  8.27k|  ada_log("url_aggregator::get_hash");
13767|       |  // If this’s URL’s fragment is either null or the empty string, then return
13768|       |  // the empty string. Return U+0023 (#), followed by this’s URL’s fragment.
13769|  8.27k|  if (components.hash_start == url_components::omitted) {
  ------------------
  |  Branch (13769:7): [True: 6.67k, False: 1.60k]
  ------------------
13770|  6.67k|    return "";
13771|  6.67k|  }
13772|  1.60k|  if (buffer.size() - components.hash_start <= 1) {
  ------------------
  |  Branch (13772:7): [True: 78, False: 1.52k]
  ------------------
13773|     78|    return "";
13774|     78|  }
13775|  1.52k|  return helpers::substring(buffer, components.hash_start);
13776|  1.60k|}
_ZNK3ada14url_aggregator8get_hostEv:
13778|  12.5k|[[nodiscard]] std::string_view url_aggregator::get_host() const noexcept {
13779|  12.5k|  ada_log("url_aggregator::get_host");
13780|       |  // Technically, we should check if there is a hostname, but
13781|       |  // the code below works even if there isn't.
13782|       |  // if(!has_hostname()) { return ""; }
13783|  12.5k|  size_t start = components.host_start;
13784|  12.5k|  if (components.host_end > components.host_start &&
  ------------------
  |  Branch (13784:7): [True: 8.68k, False: 3.90k]
  ------------------
13785|  12.5k|      buffer[components.host_start] == '@') {
  ------------------
  |  Branch (13785:7): [True: 1.70k, False: 6.98k]
  ------------------
13786|  1.70k|    start++;
13787|  1.70k|  }
13788|       |  // if we have an empty host, then the space between components.host_end and
13789|       |  // components.pathname_start may be occupied by /.
13790|  12.5k|  if (start == components.host_end) {
  ------------------
  |  Branch (13790:7): [True: 4.04k, False: 8.53k]
  ------------------
13791|  4.04k|    return std::string_view();
13792|  4.04k|  }
13793|  8.53k|  return helpers::substring(buffer, start, components.pathname_start);
13794|  12.5k|}
_ZNK3ada14url_aggregator12get_hostnameEv:
13796|  45.1k|[[nodiscard]] std::string_view url_aggregator::get_hostname() const noexcept {
13797|  45.1k|  ada_log("url_aggregator::get_hostname");
13798|       |  // Technically, we should check if there is a hostname, but
13799|       |  // the code below works even if there isn't.
13800|       |  // if(!has_hostname()) { return ""; }
13801|  45.1k|  size_t start = components.host_start;
13802|       |  // So host_start is not where the host begins.
13803|  45.1k|  if (components.host_end > components.host_start &&
  ------------------
  |  Branch (13803:7): [True: 27.7k, False: 17.4k]
  ------------------
13804|  45.1k|      buffer[components.host_start] == '@') {
  ------------------
  |  Branch (13804:7): [True: 4.54k, False: 23.1k]
  ------------------
13805|  4.54k|    start++;
13806|  4.54k|  }
13807|  45.1k|  return helpers::substring(buffer, start, components.host_end);
13808|  45.1k|}
_ZNK3ada14url_aggregator12get_pathnameEv:
13810|  15.8k|[[nodiscard]] std::string_view url_aggregator::get_pathname() const noexcept {
13811|  15.8k|  ada_log("url_aggregator::get_pathname pathname_start = ",
13812|  15.8k|          components.pathname_start, " buffer.size() = ", buffer.size(),
13813|  15.8k|          " components.search_start = ", components.search_start,
13814|  15.8k|          " components.hash_start = ", components.hash_start);
13815|  15.8k|  uint32_t ending_index = uint32_t(buffer.size());
13816|  15.8k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (13816:7): [True: 1.80k, False: 14.0k]
  ------------------
13817|  1.80k|    ending_index = components.search_start;
13818|  14.0k|  } else if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (13818:14): [True: 152, False: 13.9k]
  ------------------
13819|    152|    ending_index = components.hash_start;
13820|    152|  }
13821|  15.8k|  return helpers::substring(buffer, components.pathname_start, ending_index);
13822|  15.8k|}
_ZNK3ada14url_aggregator10get_searchEv:
13824|  9.41k|[[nodiscard]] std::string_view url_aggregator::get_search() const noexcept {
13825|  9.41k|  ada_log("url_aggregator::get_search");
13826|       |  // If this’s URL’s query is either null or the empty string, then return the
13827|       |  // empty string. Return U+003F (?), followed by this’s URL’s query.
13828|  9.41k|  if (components.search_start == url_components::omitted) {
  ------------------
  |  Branch (13828:7): [True: 7.73k, False: 1.67k]
  ------------------
13829|  7.73k|    return "";
13830|  7.73k|  }
13831|  1.67k|  uint32_t ending_index = uint32_t(buffer.size());
13832|  1.67k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (13832:7): [True: 1.62k, False: 51]
  ------------------
13833|  1.62k|    ending_index = components.hash_start;
13834|  1.62k|  }
13835|  1.67k|  if (ending_index - components.search_start <= 1) {
  ------------------
  |  Branch (13835:7): [True: 111, False: 1.56k]
  ------------------
13836|    111|    return "";
13837|    111|  }
13838|  1.56k|  return helpers::substring(buffer, components.search_start, ending_index);
13839|  1.67k|}
_ZNK3ada14url_aggregator12get_protocolEv:
13841|  15.8k|[[nodiscard]] std::string_view url_aggregator::get_protocol() const noexcept {
13842|  15.8k|  ada_log("url_aggregator::get_protocol");
13843|  15.8k|  return helpers::substring(buffer, 0, components.protocol_end);
13844|  15.8k|}
_ZN3ada14url_aggregator10parse_ipv4ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13946|  4.02k|bool url_aggregator::parse_ipv4(std::string_view input) {
13947|  4.02k|  ada_log("parse_ipv4 ", input, "[", input.size(),
13948|  4.02k|          " bytes], overlaps with buffer: ",
13949|  4.02k|          helpers::overlaps(input, buffer) ? "yes" : "no");
13950|  4.02k|  ADA_ASSERT_TRUE(validate());
13951|  4.02k|  const bool trailing_dot = (input.back() == '.');
13952|  4.02k|  if (trailing_dot) {
  ------------------
  |  Branch (13952:7): [True: 65, False: 3.96k]
  ------------------
13953|     65|    input.remove_suffix(1);
13954|     65|  }
13955|  4.02k|  size_t digit_count{0};
13956|  4.02k|  int pure_decimal_count = 0;  // entries that are decimal
13957|  4.02k|  uint64_t ipv4{0};
13958|       |  // we could unroll for better performance?
13959|  5.29k|  for (; (digit_count < 4) && !(input.empty()); digit_count++) {
  ------------------
  |  Branch (13959:10): [True: 5.26k, False: 32]
  |  Branch (13959:31): [True: 5.26k, False: 0]
  ------------------
13960|  5.26k|    uint32_t
13961|  5.26k|        segment_result{};  // If any number exceeds 32 bits, we have an error.
13962|  5.26k|    bool is_hex = checkers::has_hex_prefix(input);
13963|  5.26k|    if (is_hex && ((input.length() == 2) ||
  ------------------
  |  Branch (13963:9): [True: 1.20k, False: 4.05k]
  |  Branch (13963:20): [True: 83, False: 1.11k]
  ------------------
13964|  1.20k|                   ((input.length() > 2) && (input[2] == '.')))) {
  ------------------
  |  Branch (13964:21): [True: 1.11k, False: 0]
  |  Branch (13964:45): [True: 41, False: 1.07k]
  ------------------
13965|       |      // special case
13966|    124|      segment_result = 0;
13967|    124|      input.remove_prefix(2);
13968|  5.13k|    } else {
13969|  5.13k|      std::from_chars_result r;
13970|  5.13k|      if (is_hex) {
  ------------------
  |  Branch (13970:11): [True: 1.07k, False: 4.05k]
  ------------------
13971|  1.07k|        r = std::from_chars(input.data() + 2, input.data() + input.size(),
13972|  1.07k|                            segment_result, 16);
13973|  4.05k|      } else if ((input.length() >= 2) && input[0] == '0' &&
  ------------------
  |  Branch (13973:18): [True: 2.13k, False: 1.92k]
  |  Branch (13973:43): [True: 1.10k, False: 1.02k]
  ------------------
13974|  4.05k|                 checkers::is_digit(input[1])) {
  ------------------
  |  Branch (13974:18): [True: 504, False: 601]
  ------------------
13975|    504|        r = std::from_chars(input.data() + 1, input.data() + input.size(),
13976|    504|                            segment_result, 8);
13977|  3.55k|      } else {
13978|  3.55k|        pure_decimal_count++;
13979|  3.55k|        r = std::from_chars(input.data(), input.data() + input.size(),
13980|  3.55k|                            segment_result, 10);
13981|  3.55k|      }
13982|  5.13k|      if (r.ec != std::errc()) {
  ------------------
  |  Branch (13982:11): [True: 677, False: 4.45k]
  ------------------
13983|    677|        return is_valid = false;
13984|    677|      }
13985|  4.45k|      input.remove_prefix(r.ptr - input.data());
13986|  4.45k|    }
13987|  4.58k|    if (input.empty()) {
  ------------------
  |  Branch (13987:9): [True: 3.10k, False: 1.48k]
  ------------------
13988|       |      // We have the last value.
13989|       |      // At this stage, ipv4 contains digit_count*8 bits.
13990|       |      // So we have 32-digit_count*8 bits left.
13991|  3.10k|      if (segment_result > (uint64_t(1) << (32 - digit_count * 8))) {
  ------------------
  |  Branch (13991:11): [True: 18, False: 3.08k]
  ------------------
13992|     18|        return is_valid = false;
13993|     18|      }
13994|  3.08k|      ipv4 <<= (32 - digit_count * 8);
13995|  3.08k|      ipv4 |= segment_result;
13996|  3.08k|      goto final;
13997|  3.10k|    } else {
13998|       |      // There is more, so that the value must no be larger than 255
13999|       |      // and we must have a '.'.
14000|  1.48k|      if ((segment_result > 255) || (input[0] != '.')) {
  ------------------
  |  Branch (14000:11): [True: 115, False: 1.36k]
  |  Branch (14000:37): [True: 101, False: 1.26k]
  ------------------
14001|    216|        return is_valid = false;
14002|    216|      }
14003|  1.26k|      ipv4 <<= 8;
14004|  1.26k|      ipv4 |= segment_result;
14005|  1.26k|      input.remove_prefix(1);  // remove '.'
14006|  1.26k|    }
14007|  4.58k|  }
14008|     32|  if ((digit_count != 4) || (!input.empty())) {
  ------------------
  |  Branch (14008:7): [True: 0, False: 32]
  |  Branch (14008:29): [True: 32, False: 0]
  ------------------
14009|     32|    return is_valid = false;
14010|     32|  }
14011|  3.08k|final:
14012|  3.08k|  ada_log("url_aggregator::parse_ipv4 completed ", get_href(),
14013|  3.08k|          " host: ", get_host());
14014|       |
14015|       |  // We could also check r.ptr to see where the parsing ended.
14016|  3.08k|  if (pure_decimal_count == 4 && !trailing_dot) {
  ------------------
  |  Branch (14016:7): [True: 239, False: 2.84k]
  |  Branch (14016:34): [True: 225, False: 14]
  ------------------
14017|       |    // The original input was already all decimal and we validated it. So we
14018|       |    // don't need to do anything.
14019|  2.85k|  } else {
14020|       |    // Optimization opportunity: Get rid of unnecessary string return in ipv4
14021|       |    // serializer.
14022|       |    // TODO: This is likely a bug because it goes back update_base_hostname, not
14023|       |    // what we want to do.
14024|  2.85k|    update_base_hostname(
14025|  2.85k|        ada::serializers::ipv4(ipv4));  // We have to reserialize the address.
14026|  2.85k|  }
14027|  3.08k|  ADA_ASSERT_TRUE(validate());
14028|  3.08k|  return true;
14029|     32|}
_ZN3ada14url_aggregator10parse_ipv6ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
14031|    922|bool url_aggregator::parse_ipv6(std::string_view input) {
14032|       |  // TODO: Find a way to merge parse_ipv6 with url.cpp implementation.
14033|    922|  ada_log("parse_ipv6 ", input, "[", input.size(), " bytes]");
14034|    922|  ADA_ASSERT_TRUE(validate());
14035|    922|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
14036|    922|  if (input.empty()) {
  ------------------
  |  Branch (14036:7): [True: 61, False: 861]
  ------------------
14037|     61|    return is_valid = false;
14038|     61|  }
14039|       |  // Let address be a new IPv6 address whose IPv6 pieces are all 0.
14040|    861|  std::array<uint16_t, 8> address{};
14041|       |
14042|       |  // Let pieceIndex be 0.
14043|    861|  int piece_index = 0;
14044|       |
14045|       |  // Let compress be null.
14046|    861|  std::optional<int> compress{};
14047|       |
14048|       |  // Let pointer be a pointer for input.
14049|    861|  std::string_view::iterator pointer = input.begin();
14050|       |
14051|       |  // If c is U+003A (:), then:
14052|    861|  if (input[0] == ':') {
  ------------------
  |  Branch (14052:7): [True: 241, False: 620]
  ------------------
14053|       |    // If remaining does not start with U+003A (:), validation error, return
14054|       |    // failure.
14055|    241|    if (input.size() == 1 || input[1] != ':') {
  ------------------
  |  Branch (14055:9): [True: 6, False: 235]
  |  Branch (14055:30): [True: 10, False: 225]
  ------------------
14056|     16|      ada_log("parse_ipv6 starts with : but the rest does not start with :");
14057|     16|      return is_valid = false;
14058|     16|    }
14059|       |
14060|       |    // Increase pointer by 2.
14061|    225|    pointer += 2;
14062|       |
14063|       |    // Increase pieceIndex by 1 and then set compress to pieceIndex.
14064|    225|    compress = ++piece_index;
14065|    225|  }
14066|       |
14067|       |  // While c is not the EOF code point:
14068|  2.53k|  while (pointer != input.end()) {
  ------------------
  |  Branch (14068:10): [True: 2.06k, False: 476]
  ------------------
14069|       |    // If pieceIndex is 8, validation error, return failure.
14070|  2.06k|    if (piece_index == 8) {
  ------------------
  |  Branch (14070:9): [True: 10, False: 2.05k]
  ------------------
14071|     10|      ada_log("parse_ipv6 piece_index == 8");
14072|     10|      return is_valid = false;
14073|     10|    }
14074|       |
14075|       |    // If c is U+003A (:), then:
14076|  2.05k|    if (*pointer == ':') {
  ------------------
  |  Branch (14076:9): [True: 167, False: 1.88k]
  ------------------
14077|       |      // If compress is non-null, validation error, return failure.
14078|    167|      if (compress.has_value()) {
  ------------------
  |  Branch (14078:11): [True: 7, False: 160]
  ------------------
14079|      7|        ada_log("parse_ipv6 compress is non-null");
14080|      7|        return is_valid = false;
14081|      7|      }
14082|       |
14083|       |      // Increase pointer and pieceIndex by 1, set compress to pieceIndex, and
14084|       |      // then continue.
14085|    160|      pointer++;
14086|    160|      compress = ++piece_index;
14087|    160|      continue;
14088|    167|    }
14089|       |
14090|       |    // Let value and length be 0.
14091|  1.88k|    uint16_t value = 0, length = 0;
14092|       |
14093|       |    // While length is less than 4 and c is an ASCII hex digit,
14094|       |    // set value to value × 0x10 + c interpreted as hexadecimal number, and
14095|       |    // increase pointer and length by 1.
14096|  5.00k|    while (length < 4 && pointer != input.end() &&
  ------------------
  |  Branch (14096:12): [True: 4.69k, False: 312]
  |  Branch (14096:26): [True: 4.44k, False: 255]
  ------------------
14097|  5.00k|           unicode::is_ascii_hex_digit(*pointer)) {
  ------------------
  |  Branch (14097:12): [True: 3.12k, False: 1.31k]
  ------------------
14098|       |      // https://stackoverflow.com/questions/39060852/why-does-the-addition-of-two-shorts-return-an-int
14099|  3.12k|      value = uint16_t(value * 0x10 + unicode::convert_hex_to_binary(*pointer));
14100|  3.12k|      pointer++;
14101|  3.12k|      length++;
14102|  3.12k|    }
14103|       |
14104|       |    // If c is U+002E (.), then:
14105|  1.88k|    if (pointer != input.end() && *pointer == '.') {
  ------------------
  |  Branch (14105:9): [True: 1.54k, False: 339]
  |  Branch (14105:35): [True: 184, False: 1.36k]
  ------------------
14106|       |      // If length is 0, validation error, return failure.
14107|    184|      if (length == 0) {
  ------------------
  |  Branch (14107:11): [True: 6, False: 178]
  ------------------
14108|      6|        ada_log("parse_ipv6 length is 0");
14109|      6|        return is_valid = false;
14110|      6|      }
14111|       |
14112|       |      // Decrease pointer by length.
14113|    178|      pointer -= length;
14114|       |
14115|       |      // If pieceIndex is greater than 6, validation error, return failure.
14116|    178|      if (piece_index > 6) {
  ------------------
  |  Branch (14116:11): [True: 6, False: 172]
  ------------------
14117|      6|        ada_log("parse_ipv6 piece_index > 6");
14118|      6|        return is_valid = false;
14119|      6|      }
14120|       |
14121|       |      // Let numbersSeen be 0.
14122|    172|      int numbers_seen = 0;
14123|       |
14124|       |      // While c is not the EOF code point:
14125|    525|      while (pointer != input.end()) {
  ------------------
  |  Branch (14125:14): [True: 463, False: 62]
  ------------------
14126|       |        // Let ipv4Piece be null.
14127|    463|        std::optional<uint16_t> ipv4_piece{};
14128|       |
14129|       |        // If numbersSeen is greater than 0, then:
14130|    463|        if (numbers_seen > 0) {
  ------------------
  |  Branch (14130:13): [True: 291, False: 172]
  ------------------
14131|       |          // If c is a U+002E (.) and numbersSeen is less than 4, then increase
14132|       |          // pointer by 1.
14133|    291|          if (*pointer == '.' && numbers_seen < 4) {
  ------------------
  |  Branch (14133:15): [True: 261, False: 30]
  |  Branch (14133:34): [True: 255, False: 6]
  ------------------
14134|    255|            pointer++;
14135|    255|          } else {
14136|       |            // Otherwise, validation error, return failure.
14137|     36|            ada_log("parse_ipv6 Otherwise, validation error, return failure");
14138|     36|            return is_valid = false;
14139|     36|          }
14140|    291|        }
14141|       |
14142|       |        // If c is not an ASCII digit, validation error, return failure.
14143|    427|        if (pointer == input.end() || !checkers::is_digit(*pointer)) {
  ------------------
  |  Branch (14143:13): [True: 33, False: 394]
  |  Branch (14143:39): [True: 14, False: 380]
  ------------------
14144|     47|          ada_log(
14145|     47|              "parse_ipv6 If c is not an ASCII digit, validation error, return "
14146|     47|              "failure");
14147|     47|          return is_valid = false;
14148|     47|        }
14149|       |
14150|       |        // While c is an ASCII digit:
14151|    884|        while (pointer != input.end() && checkers::is_digit(*pointer)) {
  ------------------
  |  Branch (14151:16): [True: 822, False: 62]
  |  Branch (14151:42): [True: 531, False: 291]
  ------------------
14152|       |          // Let number be c interpreted as decimal number.
14153|    531|          int number = *pointer - '0';
14154|       |
14155|       |          // If ipv4Piece is null, then set ipv4Piece to number.
14156|    531|          if (!ipv4_piece.has_value()) {
  ------------------
  |  Branch (14156:15): [True: 380, False: 151]
  ------------------
14157|    380|            ipv4_piece = number;
14158|    380|          }
14159|       |          // Otherwise, if ipv4Piece is 0, validation error, return failure.
14160|    151|          else if (ipv4_piece == 0) {
  ------------------
  |  Branch (14160:20): [True: 6, False: 145]
  ------------------
14161|      6|            ada_log("parse_ipv6 if ipv4Piece is 0, validation error");
14162|      6|            return is_valid = false;
14163|      6|          }
14164|       |          // Otherwise, set ipv4Piece to ipv4Piece × 10 + number.
14165|    145|          else {
14166|    145|            ipv4_piece = *ipv4_piece * 10 + number;
14167|    145|          }
14168|       |
14169|       |          // If ipv4Piece is greater than 255, validation error, return failure.
14170|    525|          if (ipv4_piece > 255) {
  ------------------
  |  Branch (14170:15): [True: 21, False: 504]
  ------------------
14171|     21|            ada_log("parse_ipv6 ipv4_piece > 255");
14172|     21|            return is_valid = false;
14173|     21|          }
14174|       |
14175|       |          // Increase pointer by 1.
14176|    504|          pointer++;
14177|    504|        }
14178|       |
14179|       |        // Set address[pieceIndex] to address[pieceIndex] × 0x100 + ipv4Piece.
14180|       |        // https://stackoverflow.com/questions/39060852/why-does-the-addition-of-two-shorts-return-an-int
14181|    353|        address[piece_index] =
14182|    353|            uint16_t(address[piece_index] * 0x100 + *ipv4_piece);
14183|       |
14184|       |        // Increase numbersSeen by 1.
14185|    353|        numbers_seen++;
14186|       |
14187|       |        // If numbersSeen is 2 or 4, then increase pieceIndex by 1.
14188|    353|        if (numbers_seen == 2 || numbers_seen == 4) {
  ------------------
  |  Branch (14188:13): [True: 98, False: 255]
  |  Branch (14188:34): [True: 52, False: 203]
  ------------------
14189|    150|          piece_index++;
14190|    150|        }
14191|    353|      }
14192|       |
14193|       |      // If numbersSeen is not 4, validation error, return failure.
14194|     62|      if (numbers_seen != 4) {
  ------------------
  |  Branch (14194:11): [True: 16, False: 46]
  ------------------
14195|     16|        return is_valid = false;
14196|     16|      }
14197|       |
14198|       |      // Break.
14199|     46|      break;
14200|     62|    }
14201|       |    // Otherwise, if c is U+003A (:):
14202|  1.70k|    else if ((pointer != input.end()) && (*pointer == ':')) {
  ------------------
  |  Branch (14202:14): [True: 1.36k, False: 339]
  |  Branch (14202:42): [True: 1.20k, False: 162]
  ------------------
14203|       |      // Increase pointer by 1.
14204|  1.20k|      pointer++;
14205|       |
14206|       |      // If c is the EOF code point, validation error, return failure.
14207|  1.20k|      if (pointer == input.end()) {
  ------------------
  |  Branch (14207:11): [True: 6, False: 1.19k]
  ------------------
14208|      6|        ada_log(
14209|      6|            "parse_ipv6 If c is the EOF code point, validation error, return "
14210|      6|            "failure");
14211|      6|        return is_valid = false;
14212|      6|      }
14213|  1.20k|    }
14214|       |    // Otherwise, if c is not the EOF code point, validation error, return
14215|       |    // failure.
14216|    501|    else if (pointer != input.end()) {
  ------------------
  |  Branch (14216:14): [True: 162, False: 339]
  ------------------
14217|    162|      ada_log(
14218|    162|          "parse_ipv6 Otherwise, if c is not the EOF code point, validation "
14219|    162|          "error, return failure");
14220|    162|      return is_valid = false;
14221|    162|    }
14222|       |
14223|       |    // Set address[pieceIndex] to value.
14224|  1.53k|    address[piece_index] = value;
14225|       |
14226|       |    // Increase pieceIndex by 1.
14227|  1.53k|    piece_index++;
14228|  1.53k|  }
14229|       |
14230|       |  // If compress is non-null, then:
14231|    522|  if (compress.has_value()) {
  ------------------
  |  Branch (14231:7): [True: 366, False: 156]
  ------------------
14232|       |    // Let swaps be pieceIndex − compress.
14233|    366|    int swaps = piece_index - *compress;
14234|       |
14235|       |    // Set pieceIndex to 7.
14236|    366|    piece_index = 7;
14237|       |
14238|       |    // While pieceIndex is not 0 and swaps is greater than 0,
14239|       |    // swap address[pieceIndex] with address[compress + swaps − 1], and then
14240|       |    // decrease both pieceIndex and swaps by 1.
14241|    921|    while (piece_index != 0 && swaps > 0) {
  ------------------
  |  Branch (14241:12): [True: 906, False: 15]
  |  Branch (14241:32): [True: 555, False: 351]
  ------------------
14242|    555|      std::swap(address[piece_index], address[*compress + swaps - 1]);
14243|    555|      piece_index--;
14244|    555|      swaps--;
14245|    555|    }
14246|    366|  }
14247|       |  // Otherwise, if compress is null and pieceIndex is not 8, validation error,
14248|       |  // return failure.
14249|    156|  else if (piece_index != 8) {
  ------------------
  |  Branch (14249:12): [True: 110, False: 46]
  ------------------
14250|    110|    ada_log(
14251|    110|        "parse_ipv6 if compress is null and pieceIndex is not 8, validation "
14252|    110|        "error, return failure");
14253|    110|    return is_valid = false;
14254|    110|  }
14255|       |  // TODO: Optimization opportunity: Get rid of unnecessary string creation.
14256|       |  // TODO: This is likely a bug because it goes back update_base_hostname, not
14257|       |  // what we want to do.
14258|    412|  update_base_hostname(ada::serializers::ipv6(address));
14259|    412|  ada_log("parse_ipv6 ", get_hostname());
14260|    412|  ADA_ASSERT_TRUE(validate());
14261|    412|  return true;
14262|    522|}
_ZN3ada14url_aggregator17parse_opaque_hostENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
14264|  1.00k|bool url_aggregator::parse_opaque_host(std::string_view input) {
14265|  1.00k|  ada_log("parse_opaque_host ", input, "[", input.size(), " bytes]");
14266|  1.00k|  ADA_ASSERT_TRUE(validate());
14267|  1.00k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
14268|  1.00k|  if (std::any_of(input.begin(), input.end(),
  ------------------
  |  Branch (14268:7): [True: 103, False: 902]
  ------------------
14269|  1.00k|                  ada::unicode::is_forbidden_host_code_point)) {
14270|    103|    return is_valid = false;
14271|    103|  }
14272|       |
14273|       |  // Return the result of running UTF-8 percent-encode on input using the C0
14274|       |  // control percent-encode set.
14275|    902|  size_t idx = ada::unicode::percent_encode_index(
14276|    902|      input, character_sets::C0_CONTROL_PERCENT_ENCODE);
14277|    902|  if (idx == input.size()) {
  ------------------
  |  Branch (14277:7): [True: 458, False: 444]
  ------------------
14278|    458|    update_base_hostname(input);
14279|    458|  } else {
14280|       |    // We only create a temporary string if we need to.
14281|    444|    update_base_hostname(ada::unicode::percent_encode(
14282|    444|        input, character_sets::C0_CONTROL_PERCENT_ENCODE, idx));
14283|    444|  }
14284|    902|  ADA_ASSERT_TRUE(validate());
14285|    902|  return true;
14286|  1.00k|}
_ZN3ada14url_aggregator15delete_dash_dotEv:
14615|     79|void url_aggregator::delete_dash_dot() {
14616|     79|  ada_log("url_aggregator::delete_dash_dot");
14617|     79|  ADA_ASSERT_TRUE(validate());
14618|     79|  ADA_ASSERT_TRUE(has_dash_dot());
14619|     79|  buffer.erase(components.host_end, 2);
14620|     79|  components.pathname_start -= 2;
14621|     79|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (14621:7): [True: 30, False: 49]
  ------------------
14622|     30|    components.search_start -= 2;
14623|     30|  }
14624|     79|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (14624:7): [True: 37, False: 42]
  ------------------
14625|     37|    components.hash_start -= 2;
14626|     37|  }
14627|     79|  ADA_ASSERT_TRUE(validate());
14628|     79|  ADA_ASSERT_TRUE(!has_dash_dot());
14629|     79|}
parse.cc:_ZZN3ada4idna9ascii_mapEPcmENK3$_1clEh:
 2778|  45.2k|  auto broadcast = [](uint8_t v) -> uint64_t {
 2779|  45.2k|    return 0x101010101010101ull * v;
 2780|  45.2k|  };
parse.cc:_ZN3ada4idnaL19char_to_digit_valueEc:
 7978|  93.7k|static constexpr int32_t char_to_digit_value(char value) {
 7979|  93.7k|  if (value >= 'a' && value <= 'z') return value - 'a';
  ------------------
  |  Branch (7979:7): [True: 68.9k, False: 24.7k]
  |  Branch (7979:23): [True: 68.8k, False: 93]
  ------------------
 7980|  24.8k|  if (value >= '0' && value <= '9') return value - '0' + 26;
  ------------------
  |  Branch (7980:7): [True: 24.7k, False: 130]
  |  Branch (7980:23): [True: 24.1k, False: 635]
  ------------------
 7981|    765|  return -1;
 7982|  24.8k|}
parse.cc:_ZN3ada4idnaL5adaptEiib:
 7988|   175k|static constexpr int32_t adapt(int32_t d, int32_t n, bool firsttime) {
 7989|   175k|  if (firsttime) {
  ------------------
  |  Branch (7989:7): [True: 33.8k, False: 141k]
  ------------------
 7990|  33.8k|    d = d / damp;
 7991|   141k|  } else {
 7992|   141k|    d = d / 2;
 7993|   141k|  }
 7994|   175k|  d += d / n;
 7995|   175k|  int32_t k = 0;
 7996|   247k|  while (d > ((base - tmin) * tmax) / 2) {
  ------------------
  |  Branch (7996:10): [True: 72.0k, False: 175k]
  ------------------
 7997|  72.0k|    d /= base - tmin;
 7998|  72.0k|    k += base;
 7999|  72.0k|  }
 8000|   175k|  return k + (((base - tmin + 1) * d) / (d + skew));
 8001|   175k|}
parse.cc:_ZN3ada4idnaL13digit_to_charEi:
 7984|   336k|static constexpr char digit_to_char(int32_t digit) {
 7985|   336k|  return digit < 26 ? char(digit + 97) : char(digit + 22);
  ------------------
  |  Branch (7985:10): [True: 230k, False: 106k]
  ------------------
 7986|   336k|}
parse.cc:_ZN3ada4idnaL20find_last_not_of_nsmENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 8970|  32.2k|    const std::u32string_view label) noexcept {
 8971|  33.3k|  for (int i = label.size() - 1; i >= 0; i--)
  ------------------
  |  Branch (8971:34): [True: 33.3k, False: 0]
  ------------------
 8972|  33.3k|    if (find_direction(label[i]) != direction::NSM) return i;
  ------------------
  |  Branch (8972:9): [True: 32.2k, False: 1.07k]
  ------------------
 8973|       |
 8974|      0|  return std::u32string_view::npos;
 8975|  32.2k|}
parse.cc:_ZN3ada4idnaL12is_rtl_labelENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 8979|  32.2k|inline static bool is_rtl_label(const std::u32string_view label) noexcept {
 8980|  32.2k|  const size_t mask =
 8981|  32.2k|      (1u << direction::R) | (1u << direction::AL) | (1u << direction::AN);
 8982|       |
 8983|  32.2k|  size_t directions = 0;
 8984|   217k|  for (size_t i = 0; i < label.size(); i++) {
  ------------------
  |  Branch (8984:22): [True: 185k, False: 32.2k]
  ------------------
 8985|   185k|    directions |= 1u << find_direction(label[i]);
 8986|   185k|  }
 8987|  32.2k|  return (directions & mask) != 0;
 8988|  32.2k|}
parse.cc:_ZN3ada4idnaL14find_directionEj:
 8953|   230k|inline static direction find_direction(uint32_t code_point) noexcept {
 8954|   230k|  auto it = std::lower_bound(
 8955|   230k|      std::begin(dir_table), std::end(dir_table), code_point,
 8956|   230k|      [](const directions& d, uint32_t c) { return d.final_code < c; });
 8957|       |
 8958|       |  // next check is almost surely in vain, but we use it for safety.
 8959|   230k|  if (it == std::end(dir_table)) {
  ------------------
  |  Branch (8959:7): [True: 0, False: 230k]
  ------------------
 8960|      0|    return direction::NONE;
 8961|      0|  }
 8962|       |  // We have that d.final_code >= c.
 8963|   230k|  if (code_point >= it->start_code) {
  ------------------
  |  Branch (8963:7): [True: 229k, False: 1.48k]
  ------------------
 8964|   229k|    return it->direct;
 8965|   229k|  }
 8966|  1.48k|  return direction::NONE;
 8967|   230k|}
parse.cc:_ZZN3ada4idnaL14find_directionEjENKUlRKNS0_10directionsEjE_clES3_j:
 8956|  2.36M|      [](const directions& d, uint32_t c) { return d.final_code < c; });
_ZN3ada4idna8is_asciiENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9549|  27.3k|bool constexpr is_ascii(std::string_view view) {
 9550|   342k|  for (uint8_t c : view) {
  ------------------
  |  Branch (9550:18): [True: 342k, False: 17.3k]
  ------------------
 9551|   342k|    if (c >= 0x80) {
  ------------------
  |  Branch (9551:9): [True: 9.93k, False: 332k]
  ------------------
 9552|  9.93k|      return false;
 9553|  9.93k|    }
 9554|   342k|  }
 9555|  17.3k|  return true;
 9556|  27.3k|}
parse.cc:_ZN3ada4idnaL19from_ascii_to_asciiENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9583|  15.0k|static std::string from_ascii_to_ascii(std::string_view ut8_string) {
 9584|  15.0k|  static const std::string error = "";
 9585|       |  // copy and map
 9586|       |  // we could be more efficient by avoiding the copy when unnecessary.
 9587|  15.0k|  std::string mapped_string = std::string(ut8_string);
 9588|  15.0k|  ascii_map(mapped_string.data(), mapped_string.size());
 9589|  15.0k|  std::string out;
 9590|  15.0k|  size_t label_start = 0;
 9591|       |
 9592|  44.9k|  while (label_start != mapped_string.size()) {
  ------------------
  |  Branch (9592:10): [True: 30.7k, False: 14.2k]
  ------------------
 9593|  30.7k|    size_t loc_dot = mapped_string.find('.', label_start);
 9594|  30.7k|    bool is_last_label = (loc_dot == std::string_view::npos);
 9595|  30.7k|    size_t label_size = is_last_label ? mapped_string.size() - label_start
  ------------------
  |  Branch (9595:25): [True: 12.9k, False: 17.7k]
  ------------------
 9596|  30.7k|                                      : loc_dot - label_start;
 9597|  30.7k|    size_t label_size_with_dot = is_last_label ? label_size : label_size + 1;
  ------------------
  |  Branch (9597:34): [True: 12.9k, False: 17.7k]
  ------------------
 9598|  30.7k|    std::string_view label_view(mapped_string.data() + label_start, label_size);
 9599|  30.7k|    label_start += label_size_with_dot;
 9600|  30.7k|    if (label_size == 0) {
  ------------------
  |  Branch (9600:9): [True: 4.52k, False: 26.1k]
  ------------------
 9601|       |      // empty label? Nothing to do.
 9602|  26.1k|    } else if (begins_with(label_view, "xn--")) {
  ------------------
  |  Branch (9602:16): [True: 8.03k, False: 18.1k]
  ------------------
 9603|       |      // The xn-- part is the expensive game.
 9604|  8.03k|      out.append(label_view);
 9605|  8.03k|      std::string_view puny_segment_ascii(
 9606|  8.03k|          out.data() + out.size() - label_view.size() + 4,
 9607|  8.03k|          label_view.size() - 4);
 9608|  8.03k|      std::u32string tmp_buffer;
 9609|  8.03k|      bool is_ok = ada::idna::punycode_to_utf32(puny_segment_ascii, tmp_buffer);
 9610|  8.03k|      if (!is_ok) {
  ------------------
  |  Branch (9610:11): [True: 208, False: 7.82k]
  ------------------
 9611|    208|        return error;
 9612|    208|      }
 9613|  7.82k|      std::u32string post_map = ada::idna::map(tmp_buffer);
 9614|  7.82k|      if (tmp_buffer != post_map) {
  ------------------
  |  Branch (9614:11): [True: 378, False: 7.44k]
  ------------------
 9615|    378|        return error;
 9616|    378|      }
 9617|  7.44k|      std::u32string pre_normal = post_map;
 9618|  7.44k|      normalize(post_map);
 9619|  7.44k|      if (post_map != pre_normal) {
  ------------------
  |  Branch (9619:11): [True: 57, False: 7.39k]
  ------------------
 9620|     57|        return error;
 9621|     57|      }
 9622|  7.39k|      if (post_map.empty()) {
  ------------------
  |  Branch (9622:11): [True: 134, False: 7.25k]
  ------------------
 9623|    134|        return error;
 9624|    134|      }
 9625|  7.25k|      if (!is_label_valid(post_map)) {
  ------------------
  |  Branch (9625:11): [True: 27, False: 7.23k]
  ------------------
 9626|     27|        return error;
 9627|     27|      }
 9628|  18.1k|    } else {
 9629|  18.1k|      out.append(label_view);
 9630|  18.1k|    }
 9631|  29.9k|    if (!is_last_label) {
  ------------------
  |  Branch (9631:9): [True: 17.6k, False: 12.2k]
  ------------------
 9632|  17.6k|      out.push_back('.');
 9633|  17.6k|    }
 9634|  29.9k|  }
 9635|  14.2k|  return out;
 9636|  15.0k|}
_ZN3ada4idna11begins_withENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEES5_:
 9526|  30.6k|                           std::u32string_view prefix) {
 9527|  30.6k|  if (view.size() < prefix.size()) {
  ------------------
  |  Branch (9527:7): [True: 8.34k, False: 22.2k]
  ------------------
 9528|  8.34k|    return false;
 9529|  8.34k|  }
 9530|  22.2k|  return view.substr(0, prefix.size()) == prefix;
 9531|  30.6k|}
_ZN3ada4idna8is_asciiENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEE:
 9540|  28.5k|bool constexpr is_ascii(std::u32string_view view) {
 9541|  60.0k|  for (uint32_t c : view) {
  ------------------
  |  Branch (9541:19): [True: 60.0k, False: 3.15k]
  ------------------
 9542|  60.0k|    if (c >= 0x80) {
  ------------------
  |  Branch (9542:9): [True: 25.4k, False: 34.6k]
  ------------------
 9543|  25.4k|      return false;
 9544|  25.4k|    }
 9545|  60.0k|  }
 9546|  3.15k|  return true;
 9547|  28.5k|}
_ZN3ada4idna11begins_withENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_:
 9533|  56.6k|bool constexpr begins_with(std::string_view view, std::string_view prefix) {
 9534|  56.6k|  if (view.size() < prefix.size()) {
  ------------------
  |  Branch (9534:7): [True: 26.8k, False: 29.8k]
  ------------------
 9535|  26.8k|    return false;
 9536|  26.8k|  }
 9537|  29.8k|  return view.substr(0, prefix.size()) == prefix;
 9538|  56.6k|}
_ZN3ada7unicode18is_ascii_hex_digitEc:
10076|  37.9k|ada_really_inline constexpr bool is_ascii_hex_digit(const char c) noexcept {
10077|  37.9k|  return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') ||
  ------------------
  |  Branch (10077:11): [True: 36.6k, False: 1.37k]
  |  Branch (10077:23): [True: 17.3k, False: 19.2k]
  |  Branch (10077:37): [True: 17.7k, False: 2.91k]
  |  Branch (10077:49): [True: 14.7k, False: 2.99k]
  ------------------
10078|  37.9k|         (c >= 'a' && c <= 'f');
  ------------------
  |  Branch (10078:11): [True: 2.80k, False: 3.10k]
  |  Branch (10078:23): [True: 2.61k, False: 181]
  ------------------
10079|  37.9k|}
_ZN3ada7unicode21convert_hex_to_binaryEc:
10151|  34.1k|unsigned constexpr convert_hex_to_binary(const char c) noexcept {
10152|       |  // this code can be optimized.
10153|  34.1k|  if (c <= '9') {
  ------------------
  |  Branch (10153:7): [True: 17.0k, False: 17.0k]
  ------------------
10154|  17.0k|    return c - '0';
10155|  17.0k|  }
10156|  17.0k|  char del = c >= 'a' ? 'a' : 'A';
  ------------------
  |  Branch (10156:14): [True: 2.33k, False: 14.7k]
  ------------------
10157|  17.0k|  return 10 + (c - del);
10158|  34.1k|}
_ZN3ada7unicode36contains_forbidden_domain_code_pointEPKcm:
 9972|  16.7k|    const char* input, size_t length) noexcept {
 9973|  16.7k|  size_t i = 0;
 9974|  16.7k|  uint8_t accumulator{};
 9975|   183k|  for (; i + 4 <= length; i += 4) {
  ------------------
  |  Branch (9975:10): [True: 166k, False: 16.7k]
  ------------------
 9976|   166k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i])];
 9977|   166k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 1])];
 9978|   166k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 2])];
 9979|   166k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i + 3])];
 9980|   166k|  }
 9981|  41.6k|  for (; i < length; i++) {
  ------------------
  |  Branch (9981:10): [True: 24.9k, False: 16.7k]
  ------------------
 9982|  24.9k|    accumulator |= is_forbidden_domain_code_point_table[uint8_t(input[i])];
 9983|  24.9k|  }
 9984|  16.7k|  return accumulator;
 9985|  16.7k|}
_ZN3ada7unicode19has_tabs_or_newlineENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 9851|  88.4k|    std::string_view user_input) noexcept {
 9852|  88.4k|  size_t i = 0;
 9853|  88.4k|  const __m128i mask1 = _mm_set1_epi8('\r');
 9854|  88.4k|  const __m128i mask2 = _mm_set1_epi8('\n');
 9855|  88.4k|  const __m128i mask3 = _mm_set1_epi8('\t');
 9856|  88.4k|  __m128i running{0};
 9857|   147k|  for (; i + 15 < user_input.size(); i += 16) {
  ------------------
  |  Branch (9857:10): [True: 59.1k, False: 88.4k]
  ------------------
 9858|  59.1k|    __m128i word = _mm_loadu_si128((const __m128i*)(user_input.data() + i));
 9859|  59.1k|    running = _mm_or_si128(
 9860|  59.1k|        _mm_or_si128(running, _mm_or_si128(_mm_cmpeq_epi8(word, mask1),
 9861|  59.1k|                                           _mm_cmpeq_epi8(word, mask2))),
 9862|  59.1k|        _mm_cmpeq_epi8(word, mask3));
 9863|  59.1k|  }
 9864|  88.4k|  if (i < user_input.size()) {
  ------------------
  |  Branch (9864:7): [True: 60.3k, False: 28.0k]
  ------------------
 9865|  60.3k|    alignas(16) uint8_t buffer[16]{};
 9866|  60.3k|    memcpy(buffer, user_input.data() + i, user_input.size() - i);
 9867|  60.3k|    __m128i word = _mm_load_si128((const __m128i*)buffer);
 9868|  60.3k|    running = _mm_or_si128(
 9869|  60.3k|        _mm_or_si128(running, _mm_or_si128(_mm_cmpeq_epi8(word, mask1),
 9870|  60.3k|                                           _mm_cmpeq_epi8(word, mask2))),
 9871|  60.3k|        _mm_cmpeq_epi8(word, mask3));
 9872|  60.3k|  }
 9873|  88.4k|  return _mm_movemask_epi8(running) != 0;
 9874|  88.4k|}
_ZN3ada7helpers27remove_ascii_tab_or_newlineERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
10594|  66.0k|    std::string& input) noexcept {
10595|       |  // if this ever becomes a performance issue, we could use an approach similar
10596|       |  // to has_tabs_or_newline
10597|  66.0k|  input.erase(std::remove_if(input.begin(), input.end(),
10598|  66.0k|                             [](char c) {
10599|  66.0k|                               return ada::unicode::is_ascii_tab_or_newline(c);
10600|  66.0k|                             }),
10601|  66.0k|              input.end());
10602|  66.0k|}
_ZZN3ada7helpers27remove_ascii_tab_or_newlineERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEENKUlcE_clEc:
10598|   827k|                             [](char c) {
10599|   827k|                               return ada::unicode::is_ascii_tab_or_newline(c);
10600|   827k|                             }),
_ZN3ada7unicode23is_ascii_tab_or_newlineEc:
10086|   827k|    const char c) noexcept {
10087|   827k|  return c == '\t' || c == '\n' || c == '\r';
  ------------------
  |  Branch (10087:10): [True: 8.79k, False: 818k]
  |  Branch (10087:23): [True: 18.1k, False: 800k]
  |  Branch (10087:36): [True: 2.04k, False: 798k]
  ------------------
10088|   827k|}
_ZN3ada7helpers19parse_prepared_pathENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEENS_6scheme4typeERNS1_12basic_stringIcS4_NS1_9allocatorIcEEEE:
10859|  19.0k|                                           std::string& path) {
10860|  19.0k|  ada_log("parse_prepared_path ", input);
10861|  19.0k|  uint8_t accumulator = checkers::path_signature(input);
10862|       |  // Let us first detect a trivial case.
10863|       |  // If it is special, we check that we have no dot, no %,  no \ and no
10864|       |  // character needing percent encoding. Otherwise, we check that we have no %,
10865|       |  // no dot, and no character needing percent encoding.
10866|  19.0k|  constexpr uint8_t need_encoding = 1;
10867|  19.0k|  constexpr uint8_t backslash_char = 2;
10868|  19.0k|  constexpr uint8_t dot_char = 4;
10869|  19.0k|  constexpr uint8_t percent_char = 8;
10870|  19.0k|  bool special = type != ada::scheme::NOT_SPECIAL;
10871|  19.0k|  bool may_need_slow_file_handling = (type == ada::scheme::type::FILE &&
  ------------------
  |  Branch (10871:39): [True: 14.8k, False: 4.10k]
  ------------------
10872|  19.0k|                                      checkers::is_windows_drive_letter(input));
  ------------------
  |  Branch (10872:39): [True: 2.22k, False: 12.6k]
  ------------------
10873|  19.0k|  bool trivial_path =
10874|  19.0k|      (special ? (accumulator == 0)
  ------------------
  |  Branch (10874:7): [True: 8.62k, False: 10.3k]
  |  Branch (10874:8): [True: 16.7k, False: 2.27k]
  ------------------
10875|  19.0k|               : ((accumulator & (need_encoding | dot_char | percent_char)) ==
10876|  2.27k|                  0)) &&
10877|  19.0k|      (!may_need_slow_file_handling);
  ------------------
  |  Branch (10877:7): [True: 7.14k, False: 1.47k]
  ------------------
10878|  19.0k|  if (accumulator == dot_char && !may_need_slow_file_handling) {
  ------------------
  |  Branch (10878:7): [True: 2.80k, False: 16.1k]
  |  Branch (10878:34): [True: 2.62k, False: 175]
  ------------------
10879|       |    // '4' means that we have at least one dot, but nothing that requires
10880|       |    // percent encoding or decoding. The only part that is not trivial is
10881|       |    // that we may have single dots and double dots path segments.
10882|       |    // If we have such segments, then we either have a path that begins
10883|       |    // with '.' (easy to check), or we have the sequence './'.
10884|       |    // Note: input cannot be empty, it must at least contain one character ('.')
10885|       |    // Note: we know that '\' is not present.
10886|  2.62k|    if (input[0] != '.') {
  ------------------
  |  Branch (10886:9): [True: 2.04k, False: 579]
  ------------------
10887|  2.04k|      size_t slashdot = input.find("/.");
10888|  2.04k|      if (slashdot == std::string_view::npos) {  // common case
  ------------------
  |  Branch (10888:11): [True: 1.23k, False: 811]
  ------------------
10889|  1.23k|        trivial_path = true;
10890|  1.23k|      } else {  // uncommon
10891|       |        // only three cases matter: /./, /.. or a final /
10892|    811|        trivial_path =
10893|    811|            !(slashdot + 2 == input.size() || input[slashdot + 2] == '.' ||
  ------------------
  |  Branch (10893:15): [True: 270, False: 541]
  |  Branch (10893:47): [True: 386, False: 155]
  ------------------
10894|    811|              input[slashdot + 2] == '/');
  ------------------
  |  Branch (10894:15): [True: 60, False: 95]
  ------------------
10895|    811|      }
10896|  2.04k|    }
10897|  2.62k|  }
10898|  19.0k|  if (trivial_path) {
  ------------------
  |  Branch (10898:7): [True: 8.48k, False: 10.5k]
  ------------------
10899|  8.48k|    ada_log("parse_path trivial");
10900|  8.48k|    path += '/';
10901|  8.48k|    path += input;
10902|  8.48k|    return;
10903|  8.48k|  }
10904|       |  // We are going to need to look a bit at the path, but let us see if we can
10905|       |  // ignore percent encoding *and* backslashes *and* percent characters.
10906|       |  // Except for the trivial case, this is likely to capture 99% of paths out
10907|       |  // there.
10908|  10.5k|  bool fast_path =
10909|  10.5k|      (special &&
  ------------------
  |  Branch (10909:8): [True: 9.48k, False: 1.03k]
  ------------------
10910|  10.5k|       (accumulator & (need_encoding | backslash_char | percent_char)) == 0) &&
  ------------------
  |  Branch (10910:8): [True: 2.74k, False: 6.73k]
  ------------------
10911|  10.5k|      (type != ada::scheme::type::FILE);
  ------------------
  |  Branch (10911:7): [True: 500, False: 2.24k]
  ------------------
10912|  10.5k|  if (fast_path) {
  ------------------
  |  Branch (10912:7): [True: 500, False: 10.0k]
  ------------------
10913|    500|    ada_log("parse_prepared_path fast");
10914|       |    // Here we don't need to worry about \ or percent encoding.
10915|       |    // We also do not have a file protocol. We might have dots, however,
10916|       |    // but dots must as appear as '.', and they cannot be encoded because
10917|       |    // the symbol '%' is not present.
10918|    500|    size_t previous_location = 0;  // We start at 0.
10919|  4.89k|    do {
10920|  4.89k|      size_t new_location = input.find('/', previous_location);
10921|       |      // std::string_view path_view = input;
10922|       |      //  We process the last segment separately:
10923|  4.89k|      if (new_location == std::string_view::npos) {
  ------------------
  |  Branch (10923:11): [True: 500, False: 4.39k]
  ------------------
10924|    500|        std::string_view path_view = input.substr(previous_location);
10925|    500|        if (path_view == "..") {  // The path ends with ..
  ------------------
  |  Branch (10925:13): [True: 32, False: 468]
  ------------------
10926|       |          // e.g., if you receive ".." with an empty path, you go to "/".
10927|     32|          if (path.empty()) {
  ------------------
  |  Branch (10927:15): [True: 12, False: 20]
  ------------------
10928|     12|            path = '/';
10929|     12|            return;
10930|     12|          }
10931|       |          // Fast case where we have nothing to do:
10932|     20|          if (path.back() == '/') {
  ------------------
  |  Branch (10932:15): [True: 9, False: 11]
  ------------------
10933|      9|            return;
10934|      9|          }
10935|       |          // If you have the path "/joe/myfriend",
10936|       |          // then you delete 'myfriend'.
10937|     11|          path.resize(path.rfind('/') + 1);
10938|     11|          return;
10939|     20|        }
10940|    468|        path += '/';
10941|    468|        if (path_view != ".") {
  ------------------
  |  Branch (10941:13): [True: 323, False: 145]
  ------------------
10942|    323|          path.append(path_view);
10943|    323|        }
10944|    468|        return;
10945|  4.39k|      } else {
10946|       |        // This is a non-final segment.
10947|  4.39k|        std::string_view path_view =
10948|  4.39k|            input.substr(previous_location, new_location - previous_location);
10949|  4.39k|        previous_location = new_location + 1;
10950|  4.39k|        if (path_view == "..") {
  ------------------
  |  Branch (10950:13): [True: 620, False: 3.77k]
  ------------------
10951|    620|          size_t last_delimiter = path.rfind('/');
10952|    620|          if (last_delimiter != std::string::npos) {
  ------------------
  |  Branch (10952:15): [True: 334, False: 286]
  ------------------
10953|    334|            path.erase(last_delimiter);
10954|    334|          }
10955|  3.77k|        } else if (path_view != ".") {
  ------------------
  |  Branch (10955:20): [True: 3.23k, False: 538]
  ------------------
10956|  3.23k|          path += '/';
10957|  3.23k|          path.append(path_view);
10958|  3.23k|        }
10959|  4.39k|      }
10960|  4.89k|    } while (true);
  ------------------
  |  Branch (10960:14): [Folded - Ignored]
  ------------------
10961|  10.0k|  } else {
10962|  10.0k|    ada_log("parse_path slow");
10963|       |    // we have reached the general case
10964|  10.0k|    bool needs_percent_encoding = (accumulator & 1);
10965|  10.0k|    std::string path_buffer_tmp;
10966|  51.2k|    do {
10967|  51.2k|      size_t location = (special && (accumulator & 2))
  ------------------
  |  Branch (10967:26): [True: 42.3k, False: 8.91k]
  |  Branch (10967:37): [True: 6.83k, False: 35.4k]
  ------------------
10968|  51.2k|                            ? input.find_first_of("/\\")
10969|  51.2k|                            : input.find('/');
10970|  51.2k|      std::string_view path_view = input;
10971|  51.2k|      if (location != std::string_view::npos) {
  ------------------
  |  Branch (10971:11): [True: 41.2k, False: 10.0k]
  ------------------
10972|  41.2k|        path_view.remove_suffix(path_view.size() - location);
10973|  41.2k|        input.remove_prefix(location + 1);
10974|  41.2k|      }
10975|       |      // path_buffer is either path_view or it might point at a percent encoded
10976|       |      // temporary file.
10977|  51.2k|      std::string_view path_buffer =
10978|  51.2k|          (needs_percent_encoding &&
  ------------------
  |  Branch (10978:12): [True: 26.8k, False: 24.3k]
  ------------------
10979|  51.2k|           ada::unicode::percent_encode<false>(
  ------------------
  |  Branch (10979:12): [True: 12.3k, False: 14.5k]
  ------------------
10980|  26.8k|               path_view, character_sets::PATH_PERCENT_ENCODE, path_buffer_tmp))
10981|  51.2k|              ? path_buffer_tmp
10982|  51.2k|              : path_view;
10983|  51.2k|      if (unicode::is_double_dot_path_segment(path_buffer)) {
  ------------------
  |  Branch (10983:11): [True: 7.75k, False: 43.4k]
  ------------------
10984|  7.75k|        if ((helpers::shorten_path(path, type) || special) &&
  ------------------
  |  Branch (10984:14): [True: 3.95k, False: 3.80k]
  |  Branch (10984:51): [True: 3.26k, False: 539]
  ------------------
10985|  7.75k|            location == std::string_view::npos) {
  ------------------
  |  Branch (10985:13): [True: 623, False: 6.59k]
  ------------------
10986|    623|          path += '/';
10987|    623|        }
10988|  43.4k|      } else if (unicode::is_single_dot_path_segment(path_buffer) &&
  ------------------
  |  Branch (10988:18): [True: 4.13k, False: 39.3k]
  ------------------
10989|  43.4k|                 (location == std::string_view::npos)) {
  ------------------
  |  Branch (10989:18): [True: 315, False: 3.81k]
  ------------------
10990|    315|        path += '/';
10991|    315|      }
10992|       |      // Otherwise, if path_buffer is not a single-dot path segment, then:
10993|  43.1k|      else if (!unicode::is_single_dot_path_segment(path_buffer)) {
  ------------------
  |  Branch (10993:16): [True: 39.3k, False: 3.81k]
  ------------------
10994|       |        // If url’s scheme is "file", url’s path is empty, and path_buffer is a
10995|       |        // Windows drive letter, then replace the second code point in
10996|       |        // path_buffer with U+003A (:).
10997|  39.3k|        if (type == ada::scheme::type::FILE && path.empty() &&
  ------------------
  |  Branch (10997:13): [True: 26.8k, False: 12.4k]
  |  Branch (10997:48): [True: 10.5k, False: 16.3k]
  ------------------
10998|  39.3k|            checkers::is_windows_drive_letter(path_buffer)) {
  ------------------
  |  Branch (10998:13): [True: 2.15k, False: 8.35k]
  ------------------
10999|  2.15k|          path += '/';
11000|  2.15k|          path += path_buffer[0];
11001|  2.15k|          path += ':';
11002|  2.15k|          path_buffer.remove_prefix(2);
11003|  2.15k|          path.append(path_buffer);
11004|  37.1k|        } else {
11005|       |          // Append path_buffer to url’s path.
11006|  37.1k|          path += '/';
11007|  37.1k|          path.append(path_buffer);
11008|  37.1k|        }
11009|  39.3k|      }
11010|  51.2k|      if (location == std::string_view::npos) {
  ------------------
  |  Branch (11010:11): [True: 10.0k, False: 41.2k]
  ------------------
11011|  10.0k|        return;
11012|  10.0k|      }
11013|  51.2k|    } while (true);
  ------------------
  |  Branch (11013:14): [Folded - Ignored]
  ------------------
11014|  10.0k|  }
11015|  10.5k|}
_ZN3ada8checkers14path_signatureENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
   68|  27.6k|    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|  27.6k|  size_t i = 0;
   75|  27.6k|  uint8_t accumulator{};
   76|  78.0k|  for (; i + 7 < input.size(); i += 8) {
  ------------------
  |  Branch (76:10): [True: 50.4k, False: 27.6k]
  ------------------
   77|  50.4k|    accumulator |= uint8_t(path_signature_table[uint8_t(input[i])] |
   78|  50.4k|                           path_signature_table[uint8_t(input[i + 1])] |
   79|  50.4k|                           path_signature_table[uint8_t(input[i + 2])] |
   80|  50.4k|                           path_signature_table[uint8_t(input[i + 3])] |
   81|  50.4k|                           path_signature_table[uint8_t(input[i + 4])] |
   82|  50.4k|                           path_signature_table[uint8_t(input[i + 5])] |
   83|  50.4k|                           path_signature_table[uint8_t(input[i + 6])] |
   84|  50.4k|                           path_signature_table[uint8_t(input[i + 7])]);
   85|  50.4k|  }
   86|  98.4k|  for (; i < input.size(); i++) {
  ------------------
  |  Branch (86:10): [True: 70.8k, False: 27.6k]
  ------------------
   87|  70.8k|    accumulator |= uint8_t(path_signature_table[uint8_t(input[i])]);
   88|  70.8k|  }
   89|  27.6k|  return accumulator;
   90|  27.6k|}
_ZN3ada7unicode14percent_encodeILb0EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKhRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEE:
10221|  38.7k|                    std::string& out) {
10222|  38.7k|  ada_log("percent_encode ", input, " to output string while ",
10223|  38.7k|          append ? "appending" : "overwriting");
10224|  38.7k|  auto pointer =
10225|  38.7k|      std::find_if(input.begin(), input.end(), [character_set](const char c) {
10226|  38.7k|        return character_sets::bit_at(character_set, c);
10227|  38.7k|      });
10228|  38.7k|  ada_log("percent_encode done checking, moved to ",
10229|  38.7k|          std::distance(input.begin(), pointer));
10230|       |
10231|       |  // Optimization: Don't iterate if percent encode is not required
10232|  38.7k|  if (pointer == input.end()) {
  ------------------
  |  Branch (10232:7): [True: 21.9k, False: 16.8k]
  ------------------
10233|  21.9k|    ada_log("percent_encode encoding not needed.");
10234|  21.9k|    return false;
10235|  21.9k|  }
10236|  16.8k|  if (!append) {
  ------------------
  |  Branch (10236:7): [Folded - Ignored]
  ------------------
10237|  16.8k|    out.clear();
10238|  16.8k|  }
10239|  16.8k|  ada_log("percent_encode appending ", std::distance(input.begin(), pointer),
10240|  16.8k|          " bytes");
10241|  16.8k|  out.append(input.data(), std::distance(input.begin(), pointer));
10242|  16.8k|  ada_log("percent_encode processing ", std::distance(pointer, input.end()),
10243|  16.8k|          " bytes");
10244|   210k|  for (; pointer != input.end(); pointer++) {
  ------------------
  |  Branch (10244:10): [True: 193k, False: 16.8k]
  ------------------
10245|   193k|    if (character_sets::bit_at(character_set, *pointer)) {
  ------------------
  |  Branch (10245:9): [True: 156k, False: 37.2k]
  ------------------
10246|   156k|      out.append(character_sets::hex + uint8_t(*pointer) * 4, 3);
10247|   156k|    } else {
10248|  37.2k|      out += *pointer;
10249|  37.2k|    }
10250|   193k|  }
10251|  16.8k|  return true;
10252|  38.7k|}
_ZZN3ada7unicode14percent_encodeILb0EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKhRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEEENKUlcE_clEc:
10225|  70.2k|      std::find_if(input.begin(), input.end(), [character_set](const char c) {
10226|  70.2k|        return character_sets::bit_at(character_set, c);
10227|  70.2k|      });
_ZN3ada7unicode26is_double_dot_path_segmentENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
10094|  71.6k|    std::string_view input) noexcept {
10095|       |  // This will catch most cases:
10096|       |  // The length must be 2,4 or 6.
10097|       |  // We divide by two and require
10098|       |  // that the result be between 1 and 3 inclusively.
10099|  71.6k|  uint64_t half_length = uint64_t(input.size()) / 2;
10100|  71.6k|  if (half_length - 1 > 2) {
  ------------------
  |  Branch (10100:7): [True: 39.6k, False: 31.9k]
  ------------------
10101|  39.6k|    return false;
10102|  39.6k|  }
10103|       |  // We have a string of length 2, 4 or 6.
10104|       |  // We now check the first character:
10105|  31.9k|  if ((input[0] != '.') && (input[0] != '%')) {
  ------------------
  |  Branch (10105:7): [True: 17.3k, False: 14.5k]
  |  Branch (10105:28): [True: 7.05k, False: 10.3k]
  ------------------
10106|  7.05k|    return false;
10107|  7.05k|  }
10108|       |  // We are unlikely the get beyond this point.
10109|  24.8k|  int hash_value = (input.size() + (unsigned)(input[0])) & 3;
10110|  24.8k|  const std::string_view target = table_is_double_dot_path_segment[hash_value];
10111|  24.8k|  if (target.size() != input.size()) {
  ------------------
  |  Branch (10111:7): [True: 7.86k, False: 17.0k]
  ------------------
10112|  7.86k|    return false;
10113|  7.86k|  }
10114|       |  // We almost never get here.
10115|       |  // Optimizing the rest is relatively unimportant.
10116|  17.0k|  auto prefix_equal_unsafe = [](std::string_view a, std::string_view b) {
10117|  17.0k|    uint16_t A, B;
10118|  17.0k|    memcpy(&A, a.data(), sizeof(A));
10119|  17.0k|    memcpy(&B, b.data(), sizeof(B));
10120|  17.0k|    return A == B;
10121|  17.0k|  };
10122|  17.0k|  if (!prefix_equal_unsafe(input, target)) {
  ------------------
  |  Branch (10122:7): [True: 1.58k, False: 15.4k]
  ------------------
10123|  1.58k|    return false;
10124|  1.58k|  }
10125|  21.7k|  for (size_t i = 2; i < input.size(); i++) {
  ------------------
  |  Branch (10125:22): [True: 9.48k, False: 12.2k]
  ------------------
10126|  9.48k|    char c = input[i];
10127|  9.48k|    if ((uint8_t((c | 0x20) - 0x61) <= 25 ? (c | 0x20) : c) != target[i]) {
  ------------------
  |  Branch (10127:9): [True: 3.15k, False: 6.32k]
  |  Branch (10127:10): [True: 3.17k, False: 6.30k]
  ------------------
10128|  3.15k|      return false;
10129|  3.15k|    }
10130|  9.48k|  }
10131|  12.2k|  return true;
10132|       |  // The above code might be a bit better than the code below. Compilers
10133|       |  // are not stupid and may use the fact that these strings have length 2,4 and
10134|       |  // 6 and other tricks.
10135|       |  // return input == ".." ||
10136|       |  //  input == ".%2e" || input == ".%2E" ||
10137|       |  //  input == "%2e." || input == "%2E." ||
10138|       |  //  input == "%2e%2e" || input == "%2E%2E" || input == "%2E%2e" || input ==
10139|       |  //  "%2e%2E";
10140|  15.4k|}
_ZZN3ada7unicode26is_double_dot_path_segmentENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlS5_S5_E_clES5_S5_:
10116|  17.0k|  auto prefix_equal_unsafe = [](std::string_view a, std::string_view b) {
10117|  17.0k|    uint16_t A, B;
10118|  17.0k|    memcpy(&A, a.data(), sizeof(A));
10119|  17.0k|    memcpy(&B, b.data(), sizeof(B));
10120|  17.0k|    return A == B;
10121|  17.0k|  };
_ZN3ada7unicode26is_single_dot_path_segmentENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
10143|   118k|    std::string_view input) noexcept {
10144|   118k|  return input == "." || input == "%2e" || input == "%2E";
  ------------------
  |  Branch (10144:10): [True: 6.48k, False: 111k]
  |  Branch (10144:26): [True: 2.18k, False: 109k]
  |  Branch (10144:44): [True: 2.20k, False: 107k]
  ------------------
10145|   118k|}
_ZN3ada7unicode28is_forbidden_host_code_pointEc:
 9928|  33.1k|    const char c) noexcept {
 9929|  33.1k|  return is_forbidden_host_code_point_table[uint8_t(c)];
 9930|  33.1k|}
_ZN3ada7unicode22is_c0_control_or_spaceEc:
10081|  98.4k|ada_really_inline constexpr bool is_c0_control_or_space(const char c) noexcept {
10082|  98.4k|  return (unsigned char)c <= ' ';
10083|  98.4k|}
_ZN3ada3url10parse_pathENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11633|  7.20k|ada_really_inline void url::parse_path(std::string_view input) {
11634|  7.20k|  ada_log("parse_path ", input);
11635|  7.20k|  std::string tmp_buffer;
11636|  7.20k|  std::string_view internal_input;
11637|  7.20k|  if (unicode::has_tabs_or_newline(input)) {
  ------------------
  |  Branch (11637:7): [True: 103, False: 7.10k]
  ------------------
11638|    103|    tmp_buffer = input;
11639|       |    // Optimization opportunity: Instead of copying and then pruning, we could
11640|       |    // just directly build the string from user_input.
11641|    103|    helpers::remove_ascii_tab_or_newline(tmp_buffer);
11642|    103|    internal_input = tmp_buffer;
11643|  7.10k|  } else {
11644|  7.10k|    internal_input = input;
11645|  7.10k|  }
11646|       |
11647|       |  // If url is special, then:
11648|  7.20k|  if (is_special()) {
  ------------------
  |  Branch (11648:7): [True: 5.52k, False: 1.68k]
  ------------------
11649|  5.52k|    if (internal_input.empty()) {
  ------------------
  |  Branch (11649:9): [True: 3.45k, False: 2.06k]
  ------------------
11650|  3.45k|      path = "/";
11651|  3.45k|    } else if ((internal_input[0] == '/') || (internal_input[0] == '\\')) {
  ------------------
  |  Branch (11651:16): [True: 526, False: 1.54k]
  |  Branch (11651:46): [True: 4, False: 1.53k]
  ------------------
11652|    530|      helpers::parse_prepared_path(internal_input.substr(1), type, path);
11653|    530|      return;
11654|  1.53k|    } else {
11655|  1.53k|      helpers::parse_prepared_path(internal_input, type, path);
11656|  1.53k|      return;
11657|  1.53k|    }
11658|  5.52k|  } else if (!internal_input.empty()) {
  ------------------
  |  Branch (11658:14): [True: 767, False: 913]
  ------------------
11659|    767|    if (internal_input[0] == '/') {
  ------------------
  |  Branch (11659:9): [True: 252, False: 515]
  ------------------
11660|    252|      helpers::parse_prepared_path(internal_input.substr(1), type, path);
11661|    252|      return;
11662|    515|    } else {
11663|    515|      helpers::parse_prepared_path(internal_input, type, path);
11664|    515|      return;
11665|    515|    }
11666|    913|  } else {
11667|    913|    if (!host.has_value()) {
  ------------------
  |  Branch (11667:9): [True: 0, False: 913]
  ------------------
11668|      0|      path = "/";
11669|      0|    }
11670|    913|  }
11671|  4.37k|  return;
11672|  7.20k|}
_ZN3ada7unicode13is_alnum_plusEc:
10062|   134k|ada_really_inline constexpr bool is_alnum_plus(const char c) noexcept {
10063|   134k|  return is_alnum_plus_table[uint8_t(c)];
10064|       |  // A table is almost surely much faster than the
10065|       |  // following under most compilers: return
10066|       |  // return (std::isalnum(c) || c == '+' || c == '-' || c == '.');
10067|   134k|}
_ZN3ada7helpers18trim_c0_whitespaceERNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
10847|  59.9k|ada_really_inline void trim_c0_whitespace(std::string_view& input) noexcept {
10848|  63.2k|  while (!input.empty() &&
  ------------------
  |  Branch (10848:10): [True: 48.2k, False: 14.9k]
  ------------------
10849|  63.2k|         ada::unicode::is_c0_control_or_space(input.front())) {
  ------------------
  |  Branch (10849:10): [True: 3.36k, False: 44.9k]
  ------------------
10850|  3.36k|    input.remove_prefix(1);
10851|  3.36k|  }
10852|  62.1k|  while (!input.empty() && ada::unicode::is_c0_control_or_space(input.back())) {
  ------------------
  |  Branch (10852:10): [True: 47.2k, False: 14.9k]
  |  Branch (10852:28): [True: 2.27k, False: 44.9k]
  ------------------
10853|  2.27k|    input.remove_suffix(1);
10854|  2.27k|  }
10855|  59.9k|}
_ZN3ada7helpers10prune_hashERNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
10528|  59.9k|    std::string_view& input) noexcept {
10529|       |  // compiles down to 20--30 instructions including a class to memchr (C
10530|       |  // function). this function should be quite fast.
10531|  59.9k|  size_t location_of_first = input.find('#');
10532|  59.9k|  if (location_of_first == std::string_view::npos) {
  ------------------
  |  Branch (10532:7): [True: 58.5k, False: 1.32k]
  ------------------
10533|  58.5k|    return std::nullopt;
10534|  58.5k|  }
10535|  1.32k|  std::string_view hash = input;
10536|  1.32k|  hash.remove_prefix(location_of_first + 1);
10537|  1.32k|  input.remove_suffix(input.size() - location_of_first);
10538|  1.32k|  return hash;
10539|  59.9k|}
_ZN3ada7helpers9substringENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEm:
10605|  82.4k|                                             size_t pos) noexcept {
10606|  82.4k|  ADA_ASSERT_TRUE(pos <= input.size());
10607|       |  // The following is safer but unneeded if we have the above line:
10608|       |  // return pos > input.size() ? std::string_view() : input.substr(pos);
10609|  82.4k|  return input.substr(pos);
10610|  82.4k|}
_ZN3ada7helpers32find_authority_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11041|  9.03k|find_authority_delimiter_special(std::string_view view) noexcept {
11042|  9.03k|  auto has_zero_byte = [](uint64_t v) {
11043|  9.03k|    return ((v - 0x0101010101010101) & ~(v)&0x8080808080808080);
11044|  9.03k|  };
11045|  9.03k|  auto index_of_first_set_byte = [](uint64_t v) {
11046|  9.03k|    return ((((v - 1) & 0x101010101010101) * 0x101010101010101) >> 56) - 1;
11047|  9.03k|  };
11048|  9.03k|  auto broadcast = [](uint8_t v) -> uint64_t {
11049|  9.03k|    return 0x101010101010101ull * v;
11050|  9.03k|  };
11051|  9.03k|  size_t i = 0;
11052|  9.03k|  uint64_t mask1 = broadcast('@');
11053|  9.03k|  uint64_t mask2 = broadcast('/');
11054|  9.03k|  uint64_t mask3 = broadcast('?');
11055|  9.03k|  uint64_t mask4 = broadcast('\\');
11056|       |
11057|  13.4k|  for (; i + 7 < view.size(); i += 8) {
  ------------------
  |  Branch (11057:10): [True: 9.96k, False: 3.46k]
  ------------------
11058|  9.96k|    uint64_t word{};
11059|  9.96k|    memcpy(&word, view.data() + i, sizeof(word));
11060|  9.96k|    word = swap_bytes_if_big_endian(word);
11061|  9.96k|    uint64_t xor1 = word ^ mask1;
11062|  9.96k|    uint64_t xor2 = word ^ mask2;
11063|  9.96k|    uint64_t xor3 = word ^ mask3;
11064|  9.96k|    uint64_t xor4 = word ^ mask4;
11065|  9.96k|    uint64_t is_match = has_zero_byte(xor1) | has_zero_byte(xor2) |
11066|  9.96k|                        has_zero_byte(xor3) | has_zero_byte(xor4);
11067|  9.96k|    if (is_match) {
  ------------------
  |  Branch (11067:9): [True: 5.57k, False: 4.38k]
  ------------------
11068|  5.57k|      return size_t(i + index_of_first_set_byte(is_match));
11069|  5.57k|    }
11070|  9.96k|  }
11071|       |
11072|  3.46k|  if (i < view.size()) {
  ------------------
  |  Branch (11072:7): [True: 2.83k, False: 631]
  ------------------
11073|  2.83k|    uint64_t word{};
11074|  2.83k|    memcpy(&word, view.data() + i, view.size() - i);
11075|  2.83k|    word = swap_bytes_if_big_endian(word);
11076|  2.83k|    uint64_t xor1 = word ^ mask1;
11077|  2.83k|    uint64_t xor2 = word ^ mask2;
11078|  2.83k|    uint64_t xor3 = word ^ mask3;
11079|  2.83k|    uint64_t xor4 = word ^ mask4;
11080|  2.83k|    uint64_t is_match = has_zero_byte(xor1) | has_zero_byte(xor2) |
11081|  2.83k|                        has_zero_byte(xor3) | has_zero_byte(xor4);
11082|  2.83k|    if (is_match) {
  ------------------
  |  Branch (11082:9): [True: 2.43k, False: 399]
  ------------------
11083|  2.43k|      return size_t(i + index_of_first_set_byte(is_match));
11084|  2.43k|    }
11085|  2.83k|  }
11086|       |
11087|  1.03k|  return view.size();
11088|  3.46k|}
_ZZN3ada7helpers32find_authority_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlhE_clEh:
11048|  36.1k|  auto broadcast = [](uint8_t v) -> uint64_t {
11049|  36.1k|    return 0x101010101010101ull * v;
11050|  36.1k|  };
_ZN3ada7helpers24swap_bytes_if_big_endianEm:
10630|  88.7k|ada_really_inline uint64_t swap_bytes_if_big_endian(uint64_t val) noexcept {
10631|       |  // performance: under little-endian systems (most systems), this function
10632|       |  // is free (just returns the input).
10633|       |#if ADA_IS_BIG_ENDIAN
10634|       |  return swap_bytes(val);
10635|       |#else
10636|  88.7k|  return val;  // unchanged (trivial)
10637|  88.7k|#endif
10638|  88.7k|}
_ZZN3ada7helpers32find_authority_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlmE_clEm:
11042|  51.1k|  auto has_zero_byte = [](uint64_t v) {
11043|  51.1k|    return ((v - 0x0101010101010101) & ~(v)&0x8080808080808080);
11044|  51.1k|  };
_ZZN3ada7helpers32find_authority_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlmE0_clEm:
11045|  8.00k|  auto index_of_first_set_byte = [](uint64_t v) {
11046|  8.00k|    return ((((v - 1) & 0x101010101010101) * 0x101010101010101) >> 56) - 1;
11047|  8.00k|  };
_ZN3ada7helpers24find_authority_delimiterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11091|  1.72k|find_authority_delimiter(std::string_view view) noexcept {
11092|  1.72k|  auto has_zero_byte = [](uint64_t v) {
11093|  1.72k|    return ((v - 0x0101010101010101) & ~(v)&0x8080808080808080);
11094|  1.72k|  };
11095|  1.72k|  auto index_of_first_set_byte = [](uint64_t v) {
11096|  1.72k|    return ((((v - 1) & 0x101010101010101) * 0x101010101010101) >> 56) - 1;
11097|  1.72k|  };
11098|  1.72k|  auto broadcast = [](uint8_t v) -> uint64_t {
11099|  1.72k|    return 0x101010101010101ull * v;
11100|  1.72k|  };
11101|  1.72k|  size_t i = 0;
11102|  1.72k|  uint64_t mask1 = broadcast('@');
11103|  1.72k|  uint64_t mask2 = broadcast('/');
11104|  1.72k|  uint64_t mask3 = broadcast('?');
11105|       |
11106|  2.75k|  for (; i + 7 < view.size(); i += 8) {
  ------------------
  |  Branch (11106:10): [True: 2.19k, False: 564]
  ------------------
11107|  2.19k|    uint64_t word{};
11108|  2.19k|    memcpy(&word, view.data() + i, sizeof(word));
11109|  2.19k|    word = swap_bytes_if_big_endian(word);
11110|  2.19k|    uint64_t xor1 = word ^ mask1;
11111|  2.19k|    uint64_t xor2 = word ^ mask2;
11112|  2.19k|    uint64_t xor3 = word ^ mask3;
11113|  2.19k|    uint64_t is_match =
11114|  2.19k|        has_zero_byte(xor1) | has_zero_byte(xor2) | has_zero_byte(xor3);
11115|  2.19k|    if (is_match) {
  ------------------
  |  Branch (11115:9): [True: 1.16k, False: 1.02k]
  ------------------
11116|  1.16k|      return size_t(i + index_of_first_set_byte(is_match));
11117|  1.16k|    }
11118|  2.19k|  }
11119|       |
11120|    564|  if (i < view.size()) {
  ------------------
  |  Branch (11120:7): [True: 455, False: 109]
  ------------------
11121|    455|    uint64_t word{};
11122|    455|    memcpy(&word, view.data() + i, view.size() - i);
11123|    455|    word = swap_bytes_if_big_endian(word);
11124|    455|    uint64_t xor1 = word ^ mask1;
11125|    455|    uint64_t xor2 = word ^ mask2;
11126|    455|    uint64_t xor3 = word ^ mask3;
11127|    455|    uint64_t is_match =
11128|    455|        has_zero_byte(xor1) | has_zero_byte(xor2) | has_zero_byte(xor3);
11129|    455|    if (is_match) {
  ------------------
  |  Branch (11129:9): [True: 384, False: 71]
  ------------------
11130|    384|      return size_t(i + index_of_first_set_byte(is_match));
11131|    384|    }
11132|    455|  }
11133|       |
11134|    180|  return view.size();
11135|    564|}
_ZZN3ada7helpers24find_authority_delimiterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlhE_clEh:
11098|  5.17k|  auto broadcast = [](uint8_t v) -> uint64_t {
11099|  5.17k|    return 0x101010101010101ull * v;
11100|  5.17k|  };
_ZZN3ada7helpers24find_authority_delimiterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlmE_clEm:
11092|  7.93k|  auto has_zero_byte = [](uint64_t v) {
11093|  7.93k|    return ((v - 0x0101010101010101) & ~(v)&0x8080808080808080);
11094|  7.93k|  };
_ZZN3ada7helpers24find_authority_delimiterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEENKUlmE0_clEm:
11095|  1.54k|  auto index_of_first_set_byte = [](uint64_t v) {
11096|  1.54k|    return ((((v - 1) & 0x101010101010101) * 0x101010101010101) >> 56) - 1;
11097|  1.54k|  };
_ZN3ada7helpers12shorten_pathERNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEENS_6scheme4typeE:
10542|  12.2k|                                    ada::scheme::type type) noexcept {
10543|  12.2k|  size_t first_delimiter = path.find_first_of('/', 1);
10544|       |
10545|       |  // Let path be url’s path.
10546|       |  // If url’s scheme is "file", path’s size is 1, and path[0] is a normalized
10547|       |  // Windows drive letter, then return.
10548|  12.2k|  if (type == ada::scheme::type::FILE &&
  ------------------
  |  Branch (10548:7): [True: 10.2k, False: 2.04k]
  ------------------
10549|  12.2k|      first_delimiter == std::string_view::npos && !path.empty()) {
  ------------------
  |  Branch (10549:7): [True: 8.84k, False: 1.39k]
  |  Branch (10549:52): [True: 5.97k, False: 2.86k]
  ------------------
10550|  5.97k|    if (checkers::is_normalized_windows_drive_letter(
  ------------------
  |  Branch (10550:9): [True: 1.64k, False: 4.33k]
  ------------------
10551|  5.97k|            helpers::substring(path, 1))) {
10552|  1.64k|      return false;
10553|  1.64k|    }
10554|  5.97k|  }
10555|       |
10556|       |  // Remove path’s last item, if any.
10557|  10.6k|  size_t last_delimiter = path.rfind('/');
10558|  10.6k|  if (last_delimiter != std::string::npos) {
  ------------------
  |  Branch (10558:7): [True: 6.16k, False: 4.47k]
  ------------------
10559|  6.16k|    path.erase(last_delimiter);
10560|  6.16k|    return true;
10561|  6.16k|  }
10562|       |
10563|  4.47k|  return false;
10564|  10.6k|}
_ZN3ada7helpers27get_host_delimiter_locationEbRNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
10768|  42.5k|    const bool is_special, std::string_view& view) noexcept {
10769|       |  /**
10770|       |   * The spec at https://url.spec.whatwg.org/#hostname-state expects us to
10771|       |   * compute a variable called insideBrackets but this variable is only used
10772|       |   * once, to check whether a ':' character was found outside brackets. Exact
10773|       |   * text: "Otherwise, if c is U+003A (:) and insideBrackets is false, then:".
10774|       |   * It is conceptually simpler and arguably more efficient to just return a
10775|       |   * Boolean indicating whether ':' was found outside brackets.
10776|       |   */
10777|  42.5k|  const size_t view_size = view.size();
10778|  42.5k|  size_t location = 0;
10779|  42.5k|  bool found_colon = false;
10780|       |  /**
10781|       |   * Performance analysis:
10782|       |   *
10783|       |   * We are basically seeking the end of the hostname which can be indicated
10784|       |   * by the end of the view, or by one of the characters ':', '/', '?', '\\'
10785|       |   * (where '\\' is only applicable for special URLs). However, these must
10786|       |   * appear outside a bracket range. E.g., if you have [something?]fd: then the
10787|       |   * '?' does not count.
10788|       |   *
10789|       |   * So we can skip ahead to the next delimiter, as long as we include '[' in
10790|       |   * the set of delimiters, and that we handle it first.
10791|       |   *
10792|       |   * So the trick is to have a fast function that locates the next delimiter.
10793|       |   * Unless we find '[', then it only needs to be called once! Ideally, such a
10794|       |   * function would be provided by the C++ standard library, but it seems that
10795|       |   * find_first_of is not very fast, so we are forced to roll our own.
10796|       |   *
10797|       |   * We do not break into two loops for speed, but for clarity.
10798|       |   */
10799|  42.5k|  if (is_special) {
  ------------------
  |  Branch (10799:7): [True: 34.5k, False: 7.95k]
  ------------------
10800|       |    // We move to the next delimiter.
10801|  34.5k|    location = find_next_host_delimiter_special(view, location);
10802|       |    // Unless we find '[' then we are going only going to have to call
10803|       |    // find_next_host_delimiter_special once.
10804|  39.4k|    for (; location < view_size;
  ------------------
  |  Branch (10804:12): [True: 10.8k, False: 28.6k]
  ------------------
10805|  34.5k|         location = find_next_host_delimiter_special(view, location)) {
10806|  10.8k|      if (view[location] == '[') {
  ------------------
  |  Branch (10806:11): [True: 5.24k, False: 5.61k]
  ------------------
10807|  5.24k|        location = view.find(']', location);
10808|  5.24k|        if (location == std::string_view::npos) {
  ------------------
  |  Branch (10808:13): [True: 308, False: 4.93k]
  ------------------
10809|       |          // performance: view.find might get translated to a memchr, which
10810|       |          // has no notion of std::string_view::npos, so the code does not
10811|       |          // reflect the assembly.
10812|    308|          location = view_size;
10813|    308|          break;
10814|    308|        }
10815|  5.61k|      } else {
10816|  5.61k|        found_colon = view[location] == ':';
10817|  5.61k|        break;
10818|  5.61k|      }
10819|  10.8k|    }
10820|  34.5k|  } else {
10821|       |    // We move to the next delimiter.
10822|  7.95k|    location = find_next_host_delimiter(view, location);
10823|       |    // Unless we find '[' then we are going only going to have to call
10824|       |    // find_next_host_delimiter_special once.
10825|  11.3k|    for (; location < view_size;
  ------------------
  |  Branch (10825:12): [True: 5.14k, False: 6.16k]
  ------------------
10826|  7.95k|         location = find_next_host_delimiter(view, location)) {
10827|  5.14k|      if (view[location] == '[') {
  ------------------
  |  Branch (10827:11): [True: 3.53k, False: 1.60k]
  ------------------
10828|  3.53k|        location = view.find(']', location);
10829|  3.53k|        if (location == std::string_view::npos) {
  ------------------
  |  Branch (10829:13): [True: 186, False: 3.35k]
  ------------------
10830|       |          // performance: view.find might get translated to a memchr, which
10831|       |          // has no notion of std::string_view::npos, so the code does not
10832|       |          // reflect the assembly.
10833|    186|          location = view_size;
10834|    186|          break;
10835|    186|        }
10836|  3.53k|      } else {
10837|  1.60k|        found_colon = view[location] == ':';
10838|  1.60k|        break;
10839|  1.60k|      }
10840|  5.14k|    }
10841|  7.95k|  }
10842|       |  // performance: remove_suffix may translate into a single instruction.
10843|  42.5k|  view.remove_suffix(view_size - location);
10844|  42.5k|  return {location, found_colon};
10845|  42.5k|}
_ZN3ada7helpers32find_next_host_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEm:
10644|  39.4k|    std::string_view view, size_t location) noexcept {
10645|       |  // performance: if you plan to call find_next_host_delimiter more than once,
10646|       |  // you *really* want find_next_host_delimiter to be inlined, because
10647|       |  // otherwise, the constants may get reloaded each time (bad).
10648|  39.4k|  auto has_zero_byte = [](uint64_t v) {
10649|  39.4k|    return ((v - 0x0101010101010101) & ~(v)&0x8080808080808080);
10650|  39.4k|  };
10651|  39.4k|  auto index_of_first_set_byte = [](uint64_t v) {
10652|  39.4k|    return ((((v - 1) & 0x101010101010101) * 0x101010101010101) >> 56) - 1;
10653|  39.4k|  };
10654|  39.4k|  auto broadcast = [](uint8_t v) -> uint64_t {
10655|  39.4k|    return 0x101010101010101ull * v;
10656|  39.4k|  };
10657|  39.4k|  size_t i = location;
10658|  39.4k|  uint64_t mask1 = broadcast(':');
10659|  39.4k|  uint64_t mask2 = broadcast('/');
10660|  39.4k|  uint64_t mask3 = broadcast('\\');
10661|  39.4k|  uint64_t mask4 = broadcast('?');
10662|  39.4k|  uint64_t mask5 = broadcast('[');
10663|       |  // This loop will get autovectorized under many optimizing compilers,
10664|       |  // so you get actually SIMD!
10665|  74.3k|  for (; i + 7 < view.size(); i += 8) {
  ------------------
  |  Branch (10665:10): [True: 40.4k, False: 33.8k]
  ------------------
10666|  40.4k|    uint64_t word{};
10667|       |    // performance: the next memcpy translates into a single CPU instruction.
10668|  40.4k|    memcpy(&word, view.data() + i, sizeof(word));
10669|       |    // performance: on little-endian systems (most systems), this next line is
10670|       |    // free.
10671|  40.4k|    word = swap_bytes_if_big_endian(word);
10672|  40.4k|    uint64_t xor1 = word ^ mask1;
10673|  40.4k|    uint64_t xor2 = word ^ mask2;
10674|  40.4k|    uint64_t xor3 = word ^ mask3;
10675|  40.4k|    uint64_t xor4 = word ^ mask4;
10676|  40.4k|    uint64_t xor5 = word ^ mask5;
10677|  40.4k|    uint64_t is_match = has_zero_byte(xor1) | has_zero_byte(xor2) |
10678|  40.4k|                        has_zero_byte(xor3) | has_zero_byte(xor4) |
10679|  40.4k|                        has_zero_byte(xor5);
10680|  40.4k|    if (is_match) {
  ------------------
  |  Branch (10680:9): [True: 5.61k, False: 34.8k]
  ------------------
10681|  5.61k|      return size_t(i + index_of_first_set_byte(is_match));
10682|  5.61k|    }
10683|  40.4k|  }
10684|  33.8k|  if (i < view.size()) {
  ------------------
  |  Branch (10684:7): [True: 21.0k, False: 12.7k]
  ------------------
10685|  21.0k|    uint64_t word{};
10686|       |    // performance: the next memcpy translates into a function call, but
10687|       |    // that is difficult to avoid. Might be a bit expensive.
10688|  21.0k|    memcpy(&word, view.data() + i, view.size() - i);
10689|  21.0k|    word = swap_bytes_if_big_endian(word);
10690|  21.0k|    uint64_t xor1 = word ^ mask1;
10691|  21.0k|    uint64_t xor2 = word ^ mask2;
10692|  21.0k|    uint64_t xor3 = word ^ mask3;
10693|  21.0k|    uint64_t xor4 = word ^ mask4;
10694|  21.0k|    uint64_t xor5 = word ^ mask5;
10695|  21.0k|    uint64_t is_match = has_zero_byte(xor1) | has_zero_byte(xor2) |
10696|  21.0k|                        has_zero_byte(xor3) | has_zero_byte(xor4) |
10697|  21.0k|                        has_zero_byte(xor5);
10698|  21.0k|    if (is_match) {
  ------------------
  |  Branch (10698:9): [True: 5.24k, False: 15.8k]
  ------------------
10699|  5.24k|      return size_t(i + index_of_first_set_byte(is_match));
10700|  5.24k|    }
10701|  21.0k|  }
10702|  28.6k|  return view.size();
10703|  33.8k|}
_ZZN3ada7helpers32find_next_host_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEmENKUlhE_clEh:
10654|   197k|  auto broadcast = [](uint8_t v) -> uint64_t {
10655|   197k|    return 0x101010101010101ull * v;
10656|   197k|  };
_ZZN3ada7helpers32find_next_host_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEmENKUlmE_clEm:
10648|   307k|  auto has_zero_byte = [](uint64_t v) {
10649|   307k|    return ((v - 0x0101010101010101) & ~(v)&0x8080808080808080);
10650|   307k|  };
_ZZN3ada7helpers32find_next_host_delimiter_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEmENKUlmE0_clEm:
10651|  10.8k|  auto index_of_first_set_byte = [](uint64_t v) {
10652|  10.8k|    return ((((v - 1) & 0x101010101010101) * 0x101010101010101) >> 56) - 1;
10653|  10.8k|  };
_ZN3ada7helpers24find_next_host_delimiterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEm:
10709|  11.3k|                                                  size_t location) noexcept {
10710|       |  // performance: if you plan to call find_next_host_delimiter more than once,
10711|       |  // you *really* want find_next_host_delimiter to be inlined, because
10712|       |  // otherwise, the constants may get reloaded each time (bad).
10713|  11.3k|  auto has_zero_byte = [](uint64_t v) {
10714|  11.3k|    return ((v - 0x0101010101010101) & ~(v)&0x8080808080808080);
10715|  11.3k|  };
10716|  11.3k|  auto index_of_first_set_byte = [](uint64_t v) {
10717|  11.3k|    return ((((v - 1) & 0x101010101010101) * 0x101010101010101) >> 56) - 1;
10718|  11.3k|  };
10719|  11.3k|  auto broadcast = [](uint8_t v) -> uint64_t {
10720|  11.3k|    return 0x101010101010101ull * v;
10721|  11.3k|  };
10722|  11.3k|  size_t i = location;
10723|  11.3k|  uint64_t mask1 = broadcast(':');
10724|  11.3k|  uint64_t mask2 = broadcast('/');
10725|  11.3k|  uint64_t mask4 = broadcast('?');
10726|  11.3k|  uint64_t mask5 = broadcast('[');
10727|       |  // This loop will get autovectorized under many optimizing compilers,
10728|       |  // so you get actually SIMD!
10729|  16.6k|  for (; i + 7 < view.size(); i += 8) {
  ------------------
  |  Branch (10729:10): [True: 8.93k, False: 7.68k]
  ------------------
10730|  8.93k|    uint64_t word{};
10731|       |    // performance: the next memcpy translates into a single CPU instruction.
10732|  8.93k|    memcpy(&word, view.data() + i, sizeof(word));
10733|       |    // performance: on little-endian systems (most systems), this next line is
10734|       |    // free.
10735|  8.93k|    word = swap_bytes_if_big_endian(word);
10736|  8.93k|    uint64_t xor1 = word ^ mask1;
10737|  8.93k|    uint64_t xor2 = word ^ mask2;
10738|  8.93k|    uint64_t xor4 = word ^ mask4;
10739|  8.93k|    uint64_t xor5 = word ^ mask5;
10740|  8.93k|    uint64_t is_match = has_zero_byte(xor1) | has_zero_byte(xor2) |
10741|  8.93k|                        has_zero_byte(xor4) | has_zero_byte(xor5);
10742|  8.93k|    if (is_match) {
  ------------------
  |  Branch (10742:9): [True: 3.62k, False: 5.30k]
  ------------------
10743|  3.62k|      return size_t(i + index_of_first_set_byte(is_match));
10744|  3.62k|    }
10745|  8.93k|  }
10746|  7.68k|  if (i < view.size()) {
  ------------------
  |  Branch (10746:7): [True: 2.85k, False: 4.83k]
  ------------------
10747|  2.85k|    uint64_t word{};
10748|       |    // performance: the next memcpy translates into a function call, but
10749|       |    // that is difficult to avoid. Might be a bit expensive.
10750|  2.85k|    memcpy(&word, view.data() + i, view.size() - i);
10751|       |    // performance: on little-endian systems (most systems), this next line is
10752|       |    // free.
10753|  2.85k|    word = swap_bytes_if_big_endian(word);
10754|  2.85k|    uint64_t xor1 = word ^ mask1;
10755|  2.85k|    uint64_t xor2 = word ^ mask2;
10756|  2.85k|    uint64_t xor4 = word ^ mask4;
10757|  2.85k|    uint64_t xor5 = word ^ mask5;
10758|  2.85k|    uint64_t is_match = has_zero_byte(xor1) | has_zero_byte(xor2) |
10759|  2.85k|                        has_zero_byte(xor4) | has_zero_byte(xor5);
10760|  2.85k|    if (is_match) {
  ------------------
  |  Branch (10760:9): [True: 1.52k, False: 1.32k]
  ------------------
10761|  1.52k|      return size_t(i + index_of_first_set_byte(is_match));
10762|  1.52k|    }
10763|  2.85k|  }
10764|  6.16k|  return view.size();
10765|  7.68k|}
_ZZN3ada7helpers24find_next_host_delimiterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEmENKUlhE_clEh:
10719|  45.2k|  auto broadcast = [](uint8_t v) -> uint64_t {
10720|  45.2k|    return 0x101010101010101ull * v;
10721|  45.2k|  };
_ZZN3ada7helpers24find_next_host_delimiterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEmENKUlmE_clEm:
10713|  47.1k|  auto has_zero_byte = [](uint64_t v) {
10714|  47.1k|    return ((v - 0x0101010101010101) & ~(v)&0x8080808080808080);
10715|  47.1k|  };
_ZZN3ada7helpers24find_next_host_delimiterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEmENKUlmE0_clEm:
10716|  5.14k|  auto index_of_first_set_byte = [](uint64_t v) {
10717|  5.14k|    return ((((v - 1) & 0x101010101010101) * 0x101010101010101) >> 56) - 1;
10718|  5.14k|  };
_ZN3ada3url10parse_hostENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
11563|  10.1k|ada_really_inline bool url::parse_host(std::string_view input) {
11564|  10.1k|  ada_log("parse_host ", input, "[", input.size(), " bytes]");
11565|  10.1k|  if (input.empty()) {
  ------------------
  |  Branch (11565:7): [True: 13, False: 10.1k]
  ------------------
11566|     13|    return is_valid = false;
11567|     13|  }  // technically unnecessary.
11568|       |  // If input starts with U+005B ([), then:
11569|  10.1k|  if (input[0] == '[') {
  ------------------
  |  Branch (11569:7): [True: 786, False: 9.36k]
  ------------------
11570|       |    // If input does not end with U+005D (]), validation error, return failure.
11571|    786|    if (input.back() != ']') {
  ------------------
  |  Branch (11571:9): [True: 254, False: 532]
  ------------------
11572|    254|      return is_valid = false;
11573|    254|    }
11574|    532|    ada_log("parse_host ipv6");
11575|       |
11576|       |    // Return the result of IPv6 parsing input with its leading U+005B ([) and
11577|       |    // trailing U+005D (]) removed.
11578|    532|    input.remove_prefix(1);
11579|    532|    input.remove_suffix(1);
11580|    532|    return parse_ipv6(input);
11581|    786|  }
11582|       |
11583|       |  // If isNotSpecial is true, then return the result of opaque-host parsing
11584|       |  // input.
11585|  9.36k|  if (!is_special()) {
  ------------------
  |  Branch (11585:7): [True: 1.00k, False: 8.35k]
  ------------------
11586|  1.00k|    return parse_opaque_host(input);
11587|  1.00k|  }
11588|       |  // Let domain be the result of running UTF-8 decode without BOM on the
11589|       |  // percent-decoding of input. Let asciiDomain be the result of running domain
11590|       |  // to ASCII with domain and false. The most common case is an ASCII input, in
11591|       |  // which case we do not need to call the expensive 'to_ascii' if a few
11592|       |  // conditions are met: no '%' and no 'xn-' subsequence.
11593|  8.35k|  std::string buffer = std::string(input);
11594|       |  // This next function checks that the result is ascii, but we are going to
11595|       |  // to check anyhow with is_forbidden.
11596|       |  // bool is_ascii =
11597|  8.35k|  unicode::to_lower_ascii(buffer.data(), buffer.size());
11598|  8.35k|  bool is_forbidden = unicode::contains_forbidden_domain_code_point(
11599|  8.35k|      buffer.data(), buffer.size());
11600|  8.35k|  if (is_forbidden == 0 && buffer.find("xn-") == std::string_view::npos) {
  ------------------
  |  Branch (11600:7): [True: 5.50k, False: 2.85k]
  |  Branch (11600:28): [True: 5.18k, False: 326]
  ------------------
11601|       |    // fast path
11602|  5.18k|    host = std::move(buffer);
11603|  5.18k|    if (checkers::is_ipv4(host.value())) {
  ------------------
  |  Branch (11603:9): [True: 1.93k, False: 3.25k]
  ------------------
11604|  1.93k|      ada_log("parse_host fast path ipv4");
11605|  1.93k|      return parse_ipv4(host.value());
11606|  1.93k|    }
11607|  3.25k|    ada_log("parse_host fast path ", *host);
11608|  3.25k|    return true;
11609|  5.18k|  }
11610|  3.17k|  ada_log("parse_host calling to_ascii");
11611|  3.17k|  is_valid = ada::unicode::to_ascii(host, input, input.find('%'));
11612|  3.17k|  if (!is_valid) {
  ------------------
  |  Branch (11612:7): [True: 1.56k, False: 1.61k]
  ------------------
11613|  1.56k|    ada_log("parse_host to_ascii returns false");
11614|  1.56k|    return is_valid = false;
11615|  1.56k|  }
11616|       |
11617|  1.61k|  if (std::any_of(host.value().begin(), host.value().end(),
  ------------------
  |  Branch (11617:7): [True: 0, False: 1.61k]
  ------------------
11618|  1.61k|                  ada::unicode::is_forbidden_domain_code_point)) {
11619|      0|    host = std::nullopt;
11620|      0|    return is_valid = false;
11621|      0|  }
11622|       |
11623|       |  // If asciiDomain ends in a number, then return the result of IPv4 parsing
11624|       |  // asciiDomain.
11625|  1.61k|  if (checkers::is_ipv4(host.value())) {
  ------------------
  |  Branch (11625:7): [True: 226, False: 1.38k]
  ------------------
11626|    226|    ada_log("parse_host got ipv4", *host);
11627|    226|    return parse_ipv4(host.value());
11628|    226|  }
11629|       |
11630|  1.38k|  return true;
11631|  1.61k|}
_ZN3ada7unicode14to_lower_asciiEPcm:
 9797|  28.3k|constexpr bool to_lower_ascii(char* input, size_t length) noexcept {
 9798|  28.3k|  auto broadcast = [](uint8_t v) -> uint64_t {
 9799|  28.3k|    return 0x101010101010101ull * v;
 9800|  28.3k|  };
 9801|  28.3k|  uint64_t broadcast_80 = broadcast(0x80);
 9802|  28.3k|  uint64_t broadcast_Ap = broadcast(128 - 'A');
 9803|  28.3k|  uint64_t broadcast_Zp = broadcast(128 - 'Z' - 1);
 9804|  28.3k|  uint64_t non_ascii = 0;
 9805|  28.3k|  size_t i = 0;
 9806|       |
 9807|  45.9k|  for (; i + 7 < length; i += 8) {
  ------------------
  |  Branch (9807:10): [True: 17.6k, False: 28.3k]
  ------------------
 9808|  17.6k|    uint64_t word{};
 9809|  17.6k|    memcpy(&word, input + i, sizeof(word));
 9810|  17.6k|    non_ascii |= (word & broadcast_80);
 9811|  17.6k|    word ^=
 9812|  17.6k|        (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
 9813|  17.6k|    memcpy(input + i, &word, sizeof(word));
 9814|  17.6k|  }
 9815|  28.3k|  if (i < length) {
  ------------------
  |  Branch (9815:7): [True: 27.7k, False: 560]
  ------------------
 9816|  27.7k|    uint64_t word{};
 9817|  27.7k|    memcpy(&word, input + i, length - i);
 9818|  27.7k|    non_ascii |= (word & broadcast_80);
 9819|  27.7k|    word ^=
 9820|  27.7k|        (((word + broadcast_Ap) ^ (word + broadcast_Zp)) & broadcast_80) >> 2;
 9821|  27.7k|    memcpy(input + i, &word, length - i);
 9822|  27.7k|  }
 9823|  28.3k|  return non_ascii == 0;
 9824|  28.3k|}
_ZZN3ada7unicode14to_lower_asciiEPcmENKUlhE_clEh:
 9798|  84.9k|  auto broadcast = [](uint8_t v) -> uint64_t {
 9799|  84.9k|    return 0x101010101010101ull * v;
 9800|  84.9k|  };
_ZN3ada8checkers7is_ipv4ENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
    9|  20.2k|ada_really_inline ada_constexpr bool is_ipv4(std::string_view view) noexcept {
   10|  20.2k|  size_t last_dot = view.rfind('.');
   11|  20.2k|  if (last_dot == view.size() - 1) {
  ------------------
  |  Branch (11:7): [True: 2.42k, False: 17.8k]
  ------------------
   12|  2.42k|    view.remove_suffix(1);
   13|  2.42k|    last_dot = view.rfind('.');
   14|  2.42k|  }
   15|  20.2k|  std::string_view number =
   16|  20.2k|      (last_dot == std::string_view::npos) ? view : view.substr(last_dot + 1);
  ------------------
  |  Branch (16:7): [True: 16.1k, False: 4.10k]
  ------------------
   17|  20.2k|  if (number.empty()) {
  ------------------
  |  Branch (17:7): [True: 1.59k, False: 18.6k]
  ------------------
   18|  1.59k|    return false;
   19|  1.59k|  }
   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|  18.6k|  if (std::all_of(number.begin(), number.end(), ada::checkers::is_digit)) {
  ------------------
  |  Branch (23:7): [True: 4.77k, False: 13.8k]
  ------------------
   24|  4.77k|    return true;
   25|  4.77k|  }
   26|  13.8k|  return (checkers::has_hex_prefix(number) &&
  ------------------
  |  Branch (26:11): [True: 2.26k, False: 11.6k]
  ------------------
   27|  13.8k|          std::all_of(number.begin() + 2, number.end(),
  ------------------
  |  Branch (27:11): [True: 1.40k, False: 856]
  ------------------
   28|  2.26k|                      ada::unicode::is_lowercase_hex));
   29|  18.6k|}
_ZN3ada7unicode16is_lowercase_hexEc:
10147|  35.5k|ada_really_inline constexpr bool is_lowercase_hex(const char c) noexcept {
10148|  35.5k|  return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f');
  ------------------
  |  Branch (10148:11): [True: 35.2k, False: 209]
  |  Branch (10148:23): [True: 17.9k, False: 17.3k]
  |  Branch (10148:37): [True: 17.2k, False: 281]
  |  Branch (10148:49): [True: 16.7k, False: 575]
  ------------------
10149|  35.5k|}
_ZN3ada7unicode30is_forbidden_domain_code_pointEc:
 9967|   499k|    const char c) noexcept {
 9968|   499k|  return is_forbidden_domain_code_point_table[uint8_t(c)];
 9969|   499k|}
_ZN3ada7helpers6resizeERNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEm:
10612|     12|ada_really_inline void resize(std::string_view& input, size_t pos) noexcept {
10613|     12|  ADA_ASSERT_TRUE(pos <= input.size());
10614|     12|  input.remove_suffix(input.size() - pos);
10615|     12|}
_ZN3ada7unicode14percent_encodeILb1EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKhRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEE:
10221|  4.44k|                    std::string& out) {
10222|  4.44k|  ada_log("percent_encode ", input, " to output string while ",
10223|  4.44k|          append ? "appending" : "overwriting");
10224|  4.44k|  auto pointer =
10225|  4.44k|      std::find_if(input.begin(), input.end(), [character_set](const char c) {
10226|  4.44k|        return character_sets::bit_at(character_set, c);
10227|  4.44k|      });
10228|  4.44k|  ada_log("percent_encode done checking, moved to ",
10229|  4.44k|          std::distance(input.begin(), pointer));
10230|       |
10231|       |  // Optimization: Don't iterate if percent encode is not required
10232|  4.44k|  if (pointer == input.end()) {
  ------------------
  |  Branch (10232:7): [True: 2.95k, False: 1.48k]
  ------------------
10233|  2.95k|    ada_log("percent_encode encoding not needed.");
10234|  2.95k|    return false;
10235|  2.95k|  }
10236|  1.48k|  if (!append) {
  ------------------
  |  Branch (10236:7): [Folded - Ignored]
  ------------------
10237|      0|    out.clear();
10238|      0|  }
10239|  1.48k|  ada_log("percent_encode appending ", std::distance(input.begin(), pointer),
10240|  1.48k|          " bytes");
10241|  1.48k|  out.append(input.data(), std::distance(input.begin(), pointer));
10242|  1.48k|  ada_log("percent_encode processing ", std::distance(pointer, input.end()),
10243|  1.48k|          " bytes");
10244|  63.5k|  for (; pointer != input.end(); pointer++) {
  ------------------
  |  Branch (10244:10): [True: 62.0k, False: 1.48k]
  ------------------
10245|  62.0k|    if (character_sets::bit_at(character_set, *pointer)) {
  ------------------
  |  Branch (10245:9): [True: 46.3k, False: 15.7k]
  ------------------
10246|  46.3k|      out.append(character_sets::hex + uint8_t(*pointer) * 4, 3);
10247|  46.3k|    } else {
10248|  15.7k|      out += *pointer;
10249|  15.7k|    }
10250|  62.0k|  }
10251|  1.48k|  return true;
10252|  4.44k|}
_ZZN3ada7unicode14percent_encodeILb1EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKhRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEEENKUlcE_clEc:
10225|  31.5k|      std::find_if(input.begin(), input.end(), [character_set](const char c) {
10226|  31.5k|        return character_sets::bit_at(character_set, c);
10227|  31.5k|      });
_ZN3ada7helpers12shorten_pathERNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEENS_6scheme4typeE:
10567|    326|                                    ada::scheme::type type) noexcept {
10568|    326|  size_t first_delimiter = path.find_first_of('/', 1);
10569|       |
10570|       |  // Let path be url’s path.
10571|       |  // If url’s scheme is "file", path’s size is 1, and path[0] is a normalized
10572|       |  // Windows drive letter, then return.
10573|    326|  if (type == ada::scheme::type::FILE &&
  ------------------
  |  Branch (10573:7): [True: 93, False: 233]
  ------------------
10574|    326|      first_delimiter == std::string_view::npos && !path.empty()) {
  ------------------
  |  Branch (10574:7): [True: 75, False: 18]
  |  Branch (10574:52): [True: 75, False: 0]
  ------------------
10575|     75|    if (checkers::is_normalized_windows_drive_letter(
  ------------------
  |  Branch (10575:9): [True: 8, False: 67]
  ------------------
10576|     75|            helpers::substring(path, 1))) {
10577|      8|      return false;
10578|      8|    }
10579|     75|  }
10580|       |
10581|       |  // Remove path’s last item, if any.
10582|    318|  if (!path.empty()) {
  ------------------
  |  Branch (10582:7): [True: 308, False: 10]
  ------------------
10583|    308|    size_t slash_loc = path.rfind('/');
10584|    308|    if (slash_loc != std::string_view::npos) {
  ------------------
  |  Branch (10584:9): [True: 282, False: 26]
  ------------------
10585|    282|      path.remove_suffix(path.size() - slash_loc);
10586|    282|      return true;
10587|    282|    }
10588|    308|  }
10589|       |
10590|     36|  return false;
10591|    318|}
_ZN3ada14url_aggregator11copy_schemeERKS0_:
13203|    803|inline void url_aggregator::copy_scheme(const url_aggregator& u) noexcept {
13204|    803|  ada_log("url_aggregator::copy_scheme ", u.buffer);
13205|    803|  ADA_ASSERT_TRUE(validate());
13206|       |  // next line could overflow but unsigned arithmetic has well-defined
13207|       |  // overflows.
13208|    803|  uint32_t new_difference = u.components.protocol_end - components.protocol_end;
13209|    803|  type = u.type;
13210|    803|  buffer.erase(0, components.protocol_end);
13211|    803|  buffer.insert(0, u.get_protocol());
13212|    803|  components.protocol_end = u.components.protocol_end;
13213|       |
13214|       |  // No need to update the components
13215|    803|  if (new_difference == 0) {
  ------------------
  |  Branch (13215:7): [True: 118, False: 685]
  ------------------
13216|    118|    return;
13217|    118|  }
13218|       |
13219|       |  // Update the rest of the components.
13220|    685|  components.username_end += new_difference;
13221|    685|  components.host_start += new_difference;
13222|    685|  components.host_end += new_difference;
13223|    685|  components.pathname_start += new_difference;
13224|    685|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (13224:7): [True: 0, False: 685]
  ------------------
13225|      0|    components.search_start += new_difference;
13226|      0|  }
13227|    685|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (13227:7): [True: 0, False: 685]
  ------------------
13228|      0|    components.hash_start += new_difference;
13229|      0|  }
13230|    685|  ADA_ASSERT_TRUE(validate());
13231|    685|}
_ZN3ada14url_aggregator10parse_pathENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13418|  7.20k|ada_really_inline void url_aggregator::parse_path(std::string_view input) {
13419|  7.20k|  ada_log("url_aggregator::parse_path ", input);
13420|  7.20k|  ADA_ASSERT_TRUE(validate());
13421|  7.20k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13422|  7.20k|  std::string tmp_buffer;
13423|  7.20k|  std::string_view internal_input;
13424|  7.20k|  if (unicode::has_tabs_or_newline(input)) {
  ------------------
  |  Branch (13424:7): [True: 140, False: 7.06k]
  ------------------
13425|    140|    tmp_buffer = input;
13426|       |    // Optimization opportunity: Instead of copying and then pruning, we could
13427|       |    // just directly build the string from user_input.
13428|    140|    helpers::remove_ascii_tab_or_newline(tmp_buffer);
13429|    140|    internal_input = tmp_buffer;
13430|  7.06k|  } else {
13431|  7.06k|    internal_input = input;
13432|  7.06k|  }
13433|       |
13434|       |  // If url is special, then:
13435|  7.20k|  if (is_special()) {
  ------------------
  |  Branch (13435:7): [True: 5.52k, False: 1.68k]
  ------------------
13436|  5.52k|    if (internal_input.empty()) {
  ------------------
  |  Branch (13436:9): [True: 4.49k, False: 1.02k]
  ------------------
13437|  4.49k|      update_base_pathname("/");
13438|  4.49k|    } else if ((internal_input[0] == '/') || (internal_input[0] == '\\')) {
  ------------------
  |  Branch (13438:16): [True: 21, False: 1.00k]
  |  Branch (13438:46): [True: 3, False: 1.00k]
  ------------------
13439|     24|      consume_prepared_path(internal_input.substr(1));
13440|  1.00k|    } else {
13441|  1.00k|      consume_prepared_path(internal_input);
13442|  1.00k|    }
13443|  5.52k|  } else if (!internal_input.empty()) {
  ------------------
  |  Branch (13443:14): [True: 345, False: 1.33k]
  ------------------
13444|    345|    if (internal_input[0] == '/') {
  ------------------
  |  Branch (13444:9): [True: 32, False: 313]
  ------------------
13445|     32|      consume_prepared_path(internal_input.substr(1));
13446|    313|    } else {
13447|    313|      consume_prepared_path(internal_input);
13448|    313|    }
13449|  1.33k|  } else {
13450|       |    // Non-special URLs with an empty host can have their paths erased
13451|       |    // Path-only URLs cannot have their paths erased
13452|  1.33k|    if (components.host_start == components.host_end && !has_authority()) {
  ------------------
  |  Branch (13452:9): [True: 1.30k, False: 32]
  |  Branch (13452:57): [True: 1.17k, False: 130]
  ------------------
13453|  1.17k|      update_base_pathname("/");
13454|  1.17k|    }
13455|  1.33k|  }
13456|  7.20k|  ADA_ASSERT_TRUE(validate());
13457|  7.20k|}
_ZN3ada14url_aggregator10parse_hostENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13516|  17.8k|ada_really_inline bool url_aggregator::parse_host(std::string_view input) {
13517|  17.8k|  ada_log("url_aggregator:parse_host ", input, "[", input.size(), " bytes]");
13518|  17.8k|  ADA_ASSERT_TRUE(validate());
13519|  17.8k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13520|  17.8k|  if (input.empty()) {
  ------------------
  |  Branch (13520:7): [True: 31, False: 17.7k]
  ------------------
13521|     31|    return is_valid = false;
13522|     31|  }  // technically unnecessary.
13523|       |  // If input starts with U+005B ([), then:
13524|  17.7k|  if (input[0] == '[') {
  ------------------
  |  Branch (13524:7): [True: 1.30k, False: 16.4k]
  ------------------
13525|       |    // If input does not end with U+005D (]), validation error, return failure.
13526|  1.30k|    if (input.back() != ']') {
  ------------------
  |  Branch (13526:9): [True: 385, False: 922]
  ------------------
13527|    385|      return is_valid = false;
13528|    385|    }
13529|    922|    ada_log("parse_host ipv6");
13530|       |
13531|       |    // Return the result of IPv6 parsing input with its leading U+005B ([) and
13532|       |    // trailing U+005D (]) removed.
13533|    922|    input.remove_prefix(1);
13534|    922|    input.remove_suffix(1);
13535|    922|    return parse_ipv6(input);
13536|  1.30k|  }
13537|       |
13538|       |  // If isNotSpecial is true, then return the result of opaque-host parsing
13539|       |  // input.
13540|  16.4k|  if (!is_special()) {
  ------------------
  |  Branch (13540:7): [True: 1.00k, False: 15.4k]
  ------------------
13541|  1.00k|    return parse_opaque_host(input);
13542|  1.00k|  }
13543|       |  // Let domain be the result of running UTF-8 decode without BOM on the
13544|       |  // percent-decoding of input. Let asciiDomain be the result of running domain
13545|       |  // to ASCII with domain and false. The most common case is an ASCII input, in
13546|       |  // which case we do not need to call the expensive 'to_ascii' if a few
13547|       |  // conditions are met: no '%' and no 'xn-' subsequence.
13548|       |
13549|       |  // Often, the input does not contain any forbidden code points, and no upper
13550|       |  // case ASCII letter, then we can just copy it to the buffer. We want to
13551|       |  // optimize for such a common case.
13552|  15.4k|  uint8_t is_forbidden_or_upper =
13553|  15.4k|      unicode::contains_forbidden_domain_code_point_or_upper(input.data(),
13554|  15.4k|                                                             input.size());
13555|       |  // Minor optimization opportunity:
13556|       |  // contains_forbidden_domain_code_point_or_upper could be extend to check for
13557|       |  // the presence of characters that cannot appear in the ipv4 address and we
13558|       |  // could also check whether x and n and - are present, and so we could skip
13559|       |  // some of the checks below. However, the gains are likely to be small, and
13560|       |  // the code would be more complex.
13561|  15.4k|  if (is_forbidden_or_upper == 0 &&
  ------------------
  |  Branch (13561:7): [True: 8.66k, False: 6.80k]
  ------------------
13562|  15.4k|      input.find("xn-") == std::string_view::npos) {
  ------------------
  |  Branch (13562:7): [True: 7.91k, False: 748]
  ------------------
13563|       |    // fast path
13564|  7.91k|    update_base_hostname(input);
13565|  7.91k|    if (checkers::is_ipv4(get_hostname())) {
  ------------------
  |  Branch (13565:9): [True: 3.21k, False: 4.69k]
  ------------------
13566|  3.21k|      ada_log("parse_host fast path ipv4");
13567|  3.21k|      return parse_ipv4(get_hostname());
13568|  3.21k|    }
13569|  4.69k|    ada_log("parse_host fast path ", get_hostname());
13570|  4.69k|    return true;
13571|  7.91k|  }
13572|       |  // We have encountered at least one forbidden code point or the input contains
13573|       |  // 'xn-' (case insensitive), so we need to call 'to_ascii' to perform the full
13574|       |  // conversion.
13575|       |
13576|  7.54k|  ada_log("parse_host calling to_ascii");
13577|  7.54k|  std::optional<std::string> host = std::string(get_hostname());
13578|  7.54k|  is_valid = ada::unicode::to_ascii(host, input, input.find('%'));
13579|  7.54k|  if (!is_valid) {
  ------------------
  |  Branch (13579:7): [True: 1.99k, False: 5.55k]
  ------------------
13580|  1.99k|    ada_log("parse_host to_ascii returns false");
13581|  1.99k|    return is_valid = false;
13582|  1.99k|  }
13583|       |
13584|  5.55k|  if (std::any_of(host.value().begin(), host.value().end(),
  ------------------
  |  Branch (13584:7): [True: 0, False: 5.55k]
  ------------------
13585|  5.55k|                  ada::unicode::is_forbidden_domain_code_point)) {
13586|      0|    return is_valid = false;
13587|      0|  }
13588|       |
13589|       |  // If asciiDomain ends in a number, then return the result of IPv4 parsing
13590|       |  // asciiDomain.
13591|  5.55k|  if (checkers::is_ipv4(host.value())) {
  ------------------
  |  Branch (13591:7): [True: 808, False: 4.74k]
  ------------------
13592|    808|    ada_log("parse_host got ipv4", *host);
13593|    808|    return parse_ipv4(host.value());
13594|    808|  }
13595|       |
13596|  4.74k|  update_base_hostname(host.value());
13597|  4.74k|  ADA_ASSERT_TRUE(validate());
13598|  4.74k|  return true;
13599|  5.55k|}
_ZN3ada7unicode45contains_forbidden_domain_code_point_or_upperEPKcm:
10006|  15.4k|                                              size_t length) noexcept {
10007|  15.4k|  size_t i = 0;
10008|  15.4k|  uint8_t accumulator{};
10009|  87.7k|  for (; i + 4 <= length; i += 4) {
  ------------------
  |  Branch (10009:10): [True: 72.3k, False: 15.4k]
  ------------------
10010|  72.3k|    accumulator |=
10011|  72.3k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i])];
10012|  72.3k|    accumulator |=
10013|  72.3k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 1])];
10014|  72.3k|    accumulator |=
10015|  72.3k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 2])];
10016|  72.3k|    accumulator |=
10017|  72.3k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i + 3])];
10018|  72.3k|  }
10019|  37.6k|  for (; i < length; i++) {
  ------------------
  |  Branch (10019:10): [True: 22.1k, False: 15.4k]
  ------------------
10020|  22.1k|    accumulator |=
10021|  22.1k|        is_forbidden_domain_code_point_table_or_upper[uint8_t(input[i])];
10022|  22.1k|  }
10023|  15.4k|  return accumulator;
10024|  15.4k|}
_ZN3ada14url_aggregator21consume_prepared_pathENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
14631|  8.63k|inline void url_aggregator::consume_prepared_path(std::string_view input) {
14632|  8.63k|  ada_log("url_aggregator::consume_prepared_path ", input);
14633|       |  /***
14634|       |   * This is largely duplicated code from helpers::parse_prepared_path, which is
14635|       |   * unfortunate. This particular function is nearly identical, except that it
14636|       |   * is a method on url_aggregator. The idea is that the trivial path (which is
14637|       |   * very common) merely appends to the buffer. This is the same trivial path as
14638|       |   * with helpers::parse_prepared_path, except that we have the additional check
14639|       |   * for is_at_path(). Otherwise, we grab a copy of the current path and we
14640|       |   * modify it, and then insert it back into the buffer.
14641|       |   */
14642|  8.63k|  uint8_t accumulator = checkers::path_signature(input);
14643|       |  // Let us first detect a trivial case.
14644|       |  // If it is special, we check that we have no dot, no %,  no \ and no
14645|       |  // character needing percent encoding. Otherwise, we check that we have no %,
14646|       |  // no dot, and no character needing percent encoding.
14647|  8.63k|  constexpr uint8_t need_encoding = 1;
14648|  8.63k|  constexpr uint8_t backslash_char = 2;
14649|  8.63k|  constexpr uint8_t dot_char = 4;
14650|  8.63k|  constexpr uint8_t percent_char = 8;
14651|  8.63k|  bool special = type != ada::scheme::NOT_SPECIAL;
14652|  8.63k|  bool may_need_slow_file_handling = (type == ada::scheme::type::FILE &&
  ------------------
  |  Branch (14652:39): [True: 3.14k, False: 5.49k]
  ------------------
14653|  8.63k|                                      checkers::is_windows_drive_letter(input));
  ------------------
  |  Branch (14653:39): [True: 127, False: 3.01k]
  ------------------
14654|  8.63k|  bool trivial_path =
14655|  8.63k|      (special ? (accumulator == 0)
  ------------------
  |  Branch (14655:7): [True: 5.15k, False: 3.47k]
  |  Branch (14655:8): [True: 5.01k, False: 3.61k]
  ------------------
14656|  8.63k|               : ((accumulator & (need_encoding | dot_char | percent_char)) ==
14657|  3.61k|                  0)) &&
14658|  8.63k|      (!may_need_slow_file_handling);
  ------------------
  |  Branch (14658:7): [True: 5.08k, False: 73]
  ------------------
14659|  8.63k|  if (accumulator == dot_char && !may_need_slow_file_handling) {
  ------------------
  |  Branch (14659:7): [True: 1.12k, False: 7.51k]
  |  Branch (14659:34): [True: 1.08k, False: 38]
  ------------------
14660|       |    // '4' means that we have at least one dot, but nothing that requires
14661|       |    // percent encoding or decoding. The only part that is not trivial is
14662|       |    // that we may have single dots and double dots path segments.
14663|       |    // If we have such segments, then we either have a path that begins
14664|       |    // with '.' (easy to check), or we have the sequence './'.
14665|       |    // Note: input cannot be empty, it must at least contain one character ('.')
14666|       |    // Note: we know that '\' is not present.
14667|  1.08k|    if (input[0] != '.') {
  ------------------
  |  Branch (14667:9): [True: 563, False: 519]
  ------------------
14668|    563|      size_t slashdot = input.find("/.");
14669|    563|      if (slashdot == std::string_view::npos) {  // common case
  ------------------
  |  Branch (14669:11): [True: 150, False: 413]
  ------------------
14670|    150|        trivial_path = true;
14671|    413|      } else {  // uncommon
14672|       |        // only three cases matter: /./, /.. or a final /
14673|    413|        trivial_path =
14674|    413|            !(slashdot + 2 == input.size() || input[slashdot + 2] == '.' ||
  ------------------
  |  Branch (14674:15): [True: 163, False: 250]
  |  Branch (14674:47): [True: 208, False: 42]
  ------------------
14675|    413|              input[slashdot + 2] == '/');
  ------------------
  |  Branch (14675:15): [True: 21, False: 21]
  ------------------
14676|    413|      }
14677|    563|    }
14678|  1.08k|  }
14679|  8.63k|  if (trivial_path && is_at_path()) {
  ------------------
  |  Branch (14679:7): [True: 5.25k, False: 3.37k]
  |  Branch (14679:23): [True: 5.12k, False: 130]
  ------------------
14680|  5.12k|    ada_log("parse_path trivial");
14681|  5.12k|    buffer += '/';
14682|  5.12k|    buffer += input;
14683|  5.12k|    return;
14684|  5.12k|  }
14685|  3.50k|  std::string path = std::string(get_pathname());
14686|       |  // We are going to need to look a bit at the path, but let us see if we can
14687|       |  // ignore percent encoding *and* backslashes *and* percent characters.
14688|       |  // Except for the trivial case, this is likely to capture 99% of paths out
14689|       |  // there.
14690|  3.50k|  bool fast_path =
14691|  3.50k|      (special &&
  ------------------
  |  Branch (14691:8): [True: 2.21k, False: 1.29k]
  ------------------
14692|  3.50k|       (accumulator & (need_encoding | backslash_char | percent_char)) == 0) &&
  ------------------
  |  Branch (14692:8): [True: 866, False: 1.34k]
  ------------------
14693|  3.50k|      (type != ada::scheme::type::FILE);
  ------------------
  |  Branch (14693:7): [True: 550, False: 316]
  ------------------
14694|  3.50k|  if (fast_path) {
  ------------------
  |  Branch (14694:7): [True: 550, False: 2.95k]
  ------------------
14695|    550|    ada_log("parse_prepared_path fast");
14696|       |    // Here we don't need to worry about \ or percent encoding.
14697|       |    // We also do not have a file protocol. We might have dots, however,
14698|       |    // but dots must as appear as '.', and they cannot be encoded because
14699|       |    // the symbol '%' is not present.
14700|    550|    size_t previous_location = 0;  // We start at 0.
14701|  4.39k|    do {
14702|  4.39k|      size_t new_location = input.find('/', previous_location);
14703|       |      // std::string_view path_view = input;
14704|       |      //  We process the last segment separately:
14705|  4.39k|      if (new_location == std::string_view::npos) {
  ------------------
  |  Branch (14705:11): [True: 550, False: 3.84k]
  ------------------
14706|    550|        std::string_view path_view = input.substr(previous_location);
14707|    550|        if (path_view == "..") {  // The path ends with ..
  ------------------
  |  Branch (14707:13): [True: 73, False: 477]
  ------------------
14708|       |          // e.g., if you receive ".." with an empty path, you go to "/".
14709|     73|          if (path.empty()) {
  ------------------
  |  Branch (14709:15): [True: 27, False: 46]
  ------------------
14710|     27|            path = '/';
14711|     27|            update_base_pathname(path);
14712|     27|            return;
14713|     27|          }
14714|       |          // Fast case where we have nothing to do:
14715|     46|          if (path.back() == '/') {
  ------------------
  |  Branch (14715:15): [True: 21, False: 25]
  ------------------
14716|     21|            update_base_pathname(path);
14717|     21|            return;
14718|     21|          }
14719|       |          // If you have the path "/joe/myfriend",
14720|       |          // then you delete 'myfriend'.
14721|     25|          path.resize(path.rfind('/') + 1);
14722|     25|          update_base_pathname(path);
14723|     25|          return;
14724|     46|        }
14725|    477|        path += '/';
14726|    477|        if (path_view != ".") {
  ------------------
  |  Branch (14726:13): [True: 334, False: 143]
  ------------------
14727|    334|          path.append(path_view);
14728|    334|        }
14729|    477|        update_base_pathname(path);
14730|    477|        return;
14731|  3.84k|      } else {
14732|       |        // This is a non-final segment.
14733|  3.84k|        std::string_view path_view =
14734|  3.84k|            input.substr(previous_location, new_location - previous_location);
14735|  3.84k|        previous_location = new_location + 1;
14736|  3.84k|        if (path_view == "..") {
  ------------------
  |  Branch (14736:13): [True: 672, False: 3.17k]
  ------------------
14737|    672|          size_t last_delimiter = path.rfind('/');
14738|    672|          if (last_delimiter != std::string::npos) {
  ------------------
  |  Branch (14738:15): [True: 353, False: 319]
  ------------------
14739|    353|            path.erase(last_delimiter);
14740|    353|          }
14741|  3.17k|        } else if (path_view != ".") {
  ------------------
  |  Branch (14741:20): [True: 2.76k, False: 408]
  ------------------
14742|  2.76k|          path += '/';
14743|  2.76k|          path.append(path_view);
14744|  2.76k|        }
14745|  3.84k|      }
14746|  4.39k|    } while (true);
  ------------------
  |  Branch (14746:14): [Folded - Ignored]
  ------------------
14747|  2.95k|  } else {
14748|  2.95k|    ada_log("parse_path slow");
14749|       |    // we have reached the general case
14750|  2.95k|    bool needs_percent_encoding = (accumulator & 1);
14751|  2.95k|    std::string path_buffer_tmp;
14752|  20.4k|    do {
14753|  20.4k|      size_t location = (special && (accumulator & 2))
  ------------------
  |  Branch (14753:26): [True: 13.2k, False: 7.17k]
  |  Branch (14753:37): [True: 2.20k, False: 11.0k]
  ------------------
14754|  20.4k|                            ? input.find_first_of("/\\")
14755|  20.4k|                            : input.find('/');
14756|  20.4k|      std::string_view path_view = input;
14757|  20.4k|      if (location != std::string_view::npos) {
  ------------------
  |  Branch (14757:11): [True: 17.4k, False: 2.95k]
  ------------------
14758|  17.4k|        path_view.remove_suffix(path_view.size() - location);
14759|  17.4k|        input.remove_prefix(location + 1);
14760|  17.4k|      }
14761|       |      // path_buffer is either path_view or it might point at a percent encoded
14762|       |      // temporary string.
14763|  20.4k|      std::string_view path_buffer =
14764|  20.4k|          (needs_percent_encoding &&
  ------------------
  |  Branch (14764:12): [True: 11.8k, False: 8.52k]
  ------------------
14765|  20.4k|           ada::unicode::percent_encode<false>(
  ------------------
  |  Branch (14765:12): [True: 4.55k, False: 7.34k]
  ------------------
14766|  11.8k|               path_view, character_sets::PATH_PERCENT_ENCODE, path_buffer_tmp))
14767|  20.4k|              ? path_buffer_tmp
14768|  20.4k|              : path_view;
14769|  20.4k|      if (unicode::is_double_dot_path_segment(path_buffer)) {
  ------------------
  |  Branch (14769:11): [True: 4.53k, False: 15.8k]
  ------------------
14770|  4.53k|        if ((helpers::shorten_path(path, type) || special) &&
  ------------------
  |  Branch (14770:14): [True: 2.20k, False: 2.32k]
  |  Branch (14770:51): [True: 1.67k, False: 649]
  ------------------
14771|  4.53k|            location == std::string_view::npos) {
  ------------------
  |  Branch (14771:13): [True: 277, False: 3.60k]
  ------------------
14772|    277|          path += '/';
14773|    277|        }
14774|  15.8k|      } else if (unicode::is_single_dot_path_segment(path_buffer) &&
  ------------------
  |  Branch (14774:18): [True: 1.51k, False: 14.3k]
  ------------------
14775|  15.8k|                 (location == std::string_view::npos)) {
  ------------------
  |  Branch (14775:18): [True: 124, False: 1.39k]
  ------------------
14776|    124|        path += '/';
14777|    124|      }
14778|       |      // Otherwise, if path_buffer is not a single-dot path segment, then:
14779|  15.7k|      else if (!unicode::is_single_dot_path_segment(path_buffer)) {
  ------------------
  |  Branch (14779:16): [True: 14.3k, False: 1.39k]
  ------------------
14780|       |        // If url’s scheme is "file", url’s path is empty, and path_buffer is a
14781|       |        // Windows drive letter, then replace the second code point in
14782|       |        // path_buffer with U+003A (:).
14783|  14.3k|        if (type == ada::scheme::type::FILE && path.empty() &&
  ------------------
  |  Branch (14783:13): [True: 4.59k, False: 9.77k]
  |  Branch (14783:48): [True: 2.50k, False: 2.09k]
  ------------------
14784|  14.3k|            checkers::is_windows_drive_letter(path_buffer)) {
  ------------------
  |  Branch (14784:13): [True: 138, False: 2.36k]
  ------------------
14785|    138|          path += '/';
14786|    138|          path += path_buffer[0];
14787|    138|          path += ':';
14788|    138|          path_buffer.remove_prefix(2);
14789|    138|          path.append(path_buffer);
14790|  14.2k|        } else {
14791|       |          // Append path_buffer to url’s path.
14792|  14.2k|          path += '/';
14793|  14.2k|          path.append(path_buffer);
14794|  14.2k|        }
14795|  14.3k|      }
14796|  20.4k|      if (location == std::string_view::npos) {
  ------------------
  |  Branch (14796:11): [True: 2.95k, False: 17.4k]
  ------------------
14797|  2.95k|        update_base_pathname(path);
14798|  2.95k|        return;
14799|  2.95k|      }
14800|  20.4k|    } while (true);
  ------------------
  |  Branch (14800:14): [Folded - Ignored]
  ------------------
14801|  2.95k|  }
14802|  3.50k|}
parse.cc:_ZZN3ada4idna14is_label_validENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEEENK3$_2clEj:
 9390|  2.35k|      auto is_l_or_d = [](uint32_t code) {
 9391|  2.35k|        return std::binary_search(std::begin(L), std::end(L), code) ||
  ------------------
  |  Branch (9391:16): [True: 293, False: 2.06k]
  ------------------
 9392|  2.35k|               std::binary_search(std::begin(D), std::end(D), code);
  ------------------
  |  Branch (9392:16): [True: 633, False: 1.43k]
  ------------------
 9393|  2.35k|      };
parse.cc:_ZZN3ada4idna14is_label_validENSt3__117basic_string_viewIDiNS1_11char_traitsIDiEEEEENK3$_3clEj:
 9394|  1.84k|      auto is_r_or_d = [](uint32_t code) {
 9395|  1.84k|        return std::binary_search(std::begin(R), std::end(R), code) ||
  ------------------
  |  Branch (9395:16): [True: 283, False: 1.56k]
  ------------------
 9396|  1.84k|               std::binary_search(std::begin(D), std::end(D), code);
  ------------------
  |  Branch (9396:16): [True: 470, False: 1.09k]
  ------------------
 9397|  1.84k|      };
parse.cc:_ZZN3ada7unicode14percent_encodeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKhENK3$_4clEc:
10196|   152k|      std::find_if(input.begin(), input.end(), [character_set](const char c) {
10197|   152k|        return character_sets::bit_at(character_set, c);
10198|   152k|      });
_ZN3ada3url20set_host_or_hostnameILb0EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE:
11838|  8.27k|bool url::set_host_or_hostname(const std::string_view input) {
11839|  8.27k|  if (has_opaque_path) {
  ------------------
  |  Branch (11839:7): [True: 1.06k, False: 7.20k]
  ------------------
11840|  1.06k|    return false;
11841|  1.06k|  }
11842|       |
11843|  7.20k|  std::optional<std::string> previous_host = host;
11844|  7.20k|  std::optional<uint16_t> previous_port = port;
11845|       |
11846|  7.20k|  size_t host_end_pos = input.find('#');
11847|  7.20k|  std::string _host(input.data(), host_end_pos != std::string_view::npos
  ------------------
  |  Branch (11847:35): [True: 47, False: 7.15k]
  ------------------
11848|  7.20k|                                      ? host_end_pos
11849|  7.20k|                                      : input.size());
11850|  7.20k|  helpers::remove_ascii_tab_or_newline(_host);
11851|  7.20k|  std::string_view new_host(_host);
11852|       |
11853|       |  // If url's scheme is "file", then set state to file host state, instead of
11854|       |  // host state.
11855|  7.20k|  if (type != ada::scheme::type::FILE) {
  ------------------
  |  Branch (11855:7): [True: 5.71k, False: 1.48k]
  ------------------
11856|  5.71k|    std::string_view host_view(_host.data(), _host.length());
11857|  5.71k|    auto [location, found_colon] =
11858|  5.71k|        helpers::get_host_delimiter_location(is_special(), host_view);
11859|       |
11860|       |    // Otherwise, if c is U+003A (:) and insideBrackets is false, then:
11861|       |    // Note: the 'found_colon' value is true if and only if a colon was
11862|       |    // encountered while not inside brackets.
11863|  5.71k|    if (found_colon) {
  ------------------
  |  Branch (11863:9): [True: 111, False: 5.60k]
  ------------------
11864|    111|      if (override_hostname) {
  ------------------
  |  Branch (11864:11): [Folded - Ignored]
  ------------------
11865|      0|        return false;
11866|      0|      }
11867|    111|      std::string_view buffer = new_host.substr(location + 1);
11868|    111|      if (!buffer.empty()) {
  ------------------
  |  Branch (11868:11): [True: 99, False: 12]
  ------------------
11869|     99|        set_port(buffer);
11870|     99|      }
11871|    111|    }
11872|       |    // If url is special and host_view is the empty string, validation error,
11873|       |    // return failure. Otherwise, if state override is given, host_view is the
11874|       |    // empty string, and either url includes credentials or url’s port is
11875|       |    // non-null, return.
11876|  5.60k|    else if (host_view.empty() &&
  ------------------
  |  Branch (11876:14): [True: 4.14k, False: 1.46k]
  ------------------
11877|  5.60k|             (is_special() || has_credentials() || port.has_value())) {
  ------------------
  |  Branch (11877:15): [True: 2.97k, False: 1.16k]
  |  Branch (11877:31): [True: 12, False: 1.15k]
  |  Branch (11877:52): [True: 57, False: 1.09k]
  ------------------
11878|  3.04k|      return false;
11879|  3.04k|    }
11880|       |
11881|       |    // Let host be the result of host parsing host_view with url is not special.
11882|  2.67k|    if (host_view.empty()) {
  ------------------
  |  Branch (11882:9): [True: 1.13k, False: 1.53k]
  ------------------
11883|  1.13k|      host = "";
11884|  1.13k|      return true;
11885|  1.13k|    }
11886|       |
11887|  1.53k|    bool succeeded = parse_host(host_view);
11888|  1.53k|    if (!succeeded) {
  ------------------
  |  Branch (11888:9): [True: 538, False: 995]
  ------------------
11889|    538|      host = previous_host;
11890|    538|      update_base_port(previous_port);
11891|    538|    }
11892|  1.53k|    return succeeded;
11893|  2.67k|  }
11894|       |
11895|  1.48k|  size_t location = new_host.find_first_of("/\\?");
11896|  1.48k|  if (location != std::string_view::npos) {
  ------------------
  |  Branch (11896:7): [True: 296, False: 1.19k]
  ------------------
11897|    296|    new_host.remove_suffix(new_host.length() - location);
11898|    296|  }
11899|       |
11900|  1.48k|  if (new_host.empty()) {
  ------------------
  |  Branch (11900:7): [True: 1.01k, False: 472]
  ------------------
11901|       |    // Set url’s host to the empty string.
11902|  1.01k|    host = "";
11903|  1.01k|  } else {
11904|       |    // Let host be the result of host parsing buffer with url is not special.
11905|    472|    if (!parse_host(new_host)) {
  ------------------
  |  Branch (11905:9): [True: 193, False: 279]
  ------------------
11906|    193|      host = previous_host;
11907|    193|      update_base_port(previous_port);
11908|    193|      return false;
11909|    193|    }
11910|       |
11911|       |    // If host is "localhost", then set host to the empty string.
11912|    279|    if (host.has_value() && host.value() == "localhost") {
  ------------------
  |  Branch (11912:9): [True: 279, False: 0]
  |  Branch (11912:29): [True: 1, False: 278]
  ------------------
11913|      1|      host = "";
11914|      1|    }
11915|    279|  }
11916|  1.29k|  return true;
11917|  1.48k|}
_ZN3ada3url20set_host_or_hostnameILb1EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE:
11838|  8.27k|bool url::set_host_or_hostname(const std::string_view input) {
11839|  8.27k|  if (has_opaque_path) {
  ------------------
  |  Branch (11839:7): [True: 1.06k, False: 7.20k]
  ------------------
11840|  1.06k|    return false;
11841|  1.06k|  }
11842|       |
11843|  7.20k|  std::optional<std::string> previous_host = host;
11844|  7.20k|  std::optional<uint16_t> previous_port = port;
11845|       |
11846|  7.20k|  size_t host_end_pos = input.find('#');
11847|  7.20k|  std::string _host(input.data(), host_end_pos != std::string_view::npos
  ------------------
  |  Branch (11847:35): [True: 47, False: 7.15k]
  ------------------
11848|  7.20k|                                      ? host_end_pos
11849|  7.20k|                                      : input.size());
11850|  7.20k|  helpers::remove_ascii_tab_or_newline(_host);
11851|  7.20k|  std::string_view new_host(_host);
11852|       |
11853|       |  // If url's scheme is "file", then set state to file host state, instead of
11854|       |  // host state.
11855|  7.20k|  if (type != ada::scheme::type::FILE) {
  ------------------
  |  Branch (11855:7): [True: 5.71k, False: 1.48k]
  ------------------
11856|  5.71k|    std::string_view host_view(_host.data(), _host.length());
11857|  5.71k|    auto [location, found_colon] =
11858|  5.71k|        helpers::get_host_delimiter_location(is_special(), host_view);
11859|       |
11860|       |    // Otherwise, if c is U+003A (:) and insideBrackets is false, then:
11861|       |    // Note: the 'found_colon' value is true if and only if a colon was
11862|       |    // encountered while not inside brackets.
11863|  5.71k|    if (found_colon) {
  ------------------
  |  Branch (11863:9): [True: 111, False: 5.60k]
  ------------------
11864|    111|      if (override_hostname) {
  ------------------
  |  Branch (11864:11): [Folded - Ignored]
  ------------------
11865|    111|        return false;
11866|    111|      }
11867|      0|      std::string_view buffer = new_host.substr(location + 1);
11868|      0|      if (!buffer.empty()) {
  ------------------
  |  Branch (11868:11): [True: 0, False: 0]
  ------------------
11869|      0|        set_port(buffer);
11870|      0|      }
11871|      0|    }
11872|       |    // If url is special and host_view is the empty string, validation error,
11873|       |    // return failure. Otherwise, if state override is given, host_view is the
11874|       |    // empty string, and either url includes credentials or url’s port is
11875|       |    // non-null, return.
11876|  5.60k|    else if (host_view.empty() &&
  ------------------
  |  Branch (11876:14): [True: 4.14k, False: 1.46k]
  ------------------
11877|  5.60k|             (is_special() || has_credentials() || port.has_value())) {
  ------------------
  |  Branch (11877:15): [True: 2.97k, False: 1.16k]
  |  Branch (11877:31): [True: 12, False: 1.15k]
  |  Branch (11877:52): [True: 57, False: 1.09k]
  ------------------
11878|  3.04k|      return false;
11879|  3.04k|    }
11880|       |
11881|       |    // Let host be the result of host parsing host_view with url is not special.
11882|  2.55k|    if (host_view.empty()) {
  ------------------
  |  Branch (11882:9): [True: 1.09k, False: 1.46k]
  ------------------
11883|  1.09k|      host = "";
11884|  1.09k|      return true;
11885|  1.09k|    }
11886|       |
11887|  1.46k|    bool succeeded = parse_host(host_view);
11888|  1.46k|    if (!succeeded) {
  ------------------
  |  Branch (11888:9): [True: 519, False: 941]
  ------------------
11889|    519|      host = previous_host;
11890|    519|      update_base_port(previous_port);
11891|    519|    }
11892|  1.46k|    return succeeded;
11893|  2.55k|  }
11894|       |
11895|  1.48k|  size_t location = new_host.find_first_of("/\\?");
11896|  1.48k|  if (location != std::string_view::npos) {
  ------------------
  |  Branch (11896:7): [True: 296, False: 1.19k]
  ------------------
11897|    296|    new_host.remove_suffix(new_host.length() - location);
11898|    296|  }
11899|       |
11900|  1.48k|  if (new_host.empty()) {
  ------------------
  |  Branch (11900:7): [True: 1.01k, False: 472]
  ------------------
11901|       |    // Set url’s host to the empty string.
11902|  1.01k|    host = "";
11903|  1.01k|  } else {
11904|       |    // Let host be the result of host parsing buffer with url is not special.
11905|    472|    if (!parse_host(new_host)) {
  ------------------
  |  Branch (11905:9): [True: 193, False: 279]
  ------------------
11906|    193|      host = previous_host;
11907|    193|      update_base_port(previous_port);
11908|    193|      return false;
11909|    193|    }
11910|       |
11911|       |    // If host is "localhost", then set host to the empty string.
11912|    279|    if (host.has_value() && host.value() == "localhost") {
  ------------------
  |  Branch (11912:9): [True: 279, False: 0]
  |  Branch (11912:29): [True: 1, False: 278]
  ------------------
11913|      1|      host = "";
11914|      1|    }
11915|    279|  }
11916|  1.29k|  return true;
11917|  1.48k|}
_ZN3ada7helpers38strip_trailing_spaces_from_opaque_pathINS_3urlEEEvRT_:
11027|  10.4k|    url_type& url) noexcept {
11028|  10.4k|  ada_log("helpers::strip_trailing_spaces_from_opaque_path");
11029|  10.4k|  if (!url.has_opaque_path) return;
  ------------------
  |  Branch (11029:7): [True: 8.66k, False: 1.82k]
  ------------------
11030|  1.82k|  if (url.has_hash()) return;
  ------------------
  |  Branch (11030:7): [True: 84, False: 1.73k]
  ------------------
11031|  1.73k|  if (url.has_search()) return;
  ------------------
  |  Branch (11031:7): [True: 0, False: 1.73k]
  ------------------
11032|       |
11033|  1.73k|  auto path = std::string(url.get_pathname());
11034|  2.60k|  while (!path.empty() && path.back() == ' ') {
  ------------------
  |  Branch (11034:10): [True: 1.90k, False: 698]
  |  Branch (11034:27): [True: 868, False: 1.03k]
  ------------------
11035|    868|    path.resize(path.size() - 1);
11036|    868|  }
11037|  1.73k|  url.update_base_pathname(path);
11038|  1.73k|}
_ZN3ada3url12parse_schemeILb1EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE:
11470|    360|ada_really_inline bool url::parse_scheme(const std::string_view input) {
11471|    360|  auto parsed_type = ada::scheme::get_scheme_type(input);
11472|    360|  bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL);
11473|       |  /**
11474|       |   * In the common case, we will immediately recognize a special scheme (e.g.,
11475|       |   *http, https), in which case, we can go really fast.
11476|       |   **/
11477|    360|  if (is_input_special) {  // fast path!!!
  ------------------
  |  Branch (11477:7): [True: 55, False: 305]
  ------------------
11478|     55|    if (has_state_override) {
  ------------------
  |  Branch (11478:9): [Folded - Ignored]
  ------------------
11479|       |      // If url’s scheme is not a special scheme and buffer is a special scheme,
11480|       |      // then return.
11481|     55|      if (is_special() != is_input_special) {
  ------------------
  |  Branch (11481:11): [True: 1, False: 54]
  ------------------
11482|      1|        return true;
11483|      1|      }
11484|       |
11485|       |      // If url includes credentials or has a non-null port, and buffer is
11486|       |      // "file", then return.
11487|     54|      if ((has_credentials() || port.has_value()) &&
  ------------------
  |  Branch (11487:12): [True: 4, False: 50]
  |  Branch (11487:33): [True: 18, False: 32]
  ------------------
11488|     54|          parsed_type == ada::scheme::type::FILE) {
  ------------------
  |  Branch (11488:11): [True: 1, False: 21]
  ------------------
11489|      1|        return true;
11490|      1|      }
11491|       |
11492|       |      // If url’s scheme is "file" and its host is an empty host, then return.
11493|       |      // An empty host is the empty string.
11494|     53|      if (type == ada::scheme::type::FILE && host.has_value() &&
  ------------------
  |  Branch (11494:11): [True: 3, False: 50]
  |  Branch (11494:46): [True: 3, False: 0]
  ------------------
11495|     53|          host.value().empty()) {
  ------------------
  |  Branch (11495:11): [True: 1, False: 2]
  ------------------
11496|      1|        return true;
11497|      1|      }
11498|     53|    }
11499|       |
11500|     52|    type = parsed_type;
11501|       |
11502|     52|    if (has_state_override) {
  ------------------
  |  Branch (11502:9): [Folded - Ignored]
  ------------------
11503|       |      // This is uncommon.
11504|     52|      uint16_t urls_scheme_port = get_special_port();
11505|       |
11506|     52|      if (urls_scheme_port) {
  ------------------
  |  Branch (11506:11): [True: 24, False: 28]
  ------------------
11507|       |        // If url’s port is url’s scheme’s default port, then set url’s port to
11508|       |        // null.
11509|     24|        if (port.has_value() && *port == urls_scheme_port) {
  ------------------
  |  Branch (11509:13): [True: 18, False: 6]
  |  Branch (11509:33): [True: 1, False: 17]
  ------------------
11510|      1|          port = std::nullopt;
11511|      1|        }
11512|     24|      }
11513|     52|    }
11514|    305|  } else {  // slow path
11515|    305|    std::string _buffer = std::string(input);
11516|       |    // Next function is only valid if the input is ASCII and returns false
11517|       |    // otherwise, but it seems that we always have ascii content so we do not
11518|       |    // need to check the return value.
11519|       |    // bool is_ascii =
11520|    305|    unicode::to_lower_ascii(_buffer.data(), _buffer.size());
11521|       |
11522|    305|    if (has_state_override) {
  ------------------
  |  Branch (11522:9): [Folded - Ignored]
  ------------------
11523|       |      // If url’s scheme is a special scheme and buffer is not a special scheme,
11524|       |      // then return. If url’s scheme is not a special scheme and buffer is a
11525|       |      // special scheme, then return.
11526|    305|      if (is_special() != ada::scheme::is_special(_buffer)) {
  ------------------
  |  Branch (11526:11): [True: 162, False: 143]
  ------------------
11527|    162|        return true;
11528|    162|      }
11529|       |
11530|       |      // If url includes credentials or has a non-null port, and buffer is
11531|       |      // "file", then return.
11532|    143|      if ((has_credentials() || port.has_value()) && _buffer == "file") {
  ------------------
  |  Branch (11532:12): [True: 6, False: 137]
  |  Branch (11532:33): [True: 22, False: 115]
  |  Branch (11532:54): [True: 1, False: 27]
  ------------------
11533|      1|        return true;
11534|      1|      }
11535|       |
11536|       |      // If url’s scheme is "file" and its host is an empty host, then return.
11537|       |      // An empty host is the empty string.
11538|    142|      if (type == ada::scheme::type::FILE && host.has_value() &&
  ------------------
  |  Branch (11538:11): [True: 4, False: 138]
  |  Branch (11538:46): [True: 4, False: 0]
  ------------------
11539|    142|          host.value().empty()) {
  ------------------
  |  Branch (11539:11): [True: 1, False: 3]
  ------------------
11540|      1|        return true;
11541|      1|      }
11542|    142|    }
11543|       |
11544|    141|    set_scheme(std::move(_buffer));
11545|       |
11546|    141|    if (has_state_override) {
  ------------------
  |  Branch (11546:9): [Folded - Ignored]
  ------------------
11547|       |      // This is uncommon.
11548|    141|      uint16_t urls_scheme_port = get_special_port();
11549|       |
11550|    141|      if (urls_scheme_port) {
  ------------------
  |  Branch (11550:11): [True: 26, False: 115]
  ------------------
11551|       |        // If url’s port is url’s scheme’s default port, then set url’s port to
11552|       |        // null.
11553|     26|        if (port.has_value() && *port == urls_scheme_port) {
  ------------------
  |  Branch (11553:13): [True: 20, False: 6]
  |  Branch (11553:33): [True: 1, False: 19]
  ------------------
11554|      1|          port = std::nullopt;
11555|      1|        }
11556|     26|      }
11557|    141|    }
11558|    141|  }
11559|       |
11560|    193|  return true;
11561|    360|}
_ZN3ada3url12parse_schemeILb0EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE:
11470|  10.2k|ada_really_inline bool url::parse_scheme(const std::string_view input) {
11471|  10.2k|  auto parsed_type = ada::scheme::get_scheme_type(input);
11472|  10.2k|  bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL);
11473|       |  /**
11474|       |   * In the common case, we will immediately recognize a special scheme (e.g.,
11475|       |   *http, https), in which case, we can go really fast.
11476|       |   **/
11477|  10.2k|  if (is_input_special) {  // fast path!!!
  ------------------
  |  Branch (11477:7): [True: 4.51k, False: 5.71k]
  ------------------
11478|  4.51k|    if (has_state_override) {
  ------------------
  |  Branch (11478:9): [Folded - Ignored]
  ------------------
11479|       |      // If url’s scheme is not a special scheme and buffer is a special scheme,
11480|       |      // then return.
11481|      0|      if (is_special() != is_input_special) {
  ------------------
  |  Branch (11481:11): [True: 0, False: 0]
  ------------------
11482|      0|        return true;
11483|      0|      }
11484|       |
11485|       |      // If url includes credentials or has a non-null port, and buffer is
11486|       |      // "file", then return.
11487|      0|      if ((has_credentials() || port.has_value()) &&
  ------------------
  |  Branch (11487:12): [True: 0, False: 0]
  |  Branch (11487:33): [True: 0, False: 0]
  ------------------
11488|      0|          parsed_type == ada::scheme::type::FILE) {
  ------------------
  |  Branch (11488:11): [True: 0, False: 0]
  ------------------
11489|      0|        return true;
11490|      0|      }
11491|       |
11492|       |      // If url’s scheme is "file" and its host is an empty host, then return.
11493|       |      // An empty host is the empty string.
11494|      0|      if (type == ada::scheme::type::FILE && host.has_value() &&
  ------------------
  |  Branch (11494:11): [True: 0, False: 0]
  |  Branch (11494:46): [True: 0, False: 0]
  ------------------
11495|      0|          host.value().empty()) {
  ------------------
  |  Branch (11495:11): [True: 0, False: 0]
  ------------------
11496|      0|        return true;
11497|      0|      }
11498|      0|    }
11499|       |
11500|  4.51k|    type = parsed_type;
11501|       |
11502|  4.51k|    if (has_state_override) {
  ------------------
  |  Branch (11502:9): [Folded - Ignored]
  ------------------
11503|       |      // This is uncommon.
11504|      0|      uint16_t urls_scheme_port = get_special_port();
11505|       |
11506|      0|      if (urls_scheme_port) {
  ------------------
  |  Branch (11506:11): [True: 0, False: 0]
  ------------------
11507|       |        // If url’s port is url’s scheme’s default port, then set url’s port to
11508|       |        // null.
11509|      0|        if (port.has_value() && *port == urls_scheme_port) {
  ------------------
  |  Branch (11509:13): [True: 0, False: 0]
  |  Branch (11509:33): [True: 0, False: 0]
  ------------------
11510|      0|          port = std::nullopt;
11511|      0|        }
11512|      0|      }
11513|      0|    }
11514|  5.71k|  } else {  // slow path
11515|  5.71k|    std::string _buffer = std::string(input);
11516|       |    // Next function is only valid if the input is ASCII and returns false
11517|       |    // otherwise, but it seems that we always have ascii content so we do not
11518|       |    // need to check the return value.
11519|       |    // bool is_ascii =
11520|  5.71k|    unicode::to_lower_ascii(_buffer.data(), _buffer.size());
11521|       |
11522|  5.71k|    if (has_state_override) {
  ------------------
  |  Branch (11522:9): [Folded - Ignored]
  ------------------
11523|       |      // If url’s scheme is a special scheme and buffer is not a special scheme,
11524|       |      // then return. If url’s scheme is not a special scheme and buffer is a
11525|       |      // special scheme, then return.
11526|      0|      if (is_special() != ada::scheme::is_special(_buffer)) {
  ------------------
  |  Branch (11526:11): [True: 0, False: 0]
  ------------------
11527|      0|        return true;
11528|      0|      }
11529|       |
11530|       |      // If url includes credentials or has a non-null port, and buffer is
11531|       |      // "file", then return.
11532|      0|      if ((has_credentials() || port.has_value()) && _buffer == "file") {
  ------------------
  |  Branch (11532:12): [True: 0, False: 0]
  |  Branch (11532:33): [True: 0, False: 0]
  |  Branch (11532:54): [True: 0, False: 0]
  ------------------
11533|      0|        return true;
11534|      0|      }
11535|       |
11536|       |      // If url’s scheme is "file" and its host is an empty host, then return.
11537|       |      // An empty host is the empty string.
11538|      0|      if (type == ada::scheme::type::FILE && host.has_value() &&
  ------------------
  |  Branch (11538:11): [True: 0, False: 0]
  |  Branch (11538:46): [True: 0, False: 0]
  ------------------
11539|      0|          host.value().empty()) {
  ------------------
  |  Branch (11539:11): [True: 0, False: 0]
  ------------------
11540|      0|        return true;
11541|      0|      }
11542|      0|    }
11543|       |
11544|  5.71k|    set_scheme(std::move(_buffer));
11545|       |
11546|  5.71k|    if (has_state_override) {
  ------------------
  |  Branch (11546:9): [Folded - Ignored]
  ------------------
11547|       |      // This is uncommon.
11548|      0|      uint16_t urls_scheme_port = get_special_port();
11549|       |
11550|      0|      if (urls_scheme_port) {
  ------------------
  |  Branch (11550:11): [True: 0, False: 0]
  ------------------
11551|       |        // If url’s port is url’s scheme’s default port, then set url’s port to
11552|       |        // null.
11553|      0|        if (port.has_value() && *port == urls_scheme_port) {
  ------------------
  |  Branch (11553:13): [True: 0, False: 0]
  |  Branch (11553:33): [True: 0, False: 0]
  ------------------
11554|      0|          port = std::nullopt;
11555|      0|        }
11556|      0|      }
11557|      0|    }
11558|  5.71k|  }
11559|       |
11560|  10.2k|  return true;
11561|  10.2k|}
_ZN3ada14url_aggregator23parse_scheme_with_colonILb0EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE:
13108|  24.2k|    const std::string_view input_with_colon) {
13109|  24.2k|  ada_log("url_aggregator::parse_scheme_with_colon ", input_with_colon);
13110|  24.2k|  ADA_ASSERT_TRUE(validate());
13111|  24.2k|  ADA_ASSERT_TRUE(!helpers::overlaps(input_with_colon, buffer));
13112|  24.2k|  std::string_view input{input_with_colon};
13113|  24.2k|  input.remove_suffix(1);
13114|  24.2k|  auto parsed_type = ada::scheme::get_scheme_type(input);
13115|  24.2k|  bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL);
13116|       |  /**
13117|       |   * In the common case, we will immediately recognize a special scheme (e.g.,
13118|       |   *http, https), in which case, we can go really fast.
13119|       |   **/
13120|  24.2k|  if (is_input_special) {  // fast path!!!
  ------------------
  |  Branch (13120:7): [True: 10.5k, False: 13.6k]
  ------------------
13121|  10.5k|    if (has_state_override) {
  ------------------
  |  Branch (13121:9): [Folded - Ignored]
  ------------------
13122|       |      // If url’s scheme is not a special scheme and buffer is a special scheme,
13123|       |      // then return.
13124|      0|      if (is_special() != is_input_special) {
  ------------------
  |  Branch (13124:11): [True: 0, False: 0]
  ------------------
13125|      0|        return true;
13126|      0|      }
13127|       |
13128|       |      // If url includes credentials or has a non-null port, and buffer is
13129|       |      // "file", then return.
13130|      0|      if ((has_credentials() || components.port != url_components::omitted) &&
  ------------------
  |  Branch (13130:12): [True: 0, False: 0]
  |  Branch (13130:33): [True: 0, False: 0]
  ------------------
13131|      0|          parsed_type == ada::scheme::type::FILE) {
  ------------------
  |  Branch (13131:11): [True: 0, False: 0]
  ------------------
13132|      0|        return true;
13133|      0|      }
13134|       |
13135|       |      // If url’s scheme is "file" and its host is an empty host, then return.
13136|       |      // An empty host is the empty string.
13137|      0|      if (type == ada::scheme::type::FILE &&
  ------------------
  |  Branch (13137:11): [True: 0, False: 0]
  ------------------
13138|      0|          components.host_start == components.host_end) {
  ------------------
  |  Branch (13138:11): [True: 0, False: 0]
  ------------------
13139|      0|        return true;
13140|      0|      }
13141|      0|    }
13142|       |
13143|  10.5k|    type = parsed_type;
13144|  10.5k|    set_scheme_from_view_with_colon(input_with_colon);
13145|       |
13146|  10.5k|    if (has_state_override) {
  ------------------
  |  Branch (13146:9): [Folded - Ignored]
  ------------------
13147|       |      // This is uncommon.
13148|      0|      uint16_t urls_scheme_port = get_special_port();
13149|       |
13150|       |      // If url’s port is url’s scheme’s default port, then set url’s port to
13151|       |      // null.
13152|      0|      if (components.port == urls_scheme_port) {
  ------------------
  |  Branch (13152:11): [True: 0, False: 0]
  ------------------
13153|      0|        clear_port();
13154|      0|      }
13155|      0|    }
13156|  13.6k|  } else {  // slow path
13157|  13.6k|    std::string _buffer = std::string(input);
13158|       |    // Next function is only valid if the input is ASCII and returns false
13159|       |    // otherwise, but it seems that we always have ascii content so we do not
13160|       |    // need to check the return value.
13161|  13.6k|    unicode::to_lower_ascii(_buffer.data(), _buffer.size());
13162|       |
13163|  13.6k|    if (has_state_override) {
  ------------------
  |  Branch (13163:9): [Folded - Ignored]
  ------------------
13164|       |      // If url’s scheme is a special scheme and buffer is not a special scheme,
13165|       |      // then return. If url’s scheme is not a special scheme and buffer is a
13166|       |      // special scheme, then return.
13167|      0|      if (is_special() != ada::scheme::is_special(_buffer)) {
  ------------------
  |  Branch (13167:11): [True: 0, False: 0]
  ------------------
13168|      0|        return true;
13169|      0|      }
13170|       |
13171|       |      // If url includes credentials or has a non-null port, and buffer is
13172|       |      // "file", then return.
13173|      0|      if ((has_credentials() || components.port != url_components::omitted) &&
  ------------------
  |  Branch (13173:12): [True: 0, False: 0]
  |  Branch (13173:33): [True: 0, False: 0]
  ------------------
13174|      0|          _buffer == "file") {
  ------------------
  |  Branch (13174:11): [True: 0, False: 0]
  ------------------
13175|      0|        return true;
13176|      0|      }
13177|       |
13178|       |      // If url’s scheme is "file" and its host is an empty host, then return.
13179|       |      // An empty host is the empty string.
13180|      0|      if (type == ada::scheme::type::FILE &&
  ------------------
  |  Branch (13180:11): [True: 0, False: 0]
  ------------------
13181|      0|          components.host_start == components.host_end) {
  ------------------
  |  Branch (13181:11): [True: 0, False: 0]
  ------------------
13182|      0|        return true;
13183|      0|      }
13184|      0|    }
13185|       |
13186|  13.6k|    set_scheme(_buffer);
13187|       |
13188|  13.6k|    if (has_state_override) {
  ------------------
  |  Branch (13188:9): [Folded - Ignored]
  ------------------
13189|       |      // This is uncommon.
13190|      0|      uint16_t urls_scheme_port = get_special_port();
13191|       |
13192|       |      // If url’s port is url’s scheme’s default port, then set url’s port to
13193|       |      // null.
13194|      0|      if (components.port == urls_scheme_port) {
  ------------------
  |  Branch (13194:11): [True: 0, False: 0]
  ------------------
13195|      0|        clear_port();
13196|      0|      }
13197|      0|    }
13198|  13.6k|  }
13199|  24.2k|  ADA_ASSERT_TRUE(validate());
13200|  24.2k|  return true;
13201|  24.2k|}
_ZN3ada14url_aggregator31set_scheme_from_view_with_colonENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13234|  10.6k|    std::string_view new_scheme_with_colon) noexcept {
13235|  10.6k|  ada_log("url_aggregator::set_scheme_from_view_with_colon ",
13236|  10.6k|          new_scheme_with_colon);
13237|  10.6k|  ADA_ASSERT_TRUE(validate());
13238|  10.6k|  ADA_ASSERT_TRUE(!new_scheme_with_colon.empty() &&
13239|  10.6k|                  new_scheme_with_colon.back() == ':');
13240|       |  // next line could overflow but unsigned arithmetic has well-defined
13241|       |  // overflows.
13242|  10.6k|  uint32_t new_difference =
13243|  10.6k|      uint32_t(new_scheme_with_colon.size()) - components.protocol_end;
13244|       |
13245|  10.6k|  if (buffer.empty()) {
  ------------------
  |  Branch (13245:7): [True: 10.5k, False: 66]
  ------------------
13246|  10.5k|    buffer.append(new_scheme_with_colon);
13247|  10.5k|  } else {
13248|     66|    buffer.erase(0, components.protocol_end);
13249|     66|    buffer.insert(0, new_scheme_with_colon);
13250|     66|  }
13251|  10.6k|  components.protocol_end += new_difference;
13252|       |
13253|       |  // Update the rest of the components.
13254|  10.6k|  components.username_end += new_difference;
13255|  10.6k|  components.host_start += new_difference;
13256|  10.6k|  components.host_end += new_difference;
13257|  10.6k|  components.pathname_start += new_difference;
13258|  10.6k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (13258:7): [True: 18, False: 10.6k]
  ------------------
13259|     18|    components.search_start += new_difference;
13260|     18|  }
13261|  10.6k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (13261:7): [True: 10, False: 10.6k]
  ------------------
13262|     10|    components.hash_start += new_difference;
13263|     10|  }
13264|  10.6k|  ADA_ASSERT_TRUE(validate());
13265|  10.6k|}
_ZN3ada14url_aggregator10set_schemeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
13267|  13.8k|inline void url_aggregator::set_scheme(std::string_view new_scheme) noexcept {
13268|  13.8k|  ada_log("url_aggregator::set_scheme ", new_scheme);
13269|  13.8k|  ADA_ASSERT_TRUE(validate());
13270|  13.8k|  ADA_ASSERT_TRUE(new_scheme.empty() || new_scheme.back() != ':');
13271|       |  // next line could overflow but unsigned arithmetic has well-defined
13272|       |  // overflows.
13273|  13.8k|  uint32_t new_difference =
13274|  13.8k|      uint32_t(new_scheme.size()) - components.protocol_end + 1;
13275|       |
13276|  13.8k|  type = ada::scheme::get_scheme_type(new_scheme);
13277|  13.8k|  if (buffer.empty()) {
  ------------------
  |  Branch (13277:7): [True: 13.6k, False: 161]
  ------------------
13278|  13.6k|    buffer.append(helpers::concat(new_scheme, ":"));
13279|  13.6k|  } else {
13280|    161|    buffer.erase(0, components.protocol_end);
13281|    161|    buffer.insert(0, helpers::concat(new_scheme, ":"));
13282|    161|  }
13283|  13.8k|  components.protocol_end = uint32_t(new_scheme.size() + 1);
13284|       |
13285|       |  // Update the rest of the components.
13286|  13.8k|  components.username_end += new_difference;
13287|  13.8k|  components.host_start += new_difference;
13288|  13.8k|  components.host_end += new_difference;
13289|  13.8k|  components.pathname_start += new_difference;
13290|  13.8k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (13290:7): [True: 16, False: 13.8k]
  ------------------
13291|     16|    components.search_start += new_difference;
13292|     16|  }
13293|  13.8k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (13293:7): [True: 18, False: 13.8k]
  ------------------
13294|     18|    components.hash_start += new_difference;
13295|     18|  }
13296|  13.8k|  ADA_ASSERT_TRUE(validate());
13297|  13.8k|}
_ZN3ada14url_aggregator23parse_scheme_with_colonILb1EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE:
13108|    353|    const std::string_view input_with_colon) {
13109|    353|  ada_log("url_aggregator::parse_scheme_with_colon ", input_with_colon);
13110|    353|  ADA_ASSERT_TRUE(validate());
13111|    353|  ADA_ASSERT_TRUE(!helpers::overlaps(input_with_colon, buffer));
13112|    353|  std::string_view input{input_with_colon};
13113|    353|  input.remove_suffix(1);
13114|    353|  auto parsed_type = ada::scheme::get_scheme_type(input);
13115|    353|  bool is_input_special = (parsed_type != ada::scheme::NOT_SPECIAL);
13116|       |  /**
13117|       |   * In the common case, we will immediately recognize a special scheme (e.g.,
13118|       |   *http, https), in which case, we can go really fast.
13119|       |   **/
13120|    353|  if (is_input_special) {  // fast path!!!
  ------------------
  |  Branch (13120:7): [True: 71, False: 282]
  ------------------
13121|     71|    if (has_state_override) {
  ------------------
  |  Branch (13121:9): [Folded - Ignored]
  ------------------
13122|       |      // If url’s scheme is not a special scheme and buffer is a special scheme,
13123|       |      // then return.
13124|     71|      if (is_special() != is_input_special) {
  ------------------
  |  Branch (13124:11): [True: 2, False: 69]
  ------------------
13125|      2|        return true;
13126|      2|      }
13127|       |
13128|       |      // If url includes credentials or has a non-null port, and buffer is
13129|       |      // "file", then return.
13130|     69|      if ((has_credentials() || components.port != url_components::omitted) &&
  ------------------
  |  Branch (13130:12): [True: 3, False: 66]
  |  Branch (13130:33): [True: 30, False: 36]
  ------------------
13131|     69|          parsed_type == ada::scheme::type::FILE) {
  ------------------
  |  Branch (13131:11): [True: 1, False: 32]
  ------------------
13132|      1|        return true;
13133|      1|      }
13134|       |
13135|       |      // If url’s scheme is "file" and its host is an empty host, then return.
13136|       |      // An empty host is the empty string.
13137|     68|      if (type == ada::scheme::type::FILE &&
  ------------------
  |  Branch (13137:11): [True: 4, False: 64]
  ------------------
13138|     68|          components.host_start == components.host_end) {
  ------------------
  |  Branch (13138:11): [True: 2, False: 2]
  ------------------
13139|      2|        return true;
13140|      2|      }
13141|     68|    }
13142|       |
13143|     66|    type = parsed_type;
13144|     66|    set_scheme_from_view_with_colon(input_with_colon);
13145|       |
13146|     66|    if (has_state_override) {
  ------------------
  |  Branch (13146:9): [Folded - Ignored]
  ------------------
13147|       |      // This is uncommon.
13148|     66|      uint16_t urls_scheme_port = get_special_port();
13149|       |
13150|       |      // If url’s port is url’s scheme’s default port, then set url’s port to
13151|       |      // null.
13152|     66|      if (components.port == urls_scheme_port) {
  ------------------
  |  Branch (13152:11): [True: 13, False: 53]
  ------------------
13153|     13|        clear_port();
13154|     13|      }
13155|     66|    }
13156|    282|  } else {  // slow path
13157|    282|    std::string _buffer = std::string(input);
13158|       |    // Next function is only valid if the input is ASCII and returns false
13159|       |    // otherwise, but it seems that we always have ascii content so we do not
13160|       |    // need to check the return value.
13161|    282|    unicode::to_lower_ascii(_buffer.data(), _buffer.size());
13162|       |
13163|    282|    if (has_state_override) {
  ------------------
  |  Branch (13163:9): [Folded - Ignored]
  ------------------
13164|       |      // If url’s scheme is a special scheme and buffer is not a special scheme,
13165|       |      // then return. If url’s scheme is not a special scheme and buffer is a
13166|       |      // special scheme, then return.
13167|    282|      if (is_special() != ada::scheme::is_special(_buffer)) {
  ------------------
  |  Branch (13167:11): [True: 117, False: 165]
  ------------------
13168|    117|        return true;
13169|    117|      }
13170|       |
13171|       |      // If url includes credentials or has a non-null port, and buffer is
13172|       |      // "file", then return.
13173|    165|      if ((has_credentials() || components.port != url_components::omitted) &&
  ------------------
  |  Branch (13173:12): [True: 6, False: 159]
  |  Branch (13173:33): [True: 37, False: 122]
  ------------------
13174|    165|          _buffer == "file") {
  ------------------
  |  Branch (13174:11): [True: 1, False: 42]
  ------------------
13175|      1|        return true;
13176|      1|      }
13177|       |
13178|       |      // If url’s scheme is "file" and its host is an empty host, then return.
13179|       |      // An empty host is the empty string.
13180|    164|      if (type == ada::scheme::type::FILE &&
  ------------------
  |  Branch (13180:11): [True: 4, False: 160]
  ------------------
13181|    164|          components.host_start == components.host_end) {
  ------------------
  |  Branch (13181:11): [True: 3, False: 1]
  ------------------
13182|      3|        return true;
13183|      3|      }
13184|    164|    }
13185|       |
13186|    161|    set_scheme(_buffer);
13187|       |
13188|    161|    if (has_state_override) {
  ------------------
  |  Branch (13188:9): [Folded - Ignored]
  ------------------
13189|       |      // This is uncommon.
13190|    161|      uint16_t urls_scheme_port = get_special_port();
13191|       |
13192|       |      // If url’s port is url’s scheme’s default port, then set url’s port to
13193|       |      // null.
13194|    161|      if (components.port == urls_scheme_port) {
  ------------------
  |  Branch (13194:11): [True: 14, False: 147]
  ------------------
13195|     14|        clear_port();
13196|     14|      }
13197|    161|    }
13198|    161|  }
13199|    227|  ADA_ASSERT_TRUE(validate());
13200|    227|  return true;
13201|    353|}
_ZN3ada7helpers38strip_trailing_spaces_from_opaque_pathINS_14url_aggregatorEEEvRT_:
11027|  13.3k|    url_type& url) noexcept {
11028|  13.3k|  ada_log("helpers::strip_trailing_spaces_from_opaque_path");
11029|  13.3k|  if (!url.has_opaque_path) return;
  ------------------
  |  Branch (11029:7): [True: 11.5k, False: 1.79k]
  ------------------
11030|  1.79k|  if (url.has_hash()) return;
  ------------------
  |  Branch (11030:7): [True: 69, False: 1.72k]
  ------------------
11031|  1.72k|  if (url.has_search()) return;
  ------------------
  |  Branch (11031:7): [True: 0, False: 1.72k]
  ------------------
11032|       |
11033|  1.72k|  auto path = std::string(url.get_pathname());
11034|  2.59k|  while (!path.empty() && path.back() == ' ') {
  ------------------
  |  Branch (11034:10): [True: 1.90k, False: 682]
  |  Branch (11034:27): [True: 868, False: 1.04k]
  ------------------
11035|    868|    path.resize(path.size() - 1);
11036|    868|  }
11037|  1.72k|  url.update_base_pathname(path);
11038|  1.72k|}
_ZN3ada14url_aggregator20set_host_or_hostnameILb0EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE:
13602|  8.53k|bool url_aggregator::set_host_or_hostname(const std::string_view input) {
13603|  8.53k|  ada_log("url_aggregator::set_host_or_hostname ", input);
13604|  8.53k|  ADA_ASSERT_TRUE(validate());
13605|  8.53k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13606|  8.53k|  if (has_opaque_path) {
  ------------------
  |  Branch (13606:7): [True: 1.06k, False: 7.46k]
  ------------------
13607|  1.06k|    return false;
13608|  1.06k|  }
13609|       |
13610|  7.46k|  std::string previous_host = std::string(get_hostname());
13611|  7.46k|  uint32_t previous_port = components.port;
13612|       |
13613|  7.46k|  size_t host_end_pos = input.find('#');
13614|  7.46k|  std::string _host(input.data(), host_end_pos != std::string_view::npos
  ------------------
  |  Branch (13614:35): [True: 25, False: 7.44k]
  ------------------
13615|  7.46k|                                      ? host_end_pos
13616|  7.46k|                                      : input.size());
13617|  7.46k|  helpers::remove_ascii_tab_or_newline(_host);
13618|  7.46k|  std::string_view new_host(_host);
13619|       |
13620|       |  // If url's scheme is "file", then set state to file host state, instead of
13621|       |  // host state.
13622|  7.46k|  if (type != ada::scheme::type::FILE) {
  ------------------
  |  Branch (13622:7): [True: 5.72k, False: 1.74k]
  ------------------
13623|  5.72k|    std::string_view host_view(_host.data(), _host.length());
13624|  5.72k|    auto [location, found_colon] =
13625|  5.72k|        helpers::get_host_delimiter_location(is_special(), host_view);
13626|       |
13627|       |    // Otherwise, if c is U+003A (:) and insideBrackets is false, then:
13628|       |    // Note: the 'found_colon' value is true if and only if a colon was
13629|       |    // encountered while not inside brackets.
13630|  5.72k|    if (found_colon) {
  ------------------
  |  Branch (13630:9): [True: 200, False: 5.52k]
  ------------------
13631|    200|      if (override_hostname) {
  ------------------
  |  Branch (13631:11): [Folded - Ignored]
  ------------------
13632|      0|        return false;
13633|      0|      }
13634|    200|      std::string_view sub_buffer = new_host.substr(location + 1);
13635|    200|      if (!sub_buffer.empty()) {
  ------------------
  |  Branch (13635:11): [True: 177, False: 23]
  ------------------
13636|    177|        set_port(sub_buffer);
13637|    177|      }
13638|    200|    }
13639|       |    // If url is special and host_view is the empty string, validation error,
13640|       |    // return failure. Otherwise, if state override is given, host_view is the
13641|       |    // empty string, and either url includes credentials or url’s port is
13642|       |    // non-null, return.
13643|  5.52k|    else if (host_view.empty() &&
  ------------------
  |  Branch (13643:14): [True: 4.65k, False: 869]
  ------------------
13644|  5.52k|             (is_special() || has_credentials() ||
  ------------------
  |  Branch (13644:15): [True: 3.28k, False: 1.36k]
  |  Branch (13644:31): [True: 14, False: 1.35k]
  ------------------
13645|  4.65k|              components.port != url_components::omitted)) {
  ------------------
  |  Branch (13645:15): [True: 23, False: 1.33k]
  ------------------
13646|  3.32k|      return false;
13647|  3.32k|    }
13648|       |
13649|       |    // Let host be the result of host parsing host_view with url is not special.
13650|  2.40k|    if (host_view.empty()) {
  ------------------
  |  Branch (13650:9): [True: 1.41k, False: 990]
  ------------------
13651|  1.41k|      if (has_hostname()) {
  ------------------
  |  Branch (13651:11): [True: 204, False: 1.20k]
  ------------------
13652|    204|        clear_hostname();  // easy!
13653|  1.20k|      } else if (has_dash_dot()) {
  ------------------
  |  Branch (13653:18): [True: 2, False: 1.20k]
  ------------------
13654|      2|        add_authority_slashes_if_needed();
13655|      2|        delete_dash_dot();
13656|      2|      }
13657|  1.41k|      return true;
13658|  1.41k|    }
13659|       |
13660|    990|    bool succeeded = parse_host(host_view);
13661|    990|    if (!succeeded) {
  ------------------
  |  Branch (13661:9): [True: 363, False: 627]
  ------------------
13662|    363|      update_base_hostname(previous_host);
13663|    363|      update_base_port(previous_port);
13664|    627|    } else if (has_dash_dot()) {
  ------------------
  |  Branch (13664:16): [True: 7, False: 620]
  ------------------
13665|       |      // Should remove dash_dot from pathname
13666|      7|      delete_dash_dot();
13667|      7|    }
13668|    990|    return succeeded;
13669|  2.40k|  }
13670|       |
13671|  1.74k|  size_t location = new_host.find_first_of("/\\?");
13672|  1.74k|  if (location != std::string_view::npos) {
  ------------------
  |  Branch (13672:7): [True: 22, False: 1.72k]
  ------------------
13673|     22|    new_host.remove_suffix(new_host.length() - location);
13674|     22|  }
13675|       |
13676|  1.74k|  if (new_host.empty()) {
  ------------------
  |  Branch (13676:7): [True: 1.31k, False: 429]
  ------------------
13677|       |    // Set url’s host to the empty string.
13678|  1.31k|    clear_hostname();
13679|  1.31k|  } else {
13680|       |    // Let host be the result of host parsing buffer with url is not special.
13681|    429|    if (!parse_host(new_host)) {
  ------------------
  |  Branch (13681:9): [True: 69, False: 360]
  ------------------
13682|     69|      update_base_hostname(previous_host);
13683|     69|      update_base_port(previous_port);
13684|     69|      return false;
13685|     69|    }
13686|       |
13687|       |    // If host is "localhost", then set host to the empty string.
13688|    360|    if (helpers::substring(buffer, components.host_start,
  ------------------
  |  Branch (13688:9): [True: 20, False: 340]
  ------------------
13689|    360|                           components.host_end) == "localhost") {
13690|     20|      clear_hostname();
13691|     20|    }
13692|    360|  }
13693|  1.67k|  ADA_ASSERT_TRUE(validate());
13694|  1.67k|  return true;
13695|  1.74k|}
_ZN3ada14url_aggregator20set_host_or_hostnameILb1EEEbNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEE:
13602|  9.41k|bool url_aggregator::set_host_or_hostname(const std::string_view input) {
13603|  9.41k|  ada_log("url_aggregator::set_host_or_hostname ", input);
13604|  9.41k|  ADA_ASSERT_TRUE(validate());
13605|  9.41k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
13606|  9.41k|  if (has_opaque_path) {
  ------------------
  |  Branch (13606:7): [True: 1.06k, False: 8.35k]
  ------------------
13607|  1.06k|    return false;
13608|  1.06k|  }
13609|       |
13610|  8.35k|  std::string previous_host = std::string(get_hostname());
13611|  8.35k|  uint32_t previous_port = components.port;
13612|       |
13613|  8.35k|  size_t host_end_pos = input.find('#');
13614|  8.35k|  std::string _host(input.data(), host_end_pos != std::string_view::npos
  ------------------
  |  Branch (13614:35): [True: 25, False: 8.32k]
  ------------------
13615|  8.35k|                                      ? host_end_pos
13616|  8.35k|                                      : input.size());
13617|  8.35k|  helpers::remove_ascii_tab_or_newline(_host);
13618|  8.35k|  std::string_view new_host(_host);
13619|       |
13620|       |  // If url's scheme is "file", then set state to file host state, instead of
13621|       |  // host state.
13622|  8.35k|  if (type != ada::scheme::type::FILE) {
  ------------------
  |  Branch (13622:7): [True: 6.48k, False: 1.86k]
  ------------------
13623|  6.48k|    std::string_view host_view(_host.data(), _host.length());
13624|  6.48k|    auto [location, found_colon] =
13625|  6.48k|        helpers::get_host_delimiter_location(is_special(), host_view);
13626|       |
13627|       |    // Otherwise, if c is U+003A (:) and insideBrackets is false, then:
13628|       |    // Note: the 'found_colon' value is true if and only if a colon was
13629|       |    // encountered while not inside brackets.
13630|  6.48k|    if (found_colon) {
  ------------------
  |  Branch (13630:9): [True: 200, False: 6.28k]
  ------------------
13631|    200|      if (override_hostname) {
  ------------------
  |  Branch (13631:11): [Folded - Ignored]
  ------------------
13632|    200|        return false;
13633|    200|      }
13634|      0|      std::string_view sub_buffer = new_host.substr(location + 1);
13635|      0|      if (!sub_buffer.empty()) {
  ------------------
  |  Branch (13635:11): [True: 0, False: 0]
  ------------------
13636|      0|        set_port(sub_buffer);
13637|      0|      }
13638|      0|    }
13639|       |    // If url is special and host_view is the empty string, validation error,
13640|       |    // return failure. Otherwise, if state override is given, host_view is the
13641|       |    // empty string, and either url includes credentials or url’s port is
13642|       |    // non-null, return.
13643|  6.28k|    else if (host_view.empty() &&
  ------------------
  |  Branch (13643:14): [True: 4.78k, False: 1.50k]
  ------------------
13644|  6.28k|             (is_special() || has_credentials() ||
  ------------------
  |  Branch (13644:15): [True: 3.28k, False: 1.49k]
  |  Branch (13644:31): [True: 14, False: 1.48k]
  ------------------
13645|  4.78k|              components.port != url_components::omitted)) {
  ------------------
  |  Branch (13645:15): [True: 23, False: 1.45k]
  ------------------
13646|  3.32k|      return false;
13647|  3.32k|    }
13648|       |
13649|       |    // Let host be the result of host parsing host_view with url is not special.
13650|  2.96k|    if (host_view.empty()) {
  ------------------
  |  Branch (13650:9): [True: 1.45k, False: 1.50k]
  ------------------
13651|  1.45k|      if (has_hostname()) {
  ------------------
  |  Branch (13651:11): [True: 103, False: 1.35k]
  ------------------
13652|    103|        clear_hostname();  // easy!
13653|  1.35k|      } else if (has_dash_dot()) {
  ------------------
  |  Branch (13653:18): [True: 32, False: 1.32k]
  ------------------
13654|     32|        add_authority_slashes_if_needed();
13655|     32|        delete_dash_dot();
13656|     32|      }
13657|  1.45k|      return true;
13658|  1.45k|    }
13659|       |
13660|  1.50k|    bool succeeded = parse_host(host_view);
13661|  1.50k|    if (!succeeded) {
  ------------------
  |  Branch (13661:9): [True: 306, False: 1.19k]
  ------------------
13662|    306|      update_base_hostname(previous_host);
13663|    306|      update_base_port(previous_port);
13664|  1.19k|    } else if (has_dash_dot()) {
  ------------------
  |  Branch (13664:16): [True: 2, False: 1.19k]
  ------------------
13665|       |      // Should remove dash_dot from pathname
13666|      2|      delete_dash_dot();
13667|      2|    }
13668|  1.50k|    return succeeded;
13669|  2.96k|  }
13670|       |
13671|  1.86k|  size_t location = new_host.find_first_of("/\\?");
13672|  1.86k|  if (location != std::string_view::npos) {
  ------------------
  |  Branch (13672:7): [True: 22, False: 1.84k]
  ------------------
13673|     22|    new_host.remove_suffix(new_host.length() - location);
13674|     22|  }
13675|       |
13676|  1.86k|  if (new_host.empty()) {
  ------------------
  |  Branch (13676:7): [True: 1.38k, False: 477]
  ------------------
13677|       |    // Set url’s host to the empty string.
13678|  1.38k|    clear_hostname();
13679|  1.38k|  } else {
13680|       |    // Let host be the result of host parsing buffer with url is not special.
13681|    477|    if (!parse_host(new_host)) {
  ------------------
  |  Branch (13681:9): [True: 69, False: 408]
  ------------------
13682|     69|      update_base_hostname(previous_host);
13683|     69|      update_base_port(previous_port);
13684|     69|      return false;
13685|     69|    }
13686|       |
13687|       |    // If host is "localhost", then set host to the empty string.
13688|    408|    if (helpers::substring(buffer, components.host_start,
  ------------------
  |  Branch (13688:9): [True: 20, False: 388]
  ------------------
13689|    408|                           components.host_end) == "localhost") {
13690|     20|      clear_hostname();
13691|     20|    }
13692|    408|  }
13693|  1.79k|  ADA_ASSERT_TRUE(validate());
13694|  1.79k|  return true;
13695|  1.86k|}

_ZN3ada14character_sets6bit_atEPKhh:
  929|   826k|ada_really_inline bool bit_at(const uint8_t a[], const uint8_t i) {
  930|   826k|  return !!(a[i >> 3] & (1 << (i & 7)));
  931|   826k|}
_ZN2tl10unexpectedIN3ada6errorsEEC2EOS2_:
 1827|  59.9k|  constexpr explicit unexpected(E &&e) : m_val(std::move(e)) {}
_ZN2tl8expectedIN3ada3urlENS1_6errorsEEC2IS3_LPv0ELS6_0EEEONS_10unexpectedIT_EE:
 3269|  6.10k|        ctor_base(detail::default_constructor_tag{}) {}
_ZNR2tl10unexpectedIN3ada6errorsEE5valueEv:
 1841|  29.9k|  TL_EXPECTED_11_CONSTEXPR E &value() & { return m_val; }
_ZN2tl6detail21expected_storage_baseIN3ada3urlENS2_6errorsELb0ELb1EEC2IJS4_ELPv0EEENS_10unexpect_tEDpOT_:
 2298|  6.10k|      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
_ZN2tl6detail26expected_default_ctor_baseIN3ada3urlENS2_6errorsELb1EEC2ENS0_23default_constructor_tagE:
 2914|  14.5k|  constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
_ZN2tl8expectedIN3ada3urlENS1_6errorsEEC2IS2_LPv0ELS6_0EEEOT_:
 3356|  8.40k|      : expected(in_place, std::forward<U>(v)) {}
_ZN2tl8expectedIN3ada3urlENS1_6errorsEEC2IJS2_ELPv0EEENS_10in_place_tEDpOT_:
 3226|  8.40k|        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl6detail21expected_storage_baseIN3ada3urlENS2_6errorsELb0ELb1EEC2IJS3_ELPv0EEENS_10in_place_tEDpOT_:
 2286|  8.40k|      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
_ZN3ada3urlC2EOS0_:
 4920|  8.40k|  url(url &&u) noexcept = default;
_ZN3ada8url_baseD2Ev:
 1354|   118k|  virtual ~url_base() = default;
_ZN3ada3urlD2Ev:
 4923|  22.9k|  ~url() = default;
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEC2IS3_LPv0ELS6_0EEEONS_10unexpectedIT_EE:
 3269|  23.8k|        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl6detail21expected_storage_baseIN3ada14url_aggregatorENS2_6errorsELb0ELb1EEC2IJS4_ELPv0EEENS_10unexpect_tEDpOT_:
 2298|  23.8k|      : m_unexpect(std::forward<Args>(args)...), m_has_val(false) {}
_ZN2tl6detail26expected_default_ctor_baseIN3ada14url_aggregatorENS2_6errorsELb1EEC2ENS0_23default_constructor_tagE:
 2914|  45.4k|  constexpr explicit expected_default_ctor_base(default_constructor_tag) {}
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEC2IS2_LPv0ELS6_0EEEOT_:
 3356|  21.5k|      : expected(in_place, std::forward<U>(v)) {}
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEC2IJS2_ELPv0EEENS_10in_place_tEDpOT_:
 3226|  21.5k|        ctor_base(detail::default_constructor_tag{}) {}
_ZN2tl6detail21expected_storage_baseIN3ada14url_aggregatorENS2_6errorsELb0ELb1EEC2IJS3_ELPv0EEENS_10in_place_tEDpOT_:
 2286|  21.5k|      : m_val(std::forward<Args>(args)...), m_has_val(true) {}
_ZN3ada14url_aggregatorC2EOS0_:
 4502|  21.5k|  url_aggregator(url_aggregator &&u) noexcept = default;
_ZN3ada14url_aggregatorD2Ev:
 4505|  95.2k|  ~url_aggregator() = default;
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEC2Ev:
 3215|  28.2k|  constexpr expected() = default;
_ZN2tl6detail25expected_move_assign_baseIN3ada14url_aggregatorENS2_6errorsELb0EEC2Ev:
 2765|  28.2k|  expected_move_assign_base() = default;
_ZN2tl6detail25expected_copy_assign_baseIN3ada14url_aggregatorENS2_6errorsELb0EEC2Ev:
 2726|  28.2k|  expected_copy_assign_base() = default;
_ZN2tl6detail18expected_move_baseIN3ada14url_aggregatorENS2_6errorsELb0EEC2Ev:
 2693|  28.2k|  expected_move_base() = default;
_ZN2tl6detail18expected_copy_baseIN3ada14url_aggregatorENS2_6errorsELb0EEC2Ev:
 2658|  28.2k|  expected_copy_base() = default;
_ZN2tl6detail21expected_storage_baseIN3ada14url_aggregatorENS2_6errorsELb0ELb1EEC2Ev:
 2279|  28.2k|  constexpr expected_storage_base() : m_val(T{}), m_has_val(true) {}
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEaSEOS4_:
 3219|  14.1k|  expected &operator=(expected &&rhs) = default;
_ZN2tl6detail25expected_move_assign_baseIN3ada14url_aggregatorENS2_6errorsELb0EEaSEOS5_:
 2776|  14.1k|          &&std::is_nothrow_move_assignable<T>::value) {
 2777|  14.1k|    this->assign(std::move(rhs));
 2778|  14.1k|    return *this;
 2779|  14.1k|  }
_ZN2tl6detail24expected_operations_baseIN3ada14url_aggregatorENS2_6errorsEE6assignIS3_LPv0EEEvOS5_:
 2487|  14.1k|  void assign(expected_operations_base &&rhs) noexcept {
 2488|  14.1k|    if (!this->m_has_val && rhs.m_has_val) {
  ------------------
  |  Branch (2488:9): [True: 0, False: 14.1k]
  |  Branch (2488:29): [True: 0, False: 0]
  ------------------
 2489|      0|      geterr().~unexpected<E>();
 2490|      0|      construct(std::move(rhs).get());
 2491|  14.1k|    } else {
 2492|  14.1k|      assign_common(std::move(rhs));
 2493|  14.1k|    }
 2494|  14.1k|  }
_ZNO2tl6detail24expected_operations_baseIN3ada14url_aggregatorENS2_6errorsEE3getEv:
 2562|  2.66k|  TL_EXPECTED_11_CONSTEXPR T &&get() && { return std::move(this->m_val); }
_ZN2tl6detail24expected_operations_baseIN3ada14url_aggregatorENS2_6errorsEE13assign_commonIS5_EEvOT_:
 2543|  14.1k|  void assign_common(Rhs &&rhs) {
 2544|  14.1k|    if (this->m_has_val) {
  ------------------
  |  Branch (2544:9): [True: 14.1k, False: 0]
  ------------------
 2545|  14.1k|      if (rhs.m_has_val) {
  ------------------
  |  Branch (2545:11): [True: 2.66k, False: 11.4k]
  ------------------
 2546|  2.66k|        get() = std::forward<Rhs>(rhs).get();
 2547|  11.4k|      } else {
 2548|  11.4k|        destroy_val();
 2549|  11.4k|        construct_error(std::forward<Rhs>(rhs).geterr());
 2550|  11.4k|      }
 2551|  14.1k|    } else {
 2552|      0|      if (!rhs.m_has_val) {
  ------------------
  |  Branch (2552:11): [True: 0, False: 0]
  ------------------
 2553|      0|        geterr() = std::forward<Rhs>(rhs).geterr();
 2554|      0|      }
 2555|      0|    }
 2556|  14.1k|  }
_ZNR2tl6detail24expected_operations_baseIN3ada14url_aggregatorENS2_6errorsEE3getEv:
 2560|  14.1k|  TL_EXPECTED_11_CONSTEXPR T &get() & { return this->m_val; }
_ZN3ada14url_aggregatoraSEOS0_:
 4503|  2.66k|  url_aggregator &operator=(url_aggregator &&u) noexcept = default;
_ZN2tl6detail24expected_operations_baseIN3ada14url_aggregatorENS2_6errorsEE11destroy_valEv:
 2580|  11.4k|  TL_EXPECTED_11_CONSTEXPR void destroy_val() { get().~T(); }
_ZN2tl6detail24expected_operations_baseIN3ada14url_aggregatorENS2_6errorsEE15construct_errorIJNS_10unexpectedIS4_EEEEEvDpOT_:
 2412|  11.4k|  void construct_error(Args &&...args) noexcept {
 2413|  11.4k|    new (std::addressof(this->m_unexpect))
 2414|  11.4k|        unexpected<E>(std::forward<Args>(args)...);
 2415|  11.4k|    this->m_has_val = false;
 2416|  11.4k|  }
_ZNO2tl6detail24expected_operations_baseIN3ada14url_aggregatorENS2_6errorsEE6geterrEv:
 2571|  11.4k|  TL_EXPECTED_11_CONSTEXPR unexpected<E> &&geterr() && {
 2572|  11.4k|    return std::move(this->m_unexpect);
 2573|  11.4k|  }
_ZN2tl6detail21expected_storage_baseIN3ada14url_aggregatorENS2_6errorsELb0ELb1EED2Ev:
 2308|  73.6k|  ~expected_storage_base() {
 2309|  73.6k|    if (m_has_val) {
  ------------------
  |  Branch (2309:9): [True: 38.3k, False: 35.3k]
  ------------------
 2310|  38.3k|      m_val.~T();
 2311|  38.3k|    }
 2312|  73.6k|  }
_ZNK2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEcvbEv:
 3660|  28.6k|  constexpr explicit operator bool() const noexcept { return this->m_has_val; }
_ZNR2tl8expectedIN3ada14url_aggregatorENS1_6errorsEE5valueIS2_LPv0EEERT_v:
 3671|  2.66k|  TL_EXPECTED_11_CONSTEXPR U &value() & {
 3672|  2.66k|    if (!has_value())
  ------------------
  |  Branch (3672:9): [True: 0, False: 2.66k]
  ------------------
 3673|      0|      detail::throw_exception(bad_expected_access<E>(err().value()));
 3674|  2.66k|    return val();
 3675|  2.66k|  }
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEE3valIS2_LPv0EEERT_v:
 2983|  2.66k|  TL_EXPECTED_11_CONSTEXPR U &val() {
 2984|  2.66k|    return this->m_val;
 2985|  2.66k|  }
_ZNK2tl8expectedIN3ada14url_aggregatorENS1_6errorsEE9has_valueEv:
 3659|  19.4k|  constexpr bool has_value() const noexcept { return this->m_has_val; }
_ZN3ada8checkers14has_hex_prefixENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
  968|  21.7k|inline bool has_hex_prefix(std::string_view input) {
  969|  21.7k|  return input.size() >= 2 && has_hex_prefix_unsafe(input);
  ------------------
  |  Branch (969:10): [True: 13.4k, False: 8.35k]
  |  Branch (969:31): [True: 4.15k, False: 9.28k]
  ------------------
  970|  21.7k|}
_ZN3ada8checkers21has_hex_prefix_unsafeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
  951|  13.4k|inline bool has_hex_prefix_unsafe(std::string_view input) {
  952|       |  // This is actually efficient code, see has_hex_prefix for the assembly.
  953|  13.4k|  uint32_t value_one = 1;
  954|  13.4k|  bool is_little_endian = (reinterpret_cast<char*>(&value_one)[0] == 1);
  955|  13.4k|  uint16_t word0x{};
  956|  13.4k|  std::memcpy(&word0x, "0x", 2);  // we would use bit_cast in C++20 and the
  957|       |                                  // function could be constexpr.
  958|  13.4k|  uint16_t two_first_bytes{};
  959|  13.4k|  std::memcpy(&two_first_bytes, input.data(), 2);
  960|  13.4k|  if (is_little_endian) {
  ------------------
  |  Branch (960:7): [True: 13.4k, False: 0]
  ------------------
  961|  13.4k|    two_first_bytes |= 0x2000;
  962|  13.4k|  } else {
  963|      0|    two_first_bytes |= 0x020;
  964|      0|  }
  965|  13.4k|  return two_first_bytes == word0x;
  966|  13.4k|}
_ZN3ada8checkers8is_digitEc:
  972|  43.2k|constexpr bool is_digit(char x) noexcept { return (x >= '0') & (x <= '9'); }
_ZNK3ada3url15has_credentialsEv:
 5333|  2.53k|[[nodiscard]] ada_really_inline bool url::has_credentials() const noexcept {
 5334|  2.53k|  return !username.empty() || !password.empty();
  ------------------
  |  Branch (5334:10): [True: 32, False: 2.50k]
  |  Branch (5334:31): [True: 2, False: 2.49k]
  ------------------
 5335|  2.53k|}
_ZNK3ada8url_base10is_specialEv:
 5300|   242k|[[nodiscard]] ada_really_inline bool url_base::is_special() const noexcept {
 5301|   242k|  return type != ada::scheme::NOT_SPECIAL;
 5302|   242k|}
_ZNK2tl8expectedIN3ada3urlENS1_6errorsEEcvbEv:
 3660|  14.5k|  constexpr explicit operator bool() const noexcept { return this->m_has_val; }
_ZN2tl8expectedIN3ada3urlENS1_6errorsEEptEv:
 3636|   157k|  TL_EXPECTED_11_CONSTEXPR T *operator->() { return valptr(); }
_ZN2tl8expectedIN3ada3urlENS1_6errorsEE6valptrEv:
 2974|   157k|  T *valptr() { return std::addressof(this->m_val); }
_ZN2tl6detail21expected_storage_baseIN3ada3urlENS2_6errorsELb0ELb1EED2Ev:
 2308|  14.5k|  ~expected_storage_base() {
 2309|  14.5k|    if (m_has_val) {
  ------------------
  |  Branch (2309:9): [True: 8.40k, False: 6.10k]
  ------------------
 2310|  8.40k|      m_val.~T();
 2311|  8.40k|    }
 2312|  14.5k|  }
_ZNK3ada3url31cannot_have_credentials_or_portEv:
 5339|  24.9k|[[nodiscard]] inline bool url::cannot_have_credentials_or_port() const {
 5340|  24.9k|  return !host.has_value() || host.value().empty() ||
  ------------------
  |  Branch (5340:10): [True: 6.29k, False: 18.6k]
  |  Branch (5340:31): [True: 4.57k, False: 14.0k]
  ------------------
 5341|  24.9k|         type == ada::scheme::type::FILE;
  ------------------
  |  Branch (5341:10): [True: 1.08k, False: 12.9k]
  ------------------
 5342|  24.9k|}
_ZN3ada8checkers8is_alphaEc:
  976|  81.9k|constexpr bool is_alpha(char x) noexcept {
  977|  81.9k|  return (to_lower(x) >= 'a') && (to_lower(x) <= 'z');
  ------------------
  |  Branch (977:10): [True: 62.9k, False: 19.0k]
  |  Branch (977:34): [True: 62.2k, False: 654]
  ------------------
  978|  81.9k|}
_ZN3ada8checkers8to_lowerEc:
  974|   144k|constexpr char to_lower(char x) noexcept { return (x | 0x20); }
_ZN3ada3urlC2Ev:
 4918|  14.5k|  url() = default;
_ZN3ada3url26update_unencoded_base_hashENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 5432|    263|inline void url::update_unencoded_base_hash(std::string_view input) {
 5433|       |  // We do the percent encoding
 5434|    263|  hash = unicode::percent_encode(input,
 5435|    263|                                 ada::character_sets::FRAGMENT_PERCENT_ENCODE);
 5436|    263|}
_ZN3ada8checkers11begins_withENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEES5_:
  993|  51.8k|                                             std::string_view prefix) {
  994|       |  // in C++20, you have view.begins_with(prefix)
  995|  51.8k|  return view.size() >= prefix.size() &&
  ------------------
  |  Branch (995:10): [True: 20.0k, False: 31.7k]
  ------------------
  996|  51.8k|         (view.substr(0, prefix.size()) == prefix);
  ------------------
  |  Branch (996:10): [True: 1.08k, False: 18.9k]
  ------------------
  997|  51.8k|}
_ZN3ada3url18update_base_searchENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKh:
 5439|    268|                                    const uint8_t query_percent_encode_set[]) {
 5440|    268|  query = ada::unicode::percent_encode(input, query_percent_encode_set);
 5441|    268|}
_ZN3ada3url20update_base_hostnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 5430|     28|inline void url::update_base_hostname(std::string_view input) { host = input; }
_ZN3ada3url20update_base_pathnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 5447|  6.89k|inline void url::update_base_pathname(const std::string_view input) {
 5448|  6.89k|  path = input;
 5449|  6.89k|}
_ZN3ada3url10parse_portENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEb:
 5528|  1.44k|                                         bool check_trailing_content) noexcept {
 5529|  1.44k|  ada_log("parse_port('", view, "') ", view.size());
 5530|  1.44k|  uint16_t parsed_port{};
 5531|  1.44k|  auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port);
 5532|  1.44k|  if (r.ec == std::errc::result_out_of_range) {
  ------------------
  |  Branch (5532:7): [True: 64, False: 1.37k]
  ------------------
 5533|     64|    ada_log("parse_port: std::errc::result_out_of_range");
 5534|     64|    is_valid = false;
 5535|     64|    return 0;
 5536|     64|  }
 5537|  1.37k|  ada_log("parse_port: ", parsed_port);
 5538|  1.37k|  const size_t consumed = size_t(r.ptr - view.data());
 5539|  1.37k|  ada_log("parse_port: consumed ", consumed);
 5540|  1.37k|  if (check_trailing_content) {
  ------------------
  |  Branch (5540:7): [True: 706, False: 670]
  ------------------
 5541|    706|    is_valid &=
 5542|    706|        (consumed == view.size() || view[consumed] == '/' ||
  ------------------
  |  Branch (5542:10): [True: 572, False: 134]
  |  Branch (5542:37): [True: 37, False: 97]
  ------------------
 5543|    706|         view[consumed] == '?' || (is_special() && view[consumed] == '\\'));
  ------------------
  |  Branch (5543:10): [True: 35, False: 62]
  |  Branch (5543:36): [True: 59, False: 3]
  |  Branch (5543:52): [True: 0, False: 59]
  ------------------
 5544|    706|  }
 5545|  1.37k|  ada_log("parse_port: is_valid = ", is_valid);
 5546|  1.37k|  if (is_valid) {
  ------------------
  |  Branch (5546:7): [True: 1.16k, False: 210]
  ------------------
 5547|       |    // scheme_default_port can return 0, and we should allow 0 as a base port.
 5548|  1.16k|    auto default_port = scheme_default_port();
 5549|  1.16k|    bool is_port_valid = (default_port == 0 && parsed_port == 0) ||
  ------------------
  |  Branch (5549:27): [True: 195, False: 971]
  |  Branch (5549:48): [True: 107, False: 88]
  ------------------
 5550|  1.16k|                         (default_port != parsed_port);
  ------------------
  |  Branch (5550:26): [True: 1.05k, False: 6]
  ------------------
 5551|  1.16k|    port = (r.ec == std::errc() && is_port_valid)
  ------------------
  |  Branch (5551:13): [True: 496, False: 670]
  |  Branch (5551:36): [True: 490, False: 6]
  ------------------
 5552|  1.16k|               ? std::optional<uint16_t>(parsed_port)
 5553|  1.16k|               : std::nullopt;
 5554|  1.16k|  }
 5555|  1.37k|  return consumed;
 5556|  1.44k|}
_ZNK3ada8url_base19scheme_default_portEv:
 5309|  3.05k|url_base::scheme_default_port() const noexcept {
 5310|  3.05k|  return scheme::get_special_port(type);
 5311|  3.05k|}
_ZN3ada6scheme16get_special_portENS0_4typeE:
 4196|  3.47k|constexpr uint16_t get_special_port(ada::scheme::type type) noexcept {
 4197|  3.47k|  return details::special_ports[int(type)];
 4198|  3.47k|}
_ZN3ada8checkers23is_windows_drive_letterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
  980|  33.5k|inline constexpr bool is_windows_drive_letter(std::string_view input) noexcept {
  981|  33.5k|  return input.size() >= 2 &&
  ------------------
  |  Branch (981:10): [True: 27.9k, False: 5.57k]
  ------------------
  982|  33.5k|         (is_alpha(input[0]) && ((input[1] == ':') || (input[1] == '|'))) &&
  ------------------
  |  Branch (982:11): [True: 20.1k, False: 7.80k]
  |  Branch (982:34): [True: 5.33k, False: 14.8k]
  |  Branch (982:55): [True: 1.21k, False: 13.5k]
  ------------------
  983|  33.5k|         ((input.size() == 2) || (input[2] == '/' || input[2] == '\\' ||
  ------------------
  |  Branch (983:11): [True: 2.73k, False: 3.81k]
  |  Branch (983:35): [True: 1.82k, False: 1.98k]
  |  Branch (983:54): [True: 24, False: 1.96k]
  ------------------
  984|  3.81k|                                  input[2] == '?' || input[2] == '#'));
  ------------------
  |  Branch (984:35): [True: 53, False: 1.90k]
  |  Branch (984:54): [True: 47, False: 1.86k]
  ------------------
  985|  33.5k|}
_ZN3ada8checkers34is_normalized_windows_drive_letterENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
  988|  6.31k|    std::string_view input) noexcept {
  989|  6.31k|  return input.size() >= 2 && (is_alpha(input[0]) && (input[1] == ':'));
  ------------------
  |  Branch (989:10): [True: 4.68k, False: 1.62k]
  |  Branch (989:32): [True: 3.46k, False: 1.22k]
  |  Branch (989:54): [True: 1.65k, False: 1.80k]
  ------------------
  990|  6.31k|}
_ZN3ada3url20set_protocol_as_fileEv:
 5475|  1.61k|inline void url::set_protocol_as_file() { type = ada::scheme::type::FILE; }
_ZN3ada14url_aggregatorC2Ev:
 4500|  73.6k|  url_aggregator() = default;
_ZN3ada7helpers14leading_zeroesEj:
 1636|  45.4k|inline int leading_zeroes(uint32_t input_num) noexcept {
 1637|       |#if ADA_REGULAR_VISUAL_STUDIO
 1638|       |  unsigned long leading_zero(0);
 1639|       |  unsigned long in(input_num);
 1640|       |  return _BitScanReverse(&leading_zero, in) ? int(31 - leading_zero) : 32;
 1641|       |#else
 1642|  45.4k|  return __builtin_clz(input_num);
 1643|  45.4k|#endif  // ADA_REGULAR_VISUAL_STUDIO
 1644|  45.4k|}
_ZN3ada14url_aggregator7reserveEj:
 6346|  45.4k|inline void ada::url_aggregator::reserve(uint32_t capacity) {
 6347|  45.4k|  buffer.reserve(capacity);
 6348|  45.4k|}
_ZN3ada14url_aggregator20update_base_pathnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 5842|  25.3k|inline void url_aggregator::update_base_pathname(const std::string_view input) {
 5843|  25.3k|  ada_log("url_aggregator::update_base_pathname '", input, "' [", input.size(),
 5844|  25.3k|          " bytes] \n", to_diagram());
 5845|  25.3k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 5846|  25.3k|  ADA_ASSERT_TRUE(validate());
 5847|       |
 5848|  25.3k|  const bool begins_with_dashdash = checkers::begins_with(input, "//");
 5849|  25.3k|  if (!begins_with_dashdash && has_dash_dot()) {
  ------------------
  |  Branch (5849:7): [True: 24.9k, False: 356]
  |  Branch (5849:32): [True: 36, False: 24.9k]
  ------------------
 5850|     36|    ada_log("url_aggregator::update_base_pathname has /.: \n", to_diagram());
 5851|       |    // We must delete the ./
 5852|     36|    delete_dash_dot();
 5853|     36|  }
 5854|       |
 5855|  25.3k|  if (begins_with_dashdash && !has_opaque_path && !has_authority() &&
  ------------------
  |  Branch (5855:7): [True: 356, False: 24.9k]
  |  Branch (5855:31): [True: 355, False: 1]
  |  Branch (5855:51): [True: 133, False: 222]
  ------------------
 5856|  25.3k|      !has_dash_dot()) {
  ------------------
  |  Branch (5856:7): [True: 120, False: 13]
  ------------------
 5857|       |    // If url’s host is null, url does not have an opaque path, url’s path’s
 5858|       |    // size is greater than 1, then append U+002F (/) followed by U+002E (.) to
 5859|       |    // output.
 5860|    120|    buffer.insert(components.pathname_start, "/.");
 5861|    120|    components.pathname_start += 2;
 5862|    120|  }
 5863|       |
 5864|  25.3k|  uint32_t difference = replace_and_resize(
 5865|  25.3k|      components.pathname_start,
 5866|  25.3k|      components.pathname_start + get_pathname_length(), input);
 5867|  25.3k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (5867:7): [True: 162, False: 25.1k]
  ------------------
 5868|    162|    components.search_start += difference;
 5869|    162|  }
 5870|  25.3k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (5870:7): [True: 151, False: 25.1k]
  ------------------
 5871|    151|    components.hash_start += difference;
 5872|    151|  }
 5873|  25.3k|  ada_log("url_aggregator::update_base_pathname end '", input, "' [",
 5874|  25.3k|          input.size(), " bytes] \n", to_diagram());
 5875|  25.3k|  ADA_ASSERT_TRUE(validate());
 5876|  25.3k|}
_ZN3ada14url_aggregator18replace_and_resizeEjjNSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 5685|  55.3k|    uint32_t start, uint32_t end, std::string_view input) {
 5686|  55.3k|  uint32_t current_length = end - start;
 5687|  55.3k|  uint32_t input_size = uint32_t(input.size());
 5688|  55.3k|  uint32_t new_difference = input_size - current_length;
 5689|       |
 5690|  55.3k|  if (current_length == 0) {
  ------------------
  |  Branch (5690:7): [True: 49.2k, False: 6.11k]
  ------------------
 5691|  49.2k|    buffer.insert(start, input);
 5692|  49.2k|  } else if (input_size == current_length) {
  ------------------
  |  Branch (5692:14): [True: 1.66k, False: 4.44k]
  ------------------
 5693|  1.66k|    buffer.replace(start, input_size, input);
 5694|  4.44k|  } else if (input_size < current_length) {
  ------------------
  |  Branch (5694:14): [True: 1.69k, False: 2.75k]
  ------------------
 5695|  1.69k|    buffer.erase(start, current_length - input_size);
 5696|  1.69k|    buffer.replace(start, input_size, input);
 5697|  2.75k|  } else {
 5698|  2.75k|    buffer.replace(start, current_length, input.substr(0, current_length));
 5699|  2.75k|    buffer.insert(start + current_length, input.substr(current_length));
 5700|  2.75k|  }
 5701|       |
 5702|  55.3k|  return new_difference;
 5703|  55.3k|}
_ZNK3ada14url_aggregator19get_pathname_lengthEv:
 5734|  25.3k|url_aggregator::get_pathname_length() const noexcept {
 5735|  25.3k|  ada_log("url_aggregator::get_pathname_length");
 5736|  25.3k|  uint32_t ending_index = uint32_t(buffer.size());
 5737|  25.3k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (5737:7): [True: 162, False: 25.1k]
  ------------------
 5738|    162|    ending_index = components.search_start;
 5739|  25.1k|  } else if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (5739:14): [True: 135, False: 25.0k]
  ------------------
 5740|    135|    ending_index = components.hash_start;
 5741|    135|  }
 5742|  25.3k|  return ending_index - components.pathname_start;
 5743|  25.3k|}
_ZN3ada14url_aggregator18update_base_searchENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 5750|  1.13k|inline void url_aggregator::update_base_search(std::string_view input) {
 5751|  1.13k|  ada_log("url_aggregator::update_base_search ", input);
 5752|  1.13k|  ADA_ASSERT_TRUE(validate());
 5753|  1.13k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 5754|  1.13k|  if (input.empty()) {
  ------------------
  |  Branch (5754:7): [True: 1.09k, False: 41]
  ------------------
 5755|  1.09k|    clear_search();
 5756|  1.09k|    return;
 5757|  1.09k|  }
 5758|       |
 5759|     41|  if (input[0] == '?') {
  ------------------
  |  Branch (5759:7): [True: 41, False: 0]
  ------------------
 5760|     41|    input.remove_prefix(1);
 5761|     41|  }
 5762|       |
 5763|     41|  if (components.hash_start == url_components::omitted) {
  ------------------
  |  Branch (5763:7): [True: 41, False: 0]
  ------------------
 5764|     41|    if (components.search_start == url_components::omitted) {
  ------------------
  |  Branch (5764:9): [True: 41, False: 0]
  ------------------
 5765|     41|      components.search_start = uint32_t(buffer.size());
 5766|     41|      buffer += "?";
 5767|     41|    } else {
 5768|      0|      buffer.resize(components.search_start + 1);
 5769|      0|    }
 5770|       |
 5771|     41|    buffer.append(input);
 5772|     41|  } else {
 5773|      0|    if (components.search_start == url_components::omitted) {
  ------------------
  |  Branch (5773:9): [True: 0, False: 0]
  ------------------
 5774|      0|      components.search_start = components.hash_start;
 5775|      0|    } else {
 5776|      0|      buffer.erase(components.search_start,
 5777|      0|                   components.hash_start - components.search_start);
 5778|      0|      components.hash_start = components.search_start;
 5779|      0|    }
 5780|       |
 5781|      0|    buffer.insert(components.search_start, "?");
 5782|      0|    buffer.insert(components.search_start + 1, input);
 5783|      0|    components.hash_start += uint32_t(input.size() + 1);  // Do not forget `?`
 5784|      0|  }
 5785|       |
 5786|     41|  ADA_ASSERT_TRUE(validate());
 5787|     41|}
_ZN3ada14url_aggregator26update_unencoded_base_hashENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 5661|  2.29k|inline void url_aggregator::update_unencoded_base_hash(std::string_view input) {
 5662|  2.29k|  ada_log("url_aggregator::update_unencoded_base_hash ", input, " [",
 5663|  2.29k|          input.size(), " bytes], buffer is '", buffer, "' [", buffer.size(),
 5664|  2.29k|          " bytes] components.hash_start = ", components.hash_start);
 5665|  2.29k|  ADA_ASSERT_TRUE(validate());
 5666|  2.29k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 5667|  2.29k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (5667:7): [True: 137, False: 2.15k]
  ------------------
 5668|    137|    buffer.resize(components.hash_start);
 5669|    137|  }
 5670|  2.29k|  components.hash_start = uint32_t(buffer.size());
 5671|  2.29k|  buffer += "#";
 5672|  2.29k|  bool encoding_required = unicode::percent_encode<true>(
 5673|  2.29k|      input, ada::character_sets::FRAGMENT_PERCENT_ENCODE, buffer);
 5674|       |  // When encoding_required is false, then buffer is left unchanged, and percent
 5675|       |  // encoding was not deemed required.
 5676|  2.29k|  if (!encoding_required) {
  ------------------
  |  Branch (5676:7): [True: 1.54k, False: 752]
  ------------------
 5677|  1.54k|    buffer.append(input);
 5678|  1.54k|  }
 5679|  2.29k|  ada_log("url_aggregator::update_unencoded_base_hash final buffer is '",
 5680|  2.29k|          buffer, "' [", buffer.size(), " bytes]");
 5681|  2.29k|  ADA_ASSERT_TRUE(validate());
 5682|  2.29k|}
_ZN3ada14url_aggregator20append_base_passwordENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6067|  3.07k|inline void url_aggregator::append_base_password(const std::string_view input) {
 6068|  3.07k|  ada_log("url_aggregator::append_base_password ", input, " ", to_string(),
 6069|  3.07k|          "\n", to_diagram());
 6070|  3.07k|  ADA_ASSERT_TRUE(validate());
 6071|  3.07k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 6072|       |#if ADA_DEVELOPMENT_CHECKS
 6073|       |  // computing the expected password.
 6074|       |  std::string password_expected = std::string(get_password());
 6075|       |  password_expected.append(input);
 6076|       |#endif  // ADA_DEVELOPMENT_CHECKS
 6077|  3.07k|  add_authority_slashes_if_needed();
 6078|       |
 6079|       |  // If input is empty, do nothing.
 6080|  3.07k|  if (input.empty()) {
  ------------------
  |  Branch (6080:7): [True: 1.23k, False: 1.84k]
  ------------------
 6081|  1.23k|    return;
 6082|  1.23k|  }
 6083|       |
 6084|  1.84k|  uint32_t difference = uint32_t(input.size());
 6085|  1.84k|  if (has_password()) {
  ------------------
  |  Branch (6085:7): [True: 1.55k, False: 290]
  ------------------
 6086|  1.55k|    buffer.insert(components.host_start, input);
 6087|  1.55k|  } else {
 6088|    290|    difference++;  // Increment for ":"
 6089|    290|    buffer.insert(components.username_end, ":");
 6090|    290|    buffer.insert(components.username_end + 1, input);
 6091|    290|  }
 6092|  1.84k|  components.host_start += difference;
 6093|       |
 6094|       |  // The following line is required to add "@" to hostname. When updating
 6095|       |  // password if hostname does not start with "@", it is "append_base_password"s
 6096|       |  // responsibility to set it.
 6097|  1.84k|  if (buffer[components.host_start] != '@') {
  ------------------
  |  Branch (6097:7): [True: 227, False: 1.61k]
  ------------------
 6098|    227|    buffer.insert(components.host_start, "@");
 6099|    227|    difference++;
 6100|    227|  }
 6101|       |
 6102|  1.84k|  components.host_end += difference;
 6103|  1.84k|  components.pathname_start += difference;
 6104|  1.84k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6104:7): [True: 0, False: 1.84k]
  ------------------
 6105|      0|    components.search_start += difference;
 6106|      0|  }
 6107|  1.84k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6107:7): [True: 0, False: 1.84k]
  ------------------
 6108|      0|    components.hash_start += difference;
 6109|      0|  }
 6110|       |#if ADA_DEVELOPMENT_CHECKS
 6111|       |  std::string password_after = std::string(get_password());
 6112|       |  ADA_ASSERT_EQUAL(
 6113|       |      password_expected, password_after,
 6114|       |      "append_base_password problem after inserting " + std::string(input));
 6115|       |#endif  // ADA_DEVELOPMENT_CHECKS
 6116|  1.84k|  ADA_ASSERT_TRUE(validate());
 6117|  1.84k|}
_ZN3ada14url_aggregator31add_authority_slashes_if_neededEv:
 6320|  46.7k|inline void ada::url_aggregator::add_authority_slashes_if_needed() noexcept {
 6321|  46.7k|  ada_log("url_aggregator::add_authority_slashes_if_needed");
 6322|  46.7k|  ADA_ASSERT_TRUE(validate());
 6323|       |  // Protocol setter will insert `http:` to the URL. It is up to hostname setter
 6324|       |  // to insert
 6325|       |  // `//` initially to the buffer, since it depends on the hostname existence.
 6326|  46.7k|  if (has_authority()) {
  ------------------
  |  Branch (6326:7): [True: 30.7k, False: 16.0k]
  ------------------
 6327|  30.7k|    return;
 6328|  30.7k|  }
 6329|       |  // Performance: the common case is components.protocol_end == buffer.size()
 6330|       |  // Optimization opportunity: in many cases, the "//" is part of the input and
 6331|       |  // the insert could be fused with another insert.
 6332|  16.0k|  buffer.insert(components.protocol_end, "//");
 6333|  16.0k|  components.username_end += 2;
 6334|  16.0k|  components.host_start += 2;
 6335|  16.0k|  components.host_end += 2;
 6336|  16.0k|  components.pathname_start += 2;
 6337|  16.0k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6337:7): [True: 21, False: 16.0k]
  ------------------
 6338|     21|    components.search_start += 2;
 6339|     21|  }
 6340|  16.0k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6340:7): [True: 23, False: 16.0k]
  ------------------
 6341|     23|    components.hash_start += 2;
 6342|     23|  }
 6343|  16.0k|  ADA_ASSERT_TRUE(validate());
 6344|  16.0k|}
_ZN3ada14url_aggregator20append_base_usernameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 5949|  9.43k|inline void url_aggregator::append_base_username(const std::string_view input) {
 5950|  9.43k|  ada_log("url_aggregator::append_base_username ", input);
 5951|  9.43k|  ADA_ASSERT_TRUE(validate());
 5952|  9.43k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 5953|       |#if ADA_DEVELOPMENT_CHECKS
 5954|       |  // computing the expected password.
 5955|       |  std::string username_expected = std::string(get_username());
 5956|       |  username_expected.append(input);
 5957|       |#endif  // ADA_DEVELOPMENT_CHECKS
 5958|  9.43k|  add_authority_slashes_if_needed();
 5959|       |
 5960|       |  // If input is empty, do nothing.
 5961|  9.43k|  if (input.empty()) {
  ------------------
  |  Branch (5961:7): [True: 3.92k, False: 5.51k]
  ------------------
 5962|  3.92k|    return;
 5963|  3.92k|  }
 5964|       |
 5965|  5.51k|  uint32_t difference = uint32_t(input.size());
 5966|  5.51k|  buffer.insert(components.username_end, input);
 5967|  5.51k|  components.username_end += difference;
 5968|  5.51k|  components.host_start += difference;
 5969|       |
 5970|  5.51k|  if (buffer[components.host_start] != '@' &&
  ------------------
  |  Branch (5970:7): [True: 583, False: 4.92k]
  ------------------
 5971|  5.51k|      components.host_start != components.host_end) {
  ------------------
  |  Branch (5971:7): [True: 583, False: 0]
  ------------------
 5972|    583|    buffer.insert(components.host_start, "@");
 5973|    583|    difference++;
 5974|    583|  }
 5975|       |
 5976|  5.51k|  components.host_end += difference;
 5977|  5.51k|  components.pathname_start += difference;
 5978|  5.51k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (5978:7): [True: 0, False: 5.51k]
  ------------------
 5979|      0|    components.search_start += difference;
 5980|      0|  }
 5981|  5.51k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (5981:7): [True: 0, False: 5.51k]
  ------------------
 5982|      0|    components.hash_start += difference;
 5983|      0|  }
 5984|       |#if ADA_DEVELOPMENT_CHECKS
 5985|       |  std::string username_after = std::string(get_username());
 5986|       |  ADA_ASSERT_EQUAL(
 5987|       |      username_expected, username_after,
 5988|       |      "append_base_username problem after inserting " + std::string(input));
 5989|       |#endif  // ADA_DEVELOPMENT_CHECKS
 5990|  5.51k|  ADA_ASSERT_TRUE(validate());
 5991|  5.51k|}
_ZN3ada14url_aggregator21update_base_authorityENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEERKNS_14url_componentsE:
 5603|    767|    std::string_view base_buffer, const ada::url_components &base) {
 5604|    767|  std::string_view input = base_buffer.substr(
 5605|    767|      base.protocol_end, base.host_start - base.protocol_end);
 5606|    767|  ada_log("url_aggregator::update_base_authority ", input);
 5607|       |
 5608|    767|  bool input_starts_with_dash = checkers::begins_with(input, "//");
 5609|    767|  uint32_t diff = components.host_start - components.protocol_end;
 5610|       |
 5611|    767|  buffer.erase(components.protocol_end,
 5612|    767|               components.host_start - components.protocol_end);
 5613|    767|  components.username_end = components.protocol_end;
 5614|       |
 5615|    767|  if (input_starts_with_dash) {
  ------------------
  |  Branch (5615:7): [True: 641, False: 126]
  ------------------
 5616|    641|    input.remove_prefix(2);
 5617|    641|    diff += 2;  // add "//"
 5618|    641|    buffer.insert(components.protocol_end, "//");
 5619|    641|    components.username_end += 2;
 5620|    641|  }
 5621|       |
 5622|    767|  size_t password_delimiter = input.find(':');
 5623|       |
 5624|       |  // Check if input contains both username and password by checking the
 5625|       |  // delimiter: ":" A typical input that contains authority would be "user:pass"
 5626|    767|  if (password_delimiter != std::string_view::npos) {
  ------------------
  |  Branch (5626:7): [True: 26, False: 741]
  ------------------
 5627|       |    // Insert both username and password
 5628|     26|    std::string_view username = input.substr(0, password_delimiter);
 5629|     26|    std::string_view password = input.substr(password_delimiter + 1);
 5630|       |
 5631|     26|    buffer.insert(components.protocol_end + diff, username);
 5632|     26|    diff += uint32_t(username.size());
 5633|     26|    buffer.insert(components.protocol_end + diff, ":");
 5634|     26|    components.username_end = components.protocol_end + diff;
 5635|     26|    buffer.insert(components.protocol_end + diff + 1, password);
 5636|     26|    diff += uint32_t(password.size()) + 1;
 5637|    741|  } else if (!input.empty()) {
  ------------------
  |  Branch (5637:14): [True: 15, False: 726]
  ------------------
 5638|       |    // Insert only username
 5639|     15|    buffer.insert(components.protocol_end + diff, input);
 5640|     15|    components.username_end =
 5641|     15|        components.protocol_end + diff + uint32_t(input.size());
 5642|     15|    diff += uint32_t(input.size());
 5643|     15|  }
 5644|       |
 5645|    767|  components.host_start += diff;
 5646|       |
 5647|    767|  if (buffer.size() > base.host_start && buffer[base.host_start] != '@') {
  ------------------
  |  Branch (5647:7): [True: 0, False: 767]
  |  Branch (5647:42): [True: 0, False: 0]
  ------------------
 5648|      0|    buffer.insert(components.host_start, "@");
 5649|      0|    diff++;
 5650|      0|  }
 5651|    767|  components.host_end += diff;
 5652|    767|  components.pathname_start += diff;
 5653|    767|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (5653:7): [True: 0, False: 767]
  ------------------
 5654|      0|    components.search_start += diff;
 5655|      0|  }
 5656|    767|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (5656:7): [True: 0, False: 767]
  ------------------
 5657|      0|    components.hash_start += diff;
 5658|      0|  }
 5659|    767|}
_ZNK3ada14url_aggregator8get_hrefEv:
 6410|    767|inline std::string_view url_aggregator::get_href() const noexcept {
 6411|    767|  ada_log("url_aggregator::get_href");
 6412|    767|  return buffer;
 6413|    767|}
_ZNK3ada14url_aggregator14get_componentsEv:
 6307|    767|url_aggregator::get_components() const noexcept {
 6308|    767|  return components;
 6309|    767|}
_ZN3ada14url_aggregator16update_base_portEj:
 6119|  2.55k|inline void url_aggregator::update_base_port(uint32_t input) {
 6120|  2.55k|  ada_log("url_aggregator::update_base_port");
 6121|  2.55k|  ADA_ASSERT_TRUE(validate());
 6122|  2.55k|  if (input == url_components::omitted) {
  ------------------
  |  Branch (6122:7): [True: 1.67k, False: 882]
  ------------------
 6123|  1.67k|    clear_port();
 6124|  1.67k|    return;
 6125|  1.67k|  }
 6126|       |  // calling std::to_string(input.value()) is unfortunate given that the port
 6127|       |  // value is probably already available as a string.
 6128|    882|  std::string value = helpers::concat(":", std::to_string(input));
 6129|    882|  uint32_t difference = uint32_t(value.size());
 6130|       |
 6131|    882|  if (components.port != url_components::omitted) {
  ------------------
  |  Branch (6131:7): [True: 65, False: 817]
  ------------------
 6132|     65|    difference -= components.pathname_start - components.host_end;
 6133|     65|    buffer.erase(components.host_end,
 6134|     65|                 components.pathname_start - components.host_end);
 6135|     65|  }
 6136|       |
 6137|    882|  buffer.insert(components.host_end, value);
 6138|    882|  components.pathname_start += difference;
 6139|    882|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6139:7): [True: 203, False: 679]
  ------------------
 6140|    203|    components.search_start += difference;
 6141|    203|  }
 6142|    882|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6142:7): [True: 211, False: 671]
  ------------------
 6143|    211|    components.hash_start += difference;
 6144|    211|  }
 6145|    882|  components.port = input;
 6146|    882|  ADA_ASSERT_TRUE(validate());
 6147|    882|}
_ZN3ada7helpers6concatIJPKcNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEEEESA_DpT_:
 1627|    882|std::string concat(Args... args) {
 1628|    882|  std::string answer;
 1629|    882|  inner_concat(answer, args...);
 1630|    882|  return answer;
 1631|    882|}
_ZN3ada7helpers12inner_concatIPKcJNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEEEEEvRSA_T_DpT0_:
 1617|  4.92k|inline void inner_concat(std::string& buffer, T t, Args... args) {
 1618|  4.92k|  buffer.append(t);
 1619|  4.92k|  return inner_concat(buffer, args...);
 1620|  4.92k|}
_ZN3ada7helpers12inner_concatINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEJEEEvRS8_T_:
 1609|  4.92k|inline void inner_concat(std::string& buffer, T t) {
 1610|  4.92k|  buffer.append(t);
 1611|  4.92k|}
_ZNK3ada14url_aggregator18retrieve_base_portEv:
 6168|    767|inline uint32_t url_aggregator::retrieve_base_port() const {
 6169|    767|  ada_log("url_aggregator::retrieve_base_port");
 6170|    767|  return components.port;
 6171|    767|}
_ZN3ada14url_aggregator12clear_searchEv:
 6173|  8.10k|inline void url_aggregator::clear_search() {
 6174|  8.10k|  ada_log("url_aggregator::clear_search");
 6175|  8.10k|  ADA_ASSERT_TRUE(validate());
 6176|  8.10k|  if (components.search_start == url_components::omitted) {
  ------------------
  |  Branch (6176:7): [True: 7.93k, False: 175]
  ------------------
 6177|  7.93k|    return;
 6178|  7.93k|  }
 6179|       |
 6180|    175|  if (components.hash_start == url_components::omitted) {
  ------------------
  |  Branch (6180:7): [True: 163, False: 12]
  ------------------
 6181|    163|    buffer.resize(components.search_start);
 6182|    163|  } else {
 6183|     12|    buffer.erase(components.search_start,
 6184|     12|                 components.hash_start - components.search_start);
 6185|     12|    components.hash_start = components.search_start;
 6186|     12|  }
 6187|       |
 6188|    175|  components.search_start = url_components::omitted;
 6189|       |
 6190|       |#if ADA_DEVELOPMENT_CHECKS
 6191|       |  ADA_ASSERT_EQUAL(get_search(), "",
 6192|       |                   "search should have been cleared on buffer=" + buffer +
 6193|       |                       " with " + components.to_string() + "\n" + to_diagram());
 6194|       |#endif
 6195|    175|  ADA_ASSERT_TRUE(validate());
 6196|    175|}
_ZN3ada14url_aggregator18update_base_searchENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKh:
 5790|  2.28k|    std::string_view input, const uint8_t query_percent_encode_set[]) {
 5791|  2.28k|  ada_log("url_aggregator::update_base_search ", input,
 5792|  2.28k|          " with encoding parameter ", to_string(), "\n", to_diagram());
 5793|  2.28k|  ADA_ASSERT_TRUE(validate());
 5794|  2.28k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 5795|       |
 5796|  2.28k|  if (components.hash_start == url_components::omitted) {
  ------------------
  |  Branch (5796:7): [True: 2.15k, False: 137]
  ------------------
 5797|  2.15k|    if (components.search_start == url_components::omitted) {
  ------------------
  |  Branch (5797:9): [True: 2.05k, False: 95]
  ------------------
 5798|  2.05k|      components.search_start = uint32_t(buffer.size());
 5799|  2.05k|      buffer += "?";
 5800|  2.05k|    } else {
 5801|     95|      buffer.resize(components.search_start + 1);
 5802|     95|    }
 5803|       |
 5804|  2.15k|    bool encoding_required =
 5805|  2.15k|        unicode::percent_encode<true>(input, query_percent_encode_set, buffer);
 5806|       |    // When encoding_required is false, then buffer is left unchanged, and
 5807|       |    // percent encoding was not deemed required.
 5808|  2.15k|    if (!encoding_required) {
  ------------------
  |  Branch (5808:9): [True: 1.41k, False: 733]
  ------------------
 5809|  1.41k|      buffer.append(input);
 5810|  1.41k|    }
 5811|  2.15k|  } else {
 5812|    137|    if (components.search_start == url_components::omitted) {
  ------------------
  |  Branch (5812:9): [True: 123, False: 14]
  ------------------
 5813|    123|      components.search_start = components.hash_start;
 5814|    123|    } else {
 5815|     14|      buffer.erase(components.search_start,
 5816|     14|                   components.hash_start - components.search_start);
 5817|     14|      components.hash_start = components.search_start;
 5818|     14|    }
 5819|       |
 5820|    137|    buffer.insert(components.search_start, "?");
 5821|    137|    size_t idx =
 5822|    137|        ada::unicode::percent_encode_index(input, query_percent_encode_set);
 5823|    137|    if (idx == input.size()) {
  ------------------
  |  Branch (5823:9): [True: 58, False: 79]
  ------------------
 5824|     58|      buffer.insert(components.search_start + 1, input);
 5825|     58|      components.hash_start += uint32_t(input.size() + 1);  // Do not forget `?`
 5826|     79|    } else {
 5827|     79|      buffer.insert(components.search_start + 1, input, 0, idx);
 5828|     79|      input.remove_prefix(idx);
 5829|       |      // We only create a temporary string if we need percent encoding and
 5830|       |      // we attempt to create as small a temporary string as we can.
 5831|     79|      std::string encoded =
 5832|     79|          ada::unicode::percent_encode(input, query_percent_encode_set);
 5833|     79|      buffer.insert(components.search_start + idx + 1, encoded);
 5834|     79|      components.hash_start +=
 5835|     79|          uint32_t(encoded.size() + idx + 1);  // Do not forget `?`
 5836|     79|    }
 5837|    137|  }
 5838|       |
 5839|  2.28k|  ADA_ASSERT_TRUE(validate());
 5840|  2.28k|}
_ZN3ada14url_aggregator20update_base_hostnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 5705|  22.4k|inline void url_aggregator::update_base_hostname(const std::string_view input) {
 5706|  22.4k|  ada_log("url_aggregator::update_base_hostname ", input, " [", input.size(),
 5707|  22.4k|          " bytes], buffer is '", buffer, "' [", buffer.size(), " bytes]");
 5708|  22.4k|  ADA_ASSERT_TRUE(validate());
 5709|  22.4k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 5710|       |
 5711|       |  // This next line is required for when parsing a URL like `foo://`
 5712|  22.4k|  add_authority_slashes_if_needed();
 5713|       |
 5714|  22.4k|  bool has_credentials = components.protocol_end + 2 < components.host_start;
 5715|  22.4k|  uint32_t new_difference =
 5716|  22.4k|      replace_and_resize(components.host_start, components.host_end, input);
 5717|       |
 5718|  22.4k|  if (has_credentials) {
  ------------------
  |  Branch (5718:7): [True: 2.06k, False: 20.3k]
  ------------------
 5719|  2.06k|    buffer.insert(components.host_start, "@");
 5720|  2.06k|    new_difference++;
 5721|  2.06k|  }
 5722|  22.4k|  components.host_end += new_difference;
 5723|  22.4k|  components.pathname_start += new_difference;
 5724|  22.4k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (5724:7): [True: 161, False: 22.3k]
  ------------------
 5725|    161|    components.search_start += new_difference;
 5726|    161|  }
 5727|  22.4k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (5727:7): [True: 167, False: 22.2k]
  ------------------
 5728|    167|    components.hash_start += new_difference;
 5729|    167|  }
 5730|  22.4k|  ADA_ASSERT_TRUE(validate());
 5731|  22.4k|}
_ZN3ada14url_aggregator10parse_portENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEb:
 6416|  2.22k|    std::string_view view, bool check_trailing_content) noexcept {
 6417|  2.22k|  ada_log("url_aggregator::parse_port('", view, "') ", view.size());
 6418|  2.22k|  uint16_t parsed_port{};
 6419|  2.22k|  auto r = std::from_chars(view.data(), view.data() + view.size(), parsed_port);
 6420|  2.22k|  if (r.ec == std::errc::result_out_of_range) {
  ------------------
  |  Branch (6420:7): [True: 76, False: 2.14k]
  ------------------
 6421|     76|    ada_log("parse_port: std::errc::result_out_of_range");
 6422|     76|    is_valid = false;
 6423|     76|    return 0;
 6424|     76|  }
 6425|  2.14k|  ada_log("parse_port: ", parsed_port);
 6426|  2.14k|  const size_t consumed = size_t(r.ptr - view.data());
 6427|  2.14k|  ada_log("parse_port: consumed ", consumed);
 6428|  2.14k|  if (check_trailing_content) {
  ------------------
  |  Branch (6428:7): [True: 1.59k, False: 550]
  ------------------
 6429|  1.59k|    is_valid &=
 6430|  1.59k|        (consumed == view.size() || view[consumed] == '/' ||
  ------------------
  |  Branch (6430:10): [True: 1.29k, False: 299]
  |  Branch (6430:37): [True: 85, False: 214]
  ------------------
 6431|  1.59k|         view[consumed] == '?' || (is_special() && view[consumed] == '\\'));
  ------------------
  |  Branch (6431:10): [True: 76, False: 138]
  |  Branch (6431:36): [True: 131, False: 7]
  |  Branch (6431:52): [True: 2, False: 129]
  ------------------
 6432|  1.59k|  }
 6433|  2.14k|  ada_log("parse_port: is_valid = ", is_valid);
 6434|  2.14k|  if (is_valid) {
  ------------------
  |  Branch (6434:7): [True: 1.88k, False: 261]
  ------------------
 6435|  1.88k|    ada_log("parse_port", r.ec == std::errc());
 6436|       |    // scheme_default_port can return 0, and we should allow 0 as a base port.
 6437|  1.88k|    auto default_port = scheme_default_port();
 6438|  1.88k|    bool is_port_valid = (default_port == 0 && parsed_port == 0) ||
  ------------------
  |  Branch (6438:27): [True: 237, False: 1.64k]
  |  Branch (6438:48): [True: 84, False: 153]
  ------------------
 6439|  1.88k|                         (default_port != parsed_port);
  ------------------
  |  Branch (6439:26): [True: 1.78k, False: 13]
  ------------------
 6440|  1.88k|    if (r.ec == std::errc() && is_port_valid) {
  ------------------
  |  Branch (6440:9): [True: 842, False: 1.04k]
  |  Branch (6440:32): [True: 829, False: 13]
  ------------------
 6441|    829|      update_base_port(parsed_port);
 6442|  1.05k|    } else {
 6443|  1.05k|      clear_port();
 6444|  1.05k|    }
 6445|  1.88k|  }
 6446|  2.14k|  return consumed;
 6447|  2.22k|}
_ZN3ada14url_aggregator20append_base_pathnameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 5878|      3|inline void url_aggregator::append_base_pathname(const std::string_view input) {
 5879|      3|  ada_log("url_aggregator::append_base_pathname ", input, " ", to_string(),
 5880|      3|          "\n", to_diagram());
 5881|      3|  ADA_ASSERT_TRUE(validate());
 5882|      3|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 5883|       |#if ADA_DEVELOPMENT_CHECKS
 5884|       |  // computing the expected password.
 5885|       |  std::string path_expected = std::string(get_pathname());
 5886|       |  path_expected.append(input);
 5887|       |#endif  // ADA_DEVELOPMENT_CHECKS
 5888|      3|  uint32_t ending_index = uint32_t(buffer.size());
 5889|      3|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (5889:7): [True: 0, False: 3]
  ------------------
 5890|      0|    ending_index = components.search_start;
 5891|      3|  } else if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (5891:14): [True: 0, False: 3]
  ------------------
 5892|      0|    ending_index = components.hash_start;
 5893|      0|  }
 5894|      3|  buffer.insert(ending_index, input);
 5895|       |
 5896|      3|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (5896:7): [True: 0, False: 3]
  ------------------
 5897|      0|    components.search_start += uint32_t(input.size());
 5898|      0|  }
 5899|      3|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (5899:7): [True: 0, False: 3]
  ------------------
 5900|      0|    components.hash_start += uint32_t(input.size());
 5901|      0|  }
 5902|       |#if ADA_DEVELOPMENT_CHECKS
 5903|       |  std::string path_after = std::string(get_pathname());
 5904|       |  ADA_ASSERT_EQUAL(
 5905|       |      path_expected, path_after,
 5906|       |      "append_base_pathname problem after inserting " + std::string(input));
 5907|       |#endif  // ADA_DEVELOPMENT_CHECKS
 5908|      3|  ADA_ASSERT_TRUE(validate());
 5909|      3|}
_ZN3ada14url_aggregator20set_protocol_as_fileEv:
 6449|  4.69k|inline void url_aggregator::set_protocol_as_file() {
 6450|  4.69k|  ada_log("url_aggregator::set_protocol_as_file ");
 6451|  4.69k|  ADA_ASSERT_TRUE(validate());
 6452|  4.69k|  type = ada::scheme::type::FILE;
 6453|       |  // next line could overflow but unsigned arithmetic has well-defined
 6454|       |  // overflows.
 6455|  4.69k|  uint32_t new_difference = 5 - components.protocol_end;
 6456|       |
 6457|  4.69k|  if (buffer.empty()) {
  ------------------
  |  Branch (6457:7): [True: 562, False: 4.13k]
  ------------------
 6458|    562|    buffer.append("file:");
 6459|  4.13k|  } else {
 6460|  4.13k|    buffer.erase(0, components.protocol_end);
 6461|  4.13k|    buffer.insert(0, "file:");
 6462|  4.13k|  }
 6463|  4.69k|  components.protocol_end = 5;
 6464|       |
 6465|       |  // Update the rest of the components.
 6466|  4.69k|  components.username_end += new_difference;
 6467|  4.69k|  components.host_start += new_difference;
 6468|  4.69k|  components.host_end += new_difference;
 6469|  4.69k|  components.pathname_start += new_difference;
 6470|  4.69k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6470:7): [True: 0, False: 4.69k]
  ------------------
 6471|      0|    components.search_start += new_difference;
 6472|      0|  }
 6473|  4.69k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6473:7): [True: 0, False: 4.69k]
  ------------------
 6474|      0|    components.hash_start += new_difference;
 6475|      0|  }
 6476|  4.69k|  ADA_ASSERT_TRUE(validate());
 6477|  4.69k|}
_ZN3ada14url_aggregator14clear_pathnameEv:
 6215|  7.21k|inline void url_aggregator::clear_pathname() {
 6216|  7.21k|  ada_log("url_aggregator::clear_pathname");
 6217|  7.21k|  ADA_ASSERT_TRUE(validate());
 6218|  7.21k|  uint32_t ending_index = uint32_t(buffer.size());
 6219|  7.21k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6219:7): [True: 182, False: 7.03k]
  ------------------
 6220|    182|    ending_index = components.search_start;
 6221|  7.03k|  } else if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6221:14): [True: 157, False: 6.87k]
  ------------------
 6222|    157|    ending_index = components.hash_start;
 6223|    157|  }
 6224|  7.21k|  uint32_t pathname_length = ending_index - components.pathname_start;
 6225|  7.21k|  buffer.erase(components.pathname_start, pathname_length);
 6226|  7.21k|  uint32_t difference = pathname_length;
 6227|  7.21k|  if (components.pathname_start == components.host_end + 2 &&
  ------------------
  |  Branch (6227:7): [True: 132, False: 7.08k]
  ------------------
 6228|  7.21k|      buffer[components.host_end] == '/' &&
  ------------------
  |  Branch (6228:7): [True: 2, False: 130]
  ------------------
 6229|  7.21k|      buffer[components.host_end + 1] == '.') {
  ------------------
  |  Branch (6229:7): [True: 2, False: 0]
  ------------------
 6230|      2|    components.pathname_start -= 2;
 6231|      2|    buffer.erase(components.host_end, 2);
 6232|      2|    difference += 2;
 6233|      2|  }
 6234|  7.21k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6234:7): [True: 182, False: 7.03k]
  ------------------
 6235|    182|    components.search_start -= difference;
 6236|    182|  }
 6237|  7.21k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6237:7): [True: 176, False: 7.04k]
  ------------------
 6238|    176|    components.hash_start -= difference;
 6239|    176|  }
 6240|  7.21k|  ada_log("url_aggregator::clear_pathname completed, running checks...");
 6241|       |#if ADA_DEVELOPMENT_CHECKS
 6242|       |  ADA_ASSERT_EQUAL(get_pathname(), "",
 6243|       |                   "pathname should have been cleared on buffer=" + buffer +
 6244|       |                       " with " + components.to_string() + "\n" + to_diagram());
 6245|       |#endif
 6246|  7.21k|  ADA_ASSERT_TRUE(validate());
 6247|  7.21k|  ada_log("url_aggregator::clear_pathname completed, running checks... ok");
 6248|  7.21k|}
_ZNK3ada14url_aggregator31cannot_have_credentials_or_portEv:
 6300|  24.9k|inline bool url_aggregator::cannot_have_credentials_or_port() const {
 6301|  24.9k|  ada_log("url_aggregator::cannot_have_credentials_or_port");
 6302|  24.9k|  return type == ada::scheme::type::FILE ||
  ------------------
  |  Branch (6302:10): [True: 4.44k, False: 20.5k]
  ------------------
 6303|  24.9k|         components.host_start == components.host_end;
  ------------------
  |  Branch (6303:10): [True: 7.65k, False: 12.8k]
  ------------------
 6304|  24.9k|}
_ZN3ada7unicode20percent_encode_indexENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKh:
 5585|  9.49k|                                              const uint8_t character_set[]) {
 5586|  9.49k|  return std::distance(
 5587|  9.49k|      input.begin(),
 5588|  9.49k|      std::find_if(input.begin(), input.end(), [character_set](const char c) {
 5589|  9.49k|        return character_sets::bit_at(character_set, c);
 5590|  9.49k|      }));
 5591|  9.49k|}
_ZZN3ada7unicode20percent_encode_indexENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEEPKhENKUlcE_clEc:
 5588|  21.1k|      std::find_if(input.begin(), input.end(), [character_set](const char c) {
 5589|  21.1k|        return character_sets::bit_at(character_set, c);
 5590|  21.1k|      }));
_ZN3ada14url_aggregator20update_base_usernameENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 5911|  7.54k|inline void url_aggregator::update_base_username(const std::string_view input) {
 5912|  7.54k|  ada_log("url_aggregator::update_base_username '", input, "' ", to_string(),
 5913|  7.54k|          "\n", to_diagram());
 5914|  7.54k|  ADA_ASSERT_TRUE(validate());
 5915|  7.54k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 5916|       |
 5917|  7.54k|  add_authority_slashes_if_needed();
 5918|       |
 5919|  7.54k|  bool has_password = has_non_empty_password();
 5920|  7.54k|  bool host_starts_with_at = buffer.size() > components.host_start &&
  ------------------
  |  Branch (5920:30): [True: 7.54k, False: 0]
  ------------------
 5921|  7.54k|                             buffer[components.host_start] == '@';
  ------------------
  |  Branch (5921:30): [True: 146, False: 7.40k]
  ------------------
 5922|  7.54k|  uint32_t diff = replace_and_resize(components.protocol_end + 2,
 5923|  7.54k|                                     components.username_end, input);
 5924|       |
 5925|  7.54k|  components.username_end += diff;
 5926|  7.54k|  components.host_start += diff;
 5927|       |
 5928|  7.54k|  if (!input.empty() && !host_starts_with_at) {
  ------------------
  |  Branch (5928:7): [True: 902, False: 6.64k]
  |  Branch (5928:25): [True: 874, False: 28]
  ------------------
 5929|    874|    buffer.insert(components.host_start, "@");
 5930|    874|    diff++;
 5931|  6.67k|  } else if (input.empty() && host_starts_with_at && !has_password) {
  ------------------
  |  Branch (5931:14): [True: 6.64k, False: 28]
  |  Branch (5931:31): [True: 118, False: 6.52k]
  |  Branch (5931:54): [True: 81, False: 37]
  ------------------
 5932|       |    // Input is empty, there is no password, and we need to remove "@" from
 5933|       |    // hostname
 5934|     81|    buffer.erase(components.host_start, 1);
 5935|     81|    diff--;
 5936|     81|  }
 5937|       |
 5938|  7.54k|  components.host_end += diff;
 5939|  7.54k|  components.pathname_start += diff;
 5940|  7.54k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (5940:7): [True: 151, False: 7.39k]
  ------------------
 5941|    151|    components.search_start += diff;
 5942|    151|  }
 5943|  7.54k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (5943:7): [True: 155, False: 7.39k]
  ------------------
 5944|    155|    components.hash_start += diff;
 5945|    155|  }
 5946|  7.54k|  ADA_ASSERT_TRUE(validate());
 5947|  7.54k|}
_ZN3ada14url_aggregator20update_base_passwordENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 6013|  4.22k|inline void url_aggregator::update_base_password(const std::string_view input) {
 6014|  4.22k|  ada_log("url_aggregator::update_base_password ", input);
 6015|  4.22k|  ADA_ASSERT_TRUE(validate());
 6016|  4.22k|  ADA_ASSERT_TRUE(!helpers::overlaps(input, buffer));
 6017|       |
 6018|  4.22k|  add_authority_slashes_if_needed();
 6019|       |
 6020|       |  // TODO: Optimization opportunity. Merge the following removal functions.
 6021|  4.22k|  if (input.empty()) {
  ------------------
  |  Branch (6021:7): [True: 3.32k, False: 902]
  ------------------
 6022|  3.32k|    clear_password();
 6023|       |
 6024|       |    // Remove username too, if it is empty.
 6025|  3.32k|    if (!has_non_empty_username()) {
  ------------------
  |  Branch (6025:9): [True: 3.32k, False: 0]
  ------------------
 6026|  3.32k|      update_base_username("");
 6027|  3.32k|    }
 6028|       |
 6029|  3.32k|    return;
 6030|  3.32k|  }
 6031|       |
 6032|    902|  bool password_exists = has_password();
 6033|    902|  uint32_t difference = uint32_t(input.size());
 6034|       |
 6035|    902|  if (password_exists) {
  ------------------
  |  Branch (6035:7): [True: 6, False: 896]
  ------------------
 6036|      6|    uint32_t current_length =
 6037|      6|        components.host_start - components.username_end - 1;
 6038|      6|    buffer.erase(components.username_end + 1, current_length);
 6039|      6|    difference -= current_length;
 6040|    896|  } else {
 6041|    896|    buffer.insert(components.username_end, ":");
 6042|    896|    difference++;
 6043|    896|  }
 6044|       |
 6045|    902|  buffer.insert(components.username_end + 1, input);
 6046|    902|  components.host_start += difference;
 6047|       |
 6048|       |  // The following line is required to add "@" to hostname. When updating
 6049|       |  // password if hostname does not start with "@", it is "update_base_password"s
 6050|       |  // responsibility to set it.
 6051|    902|  if (buffer[components.host_start] != '@') {
  ------------------
  |  Branch (6051:7): [True: 0, False: 902]
  ------------------
 6052|      0|    buffer.insert(components.host_start, "@");
 6053|      0|    difference++;
 6054|      0|  }
 6055|       |
 6056|    902|  components.host_end += difference;
 6057|    902|  components.pathname_start += difference;
 6058|    902|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6058:7): [True: 65, False: 837]
  ------------------
 6059|     65|    components.search_start += difference;
 6060|     65|  }
 6061|    902|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6061:7): [True: 89, False: 813]
  ------------------
 6062|     89|    components.hash_start += difference;
 6063|     89|  }
 6064|    902|  ADA_ASSERT_TRUE(validate());
 6065|    902|}
_ZN3ada14url_aggregator14clear_passwordEv:
 5993|  3.32k|inline void url_aggregator::clear_password() {
 5994|  3.32k|  ada_log("url_aggregator::clear_password ", to_string(), "\n", to_diagram());
 5995|  3.32k|  ADA_ASSERT_TRUE(validate());
 5996|  3.32k|  if (!has_password()) {
  ------------------
  |  Branch (5996:7): [True: 3.28k, False: 37]
  ------------------
 5997|  3.28k|    return;
 5998|  3.28k|  }
 5999|       |
 6000|     37|  uint32_t diff = components.host_start - components.username_end;
 6001|     37|  buffer.erase(components.username_end, diff);
 6002|     37|  components.host_start -= diff;
 6003|     37|  components.host_end -= diff;
 6004|     37|  components.pathname_start -= diff;
 6005|     37|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6005:7): [True: 9, False: 28]
  ------------------
 6006|      9|    components.search_start -= diff;
 6007|      9|  }
 6008|     37|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6008:7): [True: 10, False: 27]
  ------------------
 6009|     10|    components.hash_start -= diff;
 6010|     10|  }
 6011|     37|}
_ZN3ada14url_aggregator10clear_portEv:
 6149|  6.03k|inline void url_aggregator::clear_port() {
 6150|  6.03k|  ada_log("url_aggregator::clear_port");
 6151|  6.03k|  ADA_ASSERT_TRUE(validate());
 6152|  6.03k|  if (components.port == url_components::omitted) {
  ------------------
  |  Branch (6152:7): [True: 5.77k, False: 267]
  ------------------
 6153|  5.77k|    return;
 6154|  5.77k|  }
 6155|    267|  uint32_t length = components.pathname_start - components.host_end;
 6156|    267|  buffer.erase(components.host_end, length);
 6157|    267|  components.pathname_start -= length;
 6158|    267|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6158:7): [True: 98, False: 169]
  ------------------
 6159|     98|    components.search_start -= length;
 6160|     98|  }
 6161|    267|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6161:7): [True: 101, False: 166]
  ------------------
 6162|    101|    components.hash_start -= length;
 6163|    101|  }
 6164|    267|  components.port = url_components::omitted;
 6165|    267|  ADA_ASSERT_TRUE(validate());
 6166|    267|}
_ZNK3ada14url_aggregator13has_authorityEv:
 6311|  54.3k|[[nodiscard]] inline bool ada::url_aggregator::has_authority() const noexcept {
 6312|  54.3k|  ada_log("url_aggregator::has_authority");
 6313|       |  // Performance: instead of doing this potentially expensive check, we could
 6314|       |  // have a boolean in the struct.
 6315|  54.3k|  return components.protocol_end + 2 <= components.host_start &&
  ------------------
  |  Branch (6315:10): [True: 34.4k, False: 19.9k]
  ------------------
 6316|  54.3k|         helpers::substring(buffer, components.protocol_end,
  ------------------
  |  Branch (6316:10): [True: 34.4k, False: 0]
  ------------------
 6317|  34.4k|                            components.protocol_end + 2) == "//";
 6318|  54.3k|}
_ZNK3ada14url_aggregator12has_dash_dotEv:
 6389|  29.4k|inline bool url_aggregator::has_dash_dot() const noexcept {
 6390|       |  // If url’s host is null, url does not have an opaque path, url’s path’s size
 6391|       |  // is greater than 1, and url’s path[0] is the empty string, then append
 6392|       |  // U+002F (/) followed by U+002E (.) to output.
 6393|  29.4k|  ada_log("url_aggregator::has_dash_dot");
 6394|       |  // Performance: instead of doing this potentially expensive check, we could
 6395|       |  // just have a boolean value in the structure.
 6396|       |#if ADA_DEVELOPMENT_CHECKS
 6397|       |  if (components.pathname_start + 1 < buffer.size() &&
 6398|       |      components.pathname_start == components.host_end + 2) {
 6399|       |    ADA_ASSERT_TRUE(buffer[components.host_end] == '/');
 6400|       |    ADA_ASSERT_TRUE(buffer[components.host_end + 1] == '.');
 6401|       |    ADA_ASSERT_TRUE(buffer[components.pathname_start] == '/');
 6402|       |    ADA_ASSERT_TRUE(buffer[components.pathname_start + 1] == '/');
 6403|       |  }
 6404|       |#endif
 6405|  29.4k|  return !has_opaque_path &&
  ------------------
  |  Branch (6405:10): [True: 24.3k, False: 5.18k]
  ------------------
 6406|  29.4k|         components.pathname_start == components.host_end + 2 &&
  ------------------
  |  Branch (6406:10): [True: 354, False: 23.9k]
  ------------------
 6407|  29.4k|         components.pathname_start + 1 < buffer.size();
  ------------------
  |  Branch (6407:10): [True: 108, False: 246]
  ------------------
 6408|  29.4k|}
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEEptEv:
 3636|   157k|  TL_EXPECTED_11_CONSTEXPR T *operator->() { return valptr(); }
_ZN2tl8expectedIN3ada14url_aggregatorENS1_6errorsEE6valptrEv:
 2974|   157k|  T *valptr() { return std::addressof(this->m_val); }
_ZNK3ada14url_aggregator22has_non_empty_usernameEv:
 6350|  14.6k|inline bool url_aggregator::has_non_empty_username() const noexcept {
 6351|  14.6k|  ada_log("url_aggregator::has_non_empty_username");
 6352|  14.6k|  return components.protocol_end + 2 < components.username_end;
 6353|  14.6k|}
_ZN3ada7helpers9substringERKNSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEEmm:
 1537|   124k|                                             size_t pos2) noexcept {
 1538|       |#if ADA_DEVELOPMENT_CHECKS
 1539|       |  if (pos2 < pos1) {
 1540|       |    std::cerr << "Negative-length substring: [" << pos1 << " to " << pos2 << ")"
 1541|       |              << std::endl;
 1542|       |    abort();
 1543|       |  }
 1544|       |#endif
 1545|   124k|  return std::string_view(input.data() + pos1, pos2 - pos1);
 1546|   124k|}
_ZNK3ada14url_aggregator22has_non_empty_passwordEv:
 6355|  18.8k|inline bool url_aggregator::has_non_empty_password() const noexcept {
 6356|  18.8k|  ada_log("url_aggregator::has_non_empty_password");
 6357|  18.8k|  return components.host_start - components.username_end > 0;
 6358|  18.8k|}
_ZNK3ada14url_aggregator15has_credentialsEv:
 6295|  3.09k|ada_really_inline bool url_aggregator::has_credentials() const noexcept {
 6296|  3.09k|  ada_log("url_aggregator::has_credentials");
 6297|  3.09k|  return has_non_empty_username() || has_non_empty_password();
  ------------------
  |  Branch (6297:10): [True: 36, False: 3.06k]
  |  Branch (6297:38): [True: 1, False: 3.06k]
  ------------------
 6298|  3.09k|}
_ZNK3ada14url_aggregator10is_at_pathEv:
 5746|  5.25k|    const noexcept {
 5747|  5.25k|  return buffer.size() == components.pathname_start;
 5748|  5.25k|}
_ZNK3ada14url_aggregator12has_hostnameEv:
 6380|  2.86k|inline bool url_aggregator::has_hostname() const noexcept {
 6381|  2.86k|  return has_authority();
 6382|  2.86k|}
_ZNK3ada14url_aggregator12has_passwordEv:
 6360|  6.06k|inline bool url_aggregator::has_password() const noexcept {
 6361|  6.06k|  ada_log("url_aggregator::has_password");
 6362|       |  // This function does not care about the length of the password
 6363|  6.06k|  return components.host_start > components.username_end &&
  ------------------
  |  Branch (6363:10): [True: 1.59k, False: 4.47k]
  ------------------
 6364|  6.06k|         buffer[components.username_end] == ':';
  ------------------
  |  Branch (6364:10): [True: 1.59k, False: 0]
  ------------------
 6365|  6.06k|}
_ZNK3ada3url8has_hashEv:
 5467|  1.82k|[[nodiscard]] inline bool url::has_hash() const noexcept {
 5468|  1.82k|  return hash.has_value();
 5469|  1.82k|}
_ZNK3ada3url10has_searchEv:
 5471|  1.73k|[[nodiscard]] inline bool url::has_search() const noexcept {
 5472|  1.73k|  return query.has_value();
 5473|  1.73k|}
_ZNK3ada14url_aggregator8has_hashEv:
 6285|  1.79k|[[nodiscard]] inline bool url_aggregator::has_hash() const noexcept {
 6286|  1.79k|  ada_log("url_aggregator::has_hash");
 6287|  1.79k|  return components.hash_start != url_components::omitted;
 6288|  1.79k|}
_ZNK3ada14url_aggregator10has_searchEv:
 6290|  1.72k|[[nodiscard]] inline bool url_aggregator::has_search() const noexcept {
 6291|  1.72k|  ada_log("url_aggregator::has_search");
 6292|  1.72k|  return components.search_start != url_components::omitted;
 6293|  1.72k|}
_ZN3ada7helpers6concatIJNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPKcS8_EEES8_DpT_:
 1627|  4.04k|std::string concat(Args... args) {
 1628|  4.04k|  std::string answer;
 1629|  4.04k|  inner_concat(answer, args...);
 1630|  4.04k|  return answer;
 1631|  4.04k|}
_ZN3ada7helpers12inner_concatINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEJPKcS8_EEEvRS8_T_DpT0_:
 1617|  4.04k|inline void inner_concat(std::string& buffer, T t, Args... args) {
 1618|  4.04k|  buffer.append(t);
 1619|  4.04k|  return inner_concat(buffer, args...);
 1620|  4.04k|}
_ZN3ada7helpers6concatIJNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKcEEENS2_12basic_stringIcS5_NS2_9allocatorIcEEEEDpT_:
 1627|  23.4k|std::string concat(Args... args) {
 1628|  23.4k|  std::string answer;
 1629|  23.4k|  inner_concat(answer, args...);
 1630|  23.4k|  return answer;
 1631|  23.4k|}
_ZN3ada7helpers12inner_concatINSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEJPKcEEEvRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEET_DpT0_:
 1617|  23.4k|inline void inner_concat(std::string& buffer, T t, Args... args) {
 1618|  23.4k|  buffer.append(t);
 1619|  23.4k|  return inner_concat(buffer, args...);
 1620|  23.4k|}
_ZN3ada7helpers12inner_concatIPKcJEEEvRNSt3__112basic_stringIcNS4_11char_traitsIcEENS4_9allocatorIcEEEET_:
 1609|  26.1k|inline void inner_concat(std::string& buffer, T t) {
 1610|  26.1k|  buffer.append(t);
 1611|  26.1k|}
_ZN3ada7helpers6concatIJNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEPKcEEES8_DpT_:
 1627|  2.74k|std::string concat(Args... args) {
 1628|  2.74k|  std::string answer;
 1629|  2.74k|  inner_concat(answer, args...);
 1630|  2.74k|  return answer;
 1631|  2.74k|}
_ZN3ada7helpers12inner_concatINSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEJPKcEEEvRS8_T_DpT0_:
 1617|  2.74k|inline void inner_concat(std::string& buffer, T t, Args... args) {
 1618|  2.74k|  buffer.append(t);
 1619|  2.74k|  return inner_concat(buffer, args...);
 1620|  2.74k|}
_ZN3ada3url16update_base_portENSt3__18optionalItEE:
 5459|  1.44k|inline void url::update_base_port(std::optional<uint16_t> input) {
 5460|  1.44k|  port = input;
 5461|  1.44k|}
_ZN3ada6scheme15get_scheme_typeENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 4199|  54.8k|constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept {
 4200|  54.8k|  if (scheme.empty()) {
  ------------------
  |  Branch (4200:7): [True: 0, False: 54.8k]
  ------------------
 4201|      0|    return ada::scheme::NOT_SPECIAL;
 4202|      0|  }
 4203|  54.8k|  int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
 4204|  54.8k|  const std::string_view target = details::is_special_list[hash_value];
 4205|  54.8k|  if ((target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1))) {
  ------------------
  |  Branch (4205:7): [True: 28.1k, False: 26.6k]
  |  Branch (4205:35): [True: 24.4k, False: 3.72k]
  ------------------
 4206|  24.4k|    return ada::scheme::type(hash_value);
 4207|  30.4k|  } else {
 4208|  30.4k|    return ada::scheme::NOT_SPECIAL;
 4209|  30.4k|  }
 4210|  54.8k|}
_ZNK3ada8url_base16get_special_portEv:
 5304|    420|[[nodiscard]] inline uint16_t url_base::get_special_port() const noexcept {
 5305|    420|  return ada::scheme::get_special_port(type);
 5306|    420|}
_ZN3ada6scheme10is_specialENSt3__117basic_string_viewIcNS1_11char_traitsIcEEEE:
 4176|    587|ada_really_inline constexpr bool is_special(std::string_view scheme) {
 4177|    587|  if (scheme.empty()) {
  ------------------
  |  Branch (4177:7): [True: 0, False: 587]
  ------------------
 4178|      0|    return false;
 4179|      0|  }
 4180|    587|  int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7;
 4181|    587|  const std::string_view target = details::is_special_list[hash_value];
 4182|    587|  return (target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1));
  ------------------
  |  Branch (4182:10): [True: 189, False: 398]
  |  Branch (4182:38): [True: 68, False: 121]
  ------------------
 4183|    587|}
_ZN3ada3url10set_schemeEONSt3__112basic_stringIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE:
 5477|  5.85k|inline void url::set_scheme(std::string &&new_scheme) noexcept {
 5478|  5.85k|  type = ada::scheme::get_scheme_type(new_scheme);
 5479|       |  // We only move the 'scheme' if it is non-special.
 5480|  5.85k|  if (!is_special()) {
  ------------------
  |  Branch (5480:7): [True: 3.05k, False: 2.79k]
  ------------------
 5481|  3.05k|    non_special_scheme = new_scheme;
 5482|  3.05k|  }
 5483|  5.85k|}
_ZN3ada7helpers6concatIJPKcNSt3__117basic_string_viewIcNS4_11char_traitsIcEEEEEEENS4_12basic_stringIcS7_NS4_9allocatorIcEEEEDpT_:
 1627|      3|std::string concat(Args... args) {
 1628|      3|  std::string answer;
 1629|      3|  inner_concat(answer, args...);
 1630|      3|  return answer;
 1631|      3|}
_ZN3ada7helpers12inner_concatIPKcJNSt3__117basic_string_viewIcNS4_11char_traitsIcEEEEEEEvRNS4_12basic_stringIcS7_NS4_9allocatorIcEEEET_DpT0_:
 1617|  4.05k|inline void inner_concat(std::string& buffer, T t, Args... args) {
 1618|  4.05k|  buffer.append(t);
 1619|  4.05k|  return inner_concat(buffer, args...);
 1620|  4.05k|}
_ZN3ada7helpers12inner_concatINSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEJEEEvRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEET_:
 1609|  4.05k|inline void inner_concat(std::string& buffer, T t) {
 1610|  4.05k|  buffer.append(t);
 1611|  4.05k|}
_ZN3ada14url_aggregator14clear_hostnameEv:
 6250|  3.04k|inline void url_aggregator::clear_hostname() {
 6251|  3.04k|  ada_log("url_aggregator::clear_hostname");
 6252|  3.04k|  ADA_ASSERT_TRUE(validate());
 6253|  3.04k|  if (!has_authority()) {
  ------------------
  |  Branch (6253:7): [True: 0, False: 3.04k]
  ------------------
 6254|      0|    return;
 6255|      0|  }
 6256|  3.04k|  ADA_ASSERT_TRUE(has_authority());
 6257|       |
 6258|  3.04k|  uint32_t hostname_length = components.host_end - components.host_start;
 6259|  3.04k|  uint32_t start = components.host_start;
 6260|       |
 6261|       |  // If hostname starts with "@", we should not remove that character.
 6262|  3.04k|  if (hostname_length > 0 && buffer[start] == '@') {
  ------------------
  |  Branch (6262:7): [True: 527, False: 2.51k]
  |  Branch (6262:30): [True: 74, False: 453]
  ------------------
 6263|     74|    start++;
 6264|     74|    hostname_length--;
 6265|     74|  }
 6266|  3.04k|  buffer.erase(start, hostname_length);
 6267|  3.04k|  components.host_end = start;
 6268|  3.04k|  components.pathname_start -= hostname_length;
 6269|  3.04k|  if (components.search_start != url_components::omitted) {
  ------------------
  |  Branch (6269:7): [True: 88, False: 2.95k]
  ------------------
 6270|     88|    components.search_start -= hostname_length;
 6271|     88|  }
 6272|  3.04k|  if (components.hash_start != url_components::omitted) {
  ------------------
  |  Branch (6272:7): [True: 79, False: 2.96k]
  ------------------
 6273|     79|    components.hash_start -= hostname_length;
 6274|     79|  }
 6275|       |#if ADA_DEVELOPMENT_CHECKS
 6276|       |  ADA_ASSERT_EQUAL(get_hostname(), "",
 6277|       |                   "hostname should have been cleared on buffer=" + buffer +
 6278|       |                       " with " + components.to_string() + "\n" + to_diagram());
 6279|       |#endif
 6280|  3.04k|  ADA_ASSERT_TRUE(has_authority());
 6281|  3.04k|  ADA_ASSERT_TRUE(has_empty_hostname());
 6282|  3.04k|  ADA_ASSERT_TRUE(validate());
 6283|  3.04k|}
_ZN3ada7helpers6concatIJNSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEPKcS6_EEENS2_12basic_stringIcS5_NS2_9allocatorIcEEEEDpT_:
 1627|  4.05k|std::string concat(Args... args) {
 1628|  4.05k|  std::string answer;
 1629|  4.05k|  inner_concat(answer, args...);
 1630|  4.05k|  return answer;
 1631|  4.05k|}
_ZN3ada7helpers12inner_concatINSt3__117basic_string_viewIcNS2_11char_traitsIcEEEEJPKcS6_EEEvRNS2_12basic_stringIcS5_NS2_9allocatorIcEEEET_DpT0_:
 1617|  4.05k|inline void inner_concat(std::string& buffer, T t, Args... args) {
 1618|  4.05k|  buffer.append(t);
 1619|  4.05k|  return inner_concat(buffer, args...);
 1620|  4.05k|}

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

