11template <
typename out_iter>
12void encode_json(std::string_view view, out_iter out) {
14 const char* hexvalues =
15 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
16 for (uint8_t c : view) {
20 }
else if (c ==
'"') {
23 }
else if (c <= 0x1f) {
28 *out++ = hexvalues[2 * c];
29 *out++ = hexvalues[2 * c + 1];
41 return "Scheme Start";
51 return "Relative Scheme";
53 return "Relative Slash";
61 return "Path or Authority";
63 return "Special Authority Ignore Slashes";
65 return "Special Authority Slashes";
67 return "Special Relative or Authority";
79 return "unknown state";
84 std::string_view& input)
noexcept {
87 size_t location_of_first = input.find(
'#');
88 if (location_of_first == std::string_view::npos) {
91 std::string_view hash = input;
92 hash.remove_prefix(location_of_first + 1);
93 input.remove_suffix(input.size() - location_of_first);
99 size_t first_delimiter = path.find_first_of(
'/', 1);
105 first_delimiter == std::string_view::npos && !path.empty()) {
107 helpers::substring(path, 1))) {
113 size_t last_delimiter = path.rfind(
'/');
114 if (last_delimiter != std::string::npos) {
115 path.erase(last_delimiter);
124 size_t first_delimiter = path.find_first_of(
'/', 1);
130 first_delimiter == std::string_view::npos && !path.empty()) {
132 helpers::substring(path, 1))) {
139 size_t slash_loc = path.rfind(
'/');
140 if (slash_loc != std::string_view::npos) {
141 path.remove_suffix(path.size() - slash_loc);
150 std::string& input)
noexcept {
153 input.erase(std::remove_if(input.begin(), input.end(),
155 return ada::unicode::is_ascii_tab_or_newline(c);
161 size_t pos)
noexcept {
165 return input.substr(pos);
170 input.remove_suffix(input.size() - pos);
176#ifdef ADA_REGULAR_VISUAL_STUDIO
180 _BitScanForward(&ret, input_num);
183 return __builtin_ctzl(input_num);
194#ifndef ada_make_uint8x16_t
195#define ada_make_uint8x16_t(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, \
196 x13, x14, x15, x16) \
198 static uint8_t array[16] = {x1, x2, x3, x4, x5, x6, x7, x8, \
199 x9, x10, x11, x12, x13, x14, x15, x16}; \
200 return vld1q_u8(array); \
205 std::string_view view,
size_t location)
noexcept {
207 if (view.size() - location < 16) {
208 for (
size_t i = location; i < view.size(); i++) {
209 if (view[i] ==
':' || view[i] ==
'/' || view[i] ==
'\\' ||
210 view[i] ==
'?' || view[i] ==
'[') {
214 return size_t(view.size());
216 auto to_bitmask = [](uint8x16_t input) -> uint16_t {
217 uint8x16_t bit_mask =
218 ada_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x01,
219 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
220 uint8x16_t minput = vandq_u8(input, bit_mask);
221 uint8x16_t tmp = vpaddq_u8(minput, minput);
222 tmp = vpaddq_u8(tmp, tmp);
223 tmp = vpaddq_u8(tmp, tmp);
224 return vgetq_lane_u16(vreinterpretq_u16_u8(tmp), 0);
229 uint8x16_t low_mask =
230 ada_make_uint8x16_t(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
231 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x03);
232 uint8x16_t high_mask =
233 ada_make_uint8x16_t(0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
234 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
235 uint8x16_t fmask = vmovq_n_u8(0xf);
237 for (; i + 15 < view.size(); i += 16) {
238 uint8x16_t word = vld1q_u8((
const uint8_t*)view.data() + i);
239 uint8x16_t lowpart = vqtbl1q_u8(low_mask, vandq_u8(word, fmask));
240 uint8x16_t highpart = vqtbl1q_u8(high_mask, vshrq_n_u8(word, 4));
241 uint8x16_t classify = vandq_u8(lowpart, highpart);
242 if (vmaxvq_u32(vreinterpretq_u32_u8(classify)) != 0) {
243 uint8x16_t is_zero = vceqq_u8(classify, zero);
244 uint16_t is_non_zero = ~to_bitmask(is_zero);
249 if (i < view.size()) {
251 vld1q_u8((
const uint8_t*)view.data() + view.length() - 16);
252 uint8x16_t lowpart = vqtbl1q_u8(low_mask, vandq_u8(word, fmask));
253 uint8x16_t highpart = vqtbl1q_u8(high_mask, vshrq_n_u8(word, 4));
254 uint8x16_t classify = vandq_u8(lowpart, highpart);
255 if (vmaxvq_u32(vreinterpretq_u32_u8(classify)) != 0) {
256 uint8x16_t is_zero = vceqq_u8(classify, zero);
257 uint16_t is_non_zero = ~to_bitmask(is_zero);
261 return size_t(view.size());
265 std::string_view view,
size_t location)
noexcept {
267 if (view.size() - location < 16) {
268 for (
size_t i = location; i < view.size(); i++) {
269 if (view[i] ==
':' || view[i] ==
'/' || view[i] ==
'\\' ||
270 view[i] ==
'?' || view[i] ==
'[') {
274 return size_t(view.size());
278 const __m128i mask1 = _mm_set1_epi8(
':');
279 const __m128i mask2 = _mm_set1_epi8(
'/');
280 const __m128i mask3 = _mm_set1_epi8(
'\\');
281 const __m128i mask4 = _mm_set1_epi8(
'?');
282 const __m128i mask5 = _mm_set1_epi8(
'[');
284 for (; i + 15 < view.size(); i += 16) {
285 __m128i word = _mm_loadu_si128((
const __m128i*)(view.data() + i));
286 __m128i m1 = _mm_cmpeq_epi8(word, mask1);
287 __m128i m2 = _mm_cmpeq_epi8(word, mask2);
288 __m128i m3 = _mm_cmpeq_epi8(word, mask3);
289 __m128i m4 = _mm_cmpeq_epi8(word, mask4);
290 __m128i m5 = _mm_cmpeq_epi8(word, mask5);
291 __m128i m = _mm_or_si128(
292 _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m3, m4)), m5);
293 int mask = _mm_movemask_epi8(m);
298 if (i < view.size()) {
300 _mm_loadu_si128((
const __m128i*)(view.data() + view.length() - 16));
301 __m128i m1 = _mm_cmpeq_epi8(word, mask1);
302 __m128i m2 = _mm_cmpeq_epi8(word, mask2);
303 __m128i m3 = _mm_cmpeq_epi8(word, mask3);
304 __m128i m4 = _mm_cmpeq_epi8(word, mask4);
305 __m128i m5 = _mm_cmpeq_epi8(word, mask5);
306 __m128i m = _mm_or_si128(
307 _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m3, m4)), m5);
308 int mask = _mm_movemask_epi8(m);
313 return size_t(view.length());
319 std::array<uint8_t, 256>
result{};
320 for (
int i : {
':',
'/',
'[',
'\\',
'?'}) {
327 std::string_view view,
size_t location)
noexcept {
328 auto const str = view.substr(location);
329 for (
auto pos = str.begin(); pos != str.end(); ++pos) {
331 return pos - str.begin() + location;
334 return size_t(view.size());
343 size_t location)
noexcept {
345 if (view.size() - location < 16) {
346 for (
size_t i = location; i < view.size(); i++) {
347 if (view[i] ==
':' || view[i] ==
'/' || view[i] ==
'?' ||
352 return size_t(view.size());
354 auto to_bitmask = [](uint8x16_t input) -> uint16_t {
355 uint8x16_t bit_mask =
356 ada_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x01,
357 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
358 uint8x16_t minput = vandq_u8(input, bit_mask);
359 uint8x16_t tmp = vpaddq_u8(minput, minput);
360 tmp = vpaddq_u8(tmp, tmp);
361 tmp = vpaddq_u8(tmp, tmp);
362 return vgetq_lane_u16(vreinterpretq_u16_u8(tmp), 0);
367 uint8x16_t low_mask =
368 ada_make_uint8x16_t(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
369 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x03);
370 uint8x16_t high_mask =
371 ada_make_uint8x16_t(0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
372 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
373 uint8x16_t fmask = vmovq_n_u8(0xf);
375 for (; i + 15 < view.size(); i += 16) {
376 uint8x16_t word = vld1q_u8((
const uint8_t*)view.data() + i);
377 uint8x16_t lowpart = vqtbl1q_u8(low_mask, vandq_u8(word, fmask));
378 uint8x16_t highpart = vqtbl1q_u8(high_mask, vshrq_n_u8(word, 4));
379 uint8x16_t classify = vandq_u8(lowpart, highpart);
380 if (vmaxvq_u32(vreinterpretq_u32_u8(classify)) != 0) {
381 uint8x16_t is_zero = vceqq_u8(classify, zero);
382 uint16_t is_non_zero = ~to_bitmask(is_zero);
387 if (i < view.size()) {
389 vld1q_u8((
const uint8_t*)view.data() + view.length() - 16);
390 uint8x16_t lowpart = vqtbl1q_u8(low_mask, vandq_u8(word, fmask));
391 uint8x16_t highpart = vqtbl1q_u8(high_mask, vshrq_n_u8(word, 4));
392 uint8x16_t classify = vandq_u8(lowpart, highpart);
393 if (vmaxvq_u32(vreinterpretq_u32_u8(classify)) != 0) {
394 uint8x16_t is_zero = vceqq_u8(classify, zero);
395 uint16_t is_non_zero = ~to_bitmask(is_zero);
399 return size_t(view.size());
403 size_t location)
noexcept {
405 if (view.size() - location < 16) {
406 for (
size_t i = location; i < view.size(); i++) {
407 if (view[i] ==
':' || view[i] ==
'/' || view[i] ==
'?' ||
412 return size_t(view.size());
416 const __m128i mask1 = _mm_set1_epi8(
':');
417 const __m128i mask2 = _mm_set1_epi8(
'/');
418 const __m128i mask4 = _mm_set1_epi8(
'?');
419 const __m128i mask5 = _mm_set1_epi8(
'[');
421 for (; i + 15 < view.size(); i += 16) {
422 __m128i word = _mm_loadu_si128((
const __m128i*)(view.data() + i));
423 __m128i m1 = _mm_cmpeq_epi8(word, mask1);
424 __m128i m2 = _mm_cmpeq_epi8(word, mask2);
425 __m128i m4 = _mm_cmpeq_epi8(word, mask4);
426 __m128i m5 = _mm_cmpeq_epi8(word, mask5);
427 __m128i m = _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m4, m5));
428 int mask = _mm_movemask_epi8(m);
433 if (i < view.size()) {
435 _mm_loadu_si128((
const __m128i*)(view.data() + view.length() - 16));
436 __m128i m1 = _mm_cmpeq_epi8(word, mask1);
437 __m128i m2 = _mm_cmpeq_epi8(word, mask2);
438 __m128i m4 = _mm_cmpeq_epi8(word, mask4);
439 __m128i m5 = _mm_cmpeq_epi8(word, mask5);
440 __m128i m = _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m4, m5));
441 int mask = _mm_movemask_epi8(m);
446 return size_t(view.length());
451 std::array<uint8_t, 256>
result{};
452 for (
int i : {
':',
'/',
'?',
'['}) {
459 size_t location)
noexcept {
460 auto const str = view.substr(location);
461 for (
auto pos = str.begin(); pos != str.end(); ++pos) {
463 return pos - str.begin() + location;
466 return size_t(view.size());
471 const bool is_special, std::string_view& view)
noexcept {
480 const size_t view_size = view.size();
482 bool found_colon =
false;
507 for (; location < view_size;
509 if (view[location] ==
'[') {
510 location = view.find(
']', location);
511 if (location == std::string_view::npos) {
515 location = view_size;
519 found_colon = view[location] ==
':';
528 for (; location < view_size;
530 if (view[location] ==
'[') {
531 location = view.find(
']', location);
532 if (location == std::string_view::npos) {
536 location = view_size;
540 found_colon = view[location] ==
':';
546 view.remove_suffix(view_size - location);
547 return {location, found_colon};
551 while (!input.empty() &&
552 ada::unicode::is_c0_control_or_space(input.front())) {
553 input.remove_prefix(1);
555 while (!input.empty() && ada::unicode::is_c0_control_or_space(input.back())) {
556 input.remove_suffix(1);
563 ada_log(
"parse_prepared_path ", input);
564 uint8_t accumulator = checkers::path_signature(input);
569 constexpr uint8_t need_encoding = 1;
570 constexpr uint8_t backslash_char = 2;
571 constexpr uint8_t dot_char = 4;
572 constexpr uint8_t percent_char = 8;
577 (special ? (accumulator == 0)
578 : ((accumulator & (need_encoding | dot_char | percent_char)) ==
580 (!may_need_slow_file_handling);
581 if (accumulator == dot_char && !may_need_slow_file_handling) {
589 if (input[0] !=
'.') {
590 size_t slashdot = input.find(
"/.");
591 if (slashdot == std::string_view::npos) {
596 !(slashdot + 2 == input.size() || input[slashdot + 2] ==
'.' ||
597 input[slashdot + 2] ==
'/');
602 ada_log(
"parse_path trivial");
613 (accumulator & (need_encoding | backslash_char | percent_char)) == 0) &&
616 ada_log(
"parse_prepared_path fast");
621 size_t previous_location = 0;
623 size_t new_location = input.find(
'/', previous_location);
626 if (new_location == std::string_view::npos) {
627 std::string_view path_view = input.substr(previous_location);
628 if (path_view ==
"..") {
635 if (path.back() ==
'/') {
640 path.resize(path.rfind(
'/') + 1);
644 if (path_view !=
".") {
645 path.append(path_view);
650 std::string_view path_view =
651 input.substr(previous_location, new_location - previous_location);
652 previous_location = new_location + 1;
653 if (path_view ==
"..") {
654 size_t last_delimiter = path.rfind(
'/');
655 if (last_delimiter != std::string::npos) {
656 path.erase(last_delimiter);
658 }
else if (path_view !=
".") {
660 path.append(path_view);
665 ada_log(
"parse_path slow");
667 bool needs_percent_encoding = (accumulator & 1);
668 std::string path_buffer_tmp;
670 size_t location = (special && (accumulator & 2))
671 ? input.find_first_of(
"/\\")
673 std::string_view path_view = input;
674 if (location != std::string_view::npos) {
675 path_view.remove_suffix(path_view.size() - location);
676 input.remove_prefix(location + 1);
680 std::string_view path_buffer =
681 (needs_percent_encoding &&
682 ada::unicode::percent_encode<false>(
686 if (unicode::is_double_dot_path_segment(path_buffer)) {
687 if ((helpers::shorten_path(path, type) || special) &&
688 location == std::string_view::npos) {
691 }
else if (unicode::is_single_dot_path_segment(path_buffer) &&
692 (location == std::string_view::npos)) {
696 else if (!unicode::is_single_dot_path_segment(path_buffer)) {
703 path += path_buffer[0];
705 path_buffer.remove_prefix(2);
706 path.append(path_buffer);
710 path.append(path_buffer);
713 if (location == std::string_view::npos) {
720bool overlaps(std::string_view input1,
const std::string& input2)
noexcept {
721 ada_log(
"helpers::overlaps check if string_view '", input1,
"' [",
722 input1.size(),
" bytes] is part of string '", input2,
"' [",
723 input2.size(),
" bytes]");
724 return !input1.empty() && !input2.empty() && input1.data() >= input2.data() &&
725 input1.data() < input2.data() + input2.size();
728template <
class url_type>
730 url_type& url)
noexcept {
731 ada_log(
"helpers::strip_trailing_spaces_from_opaque_path");
732 if (!url.has_opaque_path)
return;
733 if (url.has_hash())
return;
734 if (url.has_search())
return;
736 auto path = std::string(url.get_pathname());
737 while (!path.empty() && path.back() ==
' ') {
738 path.resize(path.size() - 1);
740 url.update_base_pathname(path);
746 std::array<uint8_t, 256>
result{};
747 for (uint8_t i : {
'@',
'/',
'\\',
'?'}) {
754find_authority_delimiter_special(std::string_view view)
noexcept {
757 for (
auto pos = view.begin(); pos != view.end(); ++pos) {
759 return pos - view.begin();
762 return size_t(view.size());
767 std::array<uint8_t, 256>
result{};
768 for (uint8_t i : {
'@',
'/',
'?'}) {
775find_authority_delimiter(std::string_view view)
noexcept {
778 for (
auto pos = view.begin(); pos != view.end(); ++pos) {
780 return pos - view.begin();
783 return size_t(view.size());
792#undef ada_make_uint8x16_t
Includes all definitions for Ada.
Definitions for URL specific checkers used within Ada.
Common definitions for cross-platform compiler support.
#define ADA_ASSERT_TRUE(COND)
#define ada_really_inline
constexpr uint8_t PATH_PERCENT_ENCODE[32]
constexpr bool is_normalized_windows_drive_letter(std::string_view input) noexcept
constexpr bool is_windows_drive_letter(std::string_view input) noexcept
Includes the definitions for helper functions.
ada_really_inline size_t find_next_host_delimiter(std::string_view view, size_t location) noexcept
static constexpr std::array< uint8_t, 256 > authority_delimiter_special
static constexpr std::array< uint8_t, 256 > host_delimiters
ada_really_inline size_t find_next_host_delimiter_special(std::string_view view, size_t location) noexcept
ada_unused std::string get_state(ada::state s)
static constexpr std::array< uint8_t, 256 > authority_delimiter
static constexpr std::array< uint8_t, 256 > special_host_delimiters
ada_really_inline int trailing_zeroes(uint32_t input_num) noexcept
ada_warn_unused std::string to_string(encoding_type type)
@ SPECIAL_RELATIVE_OR_AUTHORITY
@ SPECIAL_AUTHORITY_SLASHES
@ SPECIAL_AUTHORITY_IGNORE_SLASHES
tl::expected< result_type, ada::errors > result
Declarations for the URL scheme.