14template <
typename out_iter>
15void encode_json(std::string_view view, out_iter out) {
17 const char* hexvalues =
18 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
19 for (uint8_t c : view) {
23 }
else if (c ==
'"') {
26 }
else if (c <= 0x1f) {
31 *out++ = hexvalues[2 * c];
32 *out++ = hexvalues[2 * c + 1];
44 return "Scheme Start";
54 return "Relative Scheme";
56 return "Relative Slash";
64 return "Path or Authority";
66 return "Special Authority Ignore Slashes";
68 return "Special Authority Slashes";
70 return "Special Relative or Authority";
82 return "unknown state";
87 std::string_view& input)
noexcept {
90 size_t location_of_first = input.find(
'#');
91 if (location_of_first == std::string_view::npos) {
94 std::string_view hash = input;
95 hash.remove_prefix(location_of_first + 1);
96 input.remove_suffix(input.size() - location_of_first);
106 path.find(
'/', 1) == std::string_view::npos && !path.empty()) {
108 helpers::substring(path, 1))) {
114 size_t last_delimiter = path.rfind(
'/');
115 if (last_delimiter != std::string::npos) {
116 path.erase(last_delimiter);
129 path.find(
'/', 1) == std::string_view::npos && !path.empty()) {
131 helpers::substring(path, 1))) {
138 size_t slash_loc = path.rfind(
'/');
139 if (slash_loc != std::string_view::npos) {
140 path.remove_suffix(path.size() - slash_loc);
149 std::string& input)
noexcept {
152 std::erase_if(input, ada::unicode::is_ascii_tab_or_newline);
156 size_t pos)
noexcept {
160 return input.substr(pos);
165 input.remove_suffix(input.size() - pos);
171#ifdef ADA_REGULAR_VISUAL_STUDIO
175 _BitScanForward(&ret, input_num);
178 return __builtin_ctzl(input_num);
187 std::string_view view,
size_t location)
noexcept {
189 if (view.size() - location < 16) {
190 for (
size_t i = location; i < view.size(); i++) {
191 if (view[i] ==
':' || view[i] ==
'/' || view[i] ==
'\\' ||
192 view[i] ==
'?' || view[i] ==
'[') {
196 return size_t(view.size());
201 const __m128i low_mask =
202 _mm_setr_epi8(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
203 0x01, 0x04, 0x04, 0x00, 0x00, 0x03);
204 const __m128i high_mask =
205 _mm_setr_epi8(0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
206 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
207 const __m128i fmask = _mm_set1_epi8(0xf);
208 const __m128i zero = _mm_setzero_si128();
209 for (; i + 15 < view.size(); i += 16) {
210 __m128i word = _mm_loadu_si128((
const __m128i*)(view.data() + i));
211 __m128i lowpart = _mm_shuffle_epi8(low_mask, _mm_and_si128(word, fmask));
212 __m128i highpart = _mm_shuffle_epi8(
213 high_mask, _mm_and_si128(_mm_srli_epi16(word, 4), fmask));
214 __m128i classify = _mm_and_si128(lowpart, highpart);
215 __m128i is_zero = _mm_cmpeq_epi8(classify, zero);
219 int mask = ~_mm_movemask_epi8(is_zero) & 0xFFFF;
224 if (i < view.size()) {
226 _mm_loadu_si128((
const __m128i*)(view.data() + view.length() - 16));
227 __m128i lowpart = _mm_shuffle_epi8(low_mask, _mm_and_si128(word, fmask));
228 __m128i highpart = _mm_shuffle_epi8(
229 high_mask, _mm_and_si128(_mm_srli_epi16(word, 4), fmask));
230 __m128i classify = _mm_and_si128(lowpart, highpart);
231 __m128i is_zero = _mm_cmpeq_epi8(classify, zero);
235 int mask = ~_mm_movemask_epi8(is_zero) & 0xFFFF;
237 return view.length() - 16 +
trailing_zeroes(
static_cast<uint32_t
>(mask));
240 return size_t(view.size());
246#ifndef ada_make_uint8x16_t
247#define ada_make_uint8x16_t(x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, \
248 x13, x14, x15, x16) \
250 static uint8_t array[16] = {x1, x2, x3, x4, x5, x6, x7, x8, \
251 x9, x10, x11, x12, x13, x14, x15, x16}; \
252 return vld1q_u8(array); \
257 std::string_view view,
size_t location)
noexcept {
259 if (view.size() - location < 16) {
260 for (
size_t i = location; i < view.size(); i++) {
261 if (view[i] ==
':' || view[i] ==
'/' || view[i] ==
'\\' ||
262 view[i] ==
'?' || view[i] ==
'[') {
266 return size_t(view.size());
268 auto to_bitmask = [](uint8x16_t input) -> uint16_t {
269 uint8x16_t bit_mask =
270 ada_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x01,
271 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
272 uint8x16_t minput = vandq_u8(input, bit_mask);
273 uint8x16_t tmp = vpaddq_u8(minput, minput);
274 tmp = vpaddq_u8(tmp, tmp);
275 tmp = vpaddq_u8(tmp, tmp);
276 return vgetq_lane_u16(vreinterpretq_u16_u8(tmp), 0);
281 uint8x16_t low_mask =
282 ada_make_uint8x16_t(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
283 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x03);
284 uint8x16_t high_mask =
285 ada_make_uint8x16_t(0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
286 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
287 uint8x16_t fmask = vmovq_n_u8(0xf);
289 for (; i + 15 < view.size(); i += 16) {
290 uint8x16_t word = vld1q_u8((
const uint8_t*)view.data() + i);
291 uint8x16_t lowpart = vqtbl1q_u8(low_mask, vandq_u8(word, fmask));
292 uint8x16_t highpart = vqtbl1q_u8(high_mask, vshrq_n_u8(word, 4));
293 uint8x16_t classify = vandq_u8(lowpart, highpart);
294 if (vmaxvq_u32(vreinterpretq_u32_u8(classify)) != 0) {
295 uint8x16_t is_zero = vceqq_u8(classify, zero);
296 uint16_t is_non_zero = ~to_bitmask(is_zero);
301 if (i < view.size()) {
303 vld1q_u8((
const uint8_t*)view.data() + view.length() - 16);
304 uint8x16_t lowpart = vqtbl1q_u8(low_mask, vandq_u8(word, fmask));
305 uint8x16_t highpart = vqtbl1q_u8(high_mask, vshrq_n_u8(word, 4));
306 uint8x16_t classify = vandq_u8(lowpart, highpart);
307 if (vmaxvq_u32(vreinterpretq_u32_u8(classify)) != 0) {
308 uint8x16_t is_zero = vceqq_u8(classify, zero);
309 uint16_t is_non_zero = ~to_bitmask(is_zero);
313 return size_t(view.size());
317 std::string_view view,
size_t location)
noexcept {
319 if (view.size() - location < 16) {
320 for (
size_t i = location; i < view.size(); i++) {
321 if (view[i] ==
':' || view[i] ==
'/' || view[i] ==
'\\' ||
322 view[i] ==
'?' || view[i] ==
'[') {
326 return size_t(view.size());
330 const __m128i mask1 = _mm_set1_epi8(
':');
331 const __m128i mask2 = _mm_set1_epi8(
'/');
332 const __m128i mask3 = _mm_set1_epi8(
'\\');
333 const __m128i mask4 = _mm_set1_epi8(
'?');
334 const __m128i mask5 = _mm_set1_epi8(
'[');
336 for (; i + 15 < view.size(); i += 16) {
337 __m128i word = _mm_loadu_si128((
const __m128i*)(view.data() + i));
338 __m128i m1 = _mm_cmpeq_epi8(word, mask1);
339 __m128i m2 = _mm_cmpeq_epi8(word, mask2);
340 __m128i m3 = _mm_cmpeq_epi8(word, mask3);
341 __m128i m4 = _mm_cmpeq_epi8(word, mask4);
342 __m128i m5 = _mm_cmpeq_epi8(word, mask5);
343 __m128i m = _mm_or_si128(
344 _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m3, m4)), m5);
345 int mask = _mm_movemask_epi8(m);
350 if (i < view.size()) {
352 _mm_loadu_si128((
const __m128i*)(view.data() + view.length() - 16));
353 __m128i m1 = _mm_cmpeq_epi8(word, mask1);
354 __m128i m2 = _mm_cmpeq_epi8(word, mask2);
355 __m128i m3 = _mm_cmpeq_epi8(word, mask3);
356 __m128i m4 = _mm_cmpeq_epi8(word, mask4);
357 __m128i m5 = _mm_cmpeq_epi8(word, mask5);
358 __m128i m = _mm_or_si128(
359 _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m3, m4)), m5);
360 int mask = _mm_movemask_epi8(m);
365 return size_t(view.length());
369 std::string_view view,
size_t location)
noexcept {
371 if (view.size() - location < 16) {
372 for (
size_t i = location; i < view.size(); i++) {
373 if (view[i] ==
':' || view[i] ==
'/' || view[i] ==
'\\' ||
374 view[i] ==
'?' || view[i] ==
'[') {
378 return size_t(view.size());
382 const __m128i mask1 = __lsx_vrepli_b(
':');
383 const __m128i mask2 = __lsx_vrepli_b(
'/');
384 const __m128i mask3 = __lsx_vrepli_b(
'\\');
385 const __m128i mask4 = __lsx_vrepli_b(
'?');
386 const __m128i mask5 = __lsx_vrepli_b(
'[');
388 for (; i + 15 < view.size(); i += 16) {
389 __m128i word = __lsx_vld((
const __m128i*)(view.data() + i), 0);
390 __m128i m1 = __lsx_vseq_b(word, mask1);
391 __m128i m2 = __lsx_vseq_b(word, mask2);
392 __m128i m3 = __lsx_vseq_b(word, mask3);
393 __m128i m4 = __lsx_vseq_b(word, mask4);
394 __m128i m5 = __lsx_vseq_b(word, mask5);
396 __lsx_vor_v(__lsx_vor_v(__lsx_vor_v(m1, m2), __lsx_vor_v(m3, m4)), m5);
397 int mask = __lsx_vpickve2gr_hu(__lsx_vmsknz_b(m), 0);
402 if (i < view.size()) {
404 __lsx_vld((
const __m128i*)(view.data() + view.length() - 16), 0);
405 __m128i m1 = __lsx_vseq_b(word, mask1);
406 __m128i m2 = __lsx_vseq_b(word, mask2);
407 __m128i m3 = __lsx_vseq_b(word, mask3);
408 __m128i m4 = __lsx_vseq_b(word, mask4);
409 __m128i m5 = __lsx_vseq_b(word, mask5);
411 __lsx_vor_v(__lsx_vor_v(__lsx_vor_v(m1, m2), __lsx_vor_v(m3, m4)), m5);
412 int mask = __lsx_vpickve2gr_hu(__lsx_vmsknz_b(m), 0);
417 return size_t(view.length());
421 std::string_view view,
size_t location)
noexcept {
426 static const uint8_t tbl[16] = {
427 0xF, 0, 0, 0, 0, 0,
'[',
'\\', 0, 0, 0,
'/', 0, 0,
':',
'?'
429 vuint8m1_t vtbl = __riscv_vle8_v_u8m1(tbl, 16);
431 uint8_t* src = (uint8_t*)view.data() + location;
432 for (
size_t vl, n = view.size() - location; n > 0;
433 n -= vl, src += vl, location += vl) {
434 vl = __riscv_vsetvl_e8m1(n);
435 vuint8m1_t v = __riscv_vle8_v_u8m1(src, vl);
437 vuint8m1_t vidx = __riscv_vand(__riscv_vsrl(v, 2, vl), 0xF, vl);
438 vuint8m1_t vlut = __riscv_vrgather(vtbl, vidx, vl);
439 vbool8_t m = __riscv_vmseq(v, vlut, vl);
441 vbool8_t m1 = __riscv_vmseq(v,
':', vl);
442 vbool8_t m2 = __riscv_vmseq(v,
'/', vl);
443 vbool8_t m3 = __riscv_vmseq(v,
'?', vl);
444 vbool8_t m4 = __riscv_vmseq(v,
'[', vl);
445 vbool8_t m5 = __riscv_vmseq(v,
'\\', vl);
446 vbool8_t m = __riscv_vmor(
447 __riscv_vmor(__riscv_vmor(m1, m2, vl), __riscv_vmor(m3, m4, vl), vl),
450 long idx = __riscv_vfirst(m, vl);
451 if (idx >= 0)
return location + idx;
453 return size_t(view.size());
459 std::array<uint8_t, 256>
result{};
460 for (
int i : {
':',
'/',
'[',
'\\',
'?'}) {
467 std::string_view view,
size_t location)
noexcept {
468 auto const str = view.substr(location);
469 for (
auto pos = str.begin(); pos != str.end(); ++pos) {
471 return pos - str.begin() + location;
474 return size_t(view.size());
483 size_t location)
noexcept {
485 if (view.size() - location < 16) {
486 for (
size_t i = location; i < view.size(); i++) {
487 if (view[i] ==
':' || view[i] ==
'/' || view[i] ==
'?' ||
492 return size_t(view.size());
501 const __m128i low_mask =
502 _mm_setr_epi8(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
503 0x01, 0x04, 0x00, 0x00, 0x00, 0x03);
504 const __m128i high_mask =
505 _mm_setr_epi8(0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
506 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
507 const __m128i fmask = _mm_set1_epi8(0xf);
508 const __m128i zero = _mm_setzero_si128();
510 for (; i + 15 < view.size(); i += 16) {
511 __m128i word = _mm_loadu_si128((
const __m128i*)(view.data() + i));
512 __m128i lowpart = _mm_shuffle_epi8(low_mask, _mm_and_si128(word, fmask));
513 __m128i highpart = _mm_shuffle_epi8(
514 high_mask, _mm_and_si128(_mm_srli_epi16(word, 4), fmask));
515 __m128i classify = _mm_and_si128(lowpart, highpart);
516 __m128i is_zero = _mm_cmpeq_epi8(classify, zero);
520 int mask = ~_mm_movemask_epi8(is_zero) & 0xFFFF;
526 if (i < view.size()) {
528 _mm_loadu_si128((
const __m128i*)(view.data() + view.length() - 16));
529 __m128i lowpart = _mm_shuffle_epi8(low_mask, _mm_and_si128(word, fmask));
530 __m128i highpart = _mm_shuffle_epi8(
531 high_mask, _mm_and_si128(_mm_srli_epi16(word, 4), fmask));
532 __m128i classify = _mm_and_si128(lowpart, highpart);
533 __m128i is_zero = _mm_cmpeq_epi8(classify, zero);
537 int mask = ~_mm_movemask_epi8(is_zero) & 0xFFFF;
539 return view.length() - 16 +
trailing_zeroes(
static_cast<uint32_t
>(mask));
542 return size_t(view.size());
546 size_t location)
noexcept {
548 if (view.size() - location < 16) {
549 for (
size_t i = location; i < view.size(); i++) {
550 if (view[i] ==
':' || view[i] ==
'/' || view[i] ==
'?' ||
555 return size_t(view.size());
557 auto to_bitmask = [](uint8x16_t input) -> uint16_t {
558 uint8x16_t bit_mask =
559 ada_make_uint8x16_t(0x01, 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, 0x01,
560 0x02, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80);
561 uint8x16_t minput = vandq_u8(input, bit_mask);
562 uint8x16_t tmp = vpaddq_u8(minput, minput);
563 tmp = vpaddq_u8(tmp, tmp);
564 tmp = vpaddq_u8(tmp, tmp);
565 return vgetq_lane_u16(vreinterpretq_u16_u8(tmp), 0);
570 uint8x16_t low_mask =
571 ada_make_uint8x16_t(0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
572 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x03);
573 uint8x16_t high_mask =
574 ada_make_uint8x16_t(0x00, 0x00, 0x02, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
575 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
576 uint8x16_t fmask = vmovq_n_u8(0xf);
578 for (; i + 15 < view.size(); i += 16) {
579 uint8x16_t word = vld1q_u8((
const uint8_t*)view.data() + i);
580 uint8x16_t lowpart = vqtbl1q_u8(low_mask, vandq_u8(word, fmask));
581 uint8x16_t highpart = vqtbl1q_u8(high_mask, vshrq_n_u8(word, 4));
582 uint8x16_t classify = vandq_u8(lowpart, highpart);
583 if (vmaxvq_u32(vreinterpretq_u32_u8(classify)) != 0) {
584 uint8x16_t is_zero = vceqq_u8(classify, zero);
585 uint16_t is_non_zero = ~to_bitmask(is_zero);
590 if (i < view.size()) {
592 vld1q_u8((
const uint8_t*)view.data() + view.length() - 16);
593 uint8x16_t lowpart = vqtbl1q_u8(low_mask, vandq_u8(word, fmask));
594 uint8x16_t highpart = vqtbl1q_u8(high_mask, vshrq_n_u8(word, 4));
595 uint8x16_t classify = vandq_u8(lowpart, highpart);
596 if (vmaxvq_u32(vreinterpretq_u32_u8(classify)) != 0) {
597 uint8x16_t is_zero = vceqq_u8(classify, zero);
598 uint16_t is_non_zero = ~to_bitmask(is_zero);
602 return size_t(view.size());
606 size_t location)
noexcept {
608 if (view.size() - location < 16) {
609 for (
size_t i = location; i < view.size(); i++) {
610 if (view[i] ==
':' || view[i] ==
'/' || view[i] ==
'?' ||
615 return size_t(view.size());
619 const __m128i mask1 = _mm_set1_epi8(
':');
620 const __m128i mask2 = _mm_set1_epi8(
'/');
621 const __m128i mask4 = _mm_set1_epi8(
'?');
622 const __m128i mask5 = _mm_set1_epi8(
'[');
624 for (; i + 15 < view.size(); i += 16) {
625 __m128i word = _mm_loadu_si128((
const __m128i*)(view.data() + i));
626 __m128i m1 = _mm_cmpeq_epi8(word, mask1);
627 __m128i m2 = _mm_cmpeq_epi8(word, mask2);
628 __m128i m4 = _mm_cmpeq_epi8(word, mask4);
629 __m128i m5 = _mm_cmpeq_epi8(word, mask5);
630 __m128i m = _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m4, m5));
631 int mask = _mm_movemask_epi8(m);
636 if (i < view.size()) {
638 _mm_loadu_si128((
const __m128i*)(view.data() + view.length() - 16));
639 __m128i m1 = _mm_cmpeq_epi8(word, mask1);
640 __m128i m2 = _mm_cmpeq_epi8(word, mask2);
641 __m128i m4 = _mm_cmpeq_epi8(word, mask4);
642 __m128i m5 = _mm_cmpeq_epi8(word, mask5);
643 __m128i m = _mm_or_si128(_mm_or_si128(m1, m2), _mm_or_si128(m4, m5));
644 int mask = _mm_movemask_epi8(m);
649 return size_t(view.length());
653 size_t location)
noexcept {
655 if (view.size() - location < 16) {
656 for (
size_t i = location; i < view.size(); i++) {
657 if (view[i] ==
':' || view[i] ==
'/' || view[i] ==
'?' ||
662 return size_t(view.size());
666 const __m128i mask1 = __lsx_vrepli_b(
':');
667 const __m128i mask2 = __lsx_vrepli_b(
'/');
668 const __m128i mask4 = __lsx_vrepli_b(
'?');
669 const __m128i mask5 = __lsx_vrepli_b(
'[');
671 for (; i + 15 < view.size(); i += 16) {
672 __m128i word = __lsx_vld((
const __m128i*)(view.data() + i), 0);
673 __m128i m1 = __lsx_vseq_b(word, mask1);
674 __m128i m2 = __lsx_vseq_b(word, mask2);
675 __m128i m4 = __lsx_vseq_b(word, mask4);
676 __m128i m5 = __lsx_vseq_b(word, mask5);
677 __m128i m = __lsx_vor_v(__lsx_vor_v(m1, m2), __lsx_vor_v(m4, m5));
678 int mask = __lsx_vpickve2gr_hu(__lsx_vmsknz_b(m), 0);
683 if (i < view.size()) {
685 __lsx_vld((
const __m128i*)(view.data() + view.length() - 16), 0);
686 __m128i m1 = __lsx_vseq_b(word, mask1);
687 __m128i m2 = __lsx_vseq_b(word, mask2);
688 __m128i m4 = __lsx_vseq_b(word, mask4);
689 __m128i m5 = __lsx_vseq_b(word, mask5);
690 __m128i m = __lsx_vor_v(__lsx_vor_v(m1, m2), __lsx_vor_v(m4, m5));
691 int mask = __lsx_vpickve2gr_hu(__lsx_vmsknz_b(m), 0);
696 return size_t(view.length());
700 size_t location)
noexcept {
701 uint8_t* src = (uint8_t*)view.data() + location;
702 for (
size_t vl, n = view.size() - location; n > 0;
703 n -= vl, src += vl, location += vl) {
704 vl = __riscv_vsetvl_e8m1(n);
705 vuint8m1_t v = __riscv_vle8_v_u8m1(src, vl);
706 vbool8_t m1 = __riscv_vmseq(v,
':', vl);
707 vbool8_t m2 = __riscv_vmseq(v,
'/', vl);
708 vbool8_t m3 = __riscv_vmseq(v,
'?', vl);
709 vbool8_t m4 = __riscv_vmseq(v,
'[', vl);
711 __riscv_vmor(__riscv_vmor(m1, m2, vl), __riscv_vmor(m3, m4, vl), vl);
712 long idx = __riscv_vfirst(m, vl);
713 if (idx >= 0)
return location + idx;
715 return size_t(view.size());
720 std::array<uint8_t, 256>
result{};
721 for (
int i : {
':',
'/',
'?',
'['}) {
728 size_t location)
noexcept {
729 auto const str = view.substr(location);
730 for (
auto pos = str.begin(); pos != str.end(); ++pos) {
732 return pos - str.begin() + location;
735 return size_t(view.size());
740 const bool is_special, std::string_view& view)
noexcept {
749 const size_t view_size = view.size();
751 bool found_colon =
false;
776 for (; location < view_size;
778 if (view[location] ==
'[') {
779 location = view.find(
']', location);
780 if (location == std::string_view::npos) {
784 location = view_size;
788 found_colon = view[location] ==
':';
797 for (; location < view_size;
799 if (view[location] ==
'[') {
800 location = view.find(
']', location);
801 if (location == std::string_view::npos) {
805 location = view_size;
809 found_colon = view[location] ==
':';
815 view.remove_suffix(view_size - location);
816 return {location, found_colon};
819void trim_c0_whitespace(std::string_view& input)
noexcept {
820 while (!input.empty() &&
821 ada::unicode::is_c0_control_or_space(input.front())) {
822 input.remove_prefix(1);
824 while (!input.empty() && ada::unicode::is_c0_control_or_space(input.back())) {
825 input.remove_suffix(1);
832 ada_log(
"parse_prepared_path ", input);
833 uint8_t accumulator = checkers::path_signature(input);
838 constexpr uint8_t need_encoding = 1;
839 constexpr uint8_t backslash_char = 2;
840 constexpr uint8_t dot_char = 4;
841 constexpr uint8_t percent_char = 8;
846 (special ? (accumulator == 0)
847 : ((accumulator & (need_encoding | dot_char | percent_char)) ==
849 (!may_need_slow_file_handling);
850 if (accumulator == dot_char && !may_need_slow_file_handling) {
858 if (input[0] !=
'.') {
860 bool dot_is_file =
true;
862 slashdot = input.find(
"/.", slashdot);
863 if (slashdot == std::string_view::npos) {
868 dot_is_file &= !(slashdot == input.size() || input[slashdot] ==
'.' ||
869 input[slashdot] ==
'/');
872 trivial_path = dot_is_file;
876 ada_log(
"parse_path trivial");
887 (accumulator & (need_encoding | backslash_char | percent_char)) == 0) &&
890 ada_log(
"parse_prepared_path fast");
895 size_t previous_location = 0;
897 size_t new_location = input.find(
'/', previous_location);
900 if (new_location == std::string_view::npos) {
901 std::string_view path_view = input.substr(previous_location);
902 if (path_view ==
"..") {
909 if (path.back() ==
'/') {
914 path.resize(path.rfind(
'/') + 1);
918 if (path_view !=
".") {
919 path.append(path_view);
924 std::string_view path_view =
925 input.substr(previous_location, new_location - previous_location);
926 previous_location = new_location + 1;
927 if (path_view ==
"..") {
928 size_t last_delimiter = path.rfind(
'/');
929 if (last_delimiter != std::string::npos) {
930 path.erase(last_delimiter);
932 }
else if (path_view !=
".") {
934 path.append(path_view);
939 ada_log(
"parse_path slow");
941 bool needs_percent_encoding = (accumulator & 1);
942 std::string path_buffer_tmp;
944 size_t location = (special && (accumulator & 2))
945 ? input.find_first_of(
"/\\")
947 std::string_view path_view = input;
948 if (location != std::string_view::npos) {
949 path_view.remove_suffix(path_view.size() - location);
950 input.remove_prefix(location + 1);
954 std::string_view path_buffer =
955 (needs_percent_encoding &&
956 ada::unicode::percent_encode<false>(
960 if (unicode::is_double_dot_path_segment(path_buffer)) {
961 helpers::shorten_path(path, type);
962 if (location == std::string_view::npos) {
965 }
else if (unicode::is_single_dot_path_segment(path_buffer) &&
966 (location == std::string_view::npos)) {
970 else if (!unicode::is_single_dot_path_segment(path_buffer)) {
977 path += path_buffer[0];
979 path_buffer.remove_prefix(2);
980 path.append(path_buffer);
984 path.append(path_buffer);
987 if (location == std::string_view::npos) {
994bool overlaps(std::string_view input1,
const std::string& input2)
noexcept {
995 ada_log(
"helpers::overlaps check if string_view '", input1,
"' [",
996 input1.size(),
" bytes] is part of string '", input2,
"' [",
997 input2.size(),
" bytes]");
998 return !input1.empty() && !input2.empty() && input1.data() >= input2.data() &&
999 input1.data() < input2.data() + input2.size();
1002template <
class url_type>
1004 url_type& url)
noexcept {
1005 ada_log(
"helpers::strip_trailing_spaces_from_opaque_path");
1006 if (!url.has_opaque_path)
return;
1007 if (url.has_hash())
return;
1008 if (url.has_search())
return;
1010 auto path = std::string(url.get_pathname());
1011 while (!path.empty() && path.back() ==
' ') {
1012 path.resize(path.size() - 1);
1014 url.update_base_pathname(path);
1020 std::array<uint8_t, 256>
result{};
1021 for (uint8_t i : {
'@',
'/',
'\\',
'?'}) {
1028find_authority_delimiter_special(std::string_view view)
noexcept {
1031 for (
auto pos = view.begin(); pos != view.end(); ++pos) {
1033 return pos - view.begin();
1036 return size_t(view.size());
1041 std::array<uint8_t, 256>
result{};
1042 for (uint8_t i : {
'@',
'/',
'?'}) {
1049find_authority_delimiter(std::string_view view)
noexcept {
1052 for (
auto pos = view.begin(); pos != view.end(); ++pos) {
1054 return pos - view.begin();
1057 return size_t(view.size());
1066#undef ada_make_uint8x16_t
Definitions for URL specific checkers used within Ada.
Cross-platform compiler macros and common definitions.
#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
type
Enumeration of URL scheme types.
state
States in the URL parsing state machine.
@ SPECIAL_RELATIVE_OR_AUTHORITY
@ SPECIAL_AUTHORITY_SLASHES
@ SPECIAL_AUTHORITY_IGNORE_SLASHES
ada_warn_unused std::string_view to_string(encoding_type type)
tl::expected< result_type, ada::errors > result
URL scheme type definitions and utilities.