|
1 | | -/* auto-generated on 2026-02-23 21:29:24 -0500. Do not edit! */ |
| 1 | +/* auto-generated on 2026-03-23 17:52:13 -0400. Do not edit! */ |
2 | 2 | /* begin file include/ada.h */ |
3 | 3 | /** |
4 | 4 | * @file ada.h |
@@ -6458,6 +6458,39 @@ constexpr std::string_view is_special_list[] = {"http", " ", "https", "ws", |
6458 | 6458 | "ftp", "wss", "file", " "}; |
6459 | 6459 | // for use with get_special_port |
6460 | 6460 | constexpr uint16_t special_ports[] = {80, 0, 443, 80, 21, 443, 0, 0}; |
| 6461 | + |
| 6462 | +// @private |
| 6463 | +// convert a string_view to a 64-bit integer key for fast comparison |
| 6464 | +constexpr uint64_t make_key(std::string_view sv) { |
| 6465 | + uint64_t val = 0; |
| 6466 | + for (size_t i = 0; i < sv.size(); i++) |
| 6467 | + val |= (uint64_t)(uint8_t)sv[i] << (i * 8); |
| 6468 | + return val; |
| 6469 | +} |
| 6470 | +// precomputed keys for the special schemes, indexed by a hash of the input |
| 6471 | +// string |
| 6472 | +constexpr uint64_t scheme_keys[] = { |
| 6473 | + make_key("http"), // 0: HTTP |
| 6474 | + 0, // 1: sentinel |
| 6475 | + make_key("https"), // 2: HTTPS |
| 6476 | + make_key("ws"), // 3: WS |
| 6477 | + make_key("ftp"), // 4: FTP |
| 6478 | + make_key("wss"), // 5: WSS |
| 6479 | + make_key("file"), // 6: FILE |
| 6480 | + 0, // 7: sentinel |
| 6481 | +}; |
| 6482 | + |
| 6483 | +// @private |
| 6484 | +// branchless load of up to 5 characters into a uint64_t, padding with zeros if |
| 6485 | +// n < 5 |
| 6486 | +inline uint64_t branchless_load5(const char *p, size_t n) { |
| 6487 | + uint64_t input = (uint8_t)p[0]; |
| 6488 | + input |= ((uint64_t)(uint8_t)p[n > 1] << 8) & (0 - (uint64_t)(n > 1)); |
| 6489 | + input |= ((uint64_t)(uint8_t)p[(n > 2) * 2] << 16) & (0 - (uint64_t)(n > 2)); |
| 6490 | + input |= ((uint64_t)(uint8_t)p[(n > 3) * 3] << 24) & (0 - (uint64_t)(n > 3)); |
| 6491 | + input |= ((uint64_t)(uint8_t)p[(n > 4) * 4] << 32) & (0 - (uint64_t)(n > 4)); |
| 6492 | + return input; |
| 6493 | +} |
6461 | 6494 | } // namespace details |
6462 | 6495 |
|
6463 | 6496 | /**** |
@@ -6498,7 +6531,9 @@ constexpr uint16_t get_special_port(std::string_view scheme) noexcept { |
6498 | 6531 | } |
6499 | 6532 | int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7; |
6500 | 6533 | const std::string_view target = details::is_special_list[hash_value]; |
6501 | | - if ((target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1))) { |
| 6534 | + if (scheme.size() == target.size() && |
| 6535 | + details::branchless_load5(scheme.data(), scheme.size()) == |
| 6536 | + details::scheme_keys[hash_value]) { |
6502 | 6537 | return details::special_ports[hash_value]; |
6503 | 6538 | } else { |
6504 | 6539 | return 0; |
@@ -6513,7 +6548,9 @@ constexpr ada::scheme::type get_scheme_type(std::string_view scheme) noexcept { |
6513 | 6548 | } |
6514 | 6549 | int hash_value = (2 * scheme.size() + (unsigned)(scheme[0])) & 7; |
6515 | 6550 | const std::string_view target = details::is_special_list[hash_value]; |
6516 | | - if ((target[0] == scheme[0]) && (target.substr(1) == scheme.substr(1))) { |
| 6551 | + if (scheme.size() == target.size() && |
| 6552 | + details::branchless_load5(scheme.data(), scheme.size()) == |
| 6553 | + details::scheme_keys[hash_value]) { |
6517 | 6554 | return ada::scheme::type(hash_value); |
6518 | 6555 | } else { |
6519 | 6556 | return ada::scheme::NOT_SPECIAL; |
@@ -9368,7 +9405,8 @@ inline void url_search_params::remove(const std::string_view key, |
9368 | 9405 | } |
9369 | 9406 |
|
9370 | 9407 | inline void url_search_params::sort() { |
9371 | | - // We rely on the fact that the content is valid UTF-8. |
| 9408 | + // Keys are expected to be valid UTF-8, but percent_decode can produce |
| 9409 | + // arbitrary byte sequences. Handle truncated/invalid sequences gracefully. |
9372 | 9410 | std::ranges::stable_sort(params, [](const key_value_pair &lhs, |
9373 | 9411 | const key_value_pair &rhs) { |
9374 | 9412 | size_t i = 0, j = 0; |
@@ -9382,18 +9420,15 @@ inline void url_search_params::sort() { |
9382 | 9420 | low_surrogate1 = 0; |
9383 | 9421 | } else { |
9384 | 9422 | uint8_t c1 = uint8_t(lhs.first[i]); |
9385 | | - if (c1 <= 0x7F) { |
9386 | | - codePoint1 = c1; |
9387 | | - i++; |
9388 | | - } else if (c1 <= 0xDF) { |
| 9423 | + if (c1 > 0x7F && c1 <= 0xDF && i + 1 < lhs.first.size()) { |
9389 | 9424 | codePoint1 = ((c1 & 0x1F) << 6) | (uint8_t(lhs.first[i + 1]) & 0x3F); |
9390 | 9425 | i += 2; |
9391 | | - } else if (c1 <= 0xEF) { |
| 9426 | + } else if (c1 > 0xDF && c1 <= 0xEF && i + 2 < lhs.first.size()) { |
9392 | 9427 | codePoint1 = ((c1 & 0x0F) << 12) | |
9393 | 9428 | ((uint8_t(lhs.first[i + 1]) & 0x3F) << 6) | |
9394 | 9429 | (uint8_t(lhs.first[i + 2]) & 0x3F); |
9395 | 9430 | i += 3; |
9396 | | - } else { |
| 9431 | + } else if (c1 > 0xEF && c1 <= 0xF7 && i + 3 < lhs.first.size()) { |
9397 | 9432 | codePoint1 = ((c1 & 0x07) << 18) | |
9398 | 9433 | ((uint8_t(lhs.first[i + 1]) & 0x3F) << 12) | |
9399 | 9434 | ((uint8_t(lhs.first[i + 2]) & 0x3F) << 6) | |
@@ -9404,6 +9439,10 @@ inline void url_search_params::sort() { |
9404 | 9439 | uint16_t high_surrogate = uint16_t(0xD800 + (codePoint1 >> 10)); |
9405 | 9440 | low_surrogate1 = uint16_t(0xDC00 + (codePoint1 & 0x3FF)); |
9406 | 9441 | codePoint1 = high_surrogate; |
| 9442 | + } else { |
| 9443 | + // ASCII (c1 <= 0x7F) or truncated/invalid UTF-8: treat as raw byte |
| 9444 | + codePoint1 = c1; |
| 9445 | + i++; |
9407 | 9446 | } |
9408 | 9447 | } |
9409 | 9448 |
|
@@ -9412,18 +9451,15 @@ inline void url_search_params::sort() { |
9412 | 9451 | low_surrogate2 = 0; |
9413 | 9452 | } else { |
9414 | 9453 | uint8_t c2 = uint8_t(rhs.first[j]); |
9415 | | - if (c2 <= 0x7F) { |
9416 | | - codePoint2 = c2; |
9417 | | - j++; |
9418 | | - } else if (c2 <= 0xDF) { |
| 9454 | + if (c2 > 0x7F && c2 <= 0xDF && j + 1 < rhs.first.size()) { |
9419 | 9455 | codePoint2 = ((c2 & 0x1F) << 6) | (uint8_t(rhs.first[j + 1]) & 0x3F); |
9420 | 9456 | j += 2; |
9421 | | - } else if (c2 <= 0xEF) { |
| 9457 | + } else if (c2 > 0xDF && c2 <= 0xEF && j + 2 < rhs.first.size()) { |
9422 | 9458 | codePoint2 = ((c2 & 0x0F) << 12) | |
9423 | 9459 | ((uint8_t(rhs.first[j + 1]) & 0x3F) << 6) | |
9424 | 9460 | (uint8_t(rhs.first[j + 2]) & 0x3F); |
9425 | 9461 | j += 3; |
9426 | | - } else { |
| 9462 | + } else if (c2 > 0xEF && c2 <= 0xF7 && j + 3 < rhs.first.size()) { |
9427 | 9463 | codePoint2 = ((c2 & 0x07) << 18) | |
9428 | 9464 | ((uint8_t(rhs.first[j + 1]) & 0x3F) << 12) | |
9429 | 9465 | ((uint8_t(rhs.first[j + 2]) & 0x3F) << 6) | |
@@ -9433,6 +9469,10 @@ inline void url_search_params::sort() { |
9433 | 9469 | uint16_t high_surrogate = uint16_t(0xD800 + (codePoint2 >> 10)); |
9434 | 9470 | low_surrogate2 = uint16_t(0xDC00 + (codePoint2 & 0x3FF)); |
9435 | 9471 | codePoint2 = high_surrogate; |
| 9472 | + } else { |
| 9473 | + // ASCII (c2 <= 0x7F) or truncated/invalid UTF-8: treat as raw byte |
| 9474 | + codePoint2 = c2; |
| 9475 | + j++; |
9436 | 9476 | } |
9437 | 9477 | } |
9438 | 9478 |
|
@@ -11228,14 +11268,14 @@ constructor_string_parser<regex_provider>::parse(std::string_view input) { |
11228 | 11268 | #ifndef ADA_ADA_VERSION_H |
11229 | 11269 | #define ADA_ADA_VERSION_H |
11230 | 11270 |
|
11231 | | -#define ADA_VERSION "3.4.3" |
| 11271 | +#define ADA_VERSION "3.4.4" |
11232 | 11272 |
|
11233 | 11273 | namespace ada { |
11234 | 11274 |
|
11235 | 11275 | enum { |
11236 | 11276 | ADA_VERSION_MAJOR = 3, |
11237 | 11277 | ADA_VERSION_MINOR = 4, |
11238 | | - ADA_VERSION_REVISION = 3, |
| 11278 | + ADA_VERSION_REVISION = 4, |
11239 | 11279 | }; |
11240 | 11280 |
|
11241 | 11281 | } // namespace ada |
|