|
4 | 4 | #include <cctype> |
5 | 5 | #include <algorithm> |
6 | 6 | #include <filesystem> |
| 7 | +#include <unordered_map> |
7 | 8 | #include <boost/asio/version.hpp> |
8 | 9 | #include "http.h" |
9 | 10 |
|
@@ -428,30 +429,59 @@ namespace http |
428 | 429 |
|
429 | 430 | //---------------------------------------------------------------------------------------------------------------- |
430 | 431 |
|
431 | | - constexpr char fast_ascii_tolower(const char c) |
| 432 | + constexpr char fast_ascii_tolower(const char c) noexcept |
432 | 433 | { |
433 | 434 | // The following is a tad faster than std::tolower(c) |
434 | 435 | return (c >= 'A' && c <= 'Z') ? (c | 0x20) : c; |
435 | 436 | } |
436 | 437 |
|
437 | | - constexpr bool case_insenstive_equals(std::string_view a, std::string_view b) |
| 438 | + constexpr bool case_insenstive_equals(std::string_view a, std::string_view b) noexcept |
438 | 439 | { |
439 | 440 | return a.size() == b.size() && std::equal(begin(a), end(a), begin(b), [](char ac, char bc) { |
440 | 441 | return fast_ascii_tolower(ac) == fast_ascii_tolower(bc); |
441 | 442 | }); |
442 | 443 | } |
443 | 444 |
|
| 445 | + struct ci_hash |
| 446 | + { |
| 447 | + constexpr size_t operator()(std::string_view sv) const noexcept |
| 448 | + { |
| 449 | + constexpr std::size_t fnv_offset_basis = 14695981039346656037ull; |
| 450 | + constexpr std::size_t fnv_prime = 1099511628211ull; |
| 451 | + std::size_t hash = fnv_offset_basis; |
| 452 | + |
| 453 | + for (char c : sv) { |
| 454 | + hash ^= static_cast<std::size_t>(fast_ascii_tolower(c)); |
| 455 | + hash *= fnv_prime; |
| 456 | + } |
| 457 | + |
| 458 | + return hash; |
| 459 | + } |
| 460 | + }; |
| 461 | + |
| 462 | + struct ci_compare { constexpr bool operator()(std::string_view lhs, std::string_view rhs) const noexcept { return case_insenstive_equals(lhs, rhs); } }; |
| 463 | + |
| 464 | + const auto FIELD_MAP = [] |
| 465 | + { |
| 466 | + std::unordered_map<std::string_view, field, ci_hash, ci_compare> m; |
| 467 | + for (size_t i = 0 ; i < std::size(FIELDS) ; ++i) |
| 468 | + m[FIELDS[i]] = (field)i; |
| 469 | + return m; |
| 470 | + }(); |
| 471 | + |
444 | 472 | std::string_view field_label(field f) |
445 | 473 | { |
446 | 474 | return FIELDS[f]; |
447 | 475 | } |
448 | 476 |
|
449 | 477 | field field_enum(std::string_view f) |
450 | 478 | { |
451 | | - for (unsigned int i = 0 ; i < std::size(FIELDS) ; ++i) |
452 | | - if (case_insenstive_equals(FIELDS[i], f)) |
453 | | - return (field)i; |
454 | | - return unknown_field; |
| 479 | + const auto it = FIELD_MAP.find(f); |
| 480 | + return it != end(FIELD_MAP) ? it->second : unknown_field; |
| 481 | + // for (unsigned int i = 0 ; i < std::size(FIELDS) ; ++i) |
| 482 | + // if (case_insenstive_equals(FIELDS[i], f)) |
| 483 | + // return (field)i; |
| 484 | + // return unknown_field; |
455 | 485 | } |
456 | 486 |
|
457 | 487 | //---------------------------------------------------------------------------------------------------------------- |
|
0 commit comments