| 511 | |
| 512 | template <size_t length> |
| 513 | struct ApiInvokeDescriptor |
| 514 | { |
| 515 | size_t api; |
| 516 | size_t version; |
| 517 | |
| 518 | consteval size_t DataHash(const std::string_view &data) const |
| 519 | { |
| 520 | constexpr size_t fnvOffsetBasis = 0x811C9DC5ull; |
| 521 | constexpr size_t fnvPrime = 0x1000193ull; |
| 522 | size_t hash = fnvOffsetBasis; |
| 523 | |
| 524 | for (size_t i = 0; i < data.size(); ++i) |
| 525 | { |
| 526 | hash ^= static_cast<size_t>(data[i]); |
| 527 | hash *= fnvPrime; |
| 528 | } |
| 529 | |
| 530 | return hash; |
| 531 | } |
| 532 | |
| 533 | consteval bool operator==(const char *rhs) const |
| 534 | { |
| 535 | return api == DataHash(rhs); |
| 536 | } |
| 537 | |
| 538 | consteval ApiInvokeDescriptor(const char (&apiInvokeName)[length]) |
| 539 | { |
| 540 | const std::string_view apiInvokeNameView{apiInvokeName}; |
| 541 | const auto invokeNameDelimiter = apiInvokeNameView.find("@"); |
| 542 | |
| 543 | if (std::string_view::npos == invokeNameDelimiter) |
| 544 | { |
| 545 | api = DataHash(apiInvokeName); |
| 546 | version = SupportedMinVersion; |
| 547 | } |
| 548 | else |
| 549 | { |
| 550 | if ('v' != apiInvokeNameView[invokeNameDelimiter + 1]) |
| 551 | throw std::invalid_argument("Invalid version string, must start with 'v'"); |
| 552 | |
| 553 | const auto invokeName = apiInvokeNameView.substr(0, invokeNameDelimiter); |
| 554 | const auto invokeVersion = apiInvokeNameView.substr(invokeNameDelimiter + 2); |
| 555 | |
| 556 | api = DataHash(invokeName); |
| 557 | |
| 558 | version = 0; |
| 559 | for (char c : invokeVersion) |
| 560 | { |
| 561 | if (c < '0' || c > '9') |
| 562 | throw std::invalid_argument("Invalid version string, must be digits only"); |
| 563 | |
| 564 | version = version * 10 + (c - '0'); |
| 565 | } |
| 566 | } |
| 567 | } |
| 568 | }; |
| 569 | |
| 570 | template <ApiInvokeDescriptor descriptor> |
nothing calls this directly
no outgoing calls
no test coverage detected