#pragma once #include "bmcweb_config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace crow { namespace black_magic { enum class TypeCode : uint8_t { Unspecified = 0, Integer = 1, UnsignedInteger = 2, Float = 3, String = 4, Path = 5, Max = 6, }; // Remove when we have c++23 template constexpr typename std::underlying_type::type toUnderlying(E e) noexcept { return static_cast::type>(e); } template constexpr TypeCode getParameterTag() { if constexpr (std::is_same_v) { return TypeCode::Integer; } if constexpr (std::is_same_v) { return TypeCode::Integer; } if constexpr (std::is_same_v) { return TypeCode::Integer; } if constexpr (std::is_same_v) { return TypeCode::Integer; } if constexpr (std::is_same_v) { return TypeCode::Integer; } if constexpr (std::is_same_v) { return TypeCode::UnsignedInteger; } if constexpr (std::is_same_v) { return TypeCode::UnsignedInteger; } if constexpr (std::is_same_v) { return TypeCode::UnsignedInteger; } if constexpr (std::is_same_v) { return TypeCode::UnsignedInteger; } if constexpr (std::is_same_v) { return TypeCode::UnsignedInteger; } if constexpr (std::is_same_v) { return TypeCode::Float; } if constexpr (std::is_same_v) { return TypeCode::String; } return TypeCode::Unspecified; } template struct computeParameterTagFromArgsList; template <> struct computeParameterTagFromArgsList<> { static constexpr int value = 0; }; template struct computeParameterTagFromArgsList { static constexpr int subValue = computeParameterTagFromArgsList::value; static constexpr int value = getParameterTag::type>() != TypeCode::Unspecified ? static_cast(subValue * toUnderlying(TypeCode::Max)) + static_cast( getParameterTag::type>()) : subValue; }; inline bool isParameterTagCompatible(uint64_t a, uint64_t b) { while (true) { if (a == 0 && b == 0) { // Both tags were equivalent, parameters are compatible return true; } if (a == 0 || b == 0) { // one of the tags had more parameters than the other return false; } TypeCode sa = static_cast(a % toUnderlying(TypeCode::Max)); TypeCode sb = static_cast(b % toUnderlying(TypeCode::Max)); if (sa == TypeCode::Path) { sa = TypeCode::String; } if (sb == TypeCode::Path) { sb = TypeCode::String; } if (sa != sb) { return false; } a /= toUnderlying(TypeCode::Max); b /= toUnderlying(TypeCode::Max); } return false; } constexpr inline uint64_t getParameterTag(std::string_view url) { uint64_t tagValue = 0; size_t urlSegmentIndex = std::string_view::npos; size_t paramIndex = 0; for (size_t urlIndex = 0; urlIndex < url.size(); urlIndex++) { char character = url[urlIndex]; if (character == '<') { if (urlSegmentIndex != std::string_view::npos) { return 0; } urlSegmentIndex = urlIndex; } if (character == '>') { if (urlSegmentIndex == std::string_view::npos) { return 0; } std::string_view tag = url.substr(urlSegmentIndex, urlIndex + 1 - urlSegmentIndex); // Note, this is a really lame way to do std::pow(6, paramIndex) // std::pow doesn't work in constexpr in clang. // Ideally in the future we'd move this to use a power of 2 packing // (probably 8 instead of 6) so that these just become bit shifts uint64_t insertIndex = 1; for (size_t unused = 0; unused < paramIndex; unused++) { insertIndex *= 6; } if (tag == "") { tagValue += insertIndex * toUnderlying(TypeCode::Integer); } if (tag == "") { tagValue += insertIndex * toUnderlying(TypeCode::UnsignedInteger); } if (tag == "" || tag == "") { tagValue += insertIndex * toUnderlying(TypeCode::Float); } if (tag == "" || tag == "") { tagValue += insertIndex * toUnderlying(TypeCode::String); } if (tag == "") { tagValue += insertIndex * toUnderlying(TypeCode::Path); } paramIndex++; urlSegmentIndex = std::string_view::npos; } } if (urlSegmentIndex != std::string_view::npos) { return 0; } return tagValue; } template struct S { template using push = S; template using push_back = S; template