| #ifndef THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_REDFISH_BLACK_MAGIC_H_ |
| #define THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_REDFISH_BLACK_MAGIC_H_ |
| |
| #include <cstddef> |
| #include <cstdint> |
| #include <string> |
| #include <string_view> |
| #include <type_traits> |
| |
| namespace milotic_tlbmc { |
| namespace crow { |
| |
| namespace black_magic { |
| |
| enum class TypeCode : uint8_t { |
| kUnspecified = 0, |
| kInteger = 1, |
| kUnsignedInteger = 2, |
| kFloat = 3, |
| kString = 4, |
| kPath = 5, |
| kMax = 6, |
| }; |
| |
| // Remove when we have c++23 |
| template <typename E> |
| constexpr typename std::underlying_type<E>::type ToUnderlying(E e) noexcept { |
| return static_cast<typename std::underlying_type<E>::type>(e); |
| } |
| |
| template <typename T> |
| constexpr TypeCode GetParameterTag() { |
| if constexpr (std::is_same_v<int, T>) { |
| return TypeCode::kInteger; |
| } |
| if constexpr (std::is_same_v<char, T>) { |
| return TypeCode::kInteger; |
| } |
| if constexpr (std::is_same_v<short, T>) { |
| return TypeCode::kInteger; |
| } |
| if constexpr (std::is_same_v<long, T>) { |
| return TypeCode::kInteger; |
| } |
| if constexpr (std::is_same_v<long long, T>) { |
| return TypeCode::kInteger; |
| } |
| if constexpr (std::is_same_v<unsigned int, T>) { |
| return TypeCode::kUnsignedInteger; |
| } |
| if constexpr (std::is_same_v<unsigned char, T>) { |
| return TypeCode::kUnsignedInteger; |
| } |
| if constexpr (std::is_same_v<unsigned short, T>) { |
| return TypeCode::kUnsignedInteger; |
| } |
| if constexpr (std::is_same_v<unsigned long, T>) { |
| return TypeCode::kUnsignedInteger; |
| } |
| if constexpr (std::is_same_v<unsigned long long, T>) { |
| return TypeCode::kUnsignedInteger; |
| } |
| if constexpr (std::is_same_v<double, T>) { |
| return TypeCode::kFloat; |
| } |
| if constexpr (std::is_same_v<std::string, T>) { |
| return TypeCode::kString; |
| } |
| return TypeCode::kUnspecified; |
| } |
| |
| template <typename... Args> |
| struct ComputeParameterTagFromArgsList; |
| |
| template <> |
| struct ComputeParameterTagFromArgsList<> { |
| static constexpr int value = 0; |
| }; |
| |
| constexpr uint64_t GetParameterTag(std::string_view url) { |
| uint64_t tag_value = 0; |
| size_t url_segment_index = std::string_view::npos; |
| |
| size_t param_index = 0; |
| |
| for (size_t url_index = 0; url_index < url.size(); url_index++) { |
| char character = url[url_index]; |
| if (character == '<') { |
| if (url_segment_index != std::string_view::npos) { |
| return 0; |
| } |
| url_segment_index = url_index; |
| } |
| if (character == '>') { |
| if (url_segment_index == std::string_view::npos) { |
| return 0; |
| } |
| std::string_view tag = |
| url.substr(url_segment_index, url_index + 1 - url_segment_index); |
| |
| // 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 insert_index = 1; |
| for (size_t unused = 0; unused < param_index; unused++) { |
| insert_index *= 6; |
| } |
| if (tag == "<str>" || tag == "<string>") { |
| tag_value += insert_index * ToUnderlying(TypeCode::kString); |
| } |
| param_index++; |
| url_segment_index = std::string_view::npos; |
| } |
| } |
| if (url_segment_index != std::string_view::npos) { |
| return 0; |
| } |
| return tag_value; |
| } |
| |
| template <typename Arg, typename... Args> |
| struct ComputeParameterTagFromArgsList<Arg, Args...> { |
| static constexpr int sub_value = |
| ComputeParameterTagFromArgsList<Args...>::value; |
| static constexpr int value = |
| GetParameterTag<typename std::decay<Arg>::type>() != |
| TypeCode::kUnspecified |
| ? static_cast<unsigned long>(sub_value * |
| ToUnderlying(TypeCode::kMax)) + |
| static_cast<uint64_t>( |
| GetParameterTag<typename std::decay<Arg>::type>()) |
| : sub_value; |
| }; |
| |
| template <typename... T> |
| struct S { |
| template <typename U> |
| using push = S<U, T...>; |
| template <typename U> |
| using push_back = S<T..., U>; |
| template <template <typename... Args> class U> |
| using rebind = U<T...>; |
| }; |
| |
| template <typename F, typename Set> |
| struct CallHelper; |
| |
| template <typename F, typename... Args> |
| struct CallHelper<F, S<Args...>> { |
| template <typename F1, typename... Args1, |
| typename = decltype(std::declval<F1>()(std::declval<Args1>()...))> |
| static char test(int); |
| |
| template <typename...> |
| static int test(...); |
| |
| static constexpr bool value = sizeof(test<F, Args...>(0)) == sizeof(char); |
| }; |
| |
| template <uint64_t N> |
| struct SingleTagToType {}; |
| |
| template <> |
| struct SingleTagToType<1> { |
| using type = int64_t; |
| }; |
| |
| template <> |
| struct SingleTagToType<2> { |
| using type = uint64_t; |
| }; |
| |
| template <> |
| struct SingleTagToType<3> { |
| using type = double; |
| }; |
| |
| template <> |
| struct SingleTagToType<4> { |
| using type = std::string; |
| }; |
| |
| template <> |
| struct SingleTagToType<5> { |
| using type = std::string; |
| }; |
| |
| template <uint64_t Tag> |
| struct Arguments { |
| using subarguments = typename Arguments<Tag / 6>::type; |
| using type = typename subarguments::template push< |
| typename SingleTagToType<Tag % 6>::type>; |
| }; |
| |
| template <> |
| struct Arguments<0> { |
| using type = S<>; |
| }; |
| |
| template <typename T> |
| struct Promote { |
| using type = T; |
| }; |
| |
| template <typename T> |
| using PromoteT = typename Promote<T>::type; |
| |
| template <> |
| struct Promote<char> { |
| using type = int64_t; |
| }; |
| template <> |
| struct Promote<short> { |
| using type = int64_t; |
| }; |
| template <> |
| struct Promote<int> { |
| using type = int64_t; |
| }; |
| template <> |
| struct Promote<long> { |
| using type = int64_t; |
| }; |
| template <> |
| struct Promote<long long> { |
| using type = int64_t; |
| }; |
| template <> |
| struct Promote<unsigned char> { |
| using type = uint64_t; |
| }; |
| template <> |
| struct Promote<unsigned short> { |
| using type = uint64_t; |
| }; |
| template <> |
| struct Promote<unsigned int> { |
| using type = uint64_t; |
| }; |
| template <> |
| struct Promote<unsigned long> { |
| using type = uint64_t; |
| }; |
| template <> |
| struct Promote<unsigned long long> { |
| using type = uint64_t; |
| }; |
| |
| } // namespace black_magic |
| } // namespace crow |
| } // namespace milotic_tlbmc |
| |
| #endif // THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_REDFISH_BLACK_MAGIC_H_ |