blob: e43c1f689e44be4217c2b9c23371495f33fac3a4 [file] [log] [blame]
#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_