Skip to content

Commit

Permalink
improve support enum
Browse files Browse the repository at this point in the history
  • Loading branch information
bbbgan committed Jul 26, 2023
1 parent 20c2337 commit 33fe543
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 25 deletions.
86 changes: 69 additions & 17 deletions iguana/enum_reflection.hpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#pragma once
#include "frozen/string.h"
#include "frozen/unordered_map.h"
#include <array>
#include <string_view>

#include "frozen/string.h"
#include "frozen/unordered_map.h"

namespace iguana {
template <typename T> constexpr std::string_view get_raw_name() {
#ifdef _MSC_VER
Expand Down Expand Up @@ -61,7 +62,7 @@ template <typename E, E V> constexpr std::string_view get_raw_name_with_v() {
}

template <typename E, E V>
constexpr inline std::pair<bool, std::string_view> try_get_enum_name() {
constexpr std::pair<bool, std::string_view> try_get_enum_name() {
constexpr std::string_view sample_raw_name = get_raw_name_with_v<int, 5>();
constexpr size_t pos = sample_raw_name.find("5");
constexpr std::string_view enum_raw_name = get_raw_name_with_v<E, V>();
Expand All @@ -81,18 +82,21 @@ constexpr inline std::pair<bool, std::string_view> try_get_enum_name() {
res.substr(pos_colon == std::string_view::npos ? 0 : pos_colon + 2)};
}

template <typename E, std::size_t I> constexpr auto get_enum_name_helper() {
return try_get_enum_name<E, static_cast<E>(I)>();
// get the size of integer_sequence
template <typename T, T... I>
constexpr std::size_t integer_sequence_size(std::integer_sequence<T, I...>) {
return sizeof...(I);
}

template <typename E, std::size_t... Is>
constexpr inline auto get_enum_arr(const std::index_sequence<Is...> &) {
template <typename E, std::int64_t... Is>
constexpr inline auto
get_enum_arr(const std::integer_sequence<std::int64_t, Is...> &) {
constexpr std::size_t N = sizeof...(Is);
std::array<std::string_view, N> enum_names = {};
std::array<E, N> enum_values = {};
std::size_t num = 0;
(([&]() {
constexpr auto res = get_enum_name_helper<E, Is>();
constexpr auto res = try_get_enum_name<E, static_cast<E>(Is)>();
if constexpr (res.first) {
enum_names[num] = res.second;
enum_values[num] = static_cast<E>(Is);
Expand All @@ -103,6 +107,32 @@ constexpr inline auto get_enum_arr(const std::index_sequence<Is...> &) {
return std::make_tuple(num, enum_values, enum_names);
}

template <std::int64_t... I1, std::int64_t... I2>
constexpr auto
concatenate_sequences(std::integer_sequence<std::int64_t, I1...>,
std::integer_sequence<std::int64_t, I2...>) {
return std::integer_sequence<std::int64_t, I1..., I2...>{};
}

template <std::int64_t I, std::int64_t N, const std::array<int, N> &arr>
constexpr auto array_to_seq() {
if constexpr (I > 0) {
if constexpr (arr[I] < 50 && arr[I] >= 0) {
return array_to_seq<I - 1, N, arr>();
} else {
return concatenate_sequences(
std::integer_sequence<std::int64_t, arr[I]>{},
array_to_seq<I - 1, N, arr>());
}
} else {
if constexpr (arr[I] < 50 && arr[I] >= 0) {
return std::integer_sequence<std::int64_t>();
} else {
return std::integer_sequence<std::int64_t, arr[I]>();
}
}
}

template <typename E, size_t N, size_t... Is>
constexpr inline auto
get_enum_to_str_map(const std::array<std::string_view, N> &enum_names,
Expand All @@ -121,18 +151,40 @@ get_str_to_enum_map(const std::array<std::string_view, N> &enum_names,
{enum_names[Is], enum_values[Is]}...};
}

template <typename T> struct enum_value {
constexpr static std::array<int, 0> value = {};
};

template <bool str_to_enum, typename E, size_t N = 50>
constexpr inline auto get_enum_map() {
constexpr auto t = get_enum_arr<E>(std::make_index_sequence<N>());

if constexpr (str_to_enum) {
return get_str_to_enum_map<E, N>(
std::get<2>(t), std::get<1>(t),
std::make_index_sequence<std::get<0>(t)>{});
constexpr auto indexSeq = std::make_integer_sequence<std::int64_t, N>();
constexpr auto &arr = enum_value<E>::value;
constexpr auto size = arr.size();
if constexpr (size > 0) {
constexpr auto seq = array_to_seq<size - 1, size, arr>();
constexpr auto seq_all = concatenate_sequences(seq, indexSeq);
constexpr auto size_all = integer_sequence_size(seq_all);
constexpr auto t = get_enum_arr<E>(seq_all);
if constexpr (str_to_enum) {
return get_str_to_enum_map<E, size_all>(
std::get<2>(t), std::get<1>(t),
std::make_index_sequence<std::get<0>(t)>{});
} else {
return get_enum_to_str_map<E, size_all>(
std::get<2>(t), std::get<1>(t),
std::make_index_sequence<std::get<0>(t)>{});
}
} else {
return get_enum_to_str_map<E, N>(
std::get<2>(t), std::get<1>(t),
std::make_index_sequence<std::get<0>(t)>{});
constexpr auto t = get_enum_arr<E>(indexSeq);
if constexpr (str_to_enum) {
return get_str_to_enum_map<E, N>(
std::get<2>(t), std::get<1>(t),
std::make_index_sequence<std::get<0>(t)>{});
} else {
return get_enum_to_str_map<E, N>(
std::get<2>(t), std::get<1>(t),
std::make_index_sequence<std::get<0>(t)>{});
}
}
}
#if defined(__clang__) && (__clang_major__ >= 17)
Expand Down
43 changes: 35 additions & 8 deletions test/unit_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -212,21 +212,48 @@ TEST_CASE("test parse item seq container") {
}
}

enum class Color { RED = 1, GREEN = 3, BLUE = 4 };

enum class Fruit {
APPLE = 9999,
BANANA = -4,
ORANGE = 10,
MANGO = 99,
CHERRY = 7,
GRAPE = 100000
};
namespace iguana {
template <> struct enum_value<Fruit> {
constexpr static std::array<int, 6> value = {9999, -4, 10, 99, 7, 100000};
};
} // namespace iguana
struct test_enum_t {
Color a;
Color b;
Fruit a;
Fruit b;
Fruit c;
Fruit d;
Fruit e;
Fruit f;
};
REFLECTION(test_enum_t, a, b);
REFLECTION(test_enum_t, a, b, c, d, e, f);

TEST_CASE("test enum") {
auto validator = [](test_enum_t e) {
CHECK(e.a == Color::RED);
CHECK(e.b == Color::BLUE);
CHECK(e.a == Fruit::APPLE);
CHECK(e.b == Fruit::BANANA);
CHECK(e.c == Fruit::ORANGE);
CHECK(e.d == Fruit::MANGO);
CHECK(e.e == Fruit::CHERRY);
CHECK(e.f == Fruit::GRAPE);
};
std::string str = R"(
{"a": "RED", "b": "BLUE" })";
{
"a": "APPLE",
"b": "BANANA",
"c": "ORANGE",
"d": "MANGO",
"e": "CHERRY",
"f": "GRAPE"
}
)";
test_enum_t e;
iguana::from_json(e, str);
validator(e);
Expand Down

0 comments on commit 33fe543

Please sign in to comment.