Skip to content

Commit

Permalink
[struct_json, struct_xml, struct_yaml][feat]support cpp17 (#394)
Browse files Browse the repository at this point in the history
  • Loading branch information
qicosmos authored Aug 2, 2023
1 parent 23d62e7 commit acb748a
Show file tree
Hide file tree
Showing 15 changed files with 1,037 additions and 1,007 deletions.
3 changes: 3 additions & 0 deletions cmake/subdir.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ endforeach()

if (NOT ENABLE_CPP_20)
Set(BUILD_STRUCT_PACK ON)
Set(BUILD_STRUCT_JSON ON)
Set(BUILD_STRUCT_XML ON)
Set(BUILD_STRUCT_YAML ON)
endif()

foreach(child ${children})
Expand Down
4 changes: 2 additions & 2 deletions include/ylt/struct_yaml/yaml_reader.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@

namespace struct_yaml {

template <typename T, iguana::string_t View>
template <typename T, typename View>
inline void from_yaml(T &value, const View &view) {
iguana::from_yaml(value, view);
}

template <typename T, iguana::string_t View>
template <typename T, typename View>
inline void from_yaml(T &value, const View &view, std::error_code &ec) {
iguana::from_yaml(value, view, ec);
}
Expand Down
22 changes: 18 additions & 4 deletions include/ylt/thirdparty/iguana/define.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#pragma once

#include <array>
#if __cplusplus >= 202002L
#include <bit>
#endif
#include <string>
#include <string_view>
#include <type_traits>
Expand Down Expand Up @@ -36,11 +38,23 @@ template <typename T>
constexpr inline bool contiguous_iterator = std::contiguous_iterator<T>;

#else
IGUANA_INLINE int countr_zero(unsigned long long x) {
IGUANA_INLINE int countr_zero(unsigned long long n) {
// x will never be zero in iguana
unsigned long pos;
_BitScanForward64(&pos, x);
return pos;
#if defined(_MSC_VER) && defined(_M_X64)
unsigned long c;
_BitScanForward64(&c, n);
return static_cast<int>(c);
#elif defined(_MSC_VER) && defined(_M_IX86)
unsigned long c;
if (static_cast<uint32_t>(n) != 0) {
_BitScanForward(&c, static_cast<uint32_t>(n));
return static_cast<int>(c);
}
else {
_BitScanForward(&c, static_cast<uint32_t>(n >> 32));
return static_cast<int>(c) + 32;
}
#endif
}

namespace std {
Expand Down
172 changes: 172 additions & 0 deletions include/ylt/thirdparty/iguana/enum_reflection.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
#pragma once
#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
return __FUNCSIG__;
#else
return __PRETTY_FUNCTION__;
#endif
}

template <auto T>
constexpr std::string_view get_raw_name() {
#ifdef _MSC_VER
return __FUNCSIG__;
#else
return __PRETTY_FUNCTION__;
#endif
}

template <typename T>
inline constexpr std::string_view type_string() {
constexpr std::string_view sample = get_raw_name<int>();
constexpr size_t pos = sample.find("int");
constexpr std::string_view str = get_raw_name<T>();
constexpr auto next1 = str.rfind(sample[pos + 3]);
#if defined(_MSC_VER)
constexpr auto s1 = str.substr(pos + 6, next1 - pos - 6);
#else
constexpr auto s1 = str.substr(pos, next1 - pos);
#endif
return s1;
}

template <auto T>
inline constexpr std::string_view enum_string() {
constexpr std::string_view sample = get_raw_name<int>();
constexpr size_t pos = sample.find("int");
constexpr std::string_view str = get_raw_name<T>();
constexpr auto next1 = str.rfind(sample[pos + 3]);
#if defined(__clang__) || defined(_MSC_VER)
constexpr auto s1 = str.substr(pos, next1 - pos);
#else
constexpr auto s1 = str.substr(pos + 5, next1 - pos - 5);
#endif
return s1;
}

#if defined(__clang__) && (__clang_major__ >= 17)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wenum-constexpr-conversion"
#endif

template <typename E, E V>
constexpr std::string_view get_raw_name_with_v() {
#ifdef _MSC_VER
return __FUNCSIG__;
#else
return __PRETTY_FUNCTION__;
#endif
}

// True means the V is a valid enum value, and the second of the result is the
// name
template <typename E, E V>
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>();
constexpr auto enum_end = enum_raw_name.rfind(&sample_raw_name[pos + 1]);
#ifdef _MSC_VER
constexpr auto enum_begin = enum_raw_name.rfind(',', enum_end) + 1;
#else
constexpr auto enum_begin = enum_raw_name.rfind(' ', enum_end) + 1;
#endif
constexpr std::string_view res =
enum_raw_name.substr(enum_begin, enum_end - enum_begin);

constexpr size_t pos_brackets = res.find(')');

size_t pos_colon = res.find("::");
return {pos_brackets == std::string_view::npos,
res.substr(pos_colon == std::string_view::npos ? 0 : pos_colon + 2)};
}

// Enumerate the numbers in a integer sequence to see if they are legal enum
// value
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 = try_get_enum_name<E, static_cast<E>(Is)>();
if constexpr (res.first) {
// the Is is a valid enum value
enum_names[num] = res.second;
enum_values[num] = static_cast<E>(Is);
++num;
}
})(),
...);
return std::make_tuple(num, enum_values, enum_names);
}

template <std::size_t N, const std::array<int, N> &arr, size_t... Is>
constexpr auto array_to_seq(const std::index_sequence<Is...> &) {
return std::integer_sequence<std::int64_t, arr[Is]...>();
}

// convert array to map
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,
const std::array<E, N> &enum_values, const std::index_sequence<Is...> &) {
return frozen::unordered_map<E, frozen::string, sizeof...(Is)>{
{enum_values[Is], enum_names[Is]}...};
}

template <typename E, size_t N, size_t... Is>
constexpr inline auto get_str_to_enum_map(
const std::array<std::string_view, N> &enum_names,
const std::array<E, N> &enum_values, const std::index_sequence<Is...> &) {
return frozen::unordered_map<frozen::string, E, sizeof...(Is)>{
{enum_names[Is], enum_values[Is]}...};
}

// the default generic enum_value
// if the user has not defined a specialization template, this will be called
template <typename T>
struct enum_value {
constexpr static std::array<int, 0> value = {};
};

template <bool str_to_enum, typename E>
constexpr inline auto get_enum_map() {
constexpr auto &arr = enum_value<E>::value;
constexpr auto arr_size = arr.size();
if constexpr (arr_size > 0) {
// the user has defined a specialization template
constexpr auto arr_seq =
array_to_seq<arr_size, arr>(std::make_index_sequence<arr_size>());
constexpr auto t = get_enum_arr<E>(arr_seq);
if constexpr (str_to_enum) {
return get_str_to_enum_map<E, arr_size>(
std::get<2>(t), std::get<1>(t),
std::make_index_sequence<std::get<0>(t)>{});
}
else {
return get_enum_to_str_map<E, arr_size>(
std::get<2>(t), std::get<1>(t),
std::make_index_sequence<std::get<0>(t)>{});
}
}
else {
return false;
}
}

#if defined(__clang__) && (__clang_major__ >= 17)
#pragma clang diagnostic pop
#endif

} // namespace iguana
38 changes: 27 additions & 11 deletions include/ylt/thirdparty/iguana/json_reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ IGUANA_INLINE void parse_escape(U &value, It &&it, It &&end) {
if (*it == 'u') {
++it;
if (std::distance(it, end) <= 4)
throw std::runtime_error(R"(Expected 4 hexadecimal digits)");
IGUANA_UNLIKELY {
throw std::runtime_error(R"(Expected 4 hexadecimal digits)");
}
auto code_point = parse_unicode_hex4(it);
encode_utf8(value, code_point);
}
Expand Down Expand Up @@ -94,12 +96,6 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) {
std::string_view(&*start, static_cast<size_t>(std::distance(start, it)));
}

template <typename U, typename It, std::enable_if_t<enum_v<U>, int> = 0>
IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) {
using T = std::underlying_type_t<std::decay_t<U>>;
parse_item(reinterpret_cast<T &>(value), it, end);
}

template <bool skip = false, typename U, typename It,
std::enable_if_t<char_v<U>, int> = 0>
IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) {
Expand Down Expand Up @@ -197,7 +193,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) {
IGUANA_UNLIKELY case '\\' : ++it;
parse_escape(value, it, end);
break;
IGUANA_UNLIKELY case ']' : return;
// IGUANA_UNLIKELY case ']' : return;
IGUANA_UNLIKELY case '"' : ++it;
return;
IGUANA_LIKELY default : value.push_back(*it);
Expand Down Expand Up @@ -229,6 +225,27 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) {
throw std::runtime_error("Expected \"");
}

template <typename U, typename It, std::enable_if_t<enum_v<U>, int> = 0>
IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) {
static constexpr auto str_to_enum = get_enum_map<true, std::decay_t<U>>();
if constexpr (bool_v<decltype(str_to_enum)>) {
// not defined a specialization template
using T = std::underlying_type_t<std::decay_t<U>>;
parse_item(reinterpret_cast<T &>(value), it, end);
}
else {
std::string_view enum_names;
parse_item(enum_names, it, end);
auto it = str_to_enum.find(enum_names);
if (it != str_to_enum.end())
IGUANA_LIKELY { value = it->second; }
else {
throw std::runtime_error(std::string(enum_names) +
" missing corresponding value in enum_value");
}
}
}

template <typename U, typename It, std::enable_if_t<fixed_array_v<U>, int> = 0>
IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) {
using T = std::remove_reference_t<U>;
Expand Down Expand Up @@ -655,9 +672,8 @@ inline void parse_object(jobject &result, It &&it, It &&end) {
skip_ws(it, end);

while (true) {
if (it == end) {
break;
}
if (it == end)
IGUANA_UNLIKELY { throw std::runtime_error("Expected }"); }
std::string key;
detail::parse_item(key, it, end);

Expand Down
Loading

0 comments on commit acb748a

Please sign in to comment.