Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[struct_json, struct_xml, struct_yaml][feat]support cpp17 #394

Merged
merged 8 commits into from
Aug 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading