Skip to content

Commit

Permalink
add alias and copy iguana
Browse files Browse the repository at this point in the history
  • Loading branch information
Jacyking committed Aug 15, 2023
1 parent f27f236 commit 3184edf
Show file tree
Hide file tree
Showing 16 changed files with 1,539 additions and 1,331 deletions.
21 changes: 17 additions & 4 deletions 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,22 @@ 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
8 changes: 5 additions & 3 deletions iguana/detail/charconv.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
namespace iguana {
template <typename T>
struct is_char_type
: std::disjunction<std::is_same<T, char>, std::is_same<T, unsigned char>,
std::is_same<T, signed char>, std::is_same<T, wchar_t>,
: std::disjunction<std::is_same<T, char>, std::is_same<T, wchar_t>,
std::is_same<T, char16_t>, std::is_same<T, char32_t>> {};

namespace detail {
Expand All @@ -34,8 +33,11 @@ template <typename T> char *to_chars(char *buffer, T value) noexcept {
return xtoa(value, buffer, 10, 1); // int64_t
} else if constexpr (std::is_unsigned_v<U> && (sizeof(U) >= 8)) {
return xtoa(value, buffer, 10, 0); // uint64_t
} else if constexpr (std::is_integral_v<U> && !is_char_type<U>::value) {
} else if constexpr (std::is_integral_v<U> && (sizeof(U) > 1)) {
return itoa_fwd(value, buffer); // only support more than 2 bytes intergal
} else if constexpr (!is_char_type<U>::value) {
return itoa_fwd(static_cast<int>(value),
buffer); // only support more than 2 bytes intergal
} else {
static_assert(!sizeof(U), "only support arithmetic type except char type");
}
Expand Down
165 changes: 165 additions & 0 deletions iguana/enum_reflection.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
#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
57 changes: 40 additions & 17 deletions iguana/json_reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ template <typename U, typename It,
std::enable_if_t<sequence_container_v<U>, int> = 0>
IGUANA_INLINE void parse_item(U &value, It &&it, It &&end);

template <typename U, typename It, std::enable_if_t<smart_ptr_v<U>, int> = 0>
IGUANA_INLINE void parse_item(U &value, It &&it, It &&end);

template <typename U, typename It, std::enable_if_t<refletable_v<U>, int> = 0>
IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) {
from_json(value, it, end);
Expand All @@ -25,7 +28,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);
} else if (*it == 'n') {
Expand Down Expand Up @@ -87,12 +92,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 @@ -183,7 +182,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 @@ -215,6 +214,26 @@ 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 @@ -408,7 +427,7 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) {
}
}

template <typename U, typename It, std::enable_if_t<unique_ptr_v<U>, int> = 0>
template <typename U, typename It, std::enable_if_t<smart_ptr_v<U>, int>>
IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) {
skip_ws(it, end);
if (it < end && *it == '"')
Expand All @@ -420,7 +439,11 @@ IGUANA_INLINE void parse_item(U &value, It &&it, It &&end) {
match<'u', 'l', 'l'>(it, end);
} else {
using value_type = typename std::remove_reference_t<U>::element_type;
value = std::make_unique<value_type>();
if constexpr (unique_ptr_v<U>) {
value = std::make_unique<value_type>();
} else {
value = std::make_shared<value_type>();
}
parse_item(*value, it, end);
}
}
Expand Down Expand Up @@ -592,7 +615,7 @@ template <bool Is_view = false, typename It>
void parse(jvalue &result, It &&it, It &&end);

template <bool Is_view = false, typename It>
inline void parse_array(jarray &result, It &&it, It &&end) {
inline void parse(jarray &result, It &&it, It &&end) {
skip_ws(it, end);
match<'['>(it, end);
if (*it == ']')
Expand Down Expand Up @@ -620,7 +643,7 @@ inline void parse_array(jarray &result, It &&it, It &&end) {
}

template <bool Is_view = false, typename It>
inline void parse_object(jobject &result, It &&it, It &&end) {
inline void parse(jobject &result, It &&it, It &&end) {
skip_ws(it, end);
match<'{'>(it, end);
if (*it == '}')
Expand All @@ -632,9 +655,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 Expand Up @@ -700,11 +722,11 @@ inline void parse(jvalue &result, It &&it, It &&end) {
break;
case '[':
result.template emplace<jarray>();
parse_array<Is_view>(std::get<jarray>(result), it, end);
parse<Is_view>(std::get<jarray>(result), it, end);
break;
case '{': {
result.template emplace<jobject>();
parse_object<Is_view>(std::get<jobject>(result), it, end);
parse<Is_view>(std::get<jobject>(result), it, end);
break;
}
default:
Expand All @@ -714,6 +736,7 @@ inline void parse(jvalue &result, It &&it, It &&end) {
skip_ws(it, end);
}

// when Is_view is true, parse str as string_view
template <bool Is_view = false, typename It>
inline void parse(jvalue &result, It &&it, It &&end, std::error_code &ec) {
try {
Expand Down
Loading

0 comments on commit 3184edf

Please sign in to comment.