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

[iguana]fix and update #677

Merged
merged 1 commit into from
May 15, 2024
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
44 changes: 37 additions & 7 deletions include/ylt/standalone/iguana/detail/charconv.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,48 @@

#include "dragonbox_to_chars.h"
#include "fast_float.h"
#include "iguana/define.h"
#include "itoa.hpp"

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>> {};

inline void *to_chars_float(...) {
throw std::runtime_error("not allowed to invoke");
return {};
}

template <typename T, typename Ret = decltype(to_chars_float(
std::declval<T>(), std::declval<char *>()))>
using return_of_tochars = std::conditional_t<std::is_same_v<Ret, char *>,
std::true_type, std::false_type>;
// here std::true_type is used as a type , any other type is also ok.
using has_to_chars_float = iguana::return_of_tochars<std::true_type>;

namespace detail {
template <typename U>

// check_number==true: check if the string [first, last) is a legal number
template <bool check_number = true, typename U>
std::pair<const char *, std::errc> from_chars(const char *first,
const char *last,
U &value) noexcept {
const char *last, U &value) {
using T = std::decay_t<U>;
if constexpr (std::is_floating_point_v<T>) {
auto [p, ec] = fast_float::from_chars(first, last, value);
if constexpr (check_number) {
if (p != last || ec != std::errc{})
IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); }
}
return {p, ec};
}
else {
auto [p, ec] = std::from_chars(first, last, value);
if constexpr (check_number) {
if (p != last || ec != std::errc{})
IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); }
}
return {p, ec};
}
}
Expand All @@ -33,17 +54,26 @@ template <typename T>
char *to_chars(char *buffer, T value) noexcept {
using U = std::decay_t<T>;
if constexpr (std::is_floating_point_v<U>) {
return jkj::dragonbox::to_chars(value, buffer);
if constexpr (has_to_chars_float::value) {
return static_cast<char *>(to_chars_float(value, buffer));
}
else {
return jkj::dragonbox::to_chars(value, buffer);
}
}
else if constexpr (std::is_signed_v<U> && (sizeof(U) >= 8)) {
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
9 changes: 9 additions & 0 deletions include/ylt/standalone/iguana/detail/traits.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,15 @@ template <typename T, typename... Us>
struct has_type<T, std::tuple<Us...>>
: std::disjunction<std::is_same<T, Us>...> {};

template <class T>
struct member_tratis {};

template <class T, class Owner>
struct member_tratis<T Owner::*> {
using owner_type = Owner;
using value_type = T;
};

template <typename T>
inline constexpr bool is_int64_v =
std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t>;
Expand Down
71 changes: 66 additions & 5 deletions include/ylt/standalone/iguana/json_reader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) {
if (size == 0)
IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); }
const auto start = &*it;
auto [p, ec] = detail::from_chars(start, start + size, value);
if (ec != std::errc{})
auto [p, ec] = detail::from_chars<false>(start, start + size, value);
if (ec != std::errc{} || !can_follow_number(*p))
IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); }
it += (p - &*it);
}
Expand All @@ -82,9 +82,7 @@ IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) {
buffer[i] = *it++;
++i;
}
auto [p, ec] = detail::from_chars(buffer, buffer + i, value);
if (ec != std::errc{})
IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); }
detail::from_chars(buffer, buffer + i, value);
}
}

Expand Down Expand Up @@ -499,6 +497,44 @@ IGUANA_INLINE void skip_object_value(It &&it, It &&end) {
}
}

template <typename value_type, typename U, typename It>
IGUANA_INLINE bool from_json_variant_impl(U &value, It it, It end, It &temp_it,
It &temp_end) {
try {
value_type val;
from_json_impl(val, it, end);
value = val;
temp_it = it;
temp_end = end;
return true;
} catch (std::exception &ex) {
return false;
}
}

template <typename U, typename It, size_t... Idx>
IGUANA_INLINE void from_json_variant(U &value, It &it, It &end,
std::index_sequence<Idx...>) {
static_assert(!has_duplicate_type_v<std::remove_reference_t<U>>,
"don't allow same type in std::variant");
bool r = false;
It temp_it = it;
It temp_end = end;
((void)(!r && (r = from_json_variant_impl<
variant_element_t<Idx, std::remove_reference_t<U>>>(
value, it, end, temp_it, temp_end),
true)),
...);
it = temp_it;
end = temp_end;
}

template <typename U, typename It, std::enable_if_t<variant_v<U>, int> = 0>
IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) {
from_json_variant(value, it, end,
std::make_index_sequence<
std::variant_size_v<std::remove_reference_t<U>>>{});
}
} // namespace detail

template <typename T, typename It, std::enable_if_t<refletable_v<T>, int>>
Expand Down Expand Up @@ -608,6 +644,31 @@ IGUANA_INLINE void from_json(T &value, const View &view) {
from_json(value, std::begin(view), std::end(view));
}

template <
auto member,
typename Parant = typename member_tratis<decltype(member)>::owner_type,
typename T>
IGUANA_INLINE void from_json(T &value, std::string_view str) {
constexpr size_t duplicate_count =
iguana::duplicate_count<std::remove_reference_t<Parant>, member>();
static_assert(duplicate_count != 1, "the member is not belong to the object");
static_assert(duplicate_count == 2, "has duplicate field name");

constexpr auto name = name_of<member>();
constexpr size_t index = index_of<member>();
constexpr size_t member_count = member_count_of<member>();
str = str.substr(str.find(name) + name.size());
size_t pos = str.find(":") + 1;
if constexpr (index == member_count - 1) { // last field
str = str.substr(pos, str.find("}") - pos + 1);
}
else {
str = str.substr(pos, str.find(",") - pos);
}

detail::from_json_impl(value.*member, std::begin(str), std::end(str));
}

template <typename T, typename View,
std::enable_if_t<json_view_v<View>, int> = 0>
IGUANA_INLINE void from_json(T &value, const View &view,
Expand Down
29 changes: 25 additions & 4 deletions include/ylt/standalone/iguana/json_util.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@ class numeric_str {
if (val_.empty())
IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); }
T res;
auto [_, ec] =
detail::from_chars(val_.data(), val_.data() + val_.size(), res);
if (ec != std::errc{})
IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); }
detail::from_chars(val_.data(), val_.data() + val_.size(), res);
return res;
}

Expand Down Expand Up @@ -214,4 +211,28 @@ IGUANA_INLINE bool is_numeric(char c) noexcept {
return static_cast<bool>(is_num[static_cast<unsigned int>(c)]);
}

// '\t' '\r' '\n' '"' '}' ']' ',' ' ' '\0'
IGUANA_INLINE bool can_follow_number(char c) noexcept {
static constexpr int can_follow_num[256] = {
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // 0
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // 2
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, // 5
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, // 7
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F
};
return static_cast<bool>(can_follow_num[static_cast<unsigned int>(c)]);
}

} // namespace iguana
2 changes: 2 additions & 0 deletions include/ylt/standalone/iguana/json_writer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ IGUANA_INLINE void to_json_impl(Stream &s, T &&t) {
template <bool Is_writing_escape, typename Stream, typename T,
std::enable_if_t<variant_v<T>, int>>
IGUANA_INLINE void to_json_impl(Stream &s, T &&t) {
static_assert(!has_duplicate_type_v<std::remove_reference_t<T>>,
"don't allow same type in std::variant");
std::visit(
[&s](auto value) {
to_json_impl<Is_writing_escape>(s, value);
Expand Down
114 changes: 114 additions & 0 deletions include/ylt/standalone/iguana/reflection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,120 @@ constexpr const std::string_view get_name() {
return M::name();
}

namespace detail {
template <typename T, typename U>
constexpr bool get_index_imple(T ptr, U ele) {
if constexpr (std::is_same_v<decltype(ptr), decltype(ele)>) {
if (ele == ptr) {
return true;
}
else {
return false;
}
}
else {
return false;
}
}

template <typename T, typename Tuple, size_t... I>
constexpr size_t member_index_impl(T ptr, Tuple &tp,
std::index_sequence<I...>) {
bool r = false;
size_t index = 0;
((void)(!r && (r = get_index_imple(ptr, std::get<I>(tp)),
!r ? index++ : index, true)),
...);
return index;
}

template <typename T, typename Tuple>
constexpr size_t member_index(T ptr, Tuple &tp) {
return member_index_impl(
ptr, tp,
std::make_index_sequence<
std::tuple_size_v<std::decay_t<decltype(tp)>>>{});
}
} // namespace detail

template <auto member>
constexpr size_t index_of() {
using namespace detail;
using T = typename member_tratis<decltype(member)>::owner_type;
using M = Reflect_members<T>;
constexpr auto tp = M::apply_impl();
constexpr size_t Size = std::tuple_size_v<decltype(tp)>;
constexpr size_t index = member_index(member, tp);
static_assert(index < Size, "out of range");
return index;
}

template <auto... members>
constexpr std::array<size_t, sizeof...(members)> indexs_of() {
return std::array<size_t, sizeof...(members)>{index_of<members>()...};
}

template <auto member>
constexpr auto name_of() {
using T = typename member_tratis<decltype(member)>::owner_type;
using M = Reflect_members<T>;
constexpr auto s = M::arr()[index_of<member>()];
return std::string_view(s.data(), s.size());
}

template <auto... members>
constexpr std::array<std::string_view, sizeof...(members)> names_of() {
return std::array<std::string_view, sizeof...(members)>{
name_of<members>()...};
}

template <auto member>
constexpr auto member_count_of() {
using T = typename member_tratis<decltype(member)>::owner_type;
using M = Reflect_members<T>;
return M::value();
}

template <typename T, auto member>
constexpr size_t duplicate_count();

template <auto ptr, typename Member>
constexpr void check_duplicate(Member member, size_t &index) {
using value_type = typename member_tratis<decltype(member)>::value_type;

if (detail::get_index_imple(ptr, member)) {
index++;
}

if constexpr (is_reflection_v<value_type>) {
index += iguana::duplicate_count<value_type, ptr>();
}
}

template <typename T, auto member>
constexpr size_t duplicate_count() {
using M = Reflect_members<T>;
constexpr auto name = name_of<member>();
constexpr auto arr = M::arr();

constexpr auto tp = M::apply_impl();
size_t index = 0;
std::apply(
[&](auto... ele) {
(check_duplicate<member>(ele, index), ...);
},
tp);

for (auto &s : arr) {
if (s == name) {
index++;
break;
}
}

return index;
}

template <typename T>
constexpr const std::string_view get_fields() {
using M = Reflect_members<T>;
Expand Down
Loading
Loading