Skip to content

Commit

Permalink
fix and update (#677)
Browse files Browse the repository at this point in the history
  • Loading branch information
qicosmos authored May 15, 2024
1 parent 9968b5b commit 6e684c0
Show file tree
Hide file tree
Showing 12 changed files with 668 additions and 127 deletions.
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

0 comments on commit 6e684c0

Please sign in to comment.