Skip to content

Commit 6e684c0

Browse files
authored
fix and update (#677)
1 parent 9968b5b commit 6e684c0

File tree

12 files changed

+668
-127
lines changed

12 files changed

+668
-127
lines changed

include/ylt/standalone/iguana/detail/charconv.h

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,48 @@
33

44
#include "dragonbox_to_chars.h"
55
#include "fast_float.h"
6+
#include "iguana/define.h"
67
#include "itoa.hpp"
78

89
namespace iguana {
910
template <typename T>
1011
struct is_char_type
11-
: std::disjunction<std::is_same<T, char>, std::is_same<T, unsigned char>,
12-
std::is_same<T, signed char>, std::is_same<T, wchar_t>,
12+
: std::disjunction<std::is_same<T, char>, std::is_same<T, wchar_t>,
1313
std::is_same<T, char16_t>, std::is_same<T, char32_t>> {};
1414

15+
inline void *to_chars_float(...) {
16+
throw std::runtime_error("not allowed to invoke");
17+
return {};
18+
}
19+
20+
template <typename T, typename Ret = decltype(to_chars_float(
21+
std::declval<T>(), std::declval<char *>()))>
22+
using return_of_tochars = std::conditional_t<std::is_same_v<Ret, char *>,
23+
std::true_type, std::false_type>;
24+
// here std::true_type is used as a type , any other type is also ok.
25+
using has_to_chars_float = iguana::return_of_tochars<std::true_type>;
26+
1527
namespace detail {
16-
template <typename U>
28+
29+
// check_number==true: check if the string [first, last) is a legal number
30+
template <bool check_number = true, typename U>
1731
std::pair<const char *, std::errc> from_chars(const char *first,
18-
const char *last,
19-
U &value) noexcept {
32+
const char *last, U &value) {
2033
using T = std::decay_t<U>;
2134
if constexpr (std::is_floating_point_v<T>) {
2235
auto [p, ec] = fast_float::from_chars(first, last, value);
36+
if constexpr (check_number) {
37+
if (p != last || ec != std::errc{})
38+
IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); }
39+
}
2340
return {p, ec};
2441
}
2542
else {
2643
auto [p, ec] = std::from_chars(first, last, value);
44+
if constexpr (check_number) {
45+
if (p != last || ec != std::errc{})
46+
IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); }
47+
}
2748
return {p, ec};
2849
}
2950
}
@@ -33,17 +54,26 @@ template <typename T>
3354
char *to_chars(char *buffer, T value) noexcept {
3455
using U = std::decay_t<T>;
3556
if constexpr (std::is_floating_point_v<U>) {
36-
return jkj::dragonbox::to_chars(value, buffer);
57+
if constexpr (has_to_chars_float::value) {
58+
return static_cast<char *>(to_chars_float(value, buffer));
59+
}
60+
else {
61+
return jkj::dragonbox::to_chars(value, buffer);
62+
}
3763
}
3864
else if constexpr (std::is_signed_v<U> && (sizeof(U) >= 8)) {
3965
return xtoa(value, buffer, 10, 1); // int64_t
4066
}
4167
else if constexpr (std::is_unsigned_v<U> && (sizeof(U) >= 8)) {
4268
return xtoa(value, buffer, 10, 0); // uint64_t
4369
}
44-
else if constexpr (std::is_integral_v<U> && !is_char_type<U>::value) {
70+
else if constexpr (std::is_integral_v<U> && (sizeof(U) > 1)) {
4571
return itoa_fwd(value, buffer); // only support more than 2 bytes intergal
4672
}
73+
else if constexpr (!is_char_type<U>::value) {
74+
return itoa_fwd(static_cast<int>(value),
75+
buffer); // only support more than 2 bytes intergal
76+
}
4777
else {
4878
static_assert(!sizeof(U), "only support arithmetic type except char type");
4979
}

include/ylt/standalone/iguana/detail/traits.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ template <typename T, typename... Us>
6767
struct has_type<T, std::tuple<Us...>>
6868
: std::disjunction<std::is_same<T, Us>...> {};
6969

70+
template <class T>
71+
struct member_tratis {};
72+
73+
template <class T, class Owner>
74+
struct member_tratis<T Owner::*> {
75+
using owner_type = Owner;
76+
using value_type = T;
77+
};
78+
7079
template <typename T>
7180
inline constexpr bool is_int64_v =
7281
std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t>;

include/ylt/standalone/iguana/json_reader.hpp

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) {
6868
if (size == 0)
6969
IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); }
7070
const auto start = &*it;
71-
auto [p, ec] = detail::from_chars(start, start + size, value);
72-
if (ec != std::errc{})
71+
auto [p, ec] = detail::from_chars<false>(start, start + size, value);
72+
if (ec != std::errc{} || !can_follow_number(*p))
7373
IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); }
7474
it += (p - &*it);
7575
}
@@ -82,9 +82,7 @@ IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) {
8282
buffer[i] = *it++;
8383
++i;
8484
}
85-
auto [p, ec] = detail::from_chars(buffer, buffer + i, value);
86-
if (ec != std::errc{})
87-
IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); }
85+
detail::from_chars(buffer, buffer + i, value);
8886
}
8987
}
9088

@@ -499,6 +497,44 @@ IGUANA_INLINE void skip_object_value(It &&it, It &&end) {
499497
}
500498
}
501499

500+
template <typename value_type, typename U, typename It>
501+
IGUANA_INLINE bool from_json_variant_impl(U &value, It it, It end, It &temp_it,
502+
It &temp_end) {
503+
try {
504+
value_type val;
505+
from_json_impl(val, it, end);
506+
value = val;
507+
temp_it = it;
508+
temp_end = end;
509+
return true;
510+
} catch (std::exception &ex) {
511+
return false;
512+
}
513+
}
514+
515+
template <typename U, typename It, size_t... Idx>
516+
IGUANA_INLINE void from_json_variant(U &value, It &it, It &end,
517+
std::index_sequence<Idx...>) {
518+
static_assert(!has_duplicate_type_v<std::remove_reference_t<U>>,
519+
"don't allow same type in std::variant");
520+
bool r = false;
521+
It temp_it = it;
522+
It temp_end = end;
523+
((void)(!r && (r = from_json_variant_impl<
524+
variant_element_t<Idx, std::remove_reference_t<U>>>(
525+
value, it, end, temp_it, temp_end),
526+
true)),
527+
...);
528+
it = temp_it;
529+
end = temp_end;
530+
}
531+
532+
template <typename U, typename It, std::enable_if_t<variant_v<U>, int> = 0>
533+
IGUANA_INLINE void from_json_impl(U &value, It &&it, It &&end) {
534+
from_json_variant(value, it, end,
535+
std::make_index_sequence<
536+
std::variant_size_v<std::remove_reference_t<U>>>{});
537+
}
502538
} // namespace detail
503539

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

647+
template <
648+
auto member,
649+
typename Parant = typename member_tratis<decltype(member)>::owner_type,
650+
typename T>
651+
IGUANA_INLINE void from_json(T &value, std::string_view str) {
652+
constexpr size_t duplicate_count =
653+
iguana::duplicate_count<std::remove_reference_t<Parant>, member>();
654+
static_assert(duplicate_count != 1, "the member is not belong to the object");
655+
static_assert(duplicate_count == 2, "has duplicate field name");
656+
657+
constexpr auto name = name_of<member>();
658+
constexpr size_t index = index_of<member>();
659+
constexpr size_t member_count = member_count_of<member>();
660+
str = str.substr(str.find(name) + name.size());
661+
size_t pos = str.find(":") + 1;
662+
if constexpr (index == member_count - 1) { // last field
663+
str = str.substr(pos, str.find("}") - pos + 1);
664+
}
665+
else {
666+
str = str.substr(pos, str.find(",") - pos);
667+
}
668+
669+
detail::from_json_impl(value.*member, std::begin(str), std::end(str));
670+
}
671+
611672
template <typename T, typename View,
612673
std::enable_if_t<json_view_v<View>, int> = 0>
613674
IGUANA_INLINE void from_json(T &value, const View &view,

include/ylt/standalone/iguana/json_util.hpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,7 @@ class numeric_str {
1818
if (val_.empty())
1919
IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); }
2020
T res;
21-
auto [_, ec] =
22-
detail::from_chars(val_.data(), val_.data() + val_.size(), res);
23-
if (ec != std::errc{})
24-
IGUANA_UNLIKELY { throw std::runtime_error("Failed to parse number"); }
21+
detail::from_chars(val_.data(), val_.data() + val_.size(), res);
2522
return res;
2623
}
2724

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

214+
// '\t' '\r' '\n' '"' '}' ']' ',' ' ' '\0'
215+
IGUANA_INLINE bool can_follow_number(char c) noexcept {
216+
static constexpr int can_follow_num[256] = {
217+
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
218+
1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, // 0
219+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
220+
1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, // 2
221+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3
222+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
223+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, // 5
224+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
225+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, // 7
226+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
227+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
228+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
229+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
230+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
231+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
232+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
233+
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // F
234+
};
235+
return static_cast<bool>(can_follow_num[static_cast<unsigned int>(c)]);
236+
}
237+
217238
} // namespace iguana

include/ylt/standalone/iguana/json_writer.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,8 @@ IGUANA_INLINE void to_json_impl(Stream &s, T &&t) {
245245
template <bool Is_writing_escape, typename Stream, typename T,
246246
std::enable_if_t<variant_v<T>, int>>
247247
IGUANA_INLINE void to_json_impl(Stream &s, T &&t) {
248+
static_assert(!has_duplicate_type_v<std::remove_reference_t<T>>,
249+
"don't allow same type in std::variant");
248250
std::visit(
249251
[&s](auto value) {
250252
to_json_impl<Is_writing_escape>(s, value);

include/ylt/standalone/iguana/reflection.hpp

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -910,6 +910,120 @@ constexpr const std::string_view get_name() {
910910
return M::name();
911911
}
912912

913+
namespace detail {
914+
template <typename T, typename U>
915+
constexpr bool get_index_imple(T ptr, U ele) {
916+
if constexpr (std::is_same_v<decltype(ptr), decltype(ele)>) {
917+
if (ele == ptr) {
918+
return true;
919+
}
920+
else {
921+
return false;
922+
}
923+
}
924+
else {
925+
return false;
926+
}
927+
}
928+
929+
template <typename T, typename Tuple, size_t... I>
930+
constexpr size_t member_index_impl(T ptr, Tuple &tp,
931+
std::index_sequence<I...>) {
932+
bool r = false;
933+
size_t index = 0;
934+
((void)(!r && (r = get_index_imple(ptr, std::get<I>(tp)),
935+
!r ? index++ : index, true)),
936+
...);
937+
return index;
938+
}
939+
940+
template <typename T, typename Tuple>
941+
constexpr size_t member_index(T ptr, Tuple &tp) {
942+
return member_index_impl(
943+
ptr, tp,
944+
std::make_index_sequence<
945+
std::tuple_size_v<std::decay_t<decltype(tp)>>>{});
946+
}
947+
} // namespace detail
948+
949+
template <auto member>
950+
constexpr size_t index_of() {
951+
using namespace detail;
952+
using T = typename member_tratis<decltype(member)>::owner_type;
953+
using M = Reflect_members<T>;
954+
constexpr auto tp = M::apply_impl();
955+
constexpr size_t Size = std::tuple_size_v<decltype(tp)>;
956+
constexpr size_t index = member_index(member, tp);
957+
static_assert(index < Size, "out of range");
958+
return index;
959+
}
960+
961+
template <auto... members>
962+
constexpr std::array<size_t, sizeof...(members)> indexs_of() {
963+
return std::array<size_t, sizeof...(members)>{index_of<members>()...};
964+
}
965+
966+
template <auto member>
967+
constexpr auto name_of() {
968+
using T = typename member_tratis<decltype(member)>::owner_type;
969+
using M = Reflect_members<T>;
970+
constexpr auto s = M::arr()[index_of<member>()];
971+
return std::string_view(s.data(), s.size());
972+
}
973+
974+
template <auto... members>
975+
constexpr std::array<std::string_view, sizeof...(members)> names_of() {
976+
return std::array<std::string_view, sizeof...(members)>{
977+
name_of<members>()...};
978+
}
979+
980+
template <auto member>
981+
constexpr auto member_count_of() {
982+
using T = typename member_tratis<decltype(member)>::owner_type;
983+
using M = Reflect_members<T>;
984+
return M::value();
985+
}
986+
987+
template <typename T, auto member>
988+
constexpr size_t duplicate_count();
989+
990+
template <auto ptr, typename Member>
991+
constexpr void check_duplicate(Member member, size_t &index) {
992+
using value_type = typename member_tratis<decltype(member)>::value_type;
993+
994+
if (detail::get_index_imple(ptr, member)) {
995+
index++;
996+
}
997+
998+
if constexpr (is_reflection_v<value_type>) {
999+
index += iguana::duplicate_count<value_type, ptr>();
1000+
}
1001+
}
1002+
1003+
template <typename T, auto member>
1004+
constexpr size_t duplicate_count() {
1005+
using M = Reflect_members<T>;
1006+
constexpr auto name = name_of<member>();
1007+
constexpr auto arr = M::arr();
1008+
1009+
constexpr auto tp = M::apply_impl();
1010+
size_t index = 0;
1011+
std::apply(
1012+
[&](auto... ele) {
1013+
(check_duplicate<member>(ele, index), ...);
1014+
},
1015+
tp);
1016+
1017+
for (auto &s : arr) {
1018+
if (s == name) {
1019+
index++;
1020+
break;
1021+
}
1022+
}
1023+
1024+
return index;
1025+
}
1026+
9131027
template <typename T>
9141028
constexpr const std::string_view get_fields() {
9151029
using M = Reflect_members<T>;

0 commit comments

Comments
 (0)