Skip to content

Commit

Permalink
- json: class ordered_keys_traits
Browse files Browse the repository at this point in the history
- cxon: rebind_traits_t => replace_traits_t
- test: add cio::key::simple_traits tests
- test: fix github_events native test to produce equivalent output
  • Loading branch information
oknenavin committed Jun 30, 2024
1 parent 34d6325 commit eb78e75
Show file tree
Hide file tree
Showing 7 changed files with 311 additions and 166 deletions.
179 changes: 120 additions & 59 deletions src/cxon/lang/common/cio/class.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,36 @@ namespace cxon { namespace cio { namespace cls { // structured types reader/writ

}}}

namespace cxon { namespace cio { namespace cls { // bare object support structured types
namespace cxon { namespace cio { namespace cls { // traits

// bare-class support types
struct cxon_bare_class_tag {};
struct bare_class;
template <typename T>
struct is_bare_class;

// simple-key-class support types
struct cxon_simple_key_class_tag {};
template <typename T>
struct is_simple_key_class;
template <typename X, typename ...Fs>
constexpr bool are_simple_key_fields(Fs&&... fs);

// ordered-keys-class support types
struct cxon_ordered_keys_class_tag {};
template <typename T>
struct is_ordered_keys_class;
template <typename ...Fs>
constexpr bool are_fields_ordered(Fs&&... fs);
template <typename T> struct ordered_keys_traits : T {};

}}}

// implementation //////////////////////////////////////////////////////////////

namespace cxon { namespace cio { namespace cls {

// bare-object support types

struct bare_class {
using cxon_bare_class_tag = cls::cxon_bare_class_tag;
Expand All @@ -51,7 +78,7 @@ namespace cxon { namespace cio { namespace cls { // bare object support structur
template <typename T>
struct is_bare_class : imp::is_bare_class_<T> {};

struct cxon_simple_key_class_tag {};
// simple-key-class support types

namespace imp {
template <typename T, typename E = void_t<>>
Expand Down Expand Up @@ -81,9 +108,35 @@ namespace cxon { namespace cio { namespace cls { // bare object support structur
return imp::are_simple_key_fields_<X>(std::forward<Fs>(fs)...);
}

}}}
// ordered-keys-class support types

// implementation //////////////////////////////////////////////////////////////
namespace imp {
template <typename T, typename E = void_t<>>
struct is_ordered_keys_class_ : std::false_type {};
template <typename T>
struct is_ordered_keys_class_<T, void_t<typename T::cxon_ordered_keys_class_tag>> : std::true_type {};
}
template <typename T>
struct is_ordered_keys_class : imp::is_ordered_keys_class_<T> {};

namespace imp {
template <typename ...Fs>
constexpr bool are_fields_ordered_(Fs&&...) {
return true;
}
template <typename F, typename S, typename ...Fs>
constexpr bool are_fields_ordered_(F&& f, S&& s, Fs&&... fs) {
return std::char_traits<char>::compare(f.name, s.name, f.nale + 1) <= 0 &&
are_fields_ordered_(std::forward<S>(s), std::forward<Fs>(fs)...)
;
}
}
template <typename ...Fs>
constexpr bool are_fields_ordered(Fs&&... fs) {
return imp::are_fields_ordered_(std::forward<Fs>(fs)...) ;
}

}}}

#if __cplusplus < 202002L // use of function template name with no prior declaration in function call with explicit template arguments is a C++20 extension [-Wc++20-extensions]
namespace cxon {
Expand Down Expand Up @@ -152,61 +205,65 @@ namespace cxon { namespace cio { namespace cls {
return val::sink_read<X>(f.unit, i, e, cx);
}

template <typename X, std::size_t N, std::size_t L>
struct read_ {
template <typename T, typename Fs, typename II, typename Cx, typename Y = X>
static auto field(T& t, const char* name, const Fs& fs, int (&st)[L], II& i, II e, Cx& cx)
-> enable_if_t< Y::assume_unique_object_keys, bool>
{
return st[N] == 0 && std::char_traits<char>::compare(std::get<N>(fs).name, name, std::get<N>(fs).nale + 1) == 0 ?
(st[N] = 1, read_field_<Y>(t, std::get<N>(fs), i, e, cx)) :
read_<Y, N + 1, L>::field(t, name, fs, st, i, e, cx)
;
}
template <typename T, typename Fs, typename II, typename Cx, typename Y = X>
static auto field(T& t, const char* name, const Fs& fs, int (&st)[L], II& i, II e, Cx& cx)
-> enable_if_t<!Y::assume_unique_object_keys, bool>
{
return std::char_traits<char>::compare(std::get<N>(fs).name, name, std::get<N>(fs).nale + 1) == 0 ?
read_field_<Y>(t, std::get<N>(fs), i, e, cx) :
read_<Y, N + 1, L>::field(t, name, fs, st, i, e, cx)
;
}
};
template <typename X, std::size_t N>
struct read_<X, N, N> {
template <typename T, typename Fs, typename II, typename Cx>
static constexpr bool field(T&, const char*, const Fs&, int (&)[N], II&, II, Cx&) noexcept {
return false;
}
};
template <typename X, std::size_t N, typename T, typename Fs, typename II, typename Cx>
inline bool read_field_(option<0>, T& t, const char* name, const Fs& fs, int (&st)[N], II& i, II e, Cx& cx) {
return read_<X, 0, N>::field(t, name, fs, st, i, e, cx);
}

template <typename X, std::size_t N, typename T, typename Fs, typename II, typename Cx> // read_field in cxon namespace
inline auto read_field_(option<1>, T& t, const char* name, const Fs& fs, int (&st)[N], II& i, II e, Cx& cx)
-> decltype(read_field<X>(name, 0, i, e, cx), bool())
{ CXON_ASSERT(!X::assume_unique_object_keys, "not supported");
return read_field<X>(name, std::char_traits<char>::length(name), i, e, cx);
}
template <typename X, std::size_t N, typename T, typename Fs, typename II, typename Cx> // read_field static method of T
inline auto read_field_(option<2>, T& t, const char* name, const Fs& fs, int (&st)[N], II& i, II e, Cx& cx)
-> decltype(T::template read_field<X>(t, name, 0, i, e, cx), bool())
{ CXON_ASSERT(!X::assume_unique_object_keys, "not supported");
return T::template read_field<X>(t, name, std::char_traits<char>::length(name), i, e, cx);
}
template <typename X, std::size_t N, typename T, typename Fs, typename II, typename Cx> // read_field method of T
inline auto read_field_(option<3>, T& t, const char* name, const Fs& fs, int (&st)[N], II& i, II e, Cx& cx)
-> decltype(t.template read_field<X>(name, 0, i, e, cx), bool())
{ CXON_ASSERT(!X::assume_unique_object_keys, "not supported");
return t.template read_field<X>(name, std::char_traits<char>::length(name), i, e, cx);
namespace imp {
namespace imp {
template <typename X, std::size_t N, std::size_t L>
struct read_ {
template <typename T, typename Fs, typename II, typename Cx, typename Y = X>
static auto field(T& t, const char* name, const Fs& fs, int (&st)[L], II& i, II e, Cx& cx)
-> enable_if_t< Y::assume_unique_object_keys, bool>
{
return st[N] == 0 && std::char_traits<char>::compare(std::get<N>(fs).name, name, std::get<N>(fs).nale + 1) == 0 ?
(st[N] = 1, read_field_<Y>(t, std::get<N>(fs), i, e, cx)) :
read_<Y, N + 1, L>::field(t, name, fs, st, i, e, cx)
;
}
template <typename T, typename Fs, typename II, typename Cx, typename Y = X>
static auto field(T& t, const char* name, const Fs& fs, int (&st)[L], II& i, II e, Cx& cx)
-> enable_if_t<!Y::assume_unique_object_keys, bool>
{
return std::char_traits<char>::compare(std::get<N>(fs).name, name, std::get<N>(fs).nale + 1) == 0 ?
read_field_<Y>(t, std::get<N>(fs), i, e, cx) :
read_<Y, N + 1, L>::field(t, name, fs, st, i, e, cx)
;
}
};
template <typename X, std::size_t N>
struct read_<X, N, N> {
template <typename T, typename Fs, typename II, typename Cx>
static constexpr bool field(T&, const char*, const Fs&, int (&)[N], II&, II, Cx&) noexcept {
return false;
}
};
}
template <typename X, typename T, typename Fs, typename II, typename Cx, std::size_t N>
inline bool read_field_(option<0>, T& t, const char* name, const Fs& fs, int (&st)[N], II& i, II e, Cx& cx) {
return imp::read_<X, 0, N>::field(t, name, fs, st, i, e, cx);
}

template <typename X, typename T, typename II, typename Cx>
inline constexpr bool read_fields_(T&, const fields<>&, II& i, II e, Cx& cx) {
return consume<X>(X::map::beg, i, e, cx) && consume<X>(X::map::end, i, e, cx);
template <typename X, typename T, typename Fs, typename II, typename Cx, std::size_t N> // read_field in cxon namespace
inline auto read_field_(option<1>, T& t, const char* name, const Fs& fs, int (&st)[N], II& i, II e, Cx& cx)
-> decltype(read_field<X>(name, 0, i, e, cx), bool())
{ CXON_ASSERT(!X::assume_unique_object_keys, "not supported");
return read_field<X>(name, std::char_traits<char>::length(name), i, e, cx);
}
template <typename X, typename T, typename Fs, typename II, typename Cx, std::size_t N> // read_field static method of T
inline auto read_field_(option<2>, T& t, const char* name, const Fs& fs, int (&st)[N], II& i, II e, Cx& cx)
-> decltype(T::template read_field<X>(t, name, 0, i, e, cx), bool())
{ CXON_ASSERT(!X::assume_unique_object_keys, "not supported");
return T::template read_field<X>(t, name, std::char_traits<char>::length(name), i, e, cx);
}
template <typename X, typename T, typename Fs, typename II, typename Cx, std::size_t N> // read_field method of T
inline auto read_field_(option<3>, T& t, const char* name, const Fs& fs, int (&st)[N], II& i, II e, Cx& cx)
-> decltype(t.template read_field<X>(name, 0, i, e, cx), bool())
{ CXON_ASSERT(!X::assume_unique_object_keys, "not supported");
return t.template read_field<X>(name, std::char_traits<char>::length(name), i, e, cx);
}
}
template <typename X, typename T, typename Fs, typename II, typename Cx, std::size_t N>
inline bool read_field_(T& t, const char* name, const Fs& fs, int (&st)[N], II& i, II e, Cx& cx) {
using Y = unbind_traits_t<X, cio::key::simple_traits>;
return imp::read_field_<Y>(option<3>(), t, name, fs, st, i, e, cx);
}

template <typename X, typename T, typename ...Fs, typename II, typename Cx>
Expand All @@ -226,7 +283,7 @@ namespace cxon { namespace cio { namespace cls {
II const o = i;
if (!read_map_key<X>(id, i, e, cx))
return rewind(i, o), false;
if (!read_field_<X>(option<3>(), t, id, fs, st, i, e, cx))
if (!read_field_<X>(t, id, fs, st, i, e, cx))
return cx && (rewind(i, o), cx/X::read_error::unexpected);
if (cnt::consume_sep<X, typename X::map>(i, e, cx))
continue;
Expand All @@ -247,13 +304,17 @@ namespace cxon { namespace cio { namespace cls {
II const o = i;
if (!read_map_key<X>(id, i, e, cx))
return false;
if (!read_field_<X>(option<3>(), t, id, fs, st, i, e, cx))
if (!read_field_<X>(t, id, fs, st, i, e, cx))
return cx && (rewind(i, o), cx/X::read_error::unexpected);
if (!consume<X>(i, e, cx))
return false;
}
return true;
}
template <typename X, typename T, typename II, typename Cx>
inline constexpr bool read_fields_(T&, const fields<>&, II& i, II e, Cx& cx) {
return consume<X>(X::map::beg, i, e, cx) && consume<X>(X::map::end, i, e, cx);
}

}

Expand Down
5 changes: 2 additions & 3 deletions src/cxon/lang/common/cio/key.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ namespace cxon { namespace cio { namespace key { // key read/write extension poi
inline bool write_key(O& o, const T& t, Cx& cx);

template <typename T> struct simple_traits : T {};
template <typename T> using is_simple_key_context = has_traits<T, simple_traits>;

}}}

Expand All @@ -66,7 +65,7 @@ namespace cxon { namespace cio {
-> enable_if_t<is_char<T>::value, bool>
{
using Y = conditional_t<X::unquote_quoted_keys, quoted_key_context<X>, X>;
using Z = conditional_t<key::is_simple_key_context<Y>::value, rebind_traits_t<Y, key::simple_traits, str::raw_traits>, Y>;
using Z = replace_traits_t<Y, key::simple_traits, str::raw_traits>;
return str::pointer_write<Z>(o, t, s, cx) && poke<Z>(o, Z::map::div, cx);
}

Expand Down Expand Up @@ -103,7 +102,7 @@ namespace cxon { namespace cio { namespace key {
template <typename X, typename T, typename II, typename Cx>
inline auto read_key_(T& t, II& i, II e, Cx& cx) -> enable_if_t<!needs_quotes<X, T>::value, bool> {
using Y = conditional_t<X::unquote_quoted_keys, quoted_key_context<X>, X>;
using Z = conditional_t<!is_unquoted_key_context<Y>::value && key::is_simple_key_context<Y>::value, rebind_traits_t<Y, key::simple_traits, str::raw_traits>, Y>;
using Z = conditional_t<!is_unquoted_key_context<Y>::value, replace_traits_t<Y, key::simple_traits, str::raw_traits>, Y>;
return read_value<Z>(t, i, e, cx);
}

Expand Down
42 changes: 29 additions & 13 deletions src/cxon/lang/json/class.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ namespace cxon { // cio::val::sink read

#define CXON_JSON_CLS_SIMPLE_KEY(T)\
namespace cxon { namespace cio { namespace cls { \
template <> struct is_simple_key_class<T> : std::true_type {};\
template <> struct is_simple_key_class<T> : std::true_type {}; \
}}}

#define CXON_JSON_CLS_READ(Type, ...)\
Expand All @@ -66,10 +66,18 @@ namespace cxon { // cio::val::sink read
using CXON_T_ = Type; \
static CXON_CXX17_CONSTEXPR auto fs = json::cls::make_fields(__VA_ARGS__); \
CXON_IF_CONSTEXPR (cio::cls::is_simple_key_class<Type>::value || cio::cls::are_simple_key_fields<X>(__VA_ARGS__)) { \
using Y = bind_traits_t<X, cio::key::simple_traits>; \
using Y = bind_traits_t<X, cio::key::simple_traits>; \
CXON_IF_CONSTEXPR (cio::cls::is_ordered_keys_class<Type>::value || cio::cls::are_fields_ordered(__VA_ARGS__)) { \
using Y = bind_traits_t<Y, cio::cls::ordered_keys_traits>; \
return json::cls::read_fields<Y>(t, fs, i, e, cx); \
} \
return json::cls::read_fields<Y>(t, fs, i, e, cx); \
} \
else return json::cls::read_fields<X>(t, fs, i, e, cx); \
CXON_IF_CONSTEXPR (cio::cls::is_ordered_keys_class<Type>::value || cio::cls::are_fields_ordered(__VA_ARGS__)) { \
using Y = bind_traits_t<X, cio::cls::ordered_keys_traits>; \
return json::cls::read_fields<Y>(t, fs, i, e, cx); \
} \
return json::cls::read_fields<X>(t, fs, i, e, cx); \
} \
}
#define CXON_JSON_CLS_WRITE(Type, ...)\
Expand All @@ -79,14 +87,14 @@ namespace cxon { // cio::val::sink read
using CXON_T_ = Type; \
static CXON_CXX17_CONSTEXPR auto fs = json::cls::make_fields(__VA_ARGS__); \
CXON_IF_CONSTEXPR (cio::cls::is_simple_key_class<Type>::value || cio::cls::are_simple_key_fields<X>(__VA_ARGS__)) { \
using Y = bind_traits_t<X, cio::key::simple_traits>; \
return json::cls::write_fields<Y>(o, t, fs, cx); \
using Y = bind_traits_t<X, cio::key::simple_traits>; \
return json::cls::write_fields<Y>(o, t, fs, cx); \
} \
else return json::cls::write_fields<X>(o, t, fs, cx); \
return json::cls::write_fields<X>(o, t, fs, cx); \
} \
}
#define CXON_JSON_CLS(Type, ...)\
CXON_JSON_CLS_READ(Type, __VA_ARGS__)\
CXON_JSON_CLS_READ(Type, __VA_ARGS__) \
CXON_JSON_CLS_WRITE(Type, __VA_ARGS__)

#define CXON_JSON_CLS_SIMPLE_KEY_MEMBER()\
Expand All @@ -98,24 +106,32 @@ namespace cxon { // cio::val::sink read
using CXON_T_ = Type; ((void)((CXON_T_*)0)); \
static CXON_CXX17_CONSTEXPR auto fs = cxon::json::cls::make_fields(__VA_ARGS__); \
CXON_IF_CONSTEXPR (cxon::cio::cls::is_simple_key_class<Type>::value || cxon::cio::cls::are_simple_key_fields<X>(__VA_ARGS__)) { \
using Y = cxon::bind_traits_t<X, cxon::cio::key::simple_traits>; \
using Y = cxon::bind_traits_t<X, cxon::cio::key::simple_traits>; \
CXON_IF_CONSTEXPR (cxon::cio::cls::is_ordered_keys_class<Type>::value || cxon::cio::cls::are_fields_ordered(__VA_ARGS__)) { \
using Y = cxon::bind_traits_t<Y, cxon::cio::cls::ordered_keys_traits>; \
return cxon::json::cls::read_fields<Y>(t, fs, i, e, cx); \
} \
return cxon::json::cls::read_fields<Y>(t, fs, i, e, cx); \
} \
CXON_IF_CONSTEXPR (cxon::cio::cls::is_ordered_keys_class<Type>::value || cxon::cio::cls::are_fields_ordered(__VA_ARGS__)) { \
using Y = cxon::bind_traits_t<X, cxon::cio::cls::ordered_keys_traits>; \
return cxon::json::cls::read_fields<Y>(t, fs, i, e, cx); \
} \
else return cxon::json::cls::read_fields<X>(t, fs, i, e, cx); \
return cxon::json::cls::read_fields<X>(t, fs, i, e, cx); \
}
#define CXON_JSON_CLS_WRITE_MEMBER(Type, ...)\
template <typename X, typename O, typename Cx> \
static auto write_value(O& o, const Type& t, Cx& cx) -> cxon::enable_for_t<X, cxon::JSON> { \
using CXON_T_ = Type; ((void)((CXON_T_*)0)); \
static CXON_CXX17_CONSTEXPR auto fs = cxon::json::cls::make_fields(__VA_ARGS__); \
CXON_IF_CONSTEXPR (cxon::cio::cls::is_simple_key_class<Type>::value || cxon::cio::cls::are_simple_key_fields<X>(__VA_ARGS__)) { \
using Y = cxon::bind_traits_t<X, cxon::cio::key::simple_traits>; \
return cxon::json::cls::write_fields<Y>(o, t, fs, cx); \
using Y = cxon::bind_traits_t<X, cxon::cio::key::simple_traits>; \
return cxon::json::cls::write_fields<Y>(o, t, fs, cx); \
} \
else return cxon::json::cls::write_fields<X>(o, t, fs, cx); \
return cxon::json::cls::write_fields<X>(o, t, fs, cx); \
}
#define CXON_JSON_CLS_MEMBER(Type, ...)\
CXON_JSON_CLS_READ_MEMBER(Type, __VA_ARGS__)\
CXON_JSON_CLS_READ_MEMBER(Type, __VA_ARGS__) \
CXON_JSON_CLS_WRITE_MEMBER(Type, __VA_ARGS__)

#endif // CXON_JSON_CLASS_HXX_
Loading

0 comments on commit eb78e75

Please sign in to comment.