diff --git a/include/ircd/json.h b/include/ircd/json.h index 2f4f0e6c5..731810a39 100644 --- a/include/ircd/json.h +++ b/include/ircd/json.h @@ -91,7 +91,7 @@ std::ostream &operator<<(std::ostream &, const path &); #include "json/object.h" #include "json/value.h" #include "json/index.h" -#include "json/parse.h" +#include "json/tuple.h" namespace ircd { diff --git a/include/ircd/json/parse.h b/include/ircd/json/tuple.h similarity index 62% rename from include/ircd/json/parse.h rename to include/ircd/json/tuple.h index 3bad555ea..136a7f6f1 100644 --- a/include/ircd/json/parse.h +++ b/include/ircd/json/tuple.h @@ -20,7 +20,85 @@ */ #pragma once -#define HAVE_IRCD_JSON_PARSE_H +#define HAVE_IRCD_JSON_TUPLE_H + +namespace ircd { +namespace json { + +struct tuple_base +{ + // class must be empty for EBO +}; + +template +struct tuple +:tuple_base +,std::tuple +{ + using tuple_type = std::tuple; + + static constexpr size_t size() + { + return std::tuple_size(); + } + + using std::tuple::tuple; +}; + +template +using tuple_type = typename tuple::tuple_type; + +template +using tuple_size = std::tuple_size>; + +template +using tuple_element = typename std::tuple_element>::type; + +template +constexpr auto & +stdcast(const tuple &o) +{ + return static_cast(o); +} + +template +constexpr auto & +stdcast(tuple &o) +{ + return static_cast(o); +} + +template +constexpr auto +size(const tuple &t) +{ + return t.size(); +} + +template +constexpr auto & +get(const tuple &t) +{ + return std::get(t); +} + +template +constexpr auto & +get(tuple &t) +{ + return std::get(t); +} + +template +constexpr const char * +reflect(const tuple &t) +{ + return t._member_(i); +} #define IRCD_MEMBERS(_vals_...) \ static constexpr const char *_member_(const size_t i) \ @@ -33,233 +111,129 @@ static constexpr const char *_member_(const size_t i) \ return val[i]; \ } -namespace ircd { -namespace json { - -struct basic_parse -{ -}; - -template -struct parse -:basic_parse -,std::tuple -{ - using tuple_type = std::tuple; - - static constexpr size_t size() - { - return std::tuple_size(); - } - - parse() = default; - template parse(R &r, const json::object &obj); -}; - -template -template -parse::parse(R &r, - const json::object &object) -{ - std::for_each(std::begin(object), std::end(object), [this, &r] - (auto &&member) - { - at(r, member.first, [&member] - (auto&& target) - { - using target_type = decltype(target); - using cast_type = typename std::remove_reference::type; try - { - target = lex_cast(member.second); - } - catch(const bad_lex_cast &e) - { - throw parse_error("member \"%s\" must convert to '%s'", - member.first, - typeid(target_type).name()); - } - }); - }); -} - -template -using tuple_type = typename parse::tuple_type; - -template -using tuple_size = std::tuple_size>; - template -using tuple_element = typename std::tuple_element>::type; - -template -constexpr auto & -tuple(const parse &o) -{ - return static_cast(o); -} - -template -constexpr auto & -tuple(parse &o) -{ - return static_cast(o); -} - -template -constexpr auto -size(const parse &t) -{ - return t.size(); -} - -template -constexpr auto & -get(const parse &t) -{ - return std::get(t); -} - -template -constexpr auto & -get(parse &t) -{ - return std::get(t); -} - -template -constexpr const char * -reflect(const parse &t) -{ - return t._member_(i); -} - -template constexpr -typename std::enable_if::value, void>::type -for_each(const parse &t, +typename std::enable_if::value, void>::type +for_each(const tuple &t, function&& f) {} template constexpr -typename std::enable_if::value, void>::type -for_each(parse &t, +typename std::enable_if::value, void>::type +for_each(tuple &t, function&& f) {} template constexpr -typename std::enable_if::value, void>::type -for_each(const parse &t, +typename std::enable_if::value, void>::type +for_each(const tuple &t, function&& f) { - using type = tuple_element; + using type = tuple_element; f(reflect(t), static_cast(get(t))); for_each(t, std::forward(f)); } template constexpr -typename std::enable_if::value, void>::type -for_each(parse &t, +typename std::enable_if::value, void>::type +for_each(tuple &t, function&& f) { - using type = tuple_element; + using type = tuple_element; f(reflect(t), static_cast(get(t))); for_each(t, std::forward(f)); } -template constexpr typename std::enable_if<(i < 0), void>::type -rfor_each(const parse &t, +rfor_each(const tuple &t, function&& f) {} -template constexpr typename std::enable_if<(i < 0), void>::type -rfor_each(parse &t, +rfor_each(tuple &t, function&& f) {} -template() - 1> + ssize_t i = tuple_size() - 1> constexpr -typename std::enable_if(), void>::type -rfor_each(const parse &t, +typename std::enable_if(), void>::type +rfor_each(const tuple &t, function&& f) { - using type = tuple_element; + using type = tuple_element; f(reflect(t), static_cast(get(t))); - rfor_each(t, std::forward(f)); + rfor_each(t, std::forward(f)); } -template() - 1> + ssize_t i = tuple_size() - 1> constexpr -typename std::enable_if(), void>::type -rfor_each(parse &t, +typename std::enable_if(), void>::type +rfor_each(tuple &t, function&& f) { - using type = tuple_element; + using type = tuple_element; f(reflect(t), static_cast(get(t))); - rfor_each(t, std::forward(f)); + rfor_each(t, std::forward(f)); } template constexpr -typename std::enable_if::value, bool>::type -until(const parse &t, +typename std::enable_if::value, bool>::type +until(const tuple &t, function&& f) { return true; } template constexpr -typename std::enable_if::value, bool>::type -until(parse &t, +typename std::enable_if::value, bool>::type +until(tuple &t, function&& f) { return true; } template constexpr -typename std::enable_if::value, bool>::type -until(const parse &t, +typename std::enable_if::value, bool>::type +until(const tuple &t, function&& f) { - using type = tuple_element; + using type = tuple_element; const auto &value(static_cast(get(t))); return f(reflect(t), value)? @@ -268,14 +242,14 @@ until(const parse &t, } template constexpr -typename std::enable_if::value, bool>::type -until(parse &t, +typename std::enable_if::value, bool>::type +until(tuple &t, function&& f) { - using type = tuple_element; + using type = tuple_element; auto &value(static_cast(get(t))); return f(reflect(t), value)? @@ -283,63 +257,63 @@ until(parse &t, false; } -template constexpr typename std::enable_if<(i < 0), bool>::type -runtil(const parse &t, +runtil(const tuple &t, function&& f) { return true; } -template constexpr typename std::enable_if<(i < 0), bool>::type -runtil(parse &t, +runtil(tuple &t, function&& f) { return true; } -template() - 1> + ssize_t i = tuple_size() - 1> constexpr -typename std::enable_if::value, bool>::type -runtil(const parse &t, +typename std::enable_if::value, bool>::type +runtil(const tuple &t, function&& f) { - using type = tuple_element; + using type = tuple_element; const auto &value(static_cast(get(t))); return f(reflect(t), value)? - runtil(t, std::forward(f)): + runtil(t, std::forward(f)): false; } -template() - 1> + ssize_t i = tuple_size() - 1> constexpr -typename std::enable_if::value, bool>::type -runtil(parse &t, +typename std::enable_if::value, bool>::type +runtil(tuple &t, function&& f) { - using type = tuple_element; + using type = tuple_element; auto &value(static_cast(get(t))); return f(reflect(t), value)? - runtil(t, std::forward(f)): + runtil(t, std::forward(f)): false; } -template +template constexpr size_t -indexof(parse&& t, +indexof(tuple&& t, const string_view &name) { size_t ret(0); @@ -353,13 +327,13 @@ indexof(parse&& t, return true; })); - return !res? ret : throw std::out_of_range("parse has no member with that name"); + return !res? ret : throw std::out_of_range("tuple has no member with that name"); } -template constexpr bool -at(parse&& t, +at(tuple&& t, const string_view &name, function&& f) { @@ -374,9 +348,9 @@ at(parse&& t, }); } -template +template constexpr void -keys(parse&& t, +keys(tuple&& t, const std::function &f) { for_each(t, [&f] @@ -386,10 +360,10 @@ keys(parse&& t, }); } -template constexpr void -values(parse&& t, +values(tuple&& t, function&& f) { for_each(t, [&f] @@ -399,5 +373,40 @@ values(parse&& t, }); } +template +tuple & +assign_tuple(tuple &ret, + const json::object &object) +{ + std::for_each(std::begin(object), std::end(object), [&ret](auto &&member) + { + at(ret, member.first, [&member](auto&& target) + { + using target_type = decltype(target); + using cast_type = typename std::remove_reference::type; try + { + target = lex_cast(member.second); + } + catch(const bad_lex_cast &e) + { + throw tuple_error("member \"%s\" must convert to '%s'", + member.first, + typeid(target_type).name()); + } + }); + }); + + return ret; +} + +template +tuple +make_tuple(const json::object &object) +{ + tuple ret; + assign_tuple(ret, object); + return ret; +} + } // namespace json } // namespace ircd diff --git a/include/ircd/m/event.h b/include/ircd/m/event.h index 7eb2c5dea..af57e7357 100644 --- a/include/ircd/m/event.h +++ b/include/ircd/m/event.h @@ -47,7 +47,7 @@ namespace ircd { namespace m { struct event -:json::parse +:json::tuple < string_view, time_t, @@ -68,8 +68,8 @@ struct event ) template - event(A&&... a) - :parse{*this, std::forward(a)...} + explicit event(const json::object &obj) + :tuple{json::make_tuple(obj)} {} };