diff --git a/include/ircd/json/object.h b/include/ircd/json/object.h index bf9cf73dd..3fe0bf70b 100644 --- a/include/ircd/json/object.h +++ b/include/ircd/json/object.h @@ -20,6 +20,11 @@ namespace ircd::json size_t size(const object &); template T at(const object &); template T get(const object &, const T &def = {}); + + bool sorted(const object &); + size_t serialized(const object &); + string_view stringify(mutable_buffer &, const object &); + std::ostream &operator<<(std::ostream &, const object &); } /// Lightweight interface to a JSON object string. @@ -95,45 +100,53 @@ struct ircd::json::object // returns value or empty string_view operator[](const string_view &key) const; - // constructor. Note that you are able to construct from invalid JSON. The - // parser is not invoked until other operations and that's when it errors. - using string_view::string_view; - // rewrite into allocated string copy explicit operator std::string() const; - // rewrite onto streams or buffers etc - friend bool sorted(const object &); - friend bool sorted(const member *const &, const member *const &); - friend size_t serialized(const object &); - friend size_t serialized(const member *const &, const member *const &); - friend string_view stringify(mutable_buffer &, const object &); - friend string_view stringify(mutable_buffer &, const member *const &, const member *const &); - friend std::ostream &operator<<(std::ostream &, const object &); + // constructor. Note that you are able to construct from invalid JSON. The + // parser is not invoked until other operations and that's when it errors. + using string_view::string_view; }; +namespace ircd::json +{ + bool operator==(const object::member &, const object::member &); + bool operator!=(const object::member &, const object::member &); + bool operator<=(const object::member &, const object::member &); + bool operator>=(const object::member &, const object::member &); + bool operator<(const object::member &, const object::member &); + bool operator>(const object::member &, const object::member &); + + bool sorted(const object::member *const &, const object::member *const &); + size_t serialized(const object::member *const &, const object::member *const &); + size_t serialized(const object::member &); + string_view stringify(mutable_buffer &, const object::member *const &, const object::member *const &); + string_view stringify(mutable_buffer &, const object::member &); + std::ostream &operator<<(std::ostream &, const object::member &); +} + struct ircd::json::object::member :std::pair { member(const string_view &first = {}, const string_view &second = {}) :std::pair{first, second} {} - - friend bool operator==(const object::member &, const object::member &); - friend bool operator!=(const object::member &, const object::member &); - friend bool operator<=(const object::member &, const object::member &); - friend bool operator>=(const object::member &, const object::member &); - friend bool operator<(const object::member &, const object::member &); - friend bool operator>(const object::member &, const object::member &); - - // writes a single member onto stream - friend size_t serialized(const object::member &); - friend string_view stringify(mutable_buffer &, const object::member &); - friend std::ostream &operator<<(std::ostream &, const object::member &); }; +namespace ircd::json +{ + bool operator==(const object::const_iterator &, const object::const_iterator &); + bool operator!=(const object::const_iterator &, const object::const_iterator &); + bool operator<=(const object::const_iterator &, const object::const_iterator &); + bool operator>=(const object::const_iterator &, const object::const_iterator &); + bool operator<(const object::const_iterator &, const object::const_iterator &); + bool operator>(const object::const_iterator &, const object::const_iterator &); +} + struct ircd::json::object::const_iterator { + friend class object; + using key_type = string_view; using mapped_type = string_view; using value_type = const member; @@ -144,9 +157,6 @@ struct ircd::json::object::const_iterator using key_compare = std::less; using iterator_category = std::forward_iterator_tag; - protected: - friend class object; - const char *start {nullptr}; const char *stop {nullptr}; member state; @@ -157,29 +167,21 @@ struct ircd::json::object::const_iterator {} public: - value_type *operator->() const { return &state; } - value_type &operator*() const { return *operator->(); } + value_type *operator->() const + { + return &state; + } + + value_type &operator*() const + { + return *operator->(); + } const_iterator &operator++(); const_iterator() = default; - - friend bool operator==(const const_iterator &, const const_iterator &); - friend bool operator!=(const const_iterator &, const const_iterator &); - friend bool operator<=(const const_iterator &, const const_iterator &); - friend bool operator>=(const const_iterator &, const const_iterator &); - friend bool operator<(const const_iterator &, const const_iterator &); - friend bool operator>(const const_iterator &, const const_iterator &); }; -inline ircd::string_view -ircd::json::object::operator[](const string_view &key) -const -{ - const auto it(find(key)); - return it != end()? it->second : string_view{}; -} - template T @@ -229,14 +231,6 @@ catch(const bad_lex_cast &e) }; } -inline ircd::string_view -ircd::json::object::get(const string_view &key, - const string_view &def) -const -{ - return get(key, def); -} - template ircd::string_view @@ -269,145 +263,3 @@ catch(const bad_lex_cast &e) { return def; } - -inline size_t -ircd::json::size(const object &object) -{ - return object.size(); -} - -inline size_t -ircd::json::object::size() -const -{ - return count(); -} - -inline size_t -ircd::json::object::count() -const -{ - return std::distance(begin(), end()); -} - -inline bool -ircd::json::operator!(const object &object) -{ - return empty(object); -} - -inline bool -ircd::json::empty(const object &object) -{ - return object.empty(); -} - -inline bool -ircd::json::object::empty() -const -{ - const string_view &sv{*this}; - assert(sv.size() > 2 || (sv.empty() || sv == empty_object)); - return sv.size() <= 2; -} - -inline bool -ircd::json::object::has(const string_view &key) -const -{ - return find(key) != end(); -} - -inline ircd::json::object::const_iterator -ircd::json::object::find(const name_hash_t &key) -const -{ - return std::find_if(begin(), end(), [&key] - (const auto &member) - { - return name_hash(member.first) == key; - }); -} - -inline ircd::json::object::const_iterator -ircd::json::object::find(const string_view &key) -const -{ - return std::find_if(begin(), end(), [&key] - (const auto &member) - { - return member.first == key; - }); -} - -inline bool -ircd::json::operator==(const object::const_iterator &a, const object::const_iterator &b) -{ - return a.start == b.start; -} - -inline bool -ircd::json::operator!=(const object::const_iterator &a, const object::const_iterator &b) -{ - return a.start != b.start; -} - -inline bool -ircd::json::operator<=(const object::const_iterator &a, const object::const_iterator &b) -{ - return a.start <= b.start; -} - -inline bool -ircd::json::operator>=(const object::const_iterator &a, const object::const_iterator &b) -{ - return a.start >= b.start; -} - -inline bool -ircd::json::operator<(const object::const_iterator &a, const object::const_iterator &b) -{ - return a.start < b.start; -} - -inline bool -ircd::json::operator>(const object::const_iterator &a, const object::const_iterator &b) -{ - return a.start > b.start; -} - -inline bool -ircd::json::operator==(const object::member &a, const object::member &b) -{ - return a.first == b.first; -} - -inline bool -ircd::json::operator!=(const object::member &a, const object::member &b) -{ - return a.first != b.first; -} - -inline bool -ircd::json::operator<=(const object::member &a, const object::member &b) -{ - return a.first <= b.first; -} - -inline bool -ircd::json::operator>=(const object::member &a, const object::member &b) -{ - return a.first >= b.first; -} - -inline bool -ircd::json::operator<(const object::member &a, const object::member &b) -{ - return a.first < b.first; -} - -inline bool -ircd::json::operator>(const object::member &a, const object::member &b) -{ - return a.first > b.first; -} diff --git a/ircd/json.cc b/ircd/json.cc index c4e93a49a..a47b0b322 100644 --- a/ircd/json.cc +++ b/ircd/json.cc @@ -1738,36 +1738,6 @@ ircd::json::object::max_sorted_members iov::max_size }; -std::ostream & -ircd::json::operator<<(std::ostream &s, const object::member &member) -{ - s << json::strung(member); - return s; -} - -ircd::string_view -ircd::json::stringify(mutable_buffer &buf, - const object::member &member) -{ - char *const start(begin(buf)); - printer(buf, printer.name << printer.name_sep, member.first); - stringify(buf, member.second); - const string_view ret - { - start, begin(buf) - }; - - assert(serialized(member) == size(ret)); - return ret; -} - -size_t -ircd::json::serialized(const object::member &member) -{ - const json::value key{member.first, json::STRING}; - return serialized(key) + 1 + serialized(member.second); -} - std::ostream & ircd::json::operator<<(std::ostream &s, const object &object) { @@ -1816,32 +1786,6 @@ catch(const std::out_of_range &e) }; } -ircd::string_view -ircd::json::stringify(mutable_buffer &buf, - const object::member *const &b, - const object::member *const &e) -{ - char *const start(begin(buf)); - static const auto stringify_member - { - [](mutable_buffer &buf, const object::member &member) - { - stringify(buf, member); - } - }; - - printer(buf, printer.object_begin); - printer::list_protocol(buf, b, e, stringify_member); - printer(buf, printer.object_end); - const string_view ret - { - start, begin(buf) - }; - - assert(serialized(b, e) == size(ret)); - return ret; -} - size_t ircd::json::serialized(const object &object) { @@ -1856,29 +1800,6 @@ ircd::json::serialized(const object &object) }); } -size_t -ircd::json::serialized(const object::member *const &begin, - const object::member *const &end) -{ - const size_t ret(1 + (begin == end)); - return std::accumulate(begin, end, ret, [] - (auto ret, const object::member &member) - { - return ret += serialized(member) + 1; - }); -} - -bool -ircd::json::sorted(const object::member *const &begin, - const object::member *const &end) -{ - return std::is_sorted(begin, end, [] - (const object::member &a, const object::member &b) - { - return a.first < b.first; - }); -} - bool ircd::json::sorted(const object &object) { @@ -1894,35 +1815,42 @@ ircd::json::sorted(const object &object) return true; } -ircd::json::object::const_iterator & -ircd::json::object::const_iterator::operator++() -try +size_t +ircd::json::size(const object &object) { - static const auto &ws - { - parser.ws - }; - - static const parser::rule member - { - parser.name >> -ws >> parser.name_sep >> -ws >> raw[parser.value(0)] - ,"next object member" - }; - - static const parser::rule parse_next - { - (parser.object_end | (parser.value_sep >> -ws >> member)) >> -ws - ,"next object member or end" - }; - - state.first = string_view{}; - state.second = string_view{}; - qi::parse(start, stop, eps > parse_next, state); - return *this; + return object.size(); } -catch(const qi::expectation_failure &e) + +bool +ircd::json::operator!(const object &object) { - throw expectation_failure(start, e); + return empty(object); +} + +bool +ircd::json::empty(const object &object) +{ + return object.empty(); +} + +// +// object +// + +ircd::string_view +ircd::json::object::operator[](const string_view &key) +const +{ + const auto it(find(key)); + return it != end()? it->second : string_view{}; +} + +ircd::string_view +ircd::json::object::get(const string_view &key, + const string_view &def) +const +{ + return get(key, def); } ircd::json::object::operator std::string() @@ -1931,6 +1859,58 @@ const return json::strung(*this); } +bool +ircd::json::object::has(const string_view &key) +const +{ + return find(key) != end(); +} + +size_t +ircd::json::object::size() +const +{ + return count(); +} + +size_t +ircd::json::object::count() +const +{ + return std::distance(begin(), end()); +} + +bool +ircd::json::object::empty() +const +{ + const string_view &sv{*this}; + assert(sv.size() > 2 || (sv.empty() || sv == empty_object)); + return sv.size() <= 2; +} + +ircd::json::object::const_iterator +ircd::json::object::find(const name_hash_t &key) +const +{ + return std::find_if(begin(), end(), [&key] + (const auto &member) + { + return name_hash(member.first) == key; + }); +} + +ircd::json::object::const_iterator +ircd::json::object::find(const string_view &key) +const +{ + return std::find_if(begin(), end(), [&key] + (const auto &member) + { + return member.first == key; + }); +} + ircd::json::object::const_iterator ircd::json::object::begin() const try @@ -1974,6 +1954,196 @@ const return { string_view::end(), string_view::end() }; } +// +// object::const_iterator +// + +bool +ircd::json::operator==(const object::const_iterator &a, const object::const_iterator &b) +{ + return a.start == b.start; +} + +bool +ircd::json::operator!=(const object::const_iterator &a, const object::const_iterator &b) +{ + return a.start != b.start; +} + +bool +ircd::json::operator<=(const object::const_iterator &a, const object::const_iterator &b) +{ + return a.start <= b.start; +} + +bool +ircd::json::operator>=(const object::const_iterator &a, const object::const_iterator &b) +{ + return a.start >= b.start; +} + +bool +ircd::json::operator<(const object::const_iterator &a, const object::const_iterator &b) +{ + return a.start < b.start; +} + +bool +ircd::json::operator>(const object::const_iterator &a, const object::const_iterator &b) +{ + return a.start > b.start; +} + +ircd::json::object::const_iterator & +ircd::json::object::const_iterator::operator++() +try +{ + static const auto &ws + { + parser.ws + }; + + static const parser::rule member + { + parser.name >> -ws >> parser.name_sep >> -ws >> raw[parser.value(0)] + ,"next object member" + }; + + static const parser::rule parse_next + { + (parser.object_end | (parser.value_sep >> -ws >> member)) >> -ws + ,"next object member or end" + }; + + state.first = string_view{}; + state.second = string_view{}; + qi::parse(start, stop, eps > parse_next, state); + return *this; +} +catch(const qi::expectation_failure &e) +{ + throw expectation_failure(start, e); +} + +// +// object::member +// + +std::ostream & +ircd::json::operator<<(std::ostream &s, const object::member &member) +{ + s << json::strung(member); + return s; +} + +ircd::string_view +ircd::json::stringify(mutable_buffer &buf, + const object::member &member) +{ + char *const start(begin(buf)); + printer(buf, printer.name << printer.name_sep, member.first); + stringify(buf, member.second); + const string_view ret + { + start, begin(buf) + }; + + assert(serialized(member) == size(ret)); + return ret; +} + +size_t +ircd::json::serialized(const object::member &member) +{ + const json::value key{member.first, json::STRING}; + return serialized(key) + 1 + serialized(member.second); +} + +ircd::string_view +ircd::json::stringify(mutable_buffer &buf, + const object::member *const &b, + const object::member *const &e) +{ + char *const start(begin(buf)); + static const auto stringify_member + { + [](mutable_buffer &buf, const object::member &member) + { + stringify(buf, member); + } + }; + + printer(buf, printer.object_begin); + printer::list_protocol(buf, b, e, stringify_member); + printer(buf, printer.object_end); + const string_view ret + { + start, begin(buf) + }; + + assert(serialized(b, e) == size(ret)); + return ret; +} + +size_t +ircd::json::serialized(const object::member *const &begin, + const object::member *const &end) +{ + const size_t ret(1 + (begin == end)); + return std::accumulate(begin, end, ret, [] + (auto ret, const object::member &member) + { + return ret += serialized(member) + 1; + }); +} + +bool +ircd::json::sorted(const object::member *const &begin, + const object::member *const &end) +{ + return std::is_sorted(begin, end, [] + (const object::member &a, const object::member &b) + { + return a.first < b.first; + }); +} + +bool +ircd::json::operator==(const object::member &a, const object::member &b) +{ + return a.first == b.first; +} + +bool +ircd::json::operator!=(const object::member &a, const object::member &b) +{ + return a.first != b.first; +} + +bool +ircd::json::operator<=(const object::member &a, const object::member &b) +{ + return a.first <= b.first; +} + +bool +ircd::json::operator>=(const object::member &a, const object::member &b) +{ + return a.first >= b.first; +} + +bool +ircd::json::operator<(const object::member &a, const object::member &b) +{ + return a.first < b.first; +} + +bool +ircd::json::operator>(const object::member &a, const object::member &b) +{ + return a.first > b.first; +} + /////////////////////////////////////////////////////////////////////////////// // // json/array.h