diff --git a/include/ircd/json/stack.h b/include/ircd/json/stack.h index 938863776..9d0322c3c 100644 --- a/include/ircd/json/stack.h +++ b/include/ircd/json/stack.h @@ -83,77 +83,6 @@ struct ircd::json::stack ~stack() noexcept; }; -/// stack::object is constructed under the scope of either a stack::member, -/// or a stack::array, or a stack itself. Only stack::member can be -/// constructed directly under its scope. -/// -/// For a stack::member parent, the named member is waiting for this value -/// after leaving the stack at ':' after the name, this object will then -/// print '{' and dtor with '}' and then return to the stack::member which -/// will then return to its parent object. -/// -/// For a stack::array parent, the stack may have been left at '[' or ',' -/// but either way this object will then print '{' and dtor with '}' and -/// then return to the stack::array. -/// -/// For a stack itself, this object is considered the "top object" and will -/// open the stack with '{' and accept member instances under its scope -/// until closing the stack with '}' after which the stack is done() -/// -struct ircd::json::stack::object -{ - stack *s {nullptr}; ///< root stack ref - member *pm {nullptr}; ///< parent member (if value of one) - array *pa {nullptr}; ///< parent array (if value in one) - member *cm {nullptr}; ///< current child member - size_t mc {0}; ///< members witnessed (monotonic) - - public: - object(stack &s); ///< Object is top - object(array &pa); ///< Object is value in the array - object(member &pm); ///< Object is value of named member - object(object &&) noexcept; - object(const object &) = delete; - ~object() noexcept; - - static const object &top(const stack &); - static object &top(stack &); -}; - -/// stack::array is constructed under the scope of either a stack::member, -/// or a stack::array, or a stack itself. stack::object and stack::array -/// can be constructed directly under its scope, but not stack::member. -/// -/// The same behavior as described by stack::object documentation applies -/// here translated to arrays. -/// -struct ircd::json::stack::array -{ - stack *s {nullptr}; ///< root stack ref - member *pm {nullptr}; ///< parent member (if value of one) - array *pa {nullptr}; ///< parent array (if value in one) - object *co {nullptr}; ///< current child object - array *ca {nullptr}; ///< current child array - size_t vc {0}; ///< values witnessed (monotonic) - - void _pre_append(); - void _post_append(); - - public: - template void append(const json::tuple &); - void append(const json::value &); - - array(stack &s); ///< Array is top - array(array &pa); ///< Array is value in the array - array(member &pm); ///< Array is value of the named member - array(const array &) = delete; - array(array &&) noexcept; - ~array() noexcept; - - static const array &top(const stack &); - static array &top(stack &); -}; - /// stack::member is an intermediary that is constructed under the scope of /// a parent stack::object. It takes a name argument. It then requires one /// object or array be constructed under its scope as its value, or a @@ -184,6 +113,7 @@ struct ircd::json::stack::member member(stack &s, const string_view &name, const json::value &); template member(object &po, const string_view &name, const json::tuple &t); template member(stack &s, const string_view &name, const json::tuple &t); + member() = default; member(const member &) = delete; member(member &&) noexcept; ~member() noexcept; @@ -192,6 +122,83 @@ struct ircd::json::stack::member static member &top(stack &); }; +/// stack::object is constructed under the scope of either a stack::member, +/// or a stack::array, or a stack itself. Only stack::member can be +/// constructed directly under its scope. +/// +/// For a stack::member parent, the named member is waiting for this value +/// after leaving the stack at ':' after the name, this object will then +/// print '{' and dtor with '}' and then return to the stack::member which +/// will then return to its parent object. +/// +/// For a stack::array parent, the stack may have been left at '[' or ',' +/// but either way this object will then print '{' and dtor with '}' and +/// then return to the stack::array. +/// +/// For a stack itself, this object is considered the "top object" and will +/// open the stack with '{' and accept member instances under its scope +/// until closing the stack with '}' after which the stack is done() +/// +struct ircd::json::stack::object +{ + member m; ///< optional internal member + stack *s {nullptr}; ///< root stack ref + member *pm {nullptr}; ///< parent member (if value of one) + array *pa {nullptr}; ///< parent array (if value in one) + member *cm {nullptr}; ///< current child member + size_t mc {0}; ///< members witnessed (monotonic) + + public: + object(stack &s); ///< Object is top + object(array &pa); ///< Object is value in the array + object(member &pm); ///< Object is value of named member + object(object &po, const string_view &name); + object(stack &s, const string_view &name); + object(object &&) noexcept; + object(const object &) = delete; + ~object() noexcept; + + static const object &top(const stack &); + static object &top(stack &); +}; + +/// stack::array is constructed under the scope of either a stack::member, +/// or a stack::array, or a stack itself. stack::object and stack::array +/// can be constructed directly under its scope, but not stack::member. +/// +/// The same behavior as described by stack::object documentation applies +/// here translated to arrays. +/// +struct ircd::json::stack::array +{ + member m; ///< optional internal member + stack *s {nullptr}; ///< root stack ref + member *pm {nullptr}; ///< parent member (if value of one) + array *pa {nullptr}; ///< parent array (if value in one) + object *co {nullptr}; ///< current child object + array *ca {nullptr}; ///< current child array + size_t vc {0}; ///< values witnessed (monotonic) + + void _pre_append(); + void _post_append(); + + public: + template void append(const json::tuple &); + void append(const json::value &); + + array(member &pm); ///< Array is value of the named member + array(array &pa); ///< Array is value in the array + array(object &po, const string_view &name); + array(stack &s, const string_view &name); + array(stack &s); + array(const array &) = delete; + array(array &&) noexcept; + ~array() noexcept; + + static const array &top(const stack &); + static array &top(stack &); +}; + /// This device chases the current active path by updating its member pointers. struct ircd::json::stack::chase { diff --git a/ircd/json.cc b/ircd/json.cc index ab90905e9..eb57da8f0 100644 --- a/ircd/json.cc +++ b/ircd/json.cc @@ -612,7 +612,8 @@ ircd::json::stack::object::top(const stack &s) ircd::json::stack::object::object(object &&other) noexcept -:s{std::move(other.s)} +:m{std::move(other.m)} +,s{std::move(other.s)} ,pm{std::move(other.pm)} ,pa{std::move(other.pa)} ,cm{std::move(other.cm)} @@ -646,6 +647,28 @@ ircd::json::stack::object::object(stack &s) s.append("{"_sv); } +ircd::json::stack::object::object(stack &s, + const string_view &name) +:object{object::top(s), name} +{ +} + +ircd::json::stack::object::object(object &po, + const string_view &name) +:m{po, name} +,s{po.s} +,pm{&m} +{ + assert(s->opened()); + s->rethrow_exception(); + + assert(pm->co == nullptr); + assert(pm->ca == nullptr); + pm->co = this; + s->append("{"_sv); + pm->vc |= true; +} + ircd::json::stack::object::object(member &pm) :s{pm.s} ,pm{&pm} @@ -760,7 +783,8 @@ ircd::json::stack::array::top(const stack &s) ircd::json::stack::array::array(array &&other) noexcept -:s{std::move(other.s)} +:m{std::move(other.m)} +,s{std::move(other.s)} ,pm{std::move(other.pm)} ,pa{std::move(other.pa)} ,co{std::move(other.co)} @@ -796,18 +820,26 @@ ircd::json::stack::array::array(stack &s) s.append("["_sv); } -ircd::json::stack::array::array(member &pm) -:s{pm.s} -,pm{&pm} +ircd::json::stack::array::array(stack &s, + const string_view &name) +:array{object::top(s), name} +{ +} + +ircd::json::stack::array::array(object &po, + const string_view &name) +:m{po, name} +,s{po.s} +,pm{&m} { assert(s->opened()); s->rethrow_exception(); - assert(pm.co == nullptr); - assert(pm.ca == nullptr); - pm.ca = this; + assert(pm->co == nullptr); + assert(pm->ca == nullptr); + pm->ca = this; s->append("["_sv); - pm.vc |= true; + pm->vc |= true; } ircd::json::stack::array::array(array &pa) @@ -827,6 +859,20 @@ ircd::json::stack::array::array(array &pa) s->append("["_sv); } +ircd::json::stack::array::array(member &pm) +:s{pm.s} +,pm{&pm} +{ + assert(s->opened()); + s->rethrow_exception(); + + assert(pm.co == nullptr); + assert(pm.ca == nullptr); + pm.ca = this; + s->append("["_sv); + pm.vc |= true; +} + ircd::json::stack::array::~array() noexcept {