Skip to content

File json_node.hpp

File List > backends > cxx > include > zmbt > core > json_node.hpp

Go to the documentation of this file

#ifndef ZMBT_CORE_JSON_NODE_HPP_
#define ZMBT_CORE_JSON_NODE_HPP_


#include <boost/json.hpp>
#include <cstddef>
#include <iostream>
#include <memory>
#include <utility>

#include "format_string.hpp"

namespace zmbt {



class JsonNode
{
    std::shared_ptr<boost::json::value> root_;
    boost::json::string node_ptr_;

    boost::json::value& get_or_create(boost::json::string_view json_ptr);

    boost::json::string resolve_tokens(boost::json::string_view query) const;

    boost::json::value& get_or_create_as(boost::json::kind request_kind, boost::json::string_view json_ptr);

    JsonNode(boost::json::string_view node_ptr, std::shared_ptr<boost::json::value> root);


public:

    ~JsonNode() noexcept = default;

    explicit JsonNode(std::shared_ptr<boost::json::value> root)
        : JsonNode("", root)
    {
    }

    JsonNode()
        : JsonNode(std::make_shared<boost::json::value>())
    {
    }

    explicit JsonNode(boost::json::storage_ptr sp)
        : JsonNode(std::make_shared<boost::json::value>(sp))
    {
    }

    JsonNode(JsonNode const& o)
        : JsonNode(o.node())
    {
    }

    JsonNode(JsonNode & o)
        : JsonNode(o.node_ptr(), o.root())
    {
    }

    JsonNode(JsonNode && o)
        : JsonNode(std::move(o.node_ptr_), std::move(o.root_))
    {
    }


    JsonNode(boost::json::value const& v) : JsonNode(std::make_shared<boost::json::value>(v)) {}
    JsonNode(boost::json::value&& v) : JsonNode(std::make_shared<boost::json::value>(std::move(v))) {}

    std::shared_ptr<boost::json::value> const& root() const { return root_; }

    boost::json::string_view node_ptr() const { return node_ptr_; }

    JsonNode copy() const
    {
        return JsonNode{node()};
    }

    boost::json::value const* node(boost::json::error_code &ec) const
    {
        return root()->find_pointer(node_ptr(), ec);
    }

    boost::json::value* node(boost::json::error_code &ec)
    {
        JsonNode const& self = *this;
        return const_cast<boost::json::value*>(self.node(ec));
    }

    boost::json::value const& node() const {
        return root()->at_pointer(node_ptr());
    }

    boost::json::value& node() {
        JsonNode const& self = *this;
        return const_cast<boost::json::value&>(self.node());
    }


    boost::json::array const& as_array() const {
        return node().as_array();
    }

    boost::json::array& as_array() {
        JsonNode const& self = *this;
        return const_cast<boost::json::array&>(self.as_array());
    }


    boost::json::object const& as_object() const {
        return node().as_object();
    }

    boost::json::object& as_object() {
        JsonNode const& self = *this;
        return const_cast<boost::json::object&>(self.as_object());
    }

    JsonNode& operator=(JsonNode const&) = default;
    JsonNode& operator=(JsonNode &&) = default;


    boost::json::value const& at(boost::json::string_view json_ptr) const;

    template <class T, class... A>
    boost::json::value const& at(boost::json::string_view fmtstr, T&& first, A&&... rest) const
    {
        return at(format(fmtstr, std::forward<T>(first), std::forward<A>(rest)...));
    }

    boost::json::value const* find_pointer(boost::json::string_view json_ptr) const
    {
        boost::json::error_code ignored;
        return node().find_pointer(resolve_tokens(json_ptr), ignored);
    }


    template <class T, class... A>
    boost::json::value const* find_pointer(boost::json::string_view fmtstr, T&& first, A&&... rest) const
    {
        return find_pointer(format(fmtstr, std::forward<T>(first), std::forward<A>(rest)...));
    }

    template <class T, class... A>
    boost::json::value* find_pointer(boost::json::string_view fmtstr, T&& first, A&&... rest)
    {
        JsonNode const& self = *this;
        return const_cast<boost::json::value*>(self.find_pointer(fmtstr, std::forward<T>(first), std::forward<A>(rest)...));
    }

    bool contains(boost::json::string_view json_ptr) const
    {
        return find_pointer(json_ptr);
    }

    template <class T, class... A>
    bool contains(boost::json::string_view fmtstr, T&& first, A&&... rest) const
    {
        return contains(format(fmtstr, std::forward<T>(first), std::forward<A>(rest)...));
    }


    boost::json::value& operator()(boost::json::string_view json_ptr = "")
    {
        return this->get_or_create(resolve_tokens(json_ptr));
    }

    template <class T, class... A>
    boost::json::value& operator()(boost::json::string_view fmtstr, T&& first, A&&... rest)
    {
        return this->operator()(format(fmtstr, first, rest...));
    }


    boost::json::value const& operator()(boost::json::string_view json_ptr = "") const
    {
        return at(json_ptr);
    }

    template <class T, class... A>
    boost::json::value const& operator()(boost::json::string_view fmtstr, T&& first, A&&... rest) const
    {
        return at(format(fmtstr, first, rest...));
    }

    boost::json::value get_or_default(boost::json::string_view json_ptr, boost::json::value const& dflt) const
    {
        boost::json::value const* ptr;
        return (ptr = find_pointer(json_ptr)) ? *ptr : dflt;
    }

    boost::json::array& get_or_create_array(boost::json::string_view json_ptr = "")
    {
        return get_or_create_as(boost::json::kind::array, json_ptr).as_array();
    }
    template <class T, class... A>
    boost::json::array& get_or_create_array(boost::json::string_view fmtstr, T&& first, A&&... rest)
    {
        return get_or_create_array(format(fmtstr, first, rest...));
    }

    boost::json::object& get_or_create_object(boost::json::string_view json_ptr = "")
    {
        return get_or_create_as(boost::json::kind::object, json_ptr).as_object();
    }


    template <class T, class... A>
    boost::json::object& get_or_create_object(boost::json::string_view fmtstr, T&& first, A&&... rest)
    {
        return get_or_create_object(format(fmtstr, first, rest...));
    }


    friend std::ostream& operator<<(std::ostream& os, JsonNode const& view)
    {
        os << view.node();
        return os;
    }

    JsonNode branch(boost::json::kind kind, boost::json::string_view subnode_ptr);

    JsonNode branch(boost::json::string_view subnode_ptr)
    {
        return branch(boost::json::kind::null, subnode_ptr);
    }

    template <class T, class... A>
    JsonNode branch(boost::json::kind kind, boost::json::string_view fmtstr, T&& first, A&&... rest)
    {
        return branch(kind, format(fmtstr, std::forward<T>(first), std::forward<A>(rest)...));
    }

    template <class T, class... A>
    JsonNode branch(boost::json::string_view fmtstr, T&& first, A&&... rest)
    {
        return branch(format(fmtstr, std::forward<T>(first), std::forward<A>(rest)...));
    }

    bool is_null() const
    {
        return node().is_null();
    }

    std::size_t size() const
    {
        switch (node().kind())
        {
        case boost::json::kind::array:
            return as_array().size();
            break;
        case boost::json::kind::object:
            return as_object().size();
            break;
        default:
            return 0;
            break;
        }
    }
};

}

#endif