/*************************************************************************** * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * * Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * * The full license is in the file LICENSE, distributed with this software. * ****************************************************************************/ #ifndef XTENSOR_XEXPRESSION_HOLDER_HPP #define XTENSOR_XEXPRESSION_HOLDER_HPP #include #include #include "xarray.hpp" #include "xjson.hpp" #include "xtensor_config.hpp" #include "xtl/xany.hpp" namespace xt { namespace detail { class xexpression_holder_impl; template class xexpression_wrapper; } class xexpression_holder // Value semantic { public: using implementation_type = detail::xexpression_holder_impl; xexpression_holder() = default; template xexpression_holder(E&& expr); xexpression_holder(implementation_type* holder); xexpression_holder(const xexpression_holder& holder); xexpression_holder(xexpression_holder&& holder); xexpression_holder& operator=(const xexpression_holder&); xexpression_holder& operator=(xexpression_holder&&); void swap(xexpression_holder&); void to_json(nlohmann::json&) const; void from_json(const nlohmann::json&); private: void init_pointer_from_json(const nlohmann::json&); void check_holder() const; std::unique_ptr p_holder; }; /************************************* * to_json and from_json declaration * *************************************/ /// @cond DOXYGEN_INCLUDE_SFINAE void to_json(nlohmann::json& j, const xexpression_holder& o); void from_json(const nlohmann::json& j, xexpression_holder& o); /// @endcond namespace detail { class xexpression_holder_impl // Entity semantic { public: xexpression_holder_impl(xexpression_holder_impl&&) = delete; xexpression_holder_impl& operator=(const xexpression_holder_impl&) = delete; xexpression_holder_impl& operator=(xexpression_holder_impl&&) = delete; virtual xexpression_holder_impl* clone() const = 0; virtual void to_json(nlohmann::json&) const = 0; virtual void from_json(const nlohmann::json&) = 0; virtual ~xexpression_holder_impl() = default; protected: xexpression_holder_impl() = default; xexpression_holder_impl(const xexpression_holder_impl&) = default; }; template class xexpression_wrapper : public xexpression_holder_impl { public: template xexpression_wrapper(E&& expr); xexpression_wrapper* clone() const; void to_json(nlohmann::json&) const; void from_json(const nlohmann::json&); ~xexpression_wrapper() = default; protected: xexpression_wrapper(const xexpression_wrapper&); private: CTE m_expression; }; } template inline xexpression_holder::xexpression_holder(E&& expr) : p_holder(new detail::xexpression_wrapper(std::forward(expr))) { } inline xexpression_holder::xexpression_holder(implementation_type* holder) : p_holder(holder) { } inline xexpression_holder::xexpression_holder(const xexpression_holder& holder) : p_holder(holder.p_holder->clone()) { } inline xexpression_holder::xexpression_holder(xexpression_holder&& holder) : p_holder(std::move(holder.p_holder)) { } inline xexpression_holder& xexpression_holder::operator=(const xexpression_holder& holder) { xexpression_holder tmp(holder); swap(tmp); return *this; } inline xexpression_holder& xexpression_holder::operator=(xexpression_holder&& holder) { swap(holder); return *this; } inline void xexpression_holder::swap(xexpression_holder& holder) { std::swap(p_holder, holder.p_holder); } inline void xexpression_holder::to_json(nlohmann::json& j) const { if (p_holder == nullptr) { return; } p_holder->to_json(j); } inline void xexpression_holder::from_json(const nlohmann::json& j) { if (!j.is_array()) { XTENSOR_THROW(std::runtime_error, "Received a JSON that does not contain a tensor"); } if (p_holder == nullptr) { init_pointer_from_json(j); } p_holder->from_json(j); } inline void xexpression_holder::init_pointer_from_json(const nlohmann::json& j) { if (j.is_array()) { return init_pointer_from_json(j[0]); } if (j.is_number()) { xt::xarray empty_arr; p_holder.reset(new detail::xexpression_wrapper>(std::move(empty_arr))); } if (j.is_boolean()) { xt::xarray empty_arr; p_holder.reset(new detail::xexpression_wrapper>(std::move(empty_arr))); } if (j.is_string()) { xt::xarray empty_arr; p_holder.reset(new detail::xexpression_wrapper>(std::move(empty_arr))); } XTENSOR_THROW(std::runtime_error, "Received a JSON with a tensor that contains unsupported data type"); } inline void xexpression_holder::check_holder() const { if (p_holder == nullptr) { XTENSOR_THROW(std::runtime_error, "The holder does not contain an expression"); } } /**************************************** * to_json and from_json implementation * ****************************************/ /// @cond DOXYGEN_INCLUDE_SFINAE inline void to_json(nlohmann::json& j, const xexpression_holder& o) { o.to_json(j); } inline void from_json(const nlohmann::json& j, xexpression_holder& o) { o.from_json(j); } /// @endcond namespace detail { template template inline xexpression_wrapper::xexpression_wrapper(E&& expr) : xexpression_holder_impl() , m_expression(std::forward(expr)) { } template inline xexpression_wrapper* xexpression_wrapper::clone() const { return new xexpression_wrapper(*this); } template inline void xexpression_wrapper::to_json(nlohmann::json& j) const { ::xt::to_json(j, m_expression); } template inline void xexpression_wrapper::from_json(const nlohmann::json& j) { ::xt::from_json(j, m_expression); } template inline xexpression_wrapper::xexpression_wrapper(const xexpression_wrapper& wrapper) : xexpression_holder_impl() , m_expression(wrapper.m_expression) { } } } #endif