/* file Reflect.hpp * * author: Roland Conybeare, Aug 2022 */ #pragma once #include "SelfTagging.hpp" #include "EstablishTypeDescr.hpp" #include "atomic/AtomicTdx.hpp" #include "pointer/PointerTdx.hpp" #include "vector/VectorTdx.hpp" #include "struct/StructTdx.hpp" #include "refcnt/Refcounted.hpp" #include #include #include // for std::pair<> namespace xo { namespace reflect { template class EstablishTdx { public: static std::unique_ptr make() { return AtomicTdx::make(); } }; /*EstablishTdx*/ // ----- xo::ref::rp ----- /* definition provide after decl for Reflect {} below */ template class EstablishTdx> { public: static std::unique_ptr make(); }; /*EstablishTdx*/ // ----- std::array ----- /* definition provide after decl for Reflect {} below */ template class EstablishTdx> { public: static std::unique_ptr make(); }; /*EstablishTdx*/ // ----- std::vector ----- /* definition provide after decl for Reflect {} below */ template class EstablishTdx> { public: static std::unique_ptr make(); }; /*EstablishTdx*/ // ----- std::pair ----- /* definition provide after decl for Reflect {} below */ template class EstablishTdx> { public: static std::unique_ptr make(); }; /*EstablishTdx*/ // ----- MakeTagged ----- template class TaggedPtrMaker { public: static TaggedPtr make_tp(T * x); static TaggedRcptr make_rctp(T * x); }; template<> class TaggedPtrMaker { public: static TaggedPtr make_tp(SelfTagging * x) { return x->self_tp(); } /*make_tp*/ static TaggedRcptr make_rctp(SelfTagging * x) { return x->self_tp(); } /*make_rctp*/ }; /*TaggedPtrMaker*/ // ----- Reflect ----- class Reflect { public: /* Use: * using mytype = ...; * if (Reflect::is_reflected()) { ... } */ template static bool is_reflected() { return TypeDescrBase::is_reflected(&typeid(T)); } /* Use: * using mytype = ...; * TypeDescrW td = Reflect::require(); * * Note: * To avoid cyclic header dependencies * (between EstablishTypeDescr.hpp <-> {vector/VectorTdx.hpp etc.}, * we use a 2-stage setup process: * * 1. EstablishTypeDescr::establish() creates a TypeDescr* object * with lowest-common-denominator .tdextra AtomicTdx. * (see [reflect/EstablishTypeDescr.hpp]) * * 2. Reflect::require() upgrades .tdextra to suitable implementation * depending on T; this means also need to visit reflection info * (TypeDescr objects) for nested types to upgrade them too. * * This allows template-fu for a compound type (like std::vector), * implemented in specialized header (like [reflect/struct/VectorTdx.hpp]) to * refer to reflection info for T without having to pull in all the * headers needed to properly reflect T (like this [reflect/Reflect.hpp]) * */ template static TypeDescrW require() { TypeDescrW retval_td = EstablishTypeDescr::establish(); /* mark TypeDescr for T as complete (even though it isn't quite yet), * so that when we encounter recursive types, reflection terminates. * For example consider type resulting from code like * * typename T; * using T = std::vector; * */ if (retval_td->mark_complete()) { /* control here on 2nd+later calls to require(). * in principle can immediately short-circuit. */ } else { /* control comes here the first time require() runs */ auto final_tdx = EstablishTdx::make(); retval_td->assign_tdextra(std::move(final_tdx)); /* also need to require for each child */ } return retval_td; } /*require*/ /* Use: * T * xyz = ...; * TaggedPtr xyz_tp = Reflect::make_tp(xyz); */ template static TaggedPtr make_tp(T * x) { return TaggedPtrMaker::make_tp(x); } template static TaggedRcptr make_rctp(T * x) { return TaggedPtrMaker::make_rctp(x); } }; /*Reflect*/ // ----- MakeTagged ----- template TaggedPtr TaggedPtrMaker::make_tp(T * x) { return TaggedPtr(Reflect::require(), x); } /*make_tp*/ template TaggedRcptr TaggedPtrMaker::make_rctp(T * x) { return TaggedRcptr(Reflect::require(), x); } /*make_rctp*/ // ----- xo::ref::rp ----- /* declared above before * class Reflect { .. } */ template std::unique_ptr EstablishTdx>::make() { /* need to ensure Object is property reflected. * * In practice must be a class type, since has to store refcount * + supply assoc'd incr/decr methods */ Reflect::require(); return RefPointerTdx>::make(); } /*make*/ // ----- std::array ----- /* declared above before * class Reflect { .. } */ template std::unique_ptr EstablishTdx>::make() { /* need to ensure Element is properly reflected */ Reflect::require(); return StdArrayTdx::make(); } /*make*/ // ----- std::vector ----- /* declared above before * class Reflect { .. } */ template std::unique_ptr EstablishTdx>::make() { /* need to ensure Element is properly reflected */ Reflect::require(); return StdVectorTdx::make(); } /*make*/ // ----- std::pair ----- /* declared above before * class Reflect { .. } */ template std::unique_ptr EstablishTdx>::make() { /* need to ensure Lhs, Rhs are properly reflected */ Reflect::require(); Reflect::require(); return StructTdx::pair(); } /*make*/ } /*namespace reflect*/ } /*namespace xo*/ /* end Reflect.hpp */