xo-reflect: feat: capture dtor
This commit is contained in:
parent
1ddc3e6a62
commit
fc2b88da4b
7 changed files with 71 additions and 21 deletions
|
|
@ -41,7 +41,8 @@ namespace xo {
|
|||
static TypeDescrW establish() {
|
||||
TypeDescrW td = TypeDescrBase::require(&typeid(T),
|
||||
std::string(type_name<T>()),
|
||||
nullptr);
|
||||
nullptr /*tdextra*/,
|
||||
nullptr /*invoker*/);
|
||||
|
||||
#ifdef NOT_USING
|
||||
std::function<TaggedPtr (void *)> to_self_tp;
|
||||
|
|
|
|||
|
|
@ -21,8 +21,6 @@ namespace xo {
|
|||
**/
|
||||
class Object : public reflect::SelfTagging {
|
||||
public:
|
||||
using TypeId = xo::reflect::TypeId;
|
||||
|
||||
Object(TypeId type_id) : type_id_{type_id} {}
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ namespace xo {
|
|||
// ----- xo::ref::rp<Object> -----
|
||||
|
||||
template<typename Object>
|
||||
class EstablishTdx<xo::ref::rp<Object>> {
|
||||
class EstablishTdx<rp<Object>> {
|
||||
public:
|
||||
/* definition provide after decl for Reflect {} below */
|
||||
static std::unique_ptr<TypeDescrExtra> make();
|
||||
|
|
@ -182,9 +182,12 @@ namespace xo {
|
|||
} else {
|
||||
/* control comes here the first time require<T>() runs */
|
||||
|
||||
static detail::InvokerAux<T> s_final_invoker;
|
||||
|
||||
auto final_tdx = EstablishTdx<T>::make();
|
||||
|
||||
retval_td->assign_tdextra(std::move(final_tdx));
|
||||
retval_td->assign_tdextra(&s_final_invoker,
|
||||
std::move(final_tdx));
|
||||
|
||||
/* also need to require for each child */
|
||||
}
|
||||
|
|
@ -274,7 +277,7 @@ namespace xo {
|
|||
*/
|
||||
template<typename Object>
|
||||
std::unique_ptr<TypeDescrExtra>
|
||||
EstablishTdx<xo::ref::rp<Object>>::make() {
|
||||
EstablishTdx<rp<Object>>::make() {
|
||||
/* need to ensure Object is property reflected.
|
||||
*
|
||||
* In practice must be a class type, since has to store refcount
|
||||
|
|
@ -282,7 +285,7 @@ namespace xo {
|
|||
*/
|
||||
Reflect::require<Object>();
|
||||
|
||||
return RefPointerTdx<xo::ref::rp<Object>>::make();
|
||||
return RefPointerTdx<rp<Object>>::make();
|
||||
} /*make*/
|
||||
|
||||
// ----- std::array<Element, N> -----
|
||||
|
|
|
|||
|
|
@ -80,11 +80,14 @@ namespace xo {
|
|||
return SelfTagger<StructT, have_to_self_tp>::self_tp(object);
|
||||
});
|
||||
|
||||
static detail::InvokerAux<StructT> s_final_invoker;
|
||||
|
||||
auto tdx = StructTdx::make(std::move(this->member_v_),
|
||||
have_to_self_tp,
|
||||
to_self_tp_fn);
|
||||
|
||||
this->td_->assign_tdextra(std::move(tdx));
|
||||
this->td_->assign_tdextra(&s_final_invoker,
|
||||
std::move(tdx));
|
||||
}
|
||||
} /*complete*/
|
||||
|
||||
|
|
|
|||
|
|
@ -88,6 +88,33 @@ namespace xo {
|
|||
/* native type_info object for encapsulated type */
|
||||
std::type_info const * tinfo_ = nullptr;
|
||||
}; /*TypeInfoRef*/
|
||||
|
||||
namespace detail {
|
||||
struct Invoker {
|
||||
virtual void dtor(void * addr) const = 0;
|
||||
};
|
||||
|
||||
/** Auxiliary template for capturing destructor for type T,
|
||||
* if it has one.
|
||||
*
|
||||
* Example
|
||||
* T * p = new T(...);
|
||||
* DestructorAux<T>::dtor(p);
|
||||
**/
|
||||
template <typename T>
|
||||
struct InvokerAux : public Invoker {
|
||||
virtual void dtor(void * addr) const override {
|
||||
T * obj = static_cast<T *>(addr);
|
||||
|
||||
obj->~T();
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct InvokerAux<void> : public Invoker {
|
||||
virtual void dtor(void *) const override {}
|
||||
};
|
||||
} /*namespace detail*/
|
||||
} /*namespace reflect*/
|
||||
} /*namespace xo*/
|
||||
|
||||
|
|
@ -191,6 +218,7 @@ namespace xo {
|
|||
*/
|
||||
static TypeDescrW require(const std::type_info * tinfo,
|
||||
const std::string & canonical_name,
|
||||
detail::Invoker * invoker,
|
||||
std::unique_ptr<TypeDescrExtra> tdextra);
|
||||
|
||||
/** Create type-description for function from input ingredients. **/
|
||||
|
|
@ -364,16 +392,21 @@ namespace xo {
|
|||
/* call this once to attach extended type information to a type-description
|
||||
* (e.g. description of struct members for a record type)
|
||||
*/
|
||||
void assign_tdextra(std::unique_ptr<TypeDescrExtra> tdx) {
|
||||
void assign_tdextra(detail::Invoker * invoker,
|
||||
std::unique_ptr<TypeDescrExtra> tdx) {
|
||||
this->complete_flag_ = true;
|
||||
this->invoker_ = invoker;
|
||||
this->tdextra_ = std::move(tdx);
|
||||
}
|
||||
|
||||
// ----- actions -----
|
||||
|
||||
private:
|
||||
TypeDescrBase(TypeId id,
|
||||
const std::type_info * tinfo,
|
||||
const std::string & canonical_name,
|
||||
std::unique_ptr<TypeDescrExtra> tdextra);
|
||||
std::unique_ptr<TypeDescrExtra> tdextra,
|
||||
detail::Invoker * invoker);
|
||||
|
||||
void assign_native_tinfo(const std::type_info * tinfo) {
|
||||
assert(!native_typeinfo_);
|
||||
|
|
@ -429,8 +462,9 @@ namespace xo {
|
|||
static std::unordered_map<FunctionTdxInfo, TypeDescrBase *> s_function_type_map;
|
||||
|
||||
private:
|
||||
/* unique id# for this type */
|
||||
/** unique id# for this type **/
|
||||
TypeId id_;
|
||||
|
||||
/** typeinfo for type T, if available. nullptr otherwise.
|
||||
*
|
||||
* 1. Always available for type-descriptions constructed via Reflect::require<T>.
|
||||
|
|
@ -438,6 +472,7 @@ namespace xo {
|
|||
* see Lambda.cpp in xo-expression.
|
||||
**/
|
||||
std::type_info const * native_typeinfo_ = nullptr;
|
||||
|
||||
/** canonical name for this type (see demangle.hpp for type_name<T>())
|
||||
* e.g.
|
||||
* xo::option::Px2
|
||||
|
|
@ -448,19 +483,28 @@ namespace xo {
|
|||
* so need to use std::string here
|
||||
**/
|
||||
std::string canonical_name_;
|
||||
|
||||
/** substring .canonical_name, just after last ':'
|
||||
* e.g.
|
||||
* Px2
|
||||
**/
|
||||
std::string_view short_name_;
|
||||
/* set to true once final value for .tdextra is established
|
||||
|
||||
/** set to true once final value for .tdextra is established
|
||||
* intially all TypeDescr objects will use AtomicTdx for .tdextra
|
||||
* Reflect::require() upgrades .tdextra for particular types.
|
||||
* When that procedure makes a decision for a type T,
|
||||
* .complete_flag will be set to true for the corresponding TypeDescrBase instance
|
||||
*/
|
||||
**/
|
||||
bool complete_flag_ = false;
|
||||
/* additional type information that either:
|
||||
|
||||
/** capture basic instance-management operations for this type.
|
||||
* Given an instance T x:
|
||||
* - invoker_->dtor(&x) invokes T::~T()
|
||||
**/
|
||||
detail::Invoker * invoker_;
|
||||
|
||||
/** additional type information that either:
|
||||
* (a) isn't universal across all types,
|
||||
* e.g. dereferencing instance of a pointer type
|
||||
* (b) can't be captured with template-fu,
|
||||
|
|
@ -469,7 +513,7 @@ namespace xo {
|
|||
* generally .tdextra will be populated some time after TypeDescrBase's ctor exits.
|
||||
* This is necessary because of (b) above, also because of possibility of recursive
|
||||
* types.
|
||||
*/
|
||||
**/
|
||||
std::unique_ptr<TypeDescrExtra> tdextra_;
|
||||
}; /*TypeDescrBase*/
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ namespace xo {
|
|||
TypeDescrW
|
||||
TypeDescrBase::require(const std::type_info * native_tinfo,
|
||||
const std::string & canonical_name,
|
||||
detail::Invoker * invoker,
|
||||
std::unique_ptr<TypeDescrExtra> tdextra)
|
||||
{
|
||||
if (native_tinfo) {
|
||||
|
|
@ -152,7 +153,8 @@ namespace xo {
|
|||
auto new_td = new TypeDescrBase(new_td_id,
|
||||
native_tinfo,
|
||||
canonical_name,
|
||||
std::move(tdextra));
|
||||
std::move(tdextra),
|
||||
invoker);
|
||||
|
||||
new_slot.reset(new_td);
|
||||
|
||||
|
|
@ -178,6 +180,7 @@ namespace xo {
|
|||
|
||||
return require(nullptr /*native_tinfo - n/avail on this path*/,
|
||||
fn_info.make_canonical_name(),
|
||||
nullptr /*invoker*/,
|
||||
std::move(fn_tdextra));
|
||||
} /*require_by_fn_info*/
|
||||
|
||||
|
|
@ -240,11 +243,13 @@ namespace xo {
|
|||
TypeDescrBase::TypeDescrBase(TypeId id,
|
||||
const std::type_info * native_tinfo,
|
||||
const std::string & canonical_name,
|
||||
std::unique_ptr<TypeDescrExtra> tdextra)
|
||||
std::unique_ptr<TypeDescrExtra> tdextra,
|
||||
detail::Invoker * invoker)
|
||||
: id_{std::move(id)},
|
||||
native_typeinfo_{native_tinfo},
|
||||
canonical_name_{std::move(canonical_name)},
|
||||
short_name_{unqualified_name(canonical_name_)},
|
||||
invoker_{invoker},
|
||||
tdextra_{std::move(tdextra)}
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,10 +9,6 @@ set(SELF_SOURCE_FILES
|
|||
FunctionTdx.test.cpp)
|
||||
|
||||
xo_add_utest_executable(${SELF_EXECUTABLE_NAME} ${SELF_SOURCE_FILES})
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# deps: indentlog, ..
|
||||
|
||||
xo_self_dependency(${SELF_EXECUTABLE_NAME} reflect)
|
||||
xo_external_target_dependency(${SELF_EXECUTABLE_NAME} Catch2 Catch2::Catch2)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue