xo-reflect: feat: capture dtor

This commit is contained in:
Roland Conybeare 2024-08-05 14:37:35 -04:00
commit fc2b88da4b
7 changed files with 71 additions and 21 deletions

View file

@ -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;

View file

@ -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:

View file

@ -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> -----

View file

@ -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*/

View file

@ -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*/

View file

@ -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)}
{
}

View file

@ -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)