C++ Variadic Template Bundlers¶
Detailed Doxygen Documentation.
Several flavors of variadic template classes for creating a single
handle to multiple components are provided. In general, these
components all have identical interfaces and the vast majority
of their member functions accept any and all arguments.
These member functions will take the given arguments and attempt
to invoke the member function of the component with a similar name,
e.g. component_tuple<wall_clock, cpu_clock>::start()
will attempt to
invoke wall_clock::start()
and cpu_clock::start()
. When arguments are
provided, these bundlers will go through a series of checks at compile-time:
Attempt to find the component member function that accepts those exact set of arguments
Attempt to find the component member function which accepts a subset of those arguments (requires type-trait configuration)
Attempt to find the component member function which accepts no arguments
Accept the component does not have the member function and invoke no member function
In the event, this workflow require specialization for a particular component, a custom specialization
of the struct in the tim::operation
namespace can be written.
Static Polymorphic Base Classes¶
-
template<typename...>
class bundle¶ Static polymorphic base class for component bundlers.
-
template<typename ...Types>
class auto_base_bundle¶ Static polymorphic base class for automatic start/stop bundlers.
-
template<typename Tag, typename BundleT, typename TupleT>
class tim::bundle<Tag, BundleT, TupleT> : public tim::api_bundle<Tag, TupleT::available_type>¶ Example:
bundle<Tag, component_bundle<Foo>, mixed_wrapper_types<concat<Bar, Baz>>>
will useTag
+trait::is_available<Tag>
ortrait::runtime_available<Tag>
to disable this bundle at compile-time or run-time, respectively. It will covertcomponent_bundle<Foo>
tocomponent_bundle<Foo, Bar, Baz>
for purposes of function signatures and it will instantiatestd::tuple<...>
depending on the compile-time availability ofBar
andBaz
.mixed_wrapper_types
is a dummy type with the appropriate aliases to perform these conversions. Here is a theoretical implementation ofmixed_wrapper_types
(which supports allocating components on the stack and the heap):template <typename... T> struct heap_wrapper_types { TIMEMORY_DELETED_OBJECT(heap_wrapper_types) /// the set of types, unaltered, in a type_list using type_list_type = type_list<T...>; /// the set of types without any pointers using reference_type = type_list<std::remove_pointer_t<T>...>; /// type list of the available types using available_type = type_list_t<reference_type>; /// the original bundle type template <typename BundleT> using this_type = convert_t<type_list<T...>, BundleT>; /// the type after available_t<concat<...>> template <typename BundleT> using type = convert_t<available_type, BundleT>; /// conversion to equivalent wrapper requiring explicit start/stop template <typename BundleT> using component_type = convert_t<type_list<T...>, BundleT>; /// conversion to equivalent wrapper which automatically starts/stops template <typename BundleT> using auto_type = concepts::auto_type_t<convert_t<type_list_type, BundleT>>; /// the valid types to instantiate in a tuple template <typename ApiT = TIMEMORY_API> using data_type = conditional_t< trait::is_available<ApiT>::value, convert_t<add_pointer_if_not_t<non_placeholder_t<non_quirk_t<type_list_t<T...>>>>, std::tuple<>>, std::tuple<>>; };
- tparam Tag
API tag type, e.g.
TIMEMORY_API
- tparam BundleT
The empty or empty + tag derived type.
- tparam TupleT
The set of components wrapped in a type which provides the appropriate aliases.
Public Functions
-
this_type &push()¶
tells each component to push itself into the call-stack hierarchy
-
this_type &pop()¶
tells each component to pop itself off of the call-stack hierarchy
-
template<typename ...Tp>
this_type &push(mpl::piecewise_select<Tp...>, scope::config)¶ selective push with scope configuration
-
template<typename ...Args>
this_type &measure(Args&&...)¶ requests each component record a measurment
-
template<typename ...Args>
this_type &sample(Args&&...)¶ requests each component take a sample (if supported)
-
template<typename ...Args>
this_type &record(Args&&...)¶ requests each component perform a measurement
-
template<typename ...Args>
this_type &reset(Args&&...)¶ invokes reset member function on all the components
-
template<typename ...Tp, typename ...Args>
this_type &start(mpl::piecewise_select<Tp...>, Args&&...)¶ variant of start() which only gets applied to Tp types
-
template<typename ...Tp, typename ...Args>
this_type &stop(mpl::piecewise_select<Tp...>, Args&&...)¶ variant of stop() which only gets applied to Tp types
-
uint64_t count()¶
number of objects that will be performing measurements
-
template<typename FuncT, typename ...Args>
decltype(auto) execute(FuncT &&func, Args&&... args)¶ when chaining together operations, this function enables executing a function inside the chain
-
template<typename ...Args>
this_type &construct(Args&&... _args)¶ construct the objects that have constructors with matching arguments
-
template<typename ...Args>
this_type &assemble(Args&&... _args)¶ provide preliminary info to the objects with matching arguments. This is typically used to notify a component that it has been bundled alongside another component that it can extract data from.
-
template<typename ...Args>
this_type &derive(Args&&... _args)¶ provide conclusive info to the objects with matching arguments. This is typically used by components to extract data from another component it has been bundled alongside, e.g. the cpu_util component can extract data from tim::component::wall_clock and tim::component::cpu_clock
-
template<typename ...Args>
this_type &mark_begin(Args&&... _args)¶ mark a beginning position in the execution (typically used by asynchronous structures)
-
template<typename ...Args>
this_type &mark_end(Args&&... _args)¶ mark a beginning position in the execution (typically used by asynchronous structures)
-
template<typename ...Args>
this_type &audit(Args&&... _args)¶ allow the components to inspect the incoming arguments before start or out-going return value before returning (typically using in GOTCHA components)
-
template<typename ...Args>
this_type &add_secondary(Args&&... _args)¶ perform an add_secondary operation. This operation allows components to add additional entries to storage which are their direct descendant
-
template<template<typename> class OpT, typename ...Args>
this_type &invoke(Args&&... _args)¶ generic member function for invoking user-provided operations
- Template Parameters
OpT – Operation struct
-
template<template<typename> class OpT, typename ...Tp, typename ...Args>
this_type &invoke(mpl::piecewise_select<Tp...>, Args&&... _args)¶ generic member function for invoking user-provided operations on a specific set of component types
- Template Parameters
OpT – Operation struct
-
template<typename ...Args>
auto get(Args&&...) const¶ returns a tuple of invoking get() on all the components
-
template<typename ...Args>
auto get_labeled(Args&&...) const¶ returns a tuple of the component label + invoking get() on all the components
-
data_type &data()¶
returns a reference to the underlying tuple of components
-
const data_type &data() const¶
returns a const reference to the underlying tuple of components
-
template<typename U>
decltype(auto) get()¶ get a component from the bundle
-
template<typename U>
decltype(auto) get() const¶ get a component from the bundle
-
this_type &get(void *&ptr, hash_value_t _hash) const¶
performs an opaque search. Opaque searches are generally provided by user_bundles with a functor such as this:
auto _get = [](void* v_this, void*& ptr, size_t _hash) { { if(!ptr && v_this && _hash == typeid_hash<Tp>()) { Tp* _this = static_cast<Tp*>(v_this); _this->get(ptr, _hash); } return ptr; };
And the component provides this function:
template <typename Tp, typename Value> void base<Tp, Value>::get(void*& ptr, size_t _hash) const { if(!ptr && _hash == typeid_hash<Tp>()) ptr = reinterpret_cast<void*>(const_cast<base_type*>(this)); }
-
template<typename U>
auto get_component(enable_if_t<trait::is_available<remove_pointer_decay_t<U>>::value && is_one_of<remove_pointer_decay_t<U>, data_type>::value, int> = 0)¶ this is a simple alternative to get<T>() when used from SFINAE in operation namespace which has a struct get also templated. Usage there can cause error with older compilers
-
template<typename U>
auto &get_reference(enable_if_t<trait::is_available<remove_pointer_decay_t<U>>::value && is_one_of<remove_pointer_decay_t<U>, data_type>::value, int> = 0)¶ returns a reference from a stack component instead of a pointer
-
template<typename U>
auto &get_reference(enable_if_t<trait::is_available<remove_pointer_decay_t<U>>::value && is_one_of<remove_pointer_decay_t<U>*, data_type>::value, int> = 0)¶ returns a reference from a heap component instead of a pointer
- template<typename U, typename T = remove_pointer_decay_t<U>, typename... Args> inline enable_if_t< will_heap_init< T >) &&!will_opaque_init< T >), bool > init (Args &&... _args, enable_if_t< is_constructible< T, Args... >(), int >=0)
create an optional type that is in variadic list AND is available AND accepts arguments
- template<typename U, typename T = remove_pointer_decay_t<U>, typename... Args> inline enable_if_t< will_heap_init< T >) &&!will_opaque_init< T >), bool > init (Args &&..., enable_if_t<!is_constructible< T, Args... >() &&is_default_constructible< T >(), long >=0)
create an optional type that is in variadic list AND is available but is not constructible with provided arguments
-
template<typename U, typename T = remove_pointer_decay_t<U>, typename ...Args>
inline bool init(Args&&... _args, enable_if_t<can_stack_init<T>(), int> = 0)¶ try to re-create a stack object with provided arguments
-
template<typename U, typename T = remove_pointer_decay_t<U>, typename ...Args>
inline bool init(Args&&..., enable_if_t<will_opaque_init<T>(), long> = 0)¶ if a type is not in variadic list but a tim::component::user_bundle is available, add it in there
-
template<typename U, typename T = remove_pointer_decay_t<U>, typename ...Args>
inline enable_if_t<!trait::is_available<T>::value || !(is_one_of<T*, data_type>::value || is_one_of<T, data_type>::value || bundle_type::has_user_bundle_v), bool> init(Args&&...)¶ do nothing if type not available, not one of the variadic types, and there is no user bundle available
-
template<typename ...T, typename ...Args>
std::array<bool, sizeof...(T)> initialize(Args&&... args)¶ variadic initialization
- Template Parameters
T – components to initialize
Args – arguments to pass to the construction of the component
-
template<typename ...Tail>
this_type &disable()¶ delete any optional types currently allocated
-
template<typename T, typename Func, typename ...Args, enable_if_t<is_one_of<T, data_type>::value, int> = 0>
inline this_type &type_apply(Func &&_func, Args&&... _args)¶ apply a member function to a stack type that is in variadic list AND is available
-
template<typename T, typename Func, typename ...Args, enable_if_t<trait::is_available<T>::value, int> = 0>
this_type &type_apply(Func &&_func, Args&&... _args)¶ apply a member function to either a heap type or a type that is in a user_bundle
-
template<typename T, typename Func, typename ...Args, enable_if_t<!trait::is_available<T>::value, int> = 0>
this_type &type_apply(Func&&, Args&&...)¶ ignore applying a member function because the type is not present
-
scope::transient_destructor get_scope_destructor()¶
returns a stack-object for calling stop
Public Static Functions
-
template<typename U>
static inline constexpr bool is_this_type()¶ Query whether type matches this_type.
-
static inline constexpr bool has_user_bundle()¶
Query at compile-time whether a user_bundle exists in the set of components. user_bundle are more restricted versions of component bundlers but allow runtime insertion of components.
-
template<typename U>
static inline constexpr bool can_stack_init()¶ Query at compile-time whether initialization can occur on the stack.
-
template<typename U>
static inline constexpr bool can_heap_init()¶ Query at compile-time whether initialization can occur on the heap.
-
template<typename U>
static inline constexpr bool can_placement_init()¶ Query at compile-time whether initialization can occur via a placement new. Placement new init allows for the combination of optional initialization without a heap allocation. Not currently available.
-
template<typename U>
static inline constexpr bool can_init()¶ Query at compile-time whether the specified type can be initialized.
-
template<typename U>
static inline constexpr bool will_heap_init()¶ Query at compile-time whether initialization will occur on the heap.
can_heap_init<T>() && !will_heap_init<T>()
will indicate that a stack-allocated instance of the same type exists.
-
template<typename U>
static inline constexpr bool will_opaque_init()¶ Query at compile-time whether initialization will happen with an opaque wrapper (i.e. via user bundle). In this situation, initialization arguments are ignored and the component will only be initialized with the tim::scope::config of the bundle.
-
template<typename U, typename ...Args, typename T = remove_pointer_decay_t<U>, enable_if_t<trait::is_available<T>::value> = 0>
static inline constexpr bool is_constructible()¶ Query at compile-time whether type can be constructed with the given argument types. if type is not available, then it probably won’t be defined, so this places the
trait::is_available<T>
check in the template parameters and thestd::is_constructible<T, ...>
in the body to avoid undefined behavior.
-
template<typename U, typename ...Args, typename T = remove_pointer_decay_t<U>, enable_if_t<!trait::is_available<T>::value> = 0>
static inline constexpr bool is_constructible()¶ Return false if the type is not available.
-
template<typename U, typename T = remove_pointer_decay_t<U>, enable_if_t<trait::is_available<T>::value> = 0>
static inline constexpr bool is_default_constructible()¶ Query at compile-time whether type supports default construction. If type is not available, then it probably won’t be defined, so this places the
trait::is_available<T>
check in the template parameters and thestd::is_constructible<T, ...>
in the body to avoid undefined behavior.
-
template<typename U, typename T = remove_pointer_decay_t<U>, enable_if_t<!trait::is_available<T>::value> = 0>
static inline constexpr bool is_default_constructible()¶ Return false if the type is not available.
-
static void init_storage()¶
requests the component initialize their storage
-
static constexpr uint64_t fixed_count()¶
query the number of (compile-time) fixed components
-
static constexpr uint64_t optional_count()¶
query the number of (run-time) optional components
-
template<typename Tag, typename CompT, typename BundleT>
class tim::auto_base_bundle<Tag, CompT, BundleT> : public tim::concepts::wrapper, public tim::concepts::variadic, public tim::concepts::auto_wrapper, public tim::concepts::tagged¶ Example:
auto_base_bundle<Tag, component_bundle<Tag>, auto_bundle<Tag, Types...>>
will useTag
+trait::is_available<Tag>
ortrait::runtime_available<Tag>
to disable this bundle at compile-time or run-time, respectively. It will wrap auto-start/stop aroundcomponent_bundle<Tag, Types...>
and useauto_bundle<Tag, Types...>
for function signatures.- tparam Tag
Unique identifying type for the bundle which when tim::trait::is_available<Tag> is false at compile-time or tim::trait::runtime_enabled<Tag>() is false at runtime, then none of the components will be collected
- tparam CompT
The empty or empty + tag non-auto type which will be wrapped
- tparam BundleT
Derived data type
Public Functions
-
inline operator component_type&()¶
implicit conversion to underlying component_type
-
inline operator const component_type&() const¶
implicit conversion to const ref of underlying component_type
-
inline auto count()¶
count number of active components in an instance
-
template<typename FuncT, typename ...Args>
inline decltype(auto) execute(FuncT &&func, Args&&... args)¶ when chaining together operations, this enables executing a function inside the chain
-
this_type &push()¶
push components into call-stack storage
-
this_type &pop()¶
pop components off call-stack storage
-
template<typename ...Args>
this_type &start(Args&&... args)¶ invoke start member function on all components
-
template<typename ...Args>
this_type &stop(Args&&... args)¶ invoke stop member function on all components
-
template<typename ...Args>
this_type &assemble(Args&&... args)¶ invoke assemble member function on all components to determine if measurements can be derived from other components in a bundle
-
template<typename ...Args>
this_type &derive(Args&&... args)¶ invoke derive member function on all components to extract measurements from other components in the bundle
-
template<typename ...Args>
this_type &mark(Args&&... args)¶ invoke mark member function on all components
-
template<typename ...Args>
this_type &mark_begin(Args&&... args)¶ invoke mark_begin member function on all components
-
template<typename ...Args>
this_type &mark_end(Args&&... args)¶ invoke mark_begin member function on all components
-
template<typename ...Args>
this_type &store(Args&&... args)¶ invoke store member function on all components
-
template<typename ...Args>
this_type &audit(Args&&... args)¶ invoke audit member function on all components
-
template<typename ...Args>
this_type &set_scope(Args&&... args)¶ modify the scope of the push operation
-
template<template<typename> class OpT, typename ...Args>
this_type &invoke(Args&&... _args)¶ invoke the provided operation on all components
-
template<typename ...Args>
inline auto get(Args&&... args) const¶ invoke get member function on all components to get their data
-
template<typename ...Args>
inline auto get_labeled(Args&&... args) const¶ invoke get member function on all components to get data labeled with component name
-
scope::transient_destructor get_scope_destructor()¶
returns a stack-object for calling stop