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 ...
Tp
>
classbundle
¶ Static polymorphic base class for component bundlers.
-
template<typename ...
Types
>
classauto_base_bundle
¶ Static polymorphic base class for automatic start/stop bundlers.
-
template<typename
Tag
, typenameBundleT
, typenameTupleT
>
classtim
::
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 ...
Tp
>
this_type &push
(mpl::piecewise_ignore<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 &start
(mpl::piecewise_ignore<Tp...>, Args&&...)¶ variant of start() which gets applied to non-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
-
template<typename ...
Tp
, typename ...Args
>
this_type &stop
(mpl::piecewise_ignore<Tp...>, Args&&...)¶ variant of stop() which gets applied to non-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<typename ...
Args
>
this_type &update_statistics
(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<template<typename> class
OpT
, typename ...Tp
, typename ...Args
>
this_type &invoke
(mpl::piecewise_ignore<Tp...>, Args&&... _args)¶ generic member function for invoking user-provided operations on all types that are not listed
- Template Parameters
OpT – Operation struct
-
template<typename ...
Args
>
autoget
(Args&&...) const¶ returns a tuple of invoking get() on all the components
-
template<typename ...
Args
>
autoget_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
-
template<typename
U
, typenameFuncT
>
decltype(auto)get
(FuncT&&)¶ get a component from the bundle and apply function if the pointer is valid
-
template<typename
U
, typenameFuncT
>
decltype(auto)get
(FuncT&&) 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
>
autoget_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
, typenameT
= 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
, typenameT
= 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
, typenameT
= remove_pointer_decay_t<U>, typename ...Args
>
inline boolinit
(Args&&... _args, enable_if_t<can_stack_init<T>(), int> = 0)¶ try to re-create a stack object with provided arguments
-
template<typename
U
, typenameT
= remove_pointer_decay_t<U>, typename ...Args
>
inline boolinit
(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
, typenameT
= 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
, typenameFunc
, 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
, typenameFunc
, 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
, typenameFunc
, 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 boolis_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 boolcan_stack_init
()¶ Query at compile-time whether initialization can occur on the stack.
-
template<typename
U
>
static inline constexpr boolcan_heap_init
()¶ Query at compile-time whether initialization can occur on the heap.
-
template<typename
U
>
static inline constexpr boolcan_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 boolcan_init
()¶ Query at compile-time whether the specified type can be initialized.
-
template<typename
U
>
static inline constexpr boolwill_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 boolwill_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
, typenameT
= remove_pointer_decay_t<U>, enable_if_t<trait::is_available<T>::value> = 0>
static inline constexpr boolis_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
, typenameT
= remove_pointer_decay_t<U>, enable_if_t<!trait::is_available<T>::value> = 0>
static inline constexpr boolis_constructible
()¶ Return false if the type is not available.
-
template<typename
U
, typenameT
= remove_pointer_decay_t<U>, enable_if_t<trait::is_available<T>::value> = 0>
static inline constexpr boolis_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
, typenameT
= remove_pointer_decay_t<U>, enable_if_t<!trait::is_available<T>::value> = 0>
static inline constexpr boolis_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
, typenameCompT
, typenameBundleT
>
classtim
::
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
-
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 autoget
(Args&&... args) const¶ invoke get member function on all components to get their data
-
template<typename ...
Args
>
inline autoget_labeled
(Args&&... args) const¶ invoke get member function on all components to get data labeled with component name
-
bool
enabled
() const¶ check whether enabled
-
bool
report_at_exit
() const¶ check whether reporting at exit
-
bool
store
() const¶ check whether storing data
-
int64_t
laps
() const¶ get the number of laps
-
uint64_t
hash
() const¶ get the key hash
-
std::string
key
() const¶ get the key
-
data_type &
data
()¶ get tuple data
-
const data_type &
data
() const¶ get tuple data
-
this_type &
report_at_exit
(bool val)¶ write to stdout during destruction
-
this_type &
rekey
(string_view_cref_t _key)¶ update key
-
this_type &
rekey
(captured_location_t _loc)¶ update key
-
this_type &
rekey
(uint64_t _hash)¶ update key
-
scope::transient_destructor
get_scope_destructor
()¶ returns a stack-object for calling stop