timemory 3.3.0
Modular C++ Toolkit for Performance Analysis and Logging. Profiling API and Tools for C, C++, CUDA, Fortran, and Python. The C++ template API is essentially a framework to creating tools: it is designed to provide a unifying interface for recording various performance measurements alongside data logging and interfaces to other tools.
generic.hpp
Go to the documentation of this file.
1// MIT License
2//
3// Copyright (c) 2020, The Regents of the University of California,
4// through Lawrence Berkeley National Laboratory (subject to receipt of any
5// required approvals from the U.S. Dept. of Energy). All rights reserved.
6//
7// Permission is hereby granted, free of charge, to any person obtaining a copy
8// of this software and associated documentation files (the "Software"), to deal
9// in the Software without restriction, including without limitation the rights
10// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11// copies of the Software, and to permit persons to whom the Software is
12// furnished to do so, subject to the following conditions:
13//
14// The above copyright notice and this permission notice shall be included in all
15// copies or substantial portions of the Software.
16//
17// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23// SOFTWARE.
24
25/**
26 * \file timemory/operations/types/generic.hpp
27 * \brief Definition for various functions for generic in operations
28 */
29
30#pragma once
31
35
36#include <type_traits>
37
38namespace tim
39{
40namespace operation
41{
42//
43//--------------------------------------------------------------------------------------//
44//
45///
46/// \struct tim::operation::generic_operator
47/// \brief This operation class is similar to pointer_operator but can handle non-pointer
48/// types
49///
50//
51//--------------------------------------------------------------------------------------//
52//
53template <typename Tp, typename Op, typename Tag>
55{
56 using type = std::remove_pointer_t<Tp>;
57
59
60private:
61 template <typename Up>
62 static bool check()
63 {
64 using U = std::decay_t<std::remove_pointer_t<Up>>;
65 static_assert(std::is_same<U, type>::value, "Error! Up != type");
66
67 // this is commented out because generic_operator does work with non-component
68 // types
69 // static_assert(
70 // concepts::is_component<U>::value,
71 // "Error! Applying generic_operator on a type that is not a component");
72
73 constexpr bool supports_runtime_checks = trait::runtime_enabled<Tp>::value &&
76
77 // if runtime checks are enabled and type or tag is not enabled, return false
78 if(supports_runtime_checks &&
80 return false;
81
82 // if supports_runtime_checks if false, compiler should optimize away this entire
83 // function call because it will be known at compile time that this function will
84 // always returns true
85 return true;
86 }
87
88 template <typename Up>
89 static bool is_invalid(Up& obj)
90 {
91 // use a type-list for checking multiple types
92 using passthrough_t =
96 return false;
98 }
99
100 //----------------------------------------------------------------------------------//
101 //
102 // Pointers
103 //
104 //----------------------------------------------------------------------------------//
105public:
106 template <typename Up, typename... Args, typename Rp = type,
109 TIMEMORY_INLINE explicit generic_operator(Up obj, Args&&... args)
110 {
111 // rely on compiler to optimize this away if supports_runtime_checks if false
112 if(!check<Up>())
113 return;
114
115 // check the component is valid before applying
116 if(obj && !is_invalid(*obj))
117 sfinae(obj, 0, 0, 0, std::forward<Args>(args)...);
118 }
119
120 template <typename Up, typename... Args, typename Rp = type,
123 TIMEMORY_INLINE explicit generic_operator(Up obj, Up rhs, Args&&... args)
124 {
125 // rely on compiler to optimize this away if supports_runtime_checks if false
126 if(!check<Up>())
127 return;
128
129 // check the components are valid before applying
130 if(obj && rhs && !is_invalid(*obj) && !is_invalid(*rhs))
131 sfinae(obj, rhs, 0, 0, 0, std::forward<Args>(args)...);
132 }
133
134 //----------------------------------------------------------------------------------//
135private:
136 template <typename Up, typename... Args>
137 TIMEMORY_INLINE auto pointer_sfinae(Up obj, int, int, int, Args&&... args)
138 -> decltype(Op(*obj, std::forward<Args>(args)...), void())
139 {
140 Op{ *obj, std::forward<Args>(args)... };
141 }
142
143 template <typename Up, typename... Args,
144 enable_if_t<std::is_default_constructible<Tp>::value> = 0>
145 TIMEMORY_INLINE auto pointer_sfinae(Up obj, int, int, long, Args&&... args)
146 -> decltype(std::declval<Op>()(*obj, std::forward<Args>(args)...), void())
147 {
148 Op{}(*obj, std::forward<Args>(args)...);
149 }
150
151 template <typename Up, typename... Args>
152 TIMEMORY_INLINE auto pointer_sfinae(Up obj, int, long, long, Args&&...)
153 -> decltype(Op{ *obj }, void())
154 {
155 Op{ *obj };
156 }
157
158 template <typename Up, typename... Args>
159 TIMEMORY_INLINE void pointer_sfinae(Up, long, long, long, Args&&...)
160 {}
161
162 //----------------------------------------------------------------------------------//
163
164 template <typename Up, typename... Args>
165 TIMEMORY_INLINE auto pointer_sfinae(Up obj, Up rhs, int, int, int, Args&&... args)
166 -> decltype(Op(*obj, *rhs, std::forward<Args>(args)...), void())
167 {
168 Op{ *obj, *rhs, std::forward<Args>(args)... };
169 }
170
171 template <typename Up, typename... Args,
172 enable_if_t<std::is_default_constructible<Tp>::value> = 0>
173 TIMEMORY_INLINE auto pointer_sfinae(Up obj, Up rhs, int, int, long, Args&&... args)
174 -> decltype(std::declval<Op>()(*obj, *rhs, std::forward<Args>(args)...), void())
175 {
176 Op{}(*obj, *rhs, std::forward<Args>(args)...);
177 }
178
179 template <typename Up, typename... Args>
180 TIMEMORY_INLINE auto pointer_sfinae(Up obj, Up rhs, int, long, long, Args&&...)
181 -> decltype(Op(*obj, *rhs), void())
182 {
183 Op{ *obj, *rhs };
184 }
185
186 template <typename Up, typename... Args>
187 TIMEMORY_INLINE void pointer_sfinae(Up, Up, long, long, long, Args&&...)
188 {}
189
190 //----------------------------------------------------------------------------------//
191 //
192 // References
193 //
194 //----------------------------------------------------------------------------------//
195public:
196 template <typename Up, typename... Args, typename Rp = Tp,
197 enable_if_t<trait::is_available<Rp>::value, int> = 0,
198 enable_if_t<!std::is_pointer<Up>::value, int> = 0>
199 TIMEMORY_INLINE explicit generic_operator(Up& obj, Args&&... args)
200 {
201 // rely on compiler to optimize this away if supports_runtime_checks if false
202 if(!check<Up>())
203 return;
204
205 // check the component is valid before applying
206 if(!is_invalid(obj))
207 sfinae(obj, 0, 0, 0, std::forward<Args>(args)...);
208 }
209
210 template <typename Up, typename... Args, typename Rp = Tp,
213 TIMEMORY_INLINE explicit generic_operator(Up& obj, Up& rhs, Args&&... args)
214 {
215 // rely on compiler to optimize this away if supports_runtime_checks if false
216 if(!check<Up>())
217 return;
218
219 // check the components are valid before applying
220 if(!is_invalid(obj) && !is_invalid(rhs))
221 sfinae(obj, rhs, 0, 0, 0, std::forward<Args>(args)...);
222 }
223
224 //----------------------------------------------------------------------------------//
225private:
226 template <typename Up, typename... Args>
227 TIMEMORY_INLINE auto sfinae(Up& obj, int, int, int, Args&&... args)
228 -> decltype(Op(obj, std::forward<Args>(args)...), void())
229 {
230 Op{ obj, std::forward<Args>(args)... };
231 }
232
233 template <typename Up, typename... Args,
234 enable_if_t<std::is_default_constructible<Tp>::value> = 0>
235 TIMEMORY_INLINE auto sfinae(Up& obj, int, int, long, Args&&... args)
236 -> decltype(std::declval<Op>()(obj, std::forward<Args>(args)...), void())
237 {
238 Op{}(obj, std::forward<Args>(args)...);
239 }
240
241 template <typename Up, typename... Args>
242 TIMEMORY_INLINE auto sfinae(Up& obj, int, long, long, Args&&...)
243 -> decltype(Op{ obj }, void())
244 {
245 Op{ obj };
246 }
247
248 template <typename Up, typename... Args,
249 enable_if_t<std::is_pointer<Up>::value, int> = 0>
250 TIMEMORY_INLINE void sfinae(Up& obj, long, long, long, Args&&... args)
251 {
252 // some operations want a raw pointer, e.g. generic_deleter
253 pointer_sfinae(obj, 0, 0, 0, std::forward<Args>(args)...);
254 }
255
256 template <typename Up, typename... Args,
257 enable_if_t<!std::is_pointer<Up>::value, int> = 0>
258 TIMEMORY_INLINE void sfinae(Up&, long, long, long, Args&&...)
259 {}
260
261 //----------------------------------------------------------------------------------//
262
263 template <typename Up, typename... Args>
264 TIMEMORY_INLINE auto sfinae(Up& obj, Up& rhs, int, int, int, Args&&... args)
265 -> decltype(Op(obj, rhs, std::forward<Args>(args)...), void())
266 {
267 Op{ obj, rhs, std::forward<Args>(args)... };
268 }
269
270 template <typename Up, typename... Args,
271 enable_if_t<std::is_default_constructible<Tp>::value> = 0>
272 TIMEMORY_INLINE auto sfinae(Up& obj, Up& rhs, int, int, long, Args&&... args)
273 -> decltype(std::declval<Op>()(obj, rhs, std::forward<Args>(args)...), void())
274 {
275 Op{}(obj, rhs, std::forward<Args>(args)...);
276 }
277
278 template <typename Up, typename... Args>
279 TIMEMORY_INLINE auto sfinae(Up& obj, Up& rhs, int, long, long, Args&&...)
280 -> decltype(Op(obj, rhs), void())
281 {
282 Op{ obj, rhs };
283 }
284
285 template <typename Up, typename... Args,
286 enable_if_t<std::is_pointer<Up>::value, int> = 0>
287 TIMEMORY_INLINE void sfinae(Up& obj, Up& rhs, long, long, long, Args&&... args)
288 {
289 // some operations want a raw pointer, e.g. generic_deleter
290 pointer_sfinae(obj, rhs, 0, 0, 0, std::forward<Args>(args)...);
291 }
292
293 template <typename Up, typename... Args,
294 enable_if_t<!std::is_pointer<Up>::value, int> = 0>
295 TIMEMORY_INLINE void sfinae(Up&, Up&, long, long, long, Args&&...)
296 {}
297
298 //----------------------------------------------------------------------------------//
299 //
300 // Not available
301 //
302 //----------------------------------------------------------------------------------//
303public:
304 // if the type is not available, never do anything
305 template <typename Up, typename... Args, typename Rp = Tp,
306 enable_if_t<!trait::is_available<Rp>::value, int> = 0>
307 TIMEMORY_INLINE generic_operator(Up&, Args&&...)
308 {}
309};
310//
311//--------------------------------------------------------------------------------------//
312//
313//
314//
315//--------------------------------------------------------------------------------------//
316//
317template <typename Tp>
319{
320 using type = Tp;
321
323
324 TIMEMORY_INLINE explicit generic_deleter(type*& obj)
325 {
326 DEBUG_PRINT_HERE("%s %s :: %p", "deleting pointer lvalue",
327 demangle<type>().c_str(), (void*) obj);
328 delete obj;
329 obj = nullptr;
330 }
331
332 template <typename Up, enable_if_t<std::is_pointer<Up>::value, int> = 0>
333 TIMEMORY_INLINE explicit generic_deleter(Up&& obj)
334 {
335 DEBUG_PRINT_HERE("%s %s :: %p", "deleting pointer rvalue",
336 demangle<type>().c_str(), (void*) obj);
337 delete obj;
338 std::ref(std::forward<Up>(obj)).get() = nullptr;
339 }
340
341 template <typename... Deleter>
342 TIMEMORY_INLINE explicit generic_deleter(std::unique_ptr<type, Deleter...>& obj)
343 {
344 DEBUG_PRINT_HERE("%s %s :: %p", "deleting unique_ptr", demangle<type>().c_str(),
345 (void*) obj.get());
346 obj.reset();
347 }
348
349 TIMEMORY_INLINE explicit generic_deleter(std::shared_ptr<type> obj)
350 {
351 DEBUG_PRINT_HERE("%s %s :: %p", "deleting shared_ptr", demangle<type>().c_str(),
352 (void*) obj.get());
353 obj.reset();
354 }
355
356 template <typename Up, enable_if_t<!std::is_pointer<Up>::value, int> = 0>
357 TIMEMORY_INLINE explicit generic_deleter(Up&&)
358 {}
359};
360//
361//--------------------------------------------------------------------------------------//
362//
363//
364//
365//--------------------------------------------------------------------------------------//
366//
367template <typename Tp>
369{
370 using type = Tp;
371
373
374 template <typename Up, enable_if_t<std::is_pointer<Up>::value, int> = 0>
375 TIMEMORY_INLINE explicit generic_counter(const Up& obj, uint64_t& count)
376 {
377 // static_assert(std::is_same<Up, type>::value, "Error! Up != type");
378 count += (trait::runtime_enabled<type>::get() && obj) ? 1 : 0;
379 }
380
381 template <typename Up, enable_if_t<!std::is_pointer<Up>::value, int> = 0>
382 TIMEMORY_INLINE explicit generic_counter(const Up&, uint64_t& count)
383 {
384 // static_assert(std::is_same<Up, type>::value, "Error! Up != type");
385 count += (trait::runtime_enabled<type>::get()) ? 1 : 0;
386 }
387};
388//
389//--------------------------------------------------------------------------------------//
390//
391} // namespace operation
392} // namespace tim
Definition: kokkosp.cpp:39
typename std::enable_if< B, T >::type enable_if_t
Alias template for enable_if.
Definition: types.hpp:190
typename impl::is_one_of< Tp, Types > is_one_of
check if type is in expansion
Definition: types.hpp:777
lightweight tuple-alternative for meta-programming logic
Definition: types.hpp:233
The declaration for the types for operations without definitions.
Include the macros for operations.
Declare the operations types.
TIMEMORY_DELETED_OBJECT(generic_counter) template< typename Up
generic_deleter(std::unique_ptr< type, Deleter... > &obj)
Definition: generic.hpp:342
TIMEMORY_DELETED_OBJECT(generic_deleter) explicit generic_deleter(type *&obj)
Definition: generic.hpp:322
generic_deleter(std::shared_ptr< type > obj)
Definition: generic.hpp:349
This operation class is similar to pointer_operator but can handle non-pointer types.
Definition: generic.hpp:55
generic_operator(Up &obj, Up &rhs, Args &&... args)
Definition: generic.hpp:213
static bool is_invalid(Up &obj)
Definition: generic.hpp:89
generic_operator(Up &, Args &&...)
Definition: generic.hpp:307
TIMEMORY_DELETED_OBJECT(generic_operator) private
Definition: generic.hpp:58
std::remove_pointer_t< Tp > type
Definition: generic.hpp:56
generic_operator(Up &obj, Args &&... args)
Definition: generic.hpp:199
generic_operator(Up obj, Up rhs, Args &&... args)
Definition: generic.hpp:123
generic_operator(Up obj, Args &&... args)
Definition: generic.hpp:109
This operation attempts to call a member function which provides whether or not the component is in a...
Definition: types.hpp:673
trait that signifies that an implementation is enabled at runtime. The value returned from get() is f...
static bool get(enable_if_t< is_available< U >::value &&get_value< U >(), int >=0)
GET specialization if component is available.
#define DEBUG_PRINT_HERE(...)
Definition: macros.hpp:168