File indexing completed on 2025-07-30 08:46:19
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #ifndef __TBB_detail__template_helpers_H
0018 #define __TBB_detail__template_helpers_H
0019
0020 #include "_utils.h"
0021 #include "_config.h"
0022
0023 #include <cstddef>
0024 #include <cstdint>
0025 #include <utility>
0026 #include <type_traits>
0027 #include <memory>
0028 #include <iterator>
0029
0030 namespace tbb {
0031 namespace detail {
0032 inline namespace d0 {
0033
0034
0035 template <typename...>
0036 struct void_impl {
0037 using type = void;
0038 };
0039
0040 template <typename... Args>
0041 using void_t = typename void_impl<Args...>::type;
0042
0043
0044 template <typename T, typename, template <typename> class... Checks>
0045 struct supports_impl {
0046 using type = std::false_type;
0047 };
0048
0049 template <typename T, template <typename> class... Checks>
0050 struct supports_impl<T, void_t<Checks<T>...>, Checks...> {
0051 using type = std::true_type;
0052 };
0053
0054 template <typename T, template <typename> class... Checks>
0055 using supports = typename supports_impl<T, void, Checks...>::type;
0056
0057
0058 template <unsigned u, unsigned long long ull >
0059 struct select_size_t_constant {
0060
0061
0062 static const std::size_t value = static_cast<std::size_t>((sizeof(std::size_t)==sizeof(u)) ? u : ull);
0063 };
0064
0065
0066
0067
0068
0069
0070
0071 template<typename T, typename U>
0072 inline T punned_cast( U* ptr ) {
0073 std::uintptr_t x = reinterpret_cast<std::uintptr_t>(ptr);
0074 return reinterpret_cast<T>(x);
0075 }
0076
0077 template<class T, size_t S, size_t R>
0078 struct padded_base : T {
0079 char pad[S - R];
0080 };
0081 template<class T, size_t S> struct padded_base<T, S, 0> : T {};
0082
0083
0084 template<class T, size_t S = max_nfs_size>
0085 struct padded : padded_base<T, S, sizeof(T) % S> {};
0086
0087 #if __TBB_CPP14_INTEGER_SEQUENCE_PRESENT
0088
0089 using std::index_sequence;
0090 using std::make_index_sequence;
0091
0092 #else
0093
0094 template<std::size_t... S> class index_sequence {};
0095
0096 template<std::size_t N, std::size_t... S>
0097 struct make_index_sequence_impl : make_index_sequence_impl < N - 1, N - 1, S... > {};
0098
0099 template<std::size_t... S>
0100 struct make_index_sequence_impl <0, S...> {
0101 using type = index_sequence<S...>;
0102 };
0103
0104 template<std::size_t N>
0105 using make_index_sequence = typename make_index_sequence_impl<N>::type;
0106
0107 #endif
0108
0109 #if __TBB_CPP17_LOGICAL_OPERATIONS_PRESENT
0110 using std::conjunction;
0111 using std::disjunction;
0112 #else
0113
0114 template <typename...>
0115 struct conjunction : std::true_type {};
0116
0117 template <typename First, typename... Args>
0118 struct conjunction<First, Args...>
0119 : std::conditional<bool(First::value), conjunction<Args...>, First>::type {};
0120
0121 template <typename T>
0122 struct conjunction<T> : T {};
0123
0124 template <typename...>
0125 struct disjunction : std::false_type {};
0126
0127 template <typename First, typename... Args>
0128 struct disjunction<First, Args...>
0129 : std::conditional<bool(First::value), First, disjunction<Args...>>::type {};
0130
0131 template <typename T>
0132 struct disjunction<T> : T {};
0133
0134 #endif
0135
0136 template <typename Iterator>
0137 using iterator_value_t = typename std::iterator_traits<Iterator>::value_type;
0138
0139 template <typename Iterator>
0140 using iterator_key_t = typename std::remove_const<typename iterator_value_t<Iterator>::first_type>::type;
0141
0142 template <typename Iterator>
0143 using iterator_mapped_t = typename iterator_value_t<Iterator>::second_type;
0144
0145 template <typename Iterator>
0146 using iterator_alloc_pair_t = std::pair<typename std::add_const<iterator_key_t<Iterator>>::type,
0147 iterator_mapped_t<Iterator>>;
0148
0149 template <typename A> using alloc_value_type = typename A::value_type;
0150 template <typename A> using alloc_ptr_t = typename std::allocator_traits<A>::pointer;
0151 template <typename A> using has_allocate = decltype(std::declval<alloc_ptr_t<A>&>() = std::declval<A>().allocate(0));
0152 template <typename A> using has_deallocate = decltype(std::declval<A>().deallocate(std::declval<alloc_ptr_t<A>>(), 0));
0153
0154
0155 template <typename T>
0156 using is_allocator = supports<T, alloc_value_type, has_allocate, has_deallocate>;
0157
0158 #if __TBB_CPP17_DEDUCTION_GUIDES_PRESENT
0159 template <typename T>
0160 inline constexpr bool is_allocator_v = is_allocator<T>::value;
0161 #endif
0162
0163
0164 template <std::size_t N, typename... Args>
0165 struct pack_element {
0166 using type = void;
0167 };
0168
0169 template <std::size_t N, typename T, typename... Args>
0170 struct pack_element<N, T, Args...> {
0171 using type = typename pack_element<N-1, Args...>::type;
0172 };
0173
0174 template <typename T, typename... Args>
0175 struct pack_element<0, T, Args...> {
0176 using type = T;
0177 };
0178
0179 template <std::size_t N, typename... Args>
0180 using pack_element_t = typename pack_element<N, Args...>::type;
0181
0182 template <typename Func>
0183 class raii_guard {
0184 public:
0185 static_assert(
0186 std::is_nothrow_copy_constructible<Func>::value &&
0187 std::is_nothrow_move_constructible<Func>::value,
0188 "Throwing an exception during the Func copy or move construction cause an unexpected behavior."
0189 );
0190
0191 raii_guard( Func f ) noexcept : my_func(f), is_active(true) {}
0192
0193 raii_guard( raii_guard&& g ) noexcept : my_func(std::move(g.my_func)), is_active(g.is_active) {
0194 g.is_active = false;
0195 }
0196
0197 ~raii_guard() {
0198 if (is_active) {
0199 my_func();
0200 }
0201 }
0202
0203 void dismiss() {
0204 is_active = false;
0205 }
0206 private:
0207 Func my_func;
0208 bool is_active;
0209 };
0210
0211 template <typename Func>
0212 raii_guard<Func> make_raii_guard( Func f ) {
0213 return raii_guard<Func>(f);
0214 }
0215
0216 template <typename Body>
0217 struct try_call_proxy {
0218 try_call_proxy( Body b ) : body(b) {}
0219
0220 template <typename OnExceptionBody>
0221 void on_exception( OnExceptionBody on_exception_body ) {
0222 auto guard = make_raii_guard(on_exception_body);
0223 body();
0224 guard.dismiss();
0225 }
0226
0227 template <typename OnCompletionBody>
0228 void on_completion(OnCompletionBody on_completion_body) {
0229 auto guard = make_raii_guard(on_completion_body);
0230 body();
0231 }
0232
0233 Body body;
0234 };
0235
0236
0237
0238
0239 template <typename Body>
0240 try_call_proxy<Body> try_call( Body b ) {
0241 return try_call_proxy<Body>(b);
0242 }
0243
0244 #if __TBB_CPP17_IS_SWAPPABLE_PRESENT
0245 using std::is_nothrow_swappable;
0246 using std::is_swappable;
0247 #else
0248 namespace is_swappable_detail {
0249 using std::swap;
0250
0251 template <typename T>
0252 using has_swap = decltype(swap(std::declval<T&>(), std::declval<T&>()));
0253
0254 #if _MSC_VER && _MSC_VER <= 1900 && !__INTEL_COMPILER
0255
0256 template <typename T>
0257 struct noexcept_wrapper {
0258 static const bool value = noexcept(swap(std::declval<T&>(), std::declval<T&>()));
0259 };
0260 template <typename T>
0261 struct is_nothrow_swappable_impl : std::integral_constant<bool, noexcept_wrapper<T>::value> {};
0262 #else
0263 template <typename T>
0264 struct is_nothrow_swappable_impl : std::integral_constant<bool, noexcept(swap(std::declval<T&>(), std::declval<T&>()))> {};
0265 #endif
0266 }
0267
0268 template <typename T>
0269 struct is_swappable : supports<T, is_swappable_detail::has_swap> {};
0270
0271 template <typename T>
0272 struct is_nothrow_swappable
0273 : conjunction<is_swappable<T>, is_swappable_detail::is_nothrow_swappable_impl<T>> {};
0274 #endif
0275
0276
0277 template< typename... Types >
0278 struct stored_pack;
0279
0280 template<>
0281 struct stored_pack<>
0282 {
0283 using pack_type = stored_pack<>;
0284 stored_pack() {}
0285
0286
0287 template< typename F, typename Pack > friend void call(F&& f, Pack&& p);
0288 template< typename Ret, typename F, typename Pack > friend Ret call_and_return(F&& f, Pack&& p);
0289
0290 protected:
0291
0292
0293 template< typename Ret, typename F, typename... Preceding >
0294 static Ret call(F&& f, const pack_type& , Preceding&&... params) {
0295 return std::forward<F>(f)(std::forward<Preceding>(params)...);
0296 }
0297 template< typename Ret, typename F, typename... Preceding >
0298 static Ret call(F&& f, pack_type&& , Preceding&&... params) {
0299 return std::forward<F>(f)(std::forward<Preceding>(params)...);
0300 }
0301 };
0302
0303 template< typename T, typename... Types >
0304 struct stored_pack<T, Types...> : stored_pack<Types...>
0305 {
0306 using pack_type = stored_pack<T, Types...>;
0307 using pack_remainder = stored_pack<Types...>;
0308
0309
0310
0311 typename std::decay<T>::type leftmost_value;
0312
0313
0314
0315 stored_pack(T&& t, Types&&... types)
0316 : pack_remainder(std::forward<Types>(types)...), leftmost_value(std::forward<T>(t)) {}
0317
0318
0319 template< typename F, typename Pack > friend void call(F&& f, Pack&& p);
0320 template< typename Ret, typename F, typename Pack > friend Ret call_and_return(F&& f, Pack&& p);
0321
0322 protected:
0323 template< typename Ret, typename F, typename... Preceding >
0324 static Ret call(F&& f, pack_type& pack, Preceding&&... params) {
0325 return pack_remainder::template call<Ret>(
0326 std::forward<F>(f), static_cast<pack_remainder&>(pack),
0327 std::forward<Preceding>(params)... , pack.leftmost_value
0328 );
0329 }
0330
0331 template< typename Ret, typename F, typename... Preceding >
0332 static Ret call(F&& f, pack_type&& pack, Preceding&&... params) {
0333 return pack_remainder::template call<Ret>(
0334 std::forward<F>(f), static_cast<pack_remainder&&>(pack),
0335 std::forward<Preceding>(params)... , std::move(pack.leftmost_value)
0336 );
0337 }
0338 };
0339
0340
0341 template< typename F, typename Pack >
0342 void call(F&& f, Pack&& p) {
0343 std::decay<Pack>::type::template call<void>(std::forward<F>(f), std::forward<Pack>(p));
0344 }
0345
0346 template< typename Ret, typename F, typename Pack >
0347 Ret call_and_return(F&& f, Pack&& p) {
0348 return std::decay<Pack>::type::template call<Ret>(std::forward<F>(f), std::forward<Pack>(p));
0349 }
0350
0351 template< typename... Types >
0352 stored_pack<Types...> save_pack(Types&&... types) {
0353 return stored_pack<Types...>(std::forward<Types>(types)...);
0354 }
0355
0356
0357
0358 template <typename Trait, typename T>
0359 struct dependent_bool : std::integral_constant<bool, bool(Trait::value)> {};
0360
0361 template <typename Callable>
0362 struct body_arg_detector;
0363
0364 template <typename Callable, typename ReturnType, typename Arg>
0365 struct body_arg_detector<ReturnType(Callable::*)(Arg)> {
0366 using arg_type = Arg;
0367 };
0368
0369 template <typename Callable, typename ReturnType, typename Arg>
0370 struct body_arg_detector<ReturnType(Callable::*)(Arg) const> {
0371 using arg_type = Arg;
0372 };
0373
0374 template <typename Callable>
0375 struct argument_detector;
0376
0377 template <typename Callable>
0378 struct argument_detector {
0379 using type = typename body_arg_detector<decltype(&Callable::operator())>::arg_type;
0380 };
0381
0382 template <typename ReturnType, typename Arg>
0383 struct argument_detector<ReturnType(*)(Arg)> {
0384 using type = Arg;
0385 };
0386
0387
0388 template <typename Callable>
0389 using argument_type_of = typename argument_detector<typename std::decay<Callable>::type>::type;
0390
0391 template <typename T>
0392 struct type_identity {
0393 using type = T;
0394 };
0395
0396 template <typename T>
0397 using type_identity_t = typename type_identity<T>::type;
0398
0399 }
0400 }
0401 }
0402
0403 #endif