Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-30 08:46:19

0001 /*
0002     Copyright (c) 2005-2023 Intel Corporation
0003 
0004     Licensed under the Apache License, Version 2.0 (the "License");
0005     you may not use this file except in compliance with the License.
0006     You may obtain a copy of the License at
0007 
0008         http://www.apache.org/licenses/LICENSE-2.0
0009 
0010     Unless required by applicable law or agreed to in writing, software
0011     distributed under the License is distributed on an "AS IS" BASIS,
0012     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013     See the License for the specific language governing permissions and
0014     limitations under the License.
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 // An internal implementation of void_t, which can be used in SFINAE contexts
0035 template <typename...>
0036 struct void_impl {
0037     using type = void;
0038 }; // struct void_impl
0039 
0040 template <typename... Args>
0041 using void_t = typename void_impl<Args...>::type;
0042 
0043 // Generic SFINAE helper for expression checks, based on the idea demonstrated in ISO C++ paper n4502
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 //! A template to select either 32-bit or 64-bit constant as compile time, depending on machine word size.
0058 template <unsigned u, unsigned long long ull >
0059 struct select_size_t_constant {
0060     // Explicit cast is needed to avoid compiler warnings about possible truncation.
0061     // The value of the right size,   which is selected by ?:, is anyway not truncated or promoted.
0062     static const std::size_t value = static_cast<std::size_t>((sizeof(std::size_t)==sizeof(u)) ? u : ull);
0063 };
0064 
0065 // TODO: do we really need it?
0066 //! Cast between unrelated pointer types.
0067 /** This method should be used sparingly as a last resort for dealing with
0068   situations that inherently break strict ISO C++ aliasing rules. */
0069 // T is a pointer type because it will be explicitly provided by the programmer as a template argument;
0070 // U is a referent type to enable the compiler to check that "ptr" is a pointer, deducing U in the process.
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 //! Pads type T to fill out to a multiple of cache line size.
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 /* __TBB_CPP14_INTEGER_SEQUENCE_PRESENT */
0108 
0109 #if __TBB_CPP17_LOGICAL_OPERATIONS_PRESENT
0110 using std::conjunction;
0111 using std::disjunction;
0112 #else // __TBB_CPP17_LOGICAL_OPERATIONS_PRESENT
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 // __TBB_CPP17_LOGICAL_OPERATIONS_PRESENT
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 // alloc_value_type should be checked first, because it can be used in other checks
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 // Template class in which the "type" determines the type of the element number N in pack Args
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 }; // class raii_guard
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 }; // struct try_call_proxy
0235 
0236 // Template helper function for API
0237 // try_call(lambda1).on_exception(lambda2)
0238 // Executes lambda1 and if it throws an exception - executes lambda2
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 // __TBB_CPP17_IS_SWAPPABLE_PRESENT
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 // Workaround for VS2015: it fails to instantiate noexcept(...) inside std::integral_constant.
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 // __TBB_CPP17_IS_SWAPPABLE_PRESENT
0275 
0276 //! Allows to store a function parameter pack as a variable and later pass it to another function
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     // Friend front-end functions
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     // Ideally, ref-qualified non-static methods would be used,
0292     // but that would greatly reduce the set of compilers where it works.
0293     template< typename Ret, typename F, typename... Preceding >
0294     static Ret call(F&& f, const pack_type& /*pack*/, 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&& /*pack*/, 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     // Since lifetime of original values is out of control, copies should be made.
0310     // Thus references should be stripped away from the deduced type.
0311     typename std::decay<T>::type leftmost_value;
0312 
0313     // Here rvalue references act in the same way as forwarding references,
0314     // as long as class template parameters were deduced via forwarding references.
0315     stored_pack(T&& t, Types&&... types)
0316     : pack_remainder(std::forward<Types>(types)...), leftmost_value(std::forward<T>(t)) {}
0317 
0318     // Friend front-end functions
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 //! Calls the given function with arguments taken from a stored_pack
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 // A structure with the value which is equal to Trait::value
0357 // but can be used in the immediate context due to parameter T
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 // Detects the argument type of callable, works for callable with one argument.
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 } // inline namespace d0
0400 } // namespace detail
0401 } // namespace tbb
0402 
0403 #endif // __TBB_detail__template_helpers_H