Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-19 09:13:36

0001 #ifndef META_UTILS_H
0002 #define META_UTILS_H
0003 
0004 #include <tuple>
0005 
0006 #define CHECK_TEST_RES(pred) MetaUtils::check(pred, __PRETTY_FUNCTION__)
0007 
0008 /// @todo Merge with Traits.h
0009 namespace MetaUtils {
0010 
0011 
0012   template <class Func, std::size_t... Is>
0013   constexpr void staticForImpl(Func &&f,
0014                                std::index_sequence<Is...>) {
0015     // Use C++17 fold expressions to apply Func f
0016     // to all Is... in sequence
0017     //
0018     // Won't work on empty tuple (Binning is not intended to work with 0 dimensions).
0019     //
0020     // std::integral_constant used to encode value into type, otherwise it's not
0021     // possible to use Is inside functor as consant expression
0022     // (std::get<Is> etc. won't work)
0023 
0024     ((void)f(std::integral_constant<std::size_t, Is>()), ...);
0025   }
0026 
0027   /// @brief Used to apply functor on tuple. Calls lambda with integral constant,
0028   /// which can be used to query tuple elements via std::get<I>(), and thus iterate
0029   /// over tuple.
0030   ///
0031   /// To use, create lambda which captures every necessary variable by referenrece (or value)
0032   /// and has (auto I) parameter. Then use I inside lambda to call templated functions.
0033   template <size_t N, class Func>
0034   constexpr void staticFor(Func&& f) {
0035     staticForImpl(std::forward<Func>(f),
0036                   std::make_index_sequence<N>{});
0037   }
0038 
0039 
0040   /// @brief Logical conjuction implementation.
0041   /// @note Source: https://en.cppreference.com/w/cpp/types/conjunction#Possible_implementation
0042   template<class...> struct conjunction : std::true_type { };
0043   template<class B1> struct conjunction<B1> : B1 { };
0044   template<class B1, class... Bn>
0045   struct conjunction<B1, Bn...>
0046       : std::conditional_t<bool(B1::value), conjunction<Bn...>, B1> {};
0047 
0048   struct nonesuch {
0049     ~nonesuch() = delete;
0050     nonesuch(nonesuch const&) = delete;
0051     void operator=(nonesuch const&) = delete;
0052   };
0053 
0054   namespace operatorTraits {
0055     template<class T>
0056     using addition_assignment_t = decltype(std::declval<T&>() += std::declval<const T&>());
0057   }
0058 
0059   /// @brief Traits detection. Check's whether expression is valid for type T.
0060   /// @note Source: https://en.cppreference.com/w/cpp/experimental/is_detected#Possible_implementation
0061   namespace detail {
0062     template <class Default, class AlwaysVoid,
0063               template<class...> class Op, class... Args>
0064     struct detector {
0065       using value_t = std::false_type;
0066       using type = Default;
0067     };
0068 
0069     template <class Default, template<class...> class Op, class... Args>
0070     struct detector<Default, std::void_t<Op<Args...>>, Op, Args...> {
0071       using value_t = std::true_type;
0072       using type = Op<Args...>;
0073     };
0074 
0075   } // namespace detail
0076 
0077   /// @note Anonymous namespace to limit visibility to this file
0078   namespace {
0079     template <typename, template <typename...> class>
0080     struct is_instance_impl : public std::false_type {};
0081 
0082     template <template <typename...> class U, typename...Ts>
0083     struct is_instance_impl<U<Ts...>, U> : public std::true_type {};
0084   }
0085 
0086   /// @brief Detects if type T is an instance of template U
0087   template <typename T, template <typename ...> class U>
0088   using is_instance = is_instance_impl<std::decay_t<T>, U>;
0089 
0090   template <template<class...> class Op, class... Args>
0091   using is_detected = typename detail::detector<nonesuch, void, Op, Args...>::value_t;
0092 
0093   template <template<class...> class Op, class... Args>
0094   using detected_t = typename detail::detector<nonesuch, void, Op, Args...>::type;
0095 
0096   template <class Default, template<class...> class Op, class... Args>
0097   using detected_or = detail::detector<Default, void, Op, Args...>;
0098 
0099   template <class Expected, template<class...> class Op, class... Args>
0100   using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
0101 
0102   template< template<class...> class Op, class... Args >
0103   constexpr bool is_detected_v = is_detected<Op, Args...>::value;
0104 
0105   /// @brief checks whether if T satisfies user defined Concept
0106   ///
0107   /// @note Concept check should appear inside body of type's member function
0108   /// or outside of type, since otherwise type is considered incomplete.
0109   template <typename T, template <class U> class Concept>
0110   constexpr bool checkConcept() {
0111     return Concept<T>::checkResult::value;
0112   }
0113 
0114   inline int check(bool pred, const char* funcName) {
0115     if (pred == false)
0116       std::clog << funcName << " FAILED\n";
0117     return (int)(pred ? EXIT_SUCCESS : EXIT_FAILURE);
0118   }
0119 
0120 
0121   namespace {
0122 
0123     template <size_t, size_t>
0124     struct _tuple {
0125       template <typename T>
0126       static auto remove (const T& t) {
0127         return std::make_tuple(t);
0128       }
0129     };
0130 
0131     template <size_t N>
0132     struct _tuple<N, N> {
0133       template <typename T>
0134       static std::tuple<> remove (const T&) {
0135         return {};
0136       }
0137     };
0138 
0139     template<size_t N, typename T, size_t... Is>
0140     auto _removeTupleElement(const T& tup, std::index_sequence<Is...>) {
0141       return std::tuple_cat( _tuple<Is, N>::remove(std::get<Is>(tup))...);
0142     }
0143 
0144   }
0145 
0146   template<size_t I, typename... Ts>
0147   auto removeTupleElement(const std::tuple<Ts...>& tup) {
0148     return _removeTupleElement<I>(tup, std::make_index_sequence<sizeof...(Ts)>{});
0149   }
0150 
0151 
0152 }
0153 
0154 #endif