Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-15 09:06:26

0001 #ifndef PODIO_UTILITIES_TYPEHELPERS_H
0002 #define PODIO_UTILITIES_TYPEHELPERS_H
0003 
0004 #include <concepts>
0005 #include <iterator>
0006 #include <map>
0007 #include <ranges>
0008 #include <tuple>
0009 #include <type_traits>
0010 #include <unordered_map>
0011 #include <vector>
0012 
0013 namespace podio {
0014 // Implement the minimal feature set we need
0015 namespace det {
0016   namespace detail {
0017     template <typename DefT, typename AlwaysVoidT, template <typename...> typename Op, typename... Args>
0018     struct detector {
0019       using value_t = std::false_type;
0020       using type = DefT;
0021     };
0022 
0023     template <typename DefT, template <typename...> typename Op, typename... Args>
0024     struct detector<DefT, std::void_t<Op<Args...>>, Op, Args...> {
0025       using value_t = std::true_type;
0026       using type = Op<Args...>;
0027     };
0028   } // namespace detail
0029 
0030   struct nonesuch {
0031     ~nonesuch() = delete;
0032     nonesuch(const nonesuch&) = delete;
0033     void operator=(const nonesuch&) = delete;
0034   };
0035 
0036   template <typename DefT, template <typename...> typename Op, typename... Args>
0037   using detected_or = detail::detector<DefT, void, Op, Args...>;
0038 
0039   template <template <typename...> typename Op, typename... Args>
0040   constexpr bool is_detected_v = requires { typename Op<Args...>; };
0041 
0042 } // namespace det
0043 
0044 namespace detail {
0045 
0046   // A helper variable template that is always false, used for static_asserts
0047   // and other compile-time checks that should always fail.
0048   template <typename T>
0049   inline constexpr bool always_false = false;
0050 
0051   /// Helper struct to determine whether a given type T is in a tuple of types
0052   /// that act as a type list in this case
0053   template <typename T, typename>
0054   struct TypeInTupleHelper : std::false_type {};
0055 
0056   template <typename T, typename... Ts>
0057   struct TypeInTupleHelper<T, std::tuple<Ts...>> : std::disjunction<std::is_same<T, Ts>...> {};
0058 
0059   /// variable template for determining whether type T is in a tuple with types
0060   /// Ts
0061   template <typename T, typename Tuple>
0062   static constexpr bool isInTuple = TypeInTupleHelper<T, Tuple>::value;
0063 
0064   /// Helper struct to turn a tuple of types into a tuple of a template of types, e.g.
0065   ///
0066   /// std::tuple<int, float> -> std::tuple<std::vector<int>, std::vector<float>>
0067   /// if the passed template is std::vector
0068   ///
0069   /// @note making the template template parameter to Template variadic because
0070   /// clang will not be satisfied otherwise if we use it with, e.g. std::vector.
0071   /// This will also make root dictionary generation fail. GCC works without this
0072   /// small workaround and is standard compliant in this case, whereas clang is
0073   /// not.
0074   template <template <typename...> typename Template, typename T>
0075   struct ToTupleOfTemplateHelper;
0076 
0077   template <template <typename...> typename Template, typename... Ts>
0078   struct ToTupleOfTemplateHelper<Template, std::tuple<Ts...>> {
0079     using type = std::tuple<Template<Ts>...>;
0080   };
0081 
0082   /// Type alias to turn a tuple of types into a tuple of vector of types
0083   template <typename Tuple>
0084   using TupleOfVector = typename ToTupleOfTemplateHelper<std::vector, Tuple>::type;
0085 
0086   /// Alias template to get the type of a tuple resulting from a concatenation of
0087   /// tuples
0088   /// See: https://devblogs.microsoft.com/oldnewthing/20200622-00/?p=103900
0089   template <typename... Tuples>
0090   using TupleCatType = decltype(std::tuple_cat(std::declval<Tuples>()...));
0091 
0092   /// variable template for determining whether the type T is in the tuple of all
0093   /// types or in the tuple of all vector of the passed types
0094   template <typename T, typename Tuple>
0095   static constexpr bool isAnyOrVectorOf = isInTuple<T, TupleCatType<Tuple, TupleOfVector<Tuple>>>;
0096 
0097   /// Helper struct to extract the type from a std::vector or return the
0098   /// original type if it is not a vector. Works only for "simple" types and does
0099   /// not strip const-ness
0100   template <typename T>
0101   struct GetVectorTypeHelper {
0102     using type = T;
0103   };
0104 
0105   template <typename T>
0106   struct GetVectorTypeHelper<std::vector<T>> {
0107     using type = T;
0108   };
0109 
0110   template <typename T>
0111   using GetVectorType = typename GetVectorTypeHelper<T>::type;
0112 
0113   /// Helper struct to detect whether a type is a std::vector
0114   template <typename T>
0115   struct IsVectorHelper : std::false_type {};
0116 
0117   template <typename T>
0118   struct IsVectorHelper<std::vector<T>> : std::true_type {};
0119 
0120   /// Alias template for deciding whether the passed type T is a vector or not
0121   template <typename T>
0122   static constexpr bool isVector = IsVectorHelper<T>::value;
0123 
0124   /// Helper struct to detect whether a type is a std::map or std::unordered_map
0125   template <typename T>
0126   struct IsMapHelper : std::false_type {};
0127 
0128   template <typename K, typename V>
0129   struct IsMapHelper<std::map<K, V>> : std::true_type {};
0130 
0131   template <typename K, typename V>
0132   struct IsMapHelper<std::unordered_map<K, V>> : std::true_type {};
0133 
0134   /// Alias template for deciding whether the passed type T is a map or
0135   /// unordered_map
0136   template <typename T>
0137   static constexpr bool isMap = IsMapHelper<T>::value;
0138 
0139   /// Helper struct to homogenize the (type) access for things that behave like
0140   /// maps, e.g. vectors of pairs (and obviously maps).
0141   ///
0142   /// @note This is not SFINAE friendly.
0143   template <typename T, typename IsMap = std::bool_constant<isMap<T>>,
0144             typename IsVector = std::bool_constant<isVector<T> && (std::tuple_size<typename T::value_type>() == 2)>>
0145   struct MapLikeTypeHelper {};
0146 
0147   /// Specialization for actual maps
0148   template <typename T>
0149   struct MapLikeTypeHelper<T, std::bool_constant<true>, std::bool_constant<false>> {
0150     using key_type = typename T::key_type;
0151     using mapped_type = typename T::mapped_type;
0152   };
0153 
0154   /// Specialization for vector of pairs / tuples (of size 2)
0155   template <typename T>
0156   struct MapLikeTypeHelper<T, std::bool_constant<false>, std::bool_constant<true>> {
0157     using key_type = typename std::tuple_element<0, typename T::value_type>::type;
0158     using mapped_type = typename std::tuple_element<1, typename T::value_type>::type;
0159   };
0160 
0161   /// Type aliases for easier usage in actual code
0162   template <typename T>
0163   using GetKeyType = typename MapLikeTypeHelper<T>::key_type;
0164 
0165   template <typename T>
0166   using GetMappedType = typename MapLikeTypeHelper<T>::mapped_type;
0167 
0168   /// Detector for checking the existence of a mutable_type type member. Used to
0169   /// determine whether T is (or could be) a podio generated default (immutable)
0170   /// handle.
0171   template <typename T>
0172   using hasMutable_t = typename T::mutable_type;
0173 
0174   /// Detector for checking the existence of an object_type type member. Used to
0175   /// determine whether T is (or could be) a podio generated mutable handle.
0176   template <typename T>
0177   using hasObject_t = typename T::object_type;
0178 
0179   /// Variable template for determining whether type T is a podio generated
0180   /// mutable handle class
0181   template <typename T>
0182   constexpr static bool isMutableHandleType = det::is_detected_v<hasObject_t, std::remove_reference_t<T>>;
0183 
0184   /// Variable template for determining whether type T is a podio generated
0185   /// default handle class
0186   template <typename T>
0187   constexpr static bool isDefaultHandleType = det::is_detected_v<hasMutable_t, std::remove_reference_t<T>>;
0188 
0189   /// Variable template for obtaining the default handle type from any podio
0190   /// generated handle type.
0191   ///
0192   /// If T is already a default handle, this will return T, if T is a mutable
0193   /// handle it will return T::object_type.
0194   template <typename T>
0195   using GetDefaultHandleType =
0196       typename det::detected_or<std::remove_reference_t<T>, hasObject_t, std::remove_reference_t<T>>::type;
0197 
0198   /// Variable template for obtaining the mutable handle type from any podio
0199   /// generated handle type.
0200   ///
0201   /// If T is already a mutable handle, this will return T, if T is a default
0202   /// handle it will return T::mutable_type.
0203   template <typename T>
0204   using GetMutableHandleType =
0205       typename det::detected_or<std::remove_reference_t<T>, hasMutable_t, std::remove_reference_t<T>>::type;
0206 
0207   /// Helper type alias to transform a tuple of handle types to a tuple of
0208   /// mutable handle types.
0209   template <typename Tuple>
0210   using TupleOfMutableTypes = typename ToTupleOfTemplateHelper<GetMutableHandleType, Tuple>::type;
0211 
0212   /// Detector for checking for the existence of an interfaced_type type member
0213   template <typename T>
0214   using hasInterface_t = typename T::interfaced_types;
0215 
0216   /// Variable template for checking whether the passed type T is an interface
0217   /// type.
0218   ///
0219   /// @note: This simply checks whether T has an interfaced_types type member.
0220   template <typename T>
0221   constexpr static bool isInterfaceType = det::is_detected_v<hasInterface_t, std::remove_reference_t<T>>;
0222 
0223   /// Helper struct to make the detection whether type U can be used to
0224   /// initialize the interface type T in a SFINAE friendly way
0225   template <typename T, typename U, typename isInterface = std::bool_constant<isInterfaceType<T>>>
0226   struct InterfaceInitializerHelper {};
0227 
0228   /// Specialization for actual interface types, including the check whether T
0229   /// is initializable from U
0230   template <typename T, typename U>
0231   struct InterfaceInitializerHelper<T, U, std::bool_constant<true>>
0232       : std::bool_constant<T::template isInitializableFrom<U>> {};
0233 
0234   /// Specialization for non interface types
0235   template <typename T, typename U>
0236   struct InterfaceInitializerHelper<T, U, std::bool_constant<false>> : std::false_type {};
0237 
0238   /// Variable template for checking whether the passed type T is an interface
0239   /// and can be initialized from type U
0240   template <typename T, typename U>
0241   constexpr static bool isInterfaceInitializableFrom = InterfaceInitializerHelper<T, U>::value;
0242 
0243 } // namespace detail
0244 
0245 // forward declaration to be able to use it below
0246 class CollectionBase;
0247 
0248 /// Concept for checking whether a passed type T is a collection
0249 template <typename T>
0250 concept CollectionType = !std::is_abstract_v<T> && std::derived_from<T, CollectionBase> &&
0251     std::default_initializable<T> && std::destructible<T> && std::movable<T> && !std::copyable<T> &&
0252     std::ranges::random_access_range<T> && requires(T t, const T ct) {
0253       // typeName's
0254       { T::typeName } -> std::convertible_to<std::string_view>;
0255       { std::bool_constant<(T::typeName, true)>() } -> std::same_as<std::true_type>; // ~is annotated with constexpr
0256       { T::valueTypeName } -> std::convertible_to<std::string_view>;
0257       {
0258         std::bool_constant<(T::valueTypeName, true)>()
0259       } -> std::same_as<std::true_type>; // ~is annotated with constexpr
0260       { T::dataTypeName } -> std::convertible_to<std::string_view>;
0261       { std::bool_constant<(T::dataTypeName, true)>() } -> std::same_as<std::true_type>; // ~is annotated with constexpr
0262       // typedefs
0263       typename T::value_type;
0264       typename T::mutable_type;
0265       requires std::convertible_to<typename T::mutable_type, typename T::value_type>;
0266       typename T::difference_type;
0267       requires std::signed_integral<typename T::difference_type>;
0268       typename T::size_type;
0269       requires std::unsigned_integral<typename T::size_type>;
0270       typename T::const_iterator;
0271       requires std::random_access_iterator<typename T::const_iterator>;
0272       typename T::iterator;
0273       requires std::random_access_iterator<typename T::iterator>;
0274       typename T::const_reverse_iterator;
0275       requires std::random_access_iterator<typename T::const_reverse_iterator>;
0276       typename T::reverse_iterator;
0277       requires std::random_access_iterator<typename T::reverse_iterator>;
0278       // member functions
0279       requires std::same_as<std::remove_reference_t<decltype(t.create())>,
0280                             typename T::mutable_type>; // UserDataCollection::create() returns reference which has to be
0281                                                        // stripped to be same as expected typedef
0282       { t.push_back(std::declval<std::add_lvalue_reference_t<std::add_const_t<typename T::mutable_type>>>()) };
0283       { t.push_back(std::declval<std::add_lvalue_reference_t<std::add_const_t<typename T::value_type>>>()) };
0284       { t.begin() } -> std::same_as<typename T::iterator>;
0285       { t.cbegin() } -> std::same_as<typename T::const_iterator>;
0286       { ct.begin() } -> std::same_as<typename T::const_iterator>;
0287       { t.end() } -> std::same_as<typename T::iterator>;
0288       { t.cend() } -> std::same_as<typename T::const_iterator>;
0289       { ct.end() } -> std::same_as<typename T::const_iterator>;
0290       { t.rbegin() } -> std::same_as<typename T::reverse_iterator>;
0291       { t.crbegin() } -> std::same_as<typename T::const_reverse_iterator>;
0292       { ct.rbegin() } -> std::same_as<typename T::const_reverse_iterator>;
0293       { t.rend() } -> std::same_as<typename T::reverse_iterator>;
0294       { t.crend() } -> std::same_as<typename T::const_reverse_iterator>;
0295       { ct.rend() } -> std::same_as<typename T::const_reverse_iterator>;
0296       // UserDataCollection element access returns by reference or const reference which has to be stripped to be same
0297       // as expected typedef
0298       requires std::same_as<std::remove_reference_t<decltype(t[std::declval<typename T::size_type>()])>,
0299                             typename T::mutable_type>;
0300       requires std::same_as<std::remove_cvref_t<decltype(ct[std::declval<typename T::size_type>()])>,
0301                             typename T::value_type>;
0302       requires std::same_as<std::remove_reference_t<decltype(t.at(std::declval<typename T::size_type>()))>,
0303                             typename T::mutable_type>;
0304       requires std::same_as<std::remove_cvref_t<decltype(ct.at(std::declval<typename T::size_type>()))>,
0305                             typename T::value_type>;
0306     };
0307 
0308 namespace utils {
0309   template <typename... T>
0310   struct TypeList {};
0311 } // namespace utils
0312 
0313 } // namespace podio
0314 
0315 #endif // PODIO_UTILITIES_TYPEHELPERS_H