Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-04 09:21:26

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