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
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 }
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 }
0044
0045 namespace detail {
0046
0047
0048
0049 template <typename T>
0050 inline constexpr bool always_false = false;
0051
0052
0053
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
0061
0062 template <typename T, typename Tuple>
0063 inline constexpr bool isInTuple = TypeInTupleHelper<T, Tuple>::value;
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
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
0084 template <typename Tuple>
0085 using TupleOfVector = typename ToTupleOfTemplateHelper<std::vector, Tuple>::type;
0086
0087
0088
0089
0090 template <typename... Tuples>
0091 using TupleCatType = decltype(std::tuple_cat(std::declval<Tuples>()...));
0092
0093
0094
0095 template <typename T, typename Tuple>
0096 inline constexpr bool isAnyOrVectorOf = isInTuple<T, TupleCatType<Tuple, TupleOfVector<Tuple>>>;
0097
0098
0099
0100
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
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
0122 template <typename T>
0123 inline constexpr bool isVector = IsVectorHelper<T>::value;
0124
0125
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
0136
0137 template <typename T>
0138 inline constexpr bool isMap = IsMapHelper<T>::value;
0139
0140
0141
0142
0143
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
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
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
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
0170
0171
0172 template <typename T>
0173 using hasMutable_t = typename T::mutable_type;
0174
0175
0176
0177 template <typename T>
0178 using hasObject_t = typename T::object_type;
0179
0180
0181
0182 template <typename T>
0183 inline constexpr bool isMutableHandleType = det::is_detected_v<hasObject_t, std::remove_reference_t<T>>;
0184
0185
0186
0187 template <typename T>
0188 inline constexpr bool isDefaultHandleType = det::is_detected_v<hasMutable_t, std::remove_reference_t<T>>;
0189
0190
0191
0192
0193
0194
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
0200
0201
0202
0203
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
0209
0210 template <typename Tuple>
0211 using TupleOfMutableTypes = typename ToTupleOfTemplateHelper<GetMutableHandleType, Tuple>::type;
0212
0213
0214 template <typename T>
0215 using hasInterface_t = typename T::interfaced_types;
0216
0217
0218
0219
0220
0221 template <typename T>
0222 inline constexpr bool isInterfaceType = det::is_detected_v<hasInterface_t, std::remove_reference_t<T>>;
0223
0224
0225
0226 template <typename T, typename U, typename isInterface = std::bool_constant<isInterfaceType<T>>>
0227 struct InterfaceInitializerHelper {};
0228
0229
0230
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
0236 template <typename T, typename U>
0237 struct InterfaceInitializerHelper<T, U, std::bool_constant<false>> : std::false_type {};
0238
0239
0240
0241 template <typename T, typename U>
0242 inline constexpr bool isInterfaceInitializableFrom = InterfaceInitializerHelper<T, U>::value;
0243
0244
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
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
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 }
0271
0272
0273 class CollectionBase;
0274
0275
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
0281 { T::typeName } -> std::convertible_to<std::string_view>;
0282 { std::bool_constant<(T::typeName, true)>() } -> std::same_as<std::true_type>;
0283 { T::valueTypeName } -> std::convertible_to<std::string_view>;
0284 {
0285 std::bool_constant<(T::valueTypeName, true)>()
0286 } -> std::same_as<std::true_type>;
0287 { T::dataTypeName } -> std::convertible_to<std::string_view>;
0288 { std::bool_constant<(T::dataTypeName, true)>() } -> std::same_as<std::true_type>;
0289
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
0306 requires std::same_as<std::remove_reference_t<decltype(t.create())>,
0307 typename T::mutable_type>;
0308
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
0324
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 }
0342
0343 }
0344
0345 #endif