|
1 | 1 | #ifndef PODIO_UTILITIES_TYPEHELPERS_H |
2 | 2 | #define PODIO_UTILITIES_TYPEHELPERS_H |
3 | 3 |
|
| 4 | +#include <concepts> |
| 5 | +#include <iterator> |
4 | 6 | #include <map> |
| 7 | +#include <ranges> |
5 | 8 | #include <tuple> |
6 | 9 | #include <type_traits> |
7 | 10 | #include <unordered_map> |
@@ -242,9 +245,65 @@ namespace detail { |
242 | 245 | // forward declaration to be able to use it below |
243 | 246 | class CollectionBase; |
244 | 247 |
|
245 | | -/// Concept for checking whether a passed type T inherits from podio::CollectionBase |
| 248 | +/// Concept for checking whether a passed type T is a collection |
246 | 249 | template <typename T> |
247 | | -concept CollectionType = std::is_base_of_v<CollectionBase, T>; |
| 250 | +concept CollectionType = !std::is_abstract_v<T> && std::derived_from<T, CollectionBase> && |
| 251 | + std::default_initializable<T> && std::destructible<T> && std::movable<T> && !std::copyable<T> && |
| 252 | + std::ranges::random_access_range<T> && requires(T t, const T ct) { |
| 253 | + // typeName's |
| 254 | + { T::typeName } -> std::convertible_to<std::string_view>; |
| 255 | + { std::bool_constant<(T::typeName, true)>() } -> std::same_as<std::true_type>; // ~is annotated with constexpr |
| 256 | + { T::valueTypeName } -> std::convertible_to<std::string_view>; |
| 257 | + { |
| 258 | + std::bool_constant<(T::valueTypeName, true)>() |
| 259 | + } -> std::same_as<std::true_type>; // ~is annotated with constexpr |
| 260 | + { T::dataTypeName } -> std::convertible_to<std::string_view>; |
| 261 | + { std::bool_constant<(T::dataTypeName, true)>() } -> std::same_as<std::true_type>; // ~is annotated with constexpr |
| 262 | + // typedefs |
| 263 | + typename T::value_type; |
| 264 | + typename T::mutable_type; |
| 265 | + requires std::convertible_to<typename T::mutable_type, typename T::value_type>; |
| 266 | + typename T::difference_type; |
| 267 | + requires std::signed_integral<typename T::difference_type>; |
| 268 | + typename T::size_type; |
| 269 | + requires std::unsigned_integral<typename T::size_type>; |
| 270 | + typename T::const_iterator; |
| 271 | + requires std::random_access_iterator<typename T::const_iterator>; |
| 272 | + typename T::iterator; |
| 273 | + requires std::random_access_iterator<typename T::iterator>; |
| 274 | + typename T::const_reverse_iterator; |
| 275 | + requires std::random_access_iterator<typename T::const_reverse_iterator>; |
| 276 | + typename T::reverse_iterator; |
| 277 | + requires std::random_access_iterator<typename T::reverse_iterator>; |
| 278 | + // member functions |
| 279 | + requires std::same_as<std::remove_reference_t<decltype(t.create())>, |
| 280 | + typename T::mutable_type>; // UserDataCollection::create() returns reference which has to be |
| 281 | + // stripped to be same as expected typedef |
| 282 | + { t.push_back(std::declval<std::add_lvalue_reference_t<std::add_const_t<typename T::mutable_type>>>()) }; |
| 283 | + { t.push_back(std::declval<std::add_lvalue_reference_t<std::add_const_t<typename T::value_type>>>()) }; |
| 284 | + { t.begin() } -> std::same_as<typename T::iterator>; |
| 285 | + { t.cbegin() } -> std::same_as<typename T::const_iterator>; |
| 286 | + { ct.begin() } -> std::same_as<typename T::const_iterator>; |
| 287 | + { t.end() } -> std::same_as<typename T::iterator>; |
| 288 | + { t.cend() } -> std::same_as<typename T::const_iterator>; |
| 289 | + { ct.end() } -> std::same_as<typename T::const_iterator>; |
| 290 | + { t.rbegin() } -> std::same_as<typename T::reverse_iterator>; |
| 291 | + { t.crbegin() } -> std::same_as<typename T::const_reverse_iterator>; |
| 292 | + { ct.rbegin() } -> std::same_as<typename T::const_reverse_iterator>; |
| 293 | + { t.rend() } -> std::same_as<typename T::reverse_iterator>; |
| 294 | + { t.crend() } -> std::same_as<typename T::const_reverse_iterator>; |
| 295 | + { ct.rend() } -> std::same_as<typename T::const_reverse_iterator>; |
| 296 | + // UserDataCollection element access returns by reference or const reference which has to be stripped to be same |
| 297 | + // as expected typedef |
| 298 | + requires std::same_as<std::remove_reference_t<decltype(t[std::declval<typename T::size_type>()])>, |
| 299 | + typename T::mutable_type>; |
| 300 | + requires std::same_as<std::remove_cvref_t<decltype(ct[std::declval<typename T::size_type>()])>, |
| 301 | + typename T::value_type>; |
| 302 | + requires std::same_as<std::remove_reference_t<decltype(t.at(std::declval<typename T::size_type>()))>, |
| 303 | + typename T::mutable_type>; |
| 304 | + requires std::same_as<std::remove_cvref_t<decltype(ct.at(std::declval<typename T::size_type>()))>, |
| 305 | + typename T::value_type>; |
| 306 | + }; |
248 | 307 |
|
249 | 308 | namespace utils { |
250 | 309 | template <typename... T> |
|
0 commit comments