|
22 | 22 |
|
23 | 23 | #include "memilio/io/io.h" |
24 | 24 | #include "memilio/utils/compiler_diagnostics.h" |
| 25 | +#include "memilio/utils/metaprogramming.h" |
25 | 26 | #include "memilio/utils/type_safe.h" |
26 | 27 |
|
27 | 28 | #include <cstddef> |
@@ -116,9 +117,10 @@ class MEMILIO_ENABLE_EBO Index<CategoryTag> : public TypeSafe<size_t, Index<Cate |
116 | 117 | public: |
117 | 118 | using TypeSafe<size_t, Index<CategoryTag>>::TypeSafe; |
118 | 119 |
|
119 | | - static size_t constexpr size = 1; |
| 120 | + static constexpr size_t size = 1; |
| 121 | + static constexpr bool has_duplicates = false; |
120 | 122 |
|
121 | | - static Index constexpr Zero() |
| 123 | + static constexpr Index Zero() |
122 | 124 | { |
123 | 125 | return Index((size_t)0); |
124 | 126 | } |
@@ -173,7 +175,8 @@ template <typename... CategoryTag> |
173 | 175 | class Index |
174 | 176 | { |
175 | 177 | public: |
176 | | - static size_t constexpr size = sizeof...(CategoryTag); |
| 178 | + static constexpr size_t size = sizeof...(CategoryTag); |
| 179 | + static constexpr bool has_duplicates = has_duplicates_v<CategoryTag...>; |
177 | 180 |
|
178 | 181 | static Index constexpr Zero() |
179 | 182 | { |
@@ -211,6 +214,25 @@ class Index |
211 | 214 | return !(this == other); |
212 | 215 | } |
213 | 216 |
|
| 217 | + bool operator<(Index const& other) const |
| 218 | + { |
| 219 | + // use apply to unfold both tuples, then use a fold expression to evaluate a pairwise less |
| 220 | + return std::apply( |
| 221 | + [&other](auto&&... indices_) { |
| 222 | + return std::apply( |
| 223 | + [&](auto&&... other_indices_) { |
| 224 | + return ((indices_ < other_indices_) && ...); |
| 225 | + }, |
| 226 | + other.indices); |
| 227 | + }, |
| 228 | + indices); |
| 229 | + } |
| 230 | + |
| 231 | + bool operator<=(Index const& other) const |
| 232 | + { |
| 233 | + return (*this == other) || (*this < other); |
| 234 | + } |
| 235 | + |
214 | 236 | /** |
215 | 237 | * serialize this. |
216 | 238 | * @see mio::serialize |
@@ -372,9 +394,16 @@ inline Index<CategoryTags...> extend_index_impl(const Index<Subset...>& i, const |
372 | 394 | * @return A (sub)index with the given categories and values from index. |
373 | 395 | */ |
374 | 396 | template <class SubIndex, class SuperIndex> |
375 | | -SubIndex reduce_index(const SuperIndex& index) |
| 397 | +decltype(auto) reduce_index(const SuperIndex& index) |
376 | 398 | { |
377 | | - return details::reduce_index_impl(index, mio::Tag<SubIndex>{}); |
| 399 | + if constexpr (SubIndex::size == 1 && std::is_base_of_v<Index<SubIndex>, SubIndex>) { |
| 400 | + // this case handles reducing from e.g. Index<AgeGroup, ...> directly to AgeGroup |
| 401 | + // the default case would instead reduce to Index<AgeGroup>, which may cause conversion errors |
| 402 | + return details::reduce_index_impl(index, mio::Tag<Index<SubIndex>>{}); |
| 403 | + } |
| 404 | + else { |
| 405 | + return details::reduce_index_impl(index, mio::Tag<SubIndex>{}); |
| 406 | + } |
378 | 407 | } |
379 | 408 |
|
380 | 409 | template <class Enum, class SuperIndex> |
|
0 commit comments