@@ -114,6 +114,13 @@ using is_one_of = std::disjunction<std::is_same<T, Ts>...>;
114
114
template <typename T, typename ... Ts>
115
115
using are_base_of = std::conjunction<std::is_base_of<T, Ts>...>;
116
116
117
+ // / traits class for checking whether type `T` is same as all other types in
118
+ // / `Ts`.
119
+ template <typename T = void , typename ... Ts>
120
+ using all_types_equal = std::conjunction<std::is_same<T, Ts>...>;
121
+ template <typename T = void , typename ... Ts>
122
+ constexpr bool all_types_equal_v = all_types_equal<T, Ts...>::value;
123
+
117
124
// / Determine if all types in Ts are distinct.
118
125
// /
119
126
// / Useful to statically assert when Ts is intended to describe a non-multi set
@@ -996,13 +1003,17 @@ class concat_iterator
996
1003
997
1004
static constexpr bool ReturnsByValue =
998
1005
!(std::is_reference_v<decltype (*std::declval<IterTs>())> && ...);
999
-
1006
+ static constexpr bool ReturnsConvertibleType =
1007
+ !all_types_equal_v<
1008
+ std::remove_cv_t <ValueT>,
1009
+ remove_cvref_t <decltype (*std::declval<IterTs>())>...> &&
1010
+ (std::is_convertible_v<decltype (*std::declval<IterTs>()), ValueT> && ...);
1011
+
1012
+ // Cannot return a reference type if a conversion takes place, provided that
1013
+ // the result of dereferencing all `IterTs...` is convertible to `ValueT`.
1000
1014
using reference_type =
1001
- typename std::conditional_t <ReturnsByValue, ValueT, ValueT &>;
1002
-
1003
- using handle_type =
1004
- typename std::conditional_t <ReturnsByValue, std::optional<ValueT>,
1005
- ValueT *>;
1015
+ std::conditional_t <ReturnsByValue || ReturnsConvertibleType, ValueT,
1016
+ ValueT &>;
1006
1017
1007
1018
// / We store both the current and end iterators for each concatenated
1008
1019
// / sequence in a tuple of pairs.
@@ -1013,66 +1024,46 @@ class concat_iterator
1013
1024
std::tuple<IterTs...> Begins;
1014
1025
std::tuple<IterTs...> Ends;
1015
1026
1016
- // / Attempts to increment a specific iterator.
1017
- // /
1018
- // / Returns true if it was able to increment the iterator. Returns false if
1019
- // / the iterator is already at the end iterator.
1020
- template <size_t Index> bool incrementHelper () {
1027
+ // / Attempts to increment the `Index`-th iterator. If the iterator is already
1028
+ // / at end, recurse over iterators in `Others...`.
1029
+ template <size_t Index, size_t ... Others> void incrementImpl () {
1021
1030
auto &Begin = std::get<Index>(Begins);
1022
1031
auto &End = std::get<Index>(Ends);
1023
- if (Begin == End)
1024
- return false ;
1025
-
1032
+ if (Begin == End) {
1033
+ if constexpr (sizeof ...(Others) != 0 )
1034
+ return incrementImpl<Others...>();
1035
+ llvm_unreachable (" Attempted to increment an end concat iterator!" );
1036
+ }
1026
1037
++Begin;
1027
- return true ;
1028
1038
}
1029
1039
1030
1040
// / Increments the first non-end iterator.
1031
1041
// /
1032
1042
// / It is an error to call this with all iterators at the end.
1033
1043
template <size_t ... Ns> void increment (std::index_sequence<Ns...>) {
1034
- // Build a sequence of functions to increment each iterator if possible.
1035
- bool (concat_iterator::*IncrementHelperFns[])() = {
1036
- &concat_iterator::incrementHelper<Ns>...};
1037
-
1038
- // Loop over them, and stop as soon as we succeed at incrementing one.
1039
- for (auto &IncrementHelperFn : IncrementHelperFns)
1040
- if ((this ->*IncrementHelperFn)())
1041
- return ;
1042
-
1043
- llvm_unreachable (" Attempted to increment an end concat iterator!" );
1044
+ incrementImpl<Ns...>();
1044
1045
}
1045
1046
1046
- // / Returns null if the specified iterator is at the end. Otherwise,
1047
- // / dereferences the iterator and returns the address of the resulting
1048
- // / reference.
1049
- template <size_t Index> handle_type getHelper () const {
1047
+ // / Dereferences the `Index`-th iterator and returns the resulting reference.
1048
+ // / If `Index` is at end, recurse over iterators in `Others...`.
1049
+ template <size_t Index, size_t ... Others> reference_type getImpl () const {
1050
1050
auto &Begin = std::get<Index>(Begins);
1051
1051
auto &End = std::get<Index>(Ends);
1052
- if (Begin == End)
1053
- return {};
1054
-
1055
- if constexpr (ReturnsByValue)
1056
- return *Begin ;
1057
- else
1058
- return & *Begin;
1052
+ if (Begin == End) {
1053
+ if constexpr ( sizeof ...(Others) != 0 )
1054
+ return getImpl<Others...>();
1055
+ llvm_unreachable (
1056
+ " Attempted to get a pointer from an end concat iterator! " ) ;
1057
+ }
1058
+ return *Begin;
1059
1059
}
1060
1060
1061
1061
// / Finds the first non-end iterator, dereferences, and returns the resulting
1062
1062
// / reference.
1063
1063
// /
1064
1064
// / It is an error to call this with all iterators at the end.
1065
1065
template <size_t ... Ns> reference_type get (std::index_sequence<Ns...>) const {
1066
- // Build a sequence of functions to get from iterator if possible.
1067
- handle_type (concat_iterator::*GetHelperFns[])()
1068
- const = {&concat_iterator::getHelper<Ns>...};
1069
-
1070
- // Loop over them, and return the first result we find.
1071
- for (auto &GetHelperFn : GetHelperFns)
1072
- if (auto P = (this ->*GetHelperFn)())
1073
- return *P;
1074
-
1075
- llvm_unreachable (" Attempted to get a pointer from an end concat iterator!" );
1066
+ return getImpl<Ns...>();
1076
1067
}
1077
1068
1078
1069
public:
0 commit comments