|
@@ -31,6 +31,7 @@
|
|
|
#include "llvm/ADT/iterator.h"
|
|
|
#include "llvm/ADT/iterator_range.h"
|
|
|
#include "llvm/Support/Compiler.h"
|
|
|
+#include "llvm/Support/ErrorHandling.h"
|
|
|
|
|
|
namespace llvm {
|
|
|
|
|
@@ -435,6 +436,151 @@ detail::zippy<detail::zip_first, T, U, Args...> zip_first(T &&t, U &&u,
|
|
|
std::forward<T>(t), std::forward<U>(u), std::forward<Args>(args)...);
|
|
|
}
|
|
|
|
|
|
+/// Iterator wrapper that concatenates sequences together.
|
|
|
+///
|
|
|
+/// This can concatenate different iterators, even with different types, into
|
|
|
+/// a single iterator provided the value types of all the concatenated
|
|
|
+/// iterators expose `reference` and `pointer` types that can be converted to
|
|
|
+/// `ValueT &` and `ValueT *` respectively. It doesn't support more
|
|
|
+/// interesting/customized pointer or reference types.
|
|
|
+///
|
|
|
+/// Currently this only supports forward or higher iterator categories as
|
|
|
+/// inputs and always exposes a forward iterator interface.
|
|
|
+template <typename ValueT, typename... IterTs>
|
|
|
+class concat_iterator
|
|
|
+ : public iterator_facade_base<concat_iterator<ValueT, IterTs...>,
|
|
|
+ std::forward_iterator_tag, ValueT> {
|
|
|
+ typedef typename concat_iterator::iterator_facade_base BaseT;
|
|
|
+
|
|
|
+ /// We store both the current and end iterators for each concatenated
|
|
|
+ /// sequence in a tuple of pairs.
|
|
|
+ ///
|
|
|
+ /// Note that something like iterator_range seems nice at first here, but the
|
|
|
+ /// range properties are of little benefit and end up getting in the way
|
|
|
+ /// because we need to do mutation on the current iterators.
|
|
|
+ std::tuple<std::pair<IterTs, IterTs>...> IterPairs;
|
|
|
+
|
|
|
+ /// Attempts to increment a specific iterator.
|
|
|
+ ///
|
|
|
+ /// Returns true if it was able to increment the iterator. Returns false if
|
|
|
+ /// the iterator is already at the end iterator.
|
|
|
+ template <size_t Index> bool incrementHelper() {
|
|
|
+ auto &IterPair = std::get<Index>(IterPairs);
|
|
|
+ if (IterPair.first == IterPair.second)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ ++IterPair.first;
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Increments the first non-end iterator.
|
|
|
+ ///
|
|
|
+ /// It is an error to call this with all iterators at the end.
|
|
|
+ template <size_t... Ns> void increment(index_sequence<Ns...>) {
|
|
|
+ // Build a sequence of functions to increment each iterator if possible.
|
|
|
+ bool (concat_iterator::*IncrementHelperFns[])() = {
|
|
|
+ &concat_iterator::incrementHelper<Ns>...};
|
|
|
+
|
|
|
+ // Loop over them, and stop as soon as we succeed at incrementing one.
|
|
|
+ for (auto &IncrementHelperFn : IncrementHelperFns)
|
|
|
+ if ((this->*IncrementHelperFn)())
|
|
|
+ return;
|
|
|
+
|
|
|
+ llvm_unreachable("Attempted to increment an end concat iterator!");
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Returns null if the specified iterator is at the end. Otherwise,
|
|
|
+ /// dereferences the iterator and returns the address of the resulting
|
|
|
+ /// reference.
|
|
|
+ template <size_t Index> ValueT *getHelper() const {
|
|
|
+ auto &IterPair = std::get<Index>(IterPairs);
|
|
|
+ if (IterPair.first == IterPair.second)
|
|
|
+ return nullptr;
|
|
|
+
|
|
|
+ return &*IterPair.first;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// Finds the first non-end iterator, dereferences, and returns the resulting
|
|
|
+ /// reference.
|
|
|
+ ///
|
|
|
+ /// It is an error to call this with all iterators at the end.
|
|
|
+ template <size_t... Ns> ValueT &get(index_sequence<Ns...>) const {
|
|
|
+ // Build a sequence of functions to get from iterator if possible.
|
|
|
+ ValueT *(concat_iterator::*GetHelperFns[])() const = {
|
|
|
+ &concat_iterator::getHelper<Ns>...};
|
|
|
+
|
|
|
+ // Loop over them, and return the first result we find.
|
|
|
+ for (auto &GetHelperFn : GetHelperFns)
|
|
|
+ if (ValueT *P = (this->*GetHelperFn)())
|
|
|
+ return *P;
|
|
|
+
|
|
|
+ llvm_unreachable("Attempted to get a pointer from an end concat iterator!");
|
|
|
+ }
|
|
|
+
|
|
|
+public:
|
|
|
+ /// Constructs an iterator from a squence of ranges.
|
|
|
+ ///
|
|
|
+ /// We need the full range to know how to switch between each of the
|
|
|
+ /// iterators.
|
|
|
+ template <typename... RangeTs>
|
|
|
+ explicit concat_iterator(RangeTs &&... Ranges)
|
|
|
+ : IterPairs({std::begin(Ranges), std::end(Ranges)}...) {}
|
|
|
+
|
|
|
+ using BaseT::operator++;
|
|
|
+ concat_iterator &operator++() {
|
|
|
+ increment(index_sequence_for<IterTs...>());
|
|
|
+ return *this;
|
|
|
+ }
|
|
|
+
|
|
|
+ ValueT &operator*() const { return get(index_sequence_for<IterTs...>()); }
|
|
|
+
|
|
|
+ bool operator==(const concat_iterator &RHS) const {
|
|
|
+ return IterPairs == RHS.IterPairs;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+namespace detail {
|
|
|
+/// Helper to store a sequence of ranges being concatenated and access them.
|
|
|
+///
|
|
|
+/// This is designed to facilitate providing actual storage when temporaries
|
|
|
+/// are passed into the constructor such that we can use it as part of range
|
|
|
+/// based for loops.
|
|
|
+template <typename ValueT, typename... RangeTs> class concat_range {
|
|
|
+public:
|
|
|
+ typedef concat_iterator<ValueT,
|
|
|
+ decltype(std::begin(std::declval<RangeTs &>()))...>
|
|
|
+ iterator;
|
|
|
+
|
|
|
+private:
|
|
|
+ std::tuple<RangeTs...> Ranges;
|
|
|
+
|
|
|
+ template <size_t... Ns> iterator begin_impl(index_sequence<Ns...>) {
|
|
|
+ return iterator(std::get<Ns>(Ranges)...);
|
|
|
+ }
|
|
|
+ template <size_t... Ns> iterator end_impl(index_sequence<Ns...>) {
|
|
|
+ return iterator(make_range(std::end(std::get<Ns>(Ranges)),
|
|
|
+ std::end(std::get<Ns>(Ranges)))...);
|
|
|
+ }
|
|
|
+
|
|
|
+public:
|
|
|
+ iterator begin() { return begin_impl(index_sequence_for<RangeTs...>{}); }
|
|
|
+ iterator end() { return end_impl(index_sequence_for<RangeTs...>{}); }
|
|
|
+ concat_range(RangeTs &&... Ranges)
|
|
|
+ : Ranges(std::forward<RangeTs>(Ranges)...) {}
|
|
|
+};
|
|
|
+}
|
|
|
+
|
|
|
+/// Concatenated range across two or more ranges.
|
|
|
+///
|
|
|
+/// The desired value type must be explicitly specified.
|
|
|
+template <typename ValueT, typename... RangeTs>
|
|
|
+detail::concat_range<ValueT, RangeTs...> concat(RangeTs &&... Ranges) {
|
|
|
+ static_assert(sizeof...(RangeTs) > 1,
|
|
|
+ "Need more than one range to concatenate!");
|
|
|
+ return detail::concat_range<ValueT, RangeTs...>(
|
|
|
+ std::forward<RangeTs>(Ranges)...);
|
|
|
+}
|
|
|
+
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
// Extra additions to <utility>
|
|
|
//===----------------------------------------------------------------------===//
|