aboutsummaryrefslogtreecommitdiff
path: root/include/llvm/ADT/STLExtras.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/llvm/ADT/STLExtras.h')
-rw-r--r--include/llvm/ADT/STLExtras.h236
1 files changed, 178 insertions, 58 deletions
diff --git a/include/llvm/ADT/STLExtras.h b/include/llvm/ADT/STLExtras.h
index ec121e0d55cd..15945adbe589 100644
--- a/include/llvm/ADT/STLExtras.h
+++ b/include/llvm/ADT/STLExtras.h
@@ -23,11 +23,13 @@
#include <cstdlib> // for qsort
#include <functional>
#include <iterator>
+#include <limits>
#include <memory>
#include <tuple>
#include <utility> // for std::pair
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/iterator.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Compiler.h"
@@ -44,6 +46,10 @@ namespace detail {
template <typename RangeT>
using IterOfRange = decltype(std::begin(std::declval<RangeT &>()));
+template <typename RangeT>
+using ValueOfRange = typename std::remove_reference<decltype(
+ *std::begin(std::declval<RangeT &>()))>::type;
+
} // End detail namespace
//===----------------------------------------------------------------------===//
@@ -123,7 +129,7 @@ inline void deleter(T *Ptr) {
//===----------------------------------------------------------------------===//
// mapped_iterator - This is a simple iterator adapter that causes a function to
-// be dereferenced whenever operator* is invoked on the iterator.
+// be applied whenever operator* is invoked on the iterator.
//
template <class RootIt, class UnaryFunc>
class mapped_iterator {
@@ -134,9 +140,8 @@ public:
iterator_category;
typedef typename std::iterator_traits<RootIt>::difference_type
difference_type;
- typedef typename std::result_of<
- UnaryFunc(decltype(*std::declval<RootIt>()))>
- ::type value_type;
+ typedef decltype(std::declval<UnaryFunc>()(*std::declval<RootIt>()))
+ value_type;
typedef void pointer;
//typedef typename UnaryFunc::result_type *pointer;
@@ -356,65 +361,126 @@ template <size_t... I> struct index_sequence;
template <class... Ts> struct index_sequence_for;
namespace detail {
-template <typename... Iters> class zip_first {
-public:
- typedef std::input_iterator_tag iterator_category;
- typedef std::tuple<decltype(*std::declval<Iters>())...> value_type;
+using std::declval;
+
+// We have to alias this since inlining the actual type at the usage site
+// in the parameter list of iterator_facade_base<> below ICEs MSVC 2017.
+template<typename... Iters> struct ZipTupleType {
+ typedef std::tuple<decltype(*declval<Iters>())...> type;
+};
+
+template <typename ZipType, typename... Iters>
+using zip_traits = iterator_facade_base<
+ ZipType, typename std::common_type<std::bidirectional_iterator_tag,
+ typename std::iterator_traits<
+ Iters>::iterator_category...>::type,
+ // ^ TODO: Implement random access methods.
+ typename ZipTupleType<Iters...>::type,
+ typename std::iterator_traits<typename std::tuple_element<
+ 0, std::tuple<Iters...>>::type>::difference_type,
+ // ^ FIXME: This follows boost::make_zip_iterator's assumption that all
+ // inner iterators have the same difference_type. It would fail if, for
+ // instance, the second field's difference_type were non-numeric while the
+ // first is.
+ typename ZipTupleType<Iters...>::type *,
+ typename ZipTupleType<Iters...>::type>;
+
+template <typename ZipType, typename... Iters>
+struct zip_common : public zip_traits<ZipType, Iters...> {
+ using Base = zip_traits<ZipType, Iters...>;
+ using value_type = typename Base::value_type;
+
std::tuple<Iters...> iterators;
-private:
- template <size_t... Ns> value_type deres(index_sequence<Ns...>) {
+protected:
+ template <size_t... Ns> value_type deref(index_sequence<Ns...>) const {
return value_type(*std::get<Ns>(iterators)...);
}
- template <size_t... Ns> decltype(iterators) tup_inc(index_sequence<Ns...>) {
+ template <size_t... Ns>
+ decltype(iterators) tup_inc(index_sequence<Ns...>) const {
return std::tuple<Iters...>(std::next(std::get<Ns>(iterators))...);
}
+ template <size_t... Ns>
+ decltype(iterators) tup_dec(index_sequence<Ns...>) const {
+ return std::tuple<Iters...>(std::prev(std::get<Ns>(iterators))...);
+ }
+
public:
- value_type operator*() { return deres(index_sequence_for<Iters...>{}); }
+ zip_common(Iters &&... ts) : iterators(std::forward<Iters>(ts)...) {}
+
+ value_type operator*() { return deref(index_sequence_for<Iters...>{}); }
- void operator++() { iterators = tup_inc(index_sequence_for<Iters...>{}); }
+ const value_type operator*() const {
+ return deref(index_sequence_for<Iters...>{});
+ }
- bool operator!=(const zip_first<Iters...> &other) const {
- return std::get<0>(iterators) != std::get<0>(other.iterators);
+ ZipType &operator++() {
+ iterators = tup_inc(index_sequence_for<Iters...>{});
+ return *reinterpret_cast<ZipType *>(this);
}
- zip_first(Iters &&... ts) : iterators(std::forward<Iters>(ts)...) {}
+
+ ZipType &operator--() {
+ static_assert(Base::IsBidirectional,
+ "All inner iterators must be at least bidirectional.");
+ iterators = tup_dec(index_sequence_for<Iters...>{});
+ return *reinterpret_cast<ZipType *>(this);
+ }
+};
+
+template <typename... Iters>
+struct zip_first : public zip_common<zip_first<Iters...>, Iters...> {
+ using Base = zip_common<zip_first<Iters...>, Iters...>;
+
+ bool operator==(const zip_first<Iters...> &other) const {
+ return std::get<0>(this->iterators) == std::get<0>(other.iterators);
+ }
+
+ zip_first(Iters &&... ts) : Base(std::forward<Iters>(ts)...) {}
};
-template <typename... Iters> class zip_shortest : public zip_first<Iters...> {
+template <typename... Iters>
+class zip_shortest : public zip_common<zip_shortest<Iters...>, Iters...> {
template <size_t... Ns>
- bool test(const zip_first<Iters...> &other, index_sequence<Ns...>) const {
+ bool test(const zip_shortest<Iters...> &other, index_sequence<Ns...>) const {
return all_of(std::initializer_list<bool>{std::get<Ns>(this->iterators) !=
std::get<Ns>(other.iterators)...},
identity<bool>{});
}
public:
- bool operator!=(const zip_first<Iters...> &other) const {
- return test(other, index_sequence_for<Iters...>{});
+ using Base = zip_common<zip_shortest<Iters...>, Iters...>;
+
+ bool operator==(const zip_shortest<Iters...> &other) const {
+ return !test(other, index_sequence_for<Iters...>{});
}
- zip_shortest(Iters &&... ts)
- : zip_first<Iters...>(std::forward<Iters>(ts)...) {}
+
+ zip_shortest(Iters &&... ts) : Base(std::forward<Iters>(ts)...) {}
};
template <template <typename...> class ItType, typename... Args> class zippy {
public:
- typedef ItType<decltype(std::begin(std::declval<Args>()))...> iterator;
+ using iterator = ItType<decltype(std::begin(std::declval<Args>()))...>;
+ using iterator_category = typename iterator::iterator_category;
+ using value_type = typename iterator::value_type;
+ using difference_type = typename iterator::difference_type;
+ using pointer = typename iterator::pointer;
+ using reference = typename iterator::reference;
private:
std::tuple<Args...> ts;
- template <size_t... Ns> iterator begin_impl(index_sequence<Ns...>) {
+ template <size_t... Ns> iterator begin_impl(index_sequence<Ns...>) const {
return iterator(std::begin(std::get<Ns>(ts))...);
}
- template <size_t... Ns> iterator end_impl(index_sequence<Ns...>) {
+ template <size_t... Ns> iterator end_impl(index_sequence<Ns...>) const {
return iterator(std::end(std::get<Ns>(ts))...);
}
public:
- iterator begin() { return begin_impl(index_sequence_for<Args...>{}); }
- iterator end() { return end_impl(index_sequence_for<Args...>{}); }
+ iterator begin() const { return begin_impl(index_sequence_for<Args...>{}); }
+ iterator end() const { return end_impl(index_sequence_for<Args...>{}); }
zippy(Args &&... ts_) : ts(std::forward<Args>(ts_)...) {}
};
} // End detail namespace
@@ -777,6 +843,13 @@ auto remove_if(R &&Range, UnaryPredicate P) -> decltype(std::begin(Range)) {
return std::remove_if(std::begin(Range), std::end(Range), P);
}
+/// Provide wrappers to std::copy_if which take ranges instead of having to
+/// pass begin/end explicitly.
+template <typename R, typename OutputIt, typename UnaryPredicate>
+OutputIt copy_if(R &&Range, OutputIt Out, UnaryPredicate P) {
+ return std::copy_if(std::begin(Range), std::end(Range), Out, P);
+}
+
/// Wrapper function around std::find to detect if an element exists
/// in a container.
template <typename R, typename E>
@@ -815,6 +888,15 @@ auto partition(R &&Range, UnaryPredicate P) -> decltype(std::begin(Range)) {
return std::partition(std::begin(Range), std::end(Range), P);
}
+/// \brief Given a range of type R, iterate the entire range and return a
+/// SmallVector with elements of the vector. This is useful, for example,
+/// when you want to iterate a range and then sort the results.
+template <unsigned Size, typename R>
+SmallVector<typename std::remove_const<detail::ValueOfRange<R>>::type, Size>
+to_vector(R &&Range) {
+ return {std::begin(Range), std::end(Range)};
+}
+
/// Provide a container algorithm similar to C++ Library Fundamentals v2's
/// `erase_if` which is equivalent to:
///
@@ -909,47 +991,85 @@ template <typename T> struct deref {
};
namespace detail {
-template <typename R> class enumerator_impl {
-public:
- template <typename X> struct result_pair {
- result_pair(std::size_t Index, X Value) : Index(Index), Value(Value) {}
+template <typename R> class enumerator_iter;
- const std::size_t Index;
- X Value;
- };
+template <typename R> struct result_pair {
+ friend class enumerator_iter<R>;
+
+ result_pair() : Index(-1) {}
+ result_pair(std::size_t Index, IterOfRange<R> Iter)
+ : Index(Index), Iter(Iter) {}
- class iterator {
- typedef
- typename std::iterator_traits<IterOfRange<R>>::reference iter_reference;
- typedef result_pair<iter_reference> result_type;
+ result_pair<R> &operator=(const result_pair<R> &Other) {
+ Index = Other.Index;
+ Iter = Other.Iter;
+ return *this;
+ }
- public:
- iterator(IterOfRange<R> &&Iter, std::size_t Index)
- : Iter(Iter), Index(Index) {}
+ std::size_t index() const { return Index; }
+ const ValueOfRange<R> &value() const { return *Iter; }
+ ValueOfRange<R> &value() { return *Iter; }
- result_type operator*() const { return result_type(Index, *Iter); }
+private:
+ std::size_t Index;
+ IterOfRange<R> Iter;
+};
- iterator &operator++() {
- ++Iter;
- ++Index;
- return *this;
- }
+template <typename R>
+class enumerator_iter
+ : public iterator_facade_base<
+ enumerator_iter<R>, std::forward_iterator_tag, result_pair<R>,
+ typename std::iterator_traits<IterOfRange<R>>::difference_type,
+ typename std::iterator_traits<IterOfRange<R>>::pointer,
+ typename std::iterator_traits<IterOfRange<R>>::reference> {
+ using result_type = result_pair<R>;
- bool operator!=(const iterator &RHS) const { return Iter != RHS.Iter; }
+public:
+ explicit enumerator_iter(IterOfRange<R> EndIter)
+ : Result(std::numeric_limits<size_t>::max(), EndIter) { }
- private:
- IterOfRange<R> Iter;
- std::size_t Index;
- };
+ enumerator_iter(std::size_t Index, IterOfRange<R> Iter)
+ : Result(Index, Iter) {}
+
+ result_type &operator*() { return Result; }
+ const result_type &operator*() const { return Result; }
+ enumerator_iter<R> &operator++() {
+ assert(Result.Index != std::numeric_limits<size_t>::max());
+ ++Result.Iter;
+ ++Result.Index;
+ return *this;
+ }
+
+ bool operator==(const enumerator_iter<R> &RHS) const {
+ // Don't compare indices here, only iterators. It's possible for an end
+ // iterator to have different indices depending on whether it was created
+ // by calling std::end() versus incrementing a valid iterator.
+ return Result.Iter == RHS.Result.Iter;
+ }
+
+ enumerator_iter<R> &operator=(const enumerator_iter<R> &Other) {
+ Result = Other.Result;
+ return *this;
+ }
+
+private:
+ result_type Result;
+};
+
+template <typename R> class enumerator {
public:
- explicit enumerator_impl(R &&Range) : Range(std::forward<R>(Range)) {}
+ explicit enumerator(R &&Range) : TheRange(std::forward<R>(Range)) {}
- iterator begin() { return iterator(std::begin(Range), 0); }
- iterator end() { return iterator(std::end(Range), std::size_t(-1)); }
+ enumerator_iter<R> begin() {
+ return enumerator_iter<R>(0, std::begin(TheRange));
+ }
+ enumerator_iter<R> end() {
+ return enumerator_iter<R>(std::end(TheRange));
+ }
private:
- R Range;
+ R TheRange;
};
}
@@ -968,8 +1088,8 @@ private:
/// Item 2 - C
/// Item 3 - D
///
-template <typename R> detail::enumerator_impl<R> enumerate(R &&Range) {
- return detail::enumerator_impl<R>(std::forward<R>(Range));
+template <typename R> detail::enumerator<R> enumerate(R &&TheRange) {
+ return detail::enumerator<R>(std::forward<R>(TheRange));
}
namespace detail {