aboutsummaryrefslogtreecommitdiff
path: root/llvm/include/llvm/ADT/STLExtras.h
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/include/llvm/ADT/STLExtras.h')
-rw-r--r--llvm/include/llvm/ADT/STLExtras.h142
1 files changed, 95 insertions, 47 deletions
diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h
index 63c7f48a5bd2..eb001346b609 100644
--- a/llvm/include/llvm/ADT/STLExtras.h
+++ b/llvm/include/llvm/ADT/STLExtras.h
@@ -17,6 +17,7 @@
#define LLVM_ADT_STLEXTRAS_H
#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/STLForwardCompat.h"
#include "llvm/ADT/iterator.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Config/abi-breaking.h"
@@ -60,15 +61,6 @@ using ValueOfRange = typename std::remove_reference<decltype(
// Extra additions to <type_traits>
//===----------------------------------------------------------------------===//
-template <typename T>
-struct negation : std::integral_constant<bool, !bool(T::value)> {};
-
-template <typename...> struct conjunction : std::true_type {};
-template <typename B1> struct conjunction<B1> : B1 {};
-template <typename B1, typename... Bn>
-struct conjunction<B1, Bn...>
- : std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
-
template <typename T> struct make_const_ptr {
using type =
typename std::add_pointer<typename std::add_const<T>::type>::type;
@@ -79,13 +71,6 @@ template <typename T> struct make_const_ref {
typename std::add_const<T>::type>::type;
};
-/// Utilities for detecting if a given trait holds for some set of arguments
-/// 'Args'. For example, the given trait could be used to detect if a given type
-/// has a copy assignment operator:
-/// template<class T>
-/// using has_copy_assign_t = decltype(std::declval<T&>()
-/// = std::declval<const T&>());
-/// bool fooHasCopyAssign = is_detected<has_copy_assign_t, FooClass>::value;
namespace detail {
template <typename...> using void_t = void;
template <class, template <class...> class Op, class... Args> struct detector {
@@ -97,16 +82,23 @@ struct detector<void_t<Op<Args...>>, Op, Args...> {
};
} // end namespace detail
+/// Detects if a given trait holds for some set of arguments 'Args'.
+/// For example, the given trait could be used to detect if a given type
+/// has a copy assignment operator:
+/// template<class T>
+/// using has_copy_assign_t = decltype(std::declval<T&>()
+/// = std::declval<const T&>());
+/// bool fooHasCopyAssign = is_detected<has_copy_assign_t, FooClass>::value;
template <template <class...> class Op, class... Args>
using is_detected = typename detail::detector<void, Op, Args...>::value_t;
-/// Check if a Callable type can be invoked with the given set of arg types.
namespace detail {
template <typename Callable, typename... Args>
using is_invocable =
decltype(std::declval<Callable &>()(std::declval<Args>()...));
} // namespace detail
+/// Check if a Callable type can be invoked with the given set of arg types.
template <typename Callable, typename... Args>
using is_invocable = is_detected<detail::is_invocable, Callable, Args...>;
@@ -194,9 +186,8 @@ public:
function_ref(
Callable &&callable,
// This is not the copy-constructor.
- std::enable_if_t<
- !std::is_same<std::remove_cv_t<std::remove_reference_t<Callable>>,
- function_ref>::value> * = nullptr,
+ std::enable_if_t<!std::is_same<remove_cvref_t<Callable>,
+ function_ref>::value> * = nullptr,
// Functor must be callable and return a suitable type.
std::enable_if_t<std::is_void<Ret>::value ||
std::is_convertible<decltype(std::declval<Callable>()(
@@ -1114,9 +1105,9 @@ public:
iterator begin() const { return iterator(base, 0); }
iterator end() const { return iterator(base, count); }
- ReferenceT operator[](unsigned index) const {
- assert(index < size() && "invalid index for value range");
- return DerivedT::dereference_iterator(base, index);
+ ReferenceT operator[](size_t Index) const {
+ assert(Index < size() && "invalid index for value range");
+ return DerivedT::dereference_iterator(base, static_cast<ptrdiff_t>(Index));
}
ReferenceT front() const {
assert(!empty() && "expected non-empty range");
@@ -1300,27 +1291,65 @@ template <> struct rank<0> {};
/// traits class for checking whether type T is one of any of the given
/// types in the variadic list.
-template <typename T, typename... Ts> struct is_one_of {
- static const bool value = false;
-};
-
-template <typename T, typename U, typename... Ts>
-struct is_one_of<T, U, Ts...> {
- static const bool value =
- std::is_same<T, U>::value || is_one_of<T, Ts...>::value;
-};
+template <typename T, typename... Ts>
+using is_one_of = disjunction<std::is_same<T, Ts>...>;
/// traits class for checking whether type T is a base class for all
/// the given types in the variadic list.
-template <typename T, typename... Ts> struct are_base_of {
- static const bool value = true;
+template <typename T, typename... Ts>
+using are_base_of = conjunction<std::is_base_of<T, Ts>...>;
+
+namespace detail {
+template <typename... Ts> struct Visitor;
+
+template <typename HeadT, typename... TailTs>
+struct Visitor<HeadT, TailTs...> : remove_cvref_t<HeadT>, Visitor<TailTs...> {
+ explicit constexpr Visitor(HeadT &&Head, TailTs &&...Tail)
+ : remove_cvref_t<HeadT>(std::forward<HeadT>(Head)),
+ Visitor<TailTs...>(std::forward<TailTs>(Tail)...) {}
+ using remove_cvref_t<HeadT>::operator();
+ using Visitor<TailTs...>::operator();
};
-template <typename T, typename U, typename... Ts>
-struct are_base_of<T, U, Ts...> {
- static const bool value =
- std::is_base_of<T, U>::value && are_base_of<T, Ts...>::value;
+template <typename HeadT> struct Visitor<HeadT> : remove_cvref_t<HeadT> {
+ explicit constexpr Visitor(HeadT &&Head)
+ : remove_cvref_t<HeadT>(std::forward<HeadT>(Head)) {}
+ using remove_cvref_t<HeadT>::operator();
};
+} // namespace detail
+
+/// Returns an opaquely-typed Callable object whose operator() overload set is
+/// the sum of the operator() overload sets of each CallableT in CallableTs.
+///
+/// The type of the returned object derives from each CallableT in CallableTs.
+/// The returned object is constructed by invoking the appropriate copy or move
+/// constructor of each CallableT, as selected by overload resolution on the
+/// corresponding argument to makeVisitor.
+///
+/// Example:
+///
+/// \code
+/// auto visitor = makeVisitor([](auto) { return "unhandled type"; },
+/// [](int i) { return "int"; },
+/// [](std::string s) { return "str"; });
+/// auto a = visitor(42); // `a` is now "int".
+/// auto b = visitor("foo"); // `b` is now "str".
+/// auto c = visitor(3.14f); // `c` is now "unhandled type".
+/// \endcode
+///
+/// Example of making a visitor with a lambda which captures a move-only type:
+///
+/// \code
+/// std::unique_ptr<FooHandler> FH = /* ... */;
+/// auto visitor = makeVisitor(
+/// [FH{std::move(FH)}](Foo F) { return FH->handle(F); },
+/// [](int i) { return i; },
+/// [](std::string s) { return atoi(s); });
+/// \endcode
+template <typename... CallableTs>
+constexpr decltype(auto) makeVisitor(CallableTs &&...Callables) {
+ return detail::Visitor<CallableTs...>(std::forward<CallableTs>(Callables)...);
+}
//===----------------------------------------------------------------------===//
// Extra additions for arrays
@@ -1332,8 +1361,15 @@ template <class Iterator, class RNG>
void shuffle(Iterator first, Iterator last, RNG &&g) {
// It would be better to use a std::uniform_int_distribution,
// but that would be stdlib dependent.
- for (auto size = last - first; size > 1; ++first, (void)--size)
- std::iter_swap(first, first + g() % size);
+ typedef
+ typename std::iterator_traits<Iterator>::difference_type difference_type;
+ for (auto size = last - first; size > 1; ++first, (void)--size) {
+ difference_type offset = g() % size;
+ // Avoid self-assignment due to incorrect assertions in libstdc++
+ // containers (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85828).
+ if (offset != difference_type(0))
+ std::iter_swap(first, first + offset);
+ }
}
/// Find the length of an array.
@@ -1373,7 +1409,7 @@ inline unsigned presortShuffleEntropy() {
template <class IteratorTy>
inline void presortShuffle(IteratorTy Start, IteratorTy End) {
std::mt19937 Generator(presortShuffleEntropy());
- std::shuffle(Start, End, Generator);
+ llvm::shuffle(Start, End, Generator);
}
} // end namespace detail
@@ -1647,6 +1683,18 @@ auto partition_point(R &&Range, Predicate P) {
return std::partition_point(adl_begin(Range), adl_end(Range), P);
}
+template<typename Range, typename Predicate>
+auto unique(Range &&R, Predicate P) {
+ return std::unique(adl_begin(R), adl_end(R), P);
+}
+
+/// Wrapper function around std::equal to detect if pair-wise elements between
+/// two ranges are the same.
+template <typename L, typename R> bool equal(L &&LRange, R &&RRange) {
+ return std::equal(adl_begin(LRange), adl_end(LRange), adl_begin(RRange),
+ adl_end(RRange));
+}
+
/// Wrapper function around std::equal to detect if all elements
/// in a container are same.
template <typename R>
@@ -1820,9 +1868,9 @@ template <typename R> struct result_pair {
result_pair(std::size_t Index, IterOfRange<R> Iter)
: Index(Index), Iter(Iter) {}
- result_pair<R>(const result_pair<R> &Other)
+ result_pair(const result_pair<R> &Other)
: Index(Other.Index), Iter(Other.Iter) {}
- result_pair<R> &operator=(const result_pair<R> &Other) {
+ result_pair &operator=(const result_pair &Other) {
Index = Other.Index;
Iter = Other.Iter;
return *this;
@@ -1856,22 +1904,22 @@ public:
result_type &operator*() { return Result; }
const result_type &operator*() const { return Result; }
- enumerator_iter<R> &operator++() {
+ enumerator_iter &operator++() {
assert(Result.Index != std::numeric_limits<size_t>::max());
++Result.Iter;
++Result.Index;
return *this;
}
- bool operator==(const enumerator_iter<R> &RHS) const {
+ bool operator==(const enumerator_iter &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>(const enumerator_iter<R> &Other) : Result(Other.Result) {}
- enumerator_iter<R> &operator=(const enumerator_iter<R> &Other) {
+ enumerator_iter(const enumerator_iter &Other) : Result(Other.Result) {}
+ enumerator_iter &operator=(const enumerator_iter &Other) {
Result = Other.Result;
return *this;
}