//===- llvm/ADT/STLExtras.h - Useful STL related functions ------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// /// \file /// This file contains some templates that are useful if you are working with /// the STL at all. /// /// No library is required when using these functions. /// //===----------------------------------------------------------------------===// #ifndef LLVM_ADT_STLEXTRAS_H #define LLVM_ADT_STLEXTRAS_H #include "llvm/ADT/ADL.h" #include "llvm/ADT/Hashing.h" #include "llvm/ADT/STLForwardCompat.h" #include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Config/abi-breaking.h" #include "llvm/Support/ErrorHandling.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef EXPENSIVE_CHECKS #include // for std::mt19937 #endif namespace llvm { //===----------------------------------------------------------------------===// // Extra additions to //===----------------------------------------------------------------------===// template struct make_const_ptr { using type = std::add_pointer_t>; }; template struct make_const_ref { using type = std::add_lvalue_reference_t>; }; /// This class provides various trait information about a callable object. /// * To access the number of arguments: Traits::num_args /// * To access the type of an argument: Traits::arg_t /// * To access the type of the result: Traits::result_t template ::value> struct function_traits : public function_traits {}; /// Overload for class function types. template struct function_traits { /// The number of arguments to this function. enum { num_args = sizeof...(Args) }; /// The result type of this function. using result_t = ReturnType; /// The type of an argument to this function. template using arg_t = std::tuple_element_t>; }; /// Overload for class function types. template struct function_traits : public function_traits {}; /// Overload for non-class function types. template struct function_traits { /// The number of arguments to this function. enum { num_args = sizeof...(Args) }; /// The result type of this function. using result_t = ReturnType; /// The type of an argument to this function. template using arg_t = std::tuple_element_t>; }; template struct function_traits : public function_traits {}; /// Overload for non-class function type references. template struct function_traits : public function_traits {}; /// traits class for checking whether type T is one of any of the given /// types in the variadic list. template using is_one_of = std::disjunction...>; /// traits class for checking whether type T is a base class for all /// the given types in the variadic list. template using are_base_of = std::conjunction...>; /// traits class for checking whether type `T` is same as all other types in /// `Ts`. template using all_types_equal = std::conjunction...>; template constexpr bool all_types_equal_v = all_types_equal::value; /// Determine if all types in Ts are distinct. /// /// Useful to statically assert when Ts is intended to describe a non-multi set /// of types. /// /// Expensive (currently quadratic in sizeof(Ts...)), and so should only be /// asserted once per instantiation of a type which requires it. template struct TypesAreDistinct; template <> struct TypesAreDistinct<> : std::true_type {}; template struct TypesAreDistinct : std::conjunction>, TypesAreDistinct> {}; /// Find the first index where a type appears in a list of types. /// /// FirstIndexOfType::value is the first index of T in Us. /// /// Typically only meaningful when it is otherwise statically known that the /// type pack has no duplicate types. This should be guaranteed explicitly with /// static_assert(TypesAreDistinct::value). /// /// It is a compile-time error to instantiate when T is not present in Us, i.e. /// if is_one_of::value is false. template struct FirstIndexOfType; template struct FirstIndexOfType : std::integral_constant::value> {}; template struct FirstIndexOfType : std::integral_constant {}; /// Find the type at a given index in a list of types. /// /// TypeAtIndex is the type at index I in Ts. template using TypeAtIndex = std::tuple_element_t>; /// Helper which adds two underlying types of enumeration type. /// Implicit conversion to a common type is accepted. template ::value, std::underlying_type_t>, typename UT2 = std::enable_if_t::value, std::underlying_type_t>> constexpr auto addEnumValues(EnumTy1 LHS, EnumTy2 RHS) { return static_cast(LHS) + static_cast(RHS); } //===----------------------------------------------------------------------===// // Extra additions to //===----------------------------------------------------------------------===// namespace callable_detail { /// Templated storage wrapper for a callable. /// /// This class is consistently default constructible, copy / move /// constructible / assignable. /// /// Supported callable types: /// - Function pointer /// - Function reference /// - Lambda /// - Function object template >>> class Callable { using value_type = std::remove_reference_t; using reference = value_type &; using const_reference = value_type const &; std::optional Obj; static_assert(!std::is_pointer_v, "Pointers to non-functions are not callable."); public: Callable() = default; Callable(T const &O) : Obj(std::in_place, O) {} Callable(Callable const &Other) = default; Callable(Callable &&Other) = default; Callable &operator=(Callable const &Other) { Obj = std::nullopt; if (Other.Obj) Obj.emplace(*Other.Obj); return *this; } Callable &operator=(Callable &&Other) { Obj = std::nullopt; if (Other.Obj) Obj.emplace(std::move(*Other.Obj)); return *this; } template , int> = 0> decltype(auto) operator()(Pn &&...Params) { return (*Obj)(std::forward(Params)...); } template , int> = 0> decltype(auto) operator()(Pn &&...Params) const { return (*Obj)(std::forward(Params)...); } bool valid() const { return Obj != std::nullopt; } bool reset() { return Obj = std::nullopt; } operator reference() { return *Obj; } operator const_reference() const { return *Obj; } }; // Function specialization. No need to waste extra space wrapping with a // std::optional. template class Callable { static constexpr bool IsPtr = std::is_pointer_v>; using StorageT = std::conditional_t *>; using CastT = std::conditional_t; private: StorageT Func = nullptr; private: template static constexpr auto convertIn(In &&I) { if constexpr (IsPtr) { // Pointer... just echo it back. return I; } else { // Must be a function reference. Return its address. return &I; } } public: Callable() = default; // Construct from a function pointer or reference. // // Disable this constructor for references to 'Callable' so we don't violate // the rule of 0. template < // clang-format off typename FnPtrOrRef, std::enable_if_t< !std::is_same_v, Callable>, int > = 0 > // clang-format on Callable(FnPtrOrRef &&F) : Func(convertIn(F)) {} template , int> = 0> decltype(auto) operator()(Pn &&...Params) const { return Func(std::forward(Params)...); } bool valid() const { return Func != nullptr; } void reset() { Func = nullptr; } operator T const &() const { if constexpr (IsPtr) { // T is a pointer... just echo it back. return Func; } else { static_assert(std::is_reference_v, "Expected a reference to a function."); // T is a function reference... dereference the stored pointer. return *Func; } } }; } // namespace callable_detail /// Returns true if the given container only contains a single element. template bool hasSingleElement(ContainerTy &&C) { auto B = adl_begin(C); auto E = adl_end(C); return B != E && std::next(B) == E; } /// Asserts that the given container has a single element and returns that /// element. template decltype(auto) getSingleElement(ContainerTy &&C) { assert(hasSingleElement(C) && "expected container with single element"); return *adl_begin(C); } /// Return a range covering \p RangeOrContainer with the first N elements /// excluded. template auto drop_begin(T &&RangeOrContainer, size_t N = 1) { return make_range(std::next(adl_begin(RangeOrContainer), N), adl_end(RangeOrContainer)); } /// Return a range covering \p RangeOrContainer with the last N elements /// excluded. template auto drop_end(T &&RangeOrContainer, size_t N = 1) { return make_range(adl_begin(RangeOrContainer), std::prev(adl_end(RangeOrContainer), N)); } // mapped_iterator - This is a simple iterator adapter that causes a function to // be applied whenever operator* is invoked on the iterator. template ()(*std::declval()))> class mapped_iterator : public iterator_adaptor_base< mapped_iterator, ItTy, typename std::iterator_traits::iterator_category, std::remove_reference_t, typename std::iterator_traits::difference_type, std::remove_reference_t *, ReferenceTy> { public: mapped_iterator() = default; mapped_iterator(ItTy U, FuncTy F) : mapped_iterator::iterator_adaptor_base(std::move(U)), F(std::move(F)) {} ItTy getCurrent() { return this->I; } const FuncTy &getFunction() const { return F; } ReferenceTy operator*() const { return F(*this->I); } private: callable_detail::Callable F{}; }; // map_iterator - Provide a convenient way to create mapped_iterators, just like // make_pair is useful for creating pairs... template inline mapped_iterator map_iterator(ItTy I, FuncTy F) { return mapped_iterator(std::move(I), std::move(F)); } template auto map_range(ContainerTy &&C, FuncTy F) { return make_range(map_iterator(adl_begin(C), F), map_iterator(adl_end(C), F)); } /// A base type of mapped iterator, that is useful for building derived /// iterators that do not need/want to store the map function (as in /// mapped_iterator). These iterators must simply provide a `mapElement` method /// that defines how to map a value of the iterator to the provided reference /// type. template class mapped_iterator_base : public iterator_adaptor_base< DerivedT, ItTy, typename std::iterator_traits::iterator_category, std::remove_reference_t, typename std::iterator_traits::difference_type, std::remove_reference_t *, ReferenceTy> { public: using BaseT = mapped_iterator_base; mapped_iterator_base(ItTy U) : mapped_iterator_base::iterator_adaptor_base(std::move(U)) {} ItTy getCurrent() { return this->I; } ReferenceTy operator*() const { return static_cast(*this).mapElement(*this->I); } }; namespace detail { template using check_has_free_function_rbegin = decltype(adl_rbegin(std::declval())); template static constexpr bool HasFreeFunctionRBegin = is_detected::value; } // namespace detail // Returns an iterator_range over the given container which iterates in reverse. // Does not mutate the container. template [[nodiscard]] auto reverse(ContainerTy &&C) { if constexpr (detail::HasFreeFunctionRBegin) return make_range(adl_rbegin(C), adl_rend(C)); else return make_range(std::make_reverse_iterator(adl_end(C)), std::make_reverse_iterator(adl_begin(C))); } /// An iterator adaptor that filters the elements of given inner iterators. /// /// The predicate parameter should be a callable object that accepts the wrapped /// iterator's reference type and returns a bool. When incrementing or /// decrementing the iterator, it will call the predicate on each element and /// skip any where it returns false. /// /// \code /// int A[] = { 1, 2, 3, 4 }; /// auto R = make_filter_range(A, [](int N) { return N % 2 == 1; }); /// // R contains { 1, 3 }. /// \endcode /// /// Note: filter_iterator_base implements support for forward iteration. /// filter_iterator_impl exists to provide support for bidirectional iteration, /// conditional on whether the wrapped iterator supports it. template class filter_iterator_base : public iterator_adaptor_base< filter_iterator_base, WrappedIteratorT, std::common_type_t::iterator_category>> { using BaseT = typename filter_iterator_base::iterator_adaptor_base; protected: WrappedIteratorT End; PredicateT Pred; void findNextValid() { while (this->I != End && !Pred(*this->I)) BaseT::operator++(); } filter_iterator_base() = default; // Construct the iterator. The begin iterator needs to know where the end // is, so that it can properly stop when it gets there. The end iterator only // needs the predicate to support bidirectional iteration. filter_iterator_base(WrappedIteratorT Begin, WrappedIteratorT End, PredicateT Pred) : BaseT(Begin), End(End), Pred(Pred) { findNextValid(); } public: using BaseT::operator++; filter_iterator_base &operator++() { BaseT::operator++(); findNextValid(); return *this; } decltype(auto) operator*() const { assert(BaseT::wrapped() != End && "Cannot dereference end iterator!"); return BaseT::operator*(); } decltype(auto) operator->() const { assert(BaseT::wrapped() != End && "Cannot dereference end iterator!"); return BaseT::operator->(); } }; /// Specialization of filter_iterator_base for forward iteration only. template class filter_iterator_impl : public filter_iterator_base { public: filter_iterator_impl() = default; filter_iterator_impl(WrappedIteratorT Begin, WrappedIteratorT End, PredicateT Pred) : filter_iterator_impl::filter_iterator_base(Begin, End, Pred) {} }; /// Specialization of filter_iterator_base for bidirectional iteration. template class filter_iterator_impl : public filter_iterator_base { using BaseT = typename filter_iterator_impl::filter_iterator_base; void findPrevValid() { while (!this->Pred(*this->I)) BaseT::operator--(); } public: using BaseT::operator--; filter_iterator_impl() = default; filter_iterator_impl(WrappedIteratorT Begin, WrappedIteratorT End, PredicateT Pred) : BaseT(Begin, End, Pred) {} filter_iterator_impl &operator--() { BaseT::operator--(); findPrevValid(); return *this; } }; namespace detail { /// A type alias which is std::bidirectional_iterator_tag if the category of /// \p IterT derives from it, and std::forward_iterator_tag otherwise. template using fwd_or_bidi_tag = std::conditional_t< std::is_base_of_v::iterator_category>, std::bidirectional_iterator_tag, std::forward_iterator_tag>; } // namespace detail /// Defines filter_iterator to a suitable specialization of /// filter_iterator_impl, based on the underlying iterator's category. template using filter_iterator = filter_iterator_impl>; /// Convenience function that takes a range of elements and a predicate, /// and return a new filter_iterator range. /// /// FIXME: Currently if RangeT && is a rvalue reference to a temporary, the /// lifetime of that temporary is not kept by the returned range object, and the /// temporary is going to be dropped on the floor after the make_iterator_range /// full expression that contains this function call. template iterator_range, PredicateT>> make_filter_range(RangeT &&Range, PredicateT Pred) { using FilterIteratorT = filter_iterator, PredicateT>; auto B = adl_begin(Range); auto E = adl_end(Range); return make_range(FilterIteratorT(B, E, Pred), FilterIteratorT(E, E, Pred)); } /// A pseudo-iterator adaptor that is designed to implement "early increment" /// style loops. /// /// This is *not a normal iterator* and should almost never be used directly. It /// is intended primarily to be used with range based for loops and some range /// algorithms. /// /// The iterator isn't quite an `OutputIterator` or an `InputIterator` but /// somewhere between them. The constraints of these iterators are: /// /// - On construction or after being incremented, it is comparable and /// dereferencable. It is *not* incrementable. /// - After being dereferenced, it is neither comparable nor dereferencable, it /// is only incrementable. /// /// This means you can only dereference the iterator once, and you can only /// increment it once between dereferences. template class early_inc_iterator_impl : public iterator_adaptor_base, WrappedIteratorT, std::input_iterator_tag> { using BaseT = typename early_inc_iterator_impl::iterator_adaptor_base; using PointerT = typename std::iterator_traits::pointer; protected: #if LLVM_ENABLE_ABI_BREAKING_CHECKS bool IsEarlyIncremented = false; #endif public: early_inc_iterator_impl(WrappedIteratorT I) : BaseT(I) {} using BaseT::operator*; decltype(*std::declval()) operator*() { #if LLVM_ENABLE_ABI_BREAKING_CHECKS assert(!IsEarlyIncremented && "Cannot dereference twice!"); IsEarlyIncremented = true; #endif return *(this->I)++; } using BaseT::operator++; early_inc_iterator_impl &operator++() { #if LLVM_ENABLE_ABI_BREAKING_CHECKS assert(IsEarlyIncremented && "Cannot increment before dereferencing!"); IsEarlyIncremented = false; #endif return *this; } friend bool operator==(const early_inc_iterator_impl &LHS, const early_inc_iterator_impl &RHS) { #if LLVM_ENABLE_ABI_BREAKING_CHECKS assert(!LHS.IsEarlyIncremented && "Cannot compare after dereferencing!"); #endif return (const BaseT &)LHS == (const BaseT &)RHS; } }; /// Make a range that does early increment to allow mutation of the underlying /// range without disrupting iteration. /// /// The underlying iterator will be incremented immediately after it is /// dereferenced, allowing deletion of the current node or insertion of nodes to /// not disrupt iteration provided they do not invalidate the *next* iterator -- /// the current iterator can be invalidated. /// /// This requires a very exact pattern of use that is only really suitable to /// range based for loops and other range algorithms that explicitly guarantee /// to dereference exactly once each element, and to increment exactly once each /// element. template iterator_range>> make_early_inc_range(RangeT &&Range) { using EarlyIncIteratorT = early_inc_iterator_impl>; return make_range(EarlyIncIteratorT(adl_begin(Range)), EarlyIncIteratorT(adl_end(Range))); } // Forward declarations required by zip_shortest/zip_equal/zip_first/zip_longest template bool all_of(R &&range, UnaryPredicate P); template bool any_of(R &&range, UnaryPredicate P); template bool all_equal(std::initializer_list Values); template constexpr size_t range_size(R &&Range); namespace detail { 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 struct ZipTupleType { using type = std::tuple())...>; }; template using zip_traits = iterator_facade_base< ZipType, std::common_type_t< std::bidirectional_iterator_tag, typename std::iterator_traits::iterator_category...>, // ^ TODO: Implement random access methods. ReferenceTupleType, typename std::iterator_traits< std::tuple_element_t<0, std::tuple>>::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. ReferenceTupleType *, ReferenceTupleType>; template struct zip_common : public zip_traits { using Base = zip_traits; using IndexSequence = std::index_sequence_for; using value_type = typename Base::value_type; std::tuple iterators; protected: template value_type deref(std::index_sequence) const { return value_type(*std::get(iterators)...); } template void tup_inc(std::index_sequence) { (++std::get(iterators), ...); } template void tup_dec(std::index_sequence) { (--std::get(iterators), ...); } template bool test_all_equals(const zip_common &other, std::index_sequence) const { return ((std::get(this->iterators) == std::get(other.iterators)) && ...); } public: zip_common(Iters &&... ts) : iterators(std::forward(ts)...) {} value_type operator*() const { return deref(IndexSequence{}); } ZipType &operator++() { tup_inc(IndexSequence{}); return static_cast(*this); } ZipType &operator--() { static_assert(Base::IsBidirectional, "All inner iterators must be at least bidirectional."); tup_dec(IndexSequence{}); return static_cast(*this); } /// Return true if all the iterator are matching `other`'s iterators. bool all_equals(zip_common &other) { return test_all_equals(other, IndexSequence{}); } }; template struct zip_first : zip_common, typename ZipTupleType::type, Iters...> { using zip_common::type, Iters...>::zip_common; bool operator==(const zip_first &other) const { return std::get<0>(this->iterators) == std::get<0>(other.iterators); } }; template struct zip_shortest : zip_common, typename ZipTupleType::type, Iters...> { using zip_common::type, Iters...>::zip_common; bool operator==(const zip_shortest &other) const { return any_iterator_equals(other, std::index_sequence_for{}); } private: template bool any_iterator_equals(const zip_shortest &other, std::index_sequence) const { return ((std::get(this->iterators) == std::get(other.iterators)) || ...); } }; /// Helper to obtain the iterator types for the tuple storage within `zippy`. template