//===--- STLExtras.h - additions to the STL ---------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // /// \file Provides STL-style algorithms for convenience. // //===----------------------------------------------------------------------===// #ifndef SWIFT_BASIC_STLEXTRAS_H #define SWIFT_BASIC_STLEXTRAS_H #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Casting.h" #include #include #include #include #include #include #include #include namespace swift { //===----------------------------------------------------------------------===// // Function Traits //===----------------------------------------------------------------------===// template struct function_traits : function_traits {}; // function template struct function_traits { using result_type = R; using argument_types = std::tuple; }; // function pointer template struct function_traits { using result_type = R; using argument_types = std::tuple; }; // std::function template struct function_traits> { using result_type = R; using argument_types = std::tuple; }; // pointer-to-member-function (i.e., operator()'s) template struct function_traits { using result_type = R; using argument_types = std::tuple; }; template struct function_traits { using result_type = R; using argument_types = std::tuple; }; /// @{ /// The equivalent of std::for_each, but for two lists at once. template inline void for_each(InputIt1 I1, InputIt1 E1, InputIt2 I2, BinaryFunction f) { while (I1 != E1) { f(*I1, *I2); ++I1; ++I2; } } template inline void for_each(const Container1 &c1, const Container2 &c2, BinaryFunction f) { assert(c1.size() == c2.size()); for_each(c1.begin(), c1.end(), c2.begin(), f); } /// The equivalent of std::for_each, but for three lists at once. template inline void for_each3(InputIt1 I1, InputIt1 E1, InputIt2 I2, InputIt3 I3, TernaryFunction f) { while (I1 != E1) { f(*I1, *I2, *I3); ++I1; ++I2; ++I3; } } template inline void for_each3(const Container1 &c1, const Container2 &c2, const Container3 &c3, TernaryFunction f) { assert(c1.size() == c2.size()); assert(c2.size() == c3.size()); for_each3(c1.begin(), c1.end(), c2.begin(), c3.begin(), f); } /// The equivalent of std::for_each, but visits the set union of two sorted /// lists without allocating additional memory. /// /// This has the following requirements: /// /// 1. The ranges must be sorted. /// 2. The elements must have the same type. /// 3. There are no duplicate elements. /// 4. All elements must be comparable with std::less. template inline void set_union_for_each(InputIt1 I1, InputIt1 E1, InputIt2 I2, InputIt2 E2, BinaryFunction f) { static_assert( std::is_same< typename std::iterator_traits::value_type, typename std::iterator_traits::value_type >::value, "Expected both iterator types to have the same underlying value type"); using RefTy = typename std::iterator_traits::reference; while (true) { // If we have reached the end of either list, visit the rest of the other // list, We do not need to worry about duplicates since each array we know // is unique. if (I1 == E1) { std::for_each(I2, E2, f); return; } if (I2 == E2) { std::for_each(I1, E1, f); return; } // If I1 < I2, then visit I1 and continue. if (std::less()(*I1, *I2)) { f(*I1); ++I1; continue; } // If I2 < I1, visit I2 and continue. if (std::less()(*I2, *I1)) { f(*I2); ++I2; continue; } // Otherwise, we know that I1 and I2 equal. We know that we can only have // one of each element in each list, so we can just visit I1 and continue. f(*I1); ++I1; ++I2; } } /// A container adapter for set_union_for_each. /// /// To see the requirements upon the containers, please see the iterator based /// set_union_for_each. template inline void set_union_for_each(const Container1 &C1, const Container2 &C2, UnaryFunction f) { // Make sure that our iterators have the same value type. static_assert( std::is_same< typename std::iterator_traits< typename Container1::iterator >::value_type, typename std::iterator_traits< typename Container2::iterator >::value_type >::value, "Expected both containers to have the same iterator value type"); set_union_for_each(C1.begin(), C1.end(), C2.begin(), C2.end(), f); } /// If \p it is equal to \p end, then return \p defaultIter. Otherwise, return /// std::next(\p it). template inline Iterator next_or_default(Iterator it, Iterator end, Iterator defaultIter) { return (it == end) ? defaultIter : std::next(it); } /// If \p it is equal to \p begin, then return \p defaultIter. Otherwise, return /// std::prev(\p it). template inline Iterator prev_or_default(Iterator it, Iterator begin, Iterator defaultIter) { return (it == begin) ? defaultIter : std::prev(it); } /// Takes an iterator and an iterator pointing to the end of the iterator range. /// If the iterator already points to the end of its range, simply return it, /// otherwise return the next element. template inline Iterator next_or_end(Iterator it, Iterator end) { return next_or_default(it, end, end); } template inline Iterator prev_or_begin(Iterator it, Iterator begin) { return prev_or_default(it, begin, begin); } /// @} /// An iterator that walks a linked list of objects until it reaches /// a null pointer. template class LinkedListIterator { T *Pointer; public: using iterator_category = std::forward_iterator_tag; using value_type = T *; using reference = T *; using pointer = void; /// Returns an iterator range starting from the given pointer and /// running until it reaches a null pointer. static llvm::iterator_range rangeBeginning(T *pointer) { return {pointer, nullptr}; } constexpr LinkedListIterator(T *pointer) : Pointer(pointer) {} T *operator*() const { assert(Pointer && "dereferencing a null iterator"); return Pointer; } LinkedListIterator &operator++() { Pointer = getNext(Pointer); return *this; } LinkedListIterator operator++(int) { auto copy = *this; Pointer = getNext(Pointer); return copy; } friend bool operator==(LinkedListIterator lhs, LinkedListIterator rhs) { return lhs.Pointer == rhs.Pointer; } friend bool operator!=(LinkedListIterator lhs, LinkedListIterator rhs) { return lhs.Pointer != rhs.Pointer; } }; /// An iterator that transforms the result of an underlying bidirectional /// iterator with a given operation. /// /// Slightly different semantics from llvm::map_iterator, but we should /// probably figure out how to merge them eventually. /// /// \tparam Iterator the underlying iterator. /// /// \tparam Operation A function object that transforms the underlying /// sequence's values into the new sequence's values. template class TransformIterator { Iterator Current; /// FIXME: Could optimize away this storage with EBCO tricks. Operation Op; /// The underlying reference type, which will be passed to the /// operation. using OpTraits = function_traits; public: using iterator_category = std::bidirectional_iterator_tag; using value_type = typename OpTraits::result_type; using reference = value_type; using pointer = void; // FIXME: Should provide a pointer proxy. using difference_type = typename std::iterator_traits::difference_type; /// Construct a new transforming iterator for the given iterator /// and operation. TransformIterator(Iterator current, Operation op) : Current(current), Op(op) { } reference operator*() const { return Op(*Current); } TransformIterator &operator++() { ++Current; return *this; } TransformIterator operator++(int) { TransformIterator old = *this; ++*this; return old; } TransformIterator &operator--() { --Current; return *this; } TransformIterator operator--(int) { TransformIterator old = *this; --*this; return old; } friend bool operator==(TransformIterator lhs, TransformIterator rhs) { return lhs.Current == rhs.Current; } friend bool operator!=(TransformIterator lhs, TransformIterator rhs) { return !(lhs == rhs); } }; /// Create a new transform iterator. template inline TransformIterator makeTransformIterator(Iterator current, Operation op) { return TransformIterator(current, op); } /// A range transformed by a specific predicate. template class TransformRange { Range Rng; Operation Op; public: using iterator = TransformIterator; TransformRange(Range range, Operation op) : Rng(range), Op(op) { } iterator begin() const { return iterator(Rng.begin(), Op); } iterator end() const { return iterator(Rng.end(), Op); } bool empty() const { return begin() == end(); } // The dummy template parameter keeps 'size()' from being eagerly // instantiated. template typename function_traits::result_type size() const { return Rng.size(); } template typename function_traits::result_type operator[](Index index) const { return Op(Rng[index]); } typename std::iterator_traits::value_type front() const { assert(!empty() && "Front of empty range"); return *begin(); } }; /// Create a new transform range. template inline TransformRange makeTransformRange(Range range, Operation op) { return TransformRange(range, op); } /// An iterator that filters and transforms the results of an /// underlying forward iterator based on a transformation from the underlying /// value type to an optional result type. /// /// \tparam Iterator the underlying iterator. /// /// \tparam OptionalTransform A function object that maps a value of /// the underlying iterator type to an optional containing a value of /// the resulting sequence, or an empty optional if this item should /// be skipped. template class OptionalTransformIterator { Iterator Current, End; /// FIXME: Could optimize away this storage with EBCO tricks. OptionalTransform Op; /// Skip any non-matching elements. void skipNonMatching() { while (Current != End && !Op(*Current)) ++Current; } using UnderlyingReference = typename std::iterator_traits::reference; using ResultReference = typename std::invoke_result::type; public: /// Used to indicate when the current iterator has already been /// "primed", meaning that it's at the end or points to a value that /// satisfies the transform. enum PrimedT { Primed }; using iterator_category = std::forward_iterator_tag; using reference = typename ResultReference::value_type; using value_type = typename ResultReference::value_type; using pointer = void; // FIXME: should add a proxy here. using difference_type = typename std::iterator_traits::difference_type; /// Construct a new optional transform iterator for the given /// iterator range and operation. OptionalTransformIterator(Iterator current, Iterator end, OptionalTransform op) : Current(current), End(end), Op(op) { // Prime the iterator. skipNonMatching(); } /// Construct a new optional transform iterator for the given iterator range /// and operation, where the iterator range has already been /// "primed" by ensuring that it is empty or the current iterator /// points to something that matches the operation. OptionalTransformIterator(Iterator current, Iterator end, OptionalTransform op, PrimedT) : Current(current), End(end), Op(op) { // Assert that the iterators have already been primed. assert((Current == End || Op(*Current)) && "Not primed!"); } reference operator*() const { return *Op(*Current); } reference operator*() { return *Op(*Current); } OptionalTransformIterator &operator++() { ++Current; skipNonMatching(); return *this; } OptionalTransformIterator operator++(int) { OptionalTransformIterator old = *this; ++*this; return old; } friend bool operator==(OptionalTransformIterator lhs, OptionalTransformIterator rhs) { return lhs.Current == rhs.Current; } friend bool operator!=(OptionalTransformIterator lhs, OptionalTransformIterator rhs) { return !(lhs == rhs); } }; /// Create a new filter iterator. template inline OptionalTransformIterator makeOptionalTransformIterator(Iterator current, Iterator end, OptionalTransform op) { return OptionalTransformIterator(current, end, op); } /// A range filtered and transformed by the optional transform. template ().begin())> class OptionalTransformRange { Iterator First, Last; OptionalTransform Op; public: using iterator = OptionalTransformIterator; OptionalTransformRange(Range range, OptionalTransform op) : First(range.begin()), Last(range.end()), Op(op) { // Prime the sequence. while (First != Last && !Op(*First)) ++First; } iterator begin() const { return iterator(First, Last, Op, iterator::Primed); } iterator end() const { return iterator(Last, Last, Op, iterator::Primed); } bool empty() const { return First == Last; } typename std::iterator_traits::value_type front() const { assert(!empty() && "Front of empty range"); return *begin(); } }; /// Create a new filter range. template inline OptionalTransformRange makeOptionalTransformRange(Range range, OptionalTransform op) { return OptionalTransformRange(range, op); } /// Function object that attempts a downcast to a subclass, wrapping /// the result in an optional to indicate success or failure. template struct DowncastAsOptional { template auto operator()(Superclass &value) const -> std::optional(value))> { if (auto result = llvm::dyn_cast(value)) return result; return std::nullopt; } template auto operator()(const Superclass &value) const -> std::optional(value))> { if (auto result = llvm::dyn_cast(value)) return result; return std::nullopt; } }; template using DowncastFilterIterator = OptionalTransformIterator>; template inline DowncastFilterIterator makeDowncastFilterIterator(Iterator current, Iterator end) { DowncastAsOptional op; return DowncastFilterIterator(current, end, op); } template class DowncastFilterRange : public OptionalTransformRange> { using Inherited = OptionalTransformRange>; public: DowncastFilterRange(Range range) : Inherited(range, DowncastAsOptional()) { } }; template DowncastFilterRange makeDowncastFilterRange(Range range) { return DowncastFilterRange(range); } /// Sorts and then uniques a container with random access iterators and an erase /// method that removes a range specified by random access iterators. template void sortUnique( Container &C, typename std::enable_if< std::is_same::iterator_category, std::random_access_iterator_tag>::value, void>::type * = nullptr) { std::sort(C.begin(), C.end()); C.erase(std::unique(C.begin(), C.end()), C.end()); } /// Sorts and then uniques a container with random access iterators and an erase /// method that removes a range specified by random access iterators. template void sortUnique( Container &C, Comparator Cmp, typename std::enable_if< std::is_same::iterator_category, std::random_access_iterator_tag>::value, void>::type * = nullptr) { std::sort(C.begin(), C.end(), Cmp); C.erase(std::unique(C.begin(), C.end()), C.end()); } /// Returns true if [II, IE) is a sorted and uniqued array. Returns false /// otherwise. template inline bool is_sorted_and_uniqued(IterTy II, IterTy IE) { using RefTy = typename std::iterator_traits::reference; // The empty list is always sorted and uniqued. if (II == IE) return true; // The list of one element is always sorted and uniqued. auto LastI = II; ++II; if (II == IE) return true; // Otherwise, until we reach the end of the list... while (II != IE) { // If LastI is greater than II then we know that our array is not sorted. If // LastI equals II, then we know that our array is not unique. If both of // those are conditions are false, then visit the next iterator element. if (std::greater_equal()(*LastI, *II)) { // Return false otherwise. return false; } LastI = II; ++II; } // Success! return true; } template inline bool is_sorted_and_uniqued(const Container &C) { return is_sorted_and_uniqued(C.begin(), C.end()); } template inline T accumulate(const Container &C, T init, BinaryOperation op) { return std::accumulate(C.begin(), C.end(), init, op); } template inline bool binary_search(const Container &C, const T &value) { return std::binary_search(C.begin(), C.end(), value); } template inline bool binary_search(const Container &C, const T &value, BinaryOperation op) { return std::binary_search(C.begin(), C.end(), value, op); } /// Returns true if the range defined by \p mainBegin ..< \p mainEnd starts with /// the same elements as the range defined by \p prefixBegin ..< \p prefixEnd. /// /// This includes cases where the prefix range is empty, as well as when the two /// ranges are the same length and contain the same elements. template inline bool hasPrefix(MainInputIterator mainBegin, const MainInputIterator mainEnd, PrefixInputIterator prefixBegin, const PrefixInputIterator prefixEnd) { while (prefixBegin != prefixEnd) { // If "main" is shorter than "prefix", it does not start with "prefix". if (mainBegin == mainEnd) return false; // If there's a mismatch, "main" does not start with "prefix". if (*mainBegin != *prefixBegin) return false; ++prefixBegin; ++mainBegin; } // If we checked every element of "prefix", "main" does start with "prefix". return true; } /// Provides default implementations of !=, <=, >, and >= based on == and <. template class RelationalOperationsBase { public: friend bool operator>(const T &left, const T &right) { return right < left; } friend bool operator>=(const T &left, const T &right) { return !(left < right); } friend bool operator<=(const T &left, const T &right) { return !(right < left); } friend bool operator!=(const T &left, const T &right) { return !(left == right); } }; /// Cast a pointer to \c U to a pointer to a supertype \c T. /// Example: Wobulator *w = up_cast(coloredWobulator) /// Useful with ?: where each arm is a different subtype. /// If \c U is not a subtype of \c T, the compiler will complain. template T *up_cast(U *ptr) { return ptr; } /// Removes all runs of values that match \p pred from the range of \p begin /// to \p end. /// /// This is similar to std::unique, but std::unique leaves the first value in /// place in a run of matching values, whereas this code removes all of them. /// /// \returns The new end iterator for the container. You should erase elements /// between this value and the existing end of the container. template Iterator removeAdjacentIf(const Iterator first, const Iterator last, BinaryPredicate pred) { using element_reference_t = typename std::iterator_traits::reference; auto nextOverlap = std::adjacent_find(first, last, pred); auto insertionPoint = nextOverlap; while (nextOverlap != last) { // We want to erase *all* the matching elements. There could be three or // more of them. Search for the end of the run. auto lastOverlapInRun = std::adjacent_find(std::next(nextOverlap), last, [&pred](element_reference_t left, element_reference_t right) -> bool { return !pred(left, right); }); // If we get the end iterator back, that means all remaining elements match. // If we don't, that means (lastOverlapInRun+1) is part of a different run. if (lastOverlapInRun != last) ++lastOverlapInRun; nextOverlap = std::adjacent_find(lastOverlapInRun, last, pred); insertionPoint = std::move(lastOverlapInRun, nextOverlap, insertionPoint); } return insertionPoint; } namespace detail { template struct bool_pack; } // namespace detail template using all_true = std::is_same, detail::bool_pack>; /// traits class for checking whether Ts consists only of compound types. template using are_all_compound = all_true::value...>; /// Erase all elements in \p c that match the given predicate \p pred. // FIXME: Remove this when C++20 is the new baseline. template typename std::unordered_set::size_type erase_if(std::unordered_set &c, Pred pred) { auto startingSize = c.size(); for (auto i = c.begin(), last = c.end(); i != last;) { if (pred(*i)) { i = c.erase(i); } else { ++i; } } return startingSize - c.size(); } /// Call \c vector.emplace_back with each of the other arguments /// to this function, in order. Constructing an intermediate /// \c std::initializer_list can be inefficient; more problematically, /// types such as \c std::vector copy out of the \c initializer_list /// instead of move. template void emplace_back_all(VectorType &vector, ValueType &&value, ValueTypes &&...values) { vector.emplace_back(std::forward(value)); emplace_back_all(vector, std::forward(values)...); } template void emplace_back_all(VectorType &vector) {} /// Apply a function to the value if present; otherwise return None. template auto transform(const std::optional &value, const Function &operation) -> std::optional { if (value) { return operation(*value); } return std::nullopt; } } // end namespace swift #endif // SWIFT_BASIC_STLEXTRAS_H