//===- STLExtras.h - additions to the STL -----------------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // /// \file Provides STL-style algorithms for convenience. // //===----------------------------------------------------------------------===// #ifndef SWIFT_BASIC_INTERLEAVE_H #define SWIFT_BASIC_INTERLEAVE_H #include "swift/Basic/LLVM.h" #include "llvm/ADT/Optional.h" #include "llvm/Support/Casting.h" #include #include #include #include namespace swift { /// @{ /// An STL-style algorithm similar to std::for_each that applies a second /// functor between every pair of elements. /// /// This provides the control flow logic to, for example, print a /// comma-separated list: /// \code /// interleave(names.begin(), names.end(), /// [&](StringRef name) { OS << name; }, /// [&] { OS << ", "; }); /// \endcode template inline void interleave(ForwardIterator begin, ForwardIterator end, UnaryFunctor each_fn, NullaryFunctor between_fn) { if (begin == end) return; each_fn(*begin); ++begin; for (; begin != end; ++begin) { between_fn(); each_fn(*begin); } } template inline void interleave(const Container &c, UnaryFunctor each_fn, NullaryFunctor between_fn) { interleave(c.begin(), c.end(), each_fn, between_fn); } /// @} /// @{ /// 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); } /// @} /// A range of iterators. template class IteratorRange { Iterator First, Last; public: typedef Iterator iterator; IteratorRange(Iterator first, Iterator last) : First(first), Last(last) { } iterator begin() const { return First; } iterator end() const { return Last; } 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 iterator range. template inline IteratorRange makeIteratorRange(Iterator first, Iterator last) { return IteratorRange(first, last); } /// An iterator that filters the results of an underlying forward /// iterator, only passing through those values that satisfy a predicate. /// /// \tparam Iterator the underlying iterator. /// /// \tparam Predicate A predicate that determines whether a value of the /// underlying iterator is available in the resulting sequence. template class FilterIterator { Iterator Current, End; /// FIXME: Could optimize away this storage with EBCO tricks. Predicate Pred; /// Skip any non-matching elements. void skipNonMatching() { while (Current != End && !Pred(*Current)) ++Current; } 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 predicate. enum PrimedT { Primed }; typedef std::forward_iterator_tag iterator_category; typedef typename std::iterator_traits::value_type value_type; typedef typename std::iterator_traits::reference reference; typedef typename std::iterator_traits::pointer pointer; typedef typename std::iterator_traits::difference_type difference_type; /// Construct a new filtering iterator for the given iterator range /// and predicate. FilterIterator(Iterator current, Iterator end, Predicate pred) : Current(current), End(end), Pred(pred) { // Prime the iterator. skipNonMatching(); } /// Construct a new filtering iterator for the given iterator range /// and predicate, where the iterator range has already been /// "primed" by ensuring that it is empty or the current iterator /// points to something that matches the predicate. FilterIterator(Iterator current, Iterator end, Predicate pred, PrimedT) : Current(current), End(end), Pred(pred) { // Assert that the iterators have already been primed. assert(Current == End || Pred(*Current) && "Not primed!"); } reference operator*() const { return *Current; } pointer operator->() const { return Current.operator->(); } FilterIterator &operator++() { ++Current; skipNonMatching(); return *this; } FilterIterator operator++(int) { FilterIterator old = *this; ++*this; return old; } friend bool operator==(FilterIterator lhs, FilterIterator rhs) { return lhs.Current == rhs.Current; } friend bool operator!=(FilterIterator lhs, FilterIterator rhs) { return !(lhs == rhs); } }; /// Create a new filter iterator. template inline FilterIterator makeFilterIterator(Iterator current, Iterator end, Predicate pred) { return FilterIterator(current, end, pred); } /// A range filtered by a specific predicate. template class FilterRange { typedef typename Range::iterator Iterator; Iterator First, Last; Predicate Pred; public: typedef FilterIterator iterator; FilterRange(Range range, Predicate pred) : First(range.begin()), Last(range.end()), Pred(pred) { // Prime the sequence. while (First != Last && !Pred(*First)) ++First; } iterator begin() const { return iterator(First, Last, Pred, iterator::Primed); } iterator end() const { return iterator(Last, Last, Pred, 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 FilterRange makeFilterRange(Range range, Predicate pred) { return FilterRange(range, pred); } /// An iterator that transforms the result of an underlying forward /// iterator with a given operation. /// /// \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. typedef typename std::iterator_traits::reference UnderlyingReference; public: typedef std::forward_iterator_tag iterator_category; typedef typename std::result_of::type value_type; typedef value_type reference; typedef void pointer; // FIXME: Should provide a pointer proxy. typedef typename std::iterator_traits::difference_type 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; } 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: typedef TransformIterator iterator; 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(); } 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 an 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; } typedef typename std::iterator_traits::reference UnderlyingReference; typedef typename std::result_of::type ResultReference; 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 }; typedef std::forward_iterator_tag iterator_category; typedef typename ResultReference::value_type reference; typedef typename ResultReference::value_type value_type; typedef void pointer; // FIXME: should add a proxy here. typedef typename std::iterator_traits::difference_type 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); } 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 class OptionalTransformRange { typedef typename Range::iterator Iterator; Iterator First, Last; OptionalTransform Op; public: typedef OptionalTransformIterator iterator; 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 -> Optional(value))> { if (auto result = llvm::dyn_cast(value)) return result; return None; } template auto operator()(const Superclass &value) const -> Optional(value))> { if (auto result = llvm::dyn_cast(value)) return result; return None; } }; template using DowncastFilterIterator = OptionalTransformIterator>; template inline DowncastFilterIterator makeDowncastFilterIterator(Iterator current, Iterator end) { DowncastAsOptional op; return DowncastFilterIterator(current, end, op); } template class DowncastFilterRange : public OptionalTransformRange> { typedef OptionalTransformRange> Inherited; public: DowncastFilterRange(Range range) : Inherited(range, DowncastAsOptional()) { } }; template DowncastFilterRange makeDowncastFilterRange(Range range) { return DowncastFilterRange(range); } } // end namespace swift #endif