// Copyright (c) 2016 Google Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef SOURCE_OPT_ITERATOR_H_ #define SOURCE_OPT_ITERATOR_H_ #include <cstddef> // for ptrdiff_t #include <iterator> #include <memory> #include <type_traits> #include <utility> #include <vector> namespace spvtools { namespace opt { // An ad hoc iterator class for std::vector<std::unique_ptr<|ValueType|>>. The // purpose of this iterator class is to provide transparent access to those // std::unique_ptr managed elements in the vector, behaving like we are using // std::vector<|ValueType|>. template <typename ValueType, bool IsConst = false> class UptrVectorIterator : public std::iterator<std::random_access_iterator_tag, typename std::conditional<IsConst, const ValueType, ValueType>::type> { public: using super = std::iterator< std::random_access_iterator_tag, typename std::conditional<IsConst, const ValueType, ValueType>::type>; using pointer = typename super::pointer; using reference = typename super::reference; using difference_type = typename super::difference_type; // Type aliases. We need to apply constness properly if |IsConst| is true. using Uptr = std::unique_ptr<ValueType>; using UptrVector = typename std::conditional<IsConst, const std::vector<Uptr>, std::vector<Uptr>>::type; using UnderlyingIterator = typename std::conditional<IsConst, typename UptrVector::const_iterator, typename UptrVector::iterator>::type; // Creates a new iterator from the given |container| and its raw iterator // |it|. UptrVectorIterator(UptrVector* container, const UnderlyingIterator& it) : container_(container), iterator_(it) {} UptrVectorIterator(const UptrVectorIterator&) = default; UptrVectorIterator& operator=(const UptrVectorIterator&) = default; inline UptrVectorIterator& operator++(); inline UptrVectorIterator operator++(int); inline UptrVectorIterator& operator--(); inline UptrVectorIterator operator--(int); reference operator*() const { return **iterator_; } pointer operator->() { return (*iterator_).get(); } reference operator[](ptrdiff_t index) { return **(iterator_ + index); } inline bool operator==(const UptrVectorIterator& that) const; inline bool operator!=(const UptrVectorIterator& that) const; inline ptrdiff_t operator-(const UptrVectorIterator& that) const; inline bool operator<(const UptrVectorIterator& that) const; // Inserts the given |value| to the position pointed to by this iterator // and returns an iterator to the newly iserted |value|. // If the underlying vector changes capacity, all previous iterators will be // invalidated. Otherwise, those previous iterators pointing to after the // insertion point will be invalidated. template <bool IsConstForMethod = IsConst> inline typename std::enable_if<!IsConstForMethod, UptrVectorIterator>::type InsertBefore(Uptr value); // Inserts the given |valueVector| to the position pointed to by this iterator // and returns an iterator to the first newly inserted value. // If the underlying vector changes capacity, all previous iterators will be // invalidated. Otherwise, those previous iterators pointing to after the // insertion point will be invalidated. template <bool IsConstForMethod = IsConst> inline typename std::enable_if<!IsConstForMethod, UptrVectorIterator>::type InsertBefore(UptrVector* valueVector); // Erases the value at the position pointed to by this iterator // and returns an iterator to the following value. // If the underlying vector changes capacity, all previous iterators will be // invalidated. Otherwise, those previous iterators pointing to after the // erasure point will be invalidated. template <bool IsConstForMethod = IsConst> inline typename std::enable_if<!IsConstForMethod, UptrVectorIterator>::type Erase(); // Returns the underlying iterator. UnderlyingIterator Get() const { return iterator_; } // Returns a valid end iterator for the underlying container. UptrVectorIterator End() const { return UptrVectorIterator(container_, container_->end()); } private: UptrVector* container_; // The container we are manipulating. UnderlyingIterator iterator_; // The raw iterator from the container. }; // Handy class for a (begin, end) iterator pair. template <typename IteratorType> class IteratorRange { public: IteratorRange(const IteratorType& b, const IteratorType& e) : begin_(b), end_(e) {} IteratorRange(IteratorType&& b, IteratorType&& e) : begin_(std::move(b)), end_(std::move(e)) {} IteratorType begin() const { return begin_; } IteratorType end() const { return end_; } bool empty() const { return begin_ == end_; } size_t size() const { return end_ - begin_; } private: IteratorType begin_; IteratorType end_; }; // Returns a (begin, end) iterator pair for the given iterators. // The iterators must belong to the same container. template <typename IteratorType> inline IteratorRange<IteratorType> make_range(const IteratorType& begin, const IteratorType& end) { return {begin, end}; } // Returns a (begin, end) iterator pair for the given iterators. // The iterators must belong to the same container. template <typename IteratorType> inline IteratorRange<IteratorType> make_range(IteratorType&& begin, IteratorType&& end) { return {std::move(begin), std::move(end)}; } // Returns a (begin, end) iterator pair for the given container. template <typename ValueType, class IteratorType = UptrVectorIterator<ValueType>> inline IteratorRange<IteratorType> make_range( std::vector<std::unique_ptr<ValueType>>& container) { return {IteratorType(&container, container.begin()), IteratorType(&container, container.end())}; } // Returns a const (begin, end) iterator pair for the given container. template <typename ValueType, class IteratorType = UptrVectorIterator<ValueType, true>> inline IteratorRange<IteratorType> make_const_range( const std::vector<std::unique_ptr<ValueType>>& container) { return {IteratorType(&container, container.cbegin()), IteratorType(&container, container.cend())}; } // Wrapping iterator class that only consider elements that satisfy the given // predicate |Predicate|. When moving to the next element of the iterator, the // FilterIterator will iterate over the range until it finds an element that // satisfies |Predicate| or reaches the end of the iterator. // // Currently this iterator is always an input iterator. template <typename SubIterator, typename Predicate> class FilterIterator : public std::iterator< std::input_iterator_tag, typename SubIterator::value_type, typename SubIterator::difference_type, typename SubIterator::pointer, typename SubIterator::reference> { public: // Iterator interface. using iterator_category = typename SubIterator::iterator_category; using value_type = typename SubIterator::value_type; using pointer = typename SubIterator::pointer; using reference = typename SubIterator::reference; using difference_type = typename SubIterator::difference_type; using Range = IteratorRange<FilterIterator>; FilterIterator(const IteratorRange<SubIterator>& iteration_range, Predicate predicate) : cur_(iteration_range.begin()), end_(iteration_range.end()), predicate_(predicate) { if (!IsPredicateSatisfied()) { MoveToNextPosition(); } } FilterIterator(const SubIterator& end, Predicate predicate) : FilterIterator({end, end}, predicate) {} inline FilterIterator& operator++() { MoveToNextPosition(); return *this; } inline FilterIterator operator++(int) { FilterIterator old = *this; MoveToNextPosition(); return old; } reference operator*() const { return *cur_; } pointer operator->() { return &*cur_; } inline bool operator==(const FilterIterator& rhs) const { return cur_ == rhs.cur_ && end_ == rhs.end_; } inline bool operator!=(const FilterIterator& rhs) const { return !(*this == rhs); } // Returns the underlying iterator. SubIterator Get() const { return cur_; } // Returns the sentinel iterator. FilterIterator GetEnd() const { return FilterIterator(end_, predicate_); } private: // Returns true if the predicate is satisfied or the current iterator reached // the end. bool IsPredicateSatisfied() { return cur_ == end_ || predicate_(*cur_); } void MoveToNextPosition() { if (cur_ == end_) return; do { ++cur_; } while (!IsPredicateSatisfied()); } SubIterator cur_; SubIterator end_; Predicate predicate_; }; template <typename SubIterator, typename Predicate> FilterIterator<SubIterator, Predicate> MakeFilterIterator( const IteratorRange<SubIterator>& sub_iterator_range, Predicate predicate) { return FilterIterator<SubIterator, Predicate>(sub_iterator_range, predicate); } template <typename SubIterator, typename Predicate> FilterIterator<SubIterator, Predicate> MakeFilterIterator( const SubIterator& begin, const SubIterator& end, Predicate predicate) { return MakeFilterIterator(make_range(begin, end), predicate); } template <typename SubIterator, typename Predicate> typename FilterIterator<SubIterator, Predicate>::Range MakeFilterIteratorRange( const SubIterator& begin, const SubIterator& end, Predicate predicate) { return typename FilterIterator<SubIterator, Predicate>::Range( MakeFilterIterator(begin, end, predicate), MakeFilterIterator(end, end, predicate)); } template <typename VT, bool IC> inline UptrVectorIterator<VT, IC>& UptrVectorIterator<VT, IC>::operator++() { ++iterator_; return *this; } template <typename VT, bool IC> inline UptrVectorIterator<VT, IC> UptrVectorIterator<VT, IC>::operator++(int) { auto it = *this; ++(*this); return it; } template <typename VT, bool IC> inline UptrVectorIterator<VT, IC>& UptrVectorIterator<VT, IC>::operator--() { --iterator_; return *this; } template <typename VT, bool IC> inline UptrVectorIterator<VT, IC> UptrVectorIterator<VT, IC>::operator--(int) { auto it = *this; --(*this); return it; } template <typename VT, bool IC> inline bool UptrVectorIterator<VT, IC>::operator==( const UptrVectorIterator& that) const { return container_ == that.container_ && iterator_ == that.iterator_; } template <typename VT, bool IC> inline bool UptrVectorIterator<VT, IC>::operator!=( const UptrVectorIterator& that) const { return !(*this == that); } template <typename VT, bool IC> inline ptrdiff_t UptrVectorIterator<VT, IC>::operator-( const UptrVectorIterator& that) const { assert(container_ == that.container_); return iterator_ - that.iterator_; } template <typename VT, bool IC> inline bool UptrVectorIterator<VT, IC>::operator<( const UptrVectorIterator& that) const { assert(container_ == that.container_); return iterator_ < that.iterator_; } template <typename VT, bool IC> template <bool IsConstForMethod> inline typename std::enable_if<!IsConstForMethod, UptrVectorIterator<VT, IC>>::type UptrVectorIterator<VT, IC>::InsertBefore(Uptr value) { auto index = iterator_ - container_->begin(); container_->insert(iterator_, std::move(value)); return UptrVectorIterator(container_, container_->begin() + index); } template <typename VT, bool IC> template <bool IsConstForMethod> inline typename std::enable_if<!IsConstForMethod, UptrVectorIterator<VT, IC>>::type UptrVectorIterator<VT, IC>::InsertBefore(UptrVector* values) { const auto pos = iterator_ - container_->begin(); const auto origsz = container_->size(); container_->resize(origsz + values->size()); std::move_backward(container_->begin() + pos, container_->begin() + origsz, container_->end()); std::move(values->begin(), values->end(), container_->begin() + pos); return UptrVectorIterator(container_, container_->begin() + pos); } template <typename VT, bool IC> template <bool IsConstForMethod> inline typename std::enable_if<!IsConstForMethod, UptrVectorIterator<VT, IC>>::type UptrVectorIterator<VT, IC>::Erase() { auto index = iterator_ - container_->begin(); (void)container_->erase(iterator_); return UptrVectorIterator(container_, container_->begin() + index); } } // namespace opt } // namespace spvtools #endif // SOURCE_OPT_ITERATOR_H_