| // 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: | |
| using iterator_category = std::random_access_iterator_tag; | |
| using value_type = ValueType; | |
| using pointer = value_type*; | |
| using reference = value_type&; | |
| using difference_type = std::ptrdiff_t; | |
| // 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::forward<IteratorType>(begin), std::forward<IteratorType>(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: | |
| // 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_ |