| // Copyright 2017-2020 The Verible Authors. | |
| // | |
| // 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. | |
| // This library provides some basic interface extensions to | |
| // iterator_range. | |
| #ifndef VERIBLE_COMMON_UTIL_CONTAINER_ITERATOR_RANGE_H_ | |
| #define VERIBLE_COMMON_UTIL_CONTAINER_ITERATOR_RANGE_H_ | |
| #include <cstddef> | |
| #include <iterator> // for std::iterator_traits | |
| #include <utility> // for std::pair | |
| #include "common/util/iterator_range.h" | |
| #include "common/util/range.h" | |
| namespace verible { | |
| // container_iterator_range provides container-like interfaces to | |
| // an iterator_range (which only has begin() and end()). | |
| // Like iterator_range, this does not own the memory referenced by the range. | |
| // IT is an iterator type. | |
| // Some methods are available for only certain iterator types. | |
| // Any operation on the underlying container that causes internal reallocation | |
| // invalidates these iterator ranges, e.g. vector::push_back(). | |
| template <typename IT> | |
| class container_iterator_range : public iterator_range<IT> { | |
| typedef container_iterator_range<IT> this_type; | |
| typedef iterator_range<IT> range_type; | |
| public: | |
| using iterator = IT; | |
| using const_iterator = IT; | |
| using value_type = typename std::iterator_traits<IT>::value_type; | |
| using reference = typename std::iterator_traits<IT>::reference; | |
| // Allow default initialization to be usable inside resize-able containers. | |
| container_iterator_range() = default; | |
| explicit container_iterator_range(std::pair<IT, IT> p) | |
| : range_type(std::move(p.first), std::move(p.second)) {} | |
| // Constructs range from two iterators. | |
| // To initialize this range to empty, pass the same iterator twice, e.g. | |
| // container.begin(). This way it will already point to a valid range, and be | |
| // extendable. | |
| container_iterator_range(IT b, IT e) | |
| : range_type(std::move(b), std::move(e)) {} | |
| bool empty() const { return this->begin() == this->end(); } | |
| // Returns the number of elements that span this range. | |
| // The run-time complexity of this depends on that of the underlying iterator. | |
| size_t size() const { return std::distance(this->begin(), this->end()); } | |
| // Dereferences first element at begin(). | |
| // Only valid if !this->empty(), just like a vector. | |
| // Available to bidirectional_iterators. | |
| reference front() const { return *this->begin(); } | |
| // Dereferences last element at end() -1. | |
| // Only valid if !this->empty(), just like a vector. | |
| // Available to bidirectional_iterators. | |
| reference back() const { | |
| auto it = this->end(); | |
| return *(--it); | |
| } | |
| // Returns reference to the i'th element. | |
| // Only available to random-access iterators. | |
| reference operator[](size_t i) const { return *(this->begin() + i); } | |
| // Clears this range by moving the end back to the beginning. | |
| void clear_to_begin() { this->reset(this->begin(), this->begin()); } | |
| // Clears this range by moving the beginning forward to the end. | |
| void clear_to_end() { this->reset(this->end(), this->end()); } | |
| // Sets the lower-bound of this range, which could grow or shrink. | |
| void set_begin(iterator iter) { this->reset(iter, this->end()); } | |
| // Sets the upper-bound of this range, which could grow or shrink. | |
| void set_end(iterator iter) { this->reset(this->begin(), iter); } | |
| // Grows front-side bound by one element. | |
| // Caller is responsible for making sure new range still falls within | |
| // valid backed memory. | |
| // Available to bidirectional_iterators. | |
| void extend_front() { | |
| auto iter = this->begin(); | |
| --iter; | |
| this->reset(iter, this->end()); | |
| } | |
| // TODO(fangism): extend_front(N) for random-access iterators | |
| // Shrink the range from the front-side by one element. | |
| // Only valid if !this->empty(). | |
| // Available to bidirectional_iterators. | |
| void pop_front() { | |
| auto iter = this->begin(); | |
| ++iter; | |
| this->reset(iter, this->end()); | |
| } | |
| // TODO(fangism): pop_front(N), like string_view::remove_prefix() | |
| // Grows back-side bound by one element. | |
| // Caller is responsible for making sure new range still falls within | |
| // valid backed memory. | |
| // Available to bidirectional_iterators. | |
| void extend_back() { | |
| auto iter = this->end(); | |
| ++iter; | |
| this->reset(this->begin(), iter); | |
| } | |
| // TODO(fangism): extend_back(N) for random-access iterators | |
| // Shrink the range from the back-side by one element. | |
| // Only valid if !this->empty(). | |
| // Available to bidirectional_iterators. | |
| void pop_back() { | |
| auto iter = this->end(); | |
| --iter; | |
| this->reset(this->begin(), iter); | |
| } | |
| // TODO(fangism): pop_back(N), like string_view::remove_suffix() | |
| // TODO(fangism): subrange(N, M), like string_view::substr() | |
| // Returns true if begin/end bounds of iterator range are identical. | |
| // Templated to allow comparison between const-mismatched iterators. | |
| template <typename T2> | |
| bool operator==(const container_iterator_range<T2>& other) const { | |
| return BoundsEqual(*this, other); | |
| } | |
| template <typename T2> | |
| bool operator!=(const container_iterator_range<T2>& other) const { | |
| return !(*this == other); | |
| } | |
| protected: | |
| // Overwrite internal iterators. | |
| // Provided because they are private (not protected) in base class. | |
| void reset(iterator b, iterator e) { | |
| *this = container_iterator_range<IT>(b, e); | |
| } | |
| }; | |
| // Convenience constructor of container_iterator_range, | |
| // analogous to std::make_pair(). | |
| template <typename T> | |
| container_iterator_range<T> make_container_range(T x, T y) { | |
| return container_iterator_range<T>(std::move(x), std::move(y)); | |
| } | |
| // Converts std::pair<Iter,Iter> to container_iterator_range<Iter>. E.g.: | |
| // for (const auto& e : make_container_range(m.equal_range(k))) ... | |
| template <typename Iter> | |
| container_iterator_range<Iter> make_container_range(std::pair<Iter, Iter> p) { | |
| return container_iterator_range<Iter>(std::move(p)); | |
| } | |
| } // namespace verible | |
| #endif // VERIBLE_COMMON_UTIL_CONTAINER_ITERATOR_RANGE_H_ |