blob: 4445c26ca511e4b74873a4f5a898cd28c492e736 [file] [log] [blame]
// 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_