Program Listing for File ranges.hpp¶
↰ Return to documentation for file (SeQuant/core/ranges.hpp
)
//
// Created by Eduard Valeyev on 3/24/18.
//
#ifndef SEQUANT_RANGES_HPP
#define SEQUANT_RANGES_HPP
#include <range/v3/all.hpp>
namespace sequant {
template <typename RangeNest>
class flattened_rangenest
: public ranges::view_facade<flattened_rangenest<RangeNest>> {
public:
using base_type = ranges::view_facade<flattened_rangenest<RangeNest>>;
flattened_rangenest() = default;
explicit flattened_rangenest(RangeNest *r) : range_(r) {}
flattened_rangenest(const flattened_rangenest &) = default;
flattened_rangenest(flattened_rangenest &&) = default;
flattened_rangenest &operator=(const flattened_rangenest &) = default;
flattened_rangenest &operator=(flattened_rangenest &&) = default;
RangeNest *range() const { return range_; }
using value_type = typename RangeNest::value_type::value_type;
private:
using Range = typename RangeNest::value_type;
RangeNest *range_;
friend ranges::range_access;
struct cursor {
private:
RangeNest *range_;
std::conditional_t<std::is_const_v<RangeNest>,
typename RangeNest::const_iterator,
typename RangeNest::iterator>
range_iter_; // sequence iterator pointing to the current element's
// range in the sequence
std::conditional_t<std::is_const_v<Range>, typename Range::const_iterator,
typename Range::iterator>
elem_iter_; // iterator pointing to the current element
mutable int64_t ordinal_ =
-1; // index of the current element within the sequence
// *range_iter_ produces a const lvalue ref, this return nonconst lvalue ref
Range ¤t_range() const { return const_cast<Range &>(*range_iter_); }
void compute_ordinal() const {
// accumulate all elements before this range_iter_
ordinal_ = std::accumulate(
_begin(*range_), range_iter_, 0,
[](std::size_t v, const Range &r) { return v + std::size(r); });
// accumulate all elements before this elem_iter_
if (range_iter_ != _end(*range_))
ordinal_ += elem_iter_ - this->_begin(current_range());
}
static auto _begin(Range &rng) {
using std::begin;
return begin(rng);
}
static auto _end(Range &rng) {
using std::end;
return end(rng);
}
static auto _begin(RangeNest &rng) {
using std::begin;
return begin(rng);
}
static auto _end(RangeNest &rng) {
using std::end;
return end(rng);
}
public:
cursor() = default;
cursor(RangeNest *range)
: range_(range),
range_iter_(std::find_if(this->_begin(*range), this->_end(*range),
[](const auto &e) {
using std::empty;
return !empty(e);
})),
elem_iter_(range_iter_ != this->_end(*range)
? this->_begin(current_range())
: decltype(elem_iter_){}),
ordinal_{range_iter_ != this->_end(*range) ? 0 : -1} {}
cursor(RangeNest *range, ranges::default_sentinel_t)
: range_(range), range_iter_(this->_end(*range)) {}
cursor(RangeNest *range, typename RangeNest::iterator range_iter,
typename Range::iterator elem_iter)
: range_(range), range_iter_(range_iter), elem_iter_(elem_iter) {
compute_ordinal();
}
const auto &read() const { return *elem_iter_; }
bool equal(const cursor &that) const {
if (range_ == that.range_) { // make sure these point to same range
const auto end_range_iter = _end(*range_);
const auto this_is_the_end = range_iter_ == end_range_iter;
const auto that_is_the_end = that.range_iter_ == end_range_iter;
if (this_is_the_end && that_is_the_end)
return true;
else if (this_is_the_end || that_is_the_end)
return false;
else
return elem_iter_ == that.elem_iter_;
} else // this points to a different range from that
return false;
}
void next() {
++ordinal_;
++elem_iter_;
if (elem_iter_ == this->_end(current_range())) {
++range_iter_;
// skip empty ranges
const auto this_is_the_end = this->_end(*range_);
while (range_iter_ != this_is_the_end && ranges::empty(*range_iter_))
++range_iter_;
if (range_iter_ != this_is_the_end)
elem_iter_ = this->_begin(current_range());
}
}
const auto range_iter() const { return range_iter_; }
const auto range_ordinal() const { return range_iter_ - _begin(*range_); }
const auto elem_iter() const { return elem_iter_; }
const auto ordinal() const {
if (ordinal_ < 0) compute_ordinal();
return ordinal_;
}
void erase() {
assert(range_iter_ != this->_end(*range_));
// TODO resolve the compilation issue
// ranges::erase(*range_iter_, elem_iter_);
// verify that capacity does not change
const auto capacity = range_iter_->capacity();
range_iter_->erase(elem_iter_);
assert(capacity == range_iter_->capacity());
}
template <typename T>
void insert(T &&elem) {
assert(range_iter_ != this->_end(*range_));
// TODO resolve the compilation issue
// ranges::insert(*range_iter_, elem_iter_, std::forward<T>(elem));
// verify that capacity does not change
const auto capacity = range_iter_->capacity();
range_iter_->insert(elem_iter_, std::forward<T>(elem));
assert(capacity == range_iter_->capacity());
}
};
cursor begin_cursor() const { return {range_}; }
cursor end_cursor() const { return {range_, ranges::default_sentinel_t{}}; }
public:
using iterator = ranges::basic_iterator<cursor>;
using const_iterator = ranges::basic_iterator<const cursor>;
};
} // namespace sequant
#endif // SEQUANT_RANGES_HPP