// Copyright 2019 Global Phasing Ltd. // // Span - span of array or std::vector. // MutableVectorSpan - span of std::vector with insert() and erase() #ifndef GEMMI_SPAN_HPP_ #define GEMMI_SPAN_HPP_ #include // for find_if, find_if_not #include #include // for out_of_range #include // for remove_cv, conditional, is_const namespace gemmi { template struct MutableVectorSpan; // Minimalistic Span, somewhat similar to C++20 std::span. template struct Span { using iterator = Item*; using const_iterator = Item const*; using element_type = Item; using value_type = typename std::remove_cv::type; friend Span; friend MutableVectorSpan; Span() = default; Span(iterator begin, std::size_t n) : begin_(begin), size_(n) {} #if !defined(_MSC_VER) || _MSC_VER-0 >= 1926 // constructor only for const Item, to allow non-const -> const conversion template Span(const Span& o, typename std::enable_if::value>::type* = 0) #else // older MSVC don't like the version above Span(const Span& o) #endif : begin_(o.begin_), size_(o.size_) {} void set_begin(iterator begin) { begin_ = begin; } void set_size(std::size_t n) { size_ = n; } const_iterator begin() const { return begin_; } const_iterator end() const { return begin_ + size_; } iterator begin() { return begin_; } iterator end() { return begin_ + size_; } Item& front() { return *begin_; } const Item& front() const { return *begin_; } Item& back() { return *(begin_ + size_ - 1); } const Item& back() const { return *(begin_ + size_ - 1); } const Item& operator[](std::size_t i) const { return *(begin_ + i); } Item& operator[](std::size_t i) { return *(begin_ + i); } Item& at(std::size_t i) { if (i >= size()) throw std::out_of_range("item index ouf of range: #" + std::to_string(i)); return *(begin_ + i); } const Item& at(std::size_t i) const { return const_cast(this)->at(i); } std::size_t size() const { return size_; } bool empty() const { return size_ == 0; } explicit operator bool() const { return size_ != 0; } template Span sub(Iter first, Iter last) { return Span(&*first, last - first); } template Span subspan(F&& func) { iterator group_begin = std::find_if(this->begin(), this->end(), func); iterator group_end = std::find_if_not(group_begin, this->end(), func); return Span(&*group_begin, group_end - group_begin); } template Span subspan(F&& func) const { using V = const value_type; return const_cast(this)->subspan(std::forward(func)); } // we use children() to iterate over Model, Chain, etc Span& children() { return *this; } const Span& children() const { return *this; } private: iterator begin_ = nullptr; std::size_t size_ = 0; }; // Span of std::vector, implements insert() and erase(). template struct MutableVectorSpan : Span { using vector_type = std::vector::value_type>; using iterator = typename Span::iterator; //friend Span; MutableVectorSpan() = default; MutableVectorSpan(Span&& p, vector_type* v) : Span(p), vector_(v) {} MutableVectorSpan(vector_type& v, iterator begin, std::size_t n) : Span(begin, n), vector_(&v) {} template MutableVectorSpan sub(Iter first, Iter last) { return {Span::sub(first, last), vector_}; } template MutableVectorSpan subspan(F&& func) { return {Span::subspan(std::forward(func)), vector_}; } template MutableVectorSpan subspan(F&& func) const { return {Span::subspan(std::forward(func)), vector_}; } iterator insert(iterator pos, Item&& item) { auto offset = this->begin_ - this->vector_->data(); auto iter = vector_->begin() + (pos - this->vector_->data()); auto ret = vector_->insert(iter, std::move(item)); this->begin_ = vector_->data() + offset; ++this->size_; return &*ret; } void erase(iterator pos) { vector_->erase(vector_->begin() + (pos - vector_->data())); --this->size_; } bool is_beginning() const { return this->begin() == vector_->data(); } bool is_ending() const { return this->end() == vector_->data() + vector_->size(); } private: vector_type* vector_ = nullptr; // for insert() and erase() }; } // namespace gemmi #endif