diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-21 11:54:28 +0000 |
commit | e6918187568dbd01842d8d1d2c808ce16a894239 (patch) | |
tree | 64f88b554b444a49f656b6c656111a145cbbaa28 /src/arrow/r/inst/include/cpp11/r_vector.hpp | |
parent | Initial commit. (diff) | |
download | ceph-e6918187568dbd01842d8d1d2c808ce16a894239.tar.xz ceph-e6918187568dbd01842d8d1d2c808ce16a894239.zip |
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | src/arrow/r/inst/include/cpp11/r_vector.hpp | 1009 |
1 files changed, 1009 insertions, 0 deletions
diff --git a/src/arrow/r/inst/include/cpp11/r_vector.hpp b/src/arrow/r/inst/include/cpp11/r_vector.hpp new file mode 100644 index 000000000..3a3d53b36 --- /dev/null +++ b/src/arrow/r/inst/include/cpp11/r_vector.hpp @@ -0,0 +1,1009 @@ +// cpp11 version: 0.3.1.1 +// vendored on: 2021-08-11 +#pragma once + +#include <stddef.h> // for ptrdiff_t, size_t + +#include <algorithm> // for max +#include <array> // for array +#include <cstdio> // for snprintf +#include <exception> // for exception +#include <initializer_list> // for initializer_list +#include <iterator> // for forward_iterator_tag, random_ac... +#include <stdexcept> // for out_of_range +#include <string> // for string, basic_string +#include <type_traits> // for decay, is_same, enable_if, is_c... +#include <utility> // for declval + +#include "cpp11/R.hpp" // for R_xlen_t, SEXP, SEXPREC, Rf_xle... +#include "cpp11/attribute_proxy.hpp" // for attribute_proxy +#include "cpp11/protect.hpp" // for preserved +#include "cpp11/r_string.hpp" // for r_string +#include "cpp11/sexp.hpp" // for sexp + +namespace cpp11 { + +using namespace cpp11::literals; + +class type_error : public std::exception { + public: + type_error(int expected, int actual) : expected_(expected), actual_(actual) {} + virtual const char* what() const noexcept { + snprintf(str_, 64, "Invalid input type, expected '%s' actual '%s'", + Rf_type2char(expected_), Rf_type2char(actual_)); + return str_; + } + + private: + int expected_; + int actual_; + mutable char str_[64]; +}; + +// Forward Declarations +class named_arg; + +namespace writable { +template <typename T> +class r_vector; +} // namespace writable + +// Declarations +template <typename T> +class r_vector { + public: + typedef ptrdiff_t difference_type; + typedef size_t size_type; + typedef T value_type; + typedef T* pointer; + typedef T& reference; + + r_vector() = default; + + r_vector(SEXP data); + + r_vector(SEXP data, bool is_altrep); + +#ifdef LONG_VECTOR_SUPPORT + T operator[](const int pos) const; + T at(const int pos) const; +#endif + T operator[](const R_xlen_t pos) const; + T operator[](const size_type pos) const; + T operator[](const r_string& name) const; + + T at(const R_xlen_t pos) const; + T at(const size_type pos) const; + T at(const r_string& name) const; + + bool contains(const r_string& name) const; + + r_vector& operator=(const r_vector& rhs) { + SEXP old_protect = protect_; + + data_ = rhs.data_; + protect_ = preserved.insert(data_); + is_altrep_ = rhs.is_altrep_; + data_p_ = rhs.data_p_; + length_ = rhs.length_; + + preserved.release(old_protect); + + return *this; + }; + + r_vector(const r_vector& rhs) { + SEXP old_protect = protect_; + + data_ = rhs.data_; + protect_ = preserved.insert(data_); + is_altrep_ = rhs.is_altrep_; + data_p_ = rhs.data_p_; + length_ = rhs.length_; + + preserved.release(old_protect); + }; + + r_vector(const writable::r_vector<T>& rhs) : r_vector(static_cast<SEXP>(rhs)) {} + + bool is_altrep() const; + + bool named() const; + + R_xlen_t size() const; + + operator SEXP() const; + + operator sexp() const; + + bool empty() const; + + /// Provide access to the underlying data, mainly for interface + /// compatibility with std::vector + SEXP data() const; + + sexp attr(const char* name) const { + return SEXP(attribute_proxy<r_vector<T>>(*this, name)); + } + + sexp attr(const std::string& name) const { + return SEXP(attribute_proxy<r_vector<T>>(*this, name.c_str())); + } + + sexp attr(SEXP name) const { return SEXP(attribute_proxy<r_vector<T>>(*this, name)); } + + r_vector<r_string> names() const { + SEXP nms = SEXP(attribute_proxy<r_vector<T>>(*this, R_NamesSymbol)); + if (nms == R_NilValue) { + return r_vector<r_string>(); + } + + return nms; + } + + class const_iterator { + public: + using difference_type = ptrdiff_t; + using value_type = T; + using pointer = T*; + using reference = T&; + using iterator_category = std::random_access_iterator_tag; + + const_iterator(const r_vector* data, R_xlen_t pos); + + inline const_iterator& operator+(R_xlen_t pos); + inline ptrdiff_t operator-(const const_iterator& other) const; + + inline const_iterator& operator++(); + inline const_iterator& operator--(); + + inline const_iterator& operator+=(R_xlen_t pos); + inline const_iterator& operator-=(R_xlen_t pos); + + inline bool operator!=(const const_iterator& other) const; + inline bool operator==(const const_iterator& other) const; + + inline T operator*() const; + + friend class writable::r_vector<T>::iterator; + + private: + const r_vector* data_; + void fill_buf(R_xlen_t pos); + + R_xlen_t pos_; + std::array<T, 64 * 64> buf_; + R_xlen_t block_start_ = 0; + R_xlen_t length_ = 0; + }; + + public: + const_iterator begin() const; + const_iterator end() const; + + const_iterator cbegin() const; + const_iterator cend() const; + + const_iterator find(const r_string& name) const; + + ~r_vector() { preserved.release(protect_); } + + private: + SEXP data_ = R_NilValue; + SEXP protect_ = R_NilValue; + bool is_altrep_ = false; + T* data_p_ = nullptr; + R_xlen_t length_ = 0; + + static T* get_p(bool is_altrep, SEXP data); + + static SEXP valid_type(SEXP data); + + friend class writable::r_vector<T>; +}; + +namespace writable { + +template <typename T> +using has_begin_fun = std::decay<decltype(*begin(std::declval<T>()))>; + +/// Read/write access to new or copied r_vectors +template <typename T> +class r_vector : public cpp11::r_vector<T> { + private: + SEXP protect_ = R_NilValue; + + // These are necessary because type names are not directly accessible in + // template inheritance + using cpp11::r_vector<T>::data_; + using cpp11::r_vector<T>::data_p_; + using cpp11::r_vector<T>::is_altrep_; + using cpp11::r_vector<T>::length_; + + R_xlen_t capacity_ = 0; + + public: + class proxy { + private: + const SEXP data_; + const R_xlen_t index_; + T* const p_; + bool is_altrep_; + + public: + proxy(SEXP data, const R_xlen_t index, T* const p, bool is_altrep); + + proxy& operator=(const T& rhs); + proxy& operator+=(const T& rhs); + proxy& operator-=(const T& rhs); + proxy& operator*=(const T& rhs); + proxy& operator/=(const T& rhs); + proxy& operator++(int); + proxy& operator--(int); + + void operator++(); + void operator--(); + + operator T() const; + }; + + typedef ptrdiff_t difference_type; + typedef size_t size_type; + typedef proxy value_type; + typedef proxy* pointer; + typedef proxy& reference; + + class iterator : public cpp11::r_vector<T>::const_iterator { + private: + const r_vector& data_; + using cpp11::r_vector<T>::const_iterator::block_start_; + using cpp11::r_vector<T>::const_iterator::pos_; + using cpp11::r_vector<T>::const_iterator::buf_; + using cpp11::r_vector<T>::const_iterator::length_; + using cpp11::r_vector<T>::const_iterator::fill_buf; + + public: + using difference_type = ptrdiff_t; + using value_type = proxy; + using pointer = proxy*; + using reference = proxy&; + using iterator_category = std::forward_iterator_tag; + + iterator(const r_vector& data, R_xlen_t pos); + + inline iterator& operator++(); + + inline proxy operator*() const; + + using cpp11::r_vector<T>::const_iterator::operator!=; + + inline iterator& operator+(R_xlen_t rhs); + }; + + r_vector() = default; + r_vector(const SEXP& data); + r_vector(SEXP&& data); + r_vector(const SEXP& data, bool is_altrep); + r_vector(SEXP&& data, bool is_altrep); + r_vector(std::initializer_list<T> il); + r_vector(std::initializer_list<named_arg> il); + r_vector(std::initializer_list<const char*> il); + r_vector(std::initializer_list<std::string> il); + + template <typename Iter> + r_vector(Iter first, Iter last); + + template <typename V, typename W = has_begin_fun<V>> + r_vector(const V& obj); + + r_vector(const R_xlen_t size); + + ~r_vector(); + + r_vector(const r_vector& rhs); + r_vector(r_vector&& rhs); + + r_vector(const cpp11::r_vector<T>& rhs); + + r_vector& operator=(const r_vector& rhs); + r_vector& operator=(r_vector&& rhs); + +#ifdef LONG_VECTOR_SUPPORT + proxy operator[](const int pos) const; + proxy at(const int pos) const; +#endif + proxy operator[](const R_xlen_t pos) const; + proxy operator[](const size_type pos) const; + proxy operator[](const r_string& name) const; + + proxy at(const R_xlen_t pos) const; + proxy at(const size_type pos) const; + proxy at(const r_string& name) const; + + void push_back(T value); + void push_back(const named_arg& value); + void pop_back(); + + void resize(R_xlen_t count); + + void reserve(R_xlen_t new_capacity); + + iterator insert(R_xlen_t pos, T value); + iterator erase(R_xlen_t pos); + + void clear(); + + iterator begin() const; + iterator end() const; + + using cpp11::r_vector<T>::cbegin; + using cpp11::r_vector<T>::cend; + using cpp11::r_vector<T>::size; + + iterator find(const r_string& name) const; + + attribute_proxy<r_vector<T>> attr(const char* name) const { + return attribute_proxy<r_vector<T>>(*this, name); + } + + attribute_proxy<r_vector<T>> attr(const std::string& name) const { + return attribute_proxy<r_vector<T>>(*this, name.c_str()); + } + + attribute_proxy<r_vector<T>> attr(SEXP name) const { + return attribute_proxy<r_vector<T>>(*this, name); + } + + attribute_proxy<r_vector<T>> names() const { + return attribute_proxy<r_vector<T>>(*this, R_NamesSymbol); + } + + operator SEXP() const; +}; +} // namespace writable + +// Implementations below + +template <typename T> +inline r_vector<T>::r_vector(const SEXP data) + : data_(valid_type(data)), + protect_(preserved.insert(data)), + is_altrep_(ALTREP(data)), + data_p_(get_p(ALTREP(data), data)), + length_(Rf_xlength(data)) {} + +template <typename T> +inline r_vector<T>::r_vector(const SEXP data, bool is_altrep) + : data_(valid_type(data)), + protect_(preserved.insert(data)), + is_altrep_(is_altrep), + data_p_(get_p(is_altrep, data)), + length_(Rf_xlength(data)) {} + +template <typename T> +inline bool r_vector<T>::is_altrep() const { + return is_altrep_; +} + +template <typename T> +inline bool r_vector<T>::named() const { + return ((this->names()) != R_NilValue); +} + +template <typename T> +inline R_xlen_t r_vector<T>::size() const { + return length_; +} + +template <typename T> +inline r_vector<T>::operator SEXP() const { + return data_; +} + +template <typename T> +inline bool r_vector<T>::empty() const { + return (!(this->size() > 0)); +} + +template <typename T> +inline r_vector<T>::operator sexp() const { + return data_; +} + +/// Provide access to the underlying data, mainly for interface +/// compatibility with std::vector +template <typename T> +inline SEXP r_vector<T>::data() const { + return data_; +} + +template <typename T> +inline typename r_vector<T>::const_iterator r_vector<T>::begin() const { + return const_iterator(this, 0); +} + +template <typename T> +inline typename r_vector<T>::const_iterator r_vector<T>::end() const { + return const_iterator(this, length_); +} + +template <typename T> +inline typename r_vector<T>::const_iterator r_vector<T>::cbegin() const { + return const_iterator(this, 0); +} + +template <typename T> +inline typename r_vector<T>::const_iterator r_vector<T>::cend() const { + return const_iterator(this, length_); +} + +template <typename T> +r_vector<T>::const_iterator::const_iterator(const r_vector* data, R_xlen_t pos) + : data_(data), pos_(pos), buf_() { + if (data_->is_altrep()) { + fill_buf(pos); + } +} + +template <typename T> +inline typename r_vector<T>::const_iterator& r_vector<T>::const_iterator::operator++() { + ++pos_; + if (data_->is_altrep() && pos_ >= block_start_ + length_) { + fill_buf(pos_); + } + return *this; +} + +template <typename T> +inline typename r_vector<T>::const_iterator& r_vector<T>::const_iterator::operator--() { + --pos_; + if (data_->is_altrep() && pos_ > 0 && pos_ < block_start_) { + fill_buf(std::max(0_xl, pos_ - 64)); + } + return *this; +} + +template <typename T> +inline typename r_vector<T>::const_iterator& r_vector<T>::const_iterator::operator+=( + R_xlen_t i) { + pos_ += i; + if (data_->is_altrep() && pos_ >= block_start_ + length_) { + fill_buf(pos_); + } + return *this; +} + +template <typename T> +inline typename r_vector<T>::const_iterator& r_vector<T>::const_iterator::operator-=( + R_xlen_t i) { + pos_ -= i; + if (data_->is_altrep() && pos_ >= block_start_ + length_) { + fill_buf(std::max(0_xl, pos_ - 64)); + } + return *this; +} + +template <typename T> +inline bool r_vector<T>::const_iterator::operator!=( + const r_vector<T>::const_iterator& other) const { + return pos_ != other.pos_; +} + +template <typename T> +inline bool r_vector<T>::const_iterator::operator==( + const r_vector<T>::const_iterator& other) const { + return pos_ == other.pos_; +} + +template <typename T> +inline ptrdiff_t r_vector<T>::const_iterator::operator-( + const r_vector<T>::const_iterator& other) const { + return pos_ - other.pos_; +} + +template <typename T> +inline typename r_vector<T>::const_iterator& r_vector<T>::const_iterator::operator+( + R_xlen_t rhs) { + pos_ += rhs; + if (data_->is_altrep() && pos_ >= block_start_ + length_) { + fill_buf(pos_); + } + return *this; +} + +template <typename T> +inline T cpp11::r_vector<T>::at(R_xlen_t pos) const { + if (pos < 0 || pos >= length_) { + throw std::out_of_range("r_vector"); + } + + return operator[](pos); +} + +template <typename T> +inline T cpp11::r_vector<T>::at(size_type pos) const { + return at(static_cast<R_xlen_t>(pos)); +} + +template <typename T> +inline T cpp11::r_vector<T>::operator[](const r_string& name) const { + SEXP names = this->names(); + R_xlen_t size = Rf_xlength(names); + + for (R_xlen_t pos = 0; pos < size; ++pos) { + auto cur = Rf_translateCharUTF8(STRING_ELT(names, pos)); + if (name == cur) { + return operator[](pos); + } + } + + throw std::out_of_range("r_vector"); +} + +template <typename T> +inline bool cpp11::r_vector<T>::contains(const r_string& name) const { + SEXP names = this->names(); + R_xlen_t size = Rf_xlength(names); + + for (R_xlen_t pos = 0; pos < size; ++pos) { + auto cur = Rf_translateCharUTF8(STRING_ELT(names, pos)); + if (name == cur) { + return true; + } + } + + return false; +} + +template <typename T> +inline typename cpp11::r_vector<T>::const_iterator cpp11::r_vector<T>::find( + const r_string& name) const { + SEXP names = this->names(); + R_xlen_t size = Rf_xlength(names); + + for (R_xlen_t pos = 0; pos < size; ++pos) { + auto cur = Rf_translateCharUTF8(STRING_ELT(names, pos)); + if (name == cur) { + return begin() + pos; + } + } + + return end(); +} + +template <typename T> +inline T r_vector<T>::const_iterator::operator*() const { + if (data_->is_altrep()) { + return buf_[pos_ - block_start_]; + } else { + return data_->data_p_[pos_]; + } +} + +#ifdef LONG_VECTOR_SUPPORT +template <typename T> +inline T r_vector<T>::operator[](const int pos) const { + return operator[](static_cast<R_xlen_t>(pos)); +} + +template <typename T> +inline T r_vector<T>::at(const int pos) const { + return at(static_cast<R_xlen_t>(pos)); +} +#endif + +template <typename T> +inline T r_vector<T>::operator[](size_type pos) const { + return operator[](static_cast<R_xlen_t>(pos)); +} + +namespace writable { + +template <typename T> +r_vector<T>::proxy::proxy(SEXP data, const R_xlen_t index, T* const p, bool is_altrep) + : data_(data), index_(index), p_(p), is_altrep_(is_altrep) {} + +template <typename T> +inline typename r_vector<T>::proxy r_vector<T>::iterator::operator*() const { + if (data_.is_altrep()) { + return proxy(data_.data(), pos_, const_cast<T*>(&buf_[pos_ - block_start_]), true); + } else { + return proxy(data_.data(), pos_, + data_.data_p_ != nullptr ? &data_.data_p_[pos_] : nullptr, false); + } +} + +template <typename T> +r_vector<T>::iterator::iterator(const r_vector& data, R_xlen_t pos) + : r_vector<T>::const_iterator(&data, pos), data_(data) {} + +template <typename T> +inline typename r_vector<T>::iterator& r_vector<T>::iterator::operator++() { + ++pos_; + if (data_.is_altrep() && pos_ >= block_start_ + length_) { + fill_buf(pos_); + } + return *this; +} + +template <typename T> +inline typename r_vector<T>::iterator& r_vector<T>::iterator::operator+(R_xlen_t rhs) { + pos_ += rhs; + if (data_.is_altrep() && pos_ >= block_start_ + length_) { + fill_buf(pos_); + } + return *this; +} + +template <typename T> +inline typename r_vector<T>::iterator r_vector<T>::begin() const { + return iterator(*this, 0); +} + +template <typename T> +inline typename r_vector<T>::iterator r_vector<T>::end() const { + return iterator(*this, length_); +} + +template <typename T> +inline r_vector<T>::r_vector(const SEXP& data) + : cpp11::r_vector<T>(safe[Rf_shallow_duplicate](data)), + protect_(preserved.insert(data_)), + capacity_(length_) {} + +template <typename T> +inline r_vector<T>::r_vector(const SEXP& data, bool is_altrep) + : cpp11::r_vector<T>(safe[Rf_shallow_duplicate](data), is_altrep), + protect_(preserved.insert(data_)), + capacity_(length_) {} + +template <typename T> +inline r_vector<T>::r_vector(SEXP&& data) + : cpp11::r_vector<T>(data), protect_(preserved.insert(data_)), capacity_(length_) {} + +template <typename T> +inline r_vector<T>::r_vector(SEXP&& data, bool is_altrep) + : cpp11::r_vector<T>(data, is_altrep), + protect_(preserved.insert(data_)), + capacity_(length_) {} + +template <typename T> +template <typename Iter> +inline r_vector<T>::r_vector(Iter first, Iter last) : r_vector() { + reserve(last - first); + while (first != last) { + push_back(*first); + ++first; + } +} + +template <typename T> +template <typename V, typename W> +inline r_vector<T>::r_vector(const V& obj) : r_vector() { + auto first = obj.begin(); + auto last = obj.end(); + reserve(last - first); + while (first != last) { + push_back(*first); + ++first; + } +} + +template <typename T> +inline r_vector<T>::r_vector(R_xlen_t size) : r_vector() { + resize(size); +} + +template <typename T> +inline r_vector<T>::~r_vector() { + preserved.release(protect_); +} + +#ifdef LONG_VECTOR_SUPPORT +template <typename T> +inline typename r_vector<T>::proxy r_vector<T>::operator[](const int pos) const { + return operator[](static_cast<R_xlen_t>(pos)); +} + +template <typename T> +inline typename r_vector<T>::proxy r_vector<T>::at(const int pos) const { + return at(static_cast<R_xlen_t>(pos)); +} +#endif + +template <typename T> +inline typename r_vector<T>::proxy r_vector<T>::operator[](const R_xlen_t pos) const { + if (is_altrep_) { + return {data_, pos, nullptr, true}; + } + return {data_, pos, data_p_ != nullptr ? &data_p_[pos] : nullptr, false}; +} + +template <typename T> +inline typename r_vector<T>::proxy r_vector<T>::operator[](size_type pos) const { + return operator[](static_cast<R_xlen_t>(pos)); +} + +template <typename T> +inline typename r_vector<T>::proxy r_vector<T>::at(const R_xlen_t pos) const { + if (pos < 0 || pos >= length_) { + throw std::out_of_range("r_vector"); + } + return operator[](static_cast<R_xlen_t>(pos)); +} + +template <typename T> +inline typename r_vector<T>::proxy r_vector<T>::at(size_type pos) const { + return at(static_cast<R_xlen_t>(pos)); +} + +template <typename T> +inline typename r_vector<T>::proxy r_vector<T>::operator[](const r_string& name) const { + SEXP names = PROTECT(this->names()); + R_xlen_t size = Rf_xlength(names); + + for (R_xlen_t pos = 0; pos < size; ++pos) { + auto cur = Rf_translateCharUTF8(STRING_ELT(names, pos)); + if (name == cur) { + UNPROTECT(1); + return operator[](pos); + } + } + + UNPROTECT(1); + throw std::out_of_range("r_vector"); +} + +template <typename T> +inline typename r_vector<T>::proxy r_vector<T>::at(const r_string& name) const { + return operator[](name); +} + +template <typename T> +inline typename r_vector<T>::iterator r_vector<T>::find(const r_string& name) const { + SEXP names = PROTECT(this->names()); + R_xlen_t size = Rf_xlength(names); + + for (R_xlen_t pos = 0; pos < size; ++pos) { + auto cur = Rf_translateCharUTF8(STRING_ELT(names, pos)); + if (name == cur) { + UNPROTECT(1); + return begin() + pos; + } + } + + UNPROTECT(1); + return end(); +} + +template <typename T> +inline r_vector<T>::r_vector(const r_vector<T>& rhs) + : cpp11::r_vector<T>(safe[Rf_shallow_duplicate](rhs)), + protect_(preserved.insert(data_)), + capacity_(rhs.capacity_) {} + +template <typename T> +inline r_vector<T>::r_vector(r_vector<T>&& rhs) + : cpp11::r_vector<T>(rhs), protect_(rhs.protect_), capacity_(rhs.capacity_) { + rhs.data_ = R_NilValue; + rhs.protect_ = R_NilValue; +} + +template <typename T> +inline r_vector<T>::r_vector(const cpp11::r_vector<T>& rhs) + : cpp11::r_vector<T>(safe[Rf_shallow_duplicate](rhs)), + protect_(preserved.insert(data_)), + capacity_(rhs.length_) {} + +// We don't release the old object until the end in case we throw an exception +// during the duplicate. +template <typename T> +inline r_vector<T>& r_vector<T>::operator=(const r_vector<T>& rhs) { + if (data_ == rhs.data_) { + return *this; + } + + cpp11::r_vector<T>::operator=(rhs); + + auto old_protect = protect_; + + data_ = safe[Rf_shallow_duplicate](rhs.data_); + protect_ = preserved.insert(data_); + + preserved.release(old_protect); + + capacity_ = rhs.capacity_; + + return *this; +} + +template <typename T> +inline r_vector<T>& r_vector<T>::operator=(r_vector<T>&& rhs) { + if (data_ == rhs.data_) { + return *this; + } + + cpp11::r_vector<T>::operator=(rhs); + + SEXP old_protect = protect_; + + data_ = rhs.data_; + protect_ = preserved.insert(data_); + + preserved.release(old_protect); + + capacity_ = rhs.capacity_; + + rhs.data_ = R_NilValue; + rhs.protect_ = R_NilValue; + + return *this; +} + +template <typename T> +inline void r_vector<T>::pop_back() { + --length_; +} + +template <typename T> +inline void r_vector<T>::resize(R_xlen_t count) { + reserve(count); + length_ = count; +} + +template <typename T> +inline typename r_vector<T>::iterator r_vector<T>::insert(R_xlen_t pos, T value) { + push_back(value); + + R_xlen_t i = length_ - 1; + while (i > pos) { + operator[](i) = (T) operator[](i - 1); + --i; + }; + operator[](pos) = value; + + return begin() + pos; +} + +template <typename T> +inline typename r_vector<T>::iterator r_vector<T>::erase(R_xlen_t pos) { + R_xlen_t i = pos; + while (i < length_ - 1) { + operator[](i) = (T) operator[](i + 1); + ++i; + } + pop_back(); + + return begin() + pos; +} + +template <typename T> +inline void r_vector<T>::clear() { + length_ = 0; +} + +template <typename T> +inline r_vector<T>::operator SEXP() const { + if (length_ < capacity_) { +#if R_VERSION >= R_Version(3, 4, 0) + SETLENGTH(data_, length_); + SET_TRUELENGTH(data_, capacity_); + SET_GROWABLE_BIT(data_); +#else + auto* p = const_cast<r_vector<T>*>(this); + p->data_ = safe[Rf_lengthgets](data_, length_); +#endif + } + return data_; +} + +template <typename T> +inline typename r_vector<T>::proxy& r_vector<T>::proxy::operator+=(const T& rhs) { + operator=(static_cast<T>(*this) + rhs); + return *this; +} + +template <typename T> +inline typename r_vector<T>::proxy& r_vector<T>::proxy::operator-=(const T& rhs) { + operator=(static_cast<T>(*this) - rhs); + return *this; +} + +template <typename T> +inline typename r_vector<T>::proxy& r_vector<T>::proxy::operator*=(const T& rhs) { + operator=(static_cast<T>(*this) * rhs); + return *this; +} + +template <typename T> +inline typename r_vector<T>::proxy& r_vector<T>::proxy::operator/=(const T& rhs) { + operator=(static_cast<T>(*this) / rhs); + return *this; +} + +template <typename T> +inline typename r_vector<T>::proxy& r_vector<T>::proxy::operator++(int) { + operator=(static_cast<T>(*this) + 1); + return *this; +} + +template <typename T> +inline typename r_vector<T>::proxy& r_vector<T>::proxy::operator--(int) { + operator=(static_cast<T>(*this) - 1); + return *this; +} + +template <typename T> +inline void r_vector<T>::proxy::operator--() { + operator=(static_cast<T>(*this) - 1); +} + +template <typename T> +inline void r_vector<T>::proxy::operator++() { + operator=(static_cast<T>(*this) + 1); +} + +} // namespace writable + +// TODO: is there a better condition we could use, e.g. assert something true +// rather than three things false? +template <typename C, typename T> +using is_container_but_not_sexp_or_string = typename std::enable_if< + !std::is_constructible<C, SEXP>::value && + !std::is_same<typename std::decay<C>::type, std::string>::value && + !std::is_same<typename std::decay<T>::type, std::string>::value, + typename std::decay<C>::type>::type; + +template <typename C, typename T = typename std::decay<C>::type::value_type> +// typename T = typename C::value_type> +is_container_but_not_sexp_or_string<C, T> as_cpp(SEXP from) { + auto obj = cpp11::r_vector<T>(from); + return {obj.begin(), obj.end()}; +} + +// TODO: could we make this generalize outside of std::string? +template <typename C, typename T = C> +using is_vector_of_strings = typename std::enable_if< + std::is_same<typename std::decay<T>::type, std::string>::value, + typename std::decay<C>::type>::type; + +template <typename C, typename T = typename std::decay<C>::type::value_type> +// typename T = typename C::value_type> +is_vector_of_strings<C, T> as_cpp(SEXP from) { + auto obj = cpp11::r_vector<cpp11::r_string>(from); + typename std::decay<C>::type res; + auto it = obj.begin(); + while (it != obj.end()) { + r_string s = *it; + res.emplace_back(static_cast<std::string>(s)); + ++it; + } + return res; +} + +template <typename T> +bool operator==(const r_vector<T>& lhs, const r_vector<T>& rhs) { + if (lhs.size() != rhs.size()) { + return false; + } + + auto lhs_it = lhs.begin(); + auto rhs_it = rhs.begin(); + + auto end = lhs.end(); + while (lhs_it != end) { + if (!(*lhs_it == *rhs_it)) { + return false; + } + ++lhs_it; + ++rhs_it; + } + return true; +} + +template <typename T> +bool operator!=(const r_vector<T>& lhs, const r_vector<T>& rhs) { + return !(lhs == rhs); +} + +} // namespace cpp11 |