1 // cpp11 version: 0.3.1.1
2 // vendored on: 2021-08-11
5 #include <stddef.h> // for ptrdiff_t, size_t
7 #include <algorithm> // for max
8 #include <array> // for array
9 #include <cstdio> // for snprintf
10 #include <exception> // for exception
11 #include <initializer_list> // for initializer_list
12 #include <iterator> // for forward_iterator_tag, random_ac...
13 #include <stdexcept> // for out_of_range
14 #include <string> // for string, basic_string
15 #include <type_traits> // for decay, is_same, enable_if, is_c...
16 #include <utility> // for declval
18 #include "cpp11/R.hpp" // for R_xlen_t, SEXP, SEXPREC, Rf_xle...
19 #include "cpp11/attribute_proxy.hpp" // for attribute_proxy
20 #include "cpp11/protect.hpp" // for preserved
21 #include "cpp11/r_string.hpp" // for r_string
22 #include "cpp11/sexp.hpp" // for sexp
26 using namespace cpp11::literals;
28 class type_error : public std::exception {
30 type_error(int expected, int actual) : expected_(expected), actual_(actual) {}
31 virtual const char* what() const noexcept {
32 snprintf(str_, 64, "Invalid input type, expected '%s' actual '%s'",
33 Rf_type2char(expected_), Rf_type2char(actual_));
40 mutable char str_[64];
43 // Forward Declarations
49 } // namespace writable
55 typedef ptrdiff_t difference_type;
56 typedef size_t size_type;
65 r_vector(SEXP data, bool is_altrep);
67 #ifdef LONG_VECTOR_SUPPORT
68 T operator[](const int pos) const;
69 T at(const int pos) const;
71 T operator[](const R_xlen_t pos) const;
72 T operator[](const size_type pos) const;
73 T operator[](const r_string& name) const;
75 T at(const R_xlen_t pos) const;
76 T at(const size_type pos) const;
77 T at(const r_string& name) const;
79 bool contains(const r_string& name) const;
81 r_vector& operator=(const r_vector& rhs) {
82 SEXP old_protect = protect_;
85 protect_ = preserved.insert(data_);
86 is_altrep_ = rhs.is_altrep_;
87 data_p_ = rhs.data_p_;
88 length_ = rhs.length_;
90 preserved.release(old_protect);
95 r_vector(const r_vector& rhs) {
96 SEXP old_protect = protect_;
99 protect_ = preserved.insert(data_);
100 is_altrep_ = rhs.is_altrep_;
101 data_p_ = rhs.data_p_;
102 length_ = rhs.length_;
104 preserved.release(old_protect);
107 r_vector(const writable::r_vector<T>& rhs) : r_vector(static_cast<SEXP>(rhs)) {}
109 bool is_altrep() const;
113 R_xlen_t size() const;
115 operator SEXP() const;
117 operator sexp() const;
121 /// Provide access to the underlying data, mainly for interface
122 /// compatibility with std::vector
125 sexp attr(const char* name) const {
126 return SEXP(attribute_proxy<r_vector<T>>(*this, name));
129 sexp attr(const std::string& name) const {
130 return SEXP(attribute_proxy<r_vector<T>>(*this, name.c_str()));
133 sexp attr(SEXP name) const { return SEXP(attribute_proxy<r_vector<T>>(*this, name)); }
135 r_vector<r_string> names() const {
136 SEXP nms = SEXP(attribute_proxy<r_vector<T>>(*this, R_NamesSymbol));
137 if (nms == R_NilValue) {
138 return r_vector<r_string>();
144 class const_iterator {
146 using difference_type = ptrdiff_t;
147 using value_type = T;
149 using reference = T&;
150 using iterator_category = std::random_access_iterator_tag;
152 const_iterator(const r_vector* data, R_xlen_t pos);
154 inline const_iterator& operator+(R_xlen_t pos);
155 inline ptrdiff_t operator-(const const_iterator& other) const;
157 inline const_iterator& operator++();
158 inline const_iterator& operator--();
160 inline const_iterator& operator+=(R_xlen_t pos);
161 inline const_iterator& operator-=(R_xlen_t pos);
163 inline bool operator!=(const const_iterator& other) const;
164 inline bool operator==(const const_iterator& other) const;
166 inline T operator*() const;
168 friend class writable::r_vector<T>::iterator;
171 const r_vector* data_;
172 void fill_buf(R_xlen_t pos);
175 std::array<T, 64 * 64> buf_;
176 R_xlen_t block_start_ = 0;
177 R_xlen_t length_ = 0;
181 const_iterator begin() const;
182 const_iterator end() const;
184 const_iterator cbegin() const;
185 const_iterator cend() const;
187 const_iterator find(const r_string& name) const;
189 ~r_vector() { preserved.release(protect_); }
192 SEXP data_ = R_NilValue;
193 SEXP protect_ = R_NilValue;
194 bool is_altrep_ = false;
195 T* data_p_ = nullptr;
196 R_xlen_t length_ = 0;
198 static T* get_p(bool is_altrep, SEXP data);
200 static SEXP valid_type(SEXP data);
202 friend class writable::r_vector<T>;
207 template <typename T>
208 using has_begin_fun = std::decay<decltype(*begin(std::declval<T>()))>;
210 /// Read/write access to new or copied r_vectors
211 template <typename T>
212 class r_vector : public cpp11::r_vector<T> {
214 SEXP protect_ = R_NilValue;
216 // These are necessary because type names are not directly accessible in
217 // template inheritance
218 using cpp11::r_vector<T>::data_;
219 using cpp11::r_vector<T>::data_p_;
220 using cpp11::r_vector<T>::is_altrep_;
221 using cpp11::r_vector<T>::length_;
223 R_xlen_t capacity_ = 0;
229 const R_xlen_t index_;
234 proxy(SEXP data, const R_xlen_t index, T* const p, bool is_altrep);
236 proxy& operator=(const T& rhs);
237 proxy& operator+=(const T& rhs);
238 proxy& operator-=(const T& rhs);
239 proxy& operator*=(const T& rhs);
240 proxy& operator/=(const T& rhs);
241 proxy& operator++(int);
242 proxy& operator--(int);
250 typedef ptrdiff_t difference_type;
251 typedef size_t size_type;
252 typedef proxy value_type;
253 typedef proxy* pointer;
254 typedef proxy& reference;
256 class iterator : public cpp11::r_vector<T>::const_iterator {
258 const r_vector& data_;
259 using cpp11::r_vector<T>::const_iterator::block_start_;
260 using cpp11::r_vector<T>::const_iterator::pos_;
261 using cpp11::r_vector<T>::const_iterator::buf_;
262 using cpp11::r_vector<T>::const_iterator::length_;
263 using cpp11::r_vector<T>::const_iterator::fill_buf;
266 using difference_type = ptrdiff_t;
267 using value_type = proxy;
268 using pointer = proxy*;
269 using reference = proxy&;
270 using iterator_category = std::forward_iterator_tag;
272 iterator(const r_vector& data, R_xlen_t pos);
274 inline iterator& operator++();
276 inline proxy operator*() const;
278 using cpp11::r_vector<T>::const_iterator::operator!=;
280 inline iterator& operator+(R_xlen_t rhs);
283 r_vector() = default;
284 r_vector(const SEXP& data);
285 r_vector(SEXP&& data);
286 r_vector(const SEXP& data, bool is_altrep);
287 r_vector(SEXP&& data, bool is_altrep);
288 r_vector(std::initializer_list<T> il);
289 r_vector(std::initializer_list<named_arg> il);
290 r_vector(std::initializer_list<const char*> il);
291 r_vector(std::initializer_list<std::string> il);
293 template <typename Iter>
294 r_vector(Iter first, Iter last);
296 template <typename V, typename W = has_begin_fun<V>>
297 r_vector(const V& obj);
299 r_vector(const R_xlen_t size);
303 r_vector(const r_vector& rhs);
304 r_vector(r_vector&& rhs);
306 r_vector(const cpp11::r_vector<T>& rhs);
308 r_vector& operator=(const r_vector& rhs);
309 r_vector& operator=(r_vector&& rhs);
311 #ifdef LONG_VECTOR_SUPPORT
312 proxy operator[](const int pos) const;
313 proxy at(const int pos) const;
315 proxy operator[](const R_xlen_t pos) const;
316 proxy operator[](const size_type pos) const;
317 proxy operator[](const r_string& name) const;
319 proxy at(const R_xlen_t pos) const;
320 proxy at(const size_type pos) const;
321 proxy at(const r_string& name) const;
323 void push_back(T value);
324 void push_back(const named_arg& value);
327 void resize(R_xlen_t count);
329 void reserve(R_xlen_t new_capacity);
331 iterator insert(R_xlen_t pos, T value);
332 iterator erase(R_xlen_t pos);
336 iterator begin() const;
337 iterator end() const;
339 using cpp11::r_vector<T>::cbegin;
340 using cpp11::r_vector<T>::cend;
341 using cpp11::r_vector<T>::size;
343 iterator find(const r_string& name) const;
345 attribute_proxy<r_vector<T>> attr(const char* name) const {
346 return attribute_proxy<r_vector<T>>(*this, name);
349 attribute_proxy<r_vector<T>> attr(const std::string& name) const {
350 return attribute_proxy<r_vector<T>>(*this, name.c_str());
353 attribute_proxy<r_vector<T>> attr(SEXP name) const {
354 return attribute_proxy<r_vector<T>>(*this, name);
357 attribute_proxy<r_vector<T>> names() const {
358 return attribute_proxy<r_vector<T>>(*this, R_NamesSymbol);
361 operator SEXP() const;
363 } // namespace writable
365 // Implementations below
367 template <typename T>
368 inline r_vector<T>::r_vector(const SEXP data)
369 : data_(valid_type(data)),
370 protect_(preserved.insert(data)),
371 is_altrep_(ALTREP(data)),
372 data_p_(get_p(ALTREP(data), data)),
373 length_(Rf_xlength(data)) {}
375 template <typename T>
376 inline r_vector<T>::r_vector(const SEXP data, bool is_altrep)
377 : data_(valid_type(data)),
378 protect_(preserved.insert(data)),
379 is_altrep_(is_altrep),
380 data_p_(get_p(is_altrep, data)),
381 length_(Rf_xlength(data)) {}
383 template <typename T>
384 inline bool r_vector<T>::is_altrep() const {
388 template <typename T>
389 inline bool r_vector<T>::named() const {
390 return ((this->names()) != R_NilValue);
393 template <typename T>
394 inline R_xlen_t r_vector<T>::size() const {
398 template <typename T>
399 inline r_vector<T>::operator SEXP() const {
403 template <typename T>
404 inline bool r_vector<T>::empty() const {
405 return (!(this->size() > 0));
408 template <typename T>
409 inline r_vector<T>::operator sexp() const {
413 /// Provide access to the underlying data, mainly for interface
414 /// compatibility with std::vector
415 template <typename T>
416 inline SEXP r_vector<T>::data() const {
420 template <typename T>
421 inline typename r_vector<T>::const_iterator r_vector<T>::begin() const {
422 return const_iterator(this, 0);
425 template <typename T>
426 inline typename r_vector<T>::const_iterator r_vector<T>::end() const {
427 return const_iterator(this, length_);
430 template <typename T>
431 inline typename r_vector<T>::const_iterator r_vector<T>::cbegin() const {
432 return const_iterator(this, 0);
435 template <typename T>
436 inline typename r_vector<T>::const_iterator r_vector<T>::cend() const {
437 return const_iterator(this, length_);
440 template <typename T>
441 r_vector<T>::const_iterator::const_iterator(const r_vector* data, R_xlen_t pos)
442 : data_(data), pos_(pos), buf_() {
443 if (data_->is_altrep()) {
448 template <typename T>
449 inline typename r_vector<T>::const_iterator& r_vector<T>::const_iterator::operator++() {
451 if (data_->is_altrep() && pos_ >= block_start_ + length_) {
457 template <typename T>
458 inline typename r_vector<T>::const_iterator& r_vector<T>::const_iterator::operator--() {
460 if (data_->is_altrep() && pos_ > 0 && pos_ < block_start_) {
461 fill_buf(std::max(0_xl, pos_ - 64));
466 template <typename T>
467 inline typename r_vector<T>::const_iterator& r_vector<T>::const_iterator::operator+=(
470 if (data_->is_altrep() && pos_ >= block_start_ + length_) {
476 template <typename T>
477 inline typename r_vector<T>::const_iterator& r_vector<T>::const_iterator::operator-=(
480 if (data_->is_altrep() && pos_ >= block_start_ + length_) {
481 fill_buf(std::max(0_xl, pos_ - 64));
486 template <typename T>
487 inline bool r_vector<T>::const_iterator::operator!=(
488 const r_vector<T>::const_iterator& other) const {
489 return pos_ != other.pos_;
492 template <typename T>
493 inline bool r_vector<T>::const_iterator::operator==(
494 const r_vector<T>::const_iterator& other) const {
495 return pos_ == other.pos_;
498 template <typename T>
499 inline ptrdiff_t r_vector<T>::const_iterator::operator-(
500 const r_vector<T>::const_iterator& other) const {
501 return pos_ - other.pos_;
504 template <typename T>
505 inline typename r_vector<T>::const_iterator& r_vector<T>::const_iterator::operator+(
508 if (data_->is_altrep() && pos_ >= block_start_ + length_) {
514 template <typename T>
515 inline T cpp11::r_vector<T>::at(R_xlen_t pos) const {
516 if (pos < 0 || pos >= length_) {
517 throw std::out_of_range("r_vector");
520 return operator[](pos);
523 template <typename T>
524 inline T cpp11::r_vector<T>::at(size_type pos) const {
525 return at(static_cast<R_xlen_t>(pos));
528 template <typename T>
529 inline T cpp11::r_vector<T>::operator[](const r_string& name) const {
530 SEXP names = this->names();
531 R_xlen_t size = Rf_xlength(names);
533 for (R_xlen_t pos = 0; pos < size; ++pos) {
534 auto cur = Rf_translateCharUTF8(STRING_ELT(names, pos));
536 return operator[](pos);
540 throw std::out_of_range("r_vector");
543 template <typename T>
544 inline bool cpp11::r_vector<T>::contains(const r_string& name) const {
545 SEXP names = this->names();
546 R_xlen_t size = Rf_xlength(names);
548 for (R_xlen_t pos = 0; pos < size; ++pos) {
549 auto cur = Rf_translateCharUTF8(STRING_ELT(names, pos));
558 template <typename T>
559 inline typename cpp11::r_vector<T>::const_iterator cpp11::r_vector<T>::find(
560 const r_string& name) const {
561 SEXP names = this->names();
562 R_xlen_t size = Rf_xlength(names);
564 for (R_xlen_t pos = 0; pos < size; ++pos) {
565 auto cur = Rf_translateCharUTF8(STRING_ELT(names, pos));
567 return begin() + pos;
574 template <typename T>
575 inline T r_vector<T>::const_iterator::operator*() const {
576 if (data_->is_altrep()) {
577 return buf_[pos_ - block_start_];
579 return data_->data_p_[pos_];
583 #ifdef LONG_VECTOR_SUPPORT
584 template <typename T>
585 inline T r_vector<T>::operator[](const int pos) const {
586 return operator[](static_cast<R_xlen_t>(pos));
589 template <typename T>
590 inline T r_vector<T>::at(const int pos) const {
591 return at(static_cast<R_xlen_t>(pos));
595 template <typename T>
596 inline T r_vector<T>::operator[](size_type pos) const {
597 return operator[](static_cast<R_xlen_t>(pos));
602 template <typename T>
603 r_vector<T>::proxy::proxy(SEXP data, const R_xlen_t index, T* const p, bool is_altrep)
604 : data_(data), index_(index), p_(p), is_altrep_(is_altrep) {}
606 template <typename T>
607 inline typename r_vector<T>::proxy r_vector<T>::iterator::operator*() const {
608 if (data_.is_altrep()) {
609 return proxy(data_.data(), pos_, const_cast<T*>(&buf_[pos_ - block_start_]), true);
611 return proxy(data_.data(), pos_,
612 data_.data_p_ != nullptr ? &data_.data_p_[pos_] : nullptr, false);
616 template <typename T>
617 r_vector<T>::iterator::iterator(const r_vector& data, R_xlen_t pos)
618 : r_vector<T>::const_iterator(&data, pos), data_(data) {}
620 template <typename T>
621 inline typename r_vector<T>::iterator& r_vector<T>::iterator::operator++() {
623 if (data_.is_altrep() && pos_ >= block_start_ + length_) {
629 template <typename T>
630 inline typename r_vector<T>::iterator& r_vector<T>::iterator::operator+(R_xlen_t rhs) {
632 if (data_.is_altrep() && pos_ >= block_start_ + length_) {
638 template <typename T>
639 inline typename r_vector<T>::iterator r_vector<T>::begin() const {
640 return iterator(*this, 0);
643 template <typename T>
644 inline typename r_vector<T>::iterator r_vector<T>::end() const {
645 return iterator(*this, length_);
648 template <typename T>
649 inline r_vector<T>::r_vector(const SEXP& data)
650 : cpp11::r_vector<T>(safe[Rf_shallow_duplicate](data)),
651 protect_(preserved.insert(data_)),
652 capacity_(length_) {}
654 template <typename T>
655 inline r_vector<T>::r_vector(const SEXP& data, bool is_altrep)
656 : cpp11::r_vector<T>(safe[Rf_shallow_duplicate](data), is_altrep),
657 protect_(preserved.insert(data_)),
658 capacity_(length_) {}
660 template <typename T>
661 inline r_vector<T>::r_vector(SEXP&& data)
662 : cpp11::r_vector<T>(data), protect_(preserved.insert(data_)), capacity_(length_) {}
664 template <typename T>
665 inline r_vector<T>::r_vector(SEXP&& data, bool is_altrep)
666 : cpp11::r_vector<T>(data, is_altrep),
667 protect_(preserved.insert(data_)),
668 capacity_(length_) {}
670 template <typename T>
671 template <typename Iter>
672 inline r_vector<T>::r_vector(Iter first, Iter last) : r_vector() {
673 reserve(last - first);
674 while (first != last) {
680 template <typename T>
681 template <typename V, typename W>
682 inline r_vector<T>::r_vector(const V& obj) : r_vector() {
683 auto first = obj.begin();
684 auto last = obj.end();
685 reserve(last - first);
686 while (first != last) {
692 template <typename T>
693 inline r_vector<T>::r_vector(R_xlen_t size) : r_vector() {
697 template <typename T>
698 inline r_vector<T>::~r_vector() {
699 preserved.release(protect_);
702 #ifdef LONG_VECTOR_SUPPORT
703 template <typename T>
704 inline typename r_vector<T>::proxy r_vector<T>::operator[](const int pos) const {
705 return operator[](static_cast<R_xlen_t>(pos));
708 template <typename T>
709 inline typename r_vector<T>::proxy r_vector<T>::at(const int pos) const {
710 return at(static_cast<R_xlen_t>(pos));
714 template <typename T>
715 inline typename r_vector<T>::proxy r_vector<T>::operator[](const R_xlen_t pos) const {
717 return {data_, pos, nullptr, true};
719 return {data_, pos, data_p_ != nullptr ? &data_p_[pos] : nullptr, false};
722 template <typename T>
723 inline typename r_vector<T>::proxy r_vector<T>::operator[](size_type pos) const {
724 return operator[](static_cast<R_xlen_t>(pos));
727 template <typename T>
728 inline typename r_vector<T>::proxy r_vector<T>::at(const R_xlen_t pos) const {
729 if (pos < 0 || pos >= length_) {
730 throw std::out_of_range("r_vector");
732 return operator[](static_cast<R_xlen_t>(pos));
735 template <typename T>
736 inline typename r_vector<T>::proxy r_vector<T>::at(size_type pos) const {
737 return at(static_cast<R_xlen_t>(pos));
740 template <typename T>
741 inline typename r_vector<T>::proxy r_vector<T>::operator[](const r_string& name) const {
742 SEXP names = PROTECT(this->names());
743 R_xlen_t size = Rf_xlength(names);
745 for (R_xlen_t pos = 0; pos < size; ++pos) {
746 auto cur = Rf_translateCharUTF8(STRING_ELT(names, pos));
749 return operator[](pos);
754 throw std::out_of_range("r_vector");
757 template <typename T>
758 inline typename r_vector<T>::proxy r_vector<T>::at(const r_string& name) const {
759 return operator[](name);
762 template <typename T>
763 inline typename r_vector<T>::iterator r_vector<T>::find(const r_string& name) const {
764 SEXP names = PROTECT(this->names());
765 R_xlen_t size = Rf_xlength(names);
767 for (R_xlen_t pos = 0; pos < size; ++pos) {
768 auto cur = Rf_translateCharUTF8(STRING_ELT(names, pos));
771 return begin() + pos;
779 template <typename T>
780 inline r_vector<T>::r_vector(const r_vector<T>& rhs)
781 : cpp11::r_vector<T>(safe[Rf_shallow_duplicate](rhs)),
782 protect_(preserved.insert(data_)),
783 capacity_(rhs.capacity_) {}
785 template <typename T>
786 inline r_vector<T>::r_vector(r_vector<T>&& rhs)
787 : cpp11::r_vector<T>(rhs), protect_(rhs.protect_), capacity_(rhs.capacity_) {
788 rhs.data_ = R_NilValue;
789 rhs.protect_ = R_NilValue;
792 template <typename T>
793 inline r_vector<T>::r_vector(const cpp11::r_vector<T>& rhs)
794 : cpp11::r_vector<T>(safe[Rf_shallow_duplicate](rhs)),
795 protect_(preserved.insert(data_)),
796 capacity_(rhs.length_) {}
798 // We don't release the old object until the end in case we throw an exception
799 // during the duplicate.
800 template <typename T>
801 inline r_vector<T>& r_vector<T>::operator=(const r_vector<T>& rhs) {
802 if (data_ == rhs.data_) {
806 cpp11::r_vector<T>::operator=(rhs);
808 auto old_protect = protect_;
810 data_ = safe[Rf_shallow_duplicate](rhs.data_);
811 protect_ = preserved.insert(data_);
813 preserved.release(old_protect);
815 capacity_ = rhs.capacity_;
820 template <typename T>
821 inline r_vector<T>& r_vector<T>::operator=(r_vector<T>&& rhs) {
822 if (data_ == rhs.data_) {
826 cpp11::r_vector<T>::operator=(rhs);
828 SEXP old_protect = protect_;
831 protect_ = preserved.insert(data_);
833 preserved.release(old_protect);
835 capacity_ = rhs.capacity_;
837 rhs.data_ = R_NilValue;
838 rhs.protect_ = R_NilValue;
843 template <typename T>
844 inline void r_vector<T>::pop_back() {
848 template <typename T>
849 inline void r_vector<T>::resize(R_xlen_t count) {
854 template <typename T>
855 inline typename r_vector<T>::iterator r_vector<T>::insert(R_xlen_t pos, T value) {
858 R_xlen_t i = length_ - 1;
860 operator[](i) = (T) operator[](i - 1);
863 operator[](pos) = value;
865 return begin() + pos;
868 template <typename T>
869 inline typename r_vector<T>::iterator r_vector<T>::erase(R_xlen_t pos) {
871 while (i < length_ - 1) {
872 operator[](i) = (T) operator[](i + 1);
877 return begin() + pos;
880 template <typename T>
881 inline void r_vector<T>::clear() {
885 template <typename T>
886 inline r_vector<T>::operator SEXP() const {
887 if (length_ < capacity_) {
888 #if R_VERSION >= R_Version(3, 4, 0)
889 SETLENGTH(data_, length_);
890 SET_TRUELENGTH(data_, capacity_);
891 SET_GROWABLE_BIT(data_);
893 auto* p = const_cast<r_vector<T>*>(this);
894 p->data_ = safe[Rf_lengthgets](data_, length_);
900 template <typename T>
901 inline typename r_vector<T>::proxy& r_vector<T>::proxy::operator+=(const T& rhs) {
902 operator=(static_cast<T>(*this) + rhs);
906 template <typename T>
907 inline typename r_vector<T>::proxy& r_vector<T>::proxy::operator-=(const T& rhs) {
908 operator=(static_cast<T>(*this) - rhs);
912 template <typename T>
913 inline typename r_vector<T>::proxy& r_vector<T>::proxy::operator*=(const T& rhs) {
914 operator=(static_cast<T>(*this) * rhs);
918 template <typename T>
919 inline typename r_vector<T>::proxy& r_vector<T>::proxy::operator/=(const T& rhs) {
920 operator=(static_cast<T>(*this) / rhs);
924 template <typename T>
925 inline typename r_vector<T>::proxy& r_vector<T>::proxy::operator++(int) {
926 operator=(static_cast<T>(*this) + 1);
930 template <typename T>
931 inline typename r_vector<T>::proxy& r_vector<T>::proxy::operator--(int) {
932 operator=(static_cast<T>(*this) - 1);
936 template <typename T>
937 inline void r_vector<T>::proxy::operator--() {
938 operator=(static_cast<T>(*this) - 1);
941 template <typename T>
942 inline void r_vector<T>::proxy::operator++() {
943 operator=(static_cast<T>(*this) + 1);
946 } // namespace writable
948 // TODO: is there a better condition we could use, e.g. assert something true
949 // rather than three things false?
950 template <typename C, typename T>
951 using is_container_but_not_sexp_or_string = typename std::enable_if<
952 !std::is_constructible<C, SEXP>::value &&
953 !std::is_same<typename std::decay<C>::type, std::string>::value &&
954 !std::is_same<typename std::decay<T>::type, std::string>::value,
955 typename std::decay<C>::type>::type;
957 template <typename C, typename T = typename std::decay<C>::type::value_type>
958 // typename T = typename C::value_type>
959 is_container_but_not_sexp_or_string<C, T> as_cpp(SEXP from) {
960 auto obj = cpp11::r_vector<T>(from);
961 return {obj.begin(), obj.end()};
964 // TODO: could we make this generalize outside of std::string?
965 template <typename C, typename T = C>
966 using is_vector_of_strings = typename std::enable_if<
967 std::is_same<typename std::decay<T>::type, std::string>::value,
968 typename std::decay<C>::type>::type;
970 template <typename C, typename T = typename std::decay<C>::type::value_type>
971 // typename T = typename C::value_type>
972 is_vector_of_strings<C, T> as_cpp(SEXP from) {
973 auto obj = cpp11::r_vector<cpp11::r_string>(from);
974 typename std::decay<C>::type res;
975 auto it = obj.begin();
976 while (it != obj.end()) {
978 res.emplace_back(static_cast<std::string>(s));
984 template <typename T>
985 bool operator==(const r_vector<T>& lhs, const r_vector<T>& rhs) {
986 if (lhs.size() != rhs.size()) {
990 auto lhs_it = lhs.begin();
991 auto rhs_it = rhs.begin();
993 auto end = lhs.end();
994 while (lhs_it != end) {
995 if (!(*lhs_it == *rhs_it)) {
1004 template <typename T>
1005 bool operator!=(const r_vector<T>& lhs, const r_vector<T>& rhs) {
1006 return !(lhs == rhs);
1009 } // namespace cpp11