Skip to content

Commit dd78834

Browse files
authored
Unify initializer_list<T> constructors (#376)
1 parent 457c441 commit dd78834

File tree

13 files changed

+163
-39
lines changed

13 files changed

+163
-39
lines changed

cpp11test/src/test-doubles.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,14 @@ context("doubles-C++") {
175175

176176
UNPROTECT(1);
177177
}
178+
179+
test_that("writable::doubles(initializer_list<double>)") {
180+
cpp11::writable::doubles x({1, 2.5, 3});
181+
expect_true(x[0] == 1.0);
182+
expect_true(x[1] == 2.5);
183+
expect_true(x[2] == 3.0);
184+
}
185+
178186
test_that("writable::doubles(SEXP, bool)") {
179187
SEXP x = PROTECT(Rf_ScalarReal(5.));
180188
cpp11::writable::doubles y(x, false);

cpp11test/src/test-integers.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,13 @@ context("integers-C++") {
168168
UNPROTECT(1);
169169
}
170170

171+
test_that("writable::integers(initializer_list<int>)") {
172+
cpp11::writable::integers x({1, 2, 3});
173+
expect_true(x[0] == 1);
174+
expect_true(x[1] == 2);
175+
expect_true(x[2] == 3);
176+
}
177+
171178
#if defined(__APPLE__) && defined(R_VERSION) && R_VERSION >= R_Version(3, 5, 0)
172179
test_that("writable::integers(ALTREP_SEXP)") {
173180
// ALTREP compact-seq

cpp11test/src/test-list.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,4 +163,17 @@ context("list-C++") {
163163
expect_true(Rf_xlength(y) == 0);
164164
expect_true(y != R_NilValue);
165165
}
166+
167+
test_that("writable::list(initializer_list<SEXP>)") {
168+
SEXP x1 = PROTECT(Rf_allocVector(INTSXP, 1));
169+
SEXP x2 = PROTECT(Rf_allocVector(REALSXP, 2));
170+
SEXP x3 = PROTECT(Rf_allocVector(STRSXP, 3));
171+
172+
cpp11::writable::list x({x1, x2, x3});
173+
expect_true(x[0] == x1);
174+
expect_true(x[1] == x2);
175+
expect_true(x[2] == x3);
176+
177+
UNPROTECT(3);
178+
}
166179
}

cpp11test/src/test-logicals.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,27 @@ context("logicals-C++") {
127127

128128
UNPROTECT(1);
129129
}
130+
131+
test_that("writable::logicals(initializer_list<r_bool>)") {
132+
cpp11::writable::logicals x(
133+
{cpp11::r_bool(true), cpp11::r_bool(false), cpp11::r_bool(NA_INTEGER)});
134+
expect_true(x[0] == cpp11::r_bool(true));
135+
expect_true(x[1] == cpp11::r_bool(false));
136+
expect_true(x[2] == cpp11::r_bool(NA_INTEGER));
137+
138+
// This works due to implicit conversion of `bool` to `r_bool`
139+
cpp11::writable::logicals y({true, false, false});
140+
expect_true(y[0] == cpp11::r_bool(true));
141+
expect_true(y[1] == cpp11::r_bool(false));
142+
expect_true(y[2] == cpp11::r_bool(false));
143+
144+
// This works due to implicit conversion of `Rboolean` to `r_bool`
145+
cpp11::writable::logicals z({TRUE, FALSE, FALSE});
146+
expect_true(z[0] == cpp11::r_bool(true));
147+
expect_true(z[1] == cpp11::r_bool(false));
148+
expect_true(z[2] == cpp11::r_bool(false));
149+
}
150+
130151
test_that("is_na(r_bool)") {
131152
cpp11::r_bool x = TRUE;
132153
expect_true(!cpp11::is_na(x));

cpp11test/src/test-raws.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,13 @@ context("raws-C++") {
128128
UNPROTECT(1);
129129
}
130130

131+
test_that("writable::raws(initializer_list<uint_8>)") {
132+
cpp11::writable::raws x({1, 2, 255});
133+
expect_true(x[0] == 1);
134+
expect_true(x[1] == 2);
135+
expect_true(x[2] == 255);
136+
}
137+
131138
// test_that("writable::raws(ALTREP_SEXP)") {
132139
// SEXP x = PROTECT(R_compact_uint8_trange(1, 5));
133140
//// Need to find (or create) an altrep class that implements duplicate.

cpp11test/src/test-strings.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,34 @@ context("strings-C++") {
133133
UNPROTECT(1);
134134
}
135135

136+
test_that("writable::strings(initializer_list<r_string>)") {
137+
cpp11::r_string abc = cpp11::r_string("abc");
138+
cpp11::r_string na = cpp11::r_string(NA_STRING);
139+
140+
cpp11::writable::strings x({abc, na, abc});
141+
expect_true(x[0] == abc);
142+
expect_true(x[1] == na);
143+
expect_true(x[2] == abc);
144+
145+
// This works due to implicit conversion of `SEXP` to `r_string`
146+
SEXP a = PROTECT(Rf_mkCharCE("a", CE_UTF8));
147+
SEXP b = PROTECT(Rf_mkCharCE("b", CE_UTF8));
148+
cpp11::writable::strings y({a, b});
149+
expect_true(y[0] == cpp11::r_string("a"));
150+
expect_true(y[1] == cpp11::r_string("b"));
151+
152+
// This works due to implicit conversion of `const char*` to `r_string`
153+
cpp11::writable::strings z({"neat", "stuff"});
154+
expect_true(z[0] == cpp11::r_string("neat"));
155+
expect_true(z[1] == cpp11::r_string("stuff"));
156+
157+
cpp11::writable::strings w({std::string("neat"), std::string("stuff")});
158+
expect_true(w[0] == cpp11::r_string("neat"));
159+
expect_true(w[1] == cpp11::r_string("stuff"));
160+
161+
UNPROTECT(2);
162+
}
163+
136164
test_that("std::initializer_list<const char*>") {
137165
cpp11::writable::strings x{"foo"};
138166
expect_true(x.size() == 1);

inst/include/cpp11/doubles.hpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,12 @@ inline SEXPTYPE r_vector<double>::get_sexptype() {
5959
return REALSXP;
6060
}
6161

62+
template <>
63+
inline void r_vector<double>::set_elt(
64+
SEXP x, R_xlen_t i, typename traits::get_underlying_type<double>::type value) {
65+
SET_REAL_ELT(x, i, value);
66+
}
67+
6268
template <>
6369
inline typename r_vector<double>::proxy& r_vector<double>::proxy::operator=(
6470
const double& rhs) {
@@ -81,10 +87,6 @@ inline r_vector<double>::proxy::operator double() const {
8187
}
8288
}
8389

84-
template <>
85-
inline r_vector<double>::r_vector(std::initializer_list<double> il)
86-
: cpp11::r_vector<double>(as_sexp(il)), capacity_(il.size()) {}
87-
8890
template <>
8991
inline r_vector<double>::r_vector(std::initializer_list<named_arg> il)
9092
: cpp11::r_vector<double>(safe[Rf_allocVector](REALSXP, il.size())),

inst/include/cpp11/integers.hpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@ inline SEXPTYPE r_vector<int>::get_sexptype() {
6060
return INTSXP;
6161
}
6262

63+
template <>
64+
inline void r_vector<int>::set_elt(
65+
SEXP x, R_xlen_t i, typename traits::get_underlying_type<int>::type value) {
66+
SET_INTEGER_ELT(x, i, value);
67+
}
68+
6369
template <>
6470
inline typename r_vector<int>::proxy& r_vector<int>::proxy::operator=(const int& rhs) {
6571
if (is_altrep_) {
@@ -81,10 +87,6 @@ inline r_vector<int>::proxy::operator int() const {
8187
}
8288
}
8389

84-
template <>
85-
inline r_vector<int>::r_vector(std::initializer_list<int> il)
86-
: cpp11::r_vector<int>(as_sexp(il)), capacity_(il.size()) {}
87-
8890
template <>
8991
inline r_vector<int>::r_vector(std::initializer_list<named_arg> il)
9092
: cpp11::r_vector<int>(safe[Rf_allocVector](INTSXP, il.size())),

inst/include/cpp11/list.hpp

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ inline SEXPTYPE r_vector<SEXP>::get_sexptype() {
6868
return VECSXP;
6969
}
7070

71+
template <>
72+
inline void r_vector<SEXP>::set_elt(
73+
SEXP x, R_xlen_t i, typename traits::get_underlying_type<SEXP>::type value) {
74+
SET_VECTOR_ELT(x, i, value);
75+
}
76+
7177
template <>
7278
inline typename r_vector<SEXP>::proxy& r_vector<SEXP>::proxy::operator=(const SEXP& rhs) {
7379
SET_VECTOR_ELT(data_, index_, rhs);
@@ -79,16 +85,6 @@ inline r_vector<SEXP>::proxy::operator SEXP() const {
7985
return VECTOR_ELT(data_, index_);
8086
}
8187

82-
template <>
83-
inline r_vector<SEXP>::r_vector(std::initializer_list<SEXP> il)
84-
: cpp11::r_vector<SEXP>(safe[Rf_allocVector](VECSXP, il.size())),
85-
capacity_(il.size()) {
86-
auto it = il.begin();
87-
for (R_xlen_t i = 0; i < capacity_; ++i, ++it) {
88-
SET_VECTOR_ELT(data_, i, *it);
89-
}
90-
}
91-
9288
template <>
9389
inline r_vector<SEXP>::r_vector(std::initializer_list<named_arg> il)
9490
: cpp11::r_vector<SEXP>(safe[Rf_allocVector](VECSXP, il.size())),

inst/include/cpp11/logicals.hpp

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ inline SEXPTYPE r_vector<r_bool>::get_sexptype() {
5858
return LGLSXP;
5959
}
6060

61+
template <>
62+
inline void r_vector<r_bool>::set_elt(
63+
SEXP x, R_xlen_t i, typename traits::get_underlying_type<r_bool>::type value) {
64+
SET_LOGICAL_ELT(x, i, value);
65+
}
66+
6167
template <>
6268
inline typename r_vector<r_bool>::proxy& r_vector<r_bool>::proxy::operator=(
6369
const r_bool& rhs) {
@@ -82,15 +88,6 @@ inline bool operator==(const r_vector<r_bool>::proxy& lhs, r_bool rhs) {
8288
return static_cast<r_bool>(lhs).operator==(rhs);
8389
}
8490

85-
template <>
86-
inline r_vector<r_bool>::r_vector(std::initializer_list<r_bool> il)
87-
: cpp11::r_vector<r_bool>(Rf_allocVector(LGLSXP, il.size())), capacity_(il.size()) {
88-
auto it = il.begin();
89-
for (R_xlen_t i = 0; i < capacity_; ++i, ++it) {
90-
SET_LOGICAL_ELT(data_, i, *it);
91-
}
92-
}
93-
9491
template <>
9592
inline r_vector<r_bool>::r_vector(std::initializer_list<named_arg> il)
9693
: cpp11::r_vector<r_bool>(safe[Rf_allocVector](LGLSXP, il.size())),

inst/include/cpp11/r_vector.hpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,6 @@ class r_vector : public cpp11::r_vector<T> {
189189
r_vector(const r_vector& rhs);
190190
r_vector(r_vector&& rhs);
191191
r_vector(const cpp11::r_vector<T>& rhs);
192-
/// Implemented in specialization
193192
r_vector(std::initializer_list<T> il);
194193
/// Implemented in specialization
195194
r_vector(std::initializer_list<named_arg> il);
@@ -308,6 +307,8 @@ class r_vector : public cpp11::r_vector<T> {
308307
private:
309308
/// Implemented in specialization
310309
static SEXPTYPE get_sexptype();
310+
/// Implemented in specialization
311+
static void set_elt(SEXP x, R_xlen_t i, underlying_type value);
311312

312313
using cpp11::r_vector<T>::get_p;
313314
};
@@ -717,6 +718,24 @@ template <typename T>
717718
inline r_vector<T>::r_vector(const cpp11::r_vector<T>& rhs)
718719
: cpp11::r_vector<T>(safe[Rf_shallow_duplicate](rhs.data_)), capacity_(rhs.length_) {}
719720

721+
template <typename T>
722+
inline r_vector<T>::r_vector(std::initializer_list<T> il)
723+
: cpp11::r_vector<T>(safe[Rf_allocVector](get_sexptype(), il.size())),
724+
capacity_(il.size()) {
725+
auto it = il.begin();
726+
727+
if (data_p_ != nullptr) {
728+
for (R_xlen_t i = 0; i < capacity_; ++i, ++it) {
729+
data_p_[i] = static_cast<underlying_type>(*it);
730+
}
731+
} else {
732+
// Handles both the ALTREP and VECSXP cases
733+
for (R_xlen_t i = 0; i < capacity_; ++i, ++it) {
734+
set_elt(data_, i, static_cast<underlying_type>(*it));
735+
}
736+
}
737+
}
738+
720739
template <typename T>
721740
inline r_vector<T>::r_vector(const R_xlen_t size) : r_vector() {
722741
resize(size);

inst/include/cpp11/raws.hpp

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <cstdint> // for uint8_t
66
#include <initializer_list> // for initializer_list
77

8+
#include "Rversion.h"
89
#include "cpp11/R.hpp" // for RAW, SEXP, SEXPREC, Rf_allocVector
910
#include "cpp11/attribute_proxy.hpp" // for attribute_proxy
1011
#include "cpp11/named_arg.hpp" // for named_arg
@@ -67,6 +68,16 @@ inline SEXPTYPE r_vector<uint8_t>::get_sexptype() {
6768
return RAWSXP;
6869
}
6970

71+
template <>
72+
inline void r_vector<uint8_t>::set_elt(
73+
SEXP x, R_xlen_t i, typename traits::get_underlying_type<uint8_t>::type value) {
74+
#if R_VERSION >= R_Version(4, 2, 0)
75+
SET_RAW_ELT(x, i, value);
76+
#else
77+
RAW(x)[i] = value;
78+
#endif
79+
}
80+
7081
template <>
7182
inline typename r_vector<uint8_t>::proxy& r_vector<uint8_t>::proxy::operator=(
7283
const uint8_t& rhs) {
@@ -89,16 +100,6 @@ inline r_vector<uint8_t>::proxy::operator uint8_t() const {
89100
}
90101
}
91102

92-
template <>
93-
inline r_vector<uint8_t>::r_vector(std::initializer_list<uint8_t> il)
94-
: cpp11::r_vector<uint8_t>(safe[Rf_allocVector](RAWSXP, il.size())),
95-
capacity_(il.size()) {
96-
auto it = il.begin();
97-
for (R_xlen_t i = 0; i < capacity_; ++i, ++it) {
98-
data_p_[i] = *it;
99-
}
100-
}
101-
102103
template <>
103104
inline r_vector<uint8_t>::r_vector(std::initializer_list<named_arg> il)
104105
: cpp11::r_vector<uint8_t>(safe[Rf_allocVector](RAWSXP, il.size())),

inst/include/cpp11/strings.hpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ inline SEXPTYPE r_vector<r_string>::get_sexptype() {
5858
return STRSXP;
5959
}
6060

61+
template <>
62+
inline void r_vector<r_string>::set_elt(
63+
SEXP x, R_xlen_t i, typename traits::get_underlying_type<r_string>::type value) {
64+
SET_STRING_ELT(x, i, value);
65+
}
66+
6167
template <>
6268
inline typename r_vector<r_string>::proxy& r_vector<r_string>::proxy::operator=(
6369
const r_string& rhs) {
@@ -113,9 +119,26 @@ inline r_vector<r_string>::r_vector(SEXP&& data)
113119
}
114120
}
115121

122+
// Requires specialization to handle `NA_STRING` and UTF-8 translation
116123
template <>
117124
inline r_vector<r_string>::r_vector(std::initializer_list<r_string> il)
118-
: cpp11::r_vector<r_string>(as_sexp(il)), capacity_(il.size()) {}
125+
: cpp11::r_vector<r_string>(safe[Rf_allocVector](STRSXP, il.size())),
126+
capacity_(il.size()) {
127+
unwind_protect([&] {
128+
auto it = il.begin();
129+
130+
for (R_xlen_t i = 0; i < capacity_; ++i, ++it) {
131+
// i.e. to `SEXP`
132+
underlying_type elt = static_cast<underlying_type>(*it);
133+
134+
if (elt == NA_STRING) {
135+
set_elt(data_, i, elt);
136+
} else {
137+
set_elt(data_, i, Rf_mkCharCE(Rf_translateCharUTF8(elt), CE_UTF8));
138+
}
139+
}
140+
});
141+
}
119142

120143
template <>
121144
inline r_vector<r_string>::r_vector(std::initializer_list<named_arg> il)

0 commit comments

Comments
 (0)