FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Add r_bool wrapper for Rboolean · amoeba/cpp11@6c34d21 · GitHub

Repository navigation

Commit 6c34d21

Browse files
authored andcommitted
Add r_bool wrapper for Rboolean
1 parent f764ada commit 6c34d21

11 files changed

Lines changed: 142 additions & 69 deletions

File tree

‎cpp11test/src/test-as.cpp‎

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,8 +331,6 @@ context("as_cpp-C++") {
331331
test_that("as_sexp(bool)") {
332332
SEXP l1 = PROTECT(cpp11::as_sexp(true));
333333
SEXP l2 = PROTECT(cpp11::as_sexp(false));
334-
/* TODO: handle NA_LOGICAL, possibly need a separate enum class rather than relying
335-
* on bool or R's Rboolean */
336334

337335
expect_true(Rf_isLogical(l1));
338336
expect_true(Rf_xlength(l1) == 1);
@@ -345,6 +343,26 @@ context("as_cpp-C++") {
345343
UNPROTECT(2);
346344
}
347345

346+
test_that("as_sexp(r_bool)") {
347+
SEXP l1 = PROTECT(cpp11::as_sexp(cpp11::r_bool(true)));
348+
SEXP l2 = PROTECT(cpp11::as_sexp(cpp11::r_bool(false)));
349+
SEXP l3 = PROTECT(cpp11::as_sexp(cpp11::r_bool()));
350+
351+
expect_true(Rf_isLogical(l1));
352+
expect_true(Rf_xlength(l1) == 1);
353+
expect_true(LOGICAL(l1)[0] == TRUE);
354+
355+
expect_true(Rf_isLogical(l2));
356+
expect_true(Rf_xlength(l2) == 1);
357+
expect_true(LOGICAL(l2)[0] == FALSE);
358+
359+
expect_true(Rf_isLogical(l3));
360+
expect_true(Rf_xlength(l3) == 1);
361+
expect_true(LOGICAL(l3)[0] == NA_LOGICAL);
362+
363+
UNPROTECT(3);
364+
}
365+
348366
test_that("as_sexp(raws)") {
349367
cpp11::writable::raws x;
350368
x.push_back(0);

‎cpp11test/src/test-logicals.cpp‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,11 @@ context("logicals-C++") {
126126

127127
UNPROTECT(1);
128128
}
129-
test_that("is_na(Rboolean)") {
130-
Rboolean x = TRUE;
129+
test_that("is_na(r_bool)") {
130+
cpp11::r_bool x = TRUE;
131131
expect_true(!cpp11::is_na(x));
132132

133-
Rboolean y = NA_LOGICAL;
133+
cpp11::r_bool y = NA_LOGICAL;
134134
expect_true(cpp11::is_na(y));
135135
}
136136

‎inst/include/cpp11.hpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "cpp11/matrix.hpp"
1717
#include "cpp11/named_arg.hpp"
1818
#include "cpp11/protect.hpp"
19+
#include "cpp11/r_bool.hpp"
1920
#include "cpp11/r_string.hpp"
2021
#include "cpp11/r_vector.hpp"
2122
#include "cpp11/raws.hpp"

‎inst/include/cpp11/R.hpp‎

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,16 @@
11
#pragma once
22

3-
#include <limits>
4-
5-
#include "R_ext/Arith.h"
6-
7-
#undef FALSE
8-
#undef TRUE
9-
#undef NA_LOGICAL
10-
11-
extern "C" {
12-
typedef enum {
13-
FALSE = 0,
14-
TRUE = 1,
15-
NA_LOGICAL = std::numeric_limits<int>::min()
16-
} Rboolean;
17-
}
18-
19-
#define R_EXT_BOOLEAN_H_
3+
#ifdef R_INTERNALS_H_
4+
#if !(defined(R_NO_REMAP) && defined(STRICT_R_HEADERS))
5+
#error R headers were included before cpp11 headers \
6+
and at least one of R_NO_REMAP or STRICT_R_HEADERS \
7+
was not defined.
8+
#endif
9+
#endif
2010

2111
#define R_NO_REMAP
2212
#define STRICT_R_HEADERS
2313
#include "Rinternals.h"
24-
#undef STRICT_R_HEADERS
25-
#undef R_NO_REMAP
2614

2715
// clang-format off
2816
#ifdef __clang__

‎inst/include/cpp11/external_pointer.hpp‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include "cpp11/R.hpp" // for SEXP, SEXPREC, TYPEOF, R_NilValue, R_C...
88
#include "cpp11/protect.hpp" // for protect, safe, protect::function
9+
#include "cpp11/r_bool.hpp" // for r_bool
910
#include "cpp11/r_vector.hpp" // for type_error
1011
#include "cpp11/sexp.hpp" // for sexp
1112

@@ -54,7 +55,7 @@ class external_pointer {
5455
external_pointer(pointer p, bool use_deleter = true, bool finalize_on_exit = true)
5556
: data_(safe[R_MakeExternalPtr]((void*)p, R_NilValue, R_NilValue)) {
5657
if (use_deleter) {
57-
R_RegisterCFinalizerEx(data_, r_deleter, static_cast<Rboolean>(finalize_on_exit));
58+
R_RegisterCFinalizerEx(data_, r_deleter, static_cast<r_bool>(finalize_on_exit));
5859
}
5960
}
6061

‎inst/include/cpp11/logicals.hpp‎

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
#include <array> // for array
55
#include <initializer_list> // for initializer_list
66

7-
#include "cpp11/R.hpp" // for Rboolean, SEXP, SEXPREC, Rf_all...
7+
#include "cpp11/R.hpp" // for SEXP, SEXPREC, Rf_all...
88
#include "cpp11/attribute_proxy.hpp" // for attribute_proxy
99
#include "cpp11/named_arg.hpp" // for named_arg
1010
#include "cpp11/protect.hpp" // for preserved
11+
#include "cpp11/r_bool.hpp" // for r_bool
1112
#include "cpp11/r_vector.hpp" // for r_vector, r_vector<>::proxy
1213
#include "cpp11/sexp.hpp" // for sexp
1314

@@ -16,41 +17,41 @@
1617
namespace cpp11 {
1718

1819
template <>
19-
inline SEXP r_vector<Rboolean>::valid_type(SEXP data) {
20+
inline SEXP r_vector<r_bool>::valid_type(SEXP data) {
2021
if (TYPEOF(data) != LGLSXP) {
2122
throw type_error(LGLSXP, TYPEOF(data));
2223
}
2324
return data;
2425
}
2526

2627
template <>
27-
inline Rboolean r_vector<Rboolean>::operator[](const R_xlen_t pos) const {
28-
return is_altrep_ ? static_cast<Rboolean>(LOGICAL_ELT(data_, pos)) : data_p_[pos];
28+
inline r_bool r_vector<r_bool>::operator[](const R_xlen_t pos) const {
29+
return is_altrep_ ? static_cast<r_bool>(LOGICAL_ELT(data_, pos)) : data_p_[pos];
2930
}
3031

3132
template <>
32-
inline Rboolean* r_vector<Rboolean>::get_p(bool is_altrep, SEXP data) {
33+
inline r_bool* r_vector<r_bool>::get_p(bool is_altrep, SEXP data) {
3334
if (is_altrep) {
3435
return nullptr;
3536
} else {
36-
return reinterpret_cast<Rboolean*>(LOGICAL(data));
37+
return reinterpret_cast<r_bool*>(LOGICAL(data));
3738
}
3839
}
3940

4041
template <>
41-
inline void r_vector<Rboolean>::const_iterator::fill_buf(R_xlen_t pos) {
42+
inline void r_vector<r_bool>::const_iterator::fill_buf(R_xlen_t pos) {
4243
length_ = std::min(64_xl, data_->size() - pos);
4344
LOGICAL_GET_REGION(data_->data_, pos, length_, reinterpret_cast<int*>(buf_.data()));
4445
block_start_ = pos;
4546
}
4647

47-
typedef r_vector<Rboolean> logicals;
48+
typedef r_vector<r_bool> logicals;
4849

4950
namespace writable {
5051

5152
template <>
52-
inline typename r_vector<Rboolean>::proxy& r_vector<Rboolean>::proxy::operator=(
53-
const Rboolean& rhs) {
53+
inline typename r_vector<r_bool>::proxy& r_vector<r_bool>::proxy::operator=(
54+
const r_bool& rhs) {
5455
if (is_altrep_) {
5556
SET_LOGICAL_ELT(data_, index_, rhs);
5657
} else {
@@ -60,17 +61,21 @@ inline typename r_vector<Rboolean>::proxy& r_vector<Rboolean>::proxy::operator=(
6061
}
6162

6263
template <>
63-
inline r_vector<Rboolean>::proxy::operator Rboolean() const {
64+
inline r_vector<r_bool>::proxy::operator r_bool() const {
6465
if (p_ == nullptr) {
65-
return static_cast<Rboolean>(LOGICAL_ELT(data_, index_));
66+
return static_cast<r_bool>(LOGICAL_ELT(data_, index_));
6667
} else {
6768
return *p_;
6869
}
6970
}
7071

72+
inline bool operator==(const r_vector<r_bool>::proxy& lhs, r_bool rhs) {
73+
return static_cast<r_bool>(lhs).operator==(rhs);
74+
}
75+
7176
template <>
72-
inline r_vector<Rboolean>::r_vector(std::initializer_list<Rboolean> il)
73-
: cpp11::r_vector<Rboolean>(Rf_allocVector(LGLSXP, il.size())), capacity_(il.size()) {
77+
inline r_vector<r_bool>::r_vector(std::initializer_list<r_bool> il)
78+
: cpp11::r_vector<r_bool>(Rf_allocVector(LGLSXP, il.size())), capacity_(il.size()) {
7479
protect_ = preserved.insert(data_);
7580
auto it = il.begin();
7681
for (R_xlen_t i = 0; i < capacity_; ++i, ++it) {
@@ -79,8 +84,8 @@ inline r_vector<Rboolean>::r_vector(std::initializer_list<Rboolean> il)
7984
}
8085

8186
template <>
82-
inline r_vector<Rboolean>::r_vector(std::initializer_list<named_arg> il)
83-
: cpp11::r_vector<Rboolean>(safe[Rf_allocVector](LGLSXP, il.size())),
87+
inline r_vector<r_bool>::r_vector(std::initializer_list<named_arg> il)
88+
: cpp11::r_vector<r_bool>(safe[Rf_allocVector](LGLSXP, il.size())),
8489
capacity_(il.size()) {
8590
protect_ = preserved.insert(data_);
8691
int n_protected = 0;
@@ -92,7 +97,7 @@ inline r_vector<Rboolean>::r_vector(std::initializer_list<named_arg> il)
9297
++n_protected;
9398
auto it = il.begin();
9499
for (R_xlen_t i = 0; i < capacity_; ++i, ++it) {
95-
data_p_[i] = static_cast<Rboolean>(LOGICAL_ELT(it->value(), 0));
100+
data_p_[i] = static_cast<r_bool>(LOGICAL_ELT(it->value(), 0));
96101
SET_STRING_ELT(names, i, Rf_mkCharCE(it->name(), CE_UTF8));
97102
}
98103
UNPROTECT(n_protected);
@@ -105,20 +110,20 @@ inline r_vector<Rboolean>::r_vector(std::initializer_list<named_arg> il)
105110
}
106111

107112
template <>
108-
inline void r_vector<Rboolean>::reserve(R_xlen_t new_capacity) {
113+
inline void r_vector<r_bool>::reserve(R_xlen_t new_capacity) {
109114
data_ = data_ == R_NilValue ? safe[Rf_allocVector](LGLSXP, new_capacity)
110115
: safe[Rf_xlengthgets](data_, new_capacity);
111116
SEXP old_protect = protect_;
112117
protect_ = preserved.insert(data_);
113118

114119
preserved.release(old_protect);
115120

116-
data_p_ = reinterpret_cast<Rboolean*>(LOGICAL(data_));
121+
data_p_ = reinterpret_cast<r_bool*>(LOGICAL(data_));
117122
capacity_ = new_capacity;
118123
}
119124

120125
template <>
121-
inline void r_vector<Rboolean>::push_back(Rboolean value) {
126+
inline void r_vector<r_bool>::push_back(r_bool value) {
122127
while (length_ >= capacity_) {
123128
reserve(capacity_ == 0 ? 1 : capacity_ *= 2);
124129
}
@@ -130,9 +135,7 @@ inline void r_vector<Rboolean>::push_back(Rboolean value) {
130135
++length_;
131136
}
132137

133-
typedef r_vector<Rboolean> logicals;
138+
typedef r_vector<r_bool> logicals;
134139

135140
} // namespace writable
136-
137-
inline bool is_na(Rboolean x) { return x == NA_LOGICAL; }
138141
} // namespace cpp11

‎inst/include/cpp11/matrix.hpp‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
#include <string> // for string
44

5-
#include "cpp11/R.hpp" // for SEXP, SEXPREC, R_xlen_t, Rboolean, INT...
5+
#include "cpp11/R.hpp" // for SEXP, SEXPREC, R_xlen_t, INT...
6+
#include "cpp11/r_bool.hpp" // for r_bool
67
#include "cpp11/r_string.hpp" // for r_string
78
#include "cpp11/r_vector.hpp" // for r_vector
89
#include "cpp11/sexp.hpp" // for sexp
@@ -95,13 +96,13 @@ class matrix {
9596

9697
using doubles_matrix = matrix<r_vector<double>, double>;
9798
using integers_matrix = matrix<r_vector<int>, int>;
98-
using logicals_matrix = matrix<r_vector<Rboolean>, Rboolean>;
99+
using logicals_matrix = matrix<r_vector<r_bool>, r_bool>;
99100
using strings_matrix = matrix<r_vector<r_string>, r_string>;
100101

101102
namespace writable {
102103
using doubles_matrix = matrix<r_vector<double>, r_vector<double>::proxy>;
103104
using integers_matrix = matrix<r_vector<int>, r_vector<int>::proxy>;
104-
using logicals_matrix = matrix<r_vector<Rboolean>, r_vector<Rboolean>::proxy>;
105+
using logicals_matrix = matrix<r_vector<r_bool>, r_vector<r_bool>::proxy>;
105106
using strings_matrix = matrix<r_vector<r_string>, r_vector<r_string>::proxy>;
106107
} // namespace writable
107108

‎inst/include/cpp11/protect.hpp‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@
66
#include <string> // for string, basic_string
77
#include <tuple> // for tuple, make_tuple
88

9-
// NB: cpp11/R.hpp must precede R_ext includes so our definition of Rboolean is used
9+
// NB: cpp11/R.hpp must precede R_ext/Error.h to ensure R_NO_REMAP is defined
1010
#include "cpp11/R.hpp" // for SEXP, SEXPREC, CDR, R_NilValue, CAR, R_Pres...
1111

12-
#include "R_ext/Error.h" // for Rf_error, Rf_warning
13-
#include "R_ext/Print.h" // for REprintf
14-
#include "R_ext/Utils.h" // for R_CheckUserInterrupt
15-
#include "Rversion.h" // for R_VERSION, R_Version
12+
#include "R_ext/Boolean.h" // for Rboolean
13+
#include "R_ext/Error.h" // for Rf_error, Rf_warning
14+
#include "R_ext/Print.h" // for REprintf
15+
#include "R_ext/Utils.h" // for R_CheckUserInterrupt
16+
#include "Rversion.h" // for R_VERSION, R_Version
1617

1718
#if defined(R_VERSION) && R_VERSION >= R_Version(3, 5, 0)
1819
#define HAS_UNWIND_PROTECT
@@ -51,7 +52,7 @@ SEXP unwind_protect(Fun&& code) {
5152
},
5253
&code,
5354
[](void* jmpbuf, Rboolean jump) {
54-
if (jump) {
55+
if (jump == TRUE) {
5556
// We need to first jump back into the C++ stacks because you can't safely throw
5657
// exceptions from C stack frames.
5758
longjmp(*static_cast<std::jmp_buf*>(jmpbuf), 1);

‎inst/include/cpp11/r_bool.hpp‎

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#pragma once
2+
3+
#include <limits> // for numeric_limits
4+
#include <type_traits> // for is_convertible, enable_if
5+
6+
#include "R_ext/Boolean.h" // for Rboolean
7+
#include "cpp11/R.hpp" // for SEXP, SEXPREC, ...
8+
#include "cpp11/as.hpp" // for as_sexp
9+
#include "cpp11/protect.hpp" // for unwind_protect, preserved
10+
#include "cpp11/sexp.hpp" // for sexp
11+
12+
namespace cpp11 {
13+
14+
class r_bool {
15+
public:
16+
r_bool() = default;
17+
18+
r_bool(SEXP data) {
19+
if (Rf_isLogical(data)) {
20+
if (Rf_xlength(data) == 1) {
21+
value_ = static_cast<Rboolean>(LOGICAL_ELT(data, 0));
22+
}
23+
}
24+
stop("Invalid r_bool value: %x", data);
25+
}
26+
27+
r_bool(bool value) : value_(value ? TRUE : FALSE) {}
28+
r_bool(Rboolean value) : value_(value) {}
29+
r_bool(int value) : value_(from_int(value)) {}
30+
31+
explicit operator bool() const { return value_ == TRUE; }
32+
operator int() const { return value_; }
33+
operator Rboolean() const { return value_; }
34+
35+
bool operator==(r_bool rhs) const { return value_ == rhs.value_; }
36+
bool operator==(bool rhs) const { return operator==(r_bool(rhs)); }
37+
bool operator==(Rboolean rhs) const { return operator==(r_bool(rhs)); }
38+
bool operator==(int rhs) const { return operator==(r_bool(rhs)); }
39+
40+
private:
41+
static constexpr Rboolean na = static_cast<Rboolean>(std::numeric_limits<int>::min());
42+
43+
static Rboolean from_int(int value) {
44+
if (value == static_cast<int>(FALSE)) return FALSE;
45+
if (value == static_cast<int>(na)) return na;
46+
return TRUE;
47+
}
48+
49+
Rboolean value_ = na;
50+
};
51+
52+
inline bool is_na(r_bool x) { return x == r_bool(); }
53+
54+
template <typename T, typename R = void>
55+
using enable_if_r_bool = enable_if_t<std::is_same<T, r_bool>::value, R>;
56+
57+
template <typename T>
58+
enable_if_r_bool<T, SEXP> as_sexp(T from) {
59+
sexp res = Rf_allocVector(LGLSXP, 1);
60+
safe[SET_LOGICAL_ELT](res.data(), 0, static_cast<Rboolean>(from));
61+
return res;
62+
}
63+
64+
} // namespace cpp11

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL