File: R.hpp

package info (click to toggle)
r-cran-cpp11 0.5.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,428 kB
  • sloc: cpp: 9,732; sh: 14; makefile: 2
file content (135 lines) | stat: -rw-r--r-- 3,286 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#pragma once

#ifdef R_INTERNALS_H_
#if !(defined(R_NO_REMAP) && defined(STRICT_R_HEADERS))
#error R headers were included before cpp11 headers \
  and at least one of R_NO_REMAP or STRICT_R_HEADERS \
  was not defined.
#endif
#endif

#ifndef R_NO_REMAP
#define R_NO_REMAP
#endif

#ifndef STRICT_R_HEADERS
#define STRICT_R_HEADERS
#endif

#include "R_ext/Boolean.h"
#include "Rinternals.h"
#include "Rversion.h"

// clang-format off
#ifdef __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wattributes"
#endif

#ifdef __GNUC__
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wattributes"
#endif
// clang-format on

#include <type_traits>

#if defined(R_VERSION) && R_VERSION >= R_Version(4, 4, 0)
// Use R's new macro
#define CPP11_PRIdXLEN_T R_PRIdXLEN_T
#else
// Recreate what new R does
#ifdef LONG_VECTOR_SUPPORT
#define CPP11_PRIdXLEN_T "td"
#else
#define CPP11_PRIdXLEN_T "d"
#endif
#endif

namespace cpp11 {
namespace literals {

constexpr R_xlen_t operator""_xl(unsigned long long int value) { return value; }

}  // namespace literals

namespace traits {
template <typename T>
struct get_underlying_type {
  using type = T;
};
}  // namespace traits

namespace detail {

// Annoyingly, `TYPEOF()` returns an `int` rather than a `SEXPTYPE`,
// which can throw warnings with `-Wsign-compare` on Windows.
inline SEXPTYPE r_typeof(SEXP x) { return static_cast<SEXPTYPE>(TYPEOF(x)); }

/// Get an object from an environment
///
/// SAFETY: Keep as a pure C function. Call like an R API function, i.e. wrap in `safe[]`
/// as required.
inline SEXP r_env_get(SEXP env, SEXP sym) {
#if defined(R_VERSION) && R_VERSION >= R_Version(4, 5, 0)
  const Rboolean inherits = FALSE;
  return R_getVar(sym, env, inherits);
#else
  SEXP out = Rf_findVarInFrame3(env, sym, TRUE);

  // Replicate the 3 checks from `R_getVar()` (along with exact error message):
  // - Object must be found in the `env`
  // - `R_MissingArg` can't leak from an `env` anymore
  // - Promises can't leak from an `env` anymore

  if (out == R_MissingArg) {
    Rf_errorcall(R_NilValue, "argument \"%s\" is missing, with no default",
                 CHAR(PRINTNAME(sym)));
  }

  if (out == R_UnboundValue) {
    Rf_errorcall(R_NilValue, "object '%s' not found", CHAR(PRINTNAME(sym)));
  }

  if (r_typeof(out) == PROMSXP) {
    PROTECT(out);
    out = Rf_eval(out, env);
    UNPROTECT(1);
  }

  return out;
#endif
}

/// Check if an object exists in an environment
///
/// SAFETY: Keep as a pure C function. Call like an R API function, i.e. wrap in `safe[]`
/// as required.
inline bool r_env_has(SEXP env, SEXP sym) {
#if R_VERSION >= R_Version(4, 2, 0)
  return R_existsVarInFrame(env, sym);
#else
  return Rf_findVarInFrame3(env, sym, FALSE) != R_UnboundValue;
#endif
}

}  // namespace detail

template <typename T>
inline T na();

template <typename T>
inline typename std::enable_if<!std::is_same<typename std::decay<T>::type, double>::value,
                               bool>::type
is_na(const T& value) {
  return value == na<T>();
}

template <typename T>
inline typename std::enable_if<std::is_same<typename std::decay<T>::type, double>::value,
                               bool>::type
is_na(const T& value) {
  return ISNA(value);
}

}  // namespace cpp11