summaryrefslogtreecommitdiffstats
path: root/src/arrow/r/inst/include/cpp11/r_string.hpp
blob: d62f7270f7cea06cc1650a2e1e1def3635b76121 (plain)
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
// cpp11 version: 0.3.1.1
// vendored on: 2021-08-11
#pragma once

#include <string>       // for string, basic_string, operator==
#include <type_traits>  // for is_convertible, enable_if

#include "R_ext/Memory.h"     // for vmaxget, vmaxset
#include "cpp11/R.hpp"        // for SEXP, SEXPREC, Rf_mkCharCE, Rf_translat...
#include "cpp11/as.hpp"       // for as_sexp
#include "cpp11/protect.hpp"  // for unwind_protect, protect, protect::function
#include "cpp11/sexp.hpp"     // for sexp

namespace cpp11 {

class r_string {
 public:
  r_string() = default;
  r_string(SEXP data) : data_(data) {}
  r_string(const char* data) : data_(safe[Rf_mkCharCE](data, CE_UTF8)) {}
  r_string(const std::string& data)
      : data_(safe[Rf_mkCharLenCE](data.c_str(), data.size(), CE_UTF8)) {}

  operator SEXP() const { return data_; }
  operator sexp() const { return data_; }
  operator std::string() const {
    std::string res;
    res.reserve(size());

    void* vmax = vmaxget();
    unwind_protect([&] { res.assign(Rf_translateCharUTF8(data_)); });
    vmaxset(vmax);

    return res;
  }

  bool operator==(const r_string& rhs) const { return data_.data() == rhs.data_.data(); }

  bool operator==(const SEXP rhs) const { return data_.data() == rhs; }

  bool operator==(const char* rhs) const {
    return static_cast<std::string>(*this) == rhs;
  }

  bool operator==(const std::string& rhs) const {
    return static_cast<std::string>(*this) == rhs;
  }

  R_xlen_t size() const { return Rf_xlength(data_); }

 private:
  sexp data_ = R_NilValue;
};

inline SEXP as_sexp(std::initializer_list<r_string> il) {
  R_xlen_t size = il.size();

  sexp data;
  unwind_protect([&] {
    data = Rf_allocVector(STRSXP, size);
    auto it = il.begin();
    for (R_xlen_t i = 0; i < size; ++i, ++it) {
      if (*it == NA_STRING) {
        SET_STRING_ELT(data, i, *it);
      } else {
        SET_STRING_ELT(data, i, Rf_mkCharCE(Rf_translateCharUTF8(*it), CE_UTF8));
      }
    }
  });
  return data;
}

template <typename T, typename R = void>
using enable_if_r_string = enable_if_t<std::is_same<T, cpp11::r_string>::value, R>;

template <typename T>
enable_if_r_string<T, SEXP> as_sexp(T from) {
  r_string str(from);
  sexp res;
  unwind_protect([&] {
    res = Rf_allocVector(STRSXP, 1);

    if (str == NA_STRING) {
      SET_STRING_ELT(res, 0, str);
    } else {
      SET_STRING_ELT(res, 0, Rf_mkCharCE(Rf_translateCharUTF8(str), CE_UTF8));
    }
  });

  return res;
}

template <>
inline r_string na() {
  return NA_STRING;
}

}  // namespace cpp11