Suppose I want to wrap some C or C++ code which contains arrays or vectors that cannot be automatically mapped to R types by Rcpp, but which I need to pass to C/C++ functions that would output valid R objects. For example:
typedef union {
size_t val_sizet;
long double val_longdbl;
} weird_struct
std::vector<weird_struct> an_unmappable_obj;
an_unmappable_obj.resize(2);
an_unmappable_obj[0].val_sizet = 1e20;
an_unmappable_obj[1].val_longdbl = 1.5 * 1e20;
Run Code Online (Sandbox Code Playgroud)
Since this is a vector of a type that cannot be converted to any of R’s native types, I’m wondering how can I return and handle these objects inside R/Rcpp in such a way that the vector (or C array containing the same values) could be serialzed through saveRDS and its values restored after readRDS.
I guess one way of doing it would be through memcpy'ing the contents of the object to some C++ vector of a type that could be converted to Rcpp's 'NumericVector` or similar, then force-casting its first element to an array of the desired C types when it needs to be used, but I'm wondering if there's a better solution.
如果您只想保存C ++数据供以后在同一会话中使用,最简单的方法是使用外部指针。例如:
// [[Rcpp::export]]
Rcpp::XPtr< std::vector<double> > xptr_example() {
std::vector<double> * x = new std::vector<double>(10);
Rcpp::XPtr< std::vector<double> > p(x, true);
return p;
}
Run Code Online (Sandbox Code Playgroud)
相反,如果您仍然只想序列化,则有很多选项,但是您将不得不编写一些其他自定义代码。
正如你所说,你可以cast和memcpy转换成一个R矢量(使用RawVector替代NumericVector),但你必须要小心,你的类只有“普通的旧数据”,并没有什么特别喜欢的指针或文件处理程序。
使用Rcpp的更多正式序列化选项和示例可以在此处和此处看到。
我打算建议将cereal库与Rcereal一起使用,但这似乎很难与union. 不过,如果使用更像 C++ 的boost::variant,那效果很好。这个想法是将对象序列化为原始向量,然后可以使用saveRDS和保存和恢复readRDS。这里有一些示例代码:
#include <Rcpp.h>
// [[Rcpp::plugins("cpp11")]]
// [[Rcpp::depends(BH, Rcereal)]]
#include <boost/variant.hpp>
#include <cereal/types/vector.hpp>
#include <cereal/types/boost_variant.hpp>
#include <cereal/archives/binary.hpp>
#include <sstream>
// [[Rcpp::export]]
Rcpp::RawVector get_weird_vec() {
std::vector<boost::variant<std::size_t, long double>> an_unmappable_obj;
an_unmappable_obj.push_back((std::size_t) 3e9);
an_unmappable_obj.push_back((long double) 1.5 * 1e20);
std::ostringstream os;
cereal::BinaryOutputArchive archive(os);
archive(an_unmappable_obj);
std::string out = os.str();
Rcpp::RawVector res(out.size());
std::copy(out.begin(), out.end(), res.begin());
return res;
}
// [[Rcpp::export]]
void process_weird_vec(Rcpp::RawVector src) {
std::stringstream ss;
ss.write(reinterpret_cast<char*>(&src[0]), src.size());
cereal::BinaryInputArchive archive(ss);
std::vector<boost::variant<std::size_t, long double>> an_unmappable_obj;
archive(an_unmappable_obj);
Rcpp::Rcout << an_unmappable_obj[0] << std::endl;
Rcpp::Rcout << an_unmappable_obj[1] << std::endl;
}
/*** R
raw <- get_weird_vec()
raw
process_weird_vec(raw)
*/
Run Code Online (Sandbox Code Playgroud)
输出:
> raw <- get_weird_vec()
> raw
[1] 02 00 00 00 00 00 00 00 00 00 00 00 00 5e d0 b2 01 00 00 00 00 80 49 41 d4
[26] b0 1a 82 42 40 08 02
> process_weird_vec(raw)
3000000000
1.5e+20
Run Code Online (Sandbox Code Playgroud)
参考:
| 归档时间: |
|
| 查看次数: |
97 次 |
| 最近记录: |