diff --git a/ChangeLog b/ChangeLog index 334f12794..0fdddac43 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2017-11-05 Daniel C. Dillon + + * inst/include/Rcpp/vector/Vector.h: Added inject() and extract() + functions to allow insertion and retrieval of raw C++ data into + and from Rcpp::Vector of arithmetic types. + * inst/unitTests/cpp/Vector.cpp: Unit tests + * inst/unitTests/runit.Vector.R: Unit tests + 2017-11-04 Dirk Eddelbuettel * vignettes/Rcpp-FAQ.Rmd: Add 'skip_final_break: true' toggle diff --git a/inst/NEWS.Rd b/inst/NEWS.Rd index 406332c4e..fa403387d 100644 --- a/inst/NEWS.Rd +++ b/inst/NEWS.Rd @@ -13,7 +13,9 @@ allocating one (Kirill Müller in \ghpr{763}). \item New \code{DateVector} and \code{DatetimeVector} classes are now the default fully deprecating the old classes as announced one year ago. - + \item New \code{Vector::inject()} and \code{Vector::extract()} functions + for copying raw byte data from C++ into an element or elements in + \code{Vector}. } \item Changes in Rcpp Package: \itemize{ diff --git a/inst/include/Rcpp/vector/Vector.h b/inst/include/Rcpp/vector/Vector.h index 141bce006..eadafaa71 100644 --- a/inst/include/Rcpp/vector/Vector.h +++ b/inst/include/Rcpp/vector/Vector.h @@ -374,6 +374,59 @@ class Vector : return NameProxy( const_cast(*this), name ) ; } + template< typename T > + inline typename traits::enable_if< + traits::is_arithmetic< stored_type >::value + && sizeof(T) <= sizeof(stored_type), void >::type + inject(R_xlen_t i, const T &val) { + std::memcpy(&cache.ref(offset(i)), &val, sizeof(T)); + } + + template< typename T > + inline typename traits::enable_if< + traits::is_arithmetic< stored_type >::value + && sizeof(T) == sizeof(stored_type), void >::type + inject(R_xlen_t start, const T *val, std::size_t len) { + std::memcpy(&cache.ref(offset(start)), val, sizeof(T) * len); + } + + template< typename T > + inline typename traits::enable_if< + traits::is_arithmetic< stored_type >::value + && sizeof(T) < sizeof(stored_type), void >::type + inject(R_xlen_t start, const T *val, std::size_t len) { + for (std::size_t i = 0; i < len; ++i) { + inject(start + i, *(val + i)); + } + } + + template< typename T > + inline typename traits::enable_if< + traits::is_arithmetic< stored_type >::value + && sizeof(stored_type) >= sizeof(T), void >::type + extract(R_xlen_t i, T &val) { + std::memcpy(&val, &cache.ref(offset(i)), sizeof(T)); + } + + template< typename T > + inline typename traits::enable_if< + traits::is_arithmetic< stored_type >::value + && sizeof(stored_type) == sizeof(T), void >::type + extract(R_xlen_t start, T *val, std::size_t len) { + std::memcpy(val, &cache.ref(offset(start)), + sizeof(stored_type) * len); + } + + template< typename T > + inline typename traits::enable_if< + traits::is_arithmetic< stored_type >::value + && sizeof(T) < sizeof(stored_type), void >::type + extract(R_xlen_t start, T *val, std::size_t len) { + for (std::size_t i = 0; i < len; ++i) { + extract(start + i, *(val + i)); + } + } + inline operator RObject() const { return RObject( Storage::get__() ); } diff --git a/inst/unitTests/cpp/Vector.cpp b/inst/unitTests/cpp/Vector.cpp index 2c47b7e7a..db7100247 100644 --- a/inst/unitTests/cpp/Vector.cpp +++ b/inst/unitTests/cpp/Vector.cpp @@ -848,3 +848,75 @@ String vec_print_integer(IntegerVector v) { IntegerVector vec_subset(IntegerVector x, IntegerVector y) { return x[y - 1]; } + +// [[Rcpp::export]] +NumericVector vec_inject() { + int64_t i = 12345; + int64_t ii = 9876543210; + + NumericVector v(2); + + v.inject(0, i); + v.inject(1, ii); + + return v; +} + +// [[Rcpp::export]] +NumericVector vec_inject_array() { + const int64_t arr[] = { 12345, 9876543210 }; + + NumericVector v(2); + v.inject(0, arr, 2); + + return v; +} + +// [[Rcpp::export]] +NumericVector vec_inject_array_smaller() { + const int32_t arr[] = { 12345, 98765432 }; + + NumericVector v(2); + v.inject(0, arr, 2); + + return v; +} + +// [[Rcpp::export]] +NumericVector vec_extract(NumericVector v) { + int64_t i; + int64_t ii; + + v.extract(0, i); + v.extract(1, ii); + + NumericVector v2(2); + v2.inject(0, i); + v2.inject(1, ii); + + return v2; +} + +// [[Rcpp::export]] +NumericVector vec_extract_array(NumericVector v) { + int64_t i[2]; + + v.extract(0, i, 2); + + NumericVector v2(2); + v2.inject(0, i, 2); + + return v2; +} + +// [[Rcpp::export]] +NumericVector vec_extract_array_smaller(NumericVector v) { + int32_t i[2]; + + v.extract(0, i, 2); + + NumericVector v2(2); + v2.inject(0, i, 2); + + return v2; +} diff --git a/inst/unitTests/runit.Vector.R b/inst/unitTests/runit.Vector.R index fdb0b0e58..25deb3c4f 100644 --- a/inst/unitTests/runit.Vector.R +++ b/inst/unitTests/runit.Vector.R @@ -755,5 +755,37 @@ if (.runThisTest) { gctorture(FALSE) checkEquals(x[y], z) } + + test.numeric.vector.inject <- function() { + v <- vec_inject() + checkIdentical(v, c(6.0992403979101885879e-320, + 4.8796606997276282938e-314)) + } + + test.numeric.vector.inject.array <- function() { + v <- vec_inject_array() + checkIdentical(v, c(6.0992403979101885879e-320, + 4.8796606997276282938e-314)) + } + + test.numeric.vector.inject.extract.array.smaller <- function() { + v <- vec_inject_array_smaller() + v2 <- vec_extract_array_smaller(v) + checkIdentical(v, v2) + } + + test.numeric.vector.extract <- function() { + v <- c(6.0992403979101885879e-320, 4.8796606997276282938e-314) + + res <- vec_extract(v) + checkIdentical(v, res) + } + + test.numeric.vector.extract_array <- function() { + v <- c(6.0992403979101885879e-320, 4.8796606997276282938e-314) + + res <- vec_extract_array(v) + checkIdentical(v, res) + } }