diff --git a/ChangeLog b/ChangeLog index 7ec6570b6..9dfd6f1e3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,38 @@ +2026-09-30 Kevin Ushey + + * inst/include/Rcpp/traits/sugar_operand.h: New trait for how sugar + expressions hold their operands: vectors by reference, and nested + expressions and views by value, so stored expressions don't dangle + * inst/include/Rcpp/traits/is_elementwise.h: New trait for whether a + sugar expression can be written in place into storage it may read from + * inst/include/Rcpp/sugar/tools/check_sizes.h: New helpers checking that + sugar operands, and vectors assigned into views, have matching lengths + * inst/include/RcppCommon.h: Include the above + * inst/include/Rcpp/sugar/sugar_forward.h: Idem + * inst/include/Rcpp/sugar/: Hold operands via sugar_operand, declare + elementwise operands, and check operand lengths + * inst/include/Rcpp/stats/dpq/dpq.h: Idem + * inst/include/Rcpp/sugar/block/SugarBlock_3.h: Also fix the type of the + third operand + * inst/include/Rcpp/sugar/logical/and.h: Fix operator&& on two single + logical results, hold their operands by value, and make NA && FALSE + return FALSE + * inst/include/Rcpp/sugar/logical/or.h: Idem for operator||, making + NA || TRUE return TRUE, and fix the base class of Or_SingleLogicalResult_bool + * inst/include/Rcpp/sugar/logical/not.h: Hold the operand of operator! + by value + * inst/include/Rcpp/sugar/logical/SingleLogicalResult.h: Add get_ref() + * inst/include/Rcpp/vector/Vector.h: Evaluate sugar expressions that + aren't elementwise before assigning them in place + * inst/include/Rcpp/vector/RangeIndexer.h: Idem, and check lengths + * inst/include/Rcpp/vector/MatrixColumn.h: Idem + * inst/include/Rcpp/vector/MatrixRow.h: Idem + * inst/include/Rcpp/vector/MatrixBase.h: Add a const get_ref() + * inst/tinytest/cpp/sugar_expressions.cpp: New tests + * inst/tinytest/test_sugar.R: Idem + * vignettes/rmd/Rcpp-sugar.Rmd: Document operand lengths, storing + expressions, and assignment + 2026-09-22 Iñaki Ucar * inst/include/Rcpp/sugar/matrix/col.h: Fix Col constructor using ncol() diff --git a/inst/NEWS.Rd b/inst/NEWS.Rd index 0bac0eee9..0666ec7ea 100644 --- a/inst/NEWS.Rd +++ b/inst/NEWS.Rd @@ -27,6 +27,18 @@ warnings (Iñaki in \ghpr{1508} closing \ghit{1497}) \item The \code{col} constructor now uses \code{nrow} in an initialization (Iñaki in \ghpr{1509}) + \item Sugar expressions hold nested expressions by value so they can be + stored, evaluate expressions that may read the target before assigning + them in place, and signal an error for operands of different lengths + (Kevin in \ghpr{1513} closing \ghit{1512}). Same-length assignment + of an expression that is not elementwise, such as \code{x = rev(x)}, + now goes through a temporary vector. + \item Assignment between overlapping subsets of the same vector, as in + \code{x[i] = x[j]}, reads the source elements before writing (Kevin in + \ghpr{1513}) + \item The sugar operators \code{!}, \code{&&} and \code{||} on single + logical results such as \code{all()} now compile, and follow R's + handling of \code{NA} (Kevin in \ghpr{1513}) } \item Changes in Rcpp Documentation: \itemize{ diff --git a/inst/include/Rcpp/stats/dpq/dpq.h b/inst/include/Rcpp/stats/dpq/dpq.h index c5721f06f..c68ab8029 100644 --- a/inst/include/Rcpp/stats/dpq/dpq.h +++ b/inst/include/Rcpp/stats/dpq/dpq.h @@ -35,9 +35,10 @@ class D0 : public Rcpp::VectorBase< REALSXP, NA, D0 > { public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef double (*FunPtr)(double,int) ; + typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ; D0( FunPtr ptr_, const VEC_TYPE& vec_, bool log_ ) : - ptr(ptr_), vec(vec_), log(log_) {} + ptr(ptr_), vec(vec_.get_ref()), log(log_) {} inline double operator[]( R_xlen_t i) const { return ptr( vec[i], log ); @@ -47,7 +48,7 @@ class D0 : public Rcpp::VectorBase< REALSXP, NA, D0 > { private: FunPtr ptr ; - const VEC_TYPE& vec; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec; int log; }; @@ -56,9 +57,10 @@ class D1 : public Rcpp::VectorBase< REALSXP, NA, D1 > { public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef double (*FunPtr)(double,double,int) ; + typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ; D1( FunPtr ptr_, const VEC_TYPE& vec_, double p0_ , bool log_) : - ptr(ptr_), vec(vec_), p0(p0_), log(log_) {} + ptr(ptr_), vec(vec_.get_ref()), p0(p0_), log(log_) {} inline double operator[]( R_xlen_t i) const { return ptr( vec[i], p0, log ); @@ -68,7 +70,7 @@ class D1 : public Rcpp::VectorBase< REALSXP, NA, D1 > { private: FunPtr ptr ; - const VEC_TYPE& vec; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec; double p0 ; int log; } ; @@ -78,9 +80,10 @@ class D2 : public Rcpp::VectorBase< REALSXP, NA, D2 > { public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef double (*FunPtr)(double,double,double,int) ; + typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ; D2( FunPtr ptr_, const VEC_TYPE& vec_, double p0_, double p1_ , bool log_) : - ptr(ptr_), vec(vec_), p0(p0_), p1(p1_), log(log_) {} + ptr(ptr_), vec(vec_.get_ref()), p0(p0_), p1(p1_), log(log_) {} inline double operator[]( R_xlen_t i) const { return ptr( vec[i], p0, p1, log ); @@ -90,7 +93,7 @@ class D2 : public Rcpp::VectorBase< REALSXP, NA, D2 > { private: FunPtr ptr ; - const VEC_TYPE& vec; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec; double p0, p1 ; int log; } ; @@ -100,9 +103,10 @@ class D3 : public Rcpp::VectorBase< REALSXP, NA, D3 > { public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef double (*FunPtr)(double,double,double,double,int) ; + typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ; D3( FunPtr ptr_, const VEC_TYPE& vec_, double p0_, double p1_, double p2_ , bool log_ ) : - ptr(ptr_), vec(vec_), p0(p0_), p1(p1_), p2(p2_), log(log_) {} + ptr(ptr_), vec(vec_.get_ref()), p0(p0_), p1(p1_), p2(p2_), log(log_) {} inline double operator[]( R_xlen_t i) const { return ptr( vec[i], p0, p1, p2, log ); @@ -112,7 +116,7 @@ class D3 : public Rcpp::VectorBase< REALSXP, NA, D3 > { private: FunPtr ptr ; - const VEC_TYPE& vec; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec; double p0, p1, p2 ; int log; } ; @@ -125,10 +129,11 @@ class P0 : public Rcpp::VectorBase< REALSXP, NA, P0 >{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef double (*FunPtr)(double,int,int) ; + typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ; P0( FunPtr ptr_, const VEC_TYPE& vec_, bool lower_tail = true, bool log_ = false ) : - ptr(ptr_), vec(vec_), lower(lower_tail), log(log_) {} + ptr(ptr_), vec(vec_.get_ref()), lower(lower_tail), log(log_) {} inline double operator[]( R_xlen_t i) const { return ptr( vec[i], lower, log ); @@ -138,7 +143,7 @@ class P0 : public Rcpp::VectorBase< REALSXP, NA, P0 >{ private: FunPtr ptr ; - const VEC_TYPE& vec; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec; int lower, log; }; @@ -149,10 +154,11 @@ class P1 : public Rcpp::VectorBase< REALSXP, NA, P1 >{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef double (*FunPtr)(double,double,int,int) ; + typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ; P1( FunPtr ptr_, const VEC_TYPE& vec_, double p0_, bool lower_tail = true, bool log_ = false ) : - ptr(ptr_), vec(vec_), p0(p0_), lower(lower_tail), log(log_) {} + ptr(ptr_), vec(vec_.get_ref()), p0(p0_), lower(lower_tail), log(log_) {} inline double operator[]( R_xlen_t i) const { return ptr( vec[i], p0, lower, log ); @@ -162,7 +168,7 @@ class P1 : public Rcpp::VectorBase< REALSXP, NA, P1 >{ private: FunPtr ptr ; - const VEC_TYPE& vec; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec; double p0 ; int lower, log; @@ -174,10 +180,11 @@ class P2 : public Rcpp::VectorBase< REALSXP, NA, P2 >{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef double (*FunPtr)(double,double,double,int,int) ; + typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ; P2( FunPtr ptr_, const VEC_TYPE& vec_, double p0_, double p1_, bool lower_tail = true, bool log_ = false ) : - ptr(ptr_), vec(vec_), p0(p0_), p1(p1_), lower(lower_tail), log(log_) {} + ptr(ptr_), vec(vec_.get_ref()), p0(p0_), p1(p1_), lower(lower_tail), log(log_) {} inline double operator[]( R_xlen_t i) const { return ptr( vec[i], p0, p1, lower, log ); @@ -187,7 +194,7 @@ class P2 : public Rcpp::VectorBase< REALSXP, NA, P2 >{ private: FunPtr ptr ; - const VEC_TYPE& vec; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec; double p0, p1 ; int lower, log; }; @@ -197,10 +204,11 @@ class P3 : public Rcpp::VectorBase< REALSXP, NA, P3 >{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef double (*FunPtr)(double,double,double,double,int,int) ; + typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ; P3( FunPtr ptr_, const VEC_TYPE& vec_, double p0_, double p1_, double p2_, bool lower_tail = true, bool log_ = false ) : - ptr(ptr_), vec(vec_), p0(p0_), p1(p1_), p2(p2_), lower(lower_tail), log(log_) {} + ptr(ptr_), vec(vec_.get_ref()), p0(p0_), p1(p1_), p2(p2_), lower(lower_tail), log(log_) {} inline double operator[]( R_xlen_t i) const { return ptr( vec[i], p0, p1, p2, lower, log ); @@ -210,7 +218,7 @@ class P3 : public Rcpp::VectorBase< REALSXP, NA, P3 >{ private: FunPtr ptr ; - const VEC_TYPE& vec; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec; double p0, p1,p2 ; int lower, log; @@ -223,10 +231,11 @@ class Q0 : public Rcpp::VectorBase< REALSXP, NA, Q0 >{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef double (*FunPtr)(double,int,int) ; + typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ; Q0( FunPtr ptr_, const VEC_TYPE& vec_, bool lower_tail = true, bool log_ = false ) : - ptr(ptr_), vec(vec_), lower(lower_tail), log(log_) {} + ptr(ptr_), vec(vec_.get_ref()), lower(lower_tail), log(log_) {} inline double operator[]( R_xlen_t i) const { return ptr( vec[i], lower, log ); @@ -236,7 +245,7 @@ class Q0 : public Rcpp::VectorBase< REALSXP, NA, Q0 >{ private: FunPtr ptr ; - const VEC_TYPE& vec; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec; int lower, log; }; @@ -246,10 +255,11 @@ class Q1 : public Rcpp::VectorBase< REALSXP, NA, Q1 >{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef double (*FunPtr)(double,double,int,int) ; + typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ; Q1( FunPtr ptr_, const VEC_TYPE& vec_, double p0_, bool lower_tail = true, bool log_ = false ) : - ptr(ptr_), vec(vec_), p0(p0_), lower(lower_tail), log(log_) {} + ptr(ptr_), vec(vec_.get_ref()), p0(p0_), lower(lower_tail), log(log_) {} inline double operator[]( R_xlen_t i) const { return ptr( vec[i], p0, lower, log ); @@ -259,7 +269,7 @@ class Q1 : public Rcpp::VectorBase< REALSXP, NA, Q1 >{ private: FunPtr ptr ; - const VEC_TYPE& vec; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec; double p0 ; int lower, log; @@ -270,10 +280,11 @@ class Q2 : public Rcpp::VectorBase< REALSXP, NA, Q2 >{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef double (*FunPtr)(double,double,double,int,int) ; + typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ; Q2( FunPtr ptr_, const VEC_TYPE& vec_, double p0_, double p1_, bool lower_tail = true, bool log_ = false ) : - ptr(ptr_), vec(vec_), p0(p0_), p1(p1_), lower(lower_tail), log(log_) {} + ptr(ptr_), vec(vec_.get_ref()), p0(p0_), p1(p1_), lower(lower_tail), log(log_) {} inline double operator[]( R_xlen_t i) const { return ptr( vec[i], p0, p1, lower, log ); @@ -283,7 +294,7 @@ class Q2 : public Rcpp::VectorBase< REALSXP, NA, Q2 >{ private: FunPtr ptr ; - const VEC_TYPE& vec; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec; double p0, p1 ; int lower, log; @@ -294,10 +305,11 @@ class Q3 : public Rcpp::VectorBase< REALSXP, NA, Q3 >{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef double (*FunPtr)(double,double,double,double,int,int) ; + typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ; Q3( FunPtr ptr_, const VEC_TYPE& vec_, double p0_, double p1_, double p2_, bool lower_tail = true, bool log_ = false ) : - ptr(ptr_), vec(vec_), p0(p0_), p1(p1_), p2(p2_), lower(lower_tail), log(log_) {} + ptr(ptr_), vec(vec_.get_ref()), p0(p0_), p1(p1_), p2(p2_), lower(lower_tail), log(log_) {} inline double operator[]( R_xlen_t i) const { return ptr( vec[i], p0, p1, p2, lower, log ); @@ -307,7 +319,7 @@ class Q3 : public Rcpp::VectorBase< REALSXP, NA, Q3 >{ private: FunPtr ptr ; - const VEC_TYPE& vec; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec; double p0, p1, p2 ; int lower, log; }; diff --git a/inst/include/Rcpp/sugar/Range.h b/inst/include/Rcpp/sugar/Range.h index 08da6d1c4..8042f3845 100644 --- a/inst/include/Rcpp/sugar/Range.h +++ b/inst/include/Rcpp/sugar/Range.h @@ -27,6 +27,8 @@ namespace Rcpp{ class Range : public VectorBase{ public: + typedef traits::elementwise_operands<> rcpp_elementwise ; + Range( R_xlen_t start_, R_xlen_t end__ ) : start(start_), end_(end__){ if( start_ > end__ ){ throw std::range_error( "upper value must be greater than lower value" ) ; diff --git a/inst/include/Rcpp/sugar/block/SugarBlock_1.h b/inst/include/Rcpp/sugar/block/SugarBlock_1.h index 78e0f8a4e..fff2fc6a2 100644 --- a/inst/include/Rcpp/sugar/block/SugarBlock_1.h +++ b/inst/include/Rcpp/sugar/block/SugarBlock_1.h @@ -29,7 +29,8 @@ template class SugarBlock_1 : public Rcpp::VectorBase< Rcpp::traits::r_sexptype_traits::rtype , NA, SugarBlock_1 > { public: typedef RESULT_TYPE (*FunPtr)(U1) ; - SugarBlock_1( FunPtr ptr_, const T1 & vec_) : ptr(ptr_), vec(vec_){} + typedef Rcpp::traits::elementwise_operands< T1 > rcpp_elementwise ; + SugarBlock_1( FunPtr ptr_, const T1 & vec_) : ptr(ptr_), vec(vec_.get_ref()){} inline RESULT_TYPE operator[]( R_xlen_t i) const { return ptr( vec[i] ) ; @@ -38,7 +39,7 @@ class SugarBlock_1 : public Rcpp::VectorBase< Rcpp::traits::r_sexptype_traits::type vec ; }; } // sugar diff --git a/inst/include/Rcpp/sugar/block/SugarBlock_2.h b/inst/include/Rcpp/sugar/block/SugarBlock_2.h index d5f01ccb9..14ecd242f 100644 --- a/inst/include/Rcpp/sugar/block/SugarBlock_2.h +++ b/inst/include/Rcpp/sugar/block/SugarBlock_2.h @@ -29,9 +29,10 @@ template ::rtype , NA, SugarBlock_2 > { public: typedef RESULT_TYPE (*FunPtr)(U1,U2) ; + typedef Rcpp::traits::elementwise_operands< T1, T2 > rcpp_elementwise ; SugarBlock_2( FunPtr ptr_, const T1 & x_, const T2& y_ ) : - ptr(ptr_), x(x_), y(y_){ - // TODO: check that x and y have same size + ptr(ptr_), x(x_.get_ref()), y(y_.get_ref()){ + check_sizes(x.size(), y.size()) ; } inline RESULT_TYPE operator[]( R_xlen_t i) const { @@ -41,8 +42,8 @@ class SugarBlock_2 : public Rcpp::VectorBase< Rcpp::traits::r_sexptype_traits::type x ; + typename Rcpp::traits::sugar_operand< T2 >::type y ; }; @@ -50,8 +51,9 @@ template class SugarBlock_2__VP : public Rcpp::VectorBase< Rcpp::traits::r_sexptype_traits::rtype , NA, SugarBlock_2__VP > { public: typedef RESULT_TYPE (*FunPtr)(U1,U2) ; + typedef Rcpp::traits::elementwise_operands< T1 > rcpp_elementwise ; SugarBlock_2__VP( FunPtr ptr_, const T1 & x_, U2 u2 ) : - ptr(ptr_), x(x_), y(u2){} + ptr(ptr_), x(x_.get_ref()), y(u2){} inline RESULT_TYPE operator[]( R_xlen_t i) const { return ptr( x[i], y ) ; @@ -60,7 +62,7 @@ class SugarBlock_2__VP : public Rcpp::VectorBase< Rcpp::traits::r_sexptype_trait private: FunPtr ptr ; - const T1& x ; + typename Rcpp::traits::sugar_operand< T1 >::type x ; U2 y ; }; @@ -68,8 +70,9 @@ template class SugarBlock_2__PV : public Rcpp::VectorBase< Rcpp::traits::r_sexptype_traits::rtype , NA, SugarBlock_2__PV > { public: typedef RESULT_TYPE (*FunPtr)(U1,U2) ; + typedef Rcpp::traits::elementwise_operands< T2 > rcpp_elementwise ; SugarBlock_2__PV( FunPtr ptr_, U1 u1, const T2& y_ ) : - ptr(ptr_), x(u1), y(y_){} + ptr(ptr_), x(u1), y(y_.get_ref()){} inline RESULT_TYPE operator[]( R_xlen_t i) const { return ptr( x, y[i] ) ; @@ -79,7 +82,7 @@ class SugarBlock_2__PV : public Rcpp::VectorBase< Rcpp::traits::r_sexptype_trait private: FunPtr ptr ; U1 x ; - const T2& y ; + typename Rcpp::traits::sugar_operand< T2 >::type y ; }; diff --git a/inst/include/Rcpp/sugar/block/SugarBlock_3.h b/inst/include/Rcpp/sugar/block/SugarBlock_3.h index a12e4dbfd..4e90a454d 100644 --- a/inst/include/Rcpp/sugar/block/SugarBlock_3.h +++ b/inst/include/Rcpp/sugar/block/SugarBlock_3.h @@ -37,9 +37,10 @@ class SugarBlock_3_VVV : public Rcpp::VectorBase< SugarBlock_3_VVV > { public: typedef RESULT_TYPE (*FunPtr)(U1,U2,U3) ; + typedef Rcpp::traits::elementwise_operands< T1, T2, T3 > rcpp_elementwise ; SugarBlock_3_VVV( FunPtr ptr_, const T1 & x_, const T2& y_, const T3& z_ ) : - ptr(ptr_), x(x_), y(y_), z(z_) { - // TODO: size checks, recycling, etc ... + ptr(ptr_), x(x_.get_ref()), y(y_.get_ref()), z(z_.get_ref()) { + check_sizes(x.size(), y.size(), z.size()) ; } inline RESULT_TYPE operator[]( R_xlen_t i) const { return ptr( x[i], y[i], z[i] ) ; @@ -48,9 +49,9 @@ class SugarBlock_3_VVV : public Rcpp::VectorBase< private: FunPtr ptr ; - const T1& x ; - const T2& y ; - const T2& z ; + typename Rcpp::traits::sugar_operand< T1 >::type x ; + typename Rcpp::traits::sugar_operand< T2 >::type y ; + typename Rcpp::traits::sugar_operand< T3 >::type z ; }; diff --git a/inst/include/Rcpp/sugar/block/SugarMath.h b/inst/include/Rcpp/sugar/block/SugarMath.h index 624f2c569..f38208cfd 100644 --- a/inst/include/Rcpp/sugar/block/SugarMath.h +++ b/inst/include/Rcpp/sugar/block/SugarMath.h @@ -34,8 +34,9 @@ class SugarMath_1 : public Rcpp::VectorBase< public: typedef Rcpp::VectorBase< Rcpp::traits::r_sexptype_traits::rtype ,NA,T1> VEC_TYPE ; + typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ; - SugarMath_1( FunPtr ptr_, const VEC_TYPE & vec_) : ptr(ptr_), vec(vec_){} + SugarMath_1( FunPtr ptr_, const VEC_TYPE & vec_) : ptr(ptr_), vec(vec_.get_ref()){} inline RESULT_TYPE operator[]( R_xlen_t i) const { U1 x = vec[i] ; @@ -46,7 +47,7 @@ class SugarMath_1 : public Rcpp::VectorBase< private: FunPtr ptr ; - const VEC_TYPE& vec ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec ; }; template @@ -57,8 +58,9 @@ class SugarMath_1 : public Rcpp::VectorBase< > { public: typedef Rcpp::VectorBase< INTSXP ,NA,T1> VEC_TYPE ; + typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ; - SugarMath_1( FunPtr ptr_, const VEC_TYPE & vec_) : ptr(ptr_), vec(vec_){} + SugarMath_1( FunPtr ptr_, const VEC_TYPE & vec_) : ptr(ptr_), vec(vec_.get_ref()){} inline RESULT_TYPE operator[]( R_xlen_t i) const { int x = vec[i] ; @@ -69,7 +71,7 @@ class SugarMath_1 : public Rcpp::VectorBase< private: FunPtr ptr ; - const VEC_TYPE& vec ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec ; }; template @@ -81,7 +83,8 @@ Rcpp::VectorBase< > { public: typedef Rcpp::VectorBase< INTSXP ,false,T1> VEC_TYPE ; - SugarMath_1( FunPtr ptr_, const VEC_TYPE & vec_) : ptr(ptr_), vec(vec_){} + typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ; + SugarMath_1( FunPtr ptr_, const VEC_TYPE & vec_) : ptr(ptr_), vec(vec_.get_ref()){} inline RESULT_TYPE operator[]( R_xlen_t i) const { return ptr( vec[i] ) ; @@ -90,7 +93,7 @@ Rcpp::VectorBase< private: FunPtr ptr ; - const VEC_TYPE& vec ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec ; }; diff --git a/inst/include/Rcpp/sugar/block/Vectorized_Math.h b/inst/include/Rcpp/sugar/block/Vectorized_Math.h index eb37acd4c..314aa08c4 100644 --- a/inst/include/Rcpp/sugar/block/Vectorized_Math.h +++ b/inst/include/Rcpp/sugar/block/Vectorized_Math.h @@ -32,6 +32,7 @@ class Vectorized : public VectorBase >{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::Extractor::type VEC_EXT ; + typedef Rcpp::traits::elementwise_operands< VEC_EXT > rcpp_elementwise ; Vectorized( const VEC_TYPE& object_) : object( object_.get_ref() ){} inline double operator[]( R_xlen_t i) const { @@ -40,7 +41,7 @@ class Vectorized : public VectorBase >{ inline R_xlen_t size() const { return object.size(); } private: - const VEC_EXT& object ; + typename Rcpp::traits::sugar_operand< VEC_EXT >::type object ; } ; template @@ -48,6 +49,7 @@ class Vectorized_INTSXP : public VectorBase VEC_TYPE ; typedef typename Rcpp::traits::Extractor::type VEC_EXT ; + typedef Rcpp::traits::elementwise_operands< VEC_EXT > rcpp_elementwise ; Vectorized_INTSXP( const VEC_TYPE& object_) : object( object_.get_ref() ){} inline double operator[]( R_xlen_t i) const { @@ -58,7 +60,7 @@ class Vectorized_INTSXP : public VectorBase::type object ; } ; template class Vectorized_INTSXP : @@ -66,6 +68,7 @@ class Vectorized_INTSXP : public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::Extractor::type VEC_EXT ; + typedef Rcpp::traits::elementwise_operands< VEC_EXT > rcpp_elementwise ; Vectorized_INTSXP( const VEC_TYPE& object_) : object( object_.get_ref() ){} inline double operator[]( R_xlen_t i) const { @@ -74,7 +77,7 @@ class Vectorized_INTSXP : inline R_xlen_t size() const { return object.size(); } private: - const VEC_EXT& object ; + typename Rcpp::traits::sugar_operand< VEC_EXT >::type object ; } ; } // sugar diff --git a/inst/include/Rcpp/sugar/functions/all.h b/inst/include/Rcpp/sugar/functions/all.h index 9a6ffc469..4d61d624d 100644 --- a/inst/include/Rcpp/sugar/functions/all.h +++ b/inst/include/Rcpp/sugar/functions/all.h @@ -30,7 +30,7 @@ class All : public SingleLogicalResult< true, All >{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef SingleLogicalResult< true, All > PARENT ; - All( const VEC_TYPE& t ) : PARENT() , object(t) {} + All( const VEC_TYPE& t ) : PARENT() , object(t.get_ref()) {} void apply(){ R_xlen_t n = object.size() ; @@ -51,7 +51,7 @@ class All : public SingleLogicalResult< true, All >{ } } private: - const VEC_TYPE& object ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type object ; } ; @@ -61,7 +61,7 @@ class All : public SingleLogicalResult< false, All >{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef SingleLogicalResult< false, All > PARENT ; - All( const VEC_TYPE& t ) : PARENT() , object(t) {} + All( const VEC_TYPE& t ) : PARENT() , object(t.get_ref()) {} void apply(){ R_xlen_t n = object.size() ; @@ -74,7 +74,7 @@ class All : public SingleLogicalResult< false, All >{ } } private: - const VEC_TYPE& object ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type object ; } ; diff --git a/inst/include/Rcpp/sugar/functions/any.h b/inst/include/Rcpp/sugar/functions/any.h index dc242af5f..5f8fdcd01 100644 --- a/inst/include/Rcpp/sugar/functions/any.h +++ b/inst/include/Rcpp/sugar/functions/any.h @@ -30,7 +30,7 @@ class Any : public SingleLogicalResult< true, Any >{ public: typedef Rcpp::VectorBase VEC_TYPE ; typedef SingleLogicalResult< true , Any > PARENT ; - Any( const VEC_TYPE& t ) : PARENT() , object(t) {} + Any( const VEC_TYPE& t ) : PARENT() , object(t.get_ref()) {} void apply(){ R_xlen_t n = object.size() ; @@ -51,7 +51,7 @@ class Any : public SingleLogicalResult< true, Any >{ } } private: - const VEC_TYPE& object ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type object ; } ; template @@ -59,7 +59,7 @@ class Any : public SingleLogicalResult< false, Any >{ public: typedef Rcpp::VectorBase VEC_TYPE ; typedef SingleLogicalResult< false , Any > PARENT ; - Any( const VEC_TYPE& t ) : PARENT() , object(t) {} + Any( const VEC_TYPE& t ) : PARENT() , object(t.get_ref()) {} void apply(){ R_xlen_t n = object.size() ; @@ -72,7 +72,7 @@ class Any : public SingleLogicalResult< false, Any >{ } } private: - const VEC_TYPE& object ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type object ; } ; } // sugar diff --git a/inst/include/Rcpp/sugar/functions/clamp.h b/inst/include/Rcpp/sugar/functions/clamp.h index 496df2e78..2950b6235 100644 --- a/inst/include/Rcpp/sugar/functions/clamp.h +++ b/inst/include/Rcpp/sugar/functions/clamp.h @@ -62,6 +62,7 @@ class Clamp_Primitive_Vector_Primitive : public VectorBase< public: typedef typename Rcpp::traits::storage_type::type STORAGE ; typedef clamp_operator OPERATOR ; + typedef Rcpp::traits::elementwise_operands< T > rcpp_elementwise ; Clamp_Primitive_Vector_Primitive( STORAGE lhs_, const T& vec_, STORAGE rhs_) : vec(vec_), op(lhs_,rhs_) {} @@ -71,7 +72,7 @@ class Clamp_Primitive_Vector_Primitive : public VectorBase< inline R_xlen_t size() const { return vec.size() ; } private: - const T& vec ; + typename Rcpp::traits::sugar_operand< T >::type vec ; OPERATOR op ; } ; diff --git a/inst/include/Rcpp/sugar/functions/complex.h b/inst/include/Rcpp/sugar/functions/complex.h index 800c856fb..6ad60ca2e 100644 --- a/inst/include/Rcpp/sugar/functions/complex.h +++ b/inst/include/Rcpp/sugar/functions/complex.h @@ -35,8 +35,9 @@ class SugarComplex : public Rcpp::VectorBase< public: typedef Rcpp::VectorBase VEC_TYPE ; + typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ; - SugarComplex( FunPtr ptr_, const VEC_TYPE & vec_) : ptr(ptr_), vec(vec_){} + SugarComplex( FunPtr ptr_, const VEC_TYPE & vec_) : ptr(ptr_), vec(vec_.get_ref()){} inline RESULT_TYPE operator[]( R_xlen_t i) const { Rcomplex x = vec[i] ; @@ -48,7 +49,7 @@ class SugarComplex : public Rcpp::VectorBase< private: FunPtr ptr ; - const VEC_TYPE& vec ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec ; }; } // sugar diff --git a/inst/include/Rcpp/sugar/functions/cummax.h b/inst/include/Rcpp/sugar/functions/cummax.h index 327dac60c..7695d7c06 100644 --- a/inst/include/Rcpp/sugar/functions/cummax.h +++ b/inst/include/Rcpp/sugar/functions/cummax.h @@ -32,7 +32,7 @@ class Cummax : public Lazy< Rcpp::Vector, Cummax > { typedef typename Rcpp::traits::storage_type::type STORAGE; typedef Rcpp::Vector VECTOR; - Cummax(const VEC_TYPE& object_) : object(object_) {} + Cummax(const VEC_TYPE& object_) : object(object_.get_ref()) {} VECTOR get() const { R_xlen_t n = object.size(); @@ -49,7 +49,7 @@ class Cummax : public Lazy< Rcpp::Vector, Cummax > { return result ; } private: - const VEC_TYPE& object; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type object; }; } // sugar diff --git a/inst/include/Rcpp/sugar/functions/cummin.h b/inst/include/Rcpp/sugar/functions/cummin.h index c4c864e0f..212a23afb 100644 --- a/inst/include/Rcpp/sugar/functions/cummin.h +++ b/inst/include/Rcpp/sugar/functions/cummin.h @@ -32,7 +32,7 @@ class Cummin : public Lazy< Rcpp::Vector, Cummin > { typedef typename Rcpp::traits::storage_type::type STORAGE; typedef Rcpp::Vector VECTOR; - Cummin(const VEC_TYPE& object_) : object(object_) {} + Cummin(const VEC_TYPE& object_) : object(object_.get_ref()) {} VECTOR get() const { R_xlen_t n = object.size(); @@ -49,7 +49,7 @@ class Cummin : public Lazy< Rcpp::Vector, Cummin > { return result ; } private: - const VEC_TYPE& object; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type object; }; } // sugar diff --git a/inst/include/Rcpp/sugar/functions/cumprod.h b/inst/include/Rcpp/sugar/functions/cumprod.h index 0ad8936fd..b09152624 100644 --- a/inst/include/Rcpp/sugar/functions/cumprod.h +++ b/inst/include/Rcpp/sugar/functions/cumprod.h @@ -33,7 +33,7 @@ class Cumprod : public Lazy< Rcpp::Vector, Cumprod > { typedef typename Rcpp::traits::storage_type::type STORAGE; typedef Rcpp::Vector VECTOR; - Cumprod(const VEC_TYPE& object_) : object(object_) {} + Cumprod(const VEC_TYPE& object_) : object(object_.get_ref()) {} VECTOR get() const { R_xlen_t n = object.size(); @@ -50,7 +50,7 @@ class Cumprod : public Lazy< Rcpp::Vector, Cumprod > { return result ; } private: - const VEC_TYPE& object; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type object; }; } // sugar diff --git a/inst/include/Rcpp/sugar/functions/cumsum.h b/inst/include/Rcpp/sugar/functions/cumsum.h index cb8e53886..f07801e5e 100644 --- a/inst/include/Rcpp/sugar/functions/cumsum.h +++ b/inst/include/Rcpp/sugar/functions/cumsum.h @@ -33,7 +33,7 @@ class Cumsum : public Lazy< Rcpp::Vector , Cumsum > { typedef typename Rcpp::traits::storage_type::type STORAGE ; typedef Rcpp::Vector VECTOR ; - Cumsum( const VEC_TYPE& object_ ) : object(object_){} + Cumsum( const VEC_TYPE& object_ ) : object(object_.get_ref()){} VECTOR get() const { R_xlen_t n = object.size() ; @@ -51,7 +51,7 @@ class Cumsum : public Lazy< Rcpp::Vector , Cumsum > { return result ; } private: - const VEC_TYPE& object ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type object ; } ; } // sugar diff --git a/inst/include/Rcpp/sugar/functions/diff.h b/inst/include/Rcpp/sugar/functions/diff.h index b6c43f3fd..add08741d 100644 --- a/inst/include/Rcpp/sugar/functions/diff.h +++ b/inst/include/Rcpp/sugar/functions/diff.h @@ -36,7 +36,7 @@ class Diff : public Rcpp::VectorBase< RTYPE, LHS_NA , Diff > typedef typename Rcpp::traits::storage_type::type STORAGE ; Diff( const LHS_TYPE& lhs_ ) : - lhs(lhs_), + lhs(lhs_.get_ref()), previous(lhs_[0]), previous_index(0), was_na(traits::is_na(previous)) @@ -66,7 +66,7 @@ class Diff : public Rcpp::VectorBase< RTYPE, LHS_NA , Diff > inline R_xlen_t size() const { return lhs.size() - 1 ; } private: - const LHS_TYPE& lhs ; + typename Rcpp::traits::sugar_operand< LHS_TYPE >::type lhs ; mutable STORAGE previous ; mutable R_xlen_t previous_index ; mutable bool was_na ; @@ -77,7 +77,7 @@ class Diff : public Rcpp::VectorBase< REALSXP, LHS_NA, D public: typedef typename Rcpp::VectorBase LHS_TYPE ; - Diff( const LHS_TYPE& lhs_ ) : lhs(lhs_), previous(lhs_[0]), previous_index(0) {} + Diff( const LHS_TYPE& lhs_ ) : lhs(lhs_.get_ref()), previous(lhs_[0]), previous_index(0) {} inline double operator[]( R_xlen_t i ) const { double y = lhs[i+1] ; @@ -90,7 +90,7 @@ class Diff : public Rcpp::VectorBase< REALSXP, LHS_NA, D inline R_xlen_t size() const { return lhs.size() - 1 ; } private: - const LHS_TYPE& lhs ; + typename Rcpp::traits::sugar_operand< LHS_TYPE >::type lhs ; mutable double previous ; mutable R_xlen_t previous_index ; } ; @@ -101,7 +101,7 @@ class Diff : public Rcpp::VectorBase< RTYPE, false , Diff LHS_TYPE ; typedef typename Rcpp::traits::storage_type::type STORAGE ; - Diff( const LHS_TYPE& lhs_ ) : lhs(lhs_), previous(lhs[0]), previous_index(0) {} + Diff( const LHS_TYPE& lhs_ ) : lhs(lhs_.get_ref()), previous(lhs[0]), previous_index(0) {} inline STORAGE operator[]( R_xlen_t i ) const { STORAGE y = lhs[i+1] ; @@ -114,7 +114,7 @@ class Diff : public Rcpp::VectorBase< RTYPE, false , Diff::type lhs ; mutable STORAGE previous ; mutable R_xlen_t previous_index ; } ; diff --git a/inst/include/Rcpp/sugar/functions/head.h b/inst/include/Rcpp/sugar/functions/head.h index 32fa7a3ec..364ecdc65 100644 --- a/inst/include/Rcpp/sugar/functions/head.h +++ b/inst/include/Rcpp/sugar/functions/head.h @@ -32,7 +32,7 @@ class Head : public Rcpp::VectorBase< RTYPE ,NA, Head > { typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::storage_type::type STORAGE ; - Head( const VEC_TYPE& object_, R_xlen_t n_ ) : object(object_), n(n_) { + Head( const VEC_TYPE& object_, R_xlen_t n_ ) : object(object_.get_ref()), n(n_) { if( n < 0 ){ n = object.size() + n ; } @@ -44,7 +44,7 @@ class Head : public Rcpp::VectorBase< RTYPE ,NA, Head > { inline R_xlen_t size() const { return n; } private: - const VEC_TYPE& object ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type object ; R_xlen_t n ; } ; diff --git a/inst/include/Rcpp/sugar/functions/ifelse.h b/inst/include/Rcpp/sugar/functions/ifelse.h index 1b58d2f41..0a0f91803 100644 --- a/inst/include/Rcpp/sugar/functions/ifelse.h +++ b/inst/include/Rcpp/sugar/functions/ifelse.h @@ -41,13 +41,14 @@ class IfElse : public VectorBase< typedef Rcpp::VectorBase LHS_TYPE ; typedef Rcpp::VectorBase RHS_TYPE ; typedef typename traits::storage_type::type STORAGE ; + typedef Rcpp::traits::elementwise_operands< COND_TYPE, LHS_T, RHS_T > rcpp_elementwise ; // typedef typename Rcpp::traits::Extractor::type LHS_EXT ; // typedef typename Rcpp::traits::Extractor::type RHS_EXT ; IfElse( const COND_TYPE& cond_, const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - cond(cond_), lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) { - /* FIXME : cond, lhs and rhs must all have the same size */ + cond(cond_.get_ref()), lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) { + check_sizes(cond.size(), lhs.size(), rhs.size()) ; RCPP_DEBUG( DEMANGLE(IfElse) ) ; } @@ -62,9 +63,9 @@ class IfElse : public VectorBase< inline R_xlen_t size() const { return cond.size() ; } private: - const COND_TYPE& cond ; - const LHS_T& lhs ; - const RHS_T& rhs ; + typename Rcpp::traits::sugar_operand< COND_TYPE >::type cond ; + typename Rcpp::traits::sugar_operand< LHS_T >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_T >::type rhs ; } ; @@ -87,10 +88,11 @@ class IfElse : public VectorBase< typedef typename Rcpp::traits::Extractor::type LHS_EXT ; typedef typename Rcpp::traits::Extractor::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< COND_TYPE, LHS_EXT, RHS_EXT > rcpp_elementwise ; IfElse( const COND_TYPE& cond_, const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - cond(cond_), lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) { - /* FIXME : cond, lhs and rhs must all have the same size */ + cond(cond_.get_ref()), lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) { + check_sizes(cond.size(), lhs.size(), rhs.size()) ; } inline STORAGE operator[]( R_xlen_t i ) const { @@ -102,9 +104,9 @@ class IfElse : public VectorBase< private: - const COND_TYPE& cond ; - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< COND_TYPE >::type cond ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; @@ -127,10 +129,11 @@ class IfElse_Primitive_Vector : public VectorBase< typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::traits::Extractor::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< COND_TYPE, RHS_EXT > rcpp_elementwise ; IfElse_Primitive_Vector( const COND_TYPE& cond_, STORAGE lhs_, const RHS_TYPE& rhs_ ) : - cond(cond_), lhs(lhs_), rhs(rhs_.get_ref()) { - /* FIXME : cond, lhs and rhs must all have the sale size */ + cond(cond_.get_ref()), lhs(lhs_), rhs(rhs_.get_ref()) { + check_sizes(cond.size(), rhs.size()) ; } inline STORAGE operator[]( R_xlen_t i ) const { @@ -143,9 +146,9 @@ class IfElse_Primitive_Vector : public VectorBase< inline R_xlen_t size() const { return cond.size() ; } private: - const COND_TYPE& cond ; + typename Rcpp::traits::sugar_operand< COND_TYPE >::type cond ; STORAGE lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; @@ -164,10 +167,11 @@ class IfElse_Primitive_Vector : public VectorBa typedef Rcpp::VectorBase RHS_TYPE ; typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::traits::Extractor::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< COND_TYPE, RHS_EXT > rcpp_elementwise ; IfElse_Primitive_Vector( const COND_TYPE& cond_, STORAGE lhs_, const RHS_TYPE& rhs_ ) : - cond(cond_), lhs(lhs_), rhs(rhs_.get_ref()) { - /* FIXME : cond, lhs and rhs must all have the same size */ + cond(cond_.get_ref()), lhs(lhs_), rhs(rhs_.get_ref()) { + check_sizes(cond.size(), rhs.size()) ; } inline STORAGE operator[]( R_xlen_t i ) const { @@ -178,9 +182,9 @@ class IfElse_Primitive_Vector : public VectorBa inline R_xlen_t size() const { return cond.size() ; } private: - const COND_TYPE& cond ; + typename Rcpp::traits::sugar_operand< COND_TYPE >::type cond ; STORAGE lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; @@ -203,10 +207,11 @@ class IfElse_Vector_Primitive : public VectorBase< typedef Rcpp::VectorBase LHS_TYPE ; typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::traits::Extractor::type LHS_EXT ; + typedef Rcpp::traits::elementwise_operands< COND_TYPE, LHS_EXT > rcpp_elementwise ; IfElse_Vector_Primitive( const COND_TYPE& cond_, const LHS_TYPE& lhs_, STORAGE rhs_ ) : - cond(cond_), lhs(lhs_.get_ref()), rhs(rhs_) { - /* FIXME : cond, lhs and rhs must all have the same size */ + cond(cond_.get_ref()), lhs(lhs_.get_ref()), rhs(rhs_) { + check_sizes(cond.size(), lhs.size()) ; } inline STORAGE operator[]( R_xlen_t i ) const { @@ -219,8 +224,8 @@ class IfElse_Vector_Primitive : public VectorBase< inline R_xlen_t size() const { return cond.size() ; } private: - const COND_TYPE& cond ; - const LHS_EXT& lhs ; + typename Rcpp::traits::sugar_operand< COND_TYPE >::type cond ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; const STORAGE rhs ; } ; @@ -240,10 +245,11 @@ class IfElse_Vector_Primitive : public VectorBa typedef Rcpp::VectorBase LHS_TYPE ; typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::traits::Extractor::type LHS_EXT ; + typedef Rcpp::traits::elementwise_operands< COND_TYPE, LHS_EXT > rcpp_elementwise ; IfElse_Vector_Primitive( const COND_TYPE& cond_, const LHS_TYPE& lhs_, STORAGE rhs_ ) : - cond(cond_), lhs(lhs_.get_ref()), rhs(rhs_) { - /* FIXME : cond, lhs and rhs must all have the sale size */ + cond(cond_.get_ref()), lhs(lhs_.get_ref()), rhs(rhs_) { + check_sizes(cond.size(), lhs.size()) ; } inline STORAGE operator[]( R_xlen_t i ) const { @@ -254,8 +260,8 @@ class IfElse_Vector_Primitive : public VectorBa inline R_xlen_t size() const { return cond.size() ; } private: - const COND_TYPE& cond ; - const LHS_EXT& lhs ; + typename Rcpp::traits::sugar_operand< COND_TYPE >::type cond ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; const STORAGE rhs ; } ; @@ -278,11 +284,10 @@ class IfElse_Primitive_Primitive : public VectorBase< public: typedef Rcpp::VectorBase COND_TYPE ; typedef typename traits::storage_type::type STORAGE ; + typedef Rcpp::traits::elementwise_operands< COND_TYPE > rcpp_elementwise ; IfElse_Primitive_Primitive( const COND_TYPE& cond_, STORAGE lhs_, STORAGE rhs_ ) : - cond(cond_), lhs(lhs_), rhs(rhs_) { - /* FIXME : cond, lhs and rhs must all have the same size */ - } + cond(cond_.get_ref()), lhs(lhs_), rhs(rhs_) {} inline STORAGE operator[]( R_xlen_t i ) const { int x = cond[i] ; @@ -293,7 +298,7 @@ class IfElse_Primitive_Primitive : public VectorBase< inline R_xlen_t size() const { return cond.size() ; } private: - const COND_TYPE& cond ; + typename Rcpp::traits::sugar_operand< COND_TYPE >::type cond ; STORAGE lhs ; STORAGE rhs ; STORAGE na ; @@ -311,11 +316,10 @@ class IfElse_Primitive_Primitive : public VectorBase< public: typedef Rcpp::VectorBase COND_TYPE ; typedef typename traits::storage_type::type STORAGE ; + typedef Rcpp::traits::elementwise_operands< COND_TYPE > rcpp_elementwise ; IfElse_Primitive_Primitive( const COND_TYPE& cond_, STORAGE lhs_, STORAGE rhs_ ) : - cond(cond_), lhs(lhs_), rhs(rhs_) { - /* FIXME : cond, lhs and rhs must all have the same size */ - } + cond(cond_.get_ref()), lhs(lhs_), rhs(rhs_) {} inline STORAGE operator[]( R_xlen_t i ) const { return cond[i] ? lhs : rhs ; @@ -324,7 +328,7 @@ class IfElse_Primitive_Primitive : public VectorBase< inline R_xlen_t size() const { return cond.size() ; } private: - const COND_TYPE& cond ; + typename Rcpp::traits::sugar_operand< COND_TYPE >::type cond ; STORAGE lhs ; STORAGE rhs ; diff --git a/inst/include/Rcpp/sugar/functions/is_finite.h b/inst/include/Rcpp/sugar/functions/is_finite.h index 1fc68191b..589ff629c 100644 --- a/inst/include/Rcpp/sugar/functions/is_finite.h +++ b/inst/include/Rcpp/sugar/functions/is_finite.h @@ -29,6 +29,8 @@ template class IsFinite : public ::Rcpp::VectorBase< LGLSXP, false, IsFinite > { public: + typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ; + IsFinite( const VEC_TYPE& obj_) : obj(obj_){} inline int operator[]( R_xlen_t i ) const { @@ -38,7 +40,7 @@ class IsFinite : public ::Rcpp::VectorBase< LGLSXP, false, IsFinite::type obj ; } ; diff --git a/inst/include/Rcpp/sugar/functions/is_infinite.h b/inst/include/Rcpp/sugar/functions/is_infinite.h index 6806683dc..846645b34 100644 --- a/inst/include/Rcpp/sugar/functions/is_infinite.h +++ b/inst/include/Rcpp/sugar/functions/is_infinite.h @@ -29,6 +29,8 @@ template class IsInfinite : public ::Rcpp::VectorBase< LGLSXP, false, IsInfinite > { public: + typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ; + IsInfinite( const VEC_TYPE& obj_) : obj(obj_){} inline int operator[]( R_xlen_t i ) const { @@ -38,7 +40,7 @@ class IsInfinite : public ::Rcpp::VectorBase< LGLSXP, false, IsInfinite::type obj ; } ; diff --git a/inst/include/Rcpp/sugar/functions/is_na.h b/inst/include/Rcpp/sugar/functions/is_na.h index 01570e9bc..ecbfb6fc9 100644 --- a/inst/include/Rcpp/sugar/functions/is_na.h +++ b/inst/include/Rcpp/sugar/functions/is_na.h @@ -31,8 +31,9 @@ class IsNa : public ::Rcpp::VectorBase< LGLSXP, false, IsNa > public: typedef typename traits::storage_type::type STORAGE ; typedef Rcpp::VectorBase BASE ; + typedef Rcpp::traits::elementwise_operands< BASE > rcpp_elementwise ; - IsNa( const BASE& obj_) : obj(obj_){} + IsNa( const BASE& obj_) : obj(obj_.get_ref()){} inline int operator[]( R_xlen_t i ) const { return ::Rcpp::traits::is_na( obj[i] ) ; @@ -41,7 +42,7 @@ class IsNa : public ::Rcpp::VectorBase< LGLSXP, false, IsNa > inline R_xlen_t size() const { return obj.size() ; } private: - const BASE& obj ; + typename Rcpp::traits::sugar_operand< BASE >::type obj ; } ; @@ -53,8 +54,9 @@ class IsNa : public ::Rcpp::VectorBase< LGLSXP, false, IsN public: typedef typename traits::storage_type::type STORAGE ; typedef Rcpp::VectorBase BASE ; + typedef Rcpp::traits::elementwise_operands< BASE > rcpp_elementwise ; - IsNa( const BASE& obj_) : obj(obj_){} + IsNa( const BASE& obj_) : obj(obj_.get_ref()){} inline int operator[]( R_xlen_t /*i*/ ) const { return FALSE ; @@ -63,7 +65,7 @@ class IsNa : public ::Rcpp::VectorBase< LGLSXP, false, IsN inline R_xlen_t size() const { return obj.size() ; } private: - const BASE& obj ; + typename Rcpp::traits::sugar_operand< BASE >::type obj ; } ; diff --git a/inst/include/Rcpp/sugar/functions/is_nan.h b/inst/include/Rcpp/sugar/functions/is_nan.h index 686fc0dcb..492970797 100644 --- a/inst/include/Rcpp/sugar/functions/is_nan.h +++ b/inst/include/Rcpp/sugar/functions/is_nan.h @@ -29,6 +29,8 @@ template class IsNaN : public ::Rcpp::VectorBase< LGLSXP, false, IsNaN > { public: + typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ; + IsNaN( const VEC_TYPE& obj_) : obj(obj_){} inline int operator[]( R_xlen_t i ) const { @@ -38,7 +40,7 @@ class IsNaN : public ::Rcpp::VectorBase< LGLSXP, false, IsNaN inline R_xlen_t size() const { return obj.size() ; } private: - const VEC_TYPE& obj ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type obj ; } ; diff --git a/inst/include/Rcpp/sugar/functions/lapply.h b/inst/include/Rcpp/sugar/functions/lapply.h index 7d098010e..21cd7ef3a 100644 --- a/inst/include/Rcpp/sugar/functions/lapply.h +++ b/inst/include/Rcpp/sugar/functions/lapply.h @@ -37,7 +37,7 @@ class Lapply : public VectorBase< typedef typename ::Rcpp::traits::result_of::type result_type ; Lapply( const VEC& vec_, Function fun_ ) : - vec(vec_), fun(fun_){} + vec(vec_.get_ref()), fun(fun_){} inline SEXP operator[]( R_xlen_t i ) const { return Rcpp::wrap( fun( vec[i] ) ); @@ -45,7 +45,7 @@ class Lapply : public VectorBase< inline R_xlen_t size() const { return vec.size() ; } private: - const VEC& vec ; + typename Rcpp::traits::sugar_operand< VEC >::type vec ; Function fun ; } ; diff --git a/inst/include/Rcpp/sugar/functions/mapply/mapply_2.h b/inst/include/Rcpp/sugar/functions/mapply/mapply_2.h index 8185f6220..b8048f621 100644 --- a/inst/include/Rcpp/sugar/functions/mapply/mapply_2.h +++ b/inst/include/Rcpp/sugar/functions/mapply/mapply_2.h @@ -42,7 +42,9 @@ class Mapply_2 : public VectorBase< typedef typename ::Rcpp::traits::result_of::type result_type ; Mapply_2( const T_1& vec_1_, const T_2& vec_2_, Function fun_ ) : - vec_1(vec_1_), vec_2(vec_2_), fun(fun_){} + vec_1(vec_1_), vec_2(vec_2_), fun(fun_){ + check_sizes(vec_1.size(), vec_2.size()) ; + } inline result_type operator[]( R_xlen_t i ) const { return fun( vec_1[i], vec_2[i] ); @@ -50,8 +52,8 @@ class Mapply_2 : public VectorBase< inline R_xlen_t size() const { return vec_1.size() ; } private: - const T_1& vec_1 ; - const T_2& vec_2 ; + typename Rcpp::traits::sugar_operand< T_1 >::type vec_1 ; + typename Rcpp::traits::sugar_operand< T_2 >::type vec_2 ; Function fun ; } ; @@ -81,7 +83,7 @@ class Mapply_2_Vector_Primitive : public inline R_xlen_t size() const { return vec_1.size() ; } private: - const T_1& vec_1 ; + typename Rcpp::traits::sugar_operand< T_1 >::type vec_1 ; PRIM_2 prim_2 ; Function fun ; } ; @@ -113,7 +115,7 @@ class Mapply_2_Primitive_Vector : public private: PRIM_1 prim_1 ; - const T_2& vec_2 ; + typename Rcpp::traits::sugar_operand< T_2 >::type vec_2 ; Function fun ; } ; diff --git a/inst/include/Rcpp/sugar/functions/mapply/mapply_3.h b/inst/include/Rcpp/sugar/functions/mapply/mapply_3.h index e009b9142..b03fbe0d8 100644 --- a/inst/include/Rcpp/sugar/functions/mapply/mapply_3.h +++ b/inst/include/Rcpp/sugar/functions/mapply/mapply_3.h @@ -51,7 +51,9 @@ class Mapply_3 : public VectorBase< typedef typename Rcpp::traits::Extractor::type EXT_3 ; Mapply_3( const VEC_1& vec_1_, const VEC_2& vec_2_, const VEC_3& vec_3_, Function fun_ ) : - vec_1(vec_1_.get_ref()), vec_2(vec_2_.get_ref()), vec_3(vec_3_.get_ref()), fun(fun_){} + vec_1(vec_1_.get_ref()), vec_2(vec_2_.get_ref()), vec_3(vec_3_.get_ref()), fun(fun_){ + check_sizes(vec_1.size(), vec_2.size(), vec_3.size()) ; + } inline result_type operator[]( R_xlen_t i ) const { return fun( vec_1[i], vec_2[i], vec_3[i] ); @@ -59,9 +61,9 @@ class Mapply_3 : public VectorBase< inline R_xlen_t size() const { return vec_1.size() ; } private: - const EXT_1& vec_1 ; - const EXT_2& vec_2 ; - const EXT_3& vec_3 ; + typename Rcpp::traits::sugar_operand< EXT_1 >::type vec_1 ; + typename Rcpp::traits::sugar_operand< EXT_2 >::type vec_2 ; + typename Rcpp::traits::sugar_operand< EXT_3 >::type vec_3 ; Function fun ; } ; diff --git a/inst/include/Rcpp/sugar/functions/max.h b/inst/include/Rcpp/sugar/functions/max.h index 7f85b1457..d370d74e8 100644 --- a/inst/include/Rcpp/sugar/functions/max.h +++ b/inst/include/Rcpp/sugar/functions/max.h @@ -52,7 +52,7 @@ namespace sugar{ } private: - const T& obj ; + typename Rcpp::traits::sugar_operand< T >::type obj ; } ; // version for NA = false @@ -81,7 +81,7 @@ namespace sugar{ } private: - const T& obj ; + typename Rcpp::traits::sugar_operand< T >::type obj ; } ; diff --git a/inst/include/Rcpp/sugar/functions/mean.h b/inst/include/Rcpp/sugar/functions/mean.h index 1ffde0d37..87ccef54a 100644 --- a/inst/include/Rcpp/sugar/functions/mean.h +++ b/inst/include/Rcpp/sugar/functions/mean.h @@ -29,7 +29,7 @@ class Mean : public Lazy > { typedef typename Rcpp::VectorBase VEC_TYPE; typedef Rcpp::Vector VECTOR; - Mean(const VEC_TYPE& object_) : object(object_) {} + Mean(const VEC_TYPE& object_) : object(object_.get_ref()) {} double get() const { VECTOR input = object; @@ -46,7 +46,7 @@ class Mean : public Lazy > { return (double)s ; } private: - const VEC_TYPE& object ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type object ; }; template @@ -54,7 +54,7 @@ class Mean : public Lazy > { public: typedef typename Rcpp::VectorBase VEC_TYPE; - Mean(const VEC_TYPE& object_) : object(object_) {} + Mean(const VEC_TYPE& object_) : object(object_.get_ref()) {} Rcomplex get() const { ComplexVector input = object; @@ -83,7 +83,7 @@ class Mean : public Lazy > { return z; } private: - const VEC_TYPE& object ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type object ; }; template @@ -91,7 +91,7 @@ class Mean : public Lazy > { public: typedef typename Rcpp::VectorBase VEC_TYPE; - Mean(const VEC_TYPE& object_) : object(object_) {} + Mean(const VEC_TYPE& object_) : object(object_.get_ref()) {} double get() const { LogicalVector input = object; @@ -105,7 +105,7 @@ class Mean : public Lazy > { return (double)s; } private: - const VEC_TYPE& object ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type object ; }; template @@ -113,7 +113,7 @@ class Mean : public Lazy > { public: typedef typename Rcpp::VectorBase VEC_TYPE; - Mean(const VEC_TYPE& object_) : object(object_) {} + Mean(const VEC_TYPE& object_) : object(object_.get_ref()) {} double get() const { IntegerVector input = object; @@ -129,7 +129,7 @@ class Mean : public Lazy > { return (double)s ; } private: - const VEC_TYPE& object ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type object ; }; } // sugar diff --git a/inst/include/Rcpp/sugar/functions/min.h b/inst/include/Rcpp/sugar/functions/min.h index 0e8b9410e..18bb44543 100644 --- a/inst/include/Rcpp/sugar/functions/min.h +++ b/inst/include/Rcpp/sugar/functions/min.h @@ -52,7 +52,7 @@ namespace sugar{ return min ; } - const T& obj ; + typename Rcpp::traits::sugar_operand< T >::type obj ; } ; // version for NA = false @@ -80,7 +80,7 @@ namespace sugar{ return min ; } - const T& obj ; + typename Rcpp::traits::sugar_operand< T >::type obj ; } ; diff --git a/inst/include/Rcpp/sugar/functions/pmax.h b/inst/include/Rcpp/sugar/functions/pmax.h index a695906de..9c497f4c4 100644 --- a/inst/include/Rcpp/sugar/functions/pmax.h +++ b/inst/include/Rcpp/sugar/functions/pmax.h @@ -104,8 +104,11 @@ class Pmax_Vector_Vector : public VectorBase< public: typedef typename Rcpp::traits::storage_type::type STORAGE ; typedef pmax_op OPERATOR ; + typedef Rcpp::traits::elementwise_operands< LHS_T, RHS_T > rcpp_elementwise ; - Pmax_Vector_Vector( const LHS_T& lhs_, const RHS_T& rhs_ ) : lhs(lhs_), rhs(rhs_), op() {} + Pmax_Vector_Vector( const LHS_T& lhs_, const RHS_T& rhs_ ) : lhs(lhs_), rhs(rhs_), op() { + check_sizes(lhs.size(), rhs.size()) ; + } inline STORAGE operator[]( R_xlen_t i ) const { return op( lhs[i], rhs[i] ) ; @@ -113,8 +116,8 @@ class Pmax_Vector_Vector : public VectorBase< inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_T& lhs ; - const RHS_T& rhs ; + typename Rcpp::traits::sugar_operand< LHS_T >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_T >::type rhs ; OPERATOR op ; } ; @@ -132,6 +135,7 @@ class Pmax_Vector_Primitive : public VectorBase< public: typedef typename Rcpp::traits::storage_type::type STORAGE ; typedef pmax_op_Vector_Primitive OPERATOR ; + typedef Rcpp::traits::elementwise_operands< LHS_T > rcpp_elementwise ; Pmax_Vector_Primitive( const LHS_T& lhs_, STORAGE rhs_ ) : lhs(lhs_), op(rhs_) {} @@ -141,7 +145,7 @@ class Pmax_Vector_Primitive : public VectorBase< inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_T& lhs ; + typename Rcpp::traits::sugar_operand< LHS_T >::type lhs ; OPERATOR op ; } ; diff --git a/inst/include/Rcpp/sugar/functions/pmin.h b/inst/include/Rcpp/sugar/functions/pmin.h index 92cb920a3..b81d64f15 100644 --- a/inst/include/Rcpp/sugar/functions/pmin.h +++ b/inst/include/Rcpp/sugar/functions/pmin.h @@ -104,8 +104,11 @@ class Pmin_Vector_Vector : public VectorBase< public: typedef typename Rcpp::traits::storage_type::type STORAGE ; typedef pmin_op OPERATOR ; + typedef Rcpp::traits::elementwise_operands< LHS_T, RHS_T > rcpp_elementwise ; - Pmin_Vector_Vector( const LHS_T& lhs_, const RHS_T& rhs_ ) : lhs(lhs_), rhs(rhs_), op() {} + Pmin_Vector_Vector( const LHS_T& lhs_, const RHS_T& rhs_ ) : lhs(lhs_), rhs(rhs_), op() { + check_sizes(lhs.size(), rhs.size()) ; + } inline STORAGE operator[]( R_xlen_t i ) const { return op( lhs[i], rhs[i] ) ; @@ -113,8 +116,8 @@ class Pmin_Vector_Vector : public VectorBase< inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_T& lhs ; - const RHS_T& rhs ; + typename Rcpp::traits::sugar_operand< LHS_T >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_T >::type rhs ; OPERATOR op ; } ; @@ -132,6 +135,7 @@ class Pmin_Vector_Primitive : public VectorBase< public: typedef typename Rcpp::traits::storage_type::type STORAGE ; typedef pmin_op_Vector_Primitive OPERATOR ; + typedef Rcpp::traits::elementwise_operands< LHS_T > rcpp_elementwise ; Pmin_Vector_Primitive( const LHS_T& lhs_, STORAGE rhs_ ) : lhs(lhs_), op(rhs_) {} @@ -139,7 +143,7 @@ class Pmin_Vector_Primitive : public VectorBase< inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_T& lhs ; + typename Rcpp::traits::sugar_operand< LHS_T >::type lhs ; OPERATOR op ; } ; diff --git a/inst/include/Rcpp/sugar/functions/pow.h b/inst/include/Rcpp/sugar/functions/pow.h index 79a5c81bf..ad0a573ca 100644 --- a/inst/include/Rcpp/sugar/functions/pow.h +++ b/inst/include/Rcpp/sugar/functions/pow.h @@ -29,6 +29,7 @@ template class Pow : public Rcpp::VectorBase< REALSXP ,NA, Pow > { public: typedef typename Rcpp::traits::storage_type::type STORAGE ; + typedef Rcpp::traits::elementwise_operands< T > rcpp_elementwise ; Pow( const T& object_, EXPONENT_TYPE exponent ) : object(object_), op(exponent) {} @@ -38,13 +39,15 @@ class Pow : public Rcpp::VectorBase< REALSXP ,NA, Pow inline R_xlen_t size() const { return object.size() ; } private: - const T& object ; + typename Rcpp::traits::sugar_operand< T >::type object ; EXPONENT_TYPE op ; } ; template class Pow : public Rcpp::VectorBase< REALSXP ,NA, Pow > { public: + typedef Rcpp::traits::elementwise_operands< T > rcpp_elementwise ; + Pow( const T& object_, EXPONENT_TYPE exponent ) : object(object_), op(exponent) {} inline double operator[]( R_xlen_t i ) const { @@ -54,12 +57,14 @@ class Pow : public Rcpp::VectorBase< REALSXP ,NA, Pow inline R_xlen_t size() const { return object.size() ; } private: - const T& object ; + typename Rcpp::traits::sugar_operand< T >::type object ; EXPONENT_TYPE op ; } ; template class Pow : public Rcpp::VectorBase< REALSXP ,false, Pow > { public: + typedef Rcpp::traits::elementwise_operands< T > rcpp_elementwise ; + Pow( const T& object_, EXPONENT_TYPE exponent ) : object(object_), op(exponent) {} inline double operator[]( R_xlen_t i ) const { @@ -68,7 +73,7 @@ class Pow : public Rcpp::VectorBase< REALSXP ,fals inline R_xlen_t size() const { return object.size() ; } private: - const T& object ; + typename Rcpp::traits::sugar_operand< T >::type object ; EXPONENT_TYPE op ; } ; diff --git a/inst/include/Rcpp/sugar/functions/range.h b/inst/include/Rcpp/sugar/functions/range.h index 50ceb8eee..1474bd3c4 100644 --- a/inst/include/Rcpp/sugar/functions/range.h +++ b/inst/include/Rcpp/sugar/functions/range.h @@ -49,7 +49,7 @@ namespace sugar{ private: - const T& obj ; + typename Rcpp::traits::sugar_operand< T >::type obj ; STORAGE min_, max_, current ; } ; @@ -75,7 +75,7 @@ namespace sugar{ private: - const T& obj ; + typename Rcpp::traits::sugar_operand< T >::type obj ; STORAGE min_, max_, current ; } ; diff --git a/inst/include/Rcpp/sugar/functions/rep.h b/inst/include/Rcpp/sugar/functions/rep.h index 47c1194ca..011fec553 100644 --- a/inst/include/Rcpp/sugar/functions/rep.h +++ b/inst/include/Rcpp/sugar/functions/rep.h @@ -32,7 +32,7 @@ class Rep : public Rcpp::VectorBase< RTYPE ,NA, Rep > { typedef typename Rcpp::traits::storage_type::type STORAGE ; Rep( const VEC_TYPE& object_, R_xlen_t times_ ) : - object(object_), times(times_), n(object_.size()){} + object(object_.get_ref()), times(times_), n(object_.size()){} inline STORAGE operator[]( R_xlen_t i ) const { return object[ i % n ] ; @@ -40,7 +40,7 @@ class Rep : public Rcpp::VectorBase< RTYPE ,NA, Rep > { inline R_xlen_t size() const { return times * n ; } private: - const VEC_TYPE& object ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type object ; R_xlen_t times, n ; } ; @@ -51,6 +51,8 @@ class Rep_Single : public Rcpp::VectorBase< Rep_Single > { public: + typedef Rcpp::traits::elementwise_operands<> rcpp_elementwise ; + Rep_Single( const T& x_, R_xlen_t n_) : x(x_), n(n_){} inline T operator[]( R_xlen_t ) const { @@ -59,7 +61,7 @@ class Rep_Single : public Rcpp::VectorBase< inline R_xlen_t size() const { return n ; } private: - const T& x ; + typename Rcpp::traits::sugar_operand< T >::type x ; R_xlen_t n; } ; diff --git a/inst/include/Rcpp/sugar/functions/rep_each.h b/inst/include/Rcpp/sugar/functions/rep_each.h index a0c0d0744..c6e0b8aad 100644 --- a/inst/include/Rcpp/sugar/functions/rep_each.h +++ b/inst/include/Rcpp/sugar/functions/rep_each.h @@ -32,7 +32,7 @@ class Rep_each : public Rcpp::VectorBase< RTYPE ,NA, Rep_each > { typedef typename Rcpp::traits::storage_type::type STORAGE ; Rep_each( const VEC_TYPE& object_, R_xlen_t times_ ) : - object(object_), times(times_), n(object.size()) {} + object(object_.get_ref()), times(times_), n(object.size()) {} inline STORAGE operator[]( R_xlen_t i ) const { return object[ i / times ] ; @@ -40,7 +40,7 @@ class Rep_each : public Rcpp::VectorBase< RTYPE ,NA, Rep_each > { inline R_xlen_t size() const { return n * times ; } private: - const VEC_TYPE& object ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type object ; R_xlen_t times, n ; } ; diff --git a/inst/include/Rcpp/sugar/functions/rep_len.h b/inst/include/Rcpp/sugar/functions/rep_len.h index 1332a3422..b557d0959 100644 --- a/inst/include/Rcpp/sugar/functions/rep_len.h +++ b/inst/include/Rcpp/sugar/functions/rep_len.h @@ -32,7 +32,7 @@ class Rep_len : public Rcpp::VectorBase< RTYPE ,NA, Rep_len > { typedef typename Rcpp::traits::storage_type::type STORAGE ; Rep_len( const VEC_TYPE& object_, R_xlen_t len_ ) : - object(object_), len(len_), n(object_.size()){} + object(object_.get_ref()), len(len_), n(object_.size()){} inline STORAGE operator[]( R_xlen_t i ) const { return object[ i % n ] ; @@ -40,7 +40,7 @@ class Rep_len : public Rcpp::VectorBase< RTYPE ,NA, Rep_len > { inline R_xlen_t size() const { return len ; } private: - const VEC_TYPE& object ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type object ; R_xlen_t len, n ; } ; diff --git a/inst/include/Rcpp/sugar/functions/rev.h b/inst/include/Rcpp/sugar/functions/rev.h index 59e225659..e1f29a3b4 100644 --- a/inst/include/Rcpp/sugar/functions/rev.h +++ b/inst/include/Rcpp/sugar/functions/rev.h @@ -32,7 +32,7 @@ class Rev : public Rcpp::VectorBase< RTYPE ,NA, Rev > { typedef typename Rcpp::traits::storage_type::type STORAGE ; Rev( const VEC_TYPE& object_ ) : - object(object_), n(object_.size() - 1) {} + object(object_.get_ref()), n(object_.size() - 1) {} inline STORAGE operator[]( R_xlen_t i ) const { return object[n - i] ; @@ -40,7 +40,7 @@ class Rev : public Rcpp::VectorBase< RTYPE ,NA, Rev > { inline R_xlen_t size() const { return n + 1; } private: - const VEC_TYPE& object ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type object ; R_xlen_t n ; } ; diff --git a/inst/include/Rcpp/sugar/functions/rowSums.h b/inst/include/Rcpp/sugar/functions/rowSums.h index 2afcd954b..0a1ae85ce 100644 --- a/inst/include/Rcpp/sugar/functions/rowSums.h +++ b/inst/include/Rcpp/sugar/functions/rowSums.h @@ -108,7 +108,7 @@ template class RowSumsImpl : public Lazy::type, RowSumsImpl > { private: - const MatrixBase& ref; + typename Rcpp::traits::sugar_operand< MatrixBase >::type ref; typedef detail::RowSumsReturn return_traits; typedef typename return_traits::type return_vector; @@ -116,7 +116,7 @@ class RowSumsImpl : public: RowSumsImpl(const MatrixBase& ref_) - : ref(ref_) + : ref(ref_.get_ref()) {} return_vector get() const { @@ -152,7 +152,7 @@ template class RowSumsImpl<__RTYPE__, NA, T, NA_RM> : \ public Lazy::type, RowSumsImpl<__RTYPE__, NA, T, NA_RM> > { \ private: \ - const MatrixBase<__RTYPE__, NA, T>& ref; \ + typename Rcpp::traits::sugar_operand< MatrixBase<__RTYPE__, NA, T> >::type ref; \ \ typedef detail::RowSumsReturn<__RTYPE__> return_traits; \ typedef typename return_traits::type return_vector; \ @@ -160,7 +160,7 @@ private: \ public: \ RowSumsImpl(const MatrixBase<__RTYPE__, NA, T>& ref_) \ - : ref(ref_) \ + : ref(ref_.get_ref()) \ {} \ \ return_vector get() const { \ @@ -195,7 +195,7 @@ template class RowSumsImpl : public Lazy::type, RowSumsImpl > { private: - const MatrixBase& ref; + typename Rcpp::traits::sugar_operand< MatrixBase >::type ref; typedef detail::RowSumsReturn return_traits; typedef typename return_traits::type return_vector; @@ -203,7 +203,7 @@ class RowSumsImpl : public: RowSumsImpl(const MatrixBase& ref_) - : ref(ref_) + : ref(ref_.get_ref()) {} return_vector get() const { @@ -236,7 +236,7 @@ template class RowSumsImpl<__RTYPE__, NA, T, true> : \ public Lazy::type, RowSumsImpl<__RTYPE__, NA, T, true> > { \ private: \ - const MatrixBase<__RTYPE__, NA, T>& ref; \ + typename Rcpp::traits::sugar_operand< MatrixBase<__RTYPE__, NA, T> >::type ref; \ \ typedef detail::RowSumsReturn<__RTYPE__> return_traits; \ typedef typename return_traits::type return_vector; \ @@ -244,7 +244,7 @@ private: \ public: \ RowSumsImpl(const MatrixBase<__RTYPE__, NA, T>& ref_) \ - : ref(ref_) \ + : ref(ref_.get_ref()) \ {} \ \ return_vector get() const { \ @@ -289,7 +289,7 @@ template class ColSumsImpl : public Lazy::type, ColSumsImpl > { private: - const MatrixBase& ref; + typename Rcpp::traits::sugar_operand< MatrixBase >::type ref; typedef detail::ColSumsReturn return_traits; typedef typename return_traits::type return_vector; @@ -297,7 +297,7 @@ class ColSumsImpl : public: ColSumsImpl(const MatrixBase& ref_) - : ref(ref_) + : ref(ref_.get_ref()) {} return_vector get() const { @@ -325,7 +325,7 @@ template class ColSumsImpl<__RTYPE__, NA, T, NA_RM> : \ public Lazy::type, ColSumsImpl<__RTYPE__, NA, T, NA_RM> > { \ private: \ - const MatrixBase<__RTYPE__, NA, T>& ref; \ + typename Rcpp::traits::sugar_operand< MatrixBase<__RTYPE__, NA, T> >::type ref; \ \ typedef detail::ColSumsReturn<__RTYPE__> return_traits; \ typedef typename return_traits::type return_vector; \ @@ -333,7 +333,7 @@ private: \ public: \ ColSumsImpl(const MatrixBase<__RTYPE__, NA, T>& ref_) \ - : ref(ref_) \ + : ref(ref_.get_ref()) \ {} \ \ return_vector get() const { \ @@ -368,7 +368,7 @@ template class ColSumsImpl : public Lazy::type, ColSumsImpl > { private: - const MatrixBase& ref; + typename Rcpp::traits::sugar_operand< MatrixBase >::type ref; typedef detail::ColSumsReturn return_traits; typedef typename return_traits::type return_vector; @@ -376,7 +376,7 @@ class ColSumsImpl : public: ColSumsImpl(const MatrixBase& ref_) - : ref(ref_) + : ref(ref_.get_ref()) {} return_vector get() const { @@ -409,7 +409,7 @@ template class ColSumsImpl<__RTYPE__, NA, T, true> : \ public Lazy::type, ColSumsImpl<__RTYPE__, NA, T, true> > { \ private: \ - const MatrixBase<__RTYPE__, NA, T>& ref; \ + typename Rcpp::traits::sugar_operand< MatrixBase<__RTYPE__, NA, T> >::type ref; \ \ typedef detail::ColSumsReturn<__RTYPE__> return_traits; \ typedef typename return_traits::type return_vector; \ @@ -417,7 +417,7 @@ private: \ public: \ ColSumsImpl(const MatrixBase<__RTYPE__, NA, T>& ref_) \ - : ref(ref_) \ + : ref(ref_.get_ref()) \ {} \ \ return_vector get() const { \ @@ -465,7 +465,7 @@ template class RowMeansImpl : public Lazy::type, RowMeansImpl > { private: - const MatrixBase& ref; + typename Rcpp::traits::sugar_operand< MatrixBase >::type ref; typedef detail::RowMeansReturn return_traits; typedef typename return_traits::type return_vector; @@ -473,7 +473,7 @@ class RowMeansImpl : public: RowMeansImpl(const MatrixBase& ref_) - : ref(ref_) + : ref(ref_.get_ref()) {} return_vector get() const { @@ -505,7 +505,7 @@ template class RowMeansImpl<__RTYPE__, NA, T, NA_RM> : \ public Lazy::type, RowMeansImpl<__RTYPE__, NA, T, NA_RM> > { \ private: \ - const MatrixBase<__RTYPE__, NA, T>& ref; \ + typename Rcpp::traits::sugar_operand< MatrixBase<__RTYPE__, NA, T> >::type ref; \ \ typedef detail::RowMeansReturn<__RTYPE__> return_traits; \ typedef typename return_traits::type return_vector; \ @@ -513,7 +513,7 @@ private: \ public: \ RowMeansImpl(const MatrixBase<__RTYPE__, NA, T>& ref_) \ - : ref(ref_) \ + : ref(ref_.get_ref()) \ {} \ \ return_vector get() const { \ @@ -552,7 +552,7 @@ template class RowMeansImpl : public Lazy::type, RowMeansImpl > { private: - const MatrixBase& ref; + typename Rcpp::traits::sugar_operand< MatrixBase >::type ref; typedef detail::RowMeansReturn return_traits; typedef typename return_traits::type return_vector; @@ -560,7 +560,7 @@ class RowMeansImpl : public: RowMeansImpl(const MatrixBase& ref_) - : ref(ref_) + : ref(ref_.get_ref()) {} return_vector get() const { @@ -604,7 +604,7 @@ template class RowMeansImpl<__RTYPE__, NA, T, true> : \ public Lazy::type, RowMeansImpl<__RTYPE__, NA, T, true> > { \ private: \ - const MatrixBase<__RTYPE__, NA, T>& ref; \ + typename Rcpp::traits::sugar_operand< MatrixBase<__RTYPE__, NA, T> >::type ref; \ \ typedef detail::RowMeansReturn<__RTYPE__> return_traits; \ typedef typename return_traits::type return_vector; \ @@ -612,7 +612,7 @@ private: \ public: \ RowMeansImpl(const MatrixBase<__RTYPE__, NA, T>& ref_) \ - : ref(ref_) \ + : ref(ref_.get_ref()) \ {} \ \ return_vector get() const { \ @@ -665,7 +665,7 @@ template class ColMeansImpl : public Lazy::type, ColMeansImpl > { private: - const MatrixBase& ref; + typename Rcpp::traits::sugar_operand< MatrixBase >::type ref; typedef detail::ColMeansReturn return_traits; typedef typename return_traits::type return_vector; @@ -673,7 +673,7 @@ class ColMeansImpl : public: ColMeansImpl(const MatrixBase& ref_) - : ref(ref_) + : ref(ref_.get_ref()) {} return_vector get() const { @@ -705,7 +705,7 @@ template class ColMeansImpl<__RTYPE__, NA, T, NA_RM> : \ public Lazy::type, ColMeansImpl<__RTYPE__, NA, T, NA_RM> > { \ private: \ - const MatrixBase<__RTYPE__, NA, T>& ref; \ + typename Rcpp::traits::sugar_operand< MatrixBase<__RTYPE__, NA, T> >::type ref; \ \ typedef detail::ColMeansReturn<__RTYPE__> return_traits; \ typedef typename return_traits::type return_vector; \ @@ -713,7 +713,7 @@ private: \ public: \ ColMeansImpl(const MatrixBase<__RTYPE__, NA, T>& ref_) \ - : ref(ref_) \ + : ref(ref_.get_ref()) \ {} \ \ return_vector get() const { \ @@ -752,7 +752,7 @@ template class ColMeansImpl : public Lazy::type, ColMeansImpl > { private: - const MatrixBase& ref; + typename Rcpp::traits::sugar_operand< MatrixBase >::type ref; typedef detail::ColMeansReturn return_traits; typedef typename return_traits::type return_vector; @@ -760,7 +760,7 @@ class ColMeansImpl : public: ColMeansImpl(const MatrixBase& ref_) - : ref(ref_) + : ref(ref_.get_ref()) {} return_vector get() const { @@ -804,7 +804,7 @@ template class ColMeansImpl<__RTYPE__, NA, T, true> : \ public Lazy::type, ColMeansImpl<__RTYPE__, NA, T, true> > { \ private: \ - const MatrixBase<__RTYPE__, NA, T>& ref; \ + typename Rcpp::traits::sugar_operand< MatrixBase<__RTYPE__, NA, T> >::type ref; \ \ typedef detail::ColMeansReturn<__RTYPE__> return_traits; \ typedef typename return_traits::type return_vector; \ @@ -812,7 +812,7 @@ private: \ public: \ ColMeansImpl(const MatrixBase<__RTYPE__, NA, T>& ref_) \ - : ref(ref_) \ + : ref(ref_.get_ref()) \ {} \ \ return_vector get() const { \ diff --git a/inst/include/Rcpp/sugar/functions/sapply.h b/inst/include/Rcpp/sugar/functions/sapply.h index 5b1311c5e..5f1a7d803 100644 --- a/inst/include/Rcpp/sugar/functions/sapply.h +++ b/inst/include/Rcpp/sugar/functions/sapply.h @@ -56,7 +56,7 @@ class Sapply : public VectorBase< inline R_xlen_t size() const { return vec.size() ; } private: - const EXT& vec ; + typename Rcpp::traits::sugar_operand< EXT >::type vec ; Function fun ; } ; @@ -90,7 +90,7 @@ class Sapply : public VectorBase< inline R_xlen_t size() const { return vec.size() ; } private: - const EXT& vec ; + typename Rcpp::traits::sugar_operand< EXT >::type vec ; Function fun ; } ; diff --git a/inst/include/Rcpp/sugar/functions/sd.h b/inst/include/Rcpp/sugar/functions/sd.h index d7da4d600..e721e4c73 100644 --- a/inst/include/Rcpp/sugar/functions/sd.h +++ b/inst/include/Rcpp/sugar/functions/sd.h @@ -31,13 +31,13 @@ class Sd : public Lazy< typename Rcpp::traits::storage_type::type , Sd VEC_TYPE ; typedef typename Rcpp::traits::storage_type::type STORAGE ; - Sd( const VEC_TYPE& object_ ) : object(object_){} + Sd( const VEC_TYPE& object_ ) : object(object_.get_ref()){} STORAGE get() const { return ::sqrt( var(object).get() ) ; } private: - const VEC_TYPE& object ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type object ; } ; } // sugar diff --git a/inst/include/Rcpp/sugar/functions/seq_along.h b/inst/include/Rcpp/sugar/functions/seq_along.h index 247e9af2c..11cd319c4 100644 --- a/inst/include/Rcpp/sugar/functions/seq_along.h +++ b/inst/include/Rcpp/sugar/functions/seq_along.h @@ -28,6 +28,8 @@ namespace sugar{ class SeqLen : public VectorBase< INTSXP,false,SeqLen > { public: + typedef Rcpp::traits::elementwise_operands<> rcpp_elementwise ; + SeqLen( R_xlen_t len_ ) : len(len_){} inline int operator[]( R_xlen_t i ) const { diff --git a/inst/include/Rcpp/sugar/functions/sign.h b/inst/include/Rcpp/sugar/functions/sign.h index 83ad71ae0..9ecc0490b 100644 --- a/inst/include/Rcpp/sugar/functions/sign.h +++ b/inst/include/Rcpp/sugar/functions/sign.h @@ -50,8 +50,9 @@ class Sign : public Rcpp::VectorBase< INTSXP,NA, Sign > { typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::storage_type::type STORAGE ; typedef int r_import_type ; + typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ; - Sign( const VEC_TYPE& object_ ) : object(object_){} + Sign( const VEC_TYPE& object_ ) : object(object_.get_ref()){} inline int operator[]( R_xlen_t i ) const { return get(i) ; @@ -61,7 +62,7 @@ class Sign : public Rcpp::VectorBase< INTSXP,NA, Sign > { operator SEXP() const { return wrap( *this ); } inline int get(R_xlen_t i) const { return sign__impl::get( object[i] ); } private: - const VEC_TYPE& object ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type object ; } ; } // sugar diff --git a/inst/include/Rcpp/sugar/functions/sum.h b/inst/include/Rcpp/sugar/functions/sum.h index fac5d10d4..df51c076d 100644 --- a/inst/include/Rcpp/sugar/functions/sum.h +++ b/inst/include/Rcpp/sugar/functions/sum.h @@ -48,7 +48,7 @@ class Sum : public Lazy< typename Rcpp::traits::storage_type::type , Sum< return result ; } private: - const VEC_EXT& object ; + typename Rcpp::traits::sugar_operand< VEC_EXT >::type object ; } ; // RTYPE = REALSXP template @@ -68,7 +68,7 @@ class Sum : public Lazy< double , Sum > { return result ; } private: - const VEC_EXT& object ; + typename Rcpp::traits::sugar_operand< VEC_EXT >::type object ; } ; @@ -90,7 +90,7 @@ class Sum : public Lazy< typename Rcpp::traits::storage_type::type object ; } ; } // sugar diff --git a/inst/include/Rcpp/sugar/functions/tail.h b/inst/include/Rcpp/sugar/functions/tail.h index 3bfe830f1..de8be4416 100644 --- a/inst/include/Rcpp/sugar/functions/tail.h +++ b/inst/include/Rcpp/sugar/functions/tail.h @@ -31,7 +31,7 @@ class Tail : public Rcpp::VectorBase< RTYPE ,NA, Tail > { typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::storage_type::type STORAGE ; - Tail( const VEC_TYPE& object_, R_xlen_t n_ ) : object(object_), start(0), n(n_) { + Tail( const VEC_TYPE& object_, R_xlen_t n_ ) : object(object_.get_ref()), start(0), n(n_) { if( n > 0 ){ start = object.size() - n ; } else { @@ -46,7 +46,7 @@ class Tail : public Rcpp::VectorBase< RTYPE ,NA, Tail > { inline R_xlen_t size() const { return n; } private: - const VEC_TYPE& object ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type object ; R_xlen_t start, n ; } ; diff --git a/inst/include/Rcpp/sugar/functions/var.h b/inst/include/Rcpp/sugar/functions/var.h index 6e064c66a..afee1805d 100644 --- a/inst/include/Rcpp/sugar/functions/var.h +++ b/inst/include/Rcpp/sugar/functions/var.h @@ -32,7 +32,7 @@ class Var : public Lazy< double , Var > { public: typedef typename Rcpp::VectorBase VEC_TYPE ; - Var( const VEC_TYPE& object_ ) : object(object_){} + Var( const VEC_TYPE& object_ ) : object(object_.get_ref()){} double get() const{ const double average = mean(object).get(); @@ -44,7 +44,7 @@ class Var : public Lazy< double , Var > { } private: - const VEC_TYPE& object ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type object ; } ; template @@ -52,7 +52,7 @@ class Var : public Lazy< double , Var > { public: typedef typename Rcpp::VectorBase VEC_TYPE ; - Var( const VEC_TYPE& object_ ) : object(object_){} + Var( const VEC_TYPE& object_ ) : object(object_.get_ref()){} double get() const{ const Rcomplex average = mean(object).get(); @@ -66,7 +66,7 @@ class Var : public Lazy< double , Var > { } private: - const VEC_TYPE& object ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type object ; } ; } // sugar diff --git a/inst/include/Rcpp/sugar/functions/which_max.h b/inst/include/Rcpp/sugar/functions/which_max.h index 165ad6a81..a92247a1e 100644 --- a/inst/include/Rcpp/sugar/functions/which_max.h +++ b/inst/include/Rcpp/sugar/functions/which_max.h @@ -30,7 +30,7 @@ class WhichMax { public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::storage_type::type STORAGE ; - WhichMax(const VEC_TYPE& obj_ ) : obj(obj_){} + WhichMax(const VEC_TYPE& obj_ ) : obj(obj_.get_ref()){} R_xlen_t get() const { STORAGE current = obj[0] ; @@ -50,7 +50,7 @@ class WhichMax { } private: - const VEC_TYPE& obj ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type obj ; } ; @@ -59,7 +59,7 @@ class WhichMax { public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::storage_type::type STORAGE ; - WhichMax(const VEC_TYPE& obj_ ) : obj(obj_){} + WhichMax(const VEC_TYPE& obj_ ) : obj(obj_.get_ref()){} R_xlen_t get() const { STORAGE current = obj[0] ; @@ -77,7 +77,7 @@ class WhichMax { } private: - const VEC_TYPE& obj ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type obj ; } ; diff --git a/inst/include/Rcpp/sugar/functions/which_min.h b/inst/include/Rcpp/sugar/functions/which_min.h index cbc8c145f..7dd5f52ad 100644 --- a/inst/include/Rcpp/sugar/functions/which_min.h +++ b/inst/include/Rcpp/sugar/functions/which_min.h @@ -30,7 +30,7 @@ class WhichMin { public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::storage_type::type STORAGE ; - WhichMin(const VEC_TYPE& obj_ ) : obj(obj_){} + WhichMin(const VEC_TYPE& obj_ ) : obj(obj_.get_ref()){} R_xlen_t get() const { STORAGE current = obj[0] ; @@ -50,7 +50,7 @@ class WhichMin { } private: - const VEC_TYPE& obj ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type obj ; } ; @@ -59,7 +59,7 @@ class WhichMin { public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::storage_type::type STORAGE ; - WhichMin(const VEC_TYPE& obj_ ) : obj(obj_){} + WhichMin(const VEC_TYPE& obj_ ) : obj(obj_.get_ref()){} R_xlen_t get() const { STORAGE current = obj[0] ; @@ -77,7 +77,7 @@ class WhichMin { } private: - const VEC_TYPE& obj ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type obj ; } ; diff --git a/inst/include/Rcpp/sugar/logical/SingleLogicalResult.h b/inst/include/Rcpp/sugar/logical/SingleLogicalResult.h index fe0aad570..4dd5730ea 100644 --- a/inst/include/Rcpp/sugar/logical/SingleLogicalResult.h +++ b/inst/include/Rcpp/sugar/logical/SingleLogicalResult.h @@ -45,6 +45,14 @@ class SingleLogicalResult { SingleLogicalResult() : result(UNRESOLVED) {} ; + T& get_ref(){ + return static_cast(*this) ; + } + + const T& get_ref() const { + return static_cast(*this) ; + } + void apply(){ if( result == UNRESOLVED ){ static_cast(*this).apply() ; diff --git a/inst/include/Rcpp/sugar/logical/and.h b/inst/include/Rcpp/sugar/logical/and.h index faa925f4f..f36763ccd 100644 --- a/inst/include/Rcpp/sugar/logical/and.h +++ b/inst/include/Rcpp/sugar/logical/and.h @@ -41,22 +41,29 @@ public SingleLogicalResult< > BASE ; And_SingleLogicalResult_SingleLogicalResult( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_) : - lhs(lhs_), rhs(rhs_){} ; + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} ; inline void apply(){ int left = lhs.get() ; - if( Rcpp::traits::is_na( left ) ){ - BASE::set( left ) ; - } else if( left == FALSE ){ + if( left == FALSE ){ BASE::set( FALSE ) ; + return ; + } + + // NA && FALSE is FALSE + int right = rhs.get() ; + if( Rcpp::traits::is_na( left ) && right != FALSE ){ + BASE::set( left ) ; } else { - BASE::set( rhs.get() ) ; + BASE::set( right ) ; } } private: - const LHS_TYPE& lhs ; - const RHS_TYPE& rhs ; + // by value, since these are usually temporaries, and non-const, since + // evaluating them caches their result + LHS_T lhs ; + RHS_T rhs ; } ; @@ -77,7 +84,7 @@ public SingleLogicalResult< > BASE ; And_SingleLogicalResult_SingleLogicalResult( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_) : - lhs(lhs_), rhs(rhs_){} ; + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} ; inline void apply(){ // here we know rhs does not have NA, so we start with the rhs @@ -90,8 +97,8 @@ public SingleLogicalResult< } private: - const LHS_TYPE& lhs ; - const RHS_TYPE& rhs ; + LHS_T lhs ; + RHS_T rhs ; } ; @@ -113,7 +120,7 @@ public SingleLogicalResult< > BASE ; And_SingleLogicalResult_SingleLogicalResult( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_) : - lhs(lhs_), rhs(rhs_){} ; + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} ; inline void apply(){ // here we know lhs does not have NA, so we start with the rhs @@ -126,8 +133,8 @@ public SingleLogicalResult< } private: - const LHS_TYPE& lhs ; - const RHS_TYPE& rhs ; + LHS_T lhs ; + RHS_T rhs ; } ; @@ -148,7 +155,7 @@ public SingleLogicalResult< > BASE ; And_SingleLogicalResult_SingleLogicalResult( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_) : - lhs(lhs_), rhs(rhs_){} ; + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} ; inline void apply(){ int left = lhs.get() ; @@ -160,8 +167,8 @@ public SingleLogicalResult< } private: - const LHS_TYPE& lhs ; - const RHS_TYPE& rhs ; + LHS_T lhs ; + RHS_T rhs ; } ; @@ -182,7 +189,7 @@ public SingleLogicalResult< > BASE ; And_SingleLogicalResult_bool( const LHS_TYPE& lhs_, bool rhs_) : - lhs(lhs_), rhs(rhs_){} ; + lhs(lhs_.get_ref()), rhs(rhs_){} ; inline void apply(){ if( !rhs ){ @@ -193,7 +200,7 @@ public SingleLogicalResult< } private: - const LHS_TYPE& lhs ; + LHS_T lhs ; bool rhs ; } ; @@ -206,8 +213,11 @@ class And_LogicalExpression_LogicalExpression : public Rcpp::VectorBase< LGLSXP, public: typedef typename Rcpp::VectorBase LHS_TYPE ; typedef typename Rcpp::VectorBase RHS_TYPE ; + typedef Rcpp::traits::elementwise_operands< LHS_TYPE, RHS_TYPE > rcpp_elementwise ; - And_LogicalExpression_LogicalExpression( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : lhs(lhs_), rhs(rhs_){} + And_LogicalExpression_LogicalExpression( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){ + check_sizes(lhs.size(), rhs.size()) ; + } inline int operator[]( R_xlen_t i ) const{ if( lhs[i] == TRUE && rhs[i] == TRUE ) return TRUE ; @@ -217,8 +227,8 @@ class And_LogicalExpression_LogicalExpression : public Rcpp::VectorBase< LGLSXP, inline R_xlen_t size() const { return lhs.size(); } private: - const LHS_TYPE& lhs ; - const RHS_TYPE& rhs ; + typename Rcpp::traits::sugar_operand< LHS_TYPE >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_TYPE >::type rhs ; } ; template class And_LogicalExpression_LogicalExpression @@ -226,8 +236,11 @@ class And_LogicalExpression_LogicalExpression public: typedef typename Rcpp::VectorBase LHS_TYPE ; typedef typename Rcpp::VectorBase RHS_TYPE ; + typedef Rcpp::traits::elementwise_operands< LHS_TYPE, RHS_TYPE > rcpp_elementwise ; - And_LogicalExpression_LogicalExpression( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : lhs(lhs_), rhs(rhs_){} + And_LogicalExpression_LogicalExpression( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){ + check_sizes(lhs.size(), rhs.size()) ; + } inline int operator[]( R_xlen_t i ) const{ if( lhs[i] == TRUE && rhs[i] == TRUE ) return TRUE ; @@ -237,8 +250,8 @@ class And_LogicalExpression_LogicalExpression inline R_xlen_t size() const { return lhs.size(); } private: - const LHS_TYPE& lhs ; - const RHS_TYPE& rhs ; + typename Rcpp::traits::sugar_operand< LHS_TYPE >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_TYPE >::type rhs ; } ; template class And_LogicalExpression_LogicalExpression @@ -246,8 +259,11 @@ class And_LogicalExpression_LogicalExpression public: typedef typename Rcpp::VectorBase LHS_TYPE ; typedef typename Rcpp::VectorBase RHS_TYPE ; + typedef Rcpp::traits::elementwise_operands< LHS_TYPE, RHS_TYPE > rcpp_elementwise ; - And_LogicalExpression_LogicalExpression( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : lhs(lhs_), rhs(rhs_){} + And_LogicalExpression_LogicalExpression( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){ + check_sizes(lhs.size(), rhs.size()) ; + } inline int operator[]( R_xlen_t i ) const{ if( lhs[i] == TRUE && rhs[i] == TRUE ) return TRUE ; @@ -257,8 +273,8 @@ class And_LogicalExpression_LogicalExpression inline R_xlen_t size() const { return lhs.size(); } private: - const LHS_TYPE& lhs ; - const RHS_TYPE& rhs ; + typename Rcpp::traits::sugar_operand< LHS_TYPE >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_TYPE >::type rhs ; } ; template class And_LogicalExpression_LogicalExpression @@ -266,8 +282,11 @@ class And_LogicalExpression_LogicalExpression public: typedef typename Rcpp::VectorBase LHS_TYPE ; typedef typename Rcpp::VectorBase RHS_TYPE ; + typedef Rcpp::traits::elementwise_operands< LHS_TYPE, RHS_TYPE > rcpp_elementwise ; - And_LogicalExpression_LogicalExpression( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : lhs(lhs_), rhs(rhs_){} + And_LogicalExpression_LogicalExpression( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){ + check_sizes(lhs.size(), rhs.size()) ; + } inline int operator[]( R_xlen_t i ) const{ if( lhs[i] == TRUE && rhs[i] == TRUE ) return TRUE ; @@ -276,8 +295,8 @@ class And_LogicalExpression_LogicalExpression inline R_xlen_t size() const { return lhs.size(); } private: - const LHS_TYPE& lhs ; - const RHS_TYPE& rhs ; + typename Rcpp::traits::sugar_operand< LHS_TYPE >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_TYPE >::type rhs ; } ; } @@ -287,7 +306,7 @@ template inline Rcpp::sugar::And_SingleLogicalResult_SingleLogicalResult operator&&( const Rcpp::sugar::SingleLogicalResult& lhs, - const Rcpp::sugar::SingleLogicalResult& rhs + const Rcpp::sugar::SingleLogicalResult& rhs ){ return Rcpp::sugar::And_SingleLogicalResult_SingleLogicalResult( lhs, rhs ) ; } diff --git a/inst/include/Rcpp/sugar/logical/not.h b/inst/include/Rcpp/sugar/logical/not.h index db63cd6e6..d975d55c1 100644 --- a/inst/include/Rcpp/sugar/logical/not.h +++ b/inst/include/Rcpp/sugar/logical/not.h @@ -43,14 +43,16 @@ class Negate_SingleLogicalResult : public SingleLogicalResult TYPE ; typedef SingleLogicalResult > BASE ; - Negate_SingleLogicalResult( const TYPE& orig_ ) : orig(orig_) {} + Negate_SingleLogicalResult( const TYPE& orig_ ) : orig(orig_.get_ref()) {} inline void apply(){ BASE::set( negate::apply( orig.get() ) ); } private: - const TYPE& orig ; + // by value, since it is usually a temporary, and non-const, since + // evaluating it caches its result + T orig ; } ; diff --git a/inst/include/Rcpp/sugar/logical/or.h b/inst/include/Rcpp/sugar/logical/or.h index 5ad28b897..4e9f610ea 100644 --- a/inst/include/Rcpp/sugar/logical/or.h +++ b/inst/include/Rcpp/sugar/logical/or.h @@ -41,22 +41,29 @@ public SingleLogicalResult< > BASE ; Or_SingleLogicalResult_SingleLogicalResult( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_) : - lhs(lhs_), rhs(rhs_){} ; + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} ; inline void apply(){ int left = lhs.get() ; - if( Rcpp::traits::is_na( left ) ){ - BASE::set( left ) ; - } else if( left == TRUE ){ + if( left == TRUE ){ BASE::set( TRUE ) ; + return ; + } + + // NA || TRUE is TRUE + int right = rhs.get() ; + if( Rcpp::traits::is_na( left ) && right != TRUE ){ + BASE::set( left ) ; } else { - BASE::set( rhs.get() ) ; + BASE::set( right ) ; } } private: - const LHS_TYPE& lhs ; - const RHS_TYPE& rhs ; + // by value, since these are usually temporaries, and non-const, since + // evaluating them caches their result + LHS_T lhs ; + RHS_T rhs ; } ; @@ -77,7 +84,7 @@ public SingleLogicalResult< > BASE ; Or_SingleLogicalResult_SingleLogicalResult( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_) : - lhs(lhs_), rhs(rhs_){} ; + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} ; inline void apply(){ // here we know rhs does not have NA, so we start with the rhs @@ -90,8 +97,8 @@ public SingleLogicalResult< } private: - const LHS_TYPE& lhs ; - const RHS_TYPE& rhs ; + LHS_T lhs ; + RHS_T rhs ; } ; @@ -113,7 +120,7 @@ public SingleLogicalResult< > BASE ; Or_SingleLogicalResult_SingleLogicalResult( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_) : - lhs(lhs_), rhs(rhs_){} ; + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} ; inline void apply(){ // here we know lhs does not have NA, so we start with the rhs @@ -126,8 +133,8 @@ public SingleLogicalResult< } private: - const LHS_TYPE& lhs ; - const RHS_TYPE& rhs ; + LHS_T lhs ; + RHS_T rhs ; } ; @@ -148,7 +155,7 @@ public SingleLogicalResult< > BASE ; Or_SingleLogicalResult_SingleLogicalResult( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_) : - lhs(lhs_), rhs(rhs_){} ; + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} ; inline void apply(){ int left = lhs.get() ; @@ -160,8 +167,8 @@ public SingleLogicalResult< } private: - const LHS_TYPE& lhs ; - const RHS_TYPE& rhs ; + LHS_T lhs ; + RHS_T rhs ; } ; @@ -170,7 +177,7 @@ template class Or_SingleLogicalResult_bool : public SingleLogicalResult< LHS_NA , - And_SingleLogicalResult_bool + Or_SingleLogicalResult_bool > { public: @@ -181,7 +188,7 @@ public SingleLogicalResult< > BASE ; Or_SingleLogicalResult_bool( const LHS_TYPE& lhs_, bool rhs_) : - lhs(lhs_), rhs(rhs_){} ; + lhs(lhs_.get_ref()), rhs(rhs_){} ; inline void apply(){ if( rhs ){ @@ -192,7 +199,7 @@ public SingleLogicalResult< } private: - const LHS_TYPE& lhs ; + LHS_T lhs ; bool rhs ; } ; @@ -203,8 +210,11 @@ class Or_LogicalExpression_LogicalExpression : public Rcpp::VectorBase< LGLSXP, public: typedef typename Rcpp::VectorBase LHS_TYPE ; typedef typename Rcpp::VectorBase RHS_TYPE ; + typedef Rcpp::traits::elementwise_operands< LHS_TYPE, RHS_TYPE > rcpp_elementwise ; - Or_LogicalExpression_LogicalExpression( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : lhs(lhs_), rhs(rhs_){} + Or_LogicalExpression_LogicalExpression( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){ + check_sizes(lhs.size(), rhs.size()) ; + } inline int operator[]( R_xlen_t i ) const{ if( lhs[i] == TRUE || rhs[i] == TRUE ) return TRUE ; @@ -214,8 +224,8 @@ class Or_LogicalExpression_LogicalExpression : public Rcpp::VectorBase< LGLSXP, inline R_xlen_t size() const { return lhs.size(); } private: - const LHS_TYPE& lhs ; - const RHS_TYPE& rhs ; + typename Rcpp::traits::sugar_operand< LHS_TYPE >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_TYPE >::type rhs ; } ; template class Or_LogicalExpression_LogicalExpression @@ -223,8 +233,11 @@ class Or_LogicalExpression_LogicalExpression public: typedef typename Rcpp::VectorBase LHS_TYPE ; typedef typename Rcpp::VectorBase RHS_TYPE ; + typedef Rcpp::traits::elementwise_operands< LHS_TYPE, RHS_TYPE > rcpp_elementwise ; - Or_LogicalExpression_LogicalExpression( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : lhs(lhs_), rhs(rhs_){} + Or_LogicalExpression_LogicalExpression( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){ + check_sizes(lhs.size(), rhs.size()) ; + } inline int operator[]( R_xlen_t i ) const{ if( lhs[i] == TRUE || rhs[i] == TRUE ) return TRUE ; @@ -234,8 +247,8 @@ class Or_LogicalExpression_LogicalExpression inline R_xlen_t size() const { return lhs.size(); } private: - const LHS_TYPE& lhs ; - const RHS_TYPE& rhs ; + typename Rcpp::traits::sugar_operand< LHS_TYPE >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_TYPE >::type rhs ; } ; template class Or_LogicalExpression_LogicalExpression @@ -243,8 +256,11 @@ class Or_LogicalExpression_LogicalExpression public: typedef typename Rcpp::VectorBase LHS_TYPE ; typedef typename Rcpp::VectorBase RHS_TYPE ; + typedef Rcpp::traits::elementwise_operands< LHS_TYPE, RHS_TYPE > rcpp_elementwise ; - Or_LogicalExpression_LogicalExpression( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : lhs(lhs_), rhs(rhs_){} + Or_LogicalExpression_LogicalExpression( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){ + check_sizes(lhs.size(), rhs.size()) ; + } inline int operator[]( R_xlen_t i ) const{ if( lhs[i] == TRUE || rhs[i] == TRUE ) return TRUE ; @@ -254,8 +270,8 @@ class Or_LogicalExpression_LogicalExpression inline R_xlen_t size() const { return lhs.size(); } private: - const LHS_TYPE& lhs ; - const RHS_TYPE& rhs ; + typename Rcpp::traits::sugar_operand< LHS_TYPE >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_TYPE >::type rhs ; } ; template class Or_LogicalExpression_LogicalExpression @@ -263,8 +279,11 @@ class Or_LogicalExpression_LogicalExpression public: typedef typename Rcpp::VectorBase LHS_TYPE ; typedef typename Rcpp::VectorBase RHS_TYPE ; + typedef Rcpp::traits::elementwise_operands< LHS_TYPE, RHS_TYPE > rcpp_elementwise ; - Or_LogicalExpression_LogicalExpression( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : lhs(lhs_), rhs(rhs_){} + Or_LogicalExpression_LogicalExpression( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){ + check_sizes(lhs.size(), rhs.size()) ; + } inline int operator[]( R_xlen_t i ) const{ if( lhs[i] == TRUE || rhs[i] == TRUE ) return TRUE ; @@ -273,8 +292,8 @@ class Or_LogicalExpression_LogicalExpression inline R_xlen_t size() const { return lhs.size(); } private: - const LHS_TYPE& lhs ; - const RHS_TYPE& rhs ; + typename Rcpp::traits::sugar_operand< LHS_TYPE >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_TYPE >::type rhs ; } ; @@ -286,7 +305,7 @@ template inline Rcpp::sugar::Or_SingleLogicalResult_SingleLogicalResult operator||( const Rcpp::sugar::SingleLogicalResult& lhs, - const Rcpp::sugar::SingleLogicalResult& rhs + const Rcpp::sugar::SingleLogicalResult& rhs ){ return Rcpp::sugar::Or_SingleLogicalResult_SingleLogicalResult( lhs, rhs ) ; } diff --git a/inst/include/Rcpp/sugar/matrix/diag.h b/inst/include/Rcpp/sugar/matrix/diag.h index af2941645..8aa4ca815 100644 --- a/inst/include/Rcpp/sugar/matrix/diag.h +++ b/inst/include/Rcpp/sugar/matrix/diag.h @@ -32,7 +32,7 @@ class Diag_Extractor : public Rcpp::VectorBase< RTYPE ,NA, Diag_Extractor MAT_TYPE ; typedef typename Rcpp::traits::storage_type::type STORAGE ; - Diag_Extractor( const MAT_TYPE& object_ ) : object(object_), n(0) { + Diag_Extractor( const MAT_TYPE& object_ ) : object(object_.get_ref()), n(0) { int nr = static_cast(object.nrow()) ; int nc = static_cast(object.ncol()) ; n = (nc < nr ) ? nc : nr ; @@ -44,7 +44,7 @@ class Diag_Extractor : public Rcpp::VectorBase< RTYPE ,NA, Diag_Extractor::type object ; R_xlen_t n ; } ; @@ -55,7 +55,7 @@ class Diag_Maker : public Rcpp::MatrixBase< RTYPE ,NA, Diag_Maker > typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::storage_type::type STORAGE ; - Diag_Maker( const VEC_TYPE& object_ ) : object(object_), n(static_cast(object_.size())) {} + Diag_Maker( const VEC_TYPE& object_ ) : object(object_.get_ref()), n(static_cast(object_.size())) {} inline STORAGE operator()( int i, int j ) const { return (i==j) ? object[i] : 0 ; @@ -65,7 +65,7 @@ class Diag_Maker : public Rcpp::MatrixBase< RTYPE ,NA, Diag_Maker > inline int nrow() const { return n; } private: - const VEC_TYPE& object ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type object ; int n ; } ; diff --git a/inst/include/Rcpp/sugar/nona/nona.h b/inst/include/Rcpp/sugar/nona/nona.h index 6eef297e4..fecd32ef7 100644 --- a/inst/include/Rcpp/sugar/nona/nona.h +++ b/inst/include/Rcpp/sugar/nona/nona.h @@ -30,6 +30,7 @@ namespace sugar { public: typedef typename Rcpp::VectorBase SUGAR_TYPE ; typedef typename Rcpp::traits::storage_type::type STORAGE ; + typedef Rcpp::traits::elementwise_operands< VECTOR > rcpp_elementwise ; Nona( const SUGAR_TYPE& expr) : data(expr.get_ref()){} @@ -37,7 +38,7 @@ namespace sugar { inline STORAGE operator[](R_xlen_t i) const { return data[i] ; } private: - const VECTOR& data ; + typename Rcpp::traits::sugar_operand< VECTOR >::type data ; } ; // specialization when the expression is actually a vector expression @@ -47,6 +48,7 @@ namespace sugar { typedef typename Rcpp::VectorBase > SUGAR_TYPE ; typedef typename Rcpp::traits::storage_type::type STORAGE ; typedef typename Rcpp::Vector::const_iterator iterator ; + typedef Rcpp::traits::elementwise_operands<> rcpp_elementwise ; Nona( const SUGAR_TYPE& expr) : data(expr.get_ref().begin()), n(expr.size()){} diff --git a/inst/include/Rcpp/sugar/operators/Comparator.h b/inst/include/Rcpp/sugar/operators/Comparator.h index d6446917a..61121c06c 100644 --- a/inst/include/Rcpp/sugar/operators/Comparator.h +++ b/inst/include/Rcpp/sugar/operators/Comparator.h @@ -33,9 +33,12 @@ class Comparator : typedef typename Rcpp::VectorBase LHS_TYPE ; typedef typename Rcpp::VectorBase RHS_TYPE ; typedef typename traits::storage_type::type STORAGE ; + typedef Rcpp::traits::elementwise_operands< LHS_TYPE, RHS_TYPE > rcpp_elementwise ; Comparator( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_) : - lhs(lhs_), rhs(rhs_), op() {} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()), op() { + check_sizes(lhs.size(), rhs.size()) ; + } inline int operator[]( R_xlen_t i ) const { STORAGE x = lhs[i] ; @@ -48,8 +51,8 @@ class Comparator : inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_TYPE& lhs ; - const RHS_TYPE& rhs ; + typename Rcpp::traits::sugar_operand< LHS_TYPE >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_TYPE >::type rhs ; Operator op ; } ; @@ -64,9 +67,12 @@ class Comparator : typedef typename Rcpp::VectorBase LHS_TYPE ; typedef typename Rcpp::VectorBase RHS_TYPE ; typedef typename traits::storage_type::type STORAGE ; + typedef Rcpp::traits::elementwise_operands< LHS_TYPE, RHS_TYPE > rcpp_elementwise ; Comparator( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_) : - lhs(lhs_), rhs(rhs_), op() {} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()), op() { + check_sizes(lhs.size(), rhs.size()) ; + } inline int operator[]( R_xlen_t i ) const { STORAGE y = rhs[i] ; @@ -77,8 +83,8 @@ class Comparator : inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_TYPE& lhs ; - const RHS_TYPE& rhs ; + typename Rcpp::traits::sugar_operand< LHS_TYPE >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_TYPE >::type rhs ; Operator op ; } ; @@ -92,9 +98,12 @@ class Comparator : typedef typename Rcpp::VectorBase LHS_TYPE ; typedef typename Rcpp::VectorBase RHS_TYPE ; typedef typename traits::storage_type::type STORAGE ; + typedef Rcpp::traits::elementwise_operands< LHS_TYPE, RHS_TYPE > rcpp_elementwise ; Comparator( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_) : - lhs(lhs_), rhs(rhs_), op() {} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()), op() { + check_sizes(lhs.size(), rhs.size()) ; + } inline int operator[]( R_xlen_t i ) const { return op( lhs[i], rhs[i] ) ; @@ -103,8 +112,8 @@ class Comparator : inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_TYPE& lhs ; - const RHS_TYPE& rhs ; + typename Rcpp::traits::sugar_operand< LHS_TYPE >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_TYPE >::type rhs ; Operator op ; } ; diff --git a/inst/include/Rcpp/sugar/operators/Comparator_With_One_Value.h b/inst/include/Rcpp/sugar/operators/Comparator_With_One_Value.h index 7286fdeda..243a45ce2 100644 --- a/inst/include/Rcpp/sugar/operators/Comparator_With_One_Value.h +++ b/inst/include/Rcpp/sugar/operators/Comparator_With_One_Value.h @@ -32,9 +32,10 @@ class Comparator_With_One_Value : public ::Rcpp::VectorBase< LGLSXP, true, Compa typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename traits::storage_type::type STORAGE ; typedef int (Comparator_With_One_Value::*METHOD)(R_xlen_t) const ; + typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ; Comparator_With_One_Value( const VEC_TYPE& lhs_, STORAGE rhs_ ) : - lhs(lhs_), rhs(rhs_), m(), op() { + lhs(lhs_.get_ref()), rhs(rhs_), m(), op() { m = Rcpp::traits::is_na(rhs) ? &Comparator_With_One_Value::rhs_is_na : @@ -49,7 +50,7 @@ class Comparator_With_One_Value : public ::Rcpp::VectorBase< LGLSXP, true, Compa inline R_xlen_t size() const { return lhs.size() ; } private: - const VEC_TYPE& lhs ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type lhs ; STORAGE rhs ; METHOD m ; Operator op ; @@ -71,9 +72,10 @@ class Comparator_With_One_Value : typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename traits::storage_type::type STORAGE ; typedef int (Comparator_With_One_Value::*METHOD)(R_xlen_t) const ; + typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ; Comparator_With_One_Value( const VEC_TYPE& lhs_, STORAGE rhs_ ) : - lhs(lhs_), rhs(rhs_), m(), op() { + lhs(lhs_.get_ref()), rhs(rhs_), m(), op() { m = Rcpp::traits::is_na(rhs) ? &Comparator_With_One_Value::rhs_is_na : @@ -88,7 +90,7 @@ class Comparator_With_One_Value : inline R_xlen_t size() const { return lhs.size() ; } private: - const VEC_TYPE& lhs ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type lhs ; STORAGE rhs ; METHOD m ; Operator op ; diff --git a/inst/include/Rcpp/sugar/operators/divides.h b/inst/include/Rcpp/sugar/operators/divides.h index 9485acf8b..3ca732231 100644 --- a/inst/include/Rcpp/sugar/operators/divides.h +++ b/inst/include/Rcpp/sugar/operators/divides.h @@ -33,9 +33,12 @@ namespace sugar{ typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::traits::Extractor< RTYPE, LHS_NA, LHS_T>::type LHS_EXT ; typedef typename Rcpp::traits::Extractor< RTYPE, RHS_NA, RHS_T>::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Divides_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) {} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) { + check_sizes(lhs.size(), rhs.size()) ; + } inline STORAGE operator[]( R_xlen_t i ) const { STORAGE x = lhs[i] ; @@ -47,8 +50,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; // RTYPE = REALSXP template @@ -59,9 +62,12 @@ namespace sugar{ typedef typename Rcpp::VectorBase RHS_TYPE ; typedef typename Rcpp::traits::Extractor::type LHS_EXT ; typedef typename Rcpp::traits::Extractor::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Divides_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) {} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) { + check_sizes(lhs.size(), rhs.size()) ; + } inline double operator[]( R_xlen_t i ) const { return lhs[i] / rhs[i] ; @@ -70,8 +76,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; @@ -83,9 +89,12 @@ namespace sugar{ typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::traits::Extractor< RTYPE, false, LHS_T>::type LHS_EXT ; typedef typename Rcpp::traits::Extractor< RTYPE, RHS_NA, RHS_T>::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Divides_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) {} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) { + check_sizes(lhs.size(), rhs.size()) ; + } inline STORAGE operator[]( R_xlen_t i ) const { STORAGE y = rhs[i] ; @@ -96,8 +105,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; // RTYPE = REALSXP template @@ -108,9 +117,12 @@ namespace sugar{ typedef typename Rcpp::VectorBase RHS_TYPE ; typedef typename Rcpp::traits::Extractor::type LHS_EXT ; typedef typename Rcpp::traits::Extractor::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Divides_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) {} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) { + check_sizes(lhs.size(), rhs.size()) ; + } inline double operator[]( R_xlen_t i ) const { return lhs[i] / rhs[i] ; @@ -119,8 +131,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; @@ -133,9 +145,12 @@ namespace sugar{ typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::traits::Extractor< RTYPE, LHS_NA, LHS_T>::type LHS_EXT ; typedef typename Rcpp::traits::Extractor< RTYPE, false, RHS_T>::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Divides_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) {} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) { + check_sizes(lhs.size(), rhs.size()) ; + } inline STORAGE operator[]( R_xlen_t i ) const { STORAGE x = lhs[i] ; @@ -145,8 +160,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; // RTYPE = REALSXP template @@ -157,9 +172,12 @@ namespace sugar{ typedef typename Rcpp::VectorBase RHS_TYPE ; typedef typename Rcpp::traits::Extractor::type LHS_EXT ; typedef typename Rcpp::traits::Extractor::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Divides_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) {} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) { + check_sizes(lhs.size(), rhs.size()) ; + } inline double operator[]( R_xlen_t i ) const { return lhs[i] / rhs[i] ; @@ -167,8 +185,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; @@ -181,9 +199,12 @@ namespace sugar{ typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::traits::Extractor::type LHS_EXT ; typedef typename Rcpp::traits::Extractor::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Divides_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) {} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) { + check_sizes(lhs.size(), rhs.size()) ; + } inline STORAGE operator[]( R_xlen_t i ) const { return lhs[i] / rhs[i] ; @@ -192,8 +213,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; // RTYPE : REALSXP template @@ -204,9 +225,12 @@ namespace sugar{ typedef typename Rcpp::VectorBase RHS_TYPE ; typedef typename Rcpp::traits::Extractor::type LHS_EXT ; typedef typename Rcpp::traits::Extractor::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Divides_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) {} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) { + check_sizes(lhs.size(), rhs.size()) ; + } inline double operator[]( R_xlen_t i ) const { return lhs[i] / rhs[i] ; @@ -215,8 +239,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; @@ -229,6 +253,7 @@ namespace sugar{ typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::Extractor::type VEC_EXT ; + typedef Rcpp::traits::elementwise_operands< VEC_EXT > rcpp_elementwise ; Divides_Vector_Primitive( const VEC_TYPE& lhs_, STORAGE rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_), rhs_na( Rcpp::traits::is_na(rhs_) ) { @@ -243,7 +268,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const VEC_EXT& lhs ; + typename Rcpp::traits::sugar_operand< VEC_EXT >::type lhs ; STORAGE rhs ; bool rhs_na ; } ; @@ -254,6 +279,7 @@ namespace sugar{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::Extractor::type VEC_EXT ; + typedef Rcpp::traits::elementwise_operands< VEC_EXT > rcpp_elementwise ; Divides_Vector_Primitive( const VEC_TYPE& lhs_, double rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_) { @@ -266,7 +292,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const VEC_EXT& lhs ; + typename Rcpp::traits::sugar_operand< VEC_EXT >::type lhs ; double rhs ; } ; @@ -279,6 +305,7 @@ namespace sugar{ typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::Extractor::type VEC_EXT ; + typedef Rcpp::traits::elementwise_operands< VEC_EXT > rcpp_elementwise ; Divides_Vector_Primitive( const VEC_TYPE& lhs_, STORAGE rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_), rhs_na( Rcpp::traits::is_na(rhs_) ) {} @@ -291,7 +318,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const VEC_EXT& lhs ; + typename Rcpp::traits::sugar_operand< VEC_EXT >::type lhs ; STORAGE rhs ; bool rhs_na ; } ; @@ -302,9 +329,10 @@ namespace sugar{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::Extractor::type VEC_EXT ; + typedef Rcpp::traits::elementwise_operands< VEC_EXT > rcpp_elementwise ; Divides_Vector_Primitive( const VEC_TYPE& lhs_, double rhs_ ) : - lhs(lhs_), rhs(rhs_){} + lhs(lhs_.get_ref()), rhs(rhs_){} inline double operator[]( R_xlen_t i ) const { return lhs[i] / rhs ; @@ -312,7 +340,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const VEC_EXT& lhs ; + typename Rcpp::traits::sugar_operand< VEC_EXT >::type lhs ; double rhs ; } ; @@ -325,6 +353,7 @@ namespace sugar{ typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::Extractor::type VEC_EXT ; typedef typename traits::storage_type::type STORAGE ; + typedef Rcpp::traits::elementwise_operands< VEC_EXT > rcpp_elementwise ; Divides_Primitive_Vector( STORAGE lhs_, const VEC_TYPE& rhs_ ) : lhs(lhs_), rhs(rhs_.get_ref()), lhs_na( Rcpp::traits::is_na(lhs_) ) {} @@ -337,7 +366,7 @@ namespace sugar{ inline R_xlen_t size() const { return rhs.size() ; } private: STORAGE lhs ; - const VEC_EXT& rhs ; + typename Rcpp::traits::sugar_operand< VEC_EXT >::type rhs ; bool lhs_na ; } ; // RTYPE = REALSXP @@ -347,6 +376,7 @@ namespace sugar{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::Extractor::type VEC_EXT ; + typedef Rcpp::traits::elementwise_operands< VEC_EXT > rcpp_elementwise ; Divides_Primitive_Vector( double lhs_, const VEC_TYPE& rhs_ ) : lhs(lhs_), rhs(rhs_.get_ref()) {} @@ -357,7 +387,7 @@ namespace sugar{ inline R_xlen_t size() const { return rhs.size() ; } private: double lhs ; - const VEC_EXT& rhs ; + typename Rcpp::traits::sugar_operand< VEC_EXT >::type rhs ; } ; @@ -369,6 +399,7 @@ namespace sugar{ typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::traits::Extractor::type VEC_EXT ; + typedef Rcpp::traits::elementwise_operands< VEC_EXT > rcpp_elementwise ; Divides_Primitive_Vector( STORAGE lhs_, const VEC_TYPE& rhs_ ) : lhs(lhs_), rhs(rhs_.get_ref()), lhs_na( Rcpp::traits::is_na(lhs_) ) {} @@ -381,7 +412,7 @@ namespace sugar{ private: STORAGE lhs ; - const VEC_EXT& rhs ; + typename Rcpp::traits::sugar_operand< VEC_EXT >::type rhs ; bool lhs_na ; } ; // RTYPE = REALSXP @@ -391,6 +422,7 @@ namespace sugar{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::Extractor::type VEC_EXT ; + typedef Rcpp::traits::elementwise_operands< VEC_EXT > rcpp_elementwise ; Divides_Primitive_Vector( double lhs_, const VEC_TYPE& rhs_ ) : lhs(lhs_), rhs(rhs_.get_ref()) {} @@ -402,7 +434,7 @@ namespace sugar{ private: double lhs ; - const VEC_EXT& rhs ; + typename Rcpp::traits::sugar_operand< VEC_EXT >::type rhs ; } ; diff --git a/inst/include/Rcpp/sugar/operators/minus.h b/inst/include/Rcpp/sugar/operators/minus.h index 04bfcb7dc..b5fd4cad9 100644 --- a/inst/include/Rcpp/sugar/operators/minus.h +++ b/inst/include/Rcpp/sugar/operators/minus.h @@ -35,9 +35,12 @@ namespace sugar{ typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::traits::Extractor< RTYPE, LHS_NA, LHS_T>::type LHS_EXT ; typedef typename Rcpp::traits::Extractor< RTYPE, RHS_NA, RHS_T>::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Minus_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) {} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) { + check_sizes(lhs.size(), rhs.size()) ; + } inline STORAGE operator[]( R_xlen_t i ) const { STORAGE x = lhs[i] ; @@ -49,8 +52,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; // RTYPE = REALSXP template @@ -61,9 +64,12 @@ namespace sugar{ typedef typename Rcpp::VectorBase RHS_TYPE ; typedef typename Rcpp::traits::Extractor::type LHS_EXT ; typedef typename Rcpp::traits::Extractor::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Minus_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) {} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) { + check_sizes(lhs.size(), rhs.size()) ; + } inline double operator[]( R_xlen_t i ) const { return lhs[i] - rhs[i] ; @@ -72,8 +78,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; @@ -85,9 +91,12 @@ namespace sugar{ typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::traits::Extractor::type LHS_EXT ; typedef typename Rcpp::traits::Extractor::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Minus_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) {} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) { + check_sizes(lhs.size(), rhs.size()) ; + } inline STORAGE operator[]( R_xlen_t i ) const { STORAGE y = rhs[i] ; @@ -98,8 +107,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; // RTYPE = REALSXP template @@ -110,9 +119,12 @@ namespace sugar{ typedef typename Rcpp::VectorBase RHS_TYPE ; typedef typename Rcpp::traits::Extractor::type LHS_EXT ; typedef typename Rcpp::traits::Extractor::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Minus_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) {} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) { + check_sizes(lhs.size(), rhs.size()) ; + } inline double operator[]( R_xlen_t i ) const { return lhs[i] - rhs[i] ; @@ -121,8 +133,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; @@ -134,9 +146,12 @@ namespace sugar{ typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::traits::Extractor::type LHS_EXT ; typedef typename Rcpp::traits::Extractor::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Minus_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) {} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) { + check_sizes(lhs.size(), rhs.size()) ; + } inline STORAGE operator[]( R_xlen_t i ) const { STORAGE x = lhs[i] ; @@ -147,8 +162,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; // RTYPE = REALSXP template @@ -159,9 +174,12 @@ namespace sugar{ typedef typename Rcpp::VectorBase RHS_TYPE ; typedef typename Rcpp::traits::Extractor::type LHS_EXT ; typedef typename Rcpp::traits::Extractor::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Minus_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) {} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) { + check_sizes(lhs.size(), rhs.size()) ; + } inline double operator[]( R_xlen_t i ) const { return lhs[i] - rhs[i] ; @@ -170,8 +188,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; @@ -184,9 +202,12 @@ namespace sugar{ typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::traits::Extractor::type LHS_EXT ; typedef typename Rcpp::traits::Extractor::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Minus_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) {} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) { + check_sizes(lhs.size(), rhs.size()) ; + } inline STORAGE operator[]( R_xlen_t i ) const { return lhs[i] - rhs[i]; @@ -195,8 +216,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; template class Minus_Vector_Vector : @@ -206,9 +227,12 @@ namespace sugar{ typedef typename Rcpp::VectorBase RHS_TYPE ; typedef typename Rcpp::traits::Extractor::type LHS_EXT ; typedef typename Rcpp::traits::Extractor::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Minus_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) {} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) { + check_sizes(lhs.size(), rhs.size()) ; + } inline double operator[]( R_xlen_t i ) const { return lhs[i] - rhs[i] ; @@ -217,8 +241,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; @@ -232,6 +256,7 @@ namespace sugar{ typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::Extractor::type VEC_EXT ; + typedef Rcpp::traits::elementwise_operands< VEC_EXT > rcpp_elementwise ; Minus_Vector_Primitive( const VEC_TYPE& lhs_, STORAGE rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_), rhs_na( Rcpp::traits::is_na(rhs_) ) {} @@ -245,7 +270,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const VEC_EXT& lhs ; + typename Rcpp::traits::sugar_operand< VEC_EXT >::type lhs ; STORAGE rhs ; bool rhs_na ; } ; @@ -255,6 +280,7 @@ namespace sugar{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::Extractor::type VEC_EXT ; + typedef Rcpp::traits::elementwise_operands< VEC_EXT > rcpp_elementwise ; Minus_Vector_Primitive( const VEC_TYPE& lhs_, double rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_){} @@ -266,7 +292,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const VEC_EXT& lhs ; + typename Rcpp::traits::sugar_operand< VEC_EXT >::type lhs ; double rhs ; } ; @@ -278,6 +304,7 @@ namespace sugar{ typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::Extractor::type VEC_EXT ; + typedef Rcpp::traits::elementwise_operands< VEC_EXT > rcpp_elementwise ; Minus_Vector_Primitive( const VEC_TYPE& lhs_, STORAGE rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_), rhs_na( Rcpp::traits::is_na(rhs_) ) {} @@ -291,7 +318,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const VEC_EXT& lhs ; + typename Rcpp::traits::sugar_operand< VEC_EXT >::type lhs ; STORAGE rhs ; bool rhs_na ; } ; @@ -301,6 +328,7 @@ namespace sugar{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::Extractor::type VEC_EXT ; + typedef Rcpp::traits::elementwise_operands< VEC_EXT > rcpp_elementwise ; Minus_Vector_Primitive( const VEC_TYPE& lhs_, double rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_){} @@ -312,7 +340,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const VEC_EXT& lhs ; + typename Rcpp::traits::sugar_operand< VEC_EXT >::type lhs ; double rhs ; } ; @@ -328,6 +356,7 @@ namespace sugar{ typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::traits::Extractor::type VEC_EXT ; + typedef Rcpp::traits::elementwise_operands< VEC_EXT > rcpp_elementwise ; Minus_Primitive_Vector( STORAGE lhs_, const VEC_TYPE& rhs_ ) : lhs(lhs_), rhs(rhs_.get_ref()), lhs_na( Rcpp::traits::is_na(lhs_) ) {} @@ -340,7 +369,7 @@ namespace sugar{ private: STORAGE lhs ; - const VEC_EXT& rhs ; + typename Rcpp::traits::sugar_operand< VEC_EXT >::type rhs ; bool lhs_na ; } ; template @@ -349,6 +378,7 @@ namespace sugar{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::Extractor::type VEC_EXT ; + typedef Rcpp::traits::elementwise_operands< VEC_EXT > rcpp_elementwise ; Minus_Primitive_Vector( double lhs_, const VEC_TYPE& rhs_ ) : lhs(lhs_), rhs(rhs_.get_ref()){} @@ -360,7 +390,7 @@ namespace sugar{ private: double lhs ; - const VEC_EXT& rhs ; + typename Rcpp::traits::sugar_operand< VEC_EXT >::type rhs ; } ; @@ -372,6 +402,7 @@ namespace sugar{ typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::traits::Extractor::type VEC_EXT ; + typedef Rcpp::traits::elementwise_operands< VEC_EXT > rcpp_elementwise ; Minus_Primitive_Vector( STORAGE lhs_, const VEC_TYPE& rhs_ ) : lhs(lhs_), rhs(rhs_.get_ref()), lhs_na( Rcpp::traits::is_na(lhs_) ) {} @@ -385,7 +416,7 @@ namespace sugar{ private: STORAGE lhs ; - const VEC_EXT& rhs ; + typename Rcpp::traits::sugar_operand< VEC_EXT >::type rhs ; bool lhs_na ; } ; @@ -395,6 +426,7 @@ namespace sugar{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::Extractor::type VEC_EXT ; + typedef Rcpp::traits::elementwise_operands< VEC_EXT > rcpp_elementwise ; Minus_Primitive_Vector( double lhs_, const VEC_TYPE& rhs_ ) : lhs(lhs_), rhs(rhs_.get_ref()){} @@ -407,7 +439,7 @@ namespace sugar{ private: double lhs ; - const VEC_EXT& rhs ; + typename Rcpp::traits::sugar_operand< VEC_EXT >::type rhs ; } ; diff --git a/inst/include/Rcpp/sugar/operators/not.h b/inst/include/Rcpp/sugar/operators/not.h index f5505aab6..d584cbd1b 100644 --- a/inst/include/Rcpp/sugar/operators/not.h +++ b/inst/include/Rcpp/sugar/operators/not.h @@ -78,9 +78,10 @@ namespace sugar{ typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename traits::storage_type::type STORAGE ; typedef not_ OPERATOR ; + typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ; Not_Vector( const VEC_TYPE& lhs_ ) : - lhs(lhs_), op() {} + lhs(lhs_.get_ref()), op() {} inline STORAGE operator[]( R_xlen_t i ) const { return op.apply( lhs[i] ) ; @@ -89,7 +90,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const VEC_TYPE& lhs ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type lhs ; OPERATOR op ; } ; diff --git a/inst/include/Rcpp/sugar/operators/plus.h b/inst/include/Rcpp/sugar/operators/plus.h index 9434f4853..683239070 100644 --- a/inst/include/Rcpp/sugar/operators/plus.h +++ b/inst/include/Rcpp/sugar/operators/plus.h @@ -35,9 +35,12 @@ namespace sugar{ typedef typename Rcpp::traits::Extractor< RTYPE, LHS_NA, LHS_T>::type LHS_EXT ; typedef typename Rcpp::traits::Extractor< RTYPE, RHS_NA, RHS_T>::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Plus_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) {} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) { + check_sizes(lhs.size(), rhs.size()) ; + } inline STORAGE operator[]( R_xlen_t i ) const { STORAGE lhs_ = lhs[i] ; @@ -49,8 +52,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; // specialization of the above for REALSXP because : // NA_REAL + NA_REAL = NA_REAL @@ -65,9 +68,12 @@ namespace sugar{ typedef typename Rcpp::traits::Extractor::type LHS_EXT ; typedef typename Rcpp::traits::Extractor::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Plus_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) {} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) { + check_sizes(lhs.size(), rhs.size()) ; + } inline double operator[]( R_xlen_t i ) const { return lhs[i] + rhs[i] ; @@ -76,8 +82,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; @@ -93,9 +99,12 @@ namespace sugar{ typedef typename Rcpp::traits::Extractor< RTYPE, false, LHS_T>::type LHS_EXT ; typedef typename Rcpp::traits::Extractor< RTYPE, RHS_NA, RHS_T>::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Plus_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){ + check_sizes(lhs.size(), rhs.size()) ; + } inline STORAGE operator[]( R_xlen_t i ) const { STORAGE rhs_ = rhs[i] ; @@ -106,8 +115,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; // LHS_NA = false & RTYPE = REALSXP template @@ -119,9 +128,12 @@ namespace sugar{ typedef typename Rcpp::traits::Extractor::type LHS_EXT ; typedef typename Rcpp::traits::Extractor::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Plus_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){ + check_sizes(lhs.size(), rhs.size()) ; + } inline double operator[]( R_xlen_t i ) const { return lhs[i] + rhs[i] ; @@ -130,8 +142,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; @@ -146,9 +158,12 @@ namespace sugar{ typedef typename Rcpp::traits::Extractor< RTYPE, LHS_NA, LHS_T>::type LHS_EXT ; typedef typename Rcpp::traits::Extractor< RTYPE, false, RHS_T>::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Plus_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){ + check_sizes(lhs.size(), rhs.size()) ; + } inline STORAGE operator[]( R_xlen_t i ) const { STORAGE lhs_ = lhs[i] ; @@ -159,8 +174,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; // RHS_NA = false, RTYPE = REALSXP template @@ -172,9 +187,12 @@ namespace sugar{ typedef typename Rcpp::traits::Extractor::type LHS_EXT ; typedef typename Rcpp::traits::Extractor::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Plus_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){ + check_sizes(lhs.size(), rhs.size()) ; + } inline double operator[]( R_xlen_t i ) const { return lhs[i] + rhs[i] ; @@ -183,8 +201,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; @@ -200,9 +218,12 @@ namespace sugar{ typedef typename Rcpp::traits::Extractor< RTYPE, false, LHS_T>::type LHS_EXT ; typedef typename Rcpp::traits::Extractor< RTYPE, false, RHS_T>::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Plus_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){ + check_sizes(lhs.size(), rhs.size()) ; + } inline STORAGE operator[]( R_xlen_t i ) const { return lhs[i] + rhs[i]; @@ -211,8 +232,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; // specialization for RHS_NA = false and LHS_NA = false, RTYPE = REALSXP template @@ -224,9 +245,12 @@ namespace sugar{ typedef typename Rcpp::traits::Extractor::type LHS_EXT ; typedef typename Rcpp::traits::Extractor::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Plus_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){ + check_sizes(lhs.size(), rhs.size()) ; + } inline double operator[]( R_xlen_t i ) const { return lhs[i] + rhs[i] ; @@ -235,8 +259,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; @@ -252,6 +276,7 @@ namespace sugar{ typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::traits::Extractor< RTYPE, NA, T>::type EXT ; + typedef Rcpp::traits::elementwise_operands< EXT > rcpp_elementwise ; Plus_Vector_Primitive( const VEC_TYPE& lhs_, STORAGE rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_), rhs_na( Rcpp::traits::is_na(rhs_) ) @@ -266,7 +291,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const EXT& lhs ; + typename Rcpp::traits::sugar_operand< EXT >::type lhs ; STORAGE rhs ; bool rhs_na ; @@ -278,6 +303,7 @@ namespace sugar{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::Extractor< REALSXP, NA, T>::type EXT ; + typedef Rcpp::traits::elementwise_operands< EXT > rcpp_elementwise ; Plus_Vector_Primitive( const VEC_TYPE& lhs_, double rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_) @@ -290,7 +316,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const EXT& lhs ; + typename Rcpp::traits::sugar_operand< EXT >::type lhs ; double rhs ; } ; @@ -303,6 +329,7 @@ namespace sugar{ typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::traits::Extractor< RTYPE, false, T>::type EXT ; + typedef Rcpp::traits::elementwise_operands< EXT > rcpp_elementwise ; Plus_Vector_Primitive( const VEC_TYPE& lhs_, STORAGE rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_), rhs_na( Rcpp::traits::is_na(rhs_) ) {} @@ -314,7 +341,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const EXT& lhs ; + typename Rcpp::traits::sugar_operand< EXT >::type lhs ; STORAGE rhs ; bool rhs_na ; } ; @@ -326,6 +353,7 @@ namespace sugar{ typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::Extractor< REALSXP, false, T>::type EXT ; + typedef Rcpp::traits::elementwise_operands< EXT > rcpp_elementwise ; Plus_Vector_Primitive( const VEC_TYPE& lhs_, double rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_) {} @@ -337,7 +365,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const EXT& lhs ; + typename Rcpp::traits::sugar_operand< EXT >::type lhs ; double rhs ; } ; @@ -353,6 +381,7 @@ namespace sugar{ typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::traits::Extractor< RTYPE, NA, T>::type EXT ; + typedef Rcpp::traits::elementwise_operands< EXT > rcpp_elementwise ; Plus_Vector_Primitive_nona( const VEC_TYPE& lhs_, STORAGE rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_) @@ -366,7 +395,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const EXT& lhs ; + typename Rcpp::traits::sugar_operand< EXT >::type lhs ; STORAGE rhs ; } ; @@ -376,6 +405,7 @@ namespace sugar{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::Extractor::type EXT ; + typedef Rcpp::traits::elementwise_operands< EXT > rcpp_elementwise ; Plus_Vector_Primitive_nona( const VEC_TYPE& lhs_, double rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_) @@ -388,7 +418,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const EXT& lhs ; + typename Rcpp::traits::sugar_operand< EXT >::type lhs ; double rhs ; } ; @@ -402,6 +432,7 @@ namespace sugar{ typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::traits::Extractor< RTYPE, false, T>::type EXT ; + typedef Rcpp::traits::elementwise_operands< EXT > rcpp_elementwise ; Plus_Vector_Primitive_nona( const VEC_TYPE& lhs_, STORAGE rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_) {} @@ -413,7 +444,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const EXT& lhs ; + typename Rcpp::traits::sugar_operand< EXT >::type lhs ; STORAGE rhs ; } ; @@ -424,6 +455,7 @@ namespace sugar{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::Extractor< REALSXP, false, T>::type EXT ; + typedef Rcpp::traits::elementwise_operands< EXT > rcpp_elementwise ; Plus_Vector_Primitive_nona( const VEC_TYPE& lhs_, double rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_) {} @@ -435,7 +467,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const EXT& lhs ; + typename Rcpp::traits::sugar_operand< EXT >::type lhs ; double rhs ; } ; diff --git a/inst/include/Rcpp/sugar/operators/times.h b/inst/include/Rcpp/sugar/operators/times.h index 54dfe0449..8ce3e1e33 100644 --- a/inst/include/Rcpp/sugar/operators/times.h +++ b/inst/include/Rcpp/sugar/operators/times.h @@ -35,9 +35,11 @@ namespace sugar{ typedef typename Rcpp::traits::Extractor< RTYPE, LHS_NA, LHS_T>::type LHS_EXT ; typedef typename Rcpp::traits::Extractor< RTYPE, RHS_NA, RHS_T>::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Times_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) { + check_sizes(lhs.size(), rhs.size()) ; } inline STORAGE operator[]( R_xlen_t i ) const { @@ -50,8 +52,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; // RTYPE = REALSXP template @@ -63,9 +65,11 @@ namespace sugar{ typedef typename Rcpp::traits::Extractor::type LHS_EXT ; typedef typename Rcpp::traits::Extractor::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Times_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_.get_ref()) { + check_sizes(lhs.size(), rhs.size()) ; } inline double operator[]( R_xlen_t i ) const { @@ -75,8 +79,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; @@ -90,9 +94,12 @@ namespace sugar{ typedef typename Rcpp::traits::Extractor< RTYPE, false, LHS_T>::type LHS_EXT ; typedef typename Rcpp::traits::Extractor< RTYPE, RHS_NA, RHS_T>::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Times_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){ + check_sizes(lhs.size(), rhs.size()) ; + } inline STORAGE operator[]( R_xlen_t i ) const { STORAGE rhs_ = rhs[i] ; @@ -103,8 +110,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; // RTYPE = REALSXP template @@ -116,9 +123,12 @@ namespace sugar{ typedef typename Rcpp::traits::Extractor::type LHS_EXT ; typedef typename Rcpp::traits::Extractor::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Times_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){ + check_sizes(lhs.size(), rhs.size()) ; + } inline double operator[]( R_xlen_t i ) const { return lhs[i] * rhs[i] ; @@ -127,8 +137,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; @@ -142,9 +152,12 @@ namespace sugar{ typedef typename Rcpp::traits::Extractor< RTYPE, LHS_NA, LHS_T>::type LHS_EXT ; typedef typename Rcpp::traits::Extractor< RTYPE, false, RHS_T>::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Times_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){ + check_sizes(lhs.size(), rhs.size()) ; + } inline STORAGE operator[]( R_xlen_t i ) const { STORAGE lhs_ = lhs[i] ; @@ -155,8 +168,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; // RTYPE = REALSXP template @@ -168,9 +181,12 @@ namespace sugar{ typedef typename Rcpp::traits::Extractor::type LHS_EXT ; typedef typename Rcpp::traits::Extractor::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Times_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){ + check_sizes(lhs.size(), rhs.size()) ; + } inline double operator[]( R_xlen_t i ) const { return lhs[i] * rhs[i] ; @@ -179,8 +195,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; // specialization for RHS_NA = false and LHS_NA = false @@ -193,9 +209,12 @@ namespace sugar{ typedef typename Rcpp::traits::Extractor< RTYPE, false, LHS_T>::type LHS_EXT ; typedef typename Rcpp::traits::Extractor< RTYPE, false, RHS_T>::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Times_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){ + check_sizes(lhs.size(), rhs.size()) ; + } inline STORAGE operator[]( R_xlen_t i ) const { return lhs[i] * rhs[i]; @@ -204,8 +223,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; // RTYPE = REALSXP template @@ -217,9 +236,12 @@ namespace sugar{ typedef typename Rcpp::traits::Extractor::type LHS_EXT ; typedef typename Rcpp::traits::Extractor::type RHS_EXT ; + typedef Rcpp::traits::elementwise_operands< LHS_EXT, RHS_EXT > rcpp_elementwise ; Times_Vector_Vector( const LHS_TYPE& lhs_, const RHS_TYPE& rhs_ ) : - lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){} + lhs(lhs_.get_ref()), rhs(rhs_.get_ref()){ + check_sizes(lhs.size(), rhs.size()) ; + } inline double operator[]( R_xlen_t i ) const { return lhs[i] * rhs[i] ; @@ -228,8 +250,8 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const LHS_EXT& lhs ; - const RHS_EXT& rhs ; + typename Rcpp::traits::sugar_operand< LHS_EXT >::type lhs ; + typename Rcpp::traits::sugar_operand< RHS_EXT >::type rhs ; } ; @@ -240,6 +262,7 @@ namespace sugar{ typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::traits::Extractor< RTYPE, NA, T>::type EXT ; + typedef Rcpp::traits::elementwise_operands< EXT > rcpp_elementwise ; Times_Vector_Primitive( const VEC_TYPE& lhs_, STORAGE rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_), rhs_na( Rcpp::traits::is_na(rhs_) ) @@ -254,7 +277,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const EXT& lhs ; + typename Rcpp::traits::sugar_operand< EXT >::type lhs ; STORAGE rhs ; bool rhs_na ; } ; @@ -265,6 +288,7 @@ namespace sugar{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::Extractor::type EXT ; + typedef Rcpp::traits::elementwise_operands< EXT > rcpp_elementwise ; Times_Vector_Primitive( const VEC_TYPE& lhs_, double rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_) @@ -277,7 +301,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const EXT& lhs ; + typename Rcpp::traits::sugar_operand< EXT >::type lhs ; double rhs ; } ; @@ -289,6 +313,7 @@ namespace sugar{ typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::traits::Extractor< RTYPE, false, T>::type EXT ; + typedef Rcpp::traits::elementwise_operands< EXT > rcpp_elementwise ; Times_Vector_Primitive( const VEC_TYPE& lhs_, STORAGE rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_), rhs_na( Rcpp::traits::is_na(rhs_) ) {} @@ -300,7 +325,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const EXT& lhs ; + typename Rcpp::traits::sugar_operand< EXT >::type lhs ; STORAGE rhs ; bool rhs_na ; @@ -312,6 +337,7 @@ namespace sugar{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::Extractor::type EXT ; + typedef Rcpp::traits::elementwise_operands< EXT > rcpp_elementwise ; Times_Vector_Primitive( const VEC_TYPE& lhs_, double rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_) {} @@ -323,7 +349,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const EXT& lhs ; + typename Rcpp::traits::sugar_operand< EXT >::type lhs ; double rhs ; } ; @@ -339,6 +365,7 @@ namespace sugar{ typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::traits::Extractor< RTYPE, NA, T>::type EXT ; + typedef Rcpp::traits::elementwise_operands< EXT > rcpp_elementwise ; Times_Vector_Primitive_nona( const VEC_TYPE& lhs_, STORAGE rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_) @@ -352,7 +379,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const EXT& lhs ; + typename Rcpp::traits::sugar_operand< EXT >::type lhs ; STORAGE rhs ; } ; @@ -363,6 +390,7 @@ namespace sugar{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::Extractor::type EXT ; + typedef Rcpp::traits::elementwise_operands< EXT > rcpp_elementwise ; Times_Vector_Primitive_nona( const VEC_TYPE& lhs_, double rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_) @@ -375,7 +403,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const EXT& lhs ; + typename Rcpp::traits::sugar_operand< EXT >::type lhs ; double rhs ; } ; @@ -387,6 +415,7 @@ namespace sugar{ typedef typename traits::storage_type::type STORAGE ; typedef typename Rcpp::traits::Extractor< RTYPE, false, T>::type EXT ; + typedef Rcpp::traits::elementwise_operands< EXT > rcpp_elementwise ; Times_Vector_Primitive_nona( const VEC_TYPE& lhs_, STORAGE rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_) {} @@ -398,7 +427,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const EXT& lhs ; + typename Rcpp::traits::sugar_operand< EXT >::type lhs ; STORAGE rhs ; } ; @@ -408,6 +437,7 @@ namespace sugar{ public: typedef typename Rcpp::VectorBase VEC_TYPE ; typedef typename Rcpp::traits::Extractor::type EXT ; + typedef Rcpp::traits::elementwise_operands< EXT > rcpp_elementwise ; Times_Vector_Primitive_nona( const VEC_TYPE& lhs_, double rhs_ ) : lhs(lhs_.get_ref()), rhs(rhs_) {} @@ -419,7 +449,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const EXT& lhs ; + typename Rcpp::traits::sugar_operand< EXT >::type lhs ; double rhs ; } ; diff --git a/inst/include/Rcpp/sugar/operators/unary_minus.h b/inst/include/Rcpp/sugar/operators/unary_minus.h index df6c075c9..ee298e64e 100644 --- a/inst/include/Rcpp/sugar/operators/unary_minus.h +++ b/inst/include/Rcpp/sugar/operators/unary_minus.h @@ -90,9 +90,10 @@ namespace sugar{ typedef typename traits::storage_type::type STORAGE ; typedef typename unary_minus_result_type::type RESULT ; typedef unary_minus OPERATOR ; + typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ; UnaryMinus_Vector( const VEC_TYPE& lhs_ ) : - lhs(lhs_), op() {} + lhs(lhs_.get_ref()), op() {} inline RESULT operator[]( R_xlen_t i ) const { return op.apply( lhs[i] ) ; @@ -101,7 +102,7 @@ namespace sugar{ inline R_xlen_t size() const { return lhs.size() ; } private: - const VEC_TYPE& lhs ; + typename Rcpp::traits::sugar_operand< VEC_TYPE >::type lhs ; OPERATOR op ; } ; diff --git a/inst/include/Rcpp/sugar/sugar_forward.h b/inst/include/Rcpp/sugar/sugar_forward.h index bf78e6378..4981c4fbe 100644 --- a/inst/include/Rcpp/sugar/sugar_forward.h +++ b/inst/include/Rcpp/sugar/sugar_forward.h @@ -25,6 +25,9 @@ // traits #include +// tools +#include + // abstractions #include diff --git a/inst/include/Rcpp/sugar/tools/check_sizes.h b/inst/include/Rcpp/sugar/tools/check_sizes.h new file mode 100644 index 000000000..988d09f4b --- /dev/null +++ b/inst/include/Rcpp/sugar/tools/check_sizes.h @@ -0,0 +1,59 @@ +// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 4 -*- +// +// check_sizes.h: Rcpp R/C++ interface class library -- operand length checks +// +// Copyright (C) 2026 Kevin Ushey +// +// This file is part of Rcpp. +// +// Rcpp is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// Rcpp is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Rcpp. If not, see . + +#ifndef Rcpp__sugar__tools__check_sizes_h +#define Rcpp__sugar__tools__check_sizes_h + +namespace Rcpp{ +namespace sugar{ + + // Kept out of line: inlining the error path keeps the compiler from + // optimizing the loops that follow these checks. +#if defined(__GNUC__) + __attribute__((noinline, cold)) +#endif + inline void NORET stop_sizes(const char* fmt, R_xlen_t n1, R_xlen_t n2) { + stop(fmt, n1, n2); + } + + // Sugar doesn't recycle the way R does: the vectors an expression + // combines must all have the same length. + inline void check_sizes(R_xlen_t n1, R_xlen_t n2) { + if (n1 != n2) + stop_sizes("sugar operands have different lengths (%d and %d)", n1, n2); + } + + inline void check_sizes(R_xlen_t n1, R_xlen_t n2, R_xlen_t n3) { + check_sizes(n1, n2); + check_sizes(n1, n3); + } + + // Likewise, a vector assigned into a range, row or column must have the + // same length as that target. + inline void check_assign_size(R_xlen_t target, R_xlen_t value) { + if (target != value) + stop_sizes("cannot assign a vector of length %d to a target of length %d", value, target); + } + +} // sugar +} // Rcpp + +#endif diff --git a/inst/include/Rcpp/traits/is_elementwise.h b/inst/include/Rcpp/traits/is_elementwise.h new file mode 100644 index 000000000..7be36fd65 --- /dev/null +++ b/inst/include/Rcpp/traits/is_elementwise.h @@ -0,0 +1,129 @@ +// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 4 -*- +// +// is_elementwise.h: Rcpp R/C++ interface class library -- whether a sugar +// expression can be written in place into storage it may read from +// +// Copyright (C) 2026 Kevin Ushey +// +// This file is part of Rcpp. +// +// Rcpp is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// Rcpp is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Rcpp. If not, see . + +#ifndef Rcpp__traits__is_elementwise_h +#define Rcpp__traits__is_elementwise_h + +#include + +namespace Rcpp{ +namespace traits{ + + // Sugar expressions declare `typedef elementwise_operands<...> + // rcpp_elementwise` when their element i depends only on element i of + // those operands, all of which have the expression's length. + template + struct elementwise_operands {} ; + + // Views declare `typedef ... rcpp_view` with the kind of view they are. + struct range_view {} ; + struct column_view {} ; + struct row_view {} ; + + // Where an expression is being written, and so which views it may read + // while it is written in place. Reading a view of the target's own + // storage is harmless if the view always covers either exactly the + // target's positions or none of them: + // + // - a whole vector: given matching lengths, any view of its storage + // covers all of it; + // - a matrix column (row): any other column (row) of the same matrix is + // either the same one or disjoint from it; + // - a range: another range of the same vector may overlap it at an + // offset, so no views are allowed. + struct vector_target { + template struct reads : true_type {} ; + } ; + struct column_target { + template struct reads : same_type {} ; + } ; + struct row_target { + template struct reads : same_type {} ; + } ; + struct range_target { + template struct reads : false_type {} ; + } ; + + template + class _has_elementwise_marker_helper : __sfinae_types { + template static __one __test(typename U::rcpp_elementwise*); + template static __two __test(...); + public: + static const bool value = sizeof(__test(0)) == 1; + }; + + template + class _has_view_tag_helper : __sfinae_types { + template static __one __test(typename U::rcpp_view*); + template static __two __test(...); + public: + static const bool value = sizeof(__test(0)) == 1; + }; + + template + struct _operands_are_elementwise : false_type {} ; + + // Whether an expression can be written in place into TARGET even if it + // reads from TARGET's storage, i.e. whether it is elementwise. Vectors + // and matrices are; views are if TARGET allows them; sugar expressions + // are if they declare elementwise operands that are. Anything else is + // assumed not to be, and has to be evaluated before it is written. + template < + typename T, + typename TARGET, + bool = _has_storage_policy_helper::value, + bool = _has_elementwise_marker_helper::value, + bool = _has_view_tag_helper::value + > + struct is_elementwise : false_type {} ; + + template + struct is_elementwise : true_type {} ; + + template + struct is_elementwise : + _operands_are_elementwise {} ; + + template + struct is_elementwise : + TARGET::template reads {} ; + + // unused operand slots + template + struct is_elementwise : true_type {} ; + + template + struct is_elementwise< VectorBase, TARGET, false, false, false > : + is_elementwise {} ; + + template + struct _operands_are_elementwise< elementwise_operands, TARGET > : + integral_constant::value && + is_elementwise::value && + is_elementwise::value + > {} ; + +} // traits +} // Rcpp + +#endif diff --git a/inst/include/Rcpp/traits/sugar_operand.h b/inst/include/Rcpp/traits/sugar_operand.h new file mode 100644 index 000000000..e9e3802e3 --- /dev/null +++ b/inst/include/Rcpp/traits/sugar_operand.h @@ -0,0 +1,65 @@ +// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 4 -*- +// +// sugar_operand.h: Rcpp R/C++ interface class library -- how sugar +// expressions hold their operands +// +// Copyright (C) 2026 Kevin Ushey +// +// This file is part of Rcpp. +// +// Rcpp is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// Rcpp is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Rcpp. If not, see . + +#ifndef Rcpp__traits__sugar_operand_h +#define Rcpp__traits__sugar_operand_h + +namespace Rcpp{ +namespace traits{ + + // Objects with a storage policy (vectors, matrices, and classes derived + // from them) own an R object. + template + class _has_storage_policy_helper : __sfinae_types { + template static __one __test(typename U::Storage*); + template static __two __test(...); + public: + static const bool value = sizeof(__test(0)) == 1; + }; + + // Sugar expressions hold objects that own an R object by reference, but + // everything else (nested sugar expressions, and views such as + // MatrixColumn) by value. Those are usually temporaries, and holding + // them by reference leaves them dangling once the full-expression that + // created them ends, e.g. when an expression is stored in an `auto` + // variable. + template ::value> + struct sugar_operand { + typedef const T& type ; + } ; + + template + struct sugar_operand { + typedef const T type ; + } ; + + // Operands are often named by their CRTP base; hold the derived type. + template + struct sugar_operand< VectorBase, false > : sugar_operand {} ; + + template + struct sugar_operand< MatrixBase, false > : sugar_operand {} ; + +} // traits +} // Rcpp + +#endif diff --git a/inst/include/Rcpp/vector/MatrixBase.h b/inst/include/Rcpp/vector/MatrixBase.h index 13ce8dfce..880c55dbb 100644 --- a/inst/include/Rcpp/vector/MatrixBase.h +++ b/inst/include/Rcpp/vector/MatrixBase.h @@ -40,6 +40,10 @@ namespace Rcpp{ return static_cast(*this) ; } + const MATRIX& get_ref() const { + return static_cast(*this) ; + } + inline stored_type operator()( int i, int j) const { return static_cast(this)->operator()(i, j) ; } diff --git a/inst/include/Rcpp/vector/MatrixColumn.h b/inst/include/Rcpp/vector/MatrixColumn.h index ffd81721c..c453228c8 100644 --- a/inst/include/Rcpp/vector/MatrixColumn.h +++ b/inst/include/Rcpp/vector/MatrixColumn.h @@ -28,6 +28,7 @@ namespace Rcpp{ template class MatrixColumn : public VectorBase > { public: + typedef traits::column_view rcpp_view ; typedef Matrix MATRIX ; typedef typename MATRIX::Proxy Proxy ; typedef typename MATRIX::const_Proxy const_Proxy ; @@ -66,12 +67,22 @@ class MatrixColumn : public VectorBase > { template MatrixColumn& operator=( const Rcpp::VectorBase& rhs ){ + sugar::check_assign_size(n, rhs.size()) ; + + if( ! traits::is_elementwise::value ){ + // rhs may read from this column's matrix, so evaluate it first + const Vector tmp(rhs) ; + return operator=( tmp ) ; + } + const T& ref = rhs.get_ref() ; RCPP_LOOP_UNROLL(start,ref) return *this ; } MatrixColumn& operator=( const MatrixColumn& rhs ){ + sugar::check_assign_size(n, rhs.n) ; + iterator rhs_start = rhs.start ; RCPP_LOOP_UNROLL(start,rhs_start) return *this ; @@ -123,6 +134,7 @@ class MatrixColumn : public VectorBase > { template class ConstMatrixColumn : public VectorBase > { public: + typedef traits::column_view rcpp_view ; typedef Matrix MATRIX ; typedef typename MATRIX::const_Proxy const_Proxy ; typedef typename MATRIX::value_type value_type ; diff --git a/inst/include/Rcpp/vector/MatrixRow.h b/inst/include/Rcpp/vector/MatrixRow.h index 2a5945c16..9394254b6 100644 --- a/inst/include/Rcpp/vector/MatrixRow.h +++ b/inst/include/Rcpp/vector/MatrixRow.h @@ -28,6 +28,7 @@ namespace Rcpp{ template class MatrixRow : public VectorBase< RTYPE, true, MatrixRow > { public: + typedef traits::row_view rcpp_view ; typedef Matrix MATRIX ; typedef typename MATRIX::Proxy Proxy ; typedef typename MATRIX::Proxy reference ; @@ -153,6 +154,14 @@ class MatrixRow : public VectorBase< RTYPE, true, MatrixRow > { template MatrixRow& operator=( const Rcpp::VectorBase& rhs ){ + sugar::check_assign_size(size(), rhs.size()) ; + + if( ! traits::is_elementwise::value ){ + // rhs may read from this row's matrix, so evaluate it first + const Vector tmp(rhs) ; + return operator=( tmp ) ; + } + int n = size() ; const T& ref = rhs.get_ref() ; RCPP_LOOP_UNROLL_LHSFUN(start,get_parent_index,ref) @@ -160,6 +169,8 @@ class MatrixRow : public VectorBase< RTYPE, true, MatrixRow > { } MatrixRow& operator=( const MatrixRow& rhs ){ + sugar::check_assign_size(size(), rhs.size()) ; + int n = size() ; RCPP_LOOP_UNROLL_LHSFUN(start,get_parent_index,rhs) return *this ; @@ -216,6 +227,7 @@ class MatrixRow : public VectorBase< RTYPE, true, MatrixRow > { template class ConstMatrixRow : public VectorBase< RTYPE, true, ConstMatrixRow > { public: + typedef traits::row_view rcpp_view ; typedef Matrix MATRIX ; typedef typename MATRIX::const_Proxy const_reference ; typedef typename MATRIX::value_type value_type ; diff --git a/inst/include/Rcpp/vector/RangeIndexer.h b/inst/include/Rcpp/vector/RangeIndexer.h index e67600b3e..ec2a000df 100644 --- a/inst/include/Rcpp/vector/RangeIndexer.h +++ b/inst/include/Rcpp/vector/RangeIndexer.h @@ -24,6 +24,13 @@ #define Rcpp__vector__RangeIndexer_h #define UNROLL_LOOP(OP) \ + ::Rcpp::sugar::check_assign_size(size_, x.size()) ; \ + if( ! ::Rcpp::traits::is_elementwise::value ){ \ + /* x may read from the vector this range */ \ + /* indexes, so evaluate it first */ \ + const Vector tmp(x) ; \ + return operator OP ( tmp ) ; \ + } \ typedef typename ::Rcpp::traits::Extractor::type EXT ; \ const EXT& input( x.get_ref() ) ; \ R_xlen_t __trip_count = (size_) >> 2; \ @@ -53,17 +60,27 @@ namespace internal{ template class RangeIndexer : public VectorBase > { public: + typedef traits::range_view rcpp_view ; typedef typename VECTOR::Proxy Proxy ; typedef typename VECTOR::iterator iterator ; RangeIndexer( VECTOR& vec_, const Rcpp::Range& range_) : start(vec_.begin() + range_.get_start() ), size_( range_.size() ) {} + RangeIndexer( const RangeIndexer& other ) : + start(other.start), size_(other.size_) {} + template RangeIndexer& operator=( const Rcpp::VectorBase& x){ UNROLL_LOOP(=) } + // without this, assigning one range to another would use the implicit + // copy assignment, which rebinds this range instead of copying elements + RangeIndexer& operator=( const RangeIndexer& x ){ + return operator=( static_cast&>(x) ) ; + } + template RangeIndexer& operator+=( const Rcpp::VectorBase& x){ UNROLL_LOOP(+=) diff --git a/inst/include/Rcpp/vector/Subsetter.h b/inst/include/Rcpp/vector/Subsetter.h index 8f97561a7..53233f1b6 100644 --- a/inst/include/Rcpp/vector/Subsetter.h +++ b/inst/include/Rcpp/vector/Subsetter.h @@ -110,16 +110,28 @@ class SubsetProxy { SubsetProxy& operator=(const SubsetProxy& other) { if (other.indices_n == 1) { + // a single source element is only ever overwritten with itself for (R_xlen_t i=0; i < indices_n; ++i) { lhs[ indices[i] ] = other.lhs[other.indices[0]]; } } - else if (indices_n == other.indices_n) { - for (R_xlen_t i=0; i < indices_n; ++i) - lhs[ indices[i] ] = other.lhs[other.indices[i]]; + else if (indices_n != other.indices_n) { + stop("index error"); + } + else if (lhs.get__() == other.lhs.get__()) { + // both subsets index the same vector, so a source element may + // be overwritten before it is read; copy the source elements + // first + Vector tmp = no_init(other.indices_n); + for (R_xlen_t i=0; i < other.indices_n; ++i) { + tmp[i] = other.lhs[other.indices[i]]; } + return *this = tmp; + } else { - stop("index error"); + for (R_xlen_t i=0; i < indices_n; ++i) { + lhs[ indices[i] ] = other.lhs[other.indices[i]]; + } } return *this; } @@ -238,7 +250,7 @@ class SubsetProxy { Vector operator __OPERATOR__ ( \ const SubsetProxy& other) { \ - Vector result(indices_n); \ + Vector result = no_init(indices_n); \ if (other.indices_n == 1) { \ for (R_xlen_t i = 0; i < indices_n; ++i) \ result[i] = lhs[indices[i]] __OPERATOR__ other.lhs[other.indices[0]]; \ diff --git a/inst/include/Rcpp/vector/Vector.h b/inst/include/Rcpp/vector/Vector.h index bfb78106c..d8f6ed4e8 100644 --- a/inst/include/Rcpp/vector/Vector.h +++ b/inst/include/Rcpp/vector/Vector.h @@ -1051,8 +1051,15 @@ class Vector : inline void assign_sugar_expression( const T& x ) { R_xlen_t n = size() ; if( n == x.size() ){ - // just copy the data - import_expression(x, n ) ; + // write into the existing storage; an expression that isn't + // elementwise may read from this vector (e.g. `x = rev(x)`), so + // evaluate it first + if( traits::is_elementwise::value ){ + import_expression(x, n ) ; + } else { + const Vector< T::r_type::value > tmp(x) ; + import_expression< Vector< T::r_type::value > >(tmp, n ) ; + } } else{ // different size, so we change the memory Shield wrapped(wrap(x)); diff --git a/inst/include/RcppCommon.h b/inst/include/RcppCommon.h index ea23f5e82..996fad61b 100644 --- a/inst/include/RcppCommon.h +++ b/inst/include/RcppCommon.h @@ -172,6 +172,8 @@ namespace Rcpp { #include #include +#include +#include #include #include diff --git a/inst/tinytest/cpp/Subset.cpp b/inst/tinytest/cpp/Subset.cpp index d8bd0d620..fc7f2cb72 100644 --- a/inst/tinytest/cpp/Subset.cpp +++ b/inst/tinytest/cpp/Subset.cpp @@ -102,6 +102,31 @@ NumericVector subset_assign_vector_size_1(NumericVector x, int i) { return x; } +// [[Rcpp::export]] +NumericVector subset_assign_alias(NumericVector x) { + // overlapping subsets of the same vector + x[IntegerVector::create(1, 2)] = x[IntegerVector::create(0, 1)]; + return x; +} + +// [[Rcpp::export]] +CharacterVector subset_assign_alias_string(CharacterVector x) { + x[IntegerVector::create(1, 2)] = x[IntegerVector::create(0, 1)]; + return x; +} + +// [[Rcpp::export]] +NumericVector subset_assign_alias_disjoint(NumericVector x) { + x[IntegerVector::create(0, 1)] = x[IntegerVector::create(2, 3)]; + return x; +} + +// [[Rcpp::export]] +NumericVector subset_assign_alias_single(NumericVector x) { + x[IntegerVector::create(0, 1, 2)] = x[IntegerVector::create(2)]; + return x; +} + // [[Rcpp::export]] NumericVector subset_sugar_add(NumericVector x, IntegerVector y) { diff --git a/inst/tinytest/cpp/sugar_expressions.cpp b/inst/tinytest/cpp/sugar_expressions.cpp new file mode 100644 index 000000000..e7ca5635b --- /dev/null +++ b/inst/tinytest/cpp/sugar_expressions.cpp @@ -0,0 +1,374 @@ +// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 8 -*- +// +// sugar_expressions.cpp: Rcpp R/C++ interface class library -- sugar +// expression lifetime, aliasing, and operand length unit tests +// +// Copyright (C) 2026 Kevin Ushey +// +// This file is part of Rcpp. +// +// Rcpp is free software: you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 2 of the License, or +// (at your option) any later version. +// +// Rcpp is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Rcpp. If not, see . + +#include +using namespace Rcpp; + +// Overwrite the stack where any destroyed temporaries used to live, so that +// an expression still referring to them reads garbage. +#if defined(__GNUC__) +__attribute__((noinline)) +#endif +void clobber_stack() { + volatile char buffer[16384]; + for (size_t i = 0; i < sizeof(buffer); i++) + buffer[i] = 0x7f; +} + +// [[Rcpp::export]] +NumericVector lifetime_arith(NumericVector x) { + auto e = x + x * 2.0; + clobber_stack(); + return e; +} + +// [[Rcpp::export]] +NumericVector lifetime_unary(NumericVector x) { + auto e = -(x * 2.0); + clobber_stack(); + return e; +} + +// [[Rcpp::export]] +NumericVector lifetime_math(NumericVector x) { + auto e = sqrt(x * 4.0); + clobber_stack(); + return e; +} + +// [[Rcpp::export]] +LogicalVector lifetime_compare(NumericVector x) { + auto e = (x * 2.0) > (x + 1.0); + clobber_stack(); + return e; +} + +// [[Rcpp::export]] +NumericVector lifetime_ifelse(NumericVector x) { + auto e = ifelse(x > 1.0, x * 10.0, x * 0.0); + clobber_stack(); + return e; +} + +// [[Rcpp::export]] +NumericVector lifetime_rev(NumericVector x) { + auto e = rev(x * 2.0); + clobber_stack(); + return e; +} + +// [[Rcpp::export]] +NumericVector lifetime_rep_scalar() { + auto e = rep(2.5, 3); + clobber_stack(); + return e; +} + +// [[Rcpp::export]] +NumericVector lifetime_pmax(NumericVector x) { + auto e = pmax(x * 2.0, x + 1.0); + clobber_stack(); + return e; +} + +// [[Rcpp::export]] +double lifetime_sum(NumericVector x) { + auto e = sum(x * 2.0); + clobber_stack(); + return e; +} + +// [[Rcpp::export]] +NumericVector lifetime_column(NumericMatrix m) { + auto e = m(_, 0) + 1.0; + clobber_stack(); + return e; +} + +// [[Rcpp::export]] +NumericVector lifetime_dnorm(NumericVector x) { + auto e = dnorm(x * 1.0, 0.0, 1.0); + clobber_stack(); + return e; +} + +// [[Rcpp::export]] +NumericVector alias_rev(NumericVector x) { + x = rev(x); + return x; +} + +// [[Rcpp::export]] +NumericVector alias_rev_copy(NumericVector x) { + NumericVector y = x; + y = rev(x); + return y; +} + +// [[Rcpp::export]] +NumericVector alias_mixed(NumericVector x) { + x = x + rev(x); + return x; +} + +// [[Rcpp::export]] +NumericVector alias_sapply(NumericVector x) { + x = sapply(x, [&](double v) { return v - x[0]; }); + return x; +} + +// [[Rcpp::export]] +NumericVector alias_elementwise(NumericVector x) { + x = x * 2.0 + x; + return x; +} + +// [[Rcpp::export]] +NumericVector alias_range_shift(NumericVector x) { + R_xlen_t n = x.size(); + x[Range(1, n - 1)] = head(x, n - 1); + return x; +} + +// [[Rcpp::export]] +NumericVector alias_range_range(NumericVector x) { + R_xlen_t n = x.size(); + x[Range(1, n - 1)] = x[Range(0, n - 2)]; + return x; +} + +// [[Rcpp::export]] +NumericVector alias_range_range_add(NumericVector x) { + R_xlen_t n = x.size(); + x[Range(1, n - 1)] += x[Range(0, n - 2)]; + return x; +} + +// [[Rcpp::export]] +NumericVector alias_range_rev(NumericVector x) { + R_xlen_t n = x.size(); + x[Range(0, n - 1)] = rev(x); + return x; +} + +// [[Rcpp::export]] +NumericVector alias_range_add_rev(NumericVector x) { + R_xlen_t n = x.size(); + x[Range(0, n - 1)] += rev(x); + return x; +} + +// [[Rcpp::export]] +NumericMatrix alias_column_rev(NumericMatrix m) { + m(_, 0) = rev(m(_, 0)); + return m; +} + +// [[Rcpp::export]] +NumericMatrix alias_row_rev(NumericMatrix m) { + m(0, _) = rev(m(0, _)); + return m; +} + +// [[Rcpp::export]] +NumericMatrix alias_column_scale(NumericMatrix m) { + for (int j = 0; j < m.ncol(); j++) + m(_, j) = m(_, j) * 2.0; + return m; +} + +// [[Rcpp::export]] +NumericMatrix alias_row_scale(NumericMatrix m) { + for (int i = 0; i < m.nrow(); i++) + m(i, _) = m(i, _) * 2.0; + return m; +} + +// [[Rcpp::export]] +NumericMatrix alias_row_from_column(NumericMatrix m) { + m(2, _) = m(_, 0) * 1.0; + return m; +} + +// [[Rcpp::export]] +NumericMatrix alias_column_from_row(NumericMatrix m) { + m(_, 2) = m(0, _) * 1.0; + return m; +} + +typedef traits::vector_target VT; +typedef traits::column_target CT; +typedef traits::row_target RT; +typedef traits::range_target GT; + +// [[Rcpp::export]] +LogicalVector elementwise_flags(NumericVector x, NumericMatrix m) { + // copy into locals, since binding the static `value` members by + // reference would require them to have definitions + bool vector = traits::is_elementwise::value; + bool arith = traits::is_elementwise::value; + bool math = traits::is_elementwise::value; + bool if_else = traits::is_elementwise 0.0, x, -x)), GT>::value; + bool reversed = traits::is_elementwise::value; + bool arith_rev = traits::is_elementwise::value; + bool first = traits::is_elementwise::value; + bool column_vector = traits::is_elementwise::value; + bool column_column = traits::is_elementwise::value; + bool column_row = traits::is_elementwise::value; + bool row_row = traits::is_elementwise::value; + bool row_column = traits::is_elementwise::value; + bool range_range = traits::is_elementwise::value; + bool sequence = traits::is_elementwise::value; + + return LogicalVector::create( + _["vector"] = vector, + _["arith"] = arith, + _["math"] = math, + _["ifelse"] = if_else, + _["rev"] = reversed, + _["arith_rev"] = arith_rev, + _["head"] = first, + _["column_vector"] = column_vector, + _["column_column"] = column_column, + _["column_row"] = column_row, + _["row_row"] = row_row, + _["row_column"] = row_column, + _["range_range"] = range_range, + _["seq"] = sequence + ); +} + +// [[Rcpp::export]] +NumericVector length_plus(NumericVector x, NumericVector y) { + return x + y; +} + +// [[Rcpp::export]] +NumericVector length_plus_scalar(NumericVector x) { + return x + 1.0; +} + +// [[Rcpp::export]] +LogicalVector length_compare(NumericVector x, NumericVector y) { + return x < y; +} + +// [[Rcpp::export]] +LogicalVector length_and(LogicalVector x, LogicalVector y) { + return x & y; +} + +// [[Rcpp::export]] +NumericVector length_pmax(NumericVector x, NumericVector y) { + return pmax(x, y); +} + +// [[Rcpp::export]] +NumericVector length_ifelse(LogicalVector cond, NumericVector x, NumericVector y) { + return ifelse(cond, x, y); +} + +// [[Rcpp::export]] +NumericVector length_range(NumericVector x, NumericVector y) { + x[Range(0, 2)] = y; + return x; +} + +// [[Rcpp::export]] +NumericVector length_range_range(NumericVector x) { + x[Range(0, 1)] = x[Range(0, 3)]; + return x; +} + +// [[Rcpp::export]] +NumericMatrix length_column(NumericMatrix m, NumericVector y) { + m(_, 0) = y; + return m; +} + +// [[Rcpp::export]] +NumericMatrix length_row(NumericMatrix m, NumericVector y) { + m(0, _) = y; + return m; +} + +// [[Rcpp::export]] +SEXP single_and(LogicalVector a, LogicalVector b) { + return all(a) && all(b); +} + +// [[Rcpp::export]] +SEXP single_or(LogicalVector a, LogicalVector b) { + return all(a) || all(b); +} + +// [[Rcpp::export]] +SEXP single_not(LogicalVector a) { + return !all(a); +} + +// [[Rcpp::export]] +SEXP single_and_nona_lhs(LogicalVector a, LogicalVector b) { + return all(noNA(a)) && all(b); +} + +// [[Rcpp::export]] +SEXP single_and_nona_rhs(LogicalVector a, LogicalVector b) { + return all(a) && all(noNA(b)); +} + +// [[Rcpp::export]] +SEXP single_and_nona_both(LogicalVector a, LogicalVector b) { + return all(noNA(a)) && all(noNA(b)); +} + +// [[Rcpp::export]] +SEXP single_or_nona_lhs(LogicalVector a, LogicalVector b) { + return all(noNA(a)) || all(b); +} + +// [[Rcpp::export]] +SEXP single_or_nona_rhs(LogicalVector a, LogicalVector b) { + return all(a) || all(noNA(b)); +} + +// [[Rcpp::export]] +SEXP single_or_nona_both(LogicalVector a, LogicalVector b) { + return all(noNA(a)) || all(noNA(b)); +} + +// [[Rcpp::export]] +SEXP single_and_bool(LogicalVector a, bool b) { + return all(a) && b; +} + +// [[Rcpp::export]] +SEXP single_or_bool(LogicalVector a, bool b) { + return b || all(a); +} + +// [[Rcpp::export]] +SEXP single_stored(LogicalVector a, LogicalVector b) { + auto e = !(all(a) && any(b)); + clobber_stack(); + return e; +} diff --git a/inst/tinytest/test_subset.R b/inst/tinytest/test_subset.R index 526a9f131..d7e6f09a2 100644 --- a/inst/tinytest/test_subset.R +++ b/inst/tinytest/test_subset.R @@ -65,6 +65,13 @@ expect_error(subset_assign_subset5(1:6), info = "index error") expect_identical(subset_assign_vector_size_1(1:6,7), c(7,7,7,4,5,6)) +## assigning between subsets of the same vector reads every source element +## before any is overwritten +expect_identical(subset_assign_alias(c(1, 2, 3)), c(1, 1, 2), info = "x[1:2] = x[0:1]") +expect_identical(subset_assign_alias_string(c("a", "b", "c")), c("a", "a", "b"), info = "x[1:2] = x[0:1], strings") +expect_identical(subset_assign_alias_disjoint(c(1, 2, 3, 4)), c(3, 4, 3, 4), info = "x[0:1] = x[2:3]") +expect_identical(subset_assign_alias_single(c(1, 2, 3)), c(3, 3, 3), info = "x[0:2] = x[2]") + x <- rnorm(10) y <- sample(10, 5) expect_identical(subset_sugar_add(x, y - 1L), x[y] + x[y]) diff --git a/inst/tinytest/test_sugar.R b/inst/tinytest/test_sugar.R index 1115dced7..66b283f77 100644 --- a/inst/tinytest/test_sugar.R +++ b/inst/tinytest/test_sugar.R @@ -22,6 +22,7 @@ if (Sys.getenv("RunAllRcppTests") != "yes") exit_file("Set 'RunAllRcppTests' to Rcpp::sourceCpp("cpp/sugar.cpp") Rcpp::sourceCpp("cpp/sugar_safe_math.cpp") Rcpp::sourceCpp("cpp/sugar_safe_math_fallback.cpp") +Rcpp::sourceCpp("cpp/sugar_expressions.cpp") ## There are some (documented, see https://blog.r-project.org/2020/11/02/will-r-work-on-apple-silicon/index.html) ## issues with NA propagation on arm64 / macOS. We not (yet ?) do anything special so we just skip some tests @@ -1704,3 +1705,109 @@ expect_equal(intmin(c(1:10)), 1L, info = "min(integer(...))") expect_equal(doublemin(1.0*c(1:10)), 1.0, info = "min(numeric(...))") expect_equal(intmax(c(1:10)), 10L, info = "min(integer(...))") expect_equal(doublemax(1.0*c(1:10)), 10.0, info = "min(numeric(...))") + + +## sugar expressions hold nested expressions by value, so they remain valid +## when stored (e.g. in an `auto` variable) past the full-expression that +## created them +x <- c(1, 2, 3) +expect_equal(lifetime_arith(x), x + x * 2, info = "auto: x + x * 2") +expect_equal(lifetime_unary(x), -(x * 2), info = "auto: -(x * 2)") +expect_equal(lifetime_math(x), sqrt(x * 4), info = "auto: sqrt(x * 4)") +expect_equal(lifetime_compare(x), (x * 2) > (x + 1), info = "auto: (x * 2) > (x + 1)") +expect_equal(lifetime_ifelse(x), ifelse(x > 1, x * 10, x * 0), info = "auto: ifelse()") +expect_equal(lifetime_rev(x), rev(x * 2), info = "auto: rev(x * 2)") +expect_equal(lifetime_rep_scalar(), rep(2.5, 3), info = "auto: rep(2.5, 3)") +expect_equal(lifetime_pmax(x), pmax(x * 2, x + 1), info = "auto: pmax()") +expect_equal(lifetime_sum(x), sum(x * 2), info = "auto: sum(x * 2)") +m <- matrix(c(1, 2, 3, 4, 5, 6), 3) +expect_equal(lifetime_column(m), m[, 1] + 1, info = "auto: m(_, 0) + 1") +expect_equal(lifetime_dnorm(x), dnorm(x), info = "auto: dnorm(x * 1)") + +## same-length assignment writes into the existing storage, so an expression +## that reads from the target has to be evaluated before it is written. The +## writes also modify the argument itself, hence the fresh copies. +x <- function() c(1, 2, 3, 4, 5) +expect_equal(alias_rev(x()), rev(x()), info = "x = rev(x)") +expect_equal(alias_rev_copy(x()), rev(x()), info = "y = x; y = rev(x)") +expect_equal(alias_mixed(x()), x() + rev(x()), info = "x = x + rev(x)") +expect_equal(alias_sapply(x()), x() - x()[1], info = "x = sapply(x, )") +expect_equal(alias_elementwise(x()), x() * 2 + x(), info = "x = x * 2 + x") +expect_equal(alias_range_shift(x()), c(1, 1, 2, 3, 4), info = "x[1:n-1] = head(x, n-1)") +expect_equal(alias_range_range(x()), c(1, 1, 2, 3, 4), info = "x[1:n-1] = x[0:n-2]") +expect_equal(alias_range_range_add(x()), c(1, 3, 5, 7, 9), info = "x[1:n-1] += x[0:n-2]") +expect_equal(alias_range_rev(x()), rev(x()), info = "x[0:n-1] = rev(x)") +expect_equal(alias_range_add_rev(x()), x() + rev(x()), info = "x[0:n-1] += rev(x)") +m <- function() matrix(c(1, 2, 3, 4, 5, 6), 3) +expect_equal(alias_column_rev(m())[, 1], rev(m()[, 1]), info = "m(_, 0) = rev(m(_, 0))") +m <- function() matrix(c(1, 2, 3, 4, 5, 6), 2) +expect_equal(alias_row_rev(m())[1, ], rev(m()[1, ]), info = "m(0, _) = rev(m(0, _))") + +## assignment still happens in place, keeping attributes +x <- function() c(a = 1, b = 2, c = 3) +expect_equal(names(alias_rev(x())), names(x()), info = "x = rev(x) keeps names") +expect_equal(names(alias_elementwise(x())), names(x()), info = "x = x * 2 + x keeps names") + +## views of the target's own matrix can be read in place when they cover the +## same positions or disjoint ones (a column from columns, a row from rows) +m <- function() matrix(as.numeric(1:9), 3) +expect_equal(alias_column_scale(m()), m() * 2, info = "m(_, j) = m(_, j) * 2") +expect_equal(alias_row_scale(m()), m() * 2, info = "m(i, _) = m(i, _) * 2") +expect_equal(alias_row_from_column(m())[3, ], m()[, 1], info = "m(2, _) = m(_, 0) * 1") +expect_equal(alias_column_from_row(m())[, 3], m()[1, ], info = "m(_, 2) = m(0, _) * 1") + +## which expressions are written in place, depending on the target +flags <- elementwise_flags(c(1, 2, 3), matrix(1, 2, 2)) +expect_equal( + flags, + c(vector = TRUE, arith = TRUE, math = TRUE, ifelse = TRUE, + rev = FALSE, arith_rev = FALSE, head = FALSE, + column_vector = TRUE, column_column = TRUE, column_row = FALSE, + row_row = TRUE, row_column = FALSE, range_range = FALSE, seq = TRUE), + info = "traits::is_elementwise" +) + +## sugar doesn't recycle: the vectors combined by an expression, and a vector +## assigned into a range, row or column, must have matching lengths +expect_equal(length_plus(c(1, 2), c(10, 20)), c(11, 22), info = "x + y, same length") +expect_equal(length_plus(numeric(), numeric()), numeric(), info = "x + y, both empty") +expect_equal(length_plus_scalar(c(1, 2)), c(2, 3), info = "x + scalar") +expect_error(length_plus(c(1, 2, 3, 4, 5), c(10, 20)), "different lengths", info = "x + ") +expect_error(length_plus(c(1, 2), c(10, 20, 30, 40)), "different lengths", info = "x + ") +expect_error(length_compare(c(1, 2, 3), c(1, 2)), "different lengths", info = "x < y") +expect_error(length_and(c(TRUE, FALSE), TRUE), "different lengths", info = "x & y") +expect_error(length_pmax(c(1, 2, 3), c(1, 2)), "different lengths", info = "pmax(x, y)") +expect_error(length_ifelse(c(TRUE, FALSE), c(1, 2), c(1, 2, 3)), "different lengths", info = "ifelse(c, x, y)") + +expect_equal(length_range(c(1, 2, 3, 4, 5), c(7, 8, 9)), c(7, 8, 9, 4, 5), info = "x[0:2] = y") +expect_error(length_range(c(1, 2, 3, 4, 5), c(7, 8)), "cannot assign", info = "x[0:2] = ") +expect_error(length_range(c(1, 2, 3, 4, 5), c(6, 7, 8, 9)), "cannot assign", info = "x[0:2] = ") +expect_error(length_range_range(c(1, 2, 3, 4, 5)), "cannot assign", info = "x[0:1] = x[0:3]") +expect_error(length_column(matrix(1, 3, 2), c(7, 8)), "cannot assign", info = "m(_, 0) = ") +expect_error(length_row(matrix(1, 3, 2), c(7, 8, 9)), "cannot assign", info = "m(0, _) = ") + +## &&, || and ! on single logical results (e.g. all(), any()) follow R's +## three-valued logic +vals <- c(TRUE, FALSE, NA) +for (a in vals) { + expect_identical(single_not(a), !a, info = sprintf("!%s", a)) + for (b in vals) { + expect_identical(single_and(a, b), a && b, info = sprintf("%s && %s", a, b)) + expect_identical(single_or(a, b), a || b, info = sprintf("%s || %s", a, b)) + if (!is.na(a)) { + expect_identical(single_and_nona_lhs(a, b), a && b, info = sprintf("noNA(%s) && %s", a, b)) + expect_identical(single_or_nona_lhs(a, b), a || b, info = sprintf("noNA(%s) || %s", a, b)) + } + if (!is.na(b)) { + expect_identical(single_and_nona_rhs(a, b), a && b, info = sprintf("%s && noNA(%s)", a, b)) + expect_identical(single_or_nona_rhs(a, b), a || b, info = sprintf("%s || noNA(%s)", a, b)) + expect_identical(single_and_bool(a, b), a && b, info = sprintf("%s && ", a, b)) + expect_identical(single_or_bool(a, b), b || a, info = sprintf(" || %s", b, a)) + } + if (!is.na(a) && !is.na(b)) { + expect_identical(single_and_nona_both(a, b), a && b, info = sprintf("noNA(%s) && noNA(%s)", a, b)) + expect_identical(single_or_nona_both(a, b), a || b, info = sprintf("noNA(%s) || noNA(%s)", a, b)) + } + } +} +expect_identical(single_stored(c(TRUE, TRUE), c(FALSE, TRUE)), FALSE, info = "auto: !(all(a) && any(b))") diff --git a/vignettes/rmd/Rcpp-sugar.Rmd b/vignettes/rmd/Rcpp-sugar.Rmd index 9384b78a9..e568880eb 100644 --- a/vignettes/rmd/Rcpp-sugar.Rmd +++ b/vignettes/rmd/Rcpp-sugar.Rmd @@ -191,7 +191,8 @@ arithmetic expression must be of the same type (for example they should be both The lhs and the rhs can either have the same size or one of them could be a primitive value of the appropriate type, for example adding a -`NumericVector` and a `double`. +`NumericVector` and a `double`. Unlike \proglang{R}, \sugar does not recycle +vectors of different sizes; see the section on expressions and assignment. ## Binary logical operators @@ -518,6 +519,69 @@ functions (\textsl{i.e.} you) should place an \code{RNGScope} at the appropriate level of your code. +# Expressions and assignment + +\sugar expressions are evaluated lazily: `x + y` builds an object describing +the computation, and its elements are only computed when the expression is +assigned to a vector or otherwise consumed, for example by `sum()`. + +## Operand lengths + +Unlike \proglang{R}, \sugar does not recycle: the vectors combined by an +expression must all have the same length, and an error is signalled +otherwise. Likewise, a vector assigned into a range, row or column (as in +`m(_, 0) = x`) must have the length of that target. Single values, like the +`2.0` in `x + 2.0`, can be combined with vectors of any length. + +## Storing expressions + +An expression holds the vectors it reads by reference, and any nested +expressions by value. It can be stored, for example in an `auto` variable, +and evaluated later, as long as the vectors it reads are still alive: + +```cpp +NumericVector x, y; + +// fine: x and y outlive e +auto e = x * 2.0 + y; +NumericVector z = e; +``` + +An expression reading from a temporary vector, however, has to be +evaluated in the statement that creates it: + +```cpp +// wrong: the clone is destroyed at the end of +// the statement, while e still refers to it +auto e = clone(x) + 1.0; + +// fine +NumericVector z = clone(x) + 1.0; +``` + +## Assignment + +Assigning an expression to an existing vector of the same length writes the +result into that vector's storage. As with any modification made through an +\pkg{Rcpp} vector, this is visible through every other reference to the same +\proglang{R} object, including the argument passed in from \proglang{R}: + +```cpp +// [[Rcpp::export]] +void twice(NumericVector x) { + // modifies the caller's vector + x = x * 2.0; +} +``` + +When the lengths differ, a new vector is allocated instead. + +An expression may read from the vector it is assigned to, as in +`x = rev(x)`. Expressions whose elements only depend on the corresponding +elements of their operands (arithmetic, comparisons, mathematical functions, +`ifelse()`, and so on) are written directly; others are first evaluated into +a temporary vector. + # Performance \label{sec:performance} @@ -658,7 +722,7 @@ public: RESULT_R_TYPE>::type STORAGE; Sapply(const VEC& vec_, Function fun_) : - vec(vec_), fun(fun_){} + vec(vec_.get_ref()), fun(fun_){} inline STORAGE operator[]( int i ) const { return converter_type::get(fun(vec[i])); @@ -669,7 +733,7 @@ public: } private: - const VEC& vec; + typename Rcpp::traits::sugar_operand::type vec; Function fun; }; @@ -801,18 +865,22 @@ is the manifestation of the _CRTP_. The constructor of the `Sapply` class template is straightforward, it -simply consists of holding the reference to the input expression and the -function. +simply consists of holding the input expression and the function. ```cpp Sapply(const VEC& vec_, Function fun_): - vec(vec_), fun(fun_){} + vec(vec_.get_ref()), fun(fun_){} private: - const VEC& vec; + typename Rcpp::traits::sugar_operand::type vec; Function fun; ``` +The input is held through `sugar_operand`: by reference when it is a vector, +and by value when it is itself a \sugar expression. Those are typically +temporaries, so holding them by reference would leave `Sapply` referring to +destroyed objects once the statement that created it ends. + ### Implementation The indexing operator and the `size` member function is what @@ -830,6 +898,13 @@ inline int size() const { } ``` +Expressions whose $i^{\text{th}}$ element only depends on the +$i^{\text{th}}$ elements of their operands can say so by declaring +`typedef Rcpp::traits::elementwise_operands rcpp_elementwise`, which +lets them be written in place when assigned to one of those operands. +`Sapply` does not, since the function it applies may read any element of +the vector being assigned to. + # Summary TBD