Skip to content

Commit 0f3e317

Browse files
fix sugar expression lifetimes, aliased assignment, and operand lengths (#1513)
* hold nested sugar expressions and views by value Sugar nodes held every operand by const reference, so an expression kept past the full-expression that built it (e.g. in an auto variable) referred to destroyed temporaries. Nodes now hold nested expressions and views by value, and only objects that own an R object (vectors, matrices) by reference. Part of #1512. * evaluate non-elementwise sugar before writing it in place Assigning a same-length sugar expression to a vector, or any expression to a range, matrix row or matrix column, writes into existing storage while the expression is still being read. When the expression read from that storage at other positions (e.g. `x = rev(x)`, `x[Range(1, n - 1)] = head(x, n - 1)`), the result was silently wrong. Elementwise nodes now declare themselves via a nested `rcpp_elementwise` type; those are still written in place, and everything else is evaluated into a temporary first. Part of #1512. * check that sugar operands have matching lengths Sugar operations on two or more vectors took their length from one operand and never compared it with the others, so a shorter operand was read past its end and a longer one was silently truncated. Likewise for vectors assigned into a range, matrix row or matrix column. These now signal an error, matching the documented requirement that operands have the same size. Part of #1512. * let rows and columns read matching views in place Evaluating every expression that reads a view into a temporary made updates like `m(_, j) = m(_, j) * 2` several times slower. Whether reading a view in place is safe depends on where the result is written: a column can read other columns of the same matrix (they coincide or are disjoint), a row other rows, and a whole vector any view, but a range can't read another range. Sugar expressions now list their elementwise operands, views declare what kind of view they are, and each write site checks the expression against its own kind of target. Part of #1512. * keep sugar length-check errors out of line With the error path inlined, the compiler could no longer propagate constants into the loops following these checks (e.g. `m(_, j) = m(_, j) * 2.0` lost its constant multiplier and vectorized half as wide). * document sugar operand lengths, lifetimes, and assignment * update NEWS * fix !, &&, and || on single logical results None of `!all(x)`, `all(x) && any(y)`, `all(x) || any(y)`, `all(x) && true` or `all(x) || true` compiled: the combinators called the non-const get() through const references, the && and || overloads for two results declared their second parameter with the first one's template arguments (so they could never be deduced), and Or_SingleLogicalResult_bool named the And class as its CRTP base. The combinators now hold their operands by value, like other sugar expressions, and the general && and || follow R's three-valued logic (NA && FALSE is FALSE, NA || TRUE is TRUE). * update NEWS * route range-to-range assignment through the aliasing checks Also mark Range as elementwise, include sugar_operand.h from is_elementwise.h, and drop stale FIXME comments in ifelse.h. * read subset elements before writing when both index the same vector * index lapply operands through VectorBase so vectors yield their stored type Holding the operand as the derived vector type made lapply() pass a proxy (e.g. const_string_proxy for character vectors) to the function, which no longer converted to a const CharacterVector& argument. Seen as a compile failure in the touch package. * update ChangeLog * enable the sugar length checks in development versions only Twelve CRAN packages rely on a longer sugar operand being cut short, so an unconditional error would block the release until all of them update. Derive RCPP_SUGAR_LENGTH_CHECKS from the version in config.h: on when the fourth component is non-zero (development snapshots, which is what reverse-dependency checks run against) and off in releases. Defining the macro before including Rcpp.h overrides the default. The tests check for the errors only when enabled, and for the truncation otherwise. --------- Co-authored-by: Dirk Eddelbuettel <edd@debian.org>
1 parent 96a8b95 commit 0f3e317

80 files changed

Lines changed: 1742 additions & 445 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎ChangeLog‎

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,56 @@
1+
2026-10-09 Kevin Ushey <kevinushey@gmail.com>
2+
3+
* inst/include/Rcpp/config.h: Define RCPP_SUGAR_LENGTH_CHECKS, on for
4+
development versions and off for releases unless overridden
5+
* inst/include/Rcpp/sugar/tools/check_sizes.h: Compile the length checks
6+
out when RCPP_SUGAR_LENGTH_CHECKS is 0
7+
* inst/tinytest/cpp/sugar_expressions.cpp: Report whether the checks are
8+
enabled
9+
* inst/tinytest/test_sugar.R: Test the length errors only when enabled,
10+
and the truncation otherwise
11+
* vignettes/rmd/Rcpp-sugar.Rmd: Document when the lengths are checked
12+
* inst/NEWS.Rd: Idem
13+
14+
* inst/include/Rcpp/sugar/functions/lapply.h: Index the operand through
15+
VectorBase so vectors yield their stored type rather than a proxy
16+
* inst/tinytest/cpp/sugar.cpp: Add a test
17+
* inst/tinytest/test_sugar.R: Idem
18+
19+
2026-09-30 Kevin Ushey <kevinushey@gmail.com>
20+
21+
* inst/include/Rcpp/traits/sugar_operand.h: New trait for how sugar
22+
expressions hold their operands: vectors by reference, and nested
23+
expressions and views by value, so stored expressions don't dangle
24+
* inst/include/Rcpp/traits/is_elementwise.h: New trait for whether a
25+
sugar expression can be written in place into storage it may read from
26+
* inst/include/Rcpp/sugar/tools/check_sizes.h: New helpers checking that
27+
sugar operands, and vectors assigned into views, have matching lengths
28+
* inst/include/RcppCommon.h: Include the above
29+
* inst/include/Rcpp/sugar/sugar_forward.h: Idem
30+
* inst/include/Rcpp/sugar/: Hold operands via sugar_operand, declare
31+
elementwise operands, and check operand lengths
32+
* inst/include/Rcpp/stats/dpq/dpq.h: Idem
33+
* inst/include/Rcpp/sugar/block/SugarBlock_3.h: Also fix the type of the
34+
third operand
35+
* inst/include/Rcpp/sugar/logical/and.h: Fix operator&& on two single
36+
logical results, hold their operands by value, and make NA && FALSE
37+
return FALSE
38+
* inst/include/Rcpp/sugar/logical/or.h: Idem for operator||, making
39+
NA || TRUE return TRUE, and fix the base class of Or_SingleLogicalResult_bool
40+
* inst/include/Rcpp/sugar/logical/not.h: Hold the operand of operator!
41+
by value
42+
* inst/include/Rcpp/sugar/logical/SingleLogicalResult.h: Add get_ref()
43+
* inst/include/Rcpp/vector/Vector.h: Evaluate sugar expressions that
44+
aren't elementwise before assigning them in place
45+
* inst/include/Rcpp/vector/RangeIndexer.h: Idem, and check lengths
46+
* inst/include/Rcpp/vector/MatrixColumn.h: Idem
47+
* inst/include/Rcpp/vector/MatrixRow.h: Idem
48+
* inst/include/Rcpp/vector/MatrixBase.h: Add a const get_ref()
49+
* inst/tinytest/cpp/sugar_expressions.cpp: New tests
50+
* inst/tinytest/test_sugar.R: Idem
51+
* vignettes/rmd/Rcpp-sugar.Rmd: Document operand lengths, storing
52+
expressions, and assignment
53+
154
2026-10-12 Kevin Ushey <kevinushey@gmail.com>
255

356
* inst/include/Rcpp/vector/traits.h: Update copyright

‎inst/NEWS.Rd‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,22 @@
2727
warnings (Iñaki in \ghpr{1508} closing \ghit{1497})
2828
\item The \code{col} constructor now uses \code{nrow} in an
2929
initialization (Iñaki in \ghpr{1509})
30+
\item Sugar expressions hold nested expressions by value so they can be
31+
stored, and evaluate expressions that may read the target before
32+
assigning them in place (Kevin in \ghpr{1513} closing \ghit{1512}).
33+
Same-length assignment of an expression that is not elementwise, such
34+
as \code{x = rev(x)}, now goes through a temporary vector.
35+
\item Development versions check that sugar operands, and vectors
36+
assigned into a range, row or column, have matching lengths, and signal
37+
an error otherwise; releases do not check, and the define
38+
\code{RCPP_SUGAR_LENGTH_CHECKS} overrides the default (Kevin in
39+
\ghpr{1513})
40+
\item Assignment between overlapping subsets of the same vector, as in
41+
\code{x[i] = x[j]}, reads the source elements before writing (Kevin in
42+
\ghpr{1513})
43+
\item The sugar operators \code{!}, \code{&&} and \code{||} on single
44+
logical results such as \code{all()} now compile, and follow R's
45+
handling of \code{NA} (Kevin in \ghpr{1513})
3046
\item Bounds-checked element access is faster, \code{size()} of
3147
atomic vectors uses the cached length, and \code{ncol()} no longer
3248
reads the \code{dim} attribute; object layouts are unchanged, as

‎inst/include/Rcpp/config.h‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,18 @@
3333
#define RCPP_DEV_VERSION RcppDevVersion(1,1,2,4)
3434
#define RCPP_DEV_VERSION_STRING "1.1.2.4"
3535

36+
// Whether sugar checks that the operands of an expression, and a vector
37+
// assigned into a range, row or column, have matching lengths. On by default
38+
// in development versions (a non-zero fourth version component), so that
39+
// reverse-dependency checks catch mismatches; off in releases, so that
40+
// packages on CRAN are not affected. Define RCPP_SUGAR_LENGTH_CHECKS as 1 or
41+
// 0 before including Rcpp.h to override.
42+
#ifndef RCPP_SUGAR_LENGTH_CHECKS
43+
# if (RCPP_DEV_VERSION % 100) != 0
44+
# define RCPP_SUGAR_LENGTH_CHECKS 1
45+
# else
46+
# define RCPP_SUGAR_LENGTH_CHECKS 0
47+
# endif
48+
#endif
49+
3650
#endif

‎inst/include/Rcpp/stats/dpq/dpq.h‎

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,10 @@ class D0 : public Rcpp::VectorBase< REALSXP, NA, D0<RTYPE,NA,T> > {
3535
public:
3636
typedef typename Rcpp::VectorBase<RTYPE,NA,T> VEC_TYPE ;
3737
typedef double (*FunPtr)(double,int) ;
38+
typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ;
3839

3940
D0( FunPtr ptr_, const VEC_TYPE& vec_, bool log_ ) :
40-
ptr(ptr_), vec(vec_), log(log_) {}
41+
ptr(ptr_), vec(vec_.get_ref()), log(log_) {}
4142

4243
inline double operator[]( R_xlen_t i) const {
4344
return ptr( vec[i], log );
@@ -47,7 +48,7 @@ class D0 : public Rcpp::VectorBase< REALSXP, NA, D0<RTYPE,NA,T> > {
4748

4849
private:
4950
FunPtr ptr ;
50-
const VEC_TYPE& vec;
51+
typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec;
5152
int log;
5253
};
5354

@@ -56,9 +57,10 @@ class D1 : public Rcpp::VectorBase< REALSXP, NA, D1<RTYPE,NA,T> > {
5657
public:
5758
typedef typename Rcpp::VectorBase<RTYPE,NA,T> VEC_TYPE ;
5859
typedef double (*FunPtr)(double,double,int) ;
60+
typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ;
5961

6062
D1( FunPtr ptr_, const VEC_TYPE& vec_, double p0_ , bool log_) :
61-
ptr(ptr_), vec(vec_), p0(p0_), log(log_) {}
63+
ptr(ptr_), vec(vec_.get_ref()), p0(p0_), log(log_) {}
6264

6365
inline double operator[]( R_xlen_t i) const {
6466
return ptr( vec[i], p0, log );
@@ -68,7 +70,7 @@ class D1 : public Rcpp::VectorBase< REALSXP, NA, D1<RTYPE,NA,T> > {
6870

6971
private:
7072
FunPtr ptr ;
71-
const VEC_TYPE& vec;
73+
typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec;
7274
double p0 ;
7375
int log;
7476
} ;
@@ -78,9 +80,10 @@ class D2 : public Rcpp::VectorBase< REALSXP, NA, D2<RTYPE,NA,T> > {
7880
public:
7981
typedef typename Rcpp::VectorBase<RTYPE,NA,T> VEC_TYPE ;
8082
typedef double (*FunPtr)(double,double,double,int) ;
83+
typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ;
8184

8285
D2( FunPtr ptr_, const VEC_TYPE& vec_, double p0_, double p1_ , bool log_) :
83-
ptr(ptr_), vec(vec_), p0(p0_), p1(p1_), log(log_) {}
86+
ptr(ptr_), vec(vec_.get_ref()), p0(p0_), p1(p1_), log(log_) {}
8487

8588
inline double operator[]( R_xlen_t i) const {
8689
return ptr( vec[i], p0, p1, log );
@@ -90,7 +93,7 @@ class D2 : public Rcpp::VectorBase< REALSXP, NA, D2<RTYPE,NA,T> > {
9093

9194
private:
9295
FunPtr ptr ;
93-
const VEC_TYPE& vec;
96+
typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec;
9497
double p0, p1 ;
9598
int log;
9699
} ;
@@ -100,9 +103,10 @@ class D3 : public Rcpp::VectorBase< REALSXP, NA, D3<RTYPE,NA,T> > {
100103
public:
101104
typedef typename Rcpp::VectorBase<RTYPE,NA,T> VEC_TYPE ;
102105
typedef double (*FunPtr)(double,double,double,double,int) ;
106+
typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ;
103107

104108
D3( FunPtr ptr_, const VEC_TYPE& vec_, double p0_, double p1_, double p2_ , bool log_ ) :
105-
ptr(ptr_), vec(vec_), p0(p0_), p1(p1_), p2(p2_), log(log_) {}
109+
ptr(ptr_), vec(vec_.get_ref()), p0(p0_), p1(p1_), p2(p2_), log(log_) {}
106110

107111
inline double operator[]( R_xlen_t i) const {
108112
return ptr( vec[i], p0, p1, p2, log );
@@ -112,7 +116,7 @@ class D3 : public Rcpp::VectorBase< REALSXP, NA, D3<RTYPE,NA,T> > {
112116

113117
private:
114118
FunPtr ptr ;
115-
const VEC_TYPE& vec;
119+
typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec;
116120
double p0, p1, p2 ;
117121
int log;
118122
} ;
@@ -125,10 +129,11 @@ class P0 : public Rcpp::VectorBase< REALSXP, NA, P0<RTYPE,NA,T> >{
125129
public:
126130
typedef typename Rcpp::VectorBase<RTYPE,NA,T> VEC_TYPE ;
127131
typedef double (*FunPtr)(double,int,int) ;
132+
typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ;
128133

129134
P0( FunPtr ptr_, const VEC_TYPE& vec_,
130135
bool lower_tail = true, bool log_ = false ) :
131-
ptr(ptr_), vec(vec_), lower(lower_tail), log(log_) {}
136+
ptr(ptr_), vec(vec_.get_ref()), lower(lower_tail), log(log_) {}
132137

133138
inline double operator[]( R_xlen_t i) const {
134139
return ptr( vec[i], lower, log );
@@ -138,7 +143,7 @@ class P0 : public Rcpp::VectorBase< REALSXP, NA, P0<RTYPE,NA,T> >{
138143

139144
private:
140145
FunPtr ptr ;
141-
const VEC_TYPE& vec;
146+
typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec;
142147
int lower, log;
143148

144149
};
@@ -149,10 +154,11 @@ class P1 : public Rcpp::VectorBase< REALSXP, NA, P1<RTYPE,NA,T> >{
149154
public:
150155
typedef typename Rcpp::VectorBase<RTYPE,NA,T> VEC_TYPE ;
151156
typedef double (*FunPtr)(double,double,int,int) ;
157+
typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ;
152158

153159
P1( FunPtr ptr_, const VEC_TYPE& vec_, double p0_,
154160
bool lower_tail = true, bool log_ = false ) :
155-
ptr(ptr_), vec(vec_), p0(p0_), lower(lower_tail), log(log_) {}
161+
ptr(ptr_), vec(vec_.get_ref()), p0(p0_), lower(lower_tail), log(log_) {}
156162

157163
inline double operator[]( R_xlen_t i) const {
158164
return ptr( vec[i], p0, lower, log );
@@ -162,7 +168,7 @@ class P1 : public Rcpp::VectorBase< REALSXP, NA, P1<RTYPE,NA,T> >{
162168

163169
private:
164170
FunPtr ptr ;
165-
const VEC_TYPE& vec;
171+
typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec;
166172
double p0 ;
167173
int lower, log;
168174

@@ -174,10 +180,11 @@ class P2 : public Rcpp::VectorBase< REALSXP, NA, P2<RTYPE,NA,T> >{
174180
public:
175181
typedef typename Rcpp::VectorBase<RTYPE,NA,T> VEC_TYPE ;
176182
typedef double (*FunPtr)(double,double,double,int,int) ;
183+
typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ;
177184

178185
P2( FunPtr ptr_, const VEC_TYPE& vec_, double p0_, double p1_,
179186
bool lower_tail = true, bool log_ = false ) :
180-
ptr(ptr_), vec(vec_), p0(p0_), p1(p1_), lower(lower_tail), log(log_) {}
187+
ptr(ptr_), vec(vec_.get_ref()), p0(p0_), p1(p1_), lower(lower_tail), log(log_) {}
181188

182189
inline double operator[]( R_xlen_t i) const {
183190
return ptr( vec[i], p0, p1, lower, log );
@@ -187,7 +194,7 @@ class P2 : public Rcpp::VectorBase< REALSXP, NA, P2<RTYPE,NA,T> >{
187194

188195
private:
189196
FunPtr ptr ;
190-
const VEC_TYPE& vec;
197+
typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec;
191198
double p0, p1 ;
192199
int lower, log;
193200
};
@@ -197,10 +204,11 @@ class P3 : public Rcpp::VectorBase< REALSXP, NA, P3<RTYPE,NA,T> >{
197204
public:
198205
typedef typename Rcpp::VectorBase<RTYPE,NA,T> VEC_TYPE ;
199206
typedef double (*FunPtr)(double,double,double,double,int,int) ;
207+
typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ;
200208

201209
P3( FunPtr ptr_, const VEC_TYPE& vec_, double p0_, double p1_, double p2_,
202210
bool lower_tail = true, bool log_ = false ) :
203-
ptr(ptr_), vec(vec_), p0(p0_), p1(p1_), p2(p2_), lower(lower_tail), log(log_) {}
211+
ptr(ptr_), vec(vec_.get_ref()), p0(p0_), p1(p1_), p2(p2_), lower(lower_tail), log(log_) {}
204212

205213
inline double operator[]( R_xlen_t i) const {
206214
return ptr( vec[i], p0, p1, p2, lower, log );
@@ -210,7 +218,7 @@ class P3 : public Rcpp::VectorBase< REALSXP, NA, P3<RTYPE,NA,T> >{
210218

211219
private:
212220
FunPtr ptr ;
213-
const VEC_TYPE& vec;
221+
typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec;
214222
double p0, p1,p2 ;
215223
int lower, log;
216224

@@ -223,10 +231,11 @@ class Q0 : public Rcpp::VectorBase< REALSXP, NA, Q0<RTYPE,NA,T> >{
223231
public:
224232
typedef typename Rcpp::VectorBase<RTYPE,NA,T> VEC_TYPE ;
225233
typedef double (*FunPtr)(double,int,int) ;
234+
typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ;
226235

227236
Q0( FunPtr ptr_, const VEC_TYPE& vec_,
228237
bool lower_tail = true, bool log_ = false ) :
229-
ptr(ptr_), vec(vec_), lower(lower_tail), log(log_) {}
238+
ptr(ptr_), vec(vec_.get_ref()), lower(lower_tail), log(log_) {}
230239

231240
inline double operator[]( R_xlen_t i) const {
232241
return ptr( vec[i], lower, log );
@@ -236,7 +245,7 @@ class Q0 : public Rcpp::VectorBase< REALSXP, NA, Q0<RTYPE,NA,T> >{
236245

237246
private:
238247
FunPtr ptr ;
239-
const VEC_TYPE& vec;
248+
typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec;
240249
int lower, log;
241250

242251
};
@@ -246,10 +255,11 @@ class Q1 : public Rcpp::VectorBase< REALSXP, NA, Q1<RTYPE,NA,T> >{
246255
public:
247256
typedef typename Rcpp::VectorBase<RTYPE,NA,T> VEC_TYPE ;
248257
typedef double (*FunPtr)(double,double,int,int) ;
258+
typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ;
249259

250260
Q1( FunPtr ptr_, const VEC_TYPE& vec_, double p0_,
251261
bool lower_tail = true, bool log_ = false ) :
252-
ptr(ptr_), vec(vec_), p0(p0_), lower(lower_tail), log(log_) {}
262+
ptr(ptr_), vec(vec_.get_ref()), p0(p0_), lower(lower_tail), log(log_) {}
253263

254264
inline double operator[]( R_xlen_t i) const {
255265
return ptr( vec[i], p0, lower, log );
@@ -259,7 +269,7 @@ class Q1 : public Rcpp::VectorBase< REALSXP, NA, Q1<RTYPE,NA,T> >{
259269

260270
private:
261271
FunPtr ptr ;
262-
const VEC_TYPE& vec;
272+
typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec;
263273
double p0 ;
264274
int lower, log;
265275

@@ -270,10 +280,11 @@ class Q2 : public Rcpp::VectorBase< REALSXP, NA, Q2<RTYPE,NA,T> >{
270280
public:
271281
typedef typename Rcpp::VectorBase<RTYPE,NA,T> VEC_TYPE ;
272282
typedef double (*FunPtr)(double,double,double,int,int) ;
283+
typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ;
273284

274285
Q2( FunPtr ptr_, const VEC_TYPE& vec_, double p0_, double p1_,
275286
bool lower_tail = true, bool log_ = false ) :
276-
ptr(ptr_), vec(vec_), p0(p0_), p1(p1_), lower(lower_tail), log(log_) {}
287+
ptr(ptr_), vec(vec_.get_ref()), p0(p0_), p1(p1_), lower(lower_tail), log(log_) {}
277288

278289
inline double operator[]( R_xlen_t i) const {
279290
return ptr( vec[i], p0, p1, lower, log );
@@ -283,7 +294,7 @@ class Q2 : public Rcpp::VectorBase< REALSXP, NA, Q2<RTYPE,NA,T> >{
283294

284295
private:
285296
FunPtr ptr ;
286-
const VEC_TYPE& vec;
297+
typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec;
287298
double p0, p1 ;
288299
int lower, log;
289300

@@ -294,10 +305,11 @@ class Q3 : public Rcpp::VectorBase< REALSXP, NA, Q3<RTYPE,NA,T> >{
294305
public:
295306
typedef typename Rcpp::VectorBase<RTYPE,NA,T> VEC_TYPE ;
296307
typedef double (*FunPtr)(double,double,double,double,int,int) ;
308+
typedef Rcpp::traits::elementwise_operands< VEC_TYPE > rcpp_elementwise ;
297309

298310
Q3( FunPtr ptr_, const VEC_TYPE& vec_, double p0_, double p1_, double p2_,
299311
bool lower_tail = true, bool log_ = false ) :
300-
ptr(ptr_), vec(vec_), p0(p0_), p1(p1_), p2(p2_), lower(lower_tail), log(log_) {}
312+
ptr(ptr_), vec(vec_.get_ref()), p0(p0_), p1(p1_), p2(p2_), lower(lower_tail), log(log_) {}
301313

302314
inline double operator[]( R_xlen_t i) const {
303315
return ptr( vec[i], p0, p1, p2, lower, log );
@@ -307,7 +319,7 @@ class Q3 : public Rcpp::VectorBase< REALSXP, NA, Q3<RTYPE,NA,T> >{
307319

308320
private:
309321
FunPtr ptr ;
310-
const VEC_TYPE& vec;
322+
typename Rcpp::traits::sugar_operand< VEC_TYPE >::type vec;
311323
double p0, p1, p2 ;
312324
int lower, log;
313325
};

‎inst/include/Rcpp/sugar/Range.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ namespace Rcpp{
2727

2828
class Range : public VectorBase<INTSXP,false, Range >{
2929
public:
30+
typedef traits::elementwise_operands<> rcpp_elementwise ;
31+
3032
Range( R_xlen_t start_, R_xlen_t end__ ) : start(start_), end_(end__){
3133
if( start_ > end__ ){
3234
throw std::range_error( "upper value must be greater than lower value" ) ;

‎inst/include/Rcpp/sugar/block/SugarBlock_1.h‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ template <bool NA, typename RESULT_TYPE, typename U1, typename T1>
2929
class SugarBlock_1 : public Rcpp::VectorBase< Rcpp::traits::r_sexptype_traits<RESULT_TYPE>::rtype , NA, SugarBlock_1<NA,RESULT_TYPE,U1,T1> > {
3030
public:
3131
typedef RESULT_TYPE (*FunPtr)(U1) ;
32-
SugarBlock_1( FunPtr ptr_, const T1 & vec_) : ptr(ptr_), vec(vec_){}
32+
typedef Rcpp::traits::elementwise_operands< T1 > rcpp_elementwise ;
33+
SugarBlock_1( FunPtr ptr_, const T1 & vec_) : ptr(ptr_), vec(vec_.get_ref()){}
3334

3435
inline RESULT_TYPE operator[]( R_xlen_t i) const {
3536
return ptr( vec[i] ) ;
@@ -38,7 +39,7 @@ class SugarBlock_1 : public Rcpp::VectorBase< Rcpp::traits::r_sexptype_traits<RE
3839

3940
private:
4041
FunPtr ptr ;
41-
const T1& vec ;
42+
typename Rcpp::traits::sugar_operand< T1 >::type vec ;
4243
};
4344

4445
} // sugar

0 commit comments

Comments
 (0)