1 // -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*-
2 //
3 // Subsetter.h: Rcpp R/C++ interface class library -- vector subsetting
4 //
5 // Copyright (C) 2014  Dirk Eddelbuettel, Romain Francois and Kevin Ushey
6 //
7 // This file is part of Rcpp.
8 //
9 // Rcpp is free software: you can redistribute it and/or modify it
10 // under the terms of the GNU General Public License as published by
11 // the Free Software Foundation, either version 2 of the License, or
12 // (at your option) any later version.
13 //
14 // Rcpp is distributed in the hope that it will be useful, but
15 // WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License for more details.
18 //
19 // You should have received a copy of the GNU General Public License
20 // along with Rcpp.  If not, see <http://www.gnu.org/licenses/>.
21 
22 #ifndef Rcpp_vector_Subsetter_h_
23 #define Rcpp_vector_Subsetter_h_
24 
25 #include <limits>
26 
27 namespace Rcpp {
28 
29 template <
30     int RTYPE, template <class> class StoragePolicy,
31     int RHS_RTYPE, bool RHS_NA, typename RHS_T
32 >
33 class SubsetProxy {
34 
35     typedef Vector<RTYPE, StoragePolicy> LHS_t;
36     typedef Vector<RHS_RTYPE, StoragePolicy> RHS_t;
37 
38 public:
39 
SubsetProxy(LHS_t & lhs_,const RHS_t & rhs_)40     SubsetProxy(LHS_t& lhs_, const RHS_t& rhs_):
41         lhs(lhs_), rhs(rhs_), lhs_n(lhs.size()), rhs_n(rhs.size()) {
42         get_indices( traits::identity< traits::int2type<RHS_RTYPE> >() );
43     }
44 
SubsetProxy(const SubsetProxy & other)45     SubsetProxy(const SubsetProxy& other):
46         lhs(other.lhs),
47         rhs(other.rhs),
48         lhs_n(other.lhs_n),
49         rhs_n(other.rhs_n),
50         indices(other.indices),
51         indices_n(other.indices_n) {}
52 
53     // Enable e.g. x[y] = z
54     template <int OtherRTYPE, template <class> class OtherStoragePolicy>
55     SubsetProxy& operator=(const Vector<OtherRTYPE, OtherStoragePolicy>& other) {
56         R_xlen_t n = other.size();
57 
58         if (n == 1) {
59             for (R_xlen_t i=0; i < indices_n; ++i) {
60                 lhs[ indices[i] ] = other[0];
61             }
62         } else if (n == indices_n) {
63             for (R_xlen_t i=0; i < n; ++i) {
64                 lhs[ indices[i] ] = other[i];
65             }
66         } else {
67             stop("index error");
68         }
69         return *this;
70     }
71 
72     // Enable e.g. x[y] = 1;
73     // TODO: std::enable_if<primitive> with C++11
74     SubsetProxy& operator=(double other) {
75         for (R_xlen_t i=0; i < indices_n; ++i) {
76             lhs[ indices[i] ] = other;
77         }
78         return *this;
79     }
80 
81     SubsetProxy& operator=(int other) {
82         for (R_xlen_t i=0; i < indices_n; ++i) {
83             lhs[ indices[i] ] = other;
84         }
85         return *this;
86     }
87 
88     SubsetProxy& operator=(const char* other) {
89         for (R_xlen_t i=0; i < indices_n; ++i) {
90             lhs[ indices[i] ] = other;
91         }
92         return *this;
93     }
94 
95     SubsetProxy& operator=(bool other) {
96         for (R_xlen_t i=0; i < indices_n; ++i) {
97             lhs[ indices[i] ] = other;
98         }
99         return *this;
100     }
101 
102     template <int RTYPE_OTHER, template <class> class StoragePolicyOther,int RHS_RTYPE_OTHER, bool RHS_NA_OTHER, typename RHS_T_OTHER>
103     SubsetProxy& operator=(const SubsetProxy<RTYPE_OTHER, StoragePolicyOther, RHS_RTYPE_OTHER, RHS_NA_OTHER, RHS_T_OTHER>& other) {
104 
105         Vector<RTYPE_OTHER, StoragePolicyOther> other_vec = other;
106         *this = other_vec;
107         return *this;
108     }
109 
110     SubsetProxy& operator=(const SubsetProxy& other) {
111         if (other.indices_n == 1) {
112             for (R_xlen_t i=0; i < indices_n; ++i) {
113                 lhs[ indices[i] ] = other.lhs[other.indices[0]];
114             }
115         }
116         else if (indices_n == other.indices_n) {
117             for (R_xlen_t i=0; i < indices_n; ++i)
118                 lhs[ indices[i] ] = other.lhs[other.indices[i]];
119             }
120         else {
121             stop("index error");
122         }
123         return *this;
124     }
125 
126     operator Vector<RTYPE, StoragePolicy>() const {
127         return get_vec();
128     }
129 
SEXP()130     operator SEXP() const {
131         return wrap( get_vec() );
132     }
133 
134 private:
135 
136     #ifndef RCPP_NO_BOUNDS_CHECK
137     template <typename IDX>
check_indices(IDX * x,R_xlen_t n,R_xlen_t size)138     void check_indices(IDX* x, R_xlen_t n, R_xlen_t size) {
139         for (IDX i=0; i < n; ++i) {
140             if (x[i] < 0 or x[i] >= size) {
141                 if(std::numeric_limits<IDX>::is_integer && size > std::numeric_limits<IDX>::max()) {
142                     stop("use NumericVector to index an object of length %td", size);
143                 }
144                 stop("index error");
145             }
146         }
147     }
148     #else
149     template <typename IDX>
150     void check_indices(IDX* x, IDX n, IDX size) {}
151     #endif
152 
get_indices(traits::identity<traits::int2type<INTSXP>> t)153     void get_indices( traits::identity< traits::int2type<INTSXP> > t ) {
154         indices.reserve(rhs_n);
155         int* ptr = INTEGER(rhs); // ok to use int * here, we'll catch any problems inside check_indices
156         check_indices(ptr, rhs_n, lhs_n);
157         for (R_xlen_t i=0; i < rhs_n; ++i) {
158             indices.push_back( rhs[i] );
159         }
160         indices_n = rhs_n;
161     }
162 
get_indices(traits::identity<traits::int2type<REALSXP>> t)163     void get_indices( traits::identity< traits::int2type<REALSXP> > t ) {
164         indices.reserve(rhs_n);
165         std::vector<R_xlen_t> tmp(rhs.size()); // create temp R_xlen_t type indices from reals
166         for(size_t i = 0 ; i < tmp.size() ; ++i) {
167             tmp[i] = rhs[i];
168         }
169         check_indices(&tmp[0], rhs_n, lhs_n);
170         for (R_xlen_t i=0; i < rhs_n; ++i) {
171             indices.push_back( tmp[i] );
172         }
173         indices_n = rhs_n;
174     }
175 
get_indices(traits::identity<traits::int2type<STRSXP>> t)176     void get_indices( traits::identity< traits::int2type<STRSXP> > t ) {
177         indices.reserve(rhs_n);
178         SEXP names = Rf_getAttrib(lhs, R_NamesSymbol);
179         if (Rf_isNull(names)) stop("names is null");
180         SEXP* namesPtr = STRING_PTR(names);
181         SEXP* rhsPtr = STRING_PTR(rhs);
182         for (R_xlen_t i = 0; i < rhs_n; ++i) {
183             SEXP* match = std::find(namesPtr, namesPtr + lhs_n, *(rhsPtr + i));
184             if (match == namesPtr + lhs_n)
185                 stop("not found");
186             indices.push_back(match - namesPtr);
187         }
188         indices_n = indices.size();
189     }
190 
get_indices(traits::identity<traits::int2type<LGLSXP>> t)191     void get_indices( traits::identity< traits::int2type<LGLSXP> > t ) {
192         indices.reserve(rhs_n);
193         if (lhs_n != rhs_n) {
194             stop("logical subsetting requires vectors of identical size");
195         }
196         int* ptr = LOGICAL(rhs);
197         for (R_xlen_t i=0; i < rhs_n; ++i) {
198             if (ptr[i] == NA_INTEGER) {
199                 stop("can't subset using a logical vector with NAs");
200             }
201             if (ptr[i]) {
202                 indices.push_back(i);
203             }
204         }
205         indices_n = indices.size();
206     }
207 
get_vec()208     Vector<RTYPE, StoragePolicy> get_vec() const {
209         Vector<RTYPE, StoragePolicy> output = no_init(indices_n);
210         for (R_xlen_t i=0; i < indices_n; ++i) {
211             output[i] = lhs[ indices[i] ];
212         }
213         SEXP names = Rf_getAttrib(lhs, R_NamesSymbol);
214         if (!Rf_isNull(names)) {
215             Shield<SEXP> out_names( Rf_allocVector(STRSXP, indices_n) );
216             for (R_xlen_t i=0; i < indices_n; ++i) {
217                 SET_STRING_ELT(out_names, i, STRING_ELT(names, indices[i]));
218             }
219             Rf_setAttrib(output, R_NamesSymbol, out_names);
220         }
221         Rf_copyMostAttrib(lhs, output);
222         return output;
223     }
224 
225     LHS_t& lhs;
226     const RHS_t& rhs;
227     R_xlen_t lhs_n;
228     R_xlen_t rhs_n;
229 
230     std::vector<R_xlen_t> indices;
231 
232     // because of the above, we keep track of the size
233     R_xlen_t indices_n;
234 
235 public:
236 
237 #define RCPP_GENERATE_SUBSET_PROXY_OPERATOR(__OPERATOR__)                             \
238     template <int RTYPE_OTHER, template <class> class StoragePolicyOther,             \
239               int RHS_RTYPE_OTHER, bool RHS_NA_OTHER, typename RHS_T_OTHER>           \
240     Vector<RTYPE, StoragePolicy> operator __OPERATOR__ (                              \
241         const SubsetProxy<RTYPE_OTHER, StoragePolicyOther, RHS_RTYPE_OTHER,           \
242                           RHS_NA_OTHER, RHS_T_OTHER>& other) {                        \
243         Vector<RTYPE, StoragePolicy> result(indices_n);                               \
244         if (other.indices_n == 1) {                                                   \
245             for (R_xlen_t i = 0; i < indices_n; ++i)                                  \
246                 result[i] = lhs[indices[i]] __OPERATOR__ other.lhs[other.indices[0]]; \
247         } else if (indices_n == other.indices_n) {                                    \
248             for (R_xlen_t i = 0; i < indices_n; ++i)                                  \
249                 result[i] = lhs[indices[i]] __OPERATOR__ other.lhs[other.indices[i]]; \
250         } else {                                                                      \
251             stop("index error");                                                      \
252         }                                                                             \
253         return result;                                                                \
254     }
255 
256 RCPP_GENERATE_SUBSET_PROXY_OPERATOR(+)
257 RCPP_GENERATE_SUBSET_PROXY_OPERATOR(-)
258 RCPP_GENERATE_SUBSET_PROXY_OPERATOR(*)
259 RCPP_GENERATE_SUBSET_PROXY_OPERATOR(/)
260 
261 #undef RCPP_GENERATE_SUBSET_PROXY_OPERATOR
262 
263 };
264 
265 }
266 
267 #endif
268