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