Rcpp Version 1.0.9
Subsetter.h
Go to the documentation of this file.
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 
37 
38 public:
39 
40  SubsetProxy(LHS_t& lhs_, const RHS_t& rhs_):
41  lhs(lhs_), rhs(rhs_), lhs_n(lhs.size()), rhs_n(rhs.size()) {
43  }
44 
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>
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>
104 
105  Vector<RTYPE_OTHER, StoragePolicyOther> other_vec = other;
106  *this = other_vec;
107  return *this;
108  }
109 
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 
130  operator SEXP() const {
131  return wrap( get_vec() );
132  }
133 
134 private:
135 
136  #ifndef RCPP_NO_BOUNDS_CHECK
137  template <typename IDX>
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 
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 
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 
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 
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 
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 
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 
260 
261 #undef RCPP_GENERATE_SUBSET_PROXY_OPERATOR
262 
263 };
264 
265 }
266 
267 #endif
#define RCPP_GENERATE_SUBSET_PROXY_OPERATOR(__OPERATOR__)
Definition: Subsetter.h:237
void get_indices(traits::identity< traits::int2type< REALSXP > > t)
Definition: Subsetter.h:163
SubsetProxy & operator=(const Vector< OtherRTYPE, OtherStoragePolicy > &other)
Definition: Subsetter.h:55
SubsetProxy & operator=(int other)
Definition: Subsetter.h:81
void get_indices(traits::identity< traits::int2type< STRSXP > > t)
Definition: Subsetter.h:176
void get_indices(traits::identity< traits::int2type< LGLSXP > > t)
Definition: Subsetter.h:191
SubsetProxy & operator=(bool other)
Definition: Subsetter.h:95
R_xlen_t lhs_n
Definition: Subsetter.h:227
R_xlen_t rhs_n
Definition: Subsetter.h:228
SubsetProxy & operator=(const char *other)
Definition: Subsetter.h:88
Vector< RTYPE, StoragePolicy > get_vec() const
Definition: Subsetter.h:208
void check_indices(IDX *x, R_xlen_t n, R_xlen_t size)
Definition: Subsetter.h:138
void get_indices(traits::identity< traits::int2type< INTSXP > > t)
Definition: Subsetter.h:153
SubsetProxy(const SubsetProxy &other)
Definition: Subsetter.h:45
std::vector< R_xlen_t > indices
Definition: Subsetter.h:230
SubsetProxy & operator=(const SubsetProxy &other)
Definition: Subsetter.h:110
SubsetProxy & operator=(double other)
Definition: Subsetter.h:74
SubsetProxy(LHS_t &lhs_, const RHS_t &rhs_)
Definition: Subsetter.h:40
Vector< RHS_RTYPE, StoragePolicy > RHS_t
Definition: Subsetter.h:36
const RHS_t & rhs
Definition: Subsetter.h:226
SubsetProxy & operator=(const SubsetProxy< RTYPE_OTHER, StoragePolicyOther, RHS_RTYPE_OTHER, RHS_NA_OTHER, RHS_T_OTHER > &other)
Definition: Subsetter.h:103
Vector< RTYPE, StoragePolicy > LHS_t
Definition: Subsetter.h:35
R_xlen_t indices_n
Definition: Subsetter.h:233
R_xlen_t size() const
Definition: Vector.h:276
traits::enable_if< helpers::decays_to_ctype< typename std::iterator_traits< InputIterator >::value_type >::value, typename helpers::ctype< typename std::iterator_traits< InputIterator >::value_type >::type >::type max(InputIterator begin, InputIterator end)
Definition: algorithm.h:324
Rcpp API.
Definition: algo.h:28
no_init_vector no_init(R_xlen_t size)
Definition: no_init.h:77
SEXP find(const std::string &name) const
Definition: Environment.h:145
void NORET stop(const char *fmt, Args &&... args)
Definition: exceptions.h:51
IntegerVector match(const VectorBase< RTYPE, NA, T > &x, const VectorBase< RTYPE, RHS_NA, RHS_T > &table_)
Definition: match.h:28
SEXP wrap(const Date &date)
Definition: Date.h:38