Skip to content

Commit d94ee6b

Browse files
committed
Subset methods (currently exported only for LogicalVector and CharacterVector)
1 parent cdb20cb commit d94ee6b

File tree

4 files changed

+189
-0
lines changed

4 files changed

+189
-0
lines changed

inst/include/Rcpp/traits/get_na.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ inline Rcomplex get_na<CPLXSXP>(){
4949
template<>
5050
inline SEXP get_na<STRSXP>(){ return NA_STRING ; }
5151

52+
// this is the list equivalent of an NA value
53+
template<>
54+
inline SEXP get_na<VECSXP>(){ return R_NilValue; }
55+
5256
}
5357
}
5458

inst/include/Rcpp/traits/num2type.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 8 -*-
2+
//
3+
// num2type.h: Rcpp R/C++ interface class library -- convert number to type
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__traits__num2type__h
23+
#define Rcpp__traits__num2type__h
24+
25+
namespace Rcpp{
26+
namespace traits{
27+
28+
template <std::size_t N>
29+
struct num2type {};
30+
31+
}
32+
}
33+
34+
#endif

inst/include/Rcpp/vector/Subsetter.h

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
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+
namespace Rcpp {
26+
27+
template <int RTYPE, template <class> class StoragePolicy, typename T>
28+
class Subsetter {
29+
30+
typedef Vector<RTYPE, StoragePolicy> VECTOR;
31+
32+
public:
33+
34+
explicit Subsetter(const Subsetter& rhs): vec(rhs.vec), other(rhs.other) {};
35+
Subsetter(const VECTOR& vec_, const T& other_): vec(vec_), other(other_) {};
36+
37+
inline operator SEXP() const {
38+
return subset_impl(vec, other).get__();
39+
}
40+
41+
inline operator VECTOR() const {
42+
return subset_impl(vec, other);
43+
}
44+
45+
private:
46+
47+
Subsetter() {};
48+
49+
// helper function used for the subset methods when going from logical to int
50+
template <template <class> class OtherStoragePolicy>
51+
static Vector<INTSXP, StoragePolicy> which_na( const Vector<LGLSXP, OtherStoragePolicy>& x) {
52+
std::vector<int> output;
53+
int n = x.size();
54+
output.reserve(n);
55+
for (int i=0; i < n; ++i) {
56+
if (x[i] == NA_LOGICAL) {
57+
output.push_back(NA_INTEGER);
58+
} else if (x[i]) {
59+
output.push_back(i);
60+
}
61+
}
62+
int n_ = output.size();
63+
Vector<INTSXP, StoragePolicy> output_ = no_init(n_);
64+
for (int i=0; i < n_; ++i) {
65+
output_[i] = output[i];
66+
};
67+
return output_;
68+
}
69+
70+
// Subsetting for logicals
71+
template <template <class> class OtherStoragePolicy>
72+
inline Vector<RTYPE, StoragePolicy> subset_impl( const VECTOR& this_, const Vector<LGLSXP, OtherStoragePolicy>& x ) const {
73+
Vector<INTSXP, StoragePolicy> tmp = which_na(x);
74+
if (!tmp.size()) return Vector<RTYPE, StoragePolicy>(0);
75+
else return subset_impl__hidden(this_, tmp);
76+
}
77+
78+
// Subsetting for characters
79+
template <template <class> class OtherStoragePolicy>
80+
inline Vector<RTYPE, StoragePolicy> subset_impl( const VECTOR& this_, const Vector<STRSXP, OtherStoragePolicy>& x ) const {
81+
Vector<STRSXP, StoragePolicy> names = as< Vector<STRSXP, StoragePolicy> >(Rf_getAttrib(this_, R_NamesSymbol));
82+
Vector<INTSXP, StoragePolicy> idx = match(x, names); // match returns 1-based index
83+
// apparently, we don't see sugar, so we have to do this manually
84+
Vector<INTSXP, StoragePolicy> idxm1 = no_init(idx.size());
85+
for (int i=0; i < idx.size(); ++i) {
86+
idxm1[i] = idx[i] - 1;
87+
}
88+
Vector<RTYPE, StoragePolicy> output = subset_impl__hidden(this_, idxm1);
89+
int n = output.size();
90+
if (n == 0) return Vector<RTYPE, StoragePolicy>(0);
91+
Vector<STRSXP, StoragePolicy> out_names = no_init(n);
92+
for (int i=0; i < n; ++i) {
93+
if (idx[i] == NA_INTEGER) out_names[i] = NA_STRING;
94+
else out_names[i] = names[ idx[i] - 1 ];
95+
}
96+
output.attr("names") = out_names;
97+
return output;
98+
}
99+
100+
const VECTOR& vec;
101+
const T& other;
102+
103+
private:
104+
105+
// Subsetting for integers -- note that it is 0-based
106+
template <template <class> class OtherStoragePolicy>
107+
inline Vector<RTYPE, StoragePolicy>
108+
subset_impl( const VECTOR this_, const Vector<INTSXP, OtherStoragePolicy>& x ) const {
109+
stop("Subset is not yet implemented for IntegerVectors");
110+
return Vector<RTYPE, StoragePolicy>();
111+
}
112+
113+
// Subsetting for integers -- note that it is 0-based
114+
// hidden until we decide whether to go with 0 or 1 based indexing
115+
template <template <class> class OtherStoragePolicy>
116+
inline Vector<RTYPE, StoragePolicy>
117+
subset_impl__hidden( const VECTOR this_, const Vector<INTSXP, OtherStoragePolicy>& x ) const {
118+
int n = x.size();
119+
if (n == 0) return this_;
120+
Vector<RTYPE, StoragePolicy> output = no_init(n);
121+
for (int i=0; i < n; ++i) {
122+
if (x[i] == NA_INTEGER) output[i] = traits::get_na<RTYPE>();
123+
else if (x[i] < 0) stop("Cannot subset with an integer vector with elements <= 0");
124+
else if (x[i] > this_.size() - 1) output[i] = traits::get_na<RTYPE>();
125+
else output[i] = (this_)[ x[i] ];
126+
}
127+
if (!Rf_isNull( Rf_getAttrib( this_, R_NamesSymbol) )) {
128+
Vector<STRSXP, StoragePolicy> thisnames = as<Vector<STRSXP, StoragePolicy> >(Rf_getAttrib(this_, R_NamesSymbol));
129+
Vector<STRSXP, StoragePolicy> outnames = no_init(n);
130+
for (int i=0; i < n; ++i) {
131+
if (x[i] == NA_INTEGER) outnames[i] = NA_STRING;
132+
else if (x[i] > this_.size() - 1) outnames[i] = NA_STRING;
133+
else if (x[i] >= 0) outnames[i] = thisnames[ x[i] ];
134+
}
135+
output.attr("names") = outnames;
136+
}
137+
return wrap(output);
138+
}
139+
140+
};
141+
142+
} // namespace Rcpp
143+
144+
#endif

inst/include/Rcpp/vector/Vector.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#ifndef Rcpp__vector__Vector_h
2323
#define Rcpp__vector__Vector_h
2424

25+
#include <Rcpp/vector/Subsetter.h>
26+
2527
namespace Rcpp{
2628

2729
template <int RTYPE, template <class> class StoragePolicy = PreserveStorage >
@@ -310,6 +312,11 @@ class Vector :
310312
inline operator RObject() const {
311313
return RObject( Storage::get__() );
312314
}
315+
316+
template <int RTYPE2>
317+
Vector operator[](const Vector<RTYPE2>& rhs) const {
318+
return Subsetter<RTYPE, StoragePolicy, Vector<RTYPE2, StoragePolicy> >(*this, rhs);
319+
}
313320

314321
Vector& sort(){
315322
typename traits::storage_type<RTYPE>::type* start = internal::r_vector_start<RTYPE>( Storage::get__() ) ;

0 commit comments

Comments
 (0)