|
| 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 |
0 commit comments