Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
2025-12-21 Dirk Eddelbuettel <edd@debian.org>

* inst/include/Rcpp/DataFrame.h (nrow): Rewritten using R_mapAttrib()
avoiding ATTRIB() likely to be removed by R 4.6.0
* inst/include/Rcpp/proxy/AttributeProxy.h (attributeNames): Idem
* src/utilities.cpp: Add two helper functions used by R_mapAttrib()
* inst/include/Rcpp/routines.h: Register two new helper functions
* src/rcpp_init.cpp (registerFunctions): Idem

* .github/workflows/docker.yaml: Add workflow_dispatch, update
checkout action

Expand Down
4 changes: 2 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: Rcpp
Title: Seamless R and C++ Integration
Version: 1.1.0.11
Date: 2025-12-17
Version: 1.1.0.11.2
Date: 2025-12-21
Authors@R: c(person("Dirk", "Eddelbuettel", role = c("aut", "cre"), email = "edd@debian.org",
comment = c(ORCID = "0000-0001-6419-907X")),
person("Romain", "Francois", role = "aut",
Expand Down
12 changes: 11 additions & 1 deletion inst/include/Rcpp/DataFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,15 @@ namespace Rcpp{
// compact form thereby allocating a huge vector when we just want
// the row.names. Hence this workaround.
inline int nrow() const {
#if R_VERSION >= R_Version(4, 6, 0)
SEXP v = R_mapAttrib(Parent::get__(), get_row_count, R_NilValue);
Comment thread
Enchufa2 marked this conversation as resolved.
Outdated
if (v != NULL && TYPEOF(v) == INTSXP) {
return INTEGER(v)[0];
} else {
// TODO: error?
return NA_INTEGER;
}
#else
SEXP rn = R_NilValue ;
SEXP att = ATTRIB( Parent::get__() ) ;
while( att != R_NilValue ){
Expand All @@ -81,9 +90,10 @@ namespace Rcpp{
if (TYPEOF(rn) == INTSXP && LENGTH(rn) == 2 && INTEGER(rn)[0] == NA_INTEGER)
return std::abs(INTEGER(rn)[1]);
return LENGTH(rn);
#endif
}

template <typename T>
template <typename T>
void push_back( const T& object){
Parent::push_back(object);
set_type_after_push();
Expand Down
12 changes: 11 additions & 1 deletion inst/include/Rcpp/proxy/AttributeProxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,16 +78,25 @@ class AttributeProxyPolicy {
}

std::vector<std::string> attributeNames() const {
std::vector<std::string> v ;
std::vector<std::string> v;
#if R_VERSION >= R_Version(4, 6, 0)
R_mapAttrib(static_cast<const CLASS&>(*this).get__(), get_attr_names, (void *) &v);
#else
SEXP attrs = ATTRIB( static_cast<const CLASS&>(*this).get__());
while( attrs != R_NilValue ){
v.push_back( std::string(CHAR(PRINTNAME(TAG(attrs)))) ) ;
attrs = CDR( attrs ) ;
}
#endif
return v ;
}

bool hasAttribute( const std::string& attr) const {
#if R_VERSION >= R_Version(4, 6, 0)
std::vector<std::string> v = attributeNames();
auto it = std::find(v.begin(), v.end(), attr);
return it != v.end(); // if found 'it' points to element equal to 'attr'
Comment thread
Enchufa2 marked this conversation as resolved.
Outdated
#else
SEXP attrs = ATTRIB(static_cast<const CLASS&>(*this).get__());
while( attrs != R_NilValue ){
if( attr == CHAR(PRINTNAME(TAG(attrs))) ){
Expand All @@ -96,6 +105,7 @@ class AttributeProxyPolicy {
attrs = CDR( attrs ) ;
}
return false; /* give up */
#endif
}


Expand Down
15 changes: 15 additions & 0 deletions inst/include/Rcpp/routines.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ SEXP reset_current_error();
int error_occured();
SEXP rcpp_get_current_error();
// void print(SEXP s);
SEXP get_attr_names(SEXP t, SEXP a, void* d);
SEXP get_row_count(SEXP t, SEXP a, void* d);

#else

Expand Down Expand Up @@ -309,6 +311,19 @@ inline attribute_hidden SEXP rcpp_get_current_error(){
// fun(s);
// }

inline attribute_hidden SEXP get_attr_names(SEXP tag, SEXP attr, void* data){
typedef SEXP (*Fun)(SEXP, SEXP, void*);
static Fun fun = GET_CALLABLE("get_attr_names");
return fun(tag, attr, data);
}

inline attribute_hidden SEXP get_row_count(SEXP tag, SEXP attr, void* data){
typedef SEXP (*Fun)(SEXP, SEXP, void*);
static Fun fun = GET_CALLABLE("get_row_count");
return fun(tag, attr, data);
}


#endif


Expand Down
3 changes: 3 additions & 0 deletions src/rcpp_init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ void registerFunctions(){
RCPP_REGISTER(Rcpp_precious_remove)
RCPP_REGISTER(Rcpp_cout_get)
RCPP_REGISTER(Rcpp_cerr_get)

RCPP_REGISTER(get_attr_names)
RCPP_REGISTER(get_row_count)
#undef RCPP_REGISTER
}

Expand Down
54 changes: 54 additions & 0 deletions src/utilities.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// utilities.cpp: Rcpp R/C++ interface class library -- attribute utilities
//
// Copyright (C) 2025 - current Dirk Eddelbuettel
//
// This file is part of Rcpp.
//
// Rcpp is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// Rcpp is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Rcpp. If not, see <http://www.gnu.org/licenses/>.

#define COMPILING_RCPP

#include <vector>
#include <string>
#include <Rcpp/Lighter>

// See WRE Section 6.22.6 'Working with attributes' under R 4.6.0 or later
// This function collects the names from 'tag' in a vector passed via *data
// It is used by AttributeProxyPolicy::attributeNames() in a call to R_mapAttrib
// [[Rcpp::register]]
SEXP get_attr_names(SEXP tag, SEXP attr, void* data) {
std::vector<std::string>* vecptr = static_cast<std::vector<std::string>*>(data);
std::string s{CHAR(Rf_asChar(tag))};
vecptr->push_back(s);
return NULL;
}

// See WRE Section 6.22.6 'Working with attributes' under R 4.6.0 or later
// This function extract the number of rows in a data frame
Comment thread
eddelbuettel marked this conversation as resolved.
Outdated
// It is used DataFrame_impl::nrow() in a call to R_mapAttrib()
// [[Rcpp::register]]
SEXP get_row_count(SEXP tag, SEXP attr, void* data) {
if (tag == R_RowNamesSymbol) {
if (TYPEOF(attr) == INTSXP && LENGTH(attr) == 2 && INTEGER(attr)[0] == NA_INTEGER) {
int n = std::abs(INTEGER(attr)[1]);
Comment thread
eddelbuettel marked this conversation as resolved.
Outdated
//Rcpp::Rcout << "Seeing " << n << std::endl;
return Rf_ScalarInteger(n);
}
if (Rf_isNull(attr)) {
return Rf_ScalarInteger(0);
}
return Rf_ScalarInteger(LENGTH(attr));
}
return NULL;
}