Le 07/01/12 18:55, Dirk Eddelbuettel a écrit :
On 7 January 2012 at 18:40, Romain François wrote:
| Le 07/01/12 18:36, Douglas Bates a écrit :
|> On Sat, Jan 7, 2012 at 10:55 AM, Dirk Eddelbuettel<e...@debian.org> wrote:
|>> On 7 January 2012 at 10:04, Douglas Bates wrote:
|>> | 2012/1/7 Romain François<rom...@r-enthusiasts.com>:
|>> |> Le 06/01/12 20:46, Douglas Bates a écrit :
|>> |>
|>> |>> On Fri, Jan 6, 2012 at 1:12 PM, Dirk Eddelbuettel<e...@debian.org>
wrote:
|>> |>>>
|>> |>>> On 6 January 2012 at 12:59, Douglas Bates wrote:
|>> |>>> | On Fri, Jan 6, 2012 at 12:39 PM, John
Chambers<j...@stat.stanford.edu>
|>> |>>> wrote:
|>> |>>> |> The "Rf_" part of the API in particular is ugly and somewhat
of an
|>> |>>> add-on
|>> |>>> |> forced in a few examples by the use of some common names in
the macro
|>> |>>> files.
|>> |>>> |
|>> |>>> | But, as it stands, that is a requirement when using Rcpp.
|>> |>>>
|>> |>>> Where? I can think of one propagated use, which is at the bottom
of the
|>> |>>> try/catch structure where we use ::Rf_error. But the commonly used
|>> |>>> macros
|>> |>>> hide it, and we could/should obviously wrap this.
|>> |>>>
|>> |>>> Otherwise, and especially since the 'Rcpp sugar' initiative took
off, I
|>> |>>> don't
|>> |>>> really touch any ::Rf_* myself anymore. Inside the Rcpp code base,
sure.
|>> |>>> But
|>> |>>> not really in user-facing stuff and Rcpp applications.
|>> |>>
|>> |>> I didn't make myself clear. What I meant was that it is not possible
|>> |>> to use asInteger in Rcpp and count on the name being remapped to
|>> |>> Rf_asInteger.
|>> |>>
|>> |>>> | I think of the Rf_ part as more due to the fact that C doesn't
have a
|>> |>>> | concept of namespaces so anything in the R API is at the top level
|>> |>>> | namespace leading to some conflicts.
|>> |>>>
|>> |>>> Agreed. But speaking stylistically, for the same reason that we
prefer
|>> |>>> C++
|>> |>>> versions of C header files (eg cstdint over stdint.h, cstdio over
|>> |>>> stdio.h,
|>> |>>> ...) I am with John on the preference for C++ idioms when given a
choice.
|>> |>>
|>> |>> I suppose I could have just checked whether Rcpp::as<int> calls
|>> |>> Rf_asInteger. If so, everything is cool. Unfortunately, I haven't
|>> |>> been able to find that specialization.
|>> |>>
|>> |> as lives in the inst/include/Rcpp/as.h file, and we have to follow
template
|>> |> wizardry:
|>> |>
|>> |> it starts from :
|>> |>
|>> |> template<typename T> T as( SEXP m_sexp) {
|>> |> return internal::as<T>( m_sexp, typename
|>> |> traits::r_type_traits<T>::r_category() ) ;
|>> |> }
|>> |>
|>> |> with T=int, so we end up calling this one:
|>> |>
|>> |> template<typename T> T as( SEXP x,
::Rcpp::traits::r_type_primitive_tag ) {
|>> |> if( ::Rf_length(x) != 1 ) throw ::Rcpp::not_compatible(
|>> |> "expecting a single value" ) ;
|>> |> const int RTYPE =
::Rcpp::traits::r_sexptype_traits<T>::rtype ;
|>> |> SEXP y = PROTECT( r_cast<RTYPE>(x) );
|>> |> typedef typename ::Rcpp::traits::storage_type<RTYPE>::type
|>> |> STORAGE;
|>> |> T res = caster<STORAGE,T>(
*r_vector_start<RTYPE,STORAGE>( y ) )
|>> |> ;
|>> |> UNPROTECT(1) ;
|>> |> return res ;
|>> |> }
|>> |>
|>> |>
|>> |> which does the magic. There is no calls to asInteger.
|>> |
|>> | Which, to me, is the disadvantage. The asInteger function is brief,
|>> | understandable, flexible and well-tested. This may look transparent
|>> | to you but not to many others.
|>>
|>> It is however templated and valid for more types than just integer--it
covers
|>> everything mapped by the r_type_primitive type so that the caster can be
|>> invoked.
|> You got it backwards, Dirk. The asInteger function converts any kind
|> of SEXP that it can make sense of to an integer scalar so it is fully
|> general, which is why I prefer it.
|>
|> int asInteger(SEXP x)
|> {
|> int warn = 0, res;
|>
|> if (isVectorAtomic(x)&& LENGTH(x)>= 1) {
|> switch (TYPEOF(x)) {
|> case LGLSXP:
|> return IntegerFromLogical(LOGICAL(x)[0],&warn);
|> case INTSXP:
|> return INTEGER(x)[0];
|> case REALSXP:
|> res = IntegerFromReal(REAL(x)[0],&warn);
|> CoercionWarning(warn);
|> return res;
|> case CPLXSXP:
|> res = IntegerFromComplex(COMPLEX(x)[0],&warn);
|> CoercionWarning(warn);
|> return res;
|> case STRSXP:
|> res = IntegerFromString(STRING_ELT(x, 0),&warn);
|> CoercionWarning(warn);
|> return res;
|> default:
|> UNIMPLEMENTED_TYPE("asInteger", x);
|> }
|> } else if(TYPEOF(x) == CHARSXP) {
|> res = IntegerFromString(x,&warn);
|> CoercionWarning(warn);
|> return res;
|> }
|> return NA_INTEGER;
|> }
| Right. I'm sold. I'll have a look at how to squeeze it in.
I am a bit perplexed. The as<> template is (if I may abuse database lingo)
"many to many": a SEXP contained an opaque type get matched to one of several
R base types, using template magic. But asInteger is only "many-to-one" as it
can return int only, given the opaque SEXP.
We gain about a nanosecond per invocation as per the microbenchmark we
posted. Is that really worth a rewrite? I don't care either way, I just
think we may have other open tickets...
Dirk
Not thinking about a rewrite, just adding e.g. this for int:
template <> inline int as<int>( SEXP x,
::Rcpp::traits::r_type_primitive_tag ) {
return Rf_asInteger( x ) ;
}
so that we let R's asInteger do the actual work, and Doug is right, it
does a better job than the current emplated version.
For example this works:
> fx <- cxxfunction( signature(x_="ANY"), ' int x = as<int>( x_ );
return wrap(x); ', plugin="Rcpp")
>
> fx( "123" )
[1] 123
However,
> fx( c(1L, 3L ) )
[1] 1
this passes, where as the current version complains that it should be a
single value.
--
Romain Francois
Professional R Enthusiast
http://romainfrancois.blog.free.fr
_______________________________________________
Rcpp-devel mailing list
Rcpp-devel@lists.r-forge.r-project.org
https://lists.r-forge.r-project.org/cgi-bin/mailman/listinfo/rcpp-devel