The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

tidyCpp: Tidy C++ wrapping of the C API for R

CI License CRAN Dependencies Downloads Last Commit

About

The C API of the R language and environment is robust, yet a little awkward for C++ programmers. This package wraps a tidy layer of header functions around it.

Examples

A recent motivating example is from the dang package which includes one unexported Base R function written in C. The original version is here. While short enough, we found working with a tidier version easier and more enjoyable. We include an abbreviated version (minus the copyright header) here:

#include <tidyCpp>

extern "C" {

// cf src/library/tools/src/text.c
SEXP _check_nonASCII(SEXP text, SEXP ignore_quotes) {
    /* Check if all the lines in 'text' are ASCII, after removing
       comments and ignoring the contents of quotes (unless ignore_quotes)
       (which might span more than one line and might be escaped).

       This cannot be entirely correct, as quotes and \ might occur as
       part of another character in a MBCS: but this does not happen
       in UTF-8.
    */
    int i, nbslash = 0; /* number of preceding backslashes */
    const char *p;
    char quote= '\0';
    Rboolean ign, inquote = FALSE;

    if (!R::isString(text)) R::error("invalid input");
    ign = (Rboolean) R::asLogical(ignore_quotes);
    if (ign == NA_LOGICAL) R::error("'ignore_quotes' must be TRUE or FALSE");

    for (i = 0; i < R::length(text); i++) {
        p = R::charPointer(R::stringElement(text, i)); // ASCII or not not affected by charset
        inquote = FALSE; /* avoid runaway quotes */
        for (; *p; p++) {
            if (!inquote && *p == '#') break;
            if (!inquote || ign) {
                if ((unsigned int) *p > 127) {
                    Rprintf("%s\n", R::charPointer(R::stringElement(text, i)));
                    Rprintf("found %x\n", (unsigned int) *p);
                    return R::scalarLogical(TRUE);
                }
            }
            if ((nbslash % 2 == 0) && (*p == '"' || *p == '\'')) {
                if (inquote && *p == quote) {
                    inquote = FALSE;
                } else if(!inquote) {
                    quote = *p;
                    inquote = TRUE;
                }
            }
            if (*p == '\\') nbslash++; else nbslash = 0;
        }
    }
    return R::scalarLogical(FALSE);
}

} // extern "C"

Additions from the tidyCpp wrapper can be identified easily via the R:: namespace. While the code is not hiding its C heritage, we find it overall a little easier to work with. Other examples (see below) show how using tidyCpp can help avoid the very manual and error-prone PROTECT and UNPROTECT and pairs.

For additional examples, please see the Motivation vignette for a longer discussion with more examples, and the files in the snippets/ directory for directly callable code examples.

Author

Dirk Eddelbuettel

License

GPL (>= 2)

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.