Skip to content

DavisVaughan/timerip

Repository files navigation

timerip

R build status Travis build status Codecov test coverage

In physical cosmology, the Big Rip is a hypothetical cosmological model concerning the ultimate fate of the universe, in which the matter of the universe, from stars and galaxies to atoms and subatomic particles, and even spacetime itself, is progressively torn apart by the expansion of the universe at a certain time in the future.

The goal of timerip is to be a fast extractor of individual date-time components, such as year or month, from Date or POSIXct objects.

Installation

You can install the dev version from GitHub with:

devtools::install_github("DavisVaughan/timerip")

Example

The main goal is to be faster than as.POSIXlt(), which wastes memory and time when you just want a single component.

x <- as.POSIXct("2019-01-01", tz = "EST")
x <- rep(x, 2e5)

bench::mark(
  rip_year(x),
  as.POSIXlt(x)$year + 1900L
)
#> # A tibble: 2 x 6
#>   expression                      min   median `itr/sec` mem_alloc `gc/sec`
#>   <bch:expr>                 <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#> 1 rip_year(x)                  5.33ms   6.93ms     144.    787.6KB     2.06
#> 2 as.POSIXlt(x)$year + 1900L  12.36ms  14.23ms      67.2    11.4MB    24.4

Extraction for Dates is faster too.

y <- as.Date(x)

bench::mark(
  rip_year(y),
  as.POSIXlt(y)$year + 1900L
)
#> # A tibble: 2 x 6
#>   expression                      min   median `itr/sec` mem_alloc `gc/sec`
#>   <bch:expr>                 <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl>
#> 1 rip_year(y)                  4.92ms   5.83ms     162.    790.7KB     2.08
#> 2 as.POSIXlt(y)$year + 1900L  17.82ms  19.45ms      50.9    9.16MB    12.7

C API

There is also a C API that mirrors the R API exactly. To use it, there are a few steps.

First, add timerip to both Imports and LinkingTo in your Description file:

Imports:
    timerip
LinkingTo:
    timerip

Next, add an .onLoad() R function for your package with the following in it, we’ll assume your package is named “mypackage”.

.onLoad <- function(libname, pkgname) {
  # Load timerip namespace for access to C callables
  requireNamespace("timerip", quietly = TRUE)

  # Initialize timerip API
  .Call(mypackage_init_timerip)
}

This ensures that the timerip namespace is available so you have access to the C callables that are exported from it, and then calls a package initialization function that is going to initialize the timerip C callables by calling timerip_init_api(). We haven’t created that function yet, let’s do it now.

Add a mypackage-timerip.c file with the following:

#include <timerip.c>

SEXP mypackage_init_timerip() {
  timerip_init_api();
  return R_NilValue;
}

In your init.c file, add an entry for mypackage_init_timerip(). It should look something like this:

#include <R.h>
#include <Rinternals.h>
#include <stdlib.h> // for NULL
#include <R_ext/Rdynload.h>

/* .Call calls */
extern SEXP mypackage_init_timerip();

static const R_CallMethodDef CallEntries[] = {
  {"mypackage_init_timerip", (DL_FUNC) &mypackage_init_timerip, 0},
  {NULL, NULL, 0}
};

void R_init_mypackage(DllInfo *dll)
{
  R_registerRoutines(dll, NULL, CallEntries, NULL, NULL);
  R_useDynamicSymbols(dll, FALSE);
}

If you use roxygen2, you’ll also need to have a roxygen comment in an R file that looks like this (if you don’t already).

#' @useDynLib mypackage, .registration = TRUE

Now when you run devtools::document() and then devtools::load_all() everything should load without issues.

At this point, you can access the timerip API by including <timerip.h> in your C file:

#include <timerip.h>

SEXP myfunction(SEXP x) {
  return rip_year(x);
}

Releases

No releases published

Packages

No packages published