I can write a tiny function in C++ and save it as test.cpp. It doesn’t do much, it’s just designed to need be able to run for a while:

#include <random>
#include <iostream>

extern "C" {
  
  // [[Rcpp::export]]
  double meanrand(int x) {
    std::random_device rd;  
    std::mt19937 gen(rd());
    std::uniform_real_distribution<double> unif(-10,10);
    std::default_random_engine re;
    double y = 0;
    for (int i = 1; i <= x; i++) {
      y += unif(gen);
    }
    return y;
  }
}

Now I can compile and load this function into R thanks to the magic of Rcpp:

library(Rcpp)
sourceCpp(file='test.cpp')

I run it and get a result:

meanrand(11)
## [1] 15.40397

I recently discovered emscripten, which compiles C/C++ code to LLVM machine code and then back out into highly optimized javascript. So I go into the shell and run it with em++ to compile my little function into a JS file:

em++ -O3 --memory-init-file 0 test.cpp -o test.js -s EXPORTED_FUNCTIONS="['_meanrand']"

(The -O3 --memory-init-file 0 gives me the highest optimization level without introducing some annoying filesystem things.)

If course, thanks to Jeroen’s V8, Javascript can be run from R. So let’s load the JS file and run the function:

library(V8)
ctx <- v8()
ctx$source("test.js")
ctx$eval("Module.ccall('meanrand', 'number', ['number'], [11])")
## [1] "-20.64959707749733"

Hey, it works! Even though the wrapping around it isn’t quite as pretty as Rcpp.

How fast is the emscripted code?

system.time(a <- meanrand(10000000))
##    user  system elapsed 
##   0.174   0.002   0.179
system.time(b <- ctx$eval("Module.ccall('meanrand', 'number', ['number'], [10000000])"))
##    user  system elapsed 
##   0.329   0.004   0.374

Not bad! Only about half the speed of natively-compiled C++. Not sure how much overhead each of the calls make - I suspect the V8 overhead is higher.

There’s a nugget of an idea here of injecting emscripted C++ code into htmlwidgets. Anyway, an evening’s messing around.

LS0tCnRpdGxlOiAiRW1zY3JpcHRyOiBTb21lIFBvbHlnbG90IEppZ2dlcnktUG9rZXJ5IgphdXRob3I6ICJOb2FtIFJvc3MiCmRhdGU6ICIzLzUvMjAxNyIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCkkgY2FuIHdyaXRlIGEgdGlueSBmdW5jdGlvbiBpbiBDKysgYW5kIHNhdmUgaXQgYXMgYHRlc3QuY3BwYC4gIEl0IGRvZXNuJ3QgZG8KbXVjaCwgaXQncyBqdXN0IGRlc2lnbmVkIHRvIG5lZWQgYmUgYWJsZSB0byBydW4gZm9yIGEgd2hpbGU6CgpgYGB7ciwgZW5naW5lPSdjYXQnLCBlbmdpbmUub3B0cz1saXN0KGZpbGU9J3Rlc3QuY3BwJywgbGFuZz0nY3BwJyl9CiNpbmNsdWRlIDxyYW5kb20+CiNpbmNsdWRlIDxpb3N0cmVhbT4KCmV4dGVybiAiQyIgewogIAogIC8vIFtbUmNwcDo6ZXhwb3J0XV0KICBkb3VibGUgbWVhbnJhbmQoaW50IHgpIHsKICAgIHN0ZDo6cmFuZG9tX2RldmljZSByZDsgIAogICAgc3RkOjptdDE5OTM3IGdlbihyZCgpKTsKICAgIHN0ZDo6dW5pZm9ybV9yZWFsX2Rpc3RyaWJ1dGlvbjxkb3VibGU+IHVuaWYoLTEwLDEwKTsKICAgIHN0ZDo6ZGVmYXVsdF9yYW5kb21fZW5naW5lIHJlOwogICAgZG91YmxlIHkgPSAwOwogICAgZm9yIChpbnQgaSA9IDE7IGkgPD0geDsgaSsrKSB7CiAgICAgIHkgKz0gdW5pZihnZW4pOwogICAgfQogICAgcmV0dXJuIHk7CiAgfQp9CmBgYAoKTm93IEkgY2FuIGNvbXBpbGUgYW5kIGxvYWQgdGhpcyBmdW5jdGlvbiBpbnRvIFIgdGhhbmtzIHRvIHRoZSBtYWdpYyBvZiBbKipSY3BwKipdKGh0dHA6Ly93d3cucmNwcC5vcmcpOgoKYGBge3IgbG9hZHJjcHB9CmxpYnJhcnkoUmNwcCkKc291cmNlQ3BwKGZpbGU9J3Rlc3QuY3BwJykKYGBgCgpJIHJ1biBpdCBhbmQgZ2V0IGEgcmVzdWx0OgpgYGB7ciBydW5yY3BwfQptZWFucmFuZCgxMSkKYGBgCgpJIHJlY2VudGx5IGRpc2NvdmVyZWQgWyoqZW1zY3JpcHRlbioqXShodHRwczovL2tyaXBrZW4uZ2l0aHViLmlvL2Vtc2NyaXB0ZW4tc2l0ZS8pLAp3aGljaCBjb21waWxlcyBDL0MrKyBjb2RlIHRvIExMVk0gbWFjaGluZSBjb2RlIGFuZCB0aGVuIGJhY2sgb3V0IGludG8gaGlnaGx5Cm9wdGltaXplZCBqYXZhc2NyaXB0LiAgU28gSSBnbyBpbnRvIHRoZSBzaGVsbCBhbmQgcnVuIGl0IHdpdGggYGVtKytgIHRvIGNvbXBpbGUKbXkgbGl0dGxlIGZ1bmN0aW9uIGludG8gYSBKUyBmaWxlOgoKYGBge3IsIGVuZ2luZT0nYmFzaCd9CmVtKysgLU8zIC0tbWVtb3J5LWluaXQtZmlsZSAwIHRlc3QuY3BwIC1vIHRlc3QuanMgLXMgRVhQT1JURURfRlVOQ1RJT05TPSJbJ19tZWFucmFuZCddIgpgYGAKKFRoZSBgLU8zIC0tbWVtb3J5LWluaXQtZmlsZSAwYCBnaXZlcyBtZSB0aGUgaGlnaGVzdCBvcHRpbWl6YXRpb24gbGV2ZWwgd2l0aG91dAppbnRyb2R1Y2luZyBzb21lIGFubm95aW5nIGZpbGVzeXN0ZW0gdGhpbmdzLikKCgpJZiBjb3Vyc2UsIHRoYW5rcyB0byBKZXJvZW4ncyBbKipWOCoqXShodHRwczovL2dpdGh1Yi5jb20vamVyb2Vub29tcy92OCksCkphdmFzY3JpcHQgY2FuIGJlIHJ1biBmcm9tIFIuICBTbyBsZXQncyBsb2FkIHRoZSBKUyBmaWxlIGFuZCBydW4gdGhlIGZ1bmN0aW9uOgoKYGBge3Igdjh9CmxpYnJhcnkoVjgpCmN0eCA8LSB2OCgpCmN0eCRzb3VyY2UoInRlc3QuanMiKQpjdHgkZXZhbCgiTW9kdWxlLmNjYWxsKCdtZWFucmFuZCcsICdudW1iZXInLCBbJ251bWJlciddLCBbMTFdKSIpCmBgYAoKSGV5LCBpdCB3b3JrcyEgRXZlbiB0aG91Z2ggdGhlIHdyYXBwaW5nIGFyb3VuZCBpdCBpc24ndCBxdWl0ZSBhcyAgcHJldHR5IGFzClJjcHAuCgpIb3cgZmFzdCBpcyB0aGUgZW1zY3JpcHRlZCBjb2RlPwpgYGB7ciBzcGVlZH0Kc3lzdGVtLnRpbWUoYSA8LSBtZWFucmFuZCgxMDAwMDAwMCkpCnN5c3RlbS50aW1lKGIgPC0gY3R4JGV2YWwoIk1vZHVsZS5jY2FsbCgnbWVhbnJhbmQnLCAnbnVtYmVyJywgWydudW1iZXInXSwgWzEwMDAwMDAwXSkiKSkKYGBgCgpOb3QgYmFkISBPbmx5IGFib3V0IGhhbGYgdGhlIHNwZWVkIG9mIG5hdGl2ZWx5LWNvbXBpbGVkIEMrKy4gTm90IHN1cmUgaG93Cm11Y2ggb3ZlcmhlYWQgZWFjaCBvZiB0aGUgY2FsbHMgbWFrZSAtIEkgc3VzcGVjdCB0aGUgVjggb3ZlcmhlYWQgaXMgaGlnaGVyLgoKVGhlcmUncyBhIG51Z2dldCBvZiBhbiBpZGVhIGhlcmUgb2YgaW5qZWN0aW5nIGVtc2NyaXB0ZWQgQysrIGNvZGUgaW50bwpbKipodG1sd2lkZ2V0cyoqXShodHRwczovL2dpdGh1Yi5jb20vcmFtbmF0aHYvaHRtbHdpZGdldHMpLiBBbnl3YXksIGFuIGV2ZW5pbmcncyBtZXNzaW5nIGFyb3VuZC4KCgoKCgo=