Skip to content

Commit 669e706

Browse files
committed
tweaking for rebuild
1 parent 637c4ef commit 669e706

2 files changed

+152
-8
lines changed

_posts/2017-08-04-passing-cpp-function-pointers-rcppxptrutils.md

+146-3
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ title: Passing user-supplied C++ functions with RcppXPtrUtils
33
author: Iñaki Ucar
44
license: GPL (>= 2)
55
tags: function
6-
summary: Demonstrates how to build and check user-supplied C++ functions
7-
with the RcppXPtrUtils package
6+
summary: Demonstrates how to build and check user-supplied C++ functions with the RcppXPtrUtils package
87
layout: post
98
src: 2017-08-04-passing-cpp-function-pointers-rcppxptrutils.Rmd
109
---
@@ -25,7 +24,7 @@ couple of issues though:
2524
complies with the internal signature supported by the C++ backend,
2625
which may lead to weird runtime errors.
2726

28-
## Better `XPtr` handling with RcppXPtrUtils
27+
### Better `XPtr` handling with RcppXPtrUtils
2928

3029
In a nutshell, RcppXPtrUtils provides functions for dealing with these
3130
two issues: namely, `cppXPtr` and `checkXPtr`. As a package author,
@@ -41,10 +40,154 @@ returned object is an R's `externalptr` wrapped into a class called
4140

4241

4342

43+
{% highlight r %}
44+
library(RcppXPtrUtils)
4445

46+
ptr <- cppXPtr("double foo(int a, double b) { return a + b; }")
47+
class(ptr)
48+
{% endhighlight %}
4549

4650

4751

52+
<pre class="output">
53+
[1] &quot;XPtr&quot;
54+
</pre>
4855

4956

5057

58+
{% highlight r %}
59+
ptr
60+
{% endhighlight %}
61+
62+
63+
64+
<pre class="output">
65+
'double foo(int a, double b)' &lt;pointer: 0x564011b984e0&gt;
66+
</pre>
67+
68+
The `checkXptr` function checks the object against a given
69+
signature. If the verification fails, it throws an informative error:
70+
71+
72+
73+
{% highlight r %}
74+
checkXPtr(ptr, type="double", args=c("int", "double")) # returns silently
75+
checkXPtr(ptr, "int", c("int", "double"))
76+
{% endhighlight %}
77+
78+
79+
80+
<pre class="output">
81+
Error in checkXPtr(ptr, &quot;int&quot;, c(&quot;int&quot;, &quot;double&quot;)): Bad XPtr signature:
82+
Wrong return type 'int', should be 'double'.
83+
</pre>
84+
85+
86+
87+
{% highlight r %}
88+
checkXPtr(ptr, "int", c("int"))
89+
{% endhighlight %}
90+
91+
92+
93+
<pre class="output">
94+
Error in checkXPtr(ptr, &quot;int&quot;, c(&quot;int&quot;)): Bad XPtr signature:
95+
Wrong return type 'int', should be 'double'.
96+
Wrong number of arguments, should be 2'.
97+
</pre>
98+
99+
100+
101+
{% highlight r %}
102+
checkXPtr(ptr, "int", c("double", "std::string"))
103+
{% endhighlight %}
104+
105+
106+
107+
<pre class="output">
108+
Error in checkXPtr(ptr, &quot;int&quot;, c(&quot;double&quot;, &quot;std::string&quot;)): Bad XPtr signature:
109+
Wrong return type 'int', should be 'double'.
110+
Wrong argument type 'double', should be 'int'.
111+
Wrong argument type 'std::string', should be 'double'.
112+
</pre>
113+
114+
### Complete use case
115+
116+
First, let us define a templated C++ backend that performs some
117+
processing with a user-supplied function and a couple of adapters:
118+
119+
120+
{% highlight cpp %}
121+
#include <Rcpp.h>
122+
using namespace Rcpp;
123+
124+
template <typename T>
125+
NumericVector core_processing(T func, double l) {
126+
double accum = 0;
127+
for (int i=0; i<1e3; i++)
128+
accum += sum(as<NumericVector>(func(3, l)));
129+
return NumericVector(1, accum);
130+
}
131+
132+
// [[Rcpp::export]]
133+
NumericVector execute_r(Function func, double l) {
134+
return core_processing<Function>(func, l);
135+
}
136+
137+
typedef SEXP (*funcPtr)(int, double);
138+
139+
// [[Rcpp::export]]
140+
NumericVector execute_cpp(SEXP func_, double l) {
141+
funcPtr func = *XPtr<funcPtr>(func_);
142+
return core_processing<funcPtr>(func, l);
143+
}
144+
{% endhighlight %}
145+
146+
Note that the user-supplied function takes two arguments: one is also
147+
user-provided and the other is provided by the backend itself. This
148+
core is exposed through the following R function:
149+
150+
151+
{% highlight r %}
152+
execute <- function(func, l) {
153+
stopifnot(is.numeric(l))
154+
if (is.function(func))
155+
execute_r(func, l)
156+
else {
157+
checkXPtr(func, "SEXP", c("int", "double"))
158+
execute_cpp(func, l)
159+
}
160+
}
161+
{% endhighlight %}
162+
163+
Finally, we can compare the `XPtr` approach with a pure R-based one,
164+
and with a compiled function wrapped in R, as returned by
165+
`Rcpp::cppFunction`:
166+
167+
168+
{% highlight r %}
169+
func_r <- function(n, l) rexp(n, l)
170+
cpp <- "SEXP foo(int n, double l) { return rexp(n, l); }"
171+
func_r_cpp <- Rcpp::cppFunction(cpp)
172+
func_cpp <- cppXPtr(cpp)
173+
174+
microbenchmark::microbenchmark(
175+
execute(func_r, 1.5),
176+
execute(func_r_cpp, 1.5),
177+
execute(func_cpp, 1.5)
178+
)
179+
{% endhighlight %}
180+
181+
182+
183+
<pre class="output">
184+
Unit: microseconds
185+
expr min lq mean median uq
186+
execute(func_r, 1.5) 9010.765 9434.233 9985.919 9739.334 10469.518
187+
execute(func_r_cpp, 1.5) 8751.593 9218.137 9776.670 9430.297 10257.962
188+
execute(func_cpp, 1.5) 170.708 193.201 248.939 229.528 300.495
189+
max neval cld
190+
14538.013 100 b
191+
13712.093 100 b
192+
416.451 100 a
193+
</pre>

src/2017-08-04-passing-cpp-function-pointers-rcppxptrutils.Rmd

+6-5
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ title: Passing user-supplied C++ functions with RcppXPtrUtils
33
author: Iñaki Ucar
44
license: GPL (>= 2)
55
tags: function
6-
summary: Demonstrates how to build and check user-supplied C++ functions
7-
with the RcppXPtrUtils package
6+
summary: Demonstrates how to build and check user-supplied C++ functions with the RcppXPtrUtils package
87
---
98

109
Sitting on top of R's external pointers, the `RcppXPtr` class provides
@@ -23,7 +22,7 @@ couple of issues though:
2322
complies with the internal signature supported by the C++ backend,
2423
which may lead to weird runtime errors.
2524

26-
## Better `XPtr` handling with RcppXPtrUtils
25+
### Better `XPtr` handling with RcppXPtrUtils
2726

2827
In a nutshell, RcppXPtrUtils provides functions for dealing with these
2928
two issues: namely, `cppXPtr` and `checkXPtr`. As a package author,
@@ -37,6 +36,7 @@ returns an `XPtr` to be passed to, unwrapped and called from C++. The
3736
returned object is an R's `externalptr` wrapped into a class called
3837
`XPtr` along with additional information about the function signature.
3938

39+
4040
```{r}
4141
library(RcppXPtrUtils)
4242
@@ -48,19 +48,20 @@ ptr
4848
The `checkXptr` function checks the object against a given
4949
signature. If the verification fails, it throws an informative error:
5050

51+
5152
```{r, error=TRUE}
5253
checkXPtr(ptr, type="double", args=c("int", "double")) # returns silently
5354
checkXPtr(ptr, "int", c("int", "double"))
5455
checkXPtr(ptr, "int", c("int"))
5556
checkXPtr(ptr, "int", c("double", "std::string"))
5657
```
5758

58-
## Complete use case
59+
### Complete use case
5960

6061
First, let us define a templated C++ backend that performs some
6162
processing with a user-supplied function and a couple of adapters:
6263

63-
```{r, engine='Rcpp'}
64+
```{r, engine="Rcpp"}
6465
#include <Rcpp.h>
6566
using namespace Rcpp;
6667

0 commit comments

Comments
 (0)