-
Notifications
You must be signed in to change notification settings - Fork 2
/
CObjectConversion.tex
689 lines (586 loc) · 27.4 KB
/
CObjectConversion.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
\documentclass{article}
\input{pstricks}
\usepackage{fullpage}
\usepackage{times}
\usepackage{hyperref}
\input{WebMacros}
\input{CMacros}
\input{SMacros}
\title{An Extensible Conversion Mechanism for \SFunction{.C} Calls}
\author{Duncan Temple Lang}
\begin{document}
\maketitle
\begin{abstract}
This is a note on an addition to the \SFunction{.C} interface.
The idea is to generalize the way we convert S objects
to C-level pointers that are passed to the C routine being
invoked by the caller of the \SFunction{.C}.
The mechanism is aimed at handling references to external data
such as shared memory, hdf5 files, database result sets, and data in other
languages such as Python, Perl, Java, JavaScript, etc.
Rather than copying the data reference in these objects
into S objects and then passing them to C, we can pass these
directly by converting the reference object to
data values appropriate for the C routine.
This has the potential to avoid the amount of data duplication
and make certain memory-bound computations feasible in R.
This allows for package/library developers to register C level
routines which can convert an S object to a C value. These return a
\Ctype{void *} value which is passed to the C routine. If no
suitable converter is found, the current mechanism is used for that
argument. Currently, this conversion mechanism is only invoked a) if
there registered converters, and b) if the object has a class.
A similar mechanism is used throughout the Omegahat inter-system
interface packages to handle objects of arbitrary types which can
only be handled with user-level contextual information.
This is prompted by discussions with Robert, John, Luke. An example
of how it can be used is provided in the
\href{http://cm.bell-labs.com/stat/duncan/SCConverters/SCConverters_1.0-0.tar.gz}{SCConverters
package.}
The change extends the routines \Croutine{RObjToPtr} and the
component of \Croutine{do_dotCode} that calls \Croutine{CPtrToRObj}.
These changes are in some ways orthogonal to the changes we are
proposing for \href{DynamicCSymbols}{symbol lookup}. However, that
mechanism of registering/exporting C routines allows one to provide
additional information that can identify the converters for the R
arguments and for the return value(s).
\end{abstract}
\section{Motivation}
The example is motivated by Robert's needs to handle data stored in
hdf5 and the general inter-system interface mechanism that we have
developed in Omegahat for sharing data across different languages and
interpreters. Consider the following scenario. We create an object
of class \SClass{hdf5Reference}.
\begin{verbatim}
x <- hdf5(filename)
\end{verbatim}
This is an external pointer type which contains the address of a C
level object which knows about its own data type and content. For our
example, let's assume it is an array of real values. The C level
structure might look something like
\begin{verbatim}
type length | value_0 value_1 ... value_n
\end{verbatim}
It is reasonably easy to overload the different functions that access
the data. For example, we can provide a method for \SFunction{length}
and \SFunction{[}. We can provide coercion method such as
\SFunction{as.integer}, etc. which create a new reference to the
\textit{same} data and add information about the mode of how the data
is to be used.
One of the problems with these overloaded, symbolic methods arises
when we pass the object to a C routine via the \SFunction{.C}. In our
example, we will call the C routine \Croutine{foo} which expects two
arguments. The first is an array of \Ctype{Rint}s and the second is a
scalar giving the length of this array. This is also passed to
\Croutine{foo} in the form of a pointer to a \Ctype{Rint}. So the
declaration of \Croutine{foo} is given as
\begin{verbatim}
void foo(Rint *val, Rint *len);
\end{verbatim}
If we pass the hdf5 reference object directly to the C routine, the
current \Croutine{RObjToCPtr} will not convert it to the appropriate
array of integers. Instead it will pass it as a list or simply discard
the class, depending on the exact format of the \SClass{hdf5} class.
What we would like to have happen is the following.
A simple S call of the form
\begin{verbatim}
.C("foo", as.integer(x), length(as.integer(x)))
\end{verbatim}
should retrieve the relevant data from the hdf5 object. If the
underlying data within the hdf5 object is an array of \Ctype{Sint}s,
then we want to be able to pass a pointer to that single copy of the
values. Otherwise, we will create the necessary array and copy the
values to it. Since we have assumed in our example that the
underlying data is an array of reals, we will need to create this
array of \Ctype{Rint} and populate it with the real values. However,
if the particular instance of the hdf5 object contained \Ctype{Rint}
elements, we would just point to the data segment of the
object. Similarly, we could avoid copying the data if the routine
expected real values. Additionally, we are in control of the copy of
the data and will not incur the expense of duplicate copies created by
R.
So how will this simple call work? Firstly, the call to
\SFunction{as.integer} will create a new S-level object. This
contains a refinement of the original \SClass{hdf5Reference}. This new
object will contain embedded information about the expected type of
the data. This might be via a \SField{type} slot or by changing the
class to be \SClass{hdf5IntegerReference}. Either approach conveys
sufficient information.
Secondly, the \SFunction{length} method for this type of object will
compute the appropriate length -- in our case the number of elements
in the array. The current mechanism for converting S objects to
arguments to C routines called via the \SFunction{.C} function will
handle this second argument -- the length of the array. However, it
will not correctly deal with the first argument which is not a
primitive type, but an object of class \SClass{hdf5Reference} or
\SClass{hdf5IntegerReference}. The extension to the
conversion mechanism allows the developer of the hdf5 package to
register C routines that will convert these meta-objects into the
appropriate C level pointers. This extensibility is necessary since we
cannot know how to perform the conversion for an arbitrary S object.
\subsection{Inter-Language Interfaces}
A second example in which this facility may be useful is in the
Omegahat inter-system interface packages. Consider the case where we
have a reference to a Java or Python array of real values. If the
goal is to use these in a C routine called by R, we may wish to avoid
first copying the values from the foreign system (Java or Python) to R
and then from R to C. Instead, we can go directly from Python to C
using a converter that recognizes a foreign reference to an array of
doubles and converts this to the appropriate C level value. In
certain cases, the internal representation of the foreign data may be
the same as expected by the C level code and no copying is
necessary. Any changes made by the C routine to the data (by writing
on that memory) will be immediately visible in the other system.
\subsection{Return Values}
Routines called via the \SFunction{.C} do not have an explicit return
value. However, the \SFunction{.C} call returns the values it was
given, containing any changes made by the C routine to these values.
To be generally useful, we must be able to handle these return values
in a manner that is consistent both with the S view of the
\SFunction{.C} functions return values, and also the foreign system's
view of the data. To do this, we need a \textit{reverse} converter
which takes the output from the \SFunction{.C} corresponding to an
argument and creates a) an appropriate S object, and b) updates the
foreign reference's data appropriately.
\subsection{Managing Converters}
The S user can query the list of converters using some simple
functions. She can obtain the number of converters via
\SFunction{getNumCConverters}. Brief descriptions of each converter
(as specified by its author) are available from the function
\SFunction{getCConverterDescriptions}. One can also determine which
converters are active using \SFunction{getCConverterStatus}.
The user can modify individual converters by making it active or
inactive. An inactive converter is ignored when searching for a
potential converter for an object. This allows one to temporarily
remove its effect without having to subsequently restore it at the C
level. Additionally the function \SFunction{removeCConverter}
explicitly removes the specified element from the list. Both of these
functions allow the user to identify the element of interest in the
converter list either by index or by its description string (returned
from \SFunction{getCConverterDescriptions}).
At present, the user cannot directly add a converter to the list via S
commands. Instead, she must use C code and specifically the routine
\Croutine{R_addToCConverter}. The reasons for this restriction are
simple. Firstly, the routines and user-level data are C level symbols
and specifying them in R can be more convoluted than simply writing
the C code. Secondly, the converters are written in C and typically
operate on C level values, so we assume the author is familiar with C.
An S-language interface for adding less general converters
will be added soon.
\section{Generic Converters}
This entire mechanism may appear complex and somewhat awkward.
However, it is intended to be a general framework on which classes of
simpler, more generic converters can be added. For example, a common
idiom is to have a predicate routine that checks whether the object
being converted has a particular class. The routine
\Croutine{R_matchClass} (provided in the R binary) can be used to do
this. When the developer registers the converter, she specifies
\Croutine{R_matchClass} as the predicate and the name of the class
which the converter is prepared to handle. When the predicate is
called, it compares this name to each of the names in the class
attribute of the object being converted. An example of this is
contained in the
\href{http://cm.bell-labs.com/stat/duncan/SCConverters/SCConverters_1.0-0.tar.gz}{SCConverters}
example.
Also, one can use a convention for locating the actual C routine to do
the conversion. We can take the name of the target class stored in the
user-level data field and use it to look for a C symbol with a related
name. For example, suppose the converter can handle objects of class
\SClass{hdf5}. Then, we might look for a C symbol named
\Croutine{R_hdf5_to_C}. If we find it, we invoke it, passing it the
object to be converted. This generic converter routine is relatively
easy to define. Then other developers registering converters need only
specify this routine, the \Croutine{R_matchClass} and the name of the
class (e.g. \SClass{hdf5}).
One can also develop predicate and converter routines that use S
functions. This allows developers to avoid programming in C while
still converting the argument to a value to be directly used in the C
routine.
Part of the complexity of the interface comes from the reliance on
meta or symbolic computation in that the reference objects must
contain information about the desired type. We have the data in one
system and a reference to it in R. Coercion to different types doesn't
force the data to be modified, but simply the reference to it (or more
precisely a new reference to the same data). One needs to have a
class and methods to support such coercion
(e.g. \SFunction{as.integer}), computing dimensions
(e.g. \SFunction{nrow}, \SFunction{dim}) and lengths
(e.g. \SFunction{length}), etc. This extra effort does provide more
structure to the software and so is of some value in its own
right. More importantly however is the potential for this mechanism to
make certain computations feasible. By avoiding the numerous copies
that the S language must make to operate on data in a way that
preserves the pass-by-value semantics, this direct access can greatly
reduce the memory requirements for certain computations. If such
computations could not be done in R, but now can be with direct access
conversion, the benefits may be worth the extra work.
\section{The Basic Idea}
We maintain a linked list of converter elements. This list is used for
converting R objects to C pointers.
Each element in the list contains two essential ingredients
\begin{enumerate}
\item a predicate function called to determine if this
element can successfully convert the R object, and
\item a converter function which performs the actual conversion
of the R object to a C pointer.
\end{enumerate}
A third, but potentially optional, routine is one that converts the
C-level value passed to the C routine back to R. This reverses the
conversion and allows the author to process any changes the C routine
makes to the input arguments.
Additionally, the converter element has information about whether the
converter is active and user-level data that is available to the
predicate, converter and reverse converter routines. This is used to
parameterize these routines.
Finally, each converter should have a description string that allows
users to understand what converters are in effect.
To register a converter, a developer will call the routine
\Croutine{R_addToCConverter}. This is (currently) declared in the
header file \file{R_ext/RConverters.h}. It takes five arguments. The
first three are the predicate/match routine, the converter routine and
the reverse converter. The reverse converter can be specified as
\CNull in which case the corresponding position in the list returned
by \SFunction{.C} will be \SNull{}.
Each of these three routines has a very particular signature. Again,
these are specified in \file{R_ext/RConveters.h} as
\Ctype{R_ToCPredicate}, \Ctype{R_ToCConverter} and
\Ctype{R_FromCConverter} respectively.
The remaining arguments consist of data to be used by the different
routines and a description which is used by end users to identify the
converter. The data argument is an arbitrary C value (specified as a
\Ctype{void *}). It is stored in the converter element and accessible
to each of the three routines so that these can be customized for
different classes, etc. The description is a string which is copied
so that it can be stored in the converter element.
The following code snippet contains two examples taken from the
\href{http://cm.bell-labs.com/stat/duncan/SCConverters/SCConverters_1.0-0.tar.gz}{SSConverters
package} used to test this mechanism.
\begin{verbatim}
R_addToCConverter(matchClass, convertSeq, NULL,
"VirtualIntegerSequence",
"VirtualIntegerSequence to integer");
R_addToCConverter(matchClass, convertDoubleSeq, reverseDoubleScalar,
"VirtualDoubleSequence",
"VirtualDoubleSequence to numeric");
\end{verbatim}
In the first case, we discard the return value
by specifying \CNull{} for the reverse converter argument.
\subsection{Using the Converters}
When converting an R object to a C argument, the sequence of actions
is as follows:
\begin{enumerate}
\item iterate over the list of converters
\begin{enumerate}
\item invoke the predicate routine
\item if it returns \textbf{TRUE},
\item invoke the converter
\end{enumerate}
\item use the default conversion mechanism
currently in \Croutine{RObjToCPtr}.
\end{enumerate}
In the inter-system packages we have two lists which convert from the
foreign system (i.e. C, in this case) to R. In the case of
\SFunction{.C} calls, there is no return type. However, we do have to
handle converting the arguments to R objects. When converting the
arguments to the C routine back to R objects, we use the
\Cfield{reverse} field of the converter element used to convert that
argument. This is stored when we convert the R object to C before the
call to the C routine. If the \Cfield{reverse} field of the converter
element is \CNull, we return \CVariable{R_NilValue}. Otherwise, if it
is non-null, we invoke it. We pass it the original argument, the C
value to which that was converted by the converter itself. We also
pass it auxiliary information defining the context in which the
conversion is being made. This includes the name of the function, all
of the arguments -- both C and R values -- , and the index of the
argument being converted. Finally, we also pass to the
\Croutine{reverse} routine the converter element itself. This allows
it to retrieve the \Cfield{userData} that can be used to parameterize
the \Croutine{matcher}, \Croutine{converter} and \Croutine{reverse}
routines. As one might expect, if the value of the R argument was not
handled by one of these user-registered converters, we use the regular
mechanism to convert the C value back to an R object.
\section{Extensions}
The change to the code is relatively minimal and hopefully the
performance impact will also be negligible in the case that there are
no registered converters.
We are developing a tool that can parse C code and determine the
return type of a routine. In that case, we can potentially convert the
return value in a semi-automatic fashion.
At present, the C routine is given no information about the type
expected by the C routine. We can use the new
\href{http://cm.bell-labs.com/stat/duncan/DynamicCSymbols.ps}{\Croutine{R_registerRoutines}}
mechanism for specifying information about the parameters of a C
routine accessible from S. The type of the parameter to which the R
object is being converted can then be optionally specified and can be
made available to the converter routine.
\section{An Example: Virtual Sequences}
This is a very simple example of using this facility and is merely a
description of the code in the
\href{http://cm.bell-labs.com/stat/duncan/SCConverters/SCConverters_1.0-0.tar.gz}
{SCConverters package}. It is an intentionally artificial example so
as to avoid requiring other packages such as hdf5, Python, Java, etc.
The idea is very basic. We provide an S class for representing
sequences symbolically. Objects of this virtual sequence do not
actually store or compute their elements but merely the symbolic
information that define these elements. In our case, we will look at
sequences that require knowing only the length. This is because they
are intended to represent sequences of the form $1, 2, \ldots,
length$.
\subsection{Constructor Function}
The constructor for these objects is as follows.
\begin{verbatim}
vseq <-
function(len)
{
len <- as.integer(len)
class(len) <- "VirtualSequence"
len
}
\end{verbatim}
\subsection{Coercion Function}
We provide coercion methods \SFunction{as.integer} and
\SFunction{as.double} to convert instances of the virtual sequence
class to virtual sequence objects with data of that class. Again, the
elements of the sequence will not be computed at this time. Instead,
the result of these coercion functions is a new object with a
different class. These classes are \SClass{VirtualIntegerSequence}
and \SClass{VirtualDoubleSequence}, and are prepended to the vector of
S3-style class names.
\begin{verbatim}
as.integer.VirtualSequence <-
function(x)
{
class(x) <- c("VirtualIntegerSequence", class(x))
x
}
as.double.VirtualSequence <-
function(x)
{
class(x) <- c("VirtualDoubleSequence", class(x))
x
}
\end{verbatim}
\subsection{Length Function}
We make \SFunction{length} generic
and define a method for \SClass{VirtualSequence}
objects.
\begin{verbatim}
length.VirtualSequence <-
function(x)
{
as.integer(unclass(x))
}
\end{verbatim}
\subsection{C Routines}
So far these objects don't do much. We can provide methods for
\SFunction{[}, etc. but this is not our focus here. Instead, we want
to pass instances of the \SClass{VirtualSequence} to C routines that
expect actual values and not a symbolic version. We define a simple C
routine that expects an array of \Ctype{Sint} values and a second
argument giving the length of this array.
This routine just computes the sum of the elements of the array and
returns this via the second argument.
This is defined easily as
\begin{verbatim}
void myTest(const Sint *vals, Sint *len)
{
int total = 0, i;
for(i = 0; i < *len; i++) {
total += vals[i];
}
*len = total;
}
\end{verbatim}
\subsection{The Converter}
In our example, we want to call
this routine and pass it a \SClass{VirtualSequence}
object as its first argument.
\begin{verbatim}
v <- vseq(10)
.C("myTest", as.integer(v), x = length(v))$x
\end{verbatim}
To do this, we will need to convert the sequence into actual values
and this is where the converters enter the picture. We want to have
the internal implementation of the \SFunction{.C} function recognize
the first argument as being special and call a routine that we provide
to create the appropriate array of \Ctype{Sint} objects.
The second argument will be converter in the usual manner
using the default conversion mechanism.
In order to have the \SFunction{.C} code call our converter routine,
we must first write it and then register it. We first provide the
predicate function that indicates whether it can handle the argument
to be converted. In our case, we want to handle any object which
inherits from the class \SClass{VirtualIntegerSequence} (i.e. the
value returned from \SFunction{as.integer} applied to a
\SClass{VirtualSequence} object). Since this involves matching the
class name of the object against the string
\texttt{"VirtualIntegerSequence"}, we can use the predicate routine
\Croutine{R_matchClass}.
The converter routine is quite simple. It needs to allocate an array
of \Ctype{Sint} values and fill them in with the values of the
array. The length of this array is taken from the value contained in
the \SClass{VirtualSequence} object being converted. In our simple
setup, this is obtained by coercing the object to an integer.
The code for this converter can be written as follows.
\begin{verbatim}
void *convertSeq(SEXP obj, R_CConvertInfo *inf, R_toCConverter *el)
{
Sint *ans;
int i, n;
n = asInteger(obj);
ans = (Sint *)R_alloc(n, sizeof(Sint));
for(i = 0; i < n ; i++) {
ans[i] = i+1;
}
return(ans);
}
\end{verbatim}
\subsection{Reverse Converter}
In our example, we are not interested in converting the results back
to R. The \Croutine{myTest} routine returns the answer via the second
argument. So we can discard the array we create in the converter
knowing that \Croutine{myTest} has not changed its values, etc.
Since we don't need a reverse converter, we simply specify this as
\CNull{} when registering the converter.
We now have all the components in order to register
the converter.
We do this with the call
\begin{verbatim}
R_addToCConverter(matchClass, convertSeq, NULL,
"VirtualIntegerSequence", "VirtualIntegerSequence to integer");
\end{verbatim}
We give it the predicate function and the user-level data it needs,
that is the name of the class we are prepared to handle with this
converter -- \texttt{"VirtualIntegerSequence"}. We also specify the
convert routine \Croutine{convertSeq}. And finally, we give a
description indicating that this converter handles turning a
\SClass{VirtualIntegerSequence} to an array of integers.
We can register the converter at any time. It is often convenient to
do this when the library is loaded. This can be done by calling a C
routine from the package's \SFunction{.First.lib}. Alternatively, one
can use the new initialization mechanism that calls the C routine
\Croutine{R_init_<lib name>}, if it exists.
We do this by defining the following routine
and registering the converter(s) within it.
\begin{verbatim}
void R_init_SCConverters(DllInfo *info)
{
R_addToCConverter(matchClass, convertSeq, NULL,
"VirtualIntegerSequence", "VirtualIntegerSequence to integer");
}
\end{verbatim}
\subsection{Querying the Converters}
Before invoking the \Croutine{myTest} routine,
we can examine what converters are registered, and
which are active.
\begin{verbatim}
> getCConverterDescriptions()
[1] "VirtualIntegerSequence to integer"
> getCConverterStatus()
VirtualIntegerSequence to integer
TRUE
\end{verbatim}
We could de-activate this converter
and check it has taken effect.
\begin{verbatim}
> setCConverterStatus(1, FALSE)
[1] TRUE
> getCConverterStatus()
VirtualIntegerSequence to integer
FALSE
\end{verbatim}
And we can re-activate it
easily with the command
\begin{verbatim}
> setCConverterStatus(1, TRUE)
\end{verbatim}
At this point, we want to call the \Croutine{myTest}
routine and check the converter.
\begin{verbatim}
> v <- vseq(10)
> .C("myTest", as.integer(v), length(v))
[[1]]
NULL
[[2]]
[1] 55
\end{verbatim}
Note that the first element of the returned list is \SNull. This
happens because we did not specify a reverse converter routine for
this particular conversion element.
The second value contains the sum of the elements in the
sequence, which is the same as \verb+sum(1:10)+
\subsection{Reverse Converters}
A more interesting example involves providing a reverse conversion
routine.
In this example, we will pass the sequence to a routine
that expects an array of \Ctype{double}s.
\begin{verbatim}
void myTest1(double *other, Sint *olen)
{
int i;
double sum = 0.0;
for(i = 0; i < *olen; i++)
sum += other[i];
other[0] = sum;
}
\end{verbatim}
This routine returns the sum of the elements as the
value of the first element passed to it.
We must retrieve that value and convert it
to an R object.
First, we must define a new converter to handle
\SClass{VirtualDoubleSequence} objects. This is very similar to the
converter for integers, but allocates an array of \Ctype{double}s
rather than \Ctype{Sint} elements.
\begin{verbatim}
void *convertDoubleSeq(SEXP obj, R_CConvertInfo *inf, R_toCConverter *el)
{
double *ans;
int i, n;
n = asInteger(obj);
ans = (double *)R_alloc(n, sizeof(double));
for(i = 0; i < n ; i++) {
ans[i] = i + 1;
}
return(ans);
}
\end{verbatim}
We can use the \Croutine{R_matchClass} as the predicate, giving the
class name \SClass{VirtualDoubleSequence}. What remains is writing
the reverse converter to take the array of \Ctype{double}s passed to
\Croutine{myTest1} and extracting the answer. In our case, we know
that we only want the first value. Therefore, we can use the following
routine.
\begin{verbatim}
SEXP reverseDoubleScalar(void *value, SEXP arg, R_FromCConvertInfo *info,
R_toCConverter *el)
{
SEXP ans = NEW_NUMERIC(1);
NUMERIC_DATA(ans)[0] = ((double*) value)[0];
return(ans);
}
\end{verbatim}
We register this converter using \Croutine{R_addToCConverter}
in the following manner:
\begin{verbatim}
R_addToCConverter(matchClass, convertDoubleSeq, reverseDoubleScalar,
"VirtualDoubleSequence",
"VirtualDoubleSequence to numeric");
\end{verbatim}
And now we are ready to invoke the \Croutine{myTest1} routine
and indirectly the converter routines.
\begin{verbatim}
> .C("myTest1", x=as.numeric(v), length(v))$x
[1] 55
\end{verbatim}
The reverse converter has access to contextual information via the
argument \CSymbol{info}. This is of type \Ctype{R_FromCConvertInfo}. It
contains the name of the C routine being invoked and all the arguments
passed from R and to the C routine itself. In the future, it will
also contain information about the C symbol as stored in the
\Ctype{DllInfo}. As we develop the tools, this may contain information
about the different parameters of the C routine, such as their type,
whether it can be modified by the routine, etc. This will provide
useful information that allow us omit converting values that will not
be used.
\end{document}