Skip to content

[Rcpp-devel] integer arrays as arguments for a module function

7 messages · Chris DuBois, Dirk Eddelbuettel

#
Hi all,

I'm trying to figure out how to pass in an array of integers to a function
inside a module.  For example, adding the following function to
runit.Module.R works fine:

        int bla3( IntegerVector x ) {
              return sum(x);
        }

However, I need to pass an int array, rather than an IntegerVector.  Using
int x[] in the arguments doesn't compile (though I'm unfamiliar with C++ in
general, so maybe this shouldn't work anyway).

Alternatively, should I just cast x from an IntegerVector to an int array?
 I tried various permutations of as, vector, <int>, etc, and would like to
learn the proper way of doing this.

Thanks in advance,
Chris
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.r-forge.r-project.org/pipermail/rcpp-devel/attachments/20110812/6ed90a35/attachment.htm>
#
On 12 August 2011 at 14:50, Chris DuBois wrote:
| Hi all,
| 
| I'm trying to figure out how to pass in an array of integers to a function
| inside a module. ?For example, adding the following function to runit.Module.R
| works fine:
| 
| ? ? ? ? int bla3( IntegerVector x ) {
| ? ? ? ? ? ? ? return sum(x);
| ? ? ? ? }
| 
| However, I need to pass an int array, rather than an IntegerVector. ?Using int
| x[] in the arguments doesn't compile (though I'm unfamiliar with C++ in
| general, so maybe this shouldn't work anyway). ?
| 
| Alternatively, should I just cast x from an IntegerVector to an int array? ?I
| tried various permutations of as, vector, <int>, etc, and would like to learn
| the proper way of doing this.

You generally do not want old school x[] arrays in C++. Why?  Because STL
vectors do _everything_ they do at (essentially) zero added cost, free you
from malloc/free and still allow you to access the straight memory should you
need to (to talk to a C API, say).

So use IntegerVector for _the interface_. You can the, if you must, do

     IntegerVector x;
     
     int a1[] = x.begin();     // STL-style iterator to beginning of memory
     int *a2  = x.begin();     // idem

Hope this helps,  Dirk
#
Point taken: STL looks like the way to go in general.

In my particular example, however, the arrays get immediately cast to
another structure foo (somebody else's code).  So I need to cast from
IntegerVector to int[] before they get cast to foo[].  What you suggested
works perfectly (and makes sense in hindsight).

Is the story identical for char[]?  Where x is a CharacterVector, I tried

char* a = x.begin();

and got
error: cannot convert ?Rcpp::Vector<16>::iterator? to ?char*? in assignment

Any help much appreciated.
Chris
On Fri, Aug 12, 2011 at 3:19 PM, Dirk Eddelbuettel <edd at debian.org> wrote:

            
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.r-forge.r-project.org/pipermail/rcpp-devel/attachments/20110812/303d974c/attachment-0001.htm>
#
On 12 August 2011 at 16:59, Chris DuBois wrote:
| Point taken: STL looks like the way to go in general. ?
| 
| In my particular example, however, the arrays get immediately cast to another
| structure foo (somebody else's code). ?So I need to cast from IntegerVector to
| int[] before they get cast to foo[]. ?What you suggested works perfectly (and
| makes sense in hindsight).
| 
| Is the story identical for char[]? ?Where x is a CharacterVector, I tried?
| 
| char* a = x.begin();
| 
| and got
| error: cannot convert ?Rcpp::Vector<16>::iterator? to ?char*? in
| assignment

char can be a pain. It is something C and C++ didn't get quite right by
lacking a base type for string.  Doing it in plain C (as in *argv[] from
main()) is a pain but doable. 

CharacterVector works as the equivalent of std::vector< std::string >. Out of
each element (ie string) you can extract the underlying char* but you may
have to rely on strcmp etc.  Remember that you may be dealing with pointers
of pointers...  

Have a peek at the unitTests/ directory to see if you find something.

Hope this helps,  Dirk
 
| Any help much appreciated.
| Chris
|
| On Fri, Aug 12, 2011 at 3:19 PM, Dirk Eddelbuettel <edd at debian.org> wrote:
| 
|
| On 12 August 2011 at 14:50, Chris DuBois wrote:
|     | Hi all,
|     |
|     | I'm trying to figure out how to pass in an array of integers to a
|     function
|     | inside a module. ?For example, adding the following function to
|     runit.Module.R
|     | works fine:
|     |
|     | ? ? ? ? int bla3( IntegerVector x ) {
|     | ? ? ? ? ? ? ? return sum(x);
|     | ? ? ? ? }
|     |
|     | However, I need to pass an int array, rather than an IntegerVector.
|     ?Using int
|     | x[] in the arguments doesn't compile (though I'm unfamiliar with C++ in
|     | general, so maybe this shouldn't work anyway). ?
|     |
|     | Alternatively, should I just cast x from an IntegerVector to an int
|     array? ?I
|     | tried various permutations of as, vector, <int>, etc, and would like to
|     learn
|     | the proper way of doing this.
| 
|     You generally do not want old school x[] arrays in C++. Why? ?Because STL
|     vectors do _everything_ they do at (essentially) zero added cost, free you
|     from malloc/free and still allow you to access the straight memory should
|     you
|     need to (to talk to a C API, say).
| 
|     So use IntegerVector for _the interface_. You can the, if you must, do
| 
|     ? ? IntegerVector x;
| 
|     ? ? int a1[] = x.begin(); ? ? // STL-style iterator to beginning of
|     memory
|     ? ? int *a2 ?= x.begin(); ? ? // idem
| 
|     Hope this helps, ?Dirk
| 
|     --
|     Two new Rcpp master classes for R and C++ integration scheduled for
|     New York (Sep 24) and San Francisco (Oct 8), more details are at
|     http://dirk.eddelbuettel.com/blog/2011/08/04#
|     rcpp_classes_2011-09_and_2011-10
|     http://www.revolutionanalytics.com/products/training/public/
|     rcpp-master-class.php
| 
|
#
I didn't find anything too relevant in the unit tests.  I got a bit stuck,
and asked a question on StackOverflow here:
http://stackoverflow.com/questions/7048888/stdvectorstdstring-to-char-array
.

One answer seemed particularly promising (as shown by the working demo:
http://ideone.com/U6QZ5 ).

However, when I put this code into a module, I get an error:
error: argument of type ?char* (Foo::)(const std::string&)? does not match
?char* (Foo::*)(const std::basic_string<char>&)?

Here's the example I'm working with.  Commenting out the std::transform and
it compiles fine.  Why does it work OK when not in a module, but fails when
in a module?

R code:
inc <- paste(readLines('tests/convertCharExample.txt.cpp'),collapse="\n")
fx <- cxxfunction( signature(), "" , include = inc, plugin = "Rcpp" )
a <- Module( "foo_mod", getDynLib(fx) )
b <- new(a$Foo,1:5)
b$convertExample()

convertCharExample.txt.cpp code:
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
#include <cstring>

class Foo {
public:
  Foo(IntegerVector tail) {
    this->tail = tail;
  }

  char *convert(const std::string & s)
  {
    char *pc = new char[s.size()+1];
    std::strcpy(pc, s.c_str());
    return pc;
  }

  int convertExample() {
       std::vector<std::string>  vs;
       vs.push_back("std::string");
       vs.push_back("std::vector<std::string>");
       vs.push_back("char*");
       vs.push_back("std::vector<char*>");
       std::vector<char*>  vc;

       std::transform(vs.begin(), vs.end(), std::back_inserter(vc),
convert);

       for ( size_t i = 0 ; i < vc.size() ; i++ )
            std::cout << vc[i] << std::endl;

       for ( size_t i = 0 ; i < vc.size() ; i++ )
            delete [] vc[i];
       return 0;
  }
private:
  IntegerVector tail;
};

RCPP_MODULE(foo_mod){
using namespace Rcpp ;
 class_<Foo>( "Foo" )
          .constructor<IntegerVector>()
          .method( "convertExample", &Foo::convertExample ,"")
 ;
}
On Fri, Aug 12, 2011 at 5:31 PM, Dirk Eddelbuettel <edd at debian.org> wrote:

            
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.r-forge.r-project.org/pipermail/rcpp-devel/attachments/20110813/73ce0698/attachment.htm>
#
On 13 August 2011 at 00:52, Chris DuBois wrote:
| I didn't find anything too relevant in the unit tests. ?I got a bit stuck, and
| asked a question on StackOverflow here:?http://stackoverflow.com/questions/
| 7048888/stdvectorstdstring-to-char-array.?
|
| One answer seemed particularly promising (as shown by the working demo:http://
| ideone.com/U6QZ5?).

Nice.
 
| However, when I put this code into a module, I get an error:
| error: argument of type ?char* (Foo::)(const std::string&)? does not match
| ?char* (Foo::*)(const std::basic_string<char>&)?

That is an odd issue with string. Not sure I've seen that before.
 
| Here's the example I'm working with. ?Commenting out the std::transform and it
| compiles fine. ?Why does it work OK when not in a module, but fails when in a
| module?

I do not know -- maybe Romain has an idea?

What I would do is to forgo std::transform and just do what the convert
function does inside of a little worker loop. Which should compile.

That said, we probably shouldn't have the error you triggered.
 
Dirk

| R code:
| inc <- paste(readLines('tests/convertCharExample.txt.cpp'),collapse="\n")
| fx <- cxxfunction( signature(), "" , include = inc, plugin = "Rcpp" )
| a <- Module( "foo_mod", getDynLib(fx) )
| b <- new(a$Foo,1:5)
| b$convertExample()
| 
| convertCharExample.txt.cpp code:
| #include <iostream>
| #include <string>
| #include <vector>
| #include <algorithm>
| #include <iterator>
| #include <cstring>
| ?
| class Foo {
| public:
| ? Foo(IntegerVector tail) {
| ? ? this->tail = tail;
| ? }
| 
| ? char *convert(const std::string & s)
| ? {
| ? ? char *pc = new char[s.size()+1];
| ? ? std::strcpy(pc, s.c_str());
| ? ? return pc;?
| ? }
| 
| ? int convertExample() {
| ? ? ? ?std::vector<std::string> ?vs;
| ? ? ? ?vs.push_back("std::string");
| ? ? ? ?vs.push_back("std::vector<std::string>");
| ? ? ? ?vs.push_back("char*");
| ? ? ? ?vs.push_back("std::vector<char*>");
| ? ? ? ?std::vector<char*> ?vc;
| 
| ? ? ? ?std::transform(vs.begin(), vs.end(), std::back_inserter(vc),
| convert);
| 
| ? ? ? ?for ( size_t i = 0 ; i < vc.size() ; i++ )
| ? ? ? ? ? ? std::cout << vc[i] << std::endl;
| 
| ? ? ? ?for ( size_t i = 0 ; i < vc.size() ; i++ )
| ? ? ? ? ? ? delete [] vc[i];
| ? ? ? ?return 0;
| ? }
| private:
| ? IntegerVector tail;
| };
| 
| RCPP_MODULE(foo_mod){
| using namespace Rcpp ;
| class_<Foo>( "Foo" )
| ? ? ? ? ? .constructor<IntegerVector>() ? ?
| ? ? ? ? ? .method( "convertExample", &Foo::convertExample ,"")
| ;
| } ? ? ? ? ? ? ? ? ? ??
| 
|
| On Fri, Aug 12, 2011 at 5:31 PM, Dirk Eddelbuettel <edd at debian.org> wrote:
| 
|
| On 12 August 2011 at 16:59, Chris DuBois wrote:
|     | Point taken: STL looks like the way to go in general. ?
|     |
|     | In my particular example, however, the arrays get immediately cast to
|     another
|     | structure foo (somebody else's code). ?So I need to cast from
|     IntegerVector to
|     | int[] before they get cast to foo[]. ?What you suggested works perfectly
|     (and
|     | makes sense in hindsight).
|     |
|     | Is the story identical for char[]? ?Where x is a CharacterVector, I
|     tried?
|     |
|     | char* a = x.begin();
|     |
|     | and got
|     | error: cannot convert ?Rcpp::Vector<16>::iterator? to ?char*? in
|     | assignment
| 
|     char can be a pain. It is something C and C++ didn't get quite right by
|     lacking a base type for string. ?Doing it in plain C (as in *argv[] from
|     main()) is a pain but doable.
| 
|     CharacterVector works as the equivalent of std::vector< std::string >. Out
|     of
|     each element (ie string) you can extract the underlying char* but you may
|     have to rely on strcmp etc. ?Remember that you may be dealing with
|     pointers
|     of pointers...
| 
|     Have a peek at the unitTests/ directory to see if you find something.
| 
|     Hope this helps, ?Dirk
| 
|     | Any help much appreciated.
|     | Chris
|     |
|     | On Fri, Aug 12, 2011 at 3:19 PM, Dirk Eddelbuettel <edd at debian.org>
| wrote:
|     |
|     |
| | ? ? On 12 August 2011 at 14:50, Chris DuBois wrote:
|     | ? ? | Hi all,
|     | ? ? |
|     | ? ? | I'm trying to figure out how to pass in an array of integers to a
|     | ? ? function
|     | ? ? | inside a module. ?For example, adding the following function to
|     | ? ? runit.Module.R
|     | ? ? | works fine:
|     | ? ? |
|     | ? ? | ? ? ? ? int bla3( IntegerVector x ) {
|     | ? ? | ? ? ? ? ? ? ? return sum(x);
|     | ? ? | ? ? ? ? }
|     | ? ? |
|     | ? ? | However, I need to pass an int array, rather than an
|     IntegerVector.
|     | ? ? ?Using int
|     | ? ? | x[] in the arguments doesn't compile (though I'm unfamiliar with
|     C++ in
|     | ? ? | general, so maybe this shouldn't work anyway). ?
|     | ? ? |
|     | ? ? | Alternatively, should I just cast x from an IntegerVector to an
|     int
|     | ? ? array? ?I
|     | ? ? | tried various permutations of as, vector, <int>, etc, and would
|     like to
|     | ? ? learn
|     | ? ? | the proper way of doing this.
|     |
|     | ? ? You generally do not want old school x[] arrays in C++. Why?
|     ?Because STL
|     | ? ? vectors do _everything_ they do at (essentially) zero added cost,
|     free you
|     | ? ? from malloc/free and still allow you to access the straight memory
|     should
|     | ? ? you
|     | ? ? need to (to talk to a C API, say).
|     |
|     | ? ? So use IntegerVector for _the interface_. You can the, if you must,
|     do
|     |
|     | ? ? ? ? IntegerVector x;
|     |
|     | ? ? ? ? int a1[] = x.begin(); ? ? // STL-style iterator to
|     beginning of
|     | ? ? memory
|     | ? ? ? ? int *a2 ?= x.begin(); ? ? // idem
|     |
|     | ? ? Hope this helps, ?Dirk
|     |
|     | ? ? --
|     | ? ? Two new Rcpp master classes for R and C++ integration scheduled for
|     | ? ? New York (Sep 24) and San Francisco (Oct 8), more details are at
|     | ? ? http://dirk.eddelbuettel.com/blog/2011/08/04#
|     | ? ? rcpp_classes_2011-09_and_2011-10
|     | ? ? http://www.revolutionanalytics.com/products/training/public/
|     | ? ? rcpp-master-class.php
|     |
|     |
| 
|     --
|     Two new Rcpp master classes for R and C++ integration scheduled for
|     New York (Sep 24) and San Francisco (Oct 8), more details are at
|     http://dirk.eddelbuettel.com/blog/2011/08/04#
|     rcpp_classes_2011-09_and_2011-10
|     http://www.revolutionanalytics.com/products/training/public/
|     rcpp-master-class.php
| 
|
#
On 13 August 2011 at 07:07, Dirk Eddelbuettel wrote:
| On 13 August 2011 at 00:52, Chris DuBois wrote:
| | Here's the example I'm working with. ?Commenting out the std::transform and it
| | compiles fine. ?Why does it work OK when not in a module, but fails when in a
| | module?
| 
| I do not know -- maybe Romain has an idea?

Got it. Gotta "love" C++ error messages. Upon staring at (hand-indented)

file7b8c8784.cpp:49:76: error: argument of type \
  ?char* (Foo::)(const std::string&)? does not match \
  ?char* (Foo::*)(const std::basic_string<char>&)?

for a bit longer, I realized that it is not the 'std::string' vs
'std::basic_string' issue, but rather the 'Foo::' vs 'Foo::*' !

Making convert() a free function is all that it takes:


edd at max:/tmp$ r chris.r 
Loading required package: methods
std::string
std::vector<std::string>
char*
std::vector<char*>
edd at max:/tmp$ 


The file 'chris.r' is included below.  Thanks for posting a self-contained
example -- 'mud-wrestling' these issues one by one is still the best way
forward.

There may be a way to do it with convert() as a member function though...

Dirk


-----------------------------------------------------------------------------
library(inline)

inc <- '
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
#include <cstring>

char *convert(const std::string & s) {
  char *pc = new char[s.size()+1];
  std::strcpy(pc, s.c_str());
  return pc;
}

class Foo {
public:
  Foo(IntegerVector tail) {
    this->tail = tail;
  }

  int convertExample() {
       std::vector<std::string>  vs;
       vs.push_back("std::string");
       vs.push_back("std::vector<std::string>");
       vs.push_back("char*");
       vs.push_back("std::vector<char*>");
       std::vector<char*>  vc;

       std::transform(vs.begin(), vs.end(), std::back_inserter(vc), convert);

       for ( size_t i = 0 ; i < vc.size() ; i++ )
            std::cout << vc[i] << std::endl;

       for ( size_t i = 0 ; i < vc.size() ; i++ )
            delete [] vc[i];
       return 0;
  }
private:
  IntegerVector tail;
};

RCPP_MODULE(foo_mod){
using namespace Rcpp ;
class_<Foo>( "Foo" )
          .constructor<IntegerVector>()
          .method( "convertExample", &Foo::convertExample ,"")
;
}
'


#inc <- paste(readLines('tests/convertCharExample.txt.cpp'),collapse="\n")
fx <- cxxfunction( signature(), "" , include = inc, plugin = "Rcpp" )
a <- Module( "foo_mod", getDynLib(fx) )
b <- new(a$Foo,1:5)
b$convertExample()


-----------------------------------------------------------------------------