Created
November 3, 2014 03:50
-
-
Save Sleepingwell/8588c5ee844ce0242d05 to your computer and use it in GitHub Desktop.
Holding a large number of SEXPs in C++
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <vector> | |
#include <utility> | |
#include <iterator> | |
#include <R.h> | |
#include <Rdefines.h> | |
template<typename Iter> | |
SEXP makePolygon(Iter b, Iter e) { | |
SEXP | |
coords; | |
double | |
*xi, | |
*yi; | |
size_t | |
n(static_cast<size_t>(std::distance(b, e))); | |
PROTECT(coords = allocMatrix(REALSXP, n, 2)); | |
xi = REAL(coords); | |
yi = xi + n; | |
for(; b!=e; ++b, ++xi, ++yi) { | |
*xi = b->first; | |
*yi = b->second; | |
} | |
// make call to Polygon_c to make the polygon here in practice, | |
// but just return the matrix for this little example | |
UNPROTECT(1); | |
return coords; | |
} | |
SEXP makePolygonsFromPairList(SEXP pairList) { | |
// make call to Polygons_c to make the polygons here in practice, | |
// but just return the list of 'polygons' for this little example. | |
return coerceVector(pairList, VECSXP); | |
} | |
struct PolyHolder { | |
PolyHolder(void) { | |
PROTECT_WITH_INDEX(currentRegion = R_NilValue, &icr); | |
PROTECT_WITH_INDEX(regions = R_NilValue, &ir); | |
} | |
~PolyHolder(void) { | |
UNPROTECT(2); | |
} | |
void notifyEndRegion(void) { | |
REPROTECT(regions = CONS(makePolygonsFromPairList(currentRegion), regions), ir); | |
REPROTECT(currentRegion = R_NilValue, icr); | |
} | |
template<typename Iter> | |
void addSubPolygon(Iter b, Iter e) { | |
REPROTECT(currentRegion = CONS(makePolygon(b, e), currentRegion), icr); | |
} | |
SEXP getPolygons(void) { | |
return regions; | |
} | |
private: | |
PROTECT_INDEX | |
ir, | |
icr; | |
SEXP | |
currentRegion, | |
regions; | |
}; | |
// The function to be used by .Call | |
// A silly little example that creates two 'regions', each | |
// of which contains two copies of the same polygon. | |
extern "C" SEXP testPolyHolder() { | |
typedef std::pair<double, double> Point; | |
typedef std::vector<Point> Polygon; | |
Polygon | |
p(5); | |
PolyHolder | |
ph; | |
// a unit square with lower left at origin | |
p[0] = p[4] = Point(0.0, 0.0); | |
p[1] = Point(0.0, 1.0); | |
p[2] = Point(1.0, 1.0); | |
p[3] = Point(1.0, 0.0); | |
for(int i(0); i<2; ++i) { | |
for(int j(0); j<2; ++j) { | |
ph.addSubPolygon(p.begin(), p.end()); | |
} | |
ph.notifyEndRegion(); | |
} | |
return ph.getPolygons(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment