internal_function <- function(pointer){
f <- function(xp){
force(xp)
function(...){
.External( InternalFunction_invoke, xp, ... )
}
}
o <- new( "C++Function", f(pointer) )
o@pointer <- pointer
o
}
setMethod("$", "C++Class", function(x, name) {
x <- x@generator
eval.parent(substitute(x$name))
})
.badModulePointer <- NULL
.setModulePointer <- function(module, value) {
assign("pointer", value, envir = as.environment(module))
value
}
.getModulePointer <- function(module, mustStart = TRUE) {
pointer <- get("pointer", envir = as.environment(module))
if(is.null(pointer) && mustStart) {
Module(module, mustStart = TRUE)
pointer <- get("pointer", envir = as.environment(module))
}
pointer
}
setMethod("initialize", "Module",
function(.Object,
moduleName = "UNKNOWN",
packageName = "",
pointer = .badModulePointer, ...) {
env <- new.env(TRUE, emptyenv())
as(.Object, "environment") <- env
assign("pointer", pointer, envir = env)
assign("packageName", packageName, envir = env)
assign("moduleName", moduleName, envir = env)
if(length(list(...)) > 0) {
.Object <- callNextMethod(.Object, ...)
}
.Object
})
.get_Module_function <- function(x, name, pointer = .getModulePointer(x) ){
pointer <- .getModulePointer(x)
info <- .Call( Module__get_function, pointer, name )
fun_ptr <- info[[1L]]
is_void <- info[[2L]]
doc <- info[[3L]]
sign <- info[[4L]]
formal_args <- info[[5L]]
nargs <- info[[6L]]
f <- function(...) NULL
if( nargs == 0L ) formals(f) <- NULL
stuff <- list( fun_pointer = fun_ptr, InternalFunction_invoke = InternalFunction_invoke )
body(f) <- if( nargs == 0L ){
if( is_void ) {
substitute( {
.External( InternalFunction_invoke, fun_pointer)
invisible(NULL)
}, stuff )
} else {
substitute( {
.External( InternalFunction_invoke, fun_pointer)
}, stuff )
}
} else {
if( is_void ) {
substitute( {
.External( InternalFunction_invoke, fun_pointer, ... )
invisible(NULL)
}, stuff )
} else {
substitute( {
.External( InternalFunction_invoke, fun_pointer, ... )
}, stuff )
}
}
out <- new( "C++Function", f, pointer = fun_ptr, docstring = doc, signature = sign )
if( ! is.null( formal_args ) ){
formals( out ) <- formal_args
}
out
}
.get_Module_Class <- function( x, name, pointer = .getModulePointer(x) ){
value <- .Call( Module__get_class, pointer, name )
value@generator <- get("refClassGenerators", envir=x)[[value@.Data]]
value
}
setMethod( "$", "Module", function(x, name){
pointer <- .getModulePointer(x)
storage <- get( "storage", envir = as.environment(x) )
storage[[ name ]]
} )
new_CppObject_xp <- function(module, pointer, ...) {
.External( class__newInstance, module, pointer, ... )
}
new_dummyObject <- function(...)
.External( class__dummyInstance, ...)
cpp_object_initializer <- function(.self, .refClassDef, ..., .object_pointer){
invisible(.self$finalize)
selfEnv <- as.environment(.self)
fields <- .refClassDef@fieldPrototypes
pointer <- if(missing(.object_pointer)) new_CppObject_xp(fields$.module, fields$.pointer, ...) else .object_pointer
assign(".module", fields$.module, envir = selfEnv)
assign(".pointer", pointer, envir = selfEnv)
assign(".cppclass", fields$.pointer, envir = selfEnv)
.self
}
cpp_object_dummy <- function(.self, .refClassDef) {
selfEnv <- as.environment(.self)
fields <- .refClassDef@fieldPrototypes
pointer <- new_dummyObject()
assign(".module", fields$.module, envir = selfEnv)
assign(".pointer", pointer, envir = selfEnv)
assign(".cppclass", fields$.pointer, envir = selfEnv)
.self
}
cpp_object_maker <- function(typeid, pointer){
Class <- .classes_map[[ typeid ]]
new( Class, .object_pointer = pointer )
}
Module <- function( module, PACKAGE = methods::getPackageName(where), where = topenv(parent.frame()), mustStart = FALSE ) {
if (inherits(module, "DLLInfo") && missing(mustStart)) mustStart <- TRUE
if (inherits(module, "Module")) {
xp <- .getModulePointer(module, FALSE)
if(!missing(PACKAGE))
warning("ignoring PACKAGE argument in favor of internal package from Module object")
env <- as.environment(module)
PACKAGE <- get("packageName", envir = env)
moduleName <- get("moduleName", envir = env)
}
else if( identical( typeof( module ), "externalptr" ) ){
xp <- module
moduleName <- .Call( Module__name, xp )
module <- methods::new("Module", pointer = xp, packageName = PACKAGE,
moduleName = moduleName)
} else if(is.character(module)) {
moduleName <- module
xp <- .badModulePointer
module <- methods::new("Module", pointer = xp, packageName = PACKAGE,
moduleName = moduleName)
}
if(identical(xp, .badModulePointer)) {
if(mustStart) {
name <- sprintf( "_rcpp_module_boot_%s", moduleName )
symbol <- tryCatch(getNativeSymbolInfo( name, PACKAGE ),
error = function(e)e)
if(inherits(symbol, "error"))
stop(gettextf("Failed to initialize module pointer: %s",
symbol), domain = NA)
xp <- .Call( symbol )
.setModulePointer(module, xp)
}
else
return(module)
}
classes <- .Call( Module__classes_info, xp )
if(environmentIsLocked(where))
where <- .GlobalEnv
generators <- list()
storage <- new.env()
for( i in seq_along(classes) ){
CLASS <- classes[[i]]
clname <- CLASS@.Data
fields <- cpp_fields( CLASS, where )
methods <- cpp_refMethods(CLASS, where)
generator <- methods::setRefClass( clname,
fields = fields,
contains = "C++Object",
methods = methods,
where = where
)
.self <- .refClassDef <- NULL
generator$methods(initialize =
if (cpp_hasDefaultConstructor(CLASS))
function(...) Rcpp::cpp_object_initializer(.self,.refClassDef, ...)
else
function(...) {
if (nargs()) Rcpp::cpp_object_initializer(.self,.refClassDef, ...)
else Rcpp::cpp_object_dummy(.self, .refClassDef)
}
)
rm( .self, .refClassDef )
classDef <- methods::getClass(clname)
fields <- classDef@fieldPrototypes
assign(".pointer", CLASS@pointer, envir = fields)
assign(".module", xp, envir = fields)
assign(".CppClassName", clname, envir = fields)
generators[[clname]] <- generator
if( any( grepl( "^[[]", names(CLASS@methods) ) ) ){
if( "[[" %in% names( CLASS@methods ) ){
methods::setMethod( "[[", clname, function(x, i, j, ..., exact = TRUE){
x$`[[`( i )
}, where = where )
}
if( "[[<-" %in% names( CLASS@methods ) ){
methods::setReplaceMethod( "[[", clname, function(x, i, j, ..., exact = TRUE, value){
x$`[[<-`( i, value )
x
} , where = where )
}
}
if( any( grepl( "show", names(CLASS@methods) ) ) ){
setMethod( "show", clname, function(object) object$show(), where = where )
}
}
if(length(classes)) {
module$refClassGenerators <- generators
}
for( i in seq_along(classes) ){
CLASS <- classes[[i]]
clname <- CLASS@.Data
demangled_name <- sub( "^Rcpp_", "", clname )
.classes_map[[ CLASS@typeid ]] <- storage[[ demangled_name ]] <- .get_Module_Class( module, demangled_name, xp )
if( length( CLASS@enums ) ){
for( enum in CLASS@enums ){
for( i in 1:length(enum) ){
storage[[ paste( demangled_name, ".", names(enum)[i], sep = "" ) ]] <- enum[i]
}
}
}
}
functions <- .Call( Module__functions_names, xp )
for( fun in functions ){
storage[[ fun ]] <- .get_Module_function( module, fun, xp )
converter_rx <- "^[.]___converter___(.*)___(.*)$"
if( length( matches <- grep( converter_rx, functions ) ) ){
for( i in matches ){
fun <- functions[i]
from <- sub( converter_rx, "\\1", fun )
to <- sub( converter_rx, "\\2", fun )
converter <- function( from ){}
body( converter ) <- substitute( { CONVERT(from) },
list( CONVERT = storage[[fun]] )
)
setAs( from, to, converter, where = where )
}
}
}
assign( "storage", storage, envir = as.environment(module) )
module
}
dealWith <- function( x ) if(isTRUE(x[[1]])) invisible(NULL) else x[[2]]
method_wrapper <- function( METHOD, where ){
noargs <- all( METHOD$nargs == 0 )
stuff <- list(
class_pointer = METHOD$class_pointer,
pointer = METHOD$pointer,
CppMethod__invoke = CppMethod__invoke,
CppMethod__invoke_void = CppMethod__invoke_void,
CppMethod__invoke_notvoid = CppMethod__invoke_notvoid,
dealWith = dealWith,
docstring = METHOD$info("")
)
f <- function(...) NULL
if( noargs ){
formals(f) <- NULL
}
extCall <- if( noargs ) {
if( all( METHOD$void ) ){
substitute(
{
docstring
.External(CppMethod__invoke_void, class_pointer, pointer, .pointer )
invisible(NULL)
} , stuff )
} else if( all( ! METHOD$void ) ){
substitute(
{
docstring
.External(CppMethod__invoke_notvoid, class_pointer, pointer, .pointer )
} , stuff )
} else {
substitute(
{
docstring
dealWith( .External(CppMethod__invoke, class_pointer, pointer, .pointer ) )
} , stuff )
}
} else {
if( all( METHOD$void ) ){
substitute(
{
docstring
.External(CppMethod__invoke_void, class_pointer, pointer, .pointer, ...)
invisible(NULL)
} , stuff )
} else if( all( ! METHOD$void ) ){
substitute(
{
docstring
.External(CppMethod__invoke_notvoid, class_pointer, pointer, .pointer, ...)
} , stuff )
} else {
substitute(
{
docstring
dealWith( .External(CppMethod__invoke, class_pointer, pointer, .pointer, ...) )
} , stuff )
}
}
body(f, where) <- extCall
f
}
cpp_refMethods <- function(CLASS, where) {
finalizer <- eval( substitute(
function(){
.Call( CppObject__finalize, class_pointer , .pointer )
},
list(
CLASS = CLASS@pointer,
CppObject__finalize = CppObject__finalize,
class_pointer = CLASS@pointer
)
) )
mets <- c(
sapply( CLASS@methods, method_wrapper, where = where ),
"finalize" = finalizer
)
mets
}
cpp_hasDefaultConstructor <- function(CLASS) {
.Call( Class__has_default_constructor, CLASS@pointer )
}
binding_maker <- function( FIELD, where ){
f <- function( x ) NULL
body(f) <- substitute({
if( missing( x ) )
.Call( CppField__get, class_pointer, pointer, .pointer)
else
.Call( CppField__set, class_pointer, pointer, .pointer, x)
}, list(class_pointer = FIELD$class_pointer,
pointer = FIELD$pointer,
CppField__get = CppField__get,
CppField__set = CppField__set ))
environment(f) <- where
f
}
cpp_fields <- function( CLASS, where){
sapply( CLASS@fields, binding_maker, where = where )
}
.CppClassName <- function(name) {
paste0("Rcpp_",name)
}