### buildNimbleFxnInterface(refname, symbolTable, basePtrCall)
### This is a function which builds a new reference class around
### a function which returns a pointer to a NimbleFxn.
### refname will be the name of the new class
### symbolTable will be a used to determine element types
### basePtrCall is the C++ call which builds the C++ object
### i.e. in R .Call(basePtrCall) should return the pointer
### to our NimbleFunction Class
### IMPORTANT NOTE: symbolTable MUST match form object pointed to by
### basePtrCall! In particular, if the symbolTable says an element is a
### scalar (i.e. nDims = 0) and it's really a NimArr (or vice versa),
### attempting to access this element will cause R to crash!
### Once the new class is built, a new object is create via refname$new()
### Access to the elements is provided through nimbleFxnObject$Varname
makeNFBindingFields <- function(symTab, cppNames) {
fieldList = list(.basePtr = "ANY", .DUMMY = "ANY") # We use this .DUMMY field to trick R into not mistakenly printing
# an error. See initialization function inside buildNimbleFxnInterface
vNames <- if(missing(cppNames)) names(symTab$symbols) else cppNames
for(vn in vNames) {
thisSymbol <- symTab$getSymbolObject(vn)
if(is.null(thisSymbol)) next
if(thisSymbol$type == 'model' || thisSymbol$type == 'symbolNodeFunctionVector' || thisSymbol$type == 'symbolModelVariableAccessorVector' ||thisSymbol$type == 'symbolModelValuesAccessorVector') next ## skip models and NodeFunctionVectors and modelVariableAccessors
ptrName = paste0(".", vn, "_Ptr")
fieldList[[ptrName]] <- "ANY" ## "ANY"
## Model variables:
if(inherits(thisSymbol,'symbolNimArrDoublePtr')) {
fieldList[[vn]] <- eval(substitute(
function(x) {
if(missing(x))
VPTR
else {
if(!inherits(x, 'externalptr')) stop(paste('Nimble compilation error initializing ptr ', VPTRname, '.'), call. = FALSE)
setDoublePtrFromSinglePtr(VPTR, x)
}
}, list(VPTR = as.name(ptrName), VPTRname = ptrName ) ) )
next
}
if(inherits(thisSymbol, 'symbolVecNimArrPtr')){
fieldList[[vn]] <- eval(substitute(
function(x) {
if(missing(x))
VPTR
else
{
if(!inherits(x, 'externalptr')) stop(paste('Nimble compilation error initializing ptr ', VPTRname, '.'), call. = FALSE)
setDoublePtrFromSinglePtr(VPTR, x)
}
}, list(VPTR = as.name(ptrName), VPTRname = ptrName ) ) )
next
}
if(inherits(thisSymbol, 'symbolNumericList') ) {
fieldList[[vn]] <- 'ANY'
next
}
if(inherits(thisSymbol, 'symbolNimbleFunction')) {
nfName <- paste0(".",vn,"_CnimbleFunction")
fieldList[[nfName]] <- "ANY" ## This will have the ref class object that interfaces to the C++ nimbleFunction
fieldList[[vn]] <- eval(substitute(
function(x) {
if(missing(x))
NFNAME
else {
if(!inherits(x, 'CnimbleFunctionBase')) stop(paste('Nimble compilation error initializing nimbleFunction ', NFNAMECHAR, '.'), call. = FALSE)
if(!inherits(x$.basePtr, 'externalptr')) stop(paste('Nimble compilation error initializing pointer for nimbleFunction ', NFNAMECHAR, '.'), call. = FALSE)
setDoublePtrFromSinglePtr(VPTR, x$.basePtr) ## check field name
assign(NFNAMECHAR, x, inherits = TRUE) ## avoids "<<-" warnings
}
}, list(VPTR = as.name(ptrName), NFNAME = as.name(nfName), NFNAMECHAR = nfName) ) )
next
}
if(inherits(thisSymbol, 'symbolModelValues')) { ## similar behavior to symbolNimArrDoublePtr
mvName <- paste0(".", vn, "_CmodelValues")
fieldList[[mvName]] <- "ANY" ## This will have the CmodelValues object
fieldList[[vn]] <- eval(substitute(
function(x) {
if(missing(x))
MVNAME
else {
if(!inherits(x, 'CmodelValues')) stop(paste('Nimble compilation error initializing modelVaues ', MVNAMECHAR, '.'), call. = FALSE)
if(!inherits(x$extptr, 'externalptr')) stop(paste('Nimble compilation error initializing pointer for modelValues ', MVNAMECHAR, '.'), call. = FALSE)
setDoublePtrFromSinglePtr(VPTR, x$extptr)
assign(MVNAMECHAR, x, inherits = TRUE) ## THIS WAY TO AVOID refClass "<<-" warnings
}
}, list(VPTR = as.name(ptrName), MVNAME = as.name(mvName), MVNAMECHAR = mvName ) ) )
next
}
if(inherits(thisSymbol, 'symbolNimPtrList')) { ## for nimbleFunctionList, set up with some partial generality but not all the way
nflName <- paste0(".",vn,"_CnimbleFunctionList")
accessorPtrName <- paste0(".", vn, "_setter_Ptr") ## "_setter" part must match nimbleDSL_class_symbolTable symbolNimPtrList
fieldList[[accessorPtrName]] <- "ANY"
fieldList[[nflName]] <- "ANY"
fieldList[[vn]] <- eval(substitute(
function(x) {
if(missing(x))
NFLNAME
else {
if(!inherits(x, 'nimPointerList')) stop(paste('Nimble compilation error initializing nimPointerList (nimbleFunctionList) ', NFLNAMECHAR, '.'), call. = FALSE)
if(!checkNimbleFunctionListCpp(x)) stop(paste('Nimble compilation error initializing nimbleFunctionList ', NFLNAMECHAR, '. Something is not valid in this list. It may be the contains (base class) value of one or more functions in the list.'), call. = FALSE)
setPtrVectorOfPtrs(ACCESSPTR, CONTENTSPTR, length(x$contentsList))
for(i in seq_along(x$contentsList)) {
if(!inherits(x[[i]]$.basePtr, 'externalptr')) stop(paste('Nimble compilation error initializing pointer ', i, ' of nimPointerList (nimbleFunctionList) ', NFLNAMECHAR, '.'), call. = FALSE)
setOnePtrVectorOfPtrs(ACCESSPTR, i, x[[i]]$.basePtr)
}
assign(NFLNAMECHAR, x, inherits = TRUE)
}
}, list(NFLNAME = as.name(nflName), NFLNAMECHAR = nflName, CONTENTSPTR = as.name(ptrName), ACCESSPTR = as.name(accessorPtrName) ) ) )
## getter: return the nimPointerList set up with the list of CinterfaceObjects
## setter: call setPtrVectorOfPtrs(accessorExtPtr, contentsExtrPtr. Then iterate and call setOnePtrVectorOfPtrs(accessorPtr, i, nimPtrList[[i]]$.basePtr)
next
}
if(inherits(thisSymbol, 'symbolBase')) {
if(thisSymbol$nDim > 0) {
eval(substitute( fieldList$VARNAME <- function(x){
if(missing(x) )
getNimValues(VPTR)
else
setNimValues(VPTR, x)
}, list(VPTR = as.name(ptrName), VARNAME = vn) ) )
next
}
if(thisSymbol$type == "double"){
eval(substitute( fieldList$VARNAME <- function(x){
if(missing(x) )
getDoubleValue(VPTR)
else
setDoubleValue(VPTR, x)
}, list(VPTR = as.name(ptrName), VARNAME = vn) ) )
next
}
if(thisSymbol$type == "integer"){
eval(substitute( fieldList$VARNAME <- function(x){
if(missing(x) )
getIntValue(VPTR)
else
setIntValue(VPTR, x)
}, list(VPTR = as.name(ptrName), VARNAME = vn) ) )
next
}
if(thisSymbol$type == "logical"){
eval(substitute( fieldList$VARNAME <- function(x){
if(missing(x) )
getBoolValue(VPTR)
else
setBoolValue(VPTR, x)
}, list(VPTR = as.name(ptrName), VARNAME = vn) ) )
next
}
warning("Warning: scalar datatype not current supported for variable ", vn, "\n", call. = FALSE)
browser()
return(NULL)
}
warning('Warning in trying to build interface: symbol ', vn, ' not understood.', call. = FALSE)
}
return(fieldList)
}
CnimbleFunctionBase <- setRefClass('CnimbleFunctionBase',
fields = list(
dll = "ANY",
compiledNodeFun = 'ANY',
Robject = 'ANY', ## this should be the refClassObject, not the function
cppNames = 'ANY',
cppCopyTypes = 'ANY',
neededObjects = 'ANY', ## A list of things like modelValues objects, if they don't already exist
nimbleProject = 'ANY'
),
methods = list(
initialize = function(dll = NULL, project = NULL, test = TRUE, ...) {
neededObjects <<- list()
if(!test) {
dll <<- dll
if(is.null(project)) {
warning('Missing project argument in CnimbleFunctionBase, from a nimbleFunction C++ interface. Could crash if there are member objects with project information needed.', call.=FALSE)
}
nimbleProject <<- project
}
callSuper(...)
},
setRobject = function(Robj) {
if(is.nf(Robj)) Robject <<- nf_getRefClassObject(Robj)
else Robject <<- Robj
Robject$.CobjectInterface <<- .self
},
buildNeededObjects = function(Robj) {
## .modelValuesSymbolTableLibrary should store the right dll- may not be this one
if(missing(Robj)) Robj <- Robject
for(iName in compiledNodeFun$nfProc$neededObjectNames) {
thisObj <- Robj[[iName]]
if(inherits(thisObj, 'modelValuesBaseClass')) {
if(inherits(thisObj$CobjectInterface, 'uninitializedField') || is.null(thisObj$CobjectInterface)) {
neededObjects[[iName]] <<- nimbleProject$instantiateCmodelValues(thisObj, dll)
}
next
}
if(is.nf(thisObj)) {
RCO <- nf_getRefClassObject(thisObj)
if(inherits(RCO$.CobjectInterface, 'uninitializedField') || is.null(RCO$.CobjectInterface)) {
## if(!exists('.CobjectInterface', envir = environment(thisObj), inherits = FALSE)) {
neededObjects[[iName]] <<- nimbleProject$instantiateNimbleFunction(thisObj, dll)
}
next
}
if(inherits(thisObj, 'nimbleFunctionList')) {
neededObjects[[iName]] <<- nimPointerList(thisObj$baseClass, length(thisObj$contentsList))
for(i in seq_along(thisObj$contentsList)) {
RCO <- nf_getRefClassObject(thisObj[[i]])
if(inherits(RCO$.CobjectInterface, 'uninitializedField') || is.null(RCO$.CobjectInterface)) {
##if(!exists('.CobjectInterface', envir = environment(thisObj[[i]]), inherits = FALSE)) {
neededObjects[[iName]][[i]] <<- nimbleProject$instantiateNimbleFunction(thisObj[[i]], dll)
} else {
neededObjects[[iName]][[i]] <<- RCO$.CobjectInterface ##environment(thisObj[[i]])$.CobjectInterface
}
}
names(neededObjects[[iName]]$contentsList) <<- names(thisObj$contentsList)
thisObj$CobjectInterface <- neededObjects[[iName]]
next
}
warning('Warning: object ',iName,' not of a type that can be built.', call. = FALSE)
}
},
copyFromRobject = function(Robj) {
if(missing(Robj)) Robj <- Robject
for(v in cppNames) {
if(is.null(cppCopyTypes[[v]])) next
if(is.null(Robj[[v]])) {
warning("Problem in copyFromRobject. There is an object to be copied that is NULL. Going to browser.", call. = FALSE)
browser()
}
if(cppCopyTypes[[v]] == 'modelVar') {
modelVar <- Robj[[v]] ## this is a singleVarAccessClass created by replaceModelSingles
Cmodel <- modelVar$model$CobjectInterface
varName <- modelVar$var
.self[[v]] <<- .Call('getModelObjectPtr', Cmodel$.basePtr, varName)
next
}
else if(cppCopyTypes[[v]] == 'nimbleFunction') {
modelVar <- Robj[[v]]
Cnf <- nf_getRefClassObject(modelVar)$.CobjectInterface ##environment(modelVar)$.CobjectInterface
.self[[v]] <- Cnf
next
}
else if(cppCopyTypes[[v]] == 'nimPtrList') {
if(is.null(Robj[[v]]$contentsList)) {
warning('Problem in copying a nimPtrList to C++ object. The contentsList is NULL. Going to browser', call. = FALSE)
browser()
}
if(any(unlist(lapply(Robj[[v]]$contentsList, is.null)))) {
warning('Problem in copying a nimPtrList to C++ object. The contentsList is NULL')
browser()
}
modelVar <- Robj[[v]] ## This is a nimPtrList
Cmv <- modelVar$CobjectInterface ## This was created above in build neededObjects
.self[[v]] <- Cmv
}
else if(cppCopyTypes[[v]] == 'modelValues') { ## somewhat similar to modelVar
rModelValues <- Robj[[v]]
Cmv <- rModelValues$CobjectInterface
k = getsize(rModelValues)
resize(Cmv, k)
vNames = rModelValues[['varNames']]
for(vN in vNames)
Cmv[vN,] <- rModelValues[vN,]
Cmv$symTab <- rModelValues$symTab
.self[[v]] <- Cmv
next
}
else if(cppCopyTypes[[v]] == 'nodeFxnVec') {
populateNodeFxnVec(fxnPtr = .basePtr, Robject = Robject, fxnVecName = v)
next
}
else if(cppCopyTypes[[v]] == 'modelVarAccess'){
populateManyModelVarAccess(fxnPtr = .basePtr, Robject = Robject, manyAccessName = v)
next
}
else if(cppCopyTypes[[v]] == 'modelValuesAccess'){
populateManyModelValuesAccess(fxnPtr = .basePtr, Robject = Robject, manyAccessName = v)
next
}
else if(cppCopyTypes[[v]] == "modelValuesPtr"){
curObj <- Robj[[v]]
mvPtr = curObj$modelValues$CobjectInterface$componentExtptrs[[curObj$var]]
.self[[v]] <<- mvPtr
next
}
else if(cppCopyTypes[[v]] == 'numericList'){
rawPtr = .Call('getModelObjectPtr', .basePtr, v)
.self[[v]] <<- numericList(buildType = 'C', extPtr = rawPtr)
nRows = Robj[[v]]$nRow
resize(.self[[v]], nRows)
for(i in 1:nRows){
copyDims = max(c(1, dimOrLength[[v]][[i]]) )
d1 = copyDims[1]
d2 = copyDims[2]
d3 = copyDims[3]
setSize(.self[[v]], i, d1, d2, d3)
.self[[v]][[i]] <<- Robj[[v]][[i]]
}
next
}
else if(cppCopyTypes[[v]] == 'numeric') {
.self[[v]] <<- Robj[[v]]
}
else
warning(paste0("Note: cppCopyTypes not recognized. Type = ", cppCopyTypes[[v]], "\n"), call. = FALSE)
}
},
lookupSymbol = function(symname) {
if(is.null(dll))
stop("No DLL for this object")
getNativeSymbolInfo(symname, dll)
}
))
makeNimbleFxnCppCopyTypes <- function(symTab, cppNames) {
ans <- list()
vNames <- if(missing(cppNames)) names(symTab$symbols) else cppNames
for(vn in vNames) {
thisSymbol <- symTab$getSymbolObject(vn)
if(is.null(thisSymbol)) next
else if(thisSymbol$type == 'Ronly') next ## skip models
else if(inherits(thisSymbol,'symbolNimArrDoublePtr')) {ans[[thisSymbol$name]] <- 'modelVar'; next}
else if(inherits(thisSymbol, 'symbolNodeFunctionVector')) { ans[[thisSymbol$name]] <- 'nodeFxnVec'; next}
else if(inherits(thisSymbol, 'symbolModelVariableAccessorVector')) {ans[[thisSymbol$name]] <- 'modelVarAccess';next}
else if(inherits(thisSymbol, 'symbolModelValuesAccessorVector')) {ans[[thisSymbol$name]] <- 'modelValuesAccess';next}
else if(inherits(thisSymbol, 'symbolModelValues')) {ans[[thisSymbol$name]] <- 'modelValues'; next}
else if(inherits(thisSymbol, 'symbolNimbleFunction')) {ans[[thisSymbol$name]] <- 'nimbleFunction'; next}
else if(inherits(thisSymbol, 'symbolVecNimArrPtr')) {ans[[thisSymbol$name]] <- 'modelValuesPtr'; next}
else if(inherits(thisSymbol, 'symbolNumericList')) {ans[[thisSymbol$name]] <- 'numericList'; next}
else if(inherits(thisSymbol, 'symbolNimPtrList')) {ans[[thisSymbol$name]] <- 'nimPtrList'; next}
else ans[[thisSymbol$name]] <- 'numeric'
}
ans
}
makeNimbleFxnInterfaceCallMethodCode <- function(compiledNodeFun) {
numFuns <- length(compiledNodeFun$RCfunDefs)
ans <- quote(list())
if(numFuns == 0) return(ans)
for(i in seq_along(compiledNodeFun$RCfunDefs)) {
## note that the className is really used as a boolean: any non-NULL value triggers treatment as a class, but name isn't needed
ans[[i+1]] <- compiledNodeFun$RCfunDefs[[i]]$buildRwrapperFunCode(className = compiledNodeFun$nfProc$name, includeLHS = FALSE, returnArgsAsList = FALSE, includeDotSelf = '.basePtr')
}
names(ans) <- c('', names(compiledNodeFun$RCfunDefs))
names(ans)[names(ans) == 'operator()'] <- 'run'
ans
}
buildNimbleFxnInterface <- function(refName, compiledNodeFun, basePtrCall, where = globalenv()){
defaults <- list()
if(inherits(compiledNodeFun, 'symbolTable')) {
symTab <- compiledNodeFun
defaults$cnf <- NULL
warning('No compiled node function provided, so interface will be incomplete')
} else {
symTab <- compiledNodeFun$nfProc$setupSymTab
defaults$cnf <- compiledNodeFun
}
## testObj = .Call(basePtrCall) ## We can no longer do this because we sometimes get here before there C++ code has been compiled and loaded
## cppNames = sort(.Call("getAvailableNames", testObj) )
## The following is really equivalent, because it comes *directly* from the place that generates the C++ code
cppNames <- compiledNodeFun$objectDefs$getSymbolNames()
NFBF <- makeNFBindingFields(symTab, cppNames)
defaults$cppCT <- makeNimbleFxnCppCopyTypes(symTab, cppNames)
methodsList <- makeNimbleFxnInterfaceCallMethodCode(compiledNodeFun) ##, compiledNodeFun$nfProc)
defaults$basePtrCall <- basePtrCall
fun <- substitute(function(nfObject, defaults, dll = NULL, project = NULL, ...){ #cModel removed from here
defaults$cnf$nfProc$evalNewSetupLinesOneInstance(nfObject, check = TRUE) ## in case this instance was not used during nfProc$process
callSuper(dll = dll, project = project, test = FALSE, ...)
basePtrCall <- if(is.character(defaults$basePtrCall)) {
if(inherits(dll, 'uninitializedField') | is.null(dll)) stop('Error making a nimbleFxnInterface object: no dll provided')
lookupSymbol(defaults$basePtrCall)
} else defaults$basePtrCall
.basePtr <<- .Call(basePtrCall)
cppNames <<- .Call("getAvailableNames", .basePtr)
cppCopyTypes <<- defaults$cppCT
compiledNodeFun <<- defaults$cnf
vPtrNames <- paste0('.', cppNames, '_Ptr')
for(vn in seq_along(cppNames) ){
# vPtrName <- paste(".", vn, "_Ptr", sep = "")
# eval(substitute(.DUMMY <<- newObjElementPtr(.basePtr, cppNames[vn]), list(.DUMMY = as.name(vPtrNames[vn]) ) ) )
.self[[vPtrNames[vn]]] <- newObjElementPtr(.basePtr, cppNames[vn])
#.self[[vPtrName]] <- newObjElementPtr(.basePtr, vn)
}
if(!missing(nfObject)) {
setRobject(nfObject)
buildNeededObjects()
copyFromRobject()
}
}, list())
# if we just have the name of the routine and haven't resolved it, arrange to resolve it when this initialization
# function is called. So change the .Call('name') to .Call(lookupSymbol('name')) which will use this objects
# dll field.
## if(is.character(basePtrCall))
## fun[[3]][[3]][[3]][[2]] = substitute(lookupSymbol(symname), list(symname = basePtrCall))
methodsList[[length(methodsList) + 1]] <- fun
names(methodsList)[length(methodsList)] <- 'initialize'
methodsList[[length(methodsList) + 1]] <- quote(function() {
writeLines(paste0("Derived CnimbleFunctionBase object created by buildNimbleFxnInterface for nimbleFunction with class ", class(Robject)))
})
names(methodsList)[length(methodsList)] <- 'show'
eval(substitute( newClass <- setRefClass(refName,
fields = FIELDS,
contains = 'CnimbleFunctionBase',
methods = ML,
where = where),
list(FIELDS = NFBF, ML = methodsList ) ) )
ans <- function(nfObject, dll = NULL, project) {
wrappedInterfaceBuild <- newClass$new
wrappedInterfaceBuild(nfObject, defaults, dll = dll, project = project)
# newClass$new(nfObject, defaults, dll = dll, project = project)
}
return(ans)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.