createDerivedClass: Generate code for a derived C++ class with R functions as...

Description Usage Arguments Value Author(s) See Also Examples

Description

The goal of this function is to define a new C++ class that extends the specified C++ class and which allows implementations of the virtual methods within that class (and ancestors) via R functions. This allows us to override some or all of the methods entirely within R and have those R functions be transparently available to other C++ code. One can create an instance of this new C++ class from within R and specify functions for some of the methods either during the construction or during the life of that object. In this way, the class' methods become dynamic. This mechanism is thus very convenient for exploratory prototypying where we can update methods to handle new situations and fix bugs.

We can only override virtual methods in the C++ class, i.e. those methods that are declared virtual in that class or any of its ancestors.

Specifying an R function to use for a C++ method becomes slightly more troublesome when the method is overloaded, i.e. has multiple versions with different signatures.

This function attempts to deal with various forms of inputs and to do it somewhat efficiently by avoiding recomputing information from the translation unit.

If called with one or more class names and the TU nodes it resolves the class nodes and methods Essentially, if one wants to compute the class nodes ahead of time and resolve all their methods, this information can be reused and no computations duplicated uncessarily. It can work with resolved class definitions or the raw class nodes in the tu or with just the name of the class(es) of interest.

The class names of interest can be given as a character vector and the corresponding R names can be given as the names of this character vector. Any missing names are computed using the default naming scheme.

If one has computed the class nodes and resolved their methods already, then it is simplest to loop over the classes of interest and call this function for each of these. See the example below.

Usage

1
2
3
4
5
6
7
8
9
createDerivedClass(className, tu, types = DefinitionContainer(tu),
                   classNodes = getClassNodes(tu), methods = NULL,
                   classDefs = getClassDefs(tu, klasses = classNodes),
                   virtualOnly = TRUE, inheritanceStyle = "public",
                   typeMap = list(),
                   RClassName = paste("R", className, sep = ""),
                   RNativeBaseClassName = c(native = "RDerivedClass", r = "RDerivedClass"),
                  signatures = list(), dispatchInfo = data.frame(),
                   ...)

Arguments

className

a value identifying the class which we want to extend, i.e. the base class of our soon-to-be-created new, derived class. This can be the name of the class given as a string or alternatively a node in the translation unit that identifies the class definition, e.g. returned from a call to getClassNodes. One can specify a character vector with more than one element. The elements identify different existing classes by name and the code for an extended class will be developed for each of these base classes. (These are not treated as a collection of super-classes for a single new derived base class.) If the character vector has names, these are used as the names for the new, extended classes instead of the value of the RClassName argument.

tu

the translation unit nodes obtained via a call to parseTU

types

a DefinitionContainer object which is a mutable object (an environment) used to collect all the resolved TU nodes, data types, routines, etc. so as to avoid having to repeat the same calculations each time a node is needing to be resolved in a different context.

classNodes

a list of the nodes in the translation unit object (tu) which identify the ancestor classes of the newly defined class. If tu is specified, the default argument is usually appropriate.

methods

a list of the methods for all of the ancestor classes of the newly defined classes. If the tu object is provided, these can be computed automatically.

virtualOnly

a logical value indicating whether to provide overriding methods only for the virtual methods defined in the base class or any of its ancestors.

typeMap

an object of S3-style class TypeMap which provides information about the relationships between C/C++ types and corresponding R types, i.e. C to R type equivalencies, routines and R functions for converting from one to the other, etc.

inheritanceStyle

a string specifying the nature of the inheritance, i.e. one of "public" or "protected"

RClassName

the name to use for the new C++ class being defined.

...

additional parameters passed onto internal functions (origCreateDerivedClass)

classDefs

a list of the resolved class descriptions in the translation unit

RNativeBaseClassName

a character string giving the name of the C++ class that is used as the base class for newly derived classes that have methods that can be implemented in R.

signatures

a list of the call signatures for the different methods

dispatchInfo

a data frame. This is passed to and from the different helper functions and builds up information about the number of possible arguments for different methods.

Value

An list with several components:

classDefinition

the C++ code defining and implementing this new class

rsetClass

the R code defining the R version of this class.

rsetMethods

the C++ routine that can be called from R to set the R functions to be used as methods for this class.

setMethods

the C++ routine that actually sets these methods in the C++ instance/object

rsetMethodsFunction

the R function that sets the method functions within an instance of the newly created class, i.e. that calls the rsetMethods routine

rfieldAccessors

R method for accessing the fields in the base class(es) and ancestor classes

...

Author(s)

Duncan Temple Lang

See Also

getClassNodes resolveType DefinitionContainer

Examples

 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
## Not run: 
  # the next 5 commands are something that we do generally
  # when processing code
tu = parseTU(system.file("examples", "shapes.cc.t00.tu", package = "RGCCTranslationUnit"))

z = createDerivedClass("Ellipse", tu)

# Two classes in one action and amortize the cost of calculating the
# class nodes and resolving methods.
z = createDerivedClass(c("Rectangle", "Ellipse"), tu)


# This version explicitly computes the class nodes and resolves the methods
# presumably for use in other circumstances, e.g. generating the bindings to
# the existing classes and

types = DefinitionContainer(nodes = tu)
classNodes = getClassNodes(tu, "shapes")

methods = lapply(classNodes, function(n) resolveType(getClassMethods(n), tu, types))
zz = lapply(c("Rectangle", "Ellipse"),
        function(k) {
         def = resolveType(classNodes[[k]], tu, types)
         createDerivedClass(def, methods = methods[c(k, def@ancestorClasses)])
        })
                                                                       
if(identical(zz, z))
  cat("Same results with both approaches\n")



#
names(classNodes)
createDerivedClass(c(RRectangle = "Rectangle", RCircle = "Circle", REllipse = "Ellipse"), tu)




klasses = getClassNodes(tu, "shapes")
methods = lapply(klasses, getClassMethods)
def = DefinitionContainer(nodes = tu)

rect = resolveType(klasses[["Rectangle"]], tu, def)

resolvedMethods = lapply(methods, function(x) lapply(x, resolveType, tu, def))

  # This is the command that is specific to creating the code defining
  # a derived class.
code = createDerivedClass(rect, methods = resolvedMethods["Rectangle"],
                          RClassName = "R_Rectangle")
                           

code = createDerivedClass(rect, "R_Rectangle", methods = resolvedMethods["Rectangle"], virtualOnly = FALSE)

#
ellipse = resolveType(klasses[["Ellipse"]], tu, def)
code = createDerivedClass(ellipse, methods = methods, virtualOnly = TRUE)

#"R_Ellipse", resolvedMethods[c("Ellipse", "Circle", "Shape")],
#                          "Ellipse", getFields(klasses[[c("Ellipse")]]),
#                          virtualOnly = TRUE)


## End(Not run)

omegahat/RGCCTranslationUnit documentation built on May 24, 2019, 1:53 p.m.