Mercurial > pub > dyncall > bindings
view R/rdyncall/R/dynstruct.R @ 56:16151547265e
made callback example python 2 compatible, and added some randomness to numbers to sort
author | Tassilo Philipp |
---|---|
date | Tue, 02 Feb 2021 21:07:41 +0100 |
parents | 0cfcc391201f |
children |
line wrap: on
line source
# Package: rdyncall # File: R/dynstruct.R # Description: Handling of aggregate (struct/union) C types # ---------------------------------------------------------------------------- # dynport basetype sizes .basetypeSizes <- c( B=.Machine$sizeof.long, c=1, C=1, s=2, S=2, i=4, I=4, j=.Machine$sizeof.long, J=.Machine$sizeof.long, l=.Machine$sizeof.longlong, L=.Machine$sizeof.longlong, f=4, d=8, p=.Machine$sizeof.pointer, x=.Machine$sizeof.pointer, Z=.Machine$sizeof.pointer, v=0 ) # ---------------------------------------------------------------------------- # dynport type information # TypeInfo <- function(name, type = c("base","pointer","struct","union"), size = NA, align = NA, basetype = NA, fields = NA, signature = NA) { type <- match.arg(type) x <- list(name = name, type = type, size = size, align = align, basetype = basetype, fields = fields, signature = signature) class(x) <- "typeinfo" return(x) } is.TypeInfo <- function(x) { inherits(x, "typeinfo") } getTypeInfo <- function(name, envir=parent.frame()) { if (is.character(name)) { getTypeInfoByName(name, envir) } else if (is.TypeInfo(name)) { name } else { stop("unknown type") } } getTypeInfoByName <- function(typeName, envir=parent.frame()) { char1 <- substr(typeName, 1, 1) switch(char1, "*"=TypeInfo(name=typeName, type="pointer", size=.Machine$sizeof.pointer, align=.Machine$sizeof.pointer, basetype=substr(typeName,2,nchar(typeName)), signature=typeName), "<"={ x <- getTypeInfo(substr(typeName, 2,nchar(typeName)-1), envir=envir) if (!is.null(x)) return(x) else return(TypeInfo(name=typeName, type="struct")) }, { # try as basetype basetypeSize <- unname(.basetypeSizes[typeName]) if ( !is.na(basetypeSize) ) return(TypeInfo(name=typeName,type="base", size=basetypeSize, align=basetypeSize, signature=typeName)) # try lookup symbol else if (exists(typeName,envir=envir) ) { info <- get(typeName,envir=envir) if (!inherits(info, "typeinfo")) stop("not a type information symbol") return(info) } # otherwise fail else NULL # else stop("unknown type info: ",typeName) } ) } # ---------------------------------------------------------------------------- # align C offsets align <- function(offset, alignment) { as.integer( as.integer( (offset + alignment-1) / alignment ) * alignment ) } # ---------------------------------------------------------------------------- # field information (structures and unions) makeFieldInfo <- function(fieldNames, types, offsets) { data.frame(type=I(types), offset=offsets, row.names=fieldNames) } # ---------------------------------------------------------------------------- # parse structure signature makeStructInfo <- function(name, signature, fieldNames, envir=parent.frame()) { # computations: types <- character() offsets <- integer() offset <- 0 maxAlign <- 1 # scan variables: n <- nchar(signature) i <- 1 start <- i while(i <= n) { char <- substr(signature,i,i) if (char == "*") { i <- i + 1 ; next } else if (char == "<") { i <- i + 1 while (i < n) { if ( substr(signature,i,i) == ">" ) break i <- i + 1 } } typeName <- substr(signature, start, i) types <- c(types, typeName) typeInfo <- getTypeInfo(typeName, envir=envir) alignment <- typeInfo$align maxAlign <- max(maxAlign, alignment) offset <- align( offset, alignment ) offsets <- c(offsets, offset) # increment offset by size offset <- offset + typeInfo$size # next token i <- i + 1 start <- i } # align the structure size (compiler-specific?) size <- align(offset, maxAlign) # build field information fields <- makeFieldInfo(fieldNames, types, offsets) TypeInfo(name=name,type="struct",size=size,align=maxAlign,fields=fields) } parseStructInfos <- function(sigs, envir=parent.frame()) { # split functions at ';' sigs <- unlist( strsplit(sigs, ";") ) # split name/struct signature at '(' sigs <- strsplit(sigs, "[{]") infos <- list() for (i in seq(along=sigs)) { n <- length(sigs[[i]]) if ( n == 2 ) { # parse structure name name <- sigs[[i]][[1]] name <- gsub("[ \n\t]*","",name) # split struct signature and field names tail <- unlist( strsplit(sigs[[i]][[2]], "[}]") ) sig <- tail[[1]] if (length(tail) == 2) fields <- unlist( strsplit( tail[[2]], "[ \n\t]+" ) ) else fields <- NULL assign(name, makeStructInfo(name, sig, fields, envir=envir), envir=envir) } } } # ---------------------------------------------------------------------------- # parse union signature makeUnionInfo <- function(name, signature, fieldNames, envir=parent.frame()) { # computations: types <- character() maxSize <- 0 maxAlign <- 1 # scan variables: i <- 1 start <- i n <- nchar(signature) while(i <= n) { char <- substr(signature,i,i) if (char == "*") { i <- i + 1 ; next } else if (char == "<") { i <- i + 1 while (i < n) { if ( substr(signature,i,i) == ">" ) break i <- i + 1 } } typeName <- substr(signature,start,i) types <- c(types, typeName) typeInfo <- getTypeInfo(typeName, envir) maxSize <- max( maxSize, typeInfo$size ) maxAlign <- max( maxAlign, typeInfo$align ) # next token i <- i + 1 start <- i } offsets <- rep(0, length(types) ) fields <- makeFieldInfo(fieldNames, types, offsets) TypeInfo(name=name, type="union", fields=fields, size=maxSize, align=maxAlign) } parseUnionInfos <- function(sigs, envir=parent.frame()) { # split functions at ';' sigs <- unlist( strsplit(sigs, ";") ) # split name/union signature at '|' sigs <- strsplit(sigs, "[|]") infos <- list() for (i in seq(along=sigs)) { n <- length(sigs[[i]]) if ( n == 2 ) { # parse union name name <- sigs[[i]][[1]] name <- gsub("[ \n\t]*","",name) # split union signature and field names tail <- unlist( strsplit(sigs[[i]][[2]], "[}]") ) sig <- tail[[1]] if (length(tail) == 2) fields <- unlist( strsplit( tail[[2]], "[ \n\t]+" ) ) else fields <- NULL assign( name, makeUnionInfo(name, sig, fields, envir=envir), envir=envir ) } } } # ---------------------------------------------------------------------------- # raw backed struct's (S3 Class) as.struct <- function(x, type) { if (is.TypeInfo(x)) structName <- type$name attr(x, "struct") <- type class(x) <- "struct" return(x) } new.struct <- function(type) { if (is.character(type)) { name <- type type <- getTypeInfo(type) } else if (is.TypeInfo(type)) { name <- type$name } else { stop("type is not of class TypeInfo and no character string") } if (! type$type %in% c("struct","union") ) stop("type must be C struct or union.") x <- raw( type$size ) class(x) <- "struct" attr(x, "struct") <- type$name return(x) } "$.struct" <- unpack.struct <- function(x, index) { structName <- attr(x, "struct") structInfo <- getTypeInfo(structName) fieldInfos <- structInfo$fields offset <- fieldInfos[index,"offset"] if (is.na(offset)) stop("unknown field index '", index ,"'") fieldTypeName <- as.character(fieldInfos[[index,"type"]]) fieldTypeInfo <- getTypeInfo(fieldTypeName) if (fieldTypeInfo$type %in% c("base","pointer")) { .unpack(x, offset, fieldTypeInfo$signature) } else if ( !is.null(fieldTypeInfo$fields) ) { if (is.raw(x)) { size <- fieldTypeInfo$size as.struct( x[(offset+1):(offset+1+size-1)], fieldTypeName) } else if (is.externalptr(x)) { as.struct( offsetPtr(x, offset), fieldTypeName) } } else { stop("invalid field type '", fieldTypeName,"' at field '", index ) } } "$<-.struct" <- pack.struct <- function( x, index, value ) { structName <- attr(x, "struct") structInfo <- getTypeInfo(structName) fieldInfos <- structInfo$fields offset <- fieldInfos[index,"offset"] if (is.na(offset)) stop("unknown field index '", index ,"'") fieldTypeName <- as.character(fieldInfos[index,"type"]) fieldTypeInfo <- getTypeInfo(fieldTypeName) if ( fieldTypeInfo$type %in% c("base","pointer") ) { .pack( x, offset, fieldTypeInfo$signature, value ) } else if ( !is.null(fieldTypeInfo$fields) ) { # substructure size <- fieldTypeInfo$size x[(offset+1):(offset+1+size-1)] <- as.raw(value) } else { stop("invalid field type '", fieldTypeName,"' at field '", index ) } return(x) } print.struct <- function(x, indent=0, ...) { structName <- attr(x, "struct") structInfo <- getTypeInfo(structName) fieldInfos <- structInfo$fields fieldNames <- rownames(fieldInfos) cat( "struct ", structName, " ") if (typeof(x) == "externalptr") { cat ("*") if (is.nullptr(x)) { cat("=NULL\n") return() } } cat("{\n") # print data without last for (i in seq(along=fieldNames)) { cat( rep(" ", indent+1), fieldNames[[i]] , ":" ) val <- unpack.struct(x, fieldNames[[i]]) if (typeof(val) == "externalptr") val <- "ptr" # .extptr2str(val) if (class(val) == "struct") { print.struct(val, indent=indent+1) } else cat( val, "\n" ) } cat( rep(" ", indent), "}\n") }