asBitwiseValue = function(val, defValues, className, prefix = NA) { if(is.character(val)) { i = pmatch(val, names(defValues)) if(!is.na(prefix) && any(is.na(i))) { i[is.na(i)] = pmatch(paste(prefix, val[i], sep = ""), names(defValues)) } } else { # check for a single scalar value i = match(val, defValues) # we didn't get a match, check for a combination if(any(is.na(i))) { tmp = sapply(defValues, function(x) bitAnd(val, x)) i = which(tmp != 0) if(length(i) == 0) stop("can't match ", val, " to elements of bitwise enumeration: ", paste(names(defValues), collapse = ", ")) } } if(any(is.na(i))) stop("unmatched name(s) ", val[is.na(i)]) value = bitlist(defValues[i]) # if className = NA, the we return the number. This is useful # to avoid the expense of creating a new instance only to # take the value to pass to C/C++ code. if(is.na(className)) return(value) # Create a new instance of the given class. id = paste(names(defValues)[i], collapse = " | ") ans = new(className, value) names(ans) = id ans } BitwiseValue = # # create one or more bitwise values. # function(val, name = names(val), class = if(is(val, "BitwiseValue")) class(val) else "BitwiseValue", asVector = TRUE, S3 = FALSE, defValues = getEnumValues(class, name)) { if(length(val) > 1 && !asVector) { lapply(seq(along = val), function(i) BitwiseValue(val[i], name[i], class)) } else { if(FALSE && S3) { ans = structure(val, names = name, class = unique(c(class, "BitwiseValue"))) } else { if(is(val, "character")) { if(missing(name)) name = val i = match(val, names(defValues)) if(any(is.na(i))) raiseEnumError(val, defValues, TRUE, FALSE, index = i) val = defValues[i] } if(!is.integer(val) && is.na(as.integer(val))) { # the value is too big for an integer in R. warning("BitwiseValue ", val, " doesn't fit into integer value") } ans = new(class, val) names(ans) = name } ans } } getEnumValues = function(class = NA, ids = character()) { if(!is.na(class)) { var = sprintf("%sValues", class) if(exists(var)) return(get(var)) } structure(sapply(ids, get), names = ids) } setAs("BitwiseValue", "numeric", function(from) { ans = bitlist(from) names(ans) = paste(names(from), collapse = " | ") ans }) setMethod("|", c("BitwiseValue", "BitwiseValue"), function(e1, e2) { if(class(e1) != class(e2) && !( is(e1, class(e2)) || is(e2, class(e1)))) warning("OR'ing two BitwiseValue objects of different class") v = bitlist(e1, e2) # if these are of different classes, we should decide what class the result # should be. BitwiseValue(v, paste(names(e1), names(e2), sep = " | "), class = class(e1)) }) setMethod("&", c("BitwiseValue", "BitwiseValue"), function(e1, e2) { if(class(e1) != class(e2) && !( is(e1, class(e2)) || is(e2, class(e1)))) warning("OR'ing two BitwiseValue objects of different class") v = bitAnd(e1, e2) # from package bitops # if these are of different classes, we should decide what class the result # should be. BitwiseValue(v, paste(names(e1), names(e2), sep = " & "), class = class(e1)) }) # Should this return a vector with the same number of elements as x # a single value? # Version of # Perhaps introduce a BitwiseValueVector to represent more than one element. if(FALSE) { setMethod("c", c("BitwiseValue"), function(x, ..., recursive = FALSE) { val = callNextMethod() val = val[ - grep("\\.\\.\\.[0-9]+", names(val)) ] names(val)[1] = gsub("^x\\.", "", names(val)[1]) val = structure(unlist(val), names = names(val)) BitwiseValue(val, class = class(x)) }) } setMethod("c", c("BitwiseValue"), function(x, ..., recursive = FALSE) { els = c(as(x, "numeric"), sapply(list(...), as, "numeric")) defValues = get(paste(class(x), "Values", sep = "")) return(asBitwiseValue(unlist(els), defValues, class(x))) })