From 73cb5bfc45a5f820e9786226dc9564a393c0f2a3 Mon Sep 17 00:00:00 2001 From: hcirellu Date: Thu, 13 Nov 2025 20:24:48 +0100 Subject: [PATCH 1/6] new coercion methods and consistency for existing ones --- NAMESPACE | 16 ++ NEWS.md | 2 + R/bit64-package.R | 2 +- R/integer64.R | 275 +++++++++++++++++++++------- man/as.character.integer64.Rd | 37 ++++ man/as.integer64.character.Rd | 40 +++- tests/testthat/test-bit64-package.R | 98 ++++++++++ tests/testthat/test-integer64.R | 83 ++++++++- 8 files changed, 472 insertions(+), 81 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index c7d7bd5..1a67ec0 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -33,19 +33,33 @@ S3method(aperm,integer64) S3method(as.bitstring,integer64) S3method(as.character,integer64) S3method(as.data.frame,integer64) +S3method(as.difftime,default) +S3method(as.difftime,integer64) S3method(as.double,integer64) S3method(as.integer,integer64) S3method(as.integer64,"NULL") +S3method(as.integer64,Date) +S3method(as.integer64,POSIXct) +S3method(as.integer64,POSIXlt) S3method(as.integer64,bitstring) S3method(as.integer64,character) +S3method(as.integer64,complex) +S3method(as.integer64,difftime) S3method(as.integer64,double) S3method(as.integer64,factor) S3method(as.integer64,integer) S3method(as.integer64,integer64) S3method(as.integer64,logical) +S3method(as.integer64,raw) S3method(as.list,integer64) S3method(as.logical,integer64) S3method(base::anyNA,integer64) +S3method(base::as.Date,integer64) +S3method(base::as.POSIXct,integer64) +S3method(base::as.POSIXlt,integer64) +S3method(base::as.complex,integer64) +S3method(base::as.numeric,integer64) +S3method(base::as.raw,integer64) S3method(c,integer64) S3method(cbind,integer64) S3method(ceiling,integer64) @@ -185,6 +199,7 @@ export(as.bitstring) export(as.bitstring.integer64) export(as.character.integer64) export(as.data.frame.integer64) +export(as.difftime) export(as.double.integer64) export(as.integer.integer64) export(as.integer64) @@ -399,6 +414,7 @@ importFrom(graphics,barplot) importFrom(graphics,par) importFrom(graphics,title) importFrom(methods,as) +importFrom(methods,callGeneric) importFrom(methods,is) importFrom(stats,cor) importFrom(stats,median) diff --git a/NEWS.md b/NEWS.md index 056cc06..a8fcb99 100644 --- a/NEWS.md +++ b/NEWS.md @@ -42,6 +42,8 @@ ## NEW FEATURES 1. `anyNA` gets an `integer64` method. Thanks @hcirellu. +1. `as.Date`, `as.POSIXct`, `as.POSXlt`, `as.raw`, `as.difftime` get an `integer64` method. +1. `as.integer64` gets `Date`, `POSIXct`, `POSXlt`, `raw`, `difftime` methods. ## BUG FIXES diff --git a/R/bit64-package.R b/R/bit64-package.R index d32b917..2fe42e4 100644 --- a/R/bit64-package.R +++ b/R/bit64-package.R @@ -695,7 +695,7 @@ #' ramsort ramsortorder repeat.time setattr shellorder shellsort #' shellsortorder still.identical xor #' @importFrom graphics barplot par title -#' @importFrom methods as is +#' @importFrom methods as is callGeneric #' @importFrom stats cor median quantile #' @importFrom utils head packageDescription strOptions tail #' @export : :.default :.integer64 diff --git a/R/integer64.R b/R/integer64.R index f8eb4f8..b3b75e6 100644 --- a/R/integer64.R +++ b/R/integer64.R @@ -42,6 +42,11 @@ NULL #' @param x an integer64 vector #' @param keep.names FALSE, set to TRUE to keep a names vector #' @param ... further arguments to the [NextMethod()] +#' @param origin further arguments to the [NextMethod()] +#' @param tz further arguments to the [NextMethod()] +#' @param tim further arguments to the [NextMethod()] +#' @param format further arguments to the [NextMethod()] +#' @param units further arguments to the [NextMethod()] #' #' @return `as.bitstring` returns a string of class 'bitstring'. #' @@ -63,7 +68,8 @@ NULL #' @param x an atomic vector #' @param keep.names FALSE, set to TRUE to keep a names vector #' @param ... further arguments to the [NextMethod()] -#' +#' @param units further arguments to the [NextMethod()] +#' #' @details #' `as.integer64.character` is realized using C function `strtoll` which #' does not support scientific notation. Instead of '1e6' use '1000000'. @@ -556,7 +562,7 @@ identical.integer64 <- function(x, y, #' @rdname as.integer64.character #' @export -as.integer64 <- function(x, ...) UseMethod("as.integer64") +as.integer64 <- function(x, keep.names=FALSE, ...) UseMethod("as.integer64") #' @rdname as.character.integer64 #' @export @@ -651,120 +657,247 @@ binattr <- function(e1, e2) { #' @return `integer64` returns a vector of 'integer64', i.e., #' a vector of [double()] decorated with class 'integer64'. #' @export -integer64 <- function(length=0L) { - ret <- double(length) - oldClass(ret) <- "integer64" +integer64 = function(length=0L) { + ret = double(length) + oldClass(ret) = "integer64" ret } #' @rdname bit64-package #' @param x an integer64 vector #' @export -is.integer64 <- function(x) inherits(x, "integer64") +is.integer64 = function(x) inherits(x, "integer64") #' @rdname as.integer64.character #' @export -as.integer64.NULL <- function(x, ...) { - ret <- double() - oldClass(ret) <- "integer64" - ret -} +as.integer64.NULL = function(x, keep.names=FALSE, ...) integer64() #' @rdname as.integer64.character #' @export -as.integer64.integer64 <- function(x, ...) x +as.integer64.integer64 = function(x, keep.names=FALSE, ...) x #' @rdname as.integer64.character #' @export -as.integer64.double <- function(x, keep.names=FALSE, ...) { - ret <- .Call(C_as_integer64_double, x, double(length(x))) - if (keep.names) - names(ret) <- names(x) - oldClass(ret) <- "integer64" +as.integer64.double = function(x, keep.names=FALSE, ...) { + ret = .Call(C_as_integer64_double, x, double(length(x))) + if (isTRUE(keep.names)) + names(ret) = names(x) + oldClass(ret) = "integer64" + ret +} + +#' @rdname as.integer64.character +#' @exportS3Method as.integer64 complex +as.integer64.complex = function(x, keep.names=FALSE, ...) { + xd = withCallingHandlers( + as.double(x), + warning = function(w) { + warning(conditionMessage(w), call.=FALSE) + invokeRestart("muffleWarning") + } + ) + ret = .Call(C_as_integer64_double, xd, double(length(xd))) + if (isTRUE(keep.names)) + names(ret) = names(x) + oldClass(ret) = "integer64" ret } #' @rdname as.integer64.character #' @export -as.integer64.integer <- function(x, ...) { - ret <- .Call(C_as_integer64_integer, x, double(length(x))) - oldClass(ret) <- "integer64" +as.integer64.integer = function(x, keep.names=FALSE, ...) { + ret = .Call(C_as_integer64_integer, x, double(length(x))) + if (isTRUE(keep.names)) + names(ret) = names(x) + oldClass(ret) = "integer64" + ret +} + +#' @rdname as.integer64.character +#' @exportS3Method as.integer64 raw +as.integer64.raw = function(x, keep.names=FALSE, ...) { + ret = .Call(C_as_integer64_integer, as.integer(x), double(length(x))) + if (isTRUE(keep.names)) + names(ret) = names(x) + oldClass(ret) = "integer64" ret } #' @rdname as.integer64.character #' @export -as.integer64.logical <- as.integer64.integer +as.integer64.logical = as.integer64.integer #' @rdname as.integer64.character #' @export -as.integer64.character <- function(x, ...) { - n <- length(x) - ret <- .Call(C_as_integer64_character, x, rep(NA_real_, n)) - oldClass(ret) <- "integer64" +as.integer64.character = function(x, keep.names=FALSE, ...) { + ret = .Call(C_as_integer64_character, x, rep(NA_real_, length(x))) + if (isTRUE(keep.names)) + names(ret) = names(x) + oldClass(ret) = "integer64" ret } #' @rdname as.integer64.character #' @export -as.integer64.factor <- function(x, ...) as.integer64(unclass(x), ...) +as.integer64.factor = function(x, keep.names=FALSE, ...) as.integer64(unclass(x), keep.names=keep.names, ...) -#' @rdname as.character.integer64 -#' @export -as.double.integer64 <- function(x, keep.names=FALSE, ...) { - ret <- .Call(C_as_double_integer64, x, double(length(x))) - if (keep.names) - names(ret) <- names(x) +#' @rdname as.integer64.character +#' @exportS3Method as.integer64 Date +as.integer64.Date = function(x, keep.names=FALSE, ...) { + n = names(x) + x = as.double(x) + names(x) = n + callGeneric() +} + +#' @rdname as.integer64.character +#' @exportS3Method as.integer64 POSIXct +as.integer64.POSIXct = function(x, keep.names=FALSE, ...) { + n = names(x) + x = as.double(x) + names(x) = n + callGeneric() +} + +#' @rdname as.integer64.character +#' @exportS3Method as.integer64 POSIXlt +as.integer64.POSIXlt = function(x, keep.names=FALSE, ...) { + callGeneric(x=as.POSIXct(x), keep.names=keep.names, ...) +} + +#' @rdname as.integer64.character +#' @exportS3Method as.integer64 difftime +as.integer64.difftime = function(x, keep.names=FALSE, units="auto", ...) { + n = names(x) + x = as.double(x, units=units, ...) + names(x) = n + callGeneric() +} + +.as_double_integer64 = function(x, keep.names=FALSE, keep.attributes=FALSE, ...) { + ret = .Call(C_as_double_integer64, x, double(length(x))) + if (isTRUE(keep.attributes)) { + # like dimensions for matrix operations + a = attributes(x) + a$class = NULL + attributes(ret) = a + keep.names = FALSE # names are already included + } + if (isTRUE(keep.names)) + names(ret) = names(x) ret } #' @rdname as.character.integer64 #' @export -as.integer.integer64 <- function(x, ...) { +as.double.integer64 = function(x, keep.names=FALSE, ...) + .as_double_integer64(x, keep.names, keep.attributes=FALSE, ...) + +#' @rdname as.character.integer64 +#' @exportS3Method base::as.numeric integer64 +as.numeric.integer64 = as.double.integer64 + +#' @rdname as.character.integer64 +#' @exportS3Method base::as.complex integer64 +as.complex.integer64 = function(x, ...) as.complex(as.double(x), ...) + +#' @rdname as.character.integer64 +#' @export +as.integer.integer64 = function(x, ...) .Call(C_as_integer_integer64, x, integer(length(x))) + +#' @rdname as.character.integer64 +#' @exportS3Method base::as.raw integer64 +as.raw.integer64 = function(x, ...) { + withCallingHandlers( + as.raw(.Call(C_as_integer_integer64, x, integer(length(x)))), + warning = function(w) { + warning(conditionMessage(w), call.=FALSE) + invokeRestart("muffleWarning") + } + ) } #' @rdname as.character.integer64 #' @export -as.logical.integer64 <- function(x, ...) { +as.logical.integer64 = function(x, ...) .Call(C_as_logical_integer64, x, logical(length(x))) -} #' @rdname as.character.integer64 #' @export -as.character.integer64 <- function(x, ...) { - n <- length(x) - .Call(C_as_character_integer64, x, rep(NA_character_, n)) -} +as.character.integer64 = function(x, ...) + .Call(C_as_character_integer64, x, rep(NA_character_, length(x))) #' @rdname as.character.integer64 #' @export -as.bitstring.integer64 <- function(x, ...) { - n <- length(x) - ret <- .Call(C_as_bitstring_integer64, x, rep(NA_character_, n)) - oldClass(ret) <- 'bitstring' +as.bitstring.integer64 = function(x, ...) { + ret = .Call(C_as_bitstring_integer64, x, rep(NA_character_, length(x))) + oldClass(ret) = 'bitstring' ret } +#' @rdname as.character.integer64 +#' @exportS3Method base::as.Date integer64 +as.Date.integer64 = function(x, origin, ...) { + x = as.double(x) + callGeneric() +} + +#' @rdname as.character.integer64 +#' @exportS3Method base::as.POSIXct integer64 +as.POSIXct.integer64 = function(x, tz="", origin, ...) { + x = as.double(x) + callGeneric() +} + +#' @rdname as.character.integer64 +#' @exportS3Method base::as.POSIXlt integer64 +as.POSIXlt.integer64 = function(x, tz="", origin, ...) { + x = as.double(x, ...) + callGeneric() +} + +#' @rdname as.character.integer64 +#' @export +as.difftime = function(tim, format="%X", units="auto", tz="UTC", ...) UseMethod("as.difftime") +#' @exportS3Method as.difftime default +as.difftime.default = function(tim, format="%X", units="auto", tz ="UTC", ...) { + base::as.difftime(tim, format=format, units=units, tz=tz) +} + +#' @rdname as.character.integer64 +#' @exportS3Method as.difftime integer64 +as.difftime.integer64 = function(tim, format="%X", units="auto", tz="UTC", ...) { + tim = as.double(tim) + NextMethod() +} + #' @rdname as.character.integer64 #' @export -print.bitstring <- function(x, ...) { - oldClass(x) <- minusclass(class(x), 'bitstring') +print.bitstring = function(x, ...) { + oldClass(x) = minusclass(class(x), 'bitstring') NextMethod(x) } #' @rdname as.integer64.character #' @export -as.integer64.bitstring <- function(x, ...) { - ret <- .Call(C_as_integer64_bitstring, x, double(length(x))) - oldClass(ret) <- "integer64" +as.integer64.bitstring <- function(x, keep.names=FALSE, ...) { + ret = .Call(C_as_integer64_bitstring, x, double(length(x))) + oldClass(ret) = "integer64" + if (isTRUE(keep.names)) + names(ret) = names(x) ret } - # read.table expects S4 as() -methods::setAs("character", "integer64", function(from) as.integer64.character(from)) -methods::setAs("integer64", "character", function(from) as.character.integer64(from)) +methods::setAs("ANY", "integer64", function(from) as.integer64(from)) +methods::setAs("integer64", "factor", function(from) as.factor(from)) +methods::setAs("integer64", "ordered", function(from) as.ordered(from)) +methods::setAs("integer64", "difftime", function(from) as.difftime(from, units="secs")) +methods::setAs("integer64", "POSIXct", function(from) as.POSIXct(from)) +methods::setAs("integer64", "POSIXlt", function(from) as.POSIXlt(from)) +methods::setAs("integer64", "Date", function(from) as.Date(from)) +methods::setAs("integer64", "raw", function(from) as.raw(from)) # this is a trick to generate NA_integer64_ for namespace export before # as.integer64() is available because dll is not loaded @@ -824,19 +957,35 @@ print.integer64 <- function(x, quote=FALSE, ...) { #' @param object an integer64 vector #' @param vec.len,give.head,give.length see [utils::str()] #' @export -str.integer64 <- function(object, - vec.len = strO$vec.len, - give.head = TRUE, - give.length = give.head, - ...) { - strO <- strOptions() - vec.len <- 2L*vec.len - n <- length(object) - if (n > vec.len) - object <- object[seq_len(vec.len)] +str.integer64 = function(object, vec.len=strO$vec.len, give.head=TRUE, give.length=give.head, ...) { + strO = strOptions() + vec.len = 2L*vec.len + n = length(object) + displayObject = object[seq_len(min(vec.len, length(object)))] + cat( - if (give.head) paste0("integer64 ", if (give.length && n>1L) paste0("[1:", n, "] ")), - paste(as.character(object), collapse=" "), + if (isTRUE(give.head)) { + if (length(object) == 0L && is.null(dim(object))) { + "integer64(0)" + } else { + paste0( + "integer64 ", + if (length(object) > 1L && is.null(dim(object))) { + if (isTRUE(give.length)) paste0("[1:", n, "] ") else " " + } else if (!is.null(dim(object))) { + dimO = dim(object) + if (prod(dimO) != n) + stop(gettextf("dims [product %d] do not match the length of object [%d]", prod(dimO), n, domain="R")) + if (length(dimO) == 1L) { + paste0("[", n, "(1d)] ") + } else { + paste0("[", paste(vapply(dimO, function(el) {if (el < 2L) as.character(el) else paste0("1:", el)}, ""), collapse = ", "), "] ") + } + } + ) + } + }, + paste(as.character(displayObject), collapse=" "), if (n > vec.len) " ...", " \n", sep="" diff --git a/man/as.character.integer64.Rd b/man/as.character.integer64.Rd index e4aaafc..33109e3 100644 --- a/man/as.character.integer64.Rd +++ b/man/as.character.integer64.Rd @@ -4,9 +4,16 @@ \alias{as.character.integer64} \alias{as.bitstring} \alias{as.double.integer64} +\alias{as.complex.integer64} \alias{as.integer.integer64} +\alias{as.raw.integer64} \alias{as.logical.integer64} \alias{as.bitstring.integer64} +\alias{as.Date.integer64} +\alias{as.POSIXct.integer64} +\alias{as.POSIXlt.integer64} +\alias{as.difftime} +\alias{as.difftime.integer64} \alias{print.bitstring} \alias{as.list.integer64} \title{Coerce from integer64} @@ -15,14 +22,34 @@ as.bitstring(x, ...) \method{as.double}{integer64}(x, keep.names = FALSE, ...) +\method{as.complex}{integer64}(x, ...) + \method{as.integer}{integer64}(x, ...) +\method{as.raw}{integer64}(x, ...) + \method{as.logical}{integer64}(x, ...) \method{as.character}{integer64}(x, ...) \method{as.bitstring}{integer64}(x, ...) +\method{as.Date}{integer64}(x, origin, ...) + +\method{as.POSIXct}{integer64}(x, tz = "", origin, ...) + +\method{as.POSIXlt}{integer64}(x, tz = "", origin, ...) + +as.difftime(tim, format = "\%X", units = "auto", tz = "UTC", ...) + +\method{as.difftime}{integer64}( + tim, + format = "\%X", + units = "auto", + tz = "UTC", + ... +) + \method{print}{bitstring}(x, ...) \method{as.list}{integer64}(x, ...) @@ -33,6 +60,16 @@ as.bitstring(x, ...) \item{...}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} \item{keep.names}{FALSE, set to TRUE to keep a names vector} + +\item{origin}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} + +\item{tz}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} + +\item{tim}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} + +\item{format}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} + +\item{units}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} } \value{ \code{as.bitstring} returns a string of class 'bitstring'. diff --git a/man/as.integer64.character.Rd b/man/as.integer64.character.Rd index 146f0f1..da9aeeb 100644 --- a/man/as.integer64.character.Rd +++ b/man/as.integer64.character.Rd @@ -7,9 +7,15 @@ \alias{as.integer64.NULL} \alias{as.integer64.integer64} \alias{as.integer64.double} +\alias{as.integer64.complex} \alias{as.integer64.integer} +\alias{as.integer64.raw} \alias{as.integer64.logical} \alias{as.integer64.factor} +\alias{as.integer64.Date} +\alias{as.integer64.POSIXct} +\alias{as.integer64.POSIXlt} +\alias{as.integer64.difftime} \alias{as.integer64.bitstring} \alias{NA_integer64_} \title{Coerce to integer64} @@ -17,32 +23,46 @@ An object of class \code{integer64} of length 1. } \usage{ -as.integer64(x, ...) +as.integer64(x, keep.names = FALSE, ...) -\method{as.integer64}{`NULL`}(x, ...) +\method{as.integer64}{`NULL`}(x, keep.names = FALSE, ...) -\method{as.integer64}{integer64}(x, ...) +\method{as.integer64}{integer64}(x, keep.names = FALSE, ...) \method{as.integer64}{double}(x, keep.names = FALSE, ...) -\method{as.integer64}{integer}(x, ...) +\method{as.integer64}{complex}(x, keep.names = FALSE, ...) -\method{as.integer64}{logical}(x, ...) +\method{as.integer64}{integer}(x, keep.names = FALSE, ...) -\method{as.integer64}{character}(x, ...) +\method{as.integer64}{raw}(x, keep.names = FALSE, ...) -\method{as.integer64}{factor}(x, ...) +\method{as.integer64}{logical}(x, keep.names = FALSE, ...) -\method{as.integer64}{bitstring}(x, ...) +\method{as.integer64}{character}(x, keep.names = FALSE, ...) + +\method{as.integer64}{factor}(x, keep.names = FALSE, ...) + +\method{as.integer64}{Date}(x, keep.names = FALSE, ...) + +\method{as.integer64}{POSIXct}(x, keep.names = FALSE, ...) + +\method{as.integer64}{POSIXlt}(x, keep.names = FALSE, ...) + +\method{as.integer64}{difftime}(x, keep.names = FALSE, units = "auto", ...) + +\method{as.integer64}{bitstring}(x, keep.names = FALSE, ...) NA_integer64_ } \arguments{ \item{x}{an atomic vector} -\item{...}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} - \item{keep.names}{FALSE, set to TRUE to keep a names vector} + +\item{units}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} + +\item{...}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} } \value{ The other methods return atomic vectors of the expected types diff --git a/tests/testthat/test-bit64-package.R b/tests/testthat/test-bit64-package.R index 2db72f3..63b65e7 100644 --- a/tests/testthat/test-bit64-package.R +++ b/tests/testthat/test-bit64-package.R @@ -178,6 +178,12 @@ test_that("Coercion", { as.double(as.integer64(c(NA, seq(0.0, 9.0, 0.25)))), as.double(as.integer(c(NA, seq(0.0, 9.0, 0.25)))) ) + if (getRversion() >= "4.0.0") { + expect_identical( + as.complex(as.integer64(c(NA, seq(0.0, 9.0, 0.25)))), + as.complex(as.integer(c(NA, seq(0.0, 9.0, 0.25)))) + ) + } expect_identical( as.character(as.integer64(c(NA, seq(0.0, 9.0, 0.25)))), as.character(as.integer(c(NA, seq(0.0, 9.0, 0.25)))) @@ -186,6 +192,16 @@ test_that("Coercion", { as.integer(as.integer64(c(NA, seq(0.0, 9.0, 0.25)))), as.integer(c(NA, seq(0.0, 9.0, 0.25))) ) + expect_warning( + expect_warning( + expect_identical( + as.raw(as.integer64(c(NA, seq(0.0, 9.0, 0.25)))), + as.raw(c(NA, seq(0.0, 9.0, 0.25))) + ), fixed=TRUE, + "out-of-range values treated as 0 in coercion to raw" + ), fixed=TRUE, + "out-of-range values treated as 0 in coercion to raw" + ) expect_identical( as.logical(as.integer64(c(NA, seq(0.0, 9.0, 0.25)))), as.logical(as.integer(c(NA, seq(0.0, 9.0, 0.25)))) @@ -202,6 +218,14 @@ test_that("Coercion", { as.integer64(as.double(as.integer64(-9:9))), as.integer64(-9:9) ) + expect_identical( + as.integer64(as.complex(-9:9)), + as.integer64(-9:9) + ) + expect_identical( + as.integer64(as.raw(0:9)), + as.integer64(0:9) + ) expect_identical( as.integer64(as.character(as.integer64(-9:9))), as.integer64(-9:9) @@ -210,6 +234,80 @@ test_that("Coercion", { as.integer64(as.character(lim.integer64())), lim.integer64() ) + expect_identical( + as(as.raw(1L), "integer64"), + as.integer64(1L) + ) + expect_identical( + as(TRUE, "integer64"), + as.integer64(1L) + ) + expect_identical( + as(111L, "integer64"), + as.integer64(111L) + ) + expect_identical( + as(111, "integer64"), + as.integer64(111L) + ) + expect_identical( + as(111+0i, "integer64"), + as.integer64(111L) + ) + expect_identical( + as("111", "integer64"), + as.integer64(111L) + ) + expect_identical( + as(as.factor(111), "integer64"), + as.integer64(1L) + ) + expect_identical( + as(as.ordered(111), "integer64"), + as.integer64(1L) + ) + if (getRversion() >= "4.0.0") { + expect_identical( + as(as.integer64(1L), "raw"), + as.raw(1L) + ) + } + expect_identical( + as(as.integer64(1L), "logical"), + TRUE + ) + expect_identical( + as(as.integer64(111L), "integer"), + 111L + ) + expect_identical( + as(as.integer64(111L), "integer"), + 111L + ) + expect_identical( + as(as.integer64(111L), "numeric"), + 111 + ) + expect_identical( + as(as.integer64(111L), "double"), + 111 + ) + expect_identical( + as(as.integer64(111L), "complex"), + 111+0i + ) + expect_identical( + as(as.integer64(111L), "character"), + "111" + ) + expect_identical( + as(as.integer64(111L), "factor"), + as.factor("111") + ) + expect_identical( + as(as.integer64(111L), "ordered"), + as.ordered("111") + ) }) test_that("Logical operators", { diff --git a/tests/testthat/test-integer64.R b/tests/testthat/test-integer64.R index ecdc9eb..9d79f55 100644 --- a/tests/testthat/test-integer64.R +++ b/tests/testthat/test-integer64.R @@ -1,23 +1,92 @@ test_that("integer64 coercion to/from other types work", { # from integer64 + i32 = 1:10 + i64 = as.integer64(i32) expect_identical(as.logical(as.integer64(0:1)), c(FALSE, TRUE)) - expect_identical(as.integer(as.integer64(1:10)), 1:10) - expect_identical(as.character(as.integer64(1:10)), as.character(1:10)) - expect_identical(as.double(as.integer64(1:10)), as.double(1:10)) - expect_identical(as.numeric(as.integer64(1:10)), as.numeric(1:10)) - + expect_identical(as.integer(i64), i32) + expect_identical(as.character(i64), as.character(i32)) + expect_identical(as.double(i64), as.double(i32)) + expect_identical(as.numeric(i64), as.numeric(i32)) + expect_identical(as.complex(i64), as.complex(i32)) + expect_identical(as.raw(i64), as.raw(i32)) + expect_identical(as.factor(i64), as.factor(i32)) + expect_identical(as.ordered(i64), as.ordered(i32)) + if (getRversion() >= "4.0.0") { + expect_identical(as.Date(i64), as.Date(as.numeric(i32))) + expect_identical(as.Date(i64, origin=10), as.Date(as.numeric(i32), origin=10)) + expect_identical(as.POSIXct(i64), as.POSIXct(as.numeric(i32))) + expect_identical(as.POSIXct(i64, origin=10), as.POSIXct(as.numeric(i32), origin=10)) + expect_identical(as.POSIXct(i64, tz="UTC", origin=10), as.POSIXct(as.numeric(i32), tz="UTC", origin=10)) + expect_identical(as.POSIXct(i64, tz="CET", origin=10), as.POSIXct(as.numeric(i32), tz="CET", origin=10)) + expect_identical(as.POSIXlt(i64), as.POSIXlt(i32)) + expect_identical(as.POSIXlt(i64, origin=10), as.POSIXlt(i32, origin=10)) + expect_identical(as.POSIXlt(i64, tz="UTC", origin=10), as.POSIXlt(i32, tz="UTC", origin=10)) + expect_identical(as.POSIXlt(i64, tz="CET", origin=10), as.POSIXlt(i32, tz="CET", origin=10)) + expect_error(as.difftime(i32), "need explicit units for numeric conversion", fixed=TRUE) + expect_error(as.difftime(i64), "need explicit units for numeric conversion", fixed=TRUE) + expect_identical(as.difftime(i64, units="secs"), as.difftime(i32, units="secs")) + } + # to integer64 expect_identical(as.integer64(TRUE), as.integer64(1L)) expect_identical(as.integer64(as.character(1:10)), as.integer64(1:10)) expect_identical(as.integer64(as.double(1:10)), as.integer64(1:10)) + expect_identical(as.integer64(as.complex(1:10)), as.integer64(1:10)) + expect_identical(as.integer64(as.raw(1:10)), as.integer64(1:10)) + expect_identical(as.integer64(as.factor(11:20)), as.integer64(1:10)) + expect_identical(as.integer64(as.ordered(11:20)), as.integer64(1:10)) expect_identical(as.integer64(NULL), as.integer64()) x = as.integer64(1:10) expect_identical(as.integer64(x), x) - + p = c(Sys.time(), Sys.time()) + expect_identical( + as.integer64(difftime(p+1000, p)), + as.integer64(as.integer(difftime(p+1000, p))) + ) + # as.integer.difftime does not work with `units` + expect_identical( + as.integer64(difftime(p+1000, p), units="secs"), + as.integer64(as.numeric(difftime(p+1000, p), units="secs")) + ) + expect_identical( + as.integer64(difftime(p+1000, p), units="mins"), + as.integer64(as.numeric(difftime(p+1000, p), units="mins")) + ) + expect_identical(as.integer64(p), as.integer64(as.integer(p))) + # as.integer.POSIXlt does not work properly + expect_identical(as.integer64(as.POSIXlt(p)), as.integer64(as.numeric(as.POSIXlt(p)))) + expect_identical(as.integer64(as.Date(p)), as.integer64(as.integer(as.Date(p)))) + # S4 version expect_identical(methods::as(as.character(1:10), "integer64"), as.integer64(1:10)) + expect_identical(methods::as(as.factor(11:20), "integer64"), as.integer64(1:10)) + expect_identical(methods::as(as.ordered(11:20), "integer64"), as.integer64(1:10)) + expect_warning(expect_identical(methods::as(as.complex(1:10) + 0+1i, "integer64"), as.integer64(1:10)), "imaginary parts discarded in coercion") + expect_identical(methods::as(as.numeric(1:10), "integer64"), as.integer64(1:10)) + expect_identical(methods::as(as.integer(1:10), "integer64"), as.integer64(1:10)) + expect_identical(methods::as(as.raw(1:10), "integer64"), as.integer64(1:10)) + expect_identical(methods::as(as.logical(0:2), "integer64"), as.integer64(c(0L, 1L, 1L))) + expect_identical(methods::as(difftime(p+1000, p), "integer64"), as.integer64(difftime(p+1000, p))) + expect_identical(methods::as(p, "integer64"), as.integer64(p)) + expect_identical(methods::as(as.POSIXlt(p), "integer64"), as.integer64(as.POSIXlt(p))) + expect_identical(methods::as(as.Date(p), "integer64"), as.integer64(as.Date(p))) expect_identical(methods::as(as.integer64(1:10), "character"), as.character(1:10)) - + expect_identical(methods::as(as.integer64(1:10), "factor"), as.factor(1:10)) + expect_identical(methods::as(as.integer64(1:10), "ordered"), as.ordered(1:10)) + expect_identical(methods::as(as.integer64(1:10), "complex"), as.complex(1:10)) + expect_identical(methods::as(as.integer64(1:10), "numeric"), as.numeric(1:10)) + expect_identical(methods::as(as.integer64(1:10), "integer"), as.integer(1:10)) + if (getRversion() >= "4.0.0") { + expect_identical(methods::as(as.integer64(1:10), "raw"), as.raw(1:10)) + } + expect_identical(methods::as(as.integer64(1:10), "logical"), as.logical(1:10)) + if (getRversion() >= "4.0.0") { + expect_identical(methods::as(as.integer64(1:10), "difftime"), as.difftime(1:10, units="secs")) + expect_identical(methods::as(as.integer64(1:10), "POSIXct"), as.POSIXct(as.numeric(1:10))) + expect_identical(methods::as(as.integer64(1:10), "POSIXlt"), as.POSIXlt(1:10)) + expect_identical(methods::as(as.integer64(1:10), "Date"), as.Date(as.numeric(1:10))) + } + # now for NA expect_identical(as.logical(NA_integer64_), NA) expect_identical(as.integer(NA_integer64_), NA_integer_) From 1727c1a1d547a9ef52a1c7f44b897260cfb0fad0 Mon Sep 17 00:00:00 2001 From: hcirellu Date: Thu, 13 Nov 2025 20:24:48 +0100 Subject: [PATCH 2/6] new coercion methods and consistency for existing ones --- NAMESPACE | 16 ++ NEWS.md | 2 + R/bit64-package.R | 2 +- R/integer64.R | 275 +++++++++++++++++++++------- man/as.character.integer64.Rd | 37 ++++ man/as.integer64.character.Rd | 40 +++- tests/testthat/test-bit64-package.R | 98 ++++++++++ tests/testthat/test-integer64.R | 83 ++++++++- 8 files changed, 472 insertions(+), 81 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index c7d7bd5..1a67ec0 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -33,19 +33,33 @@ S3method(aperm,integer64) S3method(as.bitstring,integer64) S3method(as.character,integer64) S3method(as.data.frame,integer64) +S3method(as.difftime,default) +S3method(as.difftime,integer64) S3method(as.double,integer64) S3method(as.integer,integer64) S3method(as.integer64,"NULL") +S3method(as.integer64,Date) +S3method(as.integer64,POSIXct) +S3method(as.integer64,POSIXlt) S3method(as.integer64,bitstring) S3method(as.integer64,character) +S3method(as.integer64,complex) +S3method(as.integer64,difftime) S3method(as.integer64,double) S3method(as.integer64,factor) S3method(as.integer64,integer) S3method(as.integer64,integer64) S3method(as.integer64,logical) +S3method(as.integer64,raw) S3method(as.list,integer64) S3method(as.logical,integer64) S3method(base::anyNA,integer64) +S3method(base::as.Date,integer64) +S3method(base::as.POSIXct,integer64) +S3method(base::as.POSIXlt,integer64) +S3method(base::as.complex,integer64) +S3method(base::as.numeric,integer64) +S3method(base::as.raw,integer64) S3method(c,integer64) S3method(cbind,integer64) S3method(ceiling,integer64) @@ -185,6 +199,7 @@ export(as.bitstring) export(as.bitstring.integer64) export(as.character.integer64) export(as.data.frame.integer64) +export(as.difftime) export(as.double.integer64) export(as.integer.integer64) export(as.integer64) @@ -399,6 +414,7 @@ importFrom(graphics,barplot) importFrom(graphics,par) importFrom(graphics,title) importFrom(methods,as) +importFrom(methods,callGeneric) importFrom(methods,is) importFrom(stats,cor) importFrom(stats,median) diff --git a/NEWS.md b/NEWS.md index 056cc06..a8fcb99 100644 --- a/NEWS.md +++ b/NEWS.md @@ -42,6 +42,8 @@ ## NEW FEATURES 1. `anyNA` gets an `integer64` method. Thanks @hcirellu. +1. `as.Date`, `as.POSIXct`, `as.POSXlt`, `as.raw`, `as.difftime` get an `integer64` method. +1. `as.integer64` gets `Date`, `POSIXct`, `POSXlt`, `raw`, `difftime` methods. ## BUG FIXES diff --git a/R/bit64-package.R b/R/bit64-package.R index d32b917..2fe42e4 100644 --- a/R/bit64-package.R +++ b/R/bit64-package.R @@ -695,7 +695,7 @@ #' ramsort ramsortorder repeat.time setattr shellorder shellsort #' shellsortorder still.identical xor #' @importFrom graphics barplot par title -#' @importFrom methods as is +#' @importFrom methods as is callGeneric #' @importFrom stats cor median quantile #' @importFrom utils head packageDescription strOptions tail #' @export : :.default :.integer64 diff --git a/R/integer64.R b/R/integer64.R index 46c70a1..f68cec0 100644 --- a/R/integer64.R +++ b/R/integer64.R @@ -42,6 +42,11 @@ NULL #' @param x an integer64 vector #' @param keep.names FALSE, set to TRUE to keep a names vector #' @param ... further arguments to the [NextMethod()] +#' @param origin further arguments to the [NextMethod()] +#' @param tz further arguments to the [NextMethod()] +#' @param tim further arguments to the [NextMethod()] +#' @param format further arguments to the [NextMethod()] +#' @param units further arguments to the [NextMethod()] #' #' @return `as.bitstring` returns a string of class 'bitstring'. #' @@ -63,7 +68,8 @@ NULL #' @param x an atomic vector #' @param keep.names FALSE, set to TRUE to keep a names vector #' @param ... further arguments to the [NextMethod()] -#' +#' @param units further arguments to the [NextMethod()] +#' #' @details #' `as.integer64.character` is realized using C function `strtoll` which #' does not support scientific notation. Instead of '1e6' use '1000000'. @@ -556,7 +562,7 @@ identical.integer64 <- function(x, y, #' @rdname as.integer64.character #' @export -as.integer64 <- function(x, ...) UseMethod("as.integer64") +as.integer64 <- function(x, keep.names=FALSE, ...) UseMethod("as.integer64") #' @rdname as.character.integer64 #' @export @@ -651,120 +657,247 @@ binattr <- function(e1, e2) { #' @return `integer64` returns a vector of 'integer64', i.e., #' a vector of [double()] decorated with class 'integer64'. #' @export -integer64 <- function(length=0L) { - ret <- double(length) - oldClass(ret) <- "integer64" +integer64 = function(length=0L) { + ret = double(length) + oldClass(ret) = "integer64" ret } #' @rdname bit64-package #' @param x an integer64 vector #' @export -is.integer64 <- function(x) inherits(x, "integer64") +is.integer64 = function(x) inherits(x, "integer64") #' @rdname as.integer64.character #' @export -as.integer64.NULL <- function(x, ...) { - ret <- double() - oldClass(ret) <- "integer64" - ret -} +as.integer64.NULL = function(x, keep.names=FALSE, ...) integer64() #' @rdname as.integer64.character #' @export -as.integer64.integer64 <- function(x, ...) x +as.integer64.integer64 = function(x, keep.names=FALSE, ...) x #' @rdname as.integer64.character #' @export -as.integer64.double <- function(x, keep.names=FALSE, ...) { - ret <- .Call(C_as_integer64_double, x, double(length(x))) - if (keep.names) - names(ret) <- names(x) - oldClass(ret) <- "integer64" +as.integer64.double = function(x, keep.names=FALSE, ...) { + ret = .Call(C_as_integer64_double, x, double(length(x))) + if (isTRUE(keep.names)) + names(ret) = names(x) + oldClass(ret) = "integer64" + ret +} + +#' @rdname as.integer64.character +#' @exportS3Method as.integer64 complex +as.integer64.complex = function(x, keep.names=FALSE, ...) { + xd = withCallingHandlers( + as.double(x), + warning = function(w) { + warning(conditionMessage(w), call.=FALSE) + invokeRestart("muffleWarning") + } + ) + ret = .Call(C_as_integer64_double, xd, double(length(xd))) + if (isTRUE(keep.names)) + names(ret) = names(x) + oldClass(ret) = "integer64" ret } #' @rdname as.integer64.character #' @export -as.integer64.integer <- function(x, ...) { - ret <- .Call(C_as_integer64_integer, x, double(length(x))) - oldClass(ret) <- "integer64" +as.integer64.integer = function(x, keep.names=FALSE, ...) { + ret = .Call(C_as_integer64_integer, x, double(length(x))) + if (isTRUE(keep.names)) + names(ret) = names(x) + oldClass(ret) = "integer64" + ret +} + +#' @rdname as.integer64.character +#' @exportS3Method as.integer64 raw +as.integer64.raw = function(x, keep.names=FALSE, ...) { + ret = .Call(C_as_integer64_integer, as.integer(x), double(length(x))) + if (isTRUE(keep.names)) + names(ret) = names(x) + oldClass(ret) = "integer64" ret } #' @rdname as.integer64.character #' @export -as.integer64.logical <- as.integer64.integer +as.integer64.logical = as.integer64.integer #' @rdname as.integer64.character #' @export -as.integer64.character <- function(x, ...) { - n <- length(x) - ret <- .Call(C_as_integer64_character, x, rep(NA_real_, n)) - oldClass(ret) <- "integer64" +as.integer64.character = function(x, keep.names=FALSE, ...) { + ret = .Call(C_as_integer64_character, x, rep(NA_real_, length(x))) + if (isTRUE(keep.names)) + names(ret) = names(x) + oldClass(ret) = "integer64" ret } #' @rdname as.integer64.character #' @export -as.integer64.factor <- function(x, ...) as.integer64(unclass(x), ...) +as.integer64.factor = function(x, keep.names=FALSE, ...) as.integer64(unclass(x), keep.names=keep.names, ...) -#' @rdname as.character.integer64 -#' @export -as.double.integer64 <- function(x, keep.names=FALSE, ...) { - ret <- .Call(C_as_double_integer64, x, double(length(x))) - if (keep.names) - names(ret) <- names(x) +#' @rdname as.integer64.character +#' @exportS3Method as.integer64 Date +as.integer64.Date = function(x, keep.names=FALSE, ...) { + n = names(x) + x = as.double(x) + names(x) = n + callGeneric() +} + +#' @rdname as.integer64.character +#' @exportS3Method as.integer64 POSIXct +as.integer64.POSIXct = function(x, keep.names=FALSE, ...) { + n = names(x) + x = as.double(x) + names(x) = n + callGeneric() +} + +#' @rdname as.integer64.character +#' @exportS3Method as.integer64 POSIXlt +as.integer64.POSIXlt = function(x, keep.names=FALSE, ...) { + callGeneric(x=as.POSIXct(x), keep.names=keep.names, ...) +} + +#' @rdname as.integer64.character +#' @exportS3Method as.integer64 difftime +as.integer64.difftime = function(x, keep.names=FALSE, units="auto", ...) { + n = names(x) + x = as.double(x, units=units, ...) + names(x) = n + callGeneric() +} + +.as_double_integer64 = function(x, keep.names=FALSE, keep.attributes=FALSE, ...) { + ret = .Call(C_as_double_integer64, x, double(length(x))) + if (isTRUE(keep.attributes)) { + # like dimensions for matrix operations + a = attributes(x) + a$class = NULL + attributes(ret) = a + keep.names = FALSE # names are already included + } + if (isTRUE(keep.names)) + names(ret) = names(x) ret } #' @rdname as.character.integer64 #' @export -as.integer.integer64 <- function(x, ...) { +as.double.integer64 = function(x, keep.names=FALSE, ...) + .as_double_integer64(x, keep.names, keep.attributes=FALSE, ...) + +#' @rdname as.character.integer64 +#' @exportS3Method base::as.numeric integer64 +as.numeric.integer64 = as.double.integer64 + +#' @rdname as.character.integer64 +#' @exportS3Method base::as.complex integer64 +as.complex.integer64 = function(x, ...) as.complex(as.double(x), ...) + +#' @rdname as.character.integer64 +#' @export +as.integer.integer64 = function(x, ...) .Call(C_as_integer_integer64, x, integer(length(x))) + +#' @rdname as.character.integer64 +#' @exportS3Method base::as.raw integer64 +as.raw.integer64 = function(x, ...) { + withCallingHandlers( + as.raw(.Call(C_as_integer_integer64, x, integer(length(x)))), + warning = function(w) { + warning(conditionMessage(w), call.=FALSE) + invokeRestart("muffleWarning") + } + ) } #' @rdname as.character.integer64 #' @export -as.logical.integer64 <- function(x, ...) { +as.logical.integer64 = function(x, ...) .Call(C_as_logical_integer64, x, logical(length(x))) -} #' @rdname as.character.integer64 #' @export -as.character.integer64 <- function(x, ...) { - n <- length(x) - .Call(C_as_character_integer64, x, rep(NA_character_, n)) -} +as.character.integer64 = function(x, ...) + .Call(C_as_character_integer64, x, rep(NA_character_, length(x))) #' @rdname as.character.integer64 #' @export -as.bitstring.integer64 <- function(x, ...) { - n <- length(x) - ret <- .Call(C_as_bitstring_integer64, x, rep(NA_character_, n)) - oldClass(ret) <- 'bitstring' +as.bitstring.integer64 = function(x, ...) { + ret = .Call(C_as_bitstring_integer64, x, rep(NA_character_, length(x))) + oldClass(ret) = 'bitstring' ret } +#' @rdname as.character.integer64 +#' @exportS3Method base::as.Date integer64 +as.Date.integer64 = function(x, origin, ...) { + x = as.double(x) + callGeneric() +} + +#' @rdname as.character.integer64 +#' @exportS3Method base::as.POSIXct integer64 +as.POSIXct.integer64 = function(x, tz="", origin, ...) { + x = as.double(x) + callGeneric() +} + +#' @rdname as.character.integer64 +#' @exportS3Method base::as.POSIXlt integer64 +as.POSIXlt.integer64 = function(x, tz="", origin, ...) { + x = as.double(x, ...) + callGeneric() +} + +#' @rdname as.character.integer64 +#' @export +as.difftime = function(tim, format="%X", units="auto", tz="UTC", ...) UseMethod("as.difftime") +#' @exportS3Method as.difftime default +as.difftime.default = function(tim, format="%X", units="auto", tz ="UTC", ...) { + base::as.difftime(tim, format=format, units=units, tz=tz) +} + +#' @rdname as.character.integer64 +#' @exportS3Method as.difftime integer64 +as.difftime.integer64 = function(tim, format="%X", units="auto", tz="UTC", ...) { + tim = as.double(tim) + NextMethod() +} + #' @rdname as.character.integer64 #' @export -print.bitstring <- function(x, ...) { - oldClass(x) <- minusclass(class(x), 'bitstring') +print.bitstring = function(x, ...) { + oldClass(x) = minusclass(class(x), 'bitstring') NextMethod(x) } #' @rdname as.integer64.character #' @export -as.integer64.bitstring <- function(x, ...) { - ret <- .Call(C_as_integer64_bitstring, x, double(length(x))) - oldClass(ret) <- "integer64" +as.integer64.bitstring <- function(x, keep.names=FALSE, ...) { + ret = .Call(C_as_integer64_bitstring, x, double(length(x))) + oldClass(ret) = "integer64" + if (isTRUE(keep.names)) + names(ret) = names(x) ret } - # read.table expects S4 as() -methods::setAs("character", "integer64", function(from) as.integer64.character(from)) -methods::setAs("integer64", "character", function(from) as.character.integer64(from)) +methods::setAs("ANY", "integer64", function(from) as.integer64(from)) +methods::setAs("integer64", "factor", function(from) as.factor(from)) +methods::setAs("integer64", "ordered", function(from) as.ordered(from)) +methods::setAs("integer64", "difftime", function(from) as.difftime(from, units="secs")) +methods::setAs("integer64", "POSIXct", function(from) as.POSIXct(from)) +methods::setAs("integer64", "POSIXlt", function(from) as.POSIXlt(from)) +methods::setAs("integer64", "Date", function(from) as.Date(from)) +methods::setAs("integer64", "raw", function(from) as.raw(from)) # this is a trick to generate NA_integer64_ for namespace export before # as.integer64() is available because dll is not loaded @@ -824,19 +957,35 @@ print.integer64 <- function(x, quote=FALSE, ...) { #' @param object an integer64 vector #' @param vec.len,give.head,give.length see [utils::str()] #' @export -str.integer64 <- function(object, - vec.len = strO$vec.len, - give.head = TRUE, - give.length = give.head, - ...) { - strO <- strOptions() - vec.len <- 2L*vec.len - n <- length(object) - if (n > vec.len) - object <- object[seq_len(vec.len)] +str.integer64 = function(object, vec.len=strO$vec.len, give.head=TRUE, give.length=give.head, ...) { + strO = strOptions() + vec.len = 2L*vec.len + n = length(object) + displayObject = object[seq_len(min(vec.len, length(object)))] + cat( - if (give.head) paste0("integer64 ", if (give.length && n>1L) paste0("[1:", n, "] ")), - paste(as.character(object), collapse=" "), + if (isTRUE(give.head)) { + if (length(object) == 0L && is.null(dim(object))) { + "integer64(0)" + } else { + paste0( + "integer64 ", + if (length(object) > 1L && is.null(dim(object))) { + if (isTRUE(give.length)) paste0("[1:", n, "] ") else " " + } else if (!is.null(dim(object))) { + dimO = dim(object) + if (prod(dimO) != n) + stop(gettextf("dims [product %d] do not match the length of object [%d]", prod(dimO), n, domain="R")) + if (length(dimO) == 1L) { + paste0("[", n, "(1d)] ") + } else { + paste0("[", paste(vapply(dimO, function(el) {if (el < 2L) as.character(el) else paste0("1:", el)}, ""), collapse = ", "), "] ") + } + } + ) + } + }, + paste(as.character(displayObject), collapse=" "), if (n > vec.len) " ...", " \n", sep="" diff --git a/man/as.character.integer64.Rd b/man/as.character.integer64.Rd index e4aaafc..33109e3 100644 --- a/man/as.character.integer64.Rd +++ b/man/as.character.integer64.Rd @@ -4,9 +4,16 @@ \alias{as.character.integer64} \alias{as.bitstring} \alias{as.double.integer64} +\alias{as.complex.integer64} \alias{as.integer.integer64} +\alias{as.raw.integer64} \alias{as.logical.integer64} \alias{as.bitstring.integer64} +\alias{as.Date.integer64} +\alias{as.POSIXct.integer64} +\alias{as.POSIXlt.integer64} +\alias{as.difftime} +\alias{as.difftime.integer64} \alias{print.bitstring} \alias{as.list.integer64} \title{Coerce from integer64} @@ -15,14 +22,34 @@ as.bitstring(x, ...) \method{as.double}{integer64}(x, keep.names = FALSE, ...) +\method{as.complex}{integer64}(x, ...) + \method{as.integer}{integer64}(x, ...) +\method{as.raw}{integer64}(x, ...) + \method{as.logical}{integer64}(x, ...) \method{as.character}{integer64}(x, ...) \method{as.bitstring}{integer64}(x, ...) +\method{as.Date}{integer64}(x, origin, ...) + +\method{as.POSIXct}{integer64}(x, tz = "", origin, ...) + +\method{as.POSIXlt}{integer64}(x, tz = "", origin, ...) + +as.difftime(tim, format = "\%X", units = "auto", tz = "UTC", ...) + +\method{as.difftime}{integer64}( + tim, + format = "\%X", + units = "auto", + tz = "UTC", + ... +) + \method{print}{bitstring}(x, ...) \method{as.list}{integer64}(x, ...) @@ -33,6 +60,16 @@ as.bitstring(x, ...) \item{...}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} \item{keep.names}{FALSE, set to TRUE to keep a names vector} + +\item{origin}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} + +\item{tz}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} + +\item{tim}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} + +\item{format}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} + +\item{units}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} } \value{ \code{as.bitstring} returns a string of class 'bitstring'. diff --git a/man/as.integer64.character.Rd b/man/as.integer64.character.Rd index 146f0f1..da9aeeb 100644 --- a/man/as.integer64.character.Rd +++ b/man/as.integer64.character.Rd @@ -7,9 +7,15 @@ \alias{as.integer64.NULL} \alias{as.integer64.integer64} \alias{as.integer64.double} +\alias{as.integer64.complex} \alias{as.integer64.integer} +\alias{as.integer64.raw} \alias{as.integer64.logical} \alias{as.integer64.factor} +\alias{as.integer64.Date} +\alias{as.integer64.POSIXct} +\alias{as.integer64.POSIXlt} +\alias{as.integer64.difftime} \alias{as.integer64.bitstring} \alias{NA_integer64_} \title{Coerce to integer64} @@ -17,32 +23,46 @@ An object of class \code{integer64} of length 1. } \usage{ -as.integer64(x, ...) +as.integer64(x, keep.names = FALSE, ...) -\method{as.integer64}{`NULL`}(x, ...) +\method{as.integer64}{`NULL`}(x, keep.names = FALSE, ...) -\method{as.integer64}{integer64}(x, ...) +\method{as.integer64}{integer64}(x, keep.names = FALSE, ...) \method{as.integer64}{double}(x, keep.names = FALSE, ...) -\method{as.integer64}{integer}(x, ...) +\method{as.integer64}{complex}(x, keep.names = FALSE, ...) -\method{as.integer64}{logical}(x, ...) +\method{as.integer64}{integer}(x, keep.names = FALSE, ...) -\method{as.integer64}{character}(x, ...) +\method{as.integer64}{raw}(x, keep.names = FALSE, ...) -\method{as.integer64}{factor}(x, ...) +\method{as.integer64}{logical}(x, keep.names = FALSE, ...) -\method{as.integer64}{bitstring}(x, ...) +\method{as.integer64}{character}(x, keep.names = FALSE, ...) + +\method{as.integer64}{factor}(x, keep.names = FALSE, ...) + +\method{as.integer64}{Date}(x, keep.names = FALSE, ...) + +\method{as.integer64}{POSIXct}(x, keep.names = FALSE, ...) + +\method{as.integer64}{POSIXlt}(x, keep.names = FALSE, ...) + +\method{as.integer64}{difftime}(x, keep.names = FALSE, units = "auto", ...) + +\method{as.integer64}{bitstring}(x, keep.names = FALSE, ...) NA_integer64_ } \arguments{ \item{x}{an atomic vector} -\item{...}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} - \item{keep.names}{FALSE, set to TRUE to keep a names vector} + +\item{units}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} + +\item{...}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} } \value{ The other methods return atomic vectors of the expected types diff --git a/tests/testthat/test-bit64-package.R b/tests/testthat/test-bit64-package.R index 2db72f3..63b65e7 100644 --- a/tests/testthat/test-bit64-package.R +++ b/tests/testthat/test-bit64-package.R @@ -178,6 +178,12 @@ test_that("Coercion", { as.double(as.integer64(c(NA, seq(0.0, 9.0, 0.25)))), as.double(as.integer(c(NA, seq(0.0, 9.0, 0.25)))) ) + if (getRversion() >= "4.0.0") { + expect_identical( + as.complex(as.integer64(c(NA, seq(0.0, 9.0, 0.25)))), + as.complex(as.integer(c(NA, seq(0.0, 9.0, 0.25)))) + ) + } expect_identical( as.character(as.integer64(c(NA, seq(0.0, 9.0, 0.25)))), as.character(as.integer(c(NA, seq(0.0, 9.0, 0.25)))) @@ -186,6 +192,16 @@ test_that("Coercion", { as.integer(as.integer64(c(NA, seq(0.0, 9.0, 0.25)))), as.integer(c(NA, seq(0.0, 9.0, 0.25))) ) + expect_warning( + expect_warning( + expect_identical( + as.raw(as.integer64(c(NA, seq(0.0, 9.0, 0.25)))), + as.raw(c(NA, seq(0.0, 9.0, 0.25))) + ), fixed=TRUE, + "out-of-range values treated as 0 in coercion to raw" + ), fixed=TRUE, + "out-of-range values treated as 0 in coercion to raw" + ) expect_identical( as.logical(as.integer64(c(NA, seq(0.0, 9.0, 0.25)))), as.logical(as.integer(c(NA, seq(0.0, 9.0, 0.25)))) @@ -202,6 +218,14 @@ test_that("Coercion", { as.integer64(as.double(as.integer64(-9:9))), as.integer64(-9:9) ) + expect_identical( + as.integer64(as.complex(-9:9)), + as.integer64(-9:9) + ) + expect_identical( + as.integer64(as.raw(0:9)), + as.integer64(0:9) + ) expect_identical( as.integer64(as.character(as.integer64(-9:9))), as.integer64(-9:9) @@ -210,6 +234,80 @@ test_that("Coercion", { as.integer64(as.character(lim.integer64())), lim.integer64() ) + expect_identical( + as(as.raw(1L), "integer64"), + as.integer64(1L) + ) + expect_identical( + as(TRUE, "integer64"), + as.integer64(1L) + ) + expect_identical( + as(111L, "integer64"), + as.integer64(111L) + ) + expect_identical( + as(111, "integer64"), + as.integer64(111L) + ) + expect_identical( + as(111+0i, "integer64"), + as.integer64(111L) + ) + expect_identical( + as("111", "integer64"), + as.integer64(111L) + ) + expect_identical( + as(as.factor(111), "integer64"), + as.integer64(1L) + ) + expect_identical( + as(as.ordered(111), "integer64"), + as.integer64(1L) + ) + if (getRversion() >= "4.0.0") { + expect_identical( + as(as.integer64(1L), "raw"), + as.raw(1L) + ) + } + expect_identical( + as(as.integer64(1L), "logical"), + TRUE + ) + expect_identical( + as(as.integer64(111L), "integer"), + 111L + ) + expect_identical( + as(as.integer64(111L), "integer"), + 111L + ) + expect_identical( + as(as.integer64(111L), "numeric"), + 111 + ) + expect_identical( + as(as.integer64(111L), "double"), + 111 + ) + expect_identical( + as(as.integer64(111L), "complex"), + 111+0i + ) + expect_identical( + as(as.integer64(111L), "character"), + "111" + ) + expect_identical( + as(as.integer64(111L), "factor"), + as.factor("111") + ) + expect_identical( + as(as.integer64(111L), "ordered"), + as.ordered("111") + ) }) test_that("Logical operators", { diff --git a/tests/testthat/test-integer64.R b/tests/testthat/test-integer64.R index c66d8d3..69ebe7c 100644 --- a/tests/testthat/test-integer64.R +++ b/tests/testthat/test-integer64.R @@ -1,23 +1,92 @@ test_that("integer64 coercion to/from other types work", { # from integer64 + i32 = 1:10 + i64 = as.integer64(i32) expect_identical(as.logical(as.integer64(0:1)), c(FALSE, TRUE)) - expect_identical(as.integer(as.integer64(1:10)), 1:10) - expect_identical(as.character(as.integer64(1:10)), as.character(1:10)) - expect_identical(as.double(as.integer64(1:10)), as.double(1:10)) - expect_identical(as.numeric(as.integer64(1:10)), as.numeric(1:10)) - + expect_identical(as.integer(i64), i32) + expect_identical(as.character(i64), as.character(i32)) + expect_identical(as.double(i64), as.double(i32)) + expect_identical(as.numeric(i64), as.numeric(i32)) + expect_identical(as.complex(i64), as.complex(i32)) + expect_identical(as.raw(i64), as.raw(i32)) + expect_identical(as.factor(i64), as.factor(i32)) + expect_identical(as.ordered(i64), as.ordered(i32)) + if (getRversion() >= "4.0.0") { + expect_identical(as.Date(i64), as.Date(as.numeric(i32))) + expect_identical(as.Date(i64, origin=10), as.Date(as.numeric(i32), origin=10)) + expect_identical(as.POSIXct(i64), as.POSIXct(as.numeric(i32))) + expect_identical(as.POSIXct(i64, origin=10), as.POSIXct(as.numeric(i32), origin=10)) + expect_identical(as.POSIXct(i64, tz="UTC", origin=10), as.POSIXct(as.numeric(i32), tz="UTC", origin=10)) + expect_identical(as.POSIXct(i64, tz="CET", origin=10), as.POSIXct(as.numeric(i32), tz="CET", origin=10)) + expect_identical(as.POSIXlt(i64), as.POSIXlt(i32)) + expect_identical(as.POSIXlt(i64, origin=10), as.POSIXlt(i32, origin=10)) + expect_identical(as.POSIXlt(i64, tz="UTC", origin=10), as.POSIXlt(i32, tz="UTC", origin=10)) + expect_identical(as.POSIXlt(i64, tz="CET", origin=10), as.POSIXlt(i32, tz="CET", origin=10)) + expect_error(as.difftime(i32), "need explicit units for numeric conversion", fixed=TRUE) + expect_error(as.difftime(i64), "need explicit units for numeric conversion", fixed=TRUE) + expect_identical(as.difftime(i64, units="secs"), as.difftime(i32, units="secs")) + } + # to integer64 expect_identical(as.integer64(TRUE), as.integer64(1L)) expect_identical(as.integer64(as.character(1:10)), as.integer64(1:10)) expect_identical(as.integer64(as.double(1:10)), as.integer64(1:10)) + expect_identical(as.integer64(as.complex(1:10)), as.integer64(1:10)) + expect_identical(as.integer64(as.raw(1:10)), as.integer64(1:10)) + expect_identical(as.integer64(as.factor(11:20)), as.integer64(1:10)) + expect_identical(as.integer64(as.ordered(11:20)), as.integer64(1:10)) expect_identical(as.integer64(NULL), as.integer64()) x = as.integer64(1:10) expect_identical(as.integer64(x), x) - + p = c(Sys.time(), Sys.time()) + expect_identical( + as.integer64(difftime(p+1000, p)), + as.integer64(as.integer(difftime(p+1000, p))) + ) + # as.integer.difftime does not work with `units` + expect_identical( + as.integer64(difftime(p+1000, p), units="secs"), + as.integer64(as.numeric(difftime(p+1000, p), units="secs")) + ) + expect_identical( + as.integer64(difftime(p+1000, p), units="mins"), + as.integer64(as.numeric(difftime(p+1000, p), units="mins")) + ) + expect_identical(as.integer64(p), as.integer64(as.integer(p))) + # as.integer.POSIXlt does not work properly + expect_identical(as.integer64(as.POSIXlt(p)), as.integer64(as.numeric(as.POSIXlt(p)))) + expect_identical(as.integer64(as.Date(p)), as.integer64(as.integer(as.Date(p)))) + # S4 version expect_identical(methods::as(as.character(1:10), "integer64"), as.integer64(1:10)) + expect_identical(methods::as(as.factor(11:20), "integer64"), as.integer64(1:10)) + expect_identical(methods::as(as.ordered(11:20), "integer64"), as.integer64(1:10)) + expect_warning(expect_identical(methods::as(as.complex(1:10) + 0+1i, "integer64"), as.integer64(1:10)), "imaginary parts discarded in coercion") + expect_identical(methods::as(as.numeric(1:10), "integer64"), as.integer64(1:10)) + expect_identical(methods::as(as.integer(1:10), "integer64"), as.integer64(1:10)) + expect_identical(methods::as(as.raw(1:10), "integer64"), as.integer64(1:10)) + expect_identical(methods::as(as.logical(0:2), "integer64"), as.integer64(c(0L, 1L, 1L))) + expect_identical(methods::as(difftime(p+1000, p), "integer64"), as.integer64(difftime(p+1000, p))) + expect_identical(methods::as(p, "integer64"), as.integer64(p)) + expect_identical(methods::as(as.POSIXlt(p), "integer64"), as.integer64(as.POSIXlt(p))) + expect_identical(methods::as(as.Date(p), "integer64"), as.integer64(as.Date(p))) expect_identical(methods::as(as.integer64(1:10), "character"), as.character(1:10)) - + expect_identical(methods::as(as.integer64(1:10), "factor"), as.factor(1:10)) + expect_identical(methods::as(as.integer64(1:10), "ordered"), as.ordered(1:10)) + expect_identical(methods::as(as.integer64(1:10), "complex"), as.complex(1:10)) + expect_identical(methods::as(as.integer64(1:10), "numeric"), as.numeric(1:10)) + expect_identical(methods::as(as.integer64(1:10), "integer"), as.integer(1:10)) + if (getRversion() >= "4.0.0") { + expect_identical(methods::as(as.integer64(1:10), "raw"), as.raw(1:10)) + } + expect_identical(methods::as(as.integer64(1:10), "logical"), as.logical(1:10)) + if (getRversion() >= "4.0.0") { + expect_identical(methods::as(as.integer64(1:10), "difftime"), as.difftime(1:10, units="secs")) + expect_identical(methods::as(as.integer64(1:10), "POSIXct"), as.POSIXct(as.numeric(1:10))) + expect_identical(methods::as(as.integer64(1:10), "POSIXlt"), as.POSIXlt(1:10)) + expect_identical(methods::as(as.integer64(1:10), "Date"), as.Date(as.numeric(1:10))) + } + # now for NA expect_identical(as.logical(NA_integer64_), NA) expect_identical(as.integer(NA_integer64_), NA_integer_) From 79f2a87e923709f2fe543aac8204b3219361bbe1 Mon Sep 17 00:00:00 2001 From: hcirellu Date: Thu, 13 Nov 2025 21:51:41 +0100 Subject: [PATCH 3/6] styling --- R/integer64.R | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/R/integer64.R b/R/integer64.R index f68cec0..cb4ff7c 100644 --- a/R/integer64.R +++ b/R/integer64.R @@ -562,11 +562,11 @@ identical.integer64 <- function(x, y, #' @rdname as.integer64.character #' @export -as.integer64 <- function(x, keep.names=FALSE, ...) UseMethod("as.integer64") +as.integer64 = function(x, keep.names=FALSE, ...) UseMethod("as.integer64") #' @rdname as.character.integer64 #' @export -as.bitstring <- function(x, ...) UseMethod("as.bitstring") +as.bitstring = function(x, ...) UseMethod("as.bitstring") #' @rdname plusclass #' @export @@ -739,7 +739,8 @@ as.integer64.character = function(x, keep.names=FALSE, ...) { #' @rdname as.integer64.character #' @export -as.integer64.factor = function(x, keep.names=FALSE, ...) as.integer64(unclass(x), keep.names=keep.names, ...) +as.integer64.factor = function(x, keep.names=FALSE, ...) + as.integer64(unclass(x), keep.names=keep.names, ...) #' @rdname as.integer64.character #' @exportS3Method as.integer64 Date @@ -762,7 +763,8 @@ as.integer64.POSIXct = function(x, keep.names=FALSE, ...) { #' @rdname as.integer64.character #' @exportS3Method as.integer64 POSIXlt as.integer64.POSIXlt = function(x, keep.names=FALSE, ...) { - callGeneric(x=as.POSIXct(x), keep.names=keep.names, ...) + x = as.POSIXct(x) + callGeneric() } #' @rdname as.integer64.character From d4d833c20eb62f517e437533fea0d1f5b3a8a1e9 Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Thu, 13 Nov 2025 13:33:25 -0800 Subject: [PATCH 4/6] comment subtle reason for catching warnings --- R/integer64.R | 1 + 1 file changed, 1 insertion(+) diff --git a/R/integer64.R b/R/integer64.R index cb4ff7c..fcf02f8 100644 --- a/R/integer64.R +++ b/R/integer64.R @@ -691,6 +691,7 @@ as.integer64.double = function(x, keep.names=FALSE, ...) { as.integer64.complex = function(x, keep.names=FALSE, ...) { xd = withCallingHandlers( as.double(x), + # call.=FALSE to avoid confusion about where the warning arises warning = function(w) { warning(conditionMessage(w), call.=FALSE) invokeRestart("muffleWarning") From 55d2c43adaac5e0af5cb91f3e2f7b404138ad2ea Mon Sep 17 00:00:00 2001 From: hcirellu Date: Thu, 13 Nov 2025 22:41:26 +0100 Subject: [PATCH 5/6] changed man and moved tests to own section for R>=4.0.0 --- R/integer64.R | 10 ++---- man/as.character.integer64.Rd | 27 ++++------------ man/as.integer64.character.Rd | 4 +-- tests/testthat/test-integer64.R | 56 ++++++++++++++++++--------------- 4 files changed, 39 insertions(+), 58 deletions(-) diff --git a/R/integer64.R b/R/integer64.R index fcf02f8..c71dfba 100644 --- a/R/integer64.R +++ b/R/integer64.R @@ -41,12 +41,7 @@ NULL #' #' @param x an integer64 vector #' @param keep.names FALSE, set to TRUE to keep a names vector -#' @param ... further arguments to the [NextMethod()] -#' @param origin further arguments to the [NextMethod()] -#' @param tz further arguments to the [NextMethod()] -#' @param tim further arguments to the [NextMethod()] -#' @param format further arguments to the [NextMethod()] -#' @param units further arguments to the [NextMethod()] +#' @param ...,origin,tz,tim,format,units further arguments to the [NextMethod()] #' #' @return `as.bitstring` returns a string of class 'bitstring'. #' @@ -67,8 +62,7 @@ NULL #' #' @param x an atomic vector #' @param keep.names FALSE, set to TRUE to keep a names vector -#' @param ... further arguments to the [NextMethod()] -#' @param units further arguments to the [NextMethod()] +#' @param ...,units further arguments to the [NextMethod()] #' #' @details #' `as.integer64.character` is realized using C function `strtoll` which diff --git a/man/as.character.integer64.Rd b/man/as.character.integer64.Rd index 33109e3..e3f5c46 100644 --- a/man/as.character.integer64.Rd +++ b/man/as.character.integer64.Rd @@ -4,6 +4,7 @@ \alias{as.character.integer64} \alias{as.bitstring} \alias{as.double.integer64} +\alias{as.numeric.integer64} \alias{as.complex.integer64} \alias{as.integer.integer64} \alias{as.raw.integer64} @@ -22,6 +23,8 @@ as.bitstring(x, ...) \method{as.double}{integer64}(x, keep.names = FALSE, ...) +\method{as.numeric}{integer64}(x, keep.names = FALSE, ...) + \method{as.complex}{integer64}(x, ...) \method{as.integer}{integer64}(x, ...) @@ -42,13 +45,7 @@ as.bitstring(x, ...) as.difftime(tim, format = "\%X", units = "auto", tz = "UTC", ...) -\method{as.difftime}{integer64}( - tim, - format = "\%X", - units = "auto", - tz = "UTC", - ... -) +\method{as.difftime}{integer64}(tim, format = "\%X", units = "auto", tz = "UTC", ...) \method{print}{bitstring}(x, ...) @@ -57,19 +54,9 @@ as.difftime(tim, format = "\%X", units = "auto", tz = "UTC", ...) \arguments{ \item{x}{an integer64 vector} -\item{...}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} +\item{..., origin, tz, tim, format, units}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} \item{keep.names}{FALSE, set to TRUE to keep a names vector} - -\item{origin}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} - -\item{tz}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} - -\item{tim}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} - -\item{format}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} - -\item{units}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} } \value{ \code{as.bitstring} returns a string of class 'bitstring'. @@ -85,9 +72,7 @@ The methods \code{\link[=format]{format()}}, \code{\link[=as.character]{as.chara \examples{ as.character(lim.integer64()) as.bitstring(lim.integer64()) - as.bitstring(as.integer64(c( - -2,-1,NA,0:2 - ))) + as.bitstring(as.integer64(c(-2, -1, NA, 0:2))) } \seealso{ \code{\link[=as.integer64.character]{as.integer64.character()}} \code{\link[=integer64]{integer64()}} diff --git a/man/as.integer64.character.Rd b/man/as.integer64.character.Rd index da9aeeb..50ef16e 100644 --- a/man/as.integer64.character.Rd +++ b/man/as.integer64.character.Rd @@ -60,9 +60,7 @@ NA_integer64_ \item{keep.names}{FALSE, set to TRUE to keep a names vector} -\item{units}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} - -\item{...}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} +\item{..., units}{further arguments to the \code{\link[=NextMethod]{NextMethod()}}} } \value{ The other methods return atomic vectors of the expected types diff --git a/tests/testthat/test-integer64.R b/tests/testthat/test-integer64.R index 69ebe7c..b04a308 100644 --- a/tests/testthat/test-integer64.R +++ b/tests/testthat/test-integer64.R @@ -11,22 +11,7 @@ test_that("integer64 coercion to/from other types work", { expect_identical(as.raw(i64), as.raw(i32)) expect_identical(as.factor(i64), as.factor(i32)) expect_identical(as.ordered(i64), as.ordered(i32)) - if (getRversion() >= "4.0.0") { - expect_identical(as.Date(i64), as.Date(as.numeric(i32))) - expect_identical(as.Date(i64, origin=10), as.Date(as.numeric(i32), origin=10)) - expect_identical(as.POSIXct(i64), as.POSIXct(as.numeric(i32))) - expect_identical(as.POSIXct(i64, origin=10), as.POSIXct(as.numeric(i32), origin=10)) - expect_identical(as.POSIXct(i64, tz="UTC", origin=10), as.POSIXct(as.numeric(i32), tz="UTC", origin=10)) - expect_identical(as.POSIXct(i64, tz="CET", origin=10), as.POSIXct(as.numeric(i32), tz="CET", origin=10)) - expect_identical(as.POSIXlt(i64), as.POSIXlt(i32)) - expect_identical(as.POSIXlt(i64, origin=10), as.POSIXlt(i32, origin=10)) - expect_identical(as.POSIXlt(i64, tz="UTC", origin=10), as.POSIXlt(i32, tz="UTC", origin=10)) - expect_identical(as.POSIXlt(i64, tz="CET", origin=10), as.POSIXlt(i32, tz="CET", origin=10)) - expect_error(as.difftime(i32), "need explicit units for numeric conversion", fixed=TRUE) - expect_error(as.difftime(i64), "need explicit units for numeric conversion", fixed=TRUE) - expect_identical(as.difftime(i64, units="secs"), as.difftime(i32, units="secs")) - } - + # to integer64 expect_identical(as.integer64(TRUE), as.integer64(1L)) expect_identical(as.integer64(as.character(1:10)), as.integer64(1:10)) @@ -76,17 +61,8 @@ test_that("integer64 coercion to/from other types work", { expect_identical(methods::as(as.integer64(1:10), "complex"), as.complex(1:10)) expect_identical(methods::as(as.integer64(1:10), "numeric"), as.numeric(1:10)) expect_identical(methods::as(as.integer64(1:10), "integer"), as.integer(1:10)) - if (getRversion() >= "4.0.0") { - expect_identical(methods::as(as.integer64(1:10), "raw"), as.raw(1:10)) - } expect_identical(methods::as(as.integer64(1:10), "logical"), as.logical(1:10)) - if (getRversion() >= "4.0.0") { - expect_identical(methods::as(as.integer64(1:10), "difftime"), as.difftime(1:10, units="secs")) - expect_identical(methods::as(as.integer64(1:10), "POSIXct"), as.POSIXct(as.numeric(1:10))) - expect_identical(methods::as(as.integer64(1:10), "POSIXlt"), as.POSIXlt(1:10)) - expect_identical(methods::as(as.integer64(1:10), "Date"), as.Date(as.numeric(1:10))) - } - + # now for NA expect_identical(as.logical(NA_integer64_), NA) expect_identical(as.integer(NA_integer64_), NA_integer_) @@ -98,6 +74,34 @@ test_that("integer64 coercion to/from other types work", { expect_identical(as.integer64(NA_character_), NA_integer64_) }) +test_that("integer64 coercion to/from other types work for R >=4.0.0", { + skip_if_not_r_version("4.0.0") + # from integer64 + i32 = 1:10 + i64 = as.integer64(i32) + expect_identical(as.Date(i64), as.Date(as.numeric(i32))) + expect_identical(as.Date(i64, origin=10), as.Date(as.numeric(i32), origin=10)) + expect_identical(as.POSIXct(i64), as.POSIXct(as.numeric(i32))) + expect_identical(as.POSIXct(i64, origin=10), as.POSIXct(as.numeric(i32), origin=10)) + expect_identical(as.POSIXct(i64, tz="UTC", origin=10), as.POSIXct(as.numeric(i32), tz="UTC", origin=10)) + expect_identical(as.POSIXct(i64, tz="CET", origin=10), as.POSIXct(as.numeric(i32), tz="CET", origin=10)) + expect_identical(as.POSIXlt(i64), as.POSIXlt(i32)) + expect_identical(as.POSIXlt(i64, origin=10), as.POSIXlt(i32, origin=10)) + expect_identical(as.POSIXlt(i64, tz="UTC", origin=10), as.POSIXlt(i32, tz="UTC", origin=10)) + expect_identical(as.POSIXlt(i64, tz="CET", origin=10), as.POSIXlt(i32, tz="CET", origin=10)) + expect_error(as.difftime(i32), "need explicit units for numeric conversion", fixed=TRUE) + expect_error(as.difftime(i64), "need explicit units for numeric conversion", fixed=TRUE) + expect_identical(as.difftime(i64, units="secs"), as.difftime(i32, units="secs")) + + # S4 version + expect_identical(methods::as(as.integer64(1:10), "raw"), as.raw(1:10)) + expect_identical(methods::as(as.integer64(1:10), "difftime"), as.difftime(1:10, units="secs")) + expect_identical(methods::as(as.integer64(1:10), "POSIXct"), as.POSIXct(as.numeric(1:10))) + expect_identical(methods::as(as.integer64(1:10), "POSIXlt"), as.POSIXlt(1:10)) + expect_identical(methods::as(as.integer64(1:10), "Date"), as.Date(as.numeric(1:10))) + +}) + test_that("S3 class basics work", { x = as.integer64(1:10) expect_s3_class(x, "integer64") From 2916c8c8f99b5445e80eae73834d57cc71aa08ed Mon Sep 17 00:00:00 2001 From: hcirellu Date: Fri, 14 Nov 2025 16:00:04 +0100 Subject: [PATCH 6/6] as.data.frame coercion --- R/integer64.R | 15 +++++++-------- man/as.data.frame.integer64.Rd | 6 +++--- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/R/integer64.R b/R/integer64.R index c71dfba..854199f 100644 --- a/R/integer64.R +++ b/R/integer64.R @@ -337,7 +337,7 @@ NULL #' Coercing integer64 vector to data.frame. #' #' @param x an integer64 vector -#' @param ... passed to NextMethod [as.data.frame()] after removing the +#' @param row.names,optional,... passed to NextMethod [as.data.frame()] after removing the #' 'integer64' class attribute #' #' @returns a one-column data.frame containing an integer64 vector @@ -350,7 +350,7 @@ NULL #' [cbind.integer64()] [integer64()] # as.vector.integer64 removed as requested by the CRAN maintainer [as.vector.integer64()] #' @examples -#' as.data.frame.integer64(as.integer64(1:12)) +#' as.data.frame(as.integer64(1:12)) #' data.frame(a=1:12, b=as.integer64(1:12)) #' @name as.data.frame.integer64 NULL @@ -1138,15 +1138,14 @@ rbind.integer64 <- function(...) { #' @rdname as.data.frame.integer64 #' @export -as.data.frame.integer64 <- function(x, ...) { - cl <- oldClass(x) +as.data.frame.integer64 <- function(x, row.names=NULL, optional=FALSE, ...) { + cl = oldClass(x) on.exit(setattr(x, "class", cl)) # tenfold runtime if using attr() here instead of setattr() setattr(x, "class", minusclass(cl, "integer64")) - ret <- as.data.frame(x, ...) - k <- length(ret) - for (i in 1:k) - setattr(ret[[i]], "class", cl) + ret = callGeneric() + for (i in seq_along(ret)) + setattr(ret[[i]], "class", cl) ret } diff --git a/man/as.data.frame.integer64.Rd b/man/as.data.frame.integer64.Rd index c2ab525..a5bc12b 100644 --- a/man/as.data.frame.integer64.Rd +++ b/man/as.data.frame.integer64.Rd @@ -4,12 +4,12 @@ \alias{as.data.frame.integer64} \title{integer64: Coercing to data.frame column} \usage{ -\method{as.data.frame}{integer64}(x, ...) +\method{as.data.frame}{integer64}(x, row.names=NULL, optional=FALSE, ...) } \arguments{ \item{x}{an integer64 vector} -\item{...}{passed to NextMethod \code{\link[=as.data.frame]{as.data.frame()}} after removing the +\item{row.names,optional,...}{passed to NextMethod \code{\link[=as.data.frame]{as.data.frame()}} after removing the 'integer64' class attribute} } \value{ @@ -26,7 +26,7 @@ but it is required to allow integer64 as data.frame columns. This is currently very slow -- any ideas for improvement? } \examples{ - as.data.frame.integer64(as.integer64(1:12)) + as.data.frame(as.integer64(1:12)) data.frame(a=1:12, b=as.integer64(1:12)) } \seealso{