···11-# Start by looking at the `big_num` class
22-31node_or_na <- function(value) is.na(value) || S7_inherits(value, node) # predicate to check if `value` is a `node` or `NA`, pulled out to reduce duplication
4253node <- new_class("node",
···75 properties = list(
86 VALUE = new_property(
97 class_numeric, # TODO: make this a generic?
1010- getter = function(self) self@VALUE
88+ getter = function(self) self@VALUE,
99+ setter = NULL
1110 ),
1212- e = new_property(class_environment, getter = function(self) self@e),
1111+ state = new_property(
1212+ class_environment,
1313+ getter = function(self) self@state,
1414+ setter = NULL
1515+ ),
1316 nxt = new_property(class_any,
1417 getter = function(self) {
1515- self@e$nxt
1818+ self@state$nxt
1619 },
1720 setter = function(self, value) {
1818- my_env <- self@e
2121+ my_env <- self@state
1922 my_env$nxt <- value
20232124 self
···3336 force(VALUE)
3437 force(nxt)
35383636- new_object(S7_object(), VALUE = VALUE, e = rlang::new_environment(list(nxt = nxt)))
3939+ new_object(S7_object(), VALUE = VALUE, state = rlang::new_environment(list(nxt = nxt)))
3740 }
3841)
3942···4245 properties = list(
4346 head = new_property(
4447 node,
4545- getter = function(self) self@e$head,
4848+ getter = function(self) self@state$head,
4649 setter = function(self, value) {
4750 # TODO: kick up to error?
4851 warning("@head should not be set manually. Maybe you meant to use `append_to_start()`?", call. = FALSE)
49525050- my_env <- self@e
5353+ my_env <- self@state
5154 my_env$head <- value
52555356 self
···5558 validator = node_or_na
5659 ),
5760 tail = new_property(node,
5858- getter = function(self) self@e$tail,
6161+ getter = function(self) self@state$tail,
5962 setter = function(self, value) {
6063 warning("@tail should not be set manually", call. = FALSE)
61646262- my_env <- self@e
6565+ my_env <- self@state
6366 my_env$tail <- value
64676568 self
6669 }
6770 ),
6868- length = new_property(class_integer, getter = function(self) self@e$length, setter = function(self, value) {
7171+ length = new_property(class_integer, getter = function(self) self@state$length, setter = function(self, value) {
6972 warning("@length should not be set manually", call. = FALSE)
7070- environ <- self@e
7373+ environ <- self@state
7174 environ$length <- as.integer(value)
72757376 self
7477 }),
7575- e = new_property(class_environment, getter = function(self) self@e)
7878+ state = new_property(class_environment, getter = function(self) self@state)
7679 ),
7780 validator = function(self) {
7881 if (!node_or_na(self@head)) {
···8588 force(num)
86898790 if (is.null(num) || num == "") {
8888- return(new_object(S7_object(), e = rlang::new_environment(list(head = NA, tail = NA, length = 0))))
9191+ return(new_object(S7_object(), state = rlang::new_environment(list(head = NA, tail = NA, length = 0))))
8992 }
90939191- extract_digit_to_node <- function(len) node(as.integer(substring(num, len, len))) # TODO: throw error if the char isn't numeric
9494+ extract_digit_to_node <- function(pos) node(as.integer(substring(num, pos, pos))) # TODO: throw error if the char isn't numeric
92959396 len <- nchar(num)
9497 nodes <- lapply(len:1, function(i) extract_digit_to_node(i))
···99102 }
100103 }
101104102102- e <- rlang::new_environment(list(
105105+ state <- rlang::new_environment(list(
103106 head = nodes[[1]],
104107 tail = nodes[[len]],
105108 length = len
106109 ))
107110108108- new_object(S7_object(), e = e)
111111+ new_object(S7_object(), state = state)
109112 }
110113)
111114···122125#'
123126#' @export
124127#' @param num A string representation of a num.
125125-big_num <- new_class("big_num", # this defines the class, and should match the name of the object on the left-hand-side of the assignment.
126126- package = "BigNum", # this defines a package for this `big_num` object so that it doesn't conflict with other potential `big_num` objects from other packages.
127127- # properties defines a list of variables that `big_num`s have. Here we have just one property, a `linked_list`
128128+big_num <- new_class("big_num",
129129+ package = "BigNum",
128130 properties = list(
129129- ll = new_property(linked_list, getter = function(self) self@ll) # this property has a custom getter, but no setter. This means that you can get a `big_num`'s `ll` but you cannot set it--i.e. this is a read-only property.
131131+ ll = new_property(
132132+ linked_list,
133133+ getter = function(self) self@ll,
134134+ setter = NULL
135135+ )
130136 ),
131131- # the class validator is a function that takes a purported `big_num` object (viz. `self`), and runs some checks to ensure that it actually is a `big_num`.
132137 validator = function(self) {
133133- # as expected, this predicate just checks if `self`'s `ll` is an actual `linked_list`
134138 if (!S7_inherits(self@ll, linked_list)) {
135139 "@ll must be a valid linked list."
136140 }
137137- # all validators should return a string if there is an error, or NULL if all's good. Let R return NULL for you automatically.
138141 },
139139- # S7 objects can have custom constructors which allow you to do some logic with inputs before ending with a call to `new_object()`
140140- # this constructor finesses the input to allow for construction of `big_num`s with a numeric `num` as well as the expected character input
141141- # note as well that the constructor is a function, and so it takes certain arguments which can have default values. Here, all `big_nums` start
142142- # out empty. However, looking at the `node` class one can note that `val` has no default and so must be provided when creating a `node` object.
143142 constructor = function(num = "") {
144143 force(num)
145145- new_object(S7_object(), ll = linked_list(format(num, trim = TRUE, scientific = FALSE)))
144144+145145+ if (!is.character(num)) warning("Coercing `num` to string using `format()`")
146146+147147+ num <- format(num, trim = TRUE, scientific = FALSE) # TODO: test this
148148+ new_object(S7_object(), ll = linked_list(num))
146149 }
147150)
148151152152+# TODO: Rewrite to inherit from linked_list--adjust methods accordingly
153153+# big_num <- new_class("big_num",
154154+# parent = linked_list,
155155+# package = "BigNum",
156156+# constructor = function(num = "") {
157157+# new_object(linked_list(), num = num)
158158+# }
159159+# )
160160+149161is.na <- new_external_generic("base", "is.na", "x")
150162method(is.na, node) <- function(x) !S7_inherits(x, node)
151163152164is_even <- new_generic("is_even", c("x"))
153165method(is_even, big_num) <- function(x) x@ll@head@VALUE %% 2 == 0
154166155155-append <- new_generic("append", c("x", "ll"))
156156-method(append, list(node, linked_list)) <- function(x, ll) {
167167+# TODO: rewrite to be external generic?
168168+bn_append <- new_generic("bn_append", c("x", "ll"))
169169+method(bn_append, list(node, linked_list)) <- function(x, ll) {
157170 suppressWarnings({
158171 if (is.na(ll@head)) {
159172 ll@head <- x
···167180168181 invisible(ll)
169182}
170170-method(append, list(class_numeric, linked_list)) <- function(x, ll) {
183183+method(bn_append, list(class_numeric, linked_list)) <- function(x, ll) {
171184 stopifnot(x < 10 && x >= 0)
172172- append(node(x), ll)
185185+ bn_append(node(x), ll)
173186}
174174-method(append, list(class_numeric | node, big_num)) <- function(x, ll) {
175175- append(x, ll@ll)
187187+method(bn_append, list(class_numeric | node, big_num)) <- function(x, ll) {
188188+ bn_append(x, ll@ll)
176189}
177190178191append_to_start <- new_generic("append_to_start", c("x", "ll"))
···231244 invisible(x)
232245}
233246247247+# method(print, big_num) <- function(x) {
248248+# len <- x@length
249249+250250+# if (len == 0) {
251251+# cat("NA\n")
252252+# return(invisible(x))
253253+# }
254254+255255+# stack <- character(len)
256256+# current <- x@head
257257+258258+# for (i in len:1) {
259259+# stack[i] <- current@VALUE
260260+# current <- current@nxt
261261+# }
262262+263263+# string <- paste0(stack, collapse = "")
264264+# cat(string, "\n")
265265+266266+# invisible(x)
267267+# }
268268+234269`+` <- new_external_generic("base", "+", c("e1", "e2"))
235270add_helper <- function(node1, node2, carry, sum) {
236271 digit <- node1@VALUE + node2@VALUE + carry
237272 carry <- digit %/% 10
238273 digit <- digit %% 10
239239- append(digit, sum)
274274+ bn_append(digit, sum)
240275241276 carry
242277}
···260295 node2 <- node2@nxt
261296 }
262297 if (carry > 0) {
263263- append(carry, sum)
298298+ bn_append(carry, sum)
264299 }
265300266301 sum
+79
R/big_num_S3.R
···11+node_or_na_s3 <- function(value) is.na(value) || inherits(value, "big_num_node_s3")
22+33+node_s3 <- function(VALUE, nxt = NA) {
44+ stopifnot(node_or_na_s3(nxt), is.numeric(VALUE), length(VALUE) == 1)
55+66+ structure(
77+ list(
88+ VALUE = VALUE,
99+ state = rlang::new_environment(list(nxt = nxt))
1010+ ),
1111+ class = "big_num_node_s3"
1212+ )
1313+}
1414+1515+linked_list_s3 <- function(num = NULL) {
1616+ force(num)
1717+1818+ if (is.null(num) || num == "") {
1919+ return(structure(list(state = rlang::new_environment(list(head = NA, tail = NA, length = 0))), class = "big_num_linked_list_s3"))
2020+ }
2121+2222+ extract_digit_to_node <- function(pos) node_s3(as.integer(substring(num, pos, pos))) # TODO: throw error if the char isn't numeric
2323+2424+ len <- nchar(num)
2525+ nodes <- lapply(len:1, function(i) extract_digit_to_node(i))
2626+2727+ if (len != 1) {
2828+ for (i in (len - 1):1) {
2929+ nodes[[i]]$state$nxt <- nodes[[i + 1]]
3030+ }
3131+ }
3232+3333+ state <- rlang::new_environment(list(
3434+ head = nodes[[1]],
3535+ tail = nodes[[len]],
3636+ length = len
3737+ ))
3838+3939+ structure(
4040+ list(
4141+ state = state
4242+ ),
4343+ class = "big_num_linked_list_s3"
4444+ )
4545+}
4646+4747+big_num_s3 <- function(num = "") {
4848+ structure(linked_list_s3(num), class = "big_num_s3")
4949+}
5050+5151+is.na.node_s3 <- function(x) {
5252+ !inherits(x, "big_num_node_s3")
5353+}
5454+5555+is_even_s3 <- function(x) {
5656+ UseMethod("is_even_s3")
5757+}
5858+5959+is_even_s3.big_num <- function(x) {
6060+ x$ll$state$head$VALUE %% 2 == 0
6161+}
6262+6363+bn_append_s3 <- function(x, ll) {
6464+ UseMethod("bn_append_s3")
6565+}
6666+6767+# TODO: fix this later
6868+bn_append_s3.linked_list <- function(x, ll) {
6969+ if (is.na(ll$state$head)) {
7070+ ll$state$head <- x
7171+ ll$state$tail <- x
7272+ } else {
7373+ ll$state$tail@nxt <- x
7474+ ll$state$tail <- x
7575+ }
7676+ ll@length <- ll@length + 1
7777+7878+ invisible(ll)
7979+}
+74
R/big_num_S4.R
···11+node_or_na_s4 <- function(value) is.na(value) || is(value, "big_num_node_s4")
22+33+setClass("big_num_node_s4",
44+ slots = c(
55+ VALUE = "numeric",
66+ state = "environment"
77+ ),
88+ prototype = list(
99+ VALUE = NA_real_
1010+ )
1111+)
1212+1313+node_s4 <- function(VALUE, nxt = NA) {
1414+ stopifnot(node_or_na_s4(nxt), is.numeric(VALUE), length(VALUE) == 1)
1515+1616+ new("big_num_node_s4", VALUE = VALUE, state = rlang::new_environment(list(nxt = nxt)))
1717+}
1818+1919+# TODO: copy this in S3 to approximate read only properties
2020+setGeneric("nxt", function(x) standardGeneric("nxt"))
2121+setMethod("nxt", "big_num_node_s4", function(x) x@state$nxt)
2222+2323+setGeneric("nxt<-", function(x, value) standardGeneric("nxt<-"))
2424+setMethod("nxt<-", "big_num_node_s4", function(x, value) {
2525+ x@state$nxt <- value
2626+ x
2727+})
2828+2929+setGeneric("VALUE", function(x) standardGeneric("VALUE"))
3030+setMethod("VALUE", "big_num_node_s4", function(x) x@VALUE)
3131+3232+setGeneric("VALUE<-", function(x, value) standardGeneric("VALUE<-"))
3333+setMethod("VALUE<-", "big_num_node_s4", function(x, value) {
3434+ stop("Can't set read-only property VALUE ")
3535+})
3636+3737+setClass("big_num_linked_list_s4",
3838+ slots = c(
3939+ state = "environment"
4040+ )
4141+)
4242+4343+linked_list_s4 <- function(num = NULL) {
4444+ force(num)
4545+4646+ if (is.null(num) || num == "") {
4747+ return(new("big_num_linked_list_s4", state = rlang::new_environment(list(head = NA, tail = NA, length = 0))))
4848+ }
4949+5050+ extract_digit_to_node <- function(pos) node_s4(as.integer(substring(num, pos, pos)))
5151+5252+ len <- nchar(num)
5353+ nodes <- lapply(len:1, function(i) extract_digit_to_node(i))
5454+5555+ if (len != 1) {
5656+ for (i in (len - 1):1) {
5757+ nodes[[i]]@state$nxt <- nodes[[i + 1]]
5858+ }
5959+ }
6060+6161+ state <- rlang::new_environment(list(
6262+ head = nodes[[1]],
6363+ tail = nodes[[len]],
6464+ length = len
6565+ ))
6666+6767+ new("big_num_linked_list_s4", state = state)
6868+}
6969+7070+setClass("big_num_s4", contains = "big_num_linked_list_s4")
7171+7272+big_num_s4 <- function(num = "") {
7373+ as(linked_list_s4(num), "big_num_s4")
7474+}