From 558483ffea10c09760308297b8883f0759fa45e4 Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Mon, 15 Jul 2024 17:23:22 +0100 Subject: [PATCH 1/2] Add a method to overwrite a bitset. This copies the value from one bitset to another one. --- R/RcppExports.R | 4 ++++ R/bitset.R | 11 +++++++++++ man/Bitset.Rd | 12 ++++++++++++ src/RcppExports.cpp | 12 ++++++++++++ src/bitset.cpp | 11 +++++++++++ tests/testthat/test-bitset.R | 25 +++++++++++++++++++++++++ 6 files changed, 75 insertions(+) diff --git a/R/RcppExports.R b/R/RcppExports.R index f5af029..c61b5b8 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -41,6 +41,10 @@ bitset_or <- function(a, b) { invisible(.Call(`_individual_bitset_or`, a, b)) } +bitset_assign <- function(a, b) { + invisible(.Call(`_individual_bitset_assign`, a, b)) +} + bitset_xor <- function(a, b) { invisible(.Call(`_individual_bitset_xor`, a, b)) } diff --git a/R/bitset.R b/R/bitset.R index 0a2db18..177ec8c 100644 --- a/R/bitset.R +++ b/R/bitset.R @@ -108,6 +108,17 @@ Bitset <- list( self }, + #' ```{r echo=FALSE, results="asis"} + #' bitset_method_doc( + #' "assign", + #' "overwrite the value of a bitset from another bitset", + #' other = "the other bitset.") + #' ``` + assign = function(other) { + bitset_assign(self$.bitset, other$.bitset) + self + }, + #' ```{r echo=FALSE, results="asis"} #' bitset_method_doc( #' "size", diff --git a/man/Bitset.Rd b/man/Bitset.Rd index 9955742..b4c8b25 100644 --- a/man/Bitset.Rd +++ b/man/Bitset.Rd @@ -61,6 +61,18 @@ clear the bitset. } } \if{html}{\out{
}} +\subsection{Method \code{assign()}}{ +overwrite the value of a bitset from another bitset +\subsection{Usage}{ +\preformatted{b$assign(other)} +} +\subsection{Arguments}{ +\describe{ +\item{\code{other}}{the other bitset.} +} +} +} +\if{html}{\out{
}} \subsection{Method \code{size()}}{ get the number of elements in the set. \subsection{Usage}{ diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index 560ac8d..a18dba4 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -124,6 +124,17 @@ BEGIN_RCPP return R_NilValue; END_RCPP } +// bitset_assign +void bitset_assign(const Rcpp::XPtr a, const Rcpp::XPtr b); +RcppExport SEXP _individual_bitset_assign(SEXP aSEXP, SEXP bSEXP) { +BEGIN_RCPP + Rcpp::RNGScope rcpp_rngScope_gen; + Rcpp::traits::input_parameter< const Rcpp::XPtr >::type a(aSEXP); + Rcpp::traits::input_parameter< const Rcpp::XPtr >::type b(bSEXP); + bitset_assign(a, b); + return R_NilValue; +END_RCPP +} // bitset_xor void bitset_xor(const Rcpp::XPtr a, const Rcpp::XPtr b); RcppExport SEXP _individual_bitset_xor(SEXP aSEXP, SEXP bSEXP) { @@ -1476,6 +1487,7 @@ static const R_CallMethodDef CallEntries[] = { {"_individual_bitset_and", (DL_FUNC) &_individual_bitset_and, 2}, {"_individual_bitset_not", (DL_FUNC) &_individual_bitset_not, 2}, {"_individual_bitset_or", (DL_FUNC) &_individual_bitset_or, 2}, + {"_individual_bitset_assign", (DL_FUNC) &_individual_bitset_assign, 2}, {"_individual_bitset_xor", (DL_FUNC) &_individual_bitset_xor, 2}, {"_individual_bitset_set_difference", (DL_FUNC) &_individual_bitset_set_difference, 2}, {"_individual_bitset_sample", (DL_FUNC) &_individual_bitset_sample, 2}, diff --git a/src/bitset.cpp b/src/bitset.cpp index dbabdce..3513202 100644 --- a/src/bitset.cpp +++ b/src/bitset.cpp @@ -88,6 +88,17 @@ void bitset_or( (*a) |= (*b); } +//[[Rcpp::export]] +void bitset_assign( + const Rcpp::XPtr a, + const Rcpp::XPtr b + ) { + if (a->max_size() != b->max_size()) { + Rcpp::stop("Incompatible bitmap sizes"); + } + (*a) = (*b); +} + //[[Rcpp::export]] void bitset_xor( const Rcpp::XPtr a, diff --git a/tests/testthat/test-bitset.R b/tests/testthat/test-bitset.R index ebed57b..28563c3 100644 --- a/tests/testthat/test-bitset.R +++ b/tests/testthat/test-bitset.R @@ -80,6 +80,31 @@ test_that("bitset or works", { expect_equal(a$to_vector(), c(1, 3, 5, 6, 7)) }) +test_that("bitset assign works", { + a <- Bitset$new(10) + a$insert(c(1, 5, 6)) + b <- Bitset$new(10) + b$insert(c(1, 3, 7)) + + a$assign(b) + expect_equal(a$to_vector(), c(1, 3, 7)) + + # Check the two bitsets aren't aliases of each other. + b$clear() + expect_equal(a$to_vector(), c(1, 3, 7)) + expect_equal(b$to_vector(), numeric(0)) +}) + +test_that("bitset assign requires bitsets to have same max size", { + a <- Bitset$new(8) + a$insert(c(1, 5, 6)) + b <- Bitset$new(10) + b$insert(c(1, 3, 7)) + + expect_error(a$assign(b), "Incompatible bitmap sizes") +}) + + test_that("bitset set difference works for sets with intersection", { a <- Bitset$new(20) From a2fab1f13d9802bb8c817aa339d12a9249836bf5 Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Tue, 16 Jul 2024 12:52:17 +0100 Subject: [PATCH 2/2] Rename assign to copy_from. --- R/RcppExports.R | 4 ++-- R/bitset.R | 31 +++++++++++++++++++------------ man/Bitset.Rd | 30 ++++++++++++++++++------------ src/RcppExports.cpp | 10 +++++----- src/bitset.cpp | 2 +- tests/testthat/test-bitset.R | 8 ++++---- 6 files changed, 49 insertions(+), 36 deletions(-) diff --git a/R/RcppExports.R b/R/RcppExports.R index c61b5b8..e8f2962 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -41,8 +41,8 @@ bitset_or <- function(a, b) { invisible(.Call(`_individual_bitset_or`, a, b)) } -bitset_assign <- function(a, b) { - invisible(.Call(`_individual_bitset_assign`, a, b)) +bitset_copy_from <- function(a, b) { + invisible(.Call(`_individual_bitset_copy_from`, a, b)) } bitset_xor <- function(a, b) { diff --git a/R/bitset.R b/R/bitset.R index 177ec8c..7c551a8 100644 --- a/R/bitset.R +++ b/R/bitset.R @@ -108,17 +108,6 @@ Bitset <- list( self }, - #' ```{r echo=FALSE, results="asis"} - #' bitset_method_doc( - #' "assign", - #' "overwrite the value of a bitset from another bitset", - #' other = "the other bitset.") - #' ``` - assign = function(other) { - bitset_assign(self$.bitset, other$.bitset) - self - }, - #' ```{r echo=FALSE, results="asis"} #' bitset_method_doc( #' "size", @@ -221,10 +210,28 @@ Bitset <- list( #' ```{r echo=FALSE, results="asis"} #' bitset_method_doc( #' "copy", - #' "returns a copy of the bitset.") + #' "returns a copy of the bitset. + #' + #' In cases where a destination bitset already exists, it may be more + #' performant to use the \\code{copy_from} method instead.") #' ``` copy = function() Bitset$new(from = bitset_copy(self$.bitset)), + + #' ```{r echo=FALSE, results="asis"} + #' bitset_method_doc( + #' "copy_from", + #' "overwrite the value of the bitset from another bitset. + #' + #' This is similar to calling \\code{other$copy()}, but can be more + #' efficient by reusing the resources of the existing bitset.", + #' other = "the other bitset.") + #' ``` + copy_from = function(other) { + bitset_copy_from(self$.bitset, other$.bitset) + self + }, + #' ```{r echo=FALSE, results="asis"} #' bitset_method_doc( #' "to_vector", diff --git a/man/Bitset.Rd b/man/Bitset.Rd index b4c8b25..22b97c9 100644 --- a/man/Bitset.Rd +++ b/man/Bitset.Rd @@ -61,18 +61,6 @@ clear the bitset. } } \if{html}{\out{
}} -\subsection{Method \code{assign()}}{ -overwrite the value of a bitset from another bitset -\subsection{Usage}{ -\preformatted{b$assign(other)} -} -\subsection{Arguments}{ -\describe{ -\item{\code{other}}{the other bitset.} -} -} -} -\if{html}{\out{
}} \subsection{Method \code{size()}}{ get the number of elements in the set. \subsection{Usage}{ @@ -172,11 +160,29 @@ k should be chosen such that \eqn{0 \le k \le N}.} \if{html}{\out{
}} \subsection{Method \code{copy()}}{ returns a copy of the bitset. + +In cases where a destination bitset already exists, it may be more +performant to use the \code{copy_from} method instead. \subsection{Usage}{ \preformatted{b$copy()} } } \if{html}{\out{
}} +\subsection{Method \code{copy_from()}}{ +overwrite the value of the bitset from another bitset. + +This is similar to calling \code{other$copy()}, but can be more +efficient by reusing the resources of the existing bitset. +\subsection{Usage}{ +\preformatted{b$copy_from(other)} +} +\subsection{Arguments}{ +\describe{ +\item{\code{other}}{the other bitset.} +} +} +} +\if{html}{\out{
}} \subsection{Method \code{to_vector()}}{ return an integer vector of the elements stored in this bitset. \subsection{Usage}{ diff --git a/src/RcppExports.cpp b/src/RcppExports.cpp index a18dba4..1c5e23d 100644 --- a/src/RcppExports.cpp +++ b/src/RcppExports.cpp @@ -124,14 +124,14 @@ BEGIN_RCPP return R_NilValue; END_RCPP } -// bitset_assign -void bitset_assign(const Rcpp::XPtr a, const Rcpp::XPtr b); -RcppExport SEXP _individual_bitset_assign(SEXP aSEXP, SEXP bSEXP) { +// bitset_copy_from +void bitset_copy_from(const Rcpp::XPtr a, const Rcpp::XPtr b); +RcppExport SEXP _individual_bitset_copy_from(SEXP aSEXP, SEXP bSEXP) { BEGIN_RCPP Rcpp::RNGScope rcpp_rngScope_gen; Rcpp::traits::input_parameter< const Rcpp::XPtr >::type a(aSEXP); Rcpp::traits::input_parameter< const Rcpp::XPtr >::type b(bSEXP); - bitset_assign(a, b); + bitset_copy_from(a, b); return R_NilValue; END_RCPP } @@ -1487,7 +1487,7 @@ static const R_CallMethodDef CallEntries[] = { {"_individual_bitset_and", (DL_FUNC) &_individual_bitset_and, 2}, {"_individual_bitset_not", (DL_FUNC) &_individual_bitset_not, 2}, {"_individual_bitset_or", (DL_FUNC) &_individual_bitset_or, 2}, - {"_individual_bitset_assign", (DL_FUNC) &_individual_bitset_assign, 2}, + {"_individual_bitset_copy_from", (DL_FUNC) &_individual_bitset_copy_from, 2}, {"_individual_bitset_xor", (DL_FUNC) &_individual_bitset_xor, 2}, {"_individual_bitset_set_difference", (DL_FUNC) &_individual_bitset_set_difference, 2}, {"_individual_bitset_sample", (DL_FUNC) &_individual_bitset_sample, 2}, diff --git a/src/bitset.cpp b/src/bitset.cpp index 3513202..aec4f9b 100644 --- a/src/bitset.cpp +++ b/src/bitset.cpp @@ -89,7 +89,7 @@ void bitset_or( } //[[Rcpp::export]] -void bitset_assign( +void bitset_copy_from( const Rcpp::XPtr a, const Rcpp::XPtr b ) { diff --git a/tests/testthat/test-bitset.R b/tests/testthat/test-bitset.R index 28563c3..888bdce 100644 --- a/tests/testthat/test-bitset.R +++ b/tests/testthat/test-bitset.R @@ -80,13 +80,13 @@ test_that("bitset or works", { expect_equal(a$to_vector(), c(1, 3, 5, 6, 7)) }) -test_that("bitset assign works", { +test_that("bitset copy from works", { a <- Bitset$new(10) a$insert(c(1, 5, 6)) b <- Bitset$new(10) b$insert(c(1, 3, 7)) - a$assign(b) + a$copy_from(b) expect_equal(a$to_vector(), c(1, 3, 7)) # Check the two bitsets aren't aliases of each other. @@ -95,13 +95,13 @@ test_that("bitset assign works", { expect_equal(b$to_vector(), numeric(0)) }) -test_that("bitset assign requires bitsets to have same max size", { +test_that("bitset copy from requires bitsets to have same max size", { a <- Bitset$new(8) a$insert(c(1, 5, 6)) b <- Bitset$new(10) b$insert(c(1, 3, 7)) - expect_error(a$assign(b), "Incompatible bitmap sizes") + expect_error(a$copy_from(b), "Incompatible bitmap sizes") })