From 93ca8cfa047ed5e97ed1300a6816b92845f4c1f0 Mon Sep 17 00:00:00 2001 From: Winston Chang Date: Fri, 5 Apr 2024 23:22:04 -0500 Subject: [PATCH] Add functions for lzstring compressing to URI components --- NAMESPACE | 1 + R/cpp11.R | 9 +++++++++ R/utils.R | 2 ++ src/code.cpp | 27 ++++++++++++++++++++++++++- src/cpp11.cpp | 35 +++++++++++++++++++++++++++++++++++ src/lz-string.hpp | 22 ++++++++++++++++++++++ 6 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 R/cpp11.R create mode 100644 src/cpp11.cpp diff --git a/NAMESPACE b/NAMESPACE index 6a56160..cd3285f 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -10,3 +10,4 @@ export(assets_remove) export(assets_version) export(export) importFrom(rlang,is_interactive) +useDynLib(shinylive, .registration = TRUE) diff --git a/R/cpp11.R b/R/cpp11.R new file mode 100644 index 0000000..47a4f0c --- /dev/null +++ b/R/cpp11.R @@ -0,0 +1,9 @@ +# Generated by cpp11: do not edit by hand + +compressToEncodedURIComponent <- function(uncompressed8) { + .Call(`_shinylive_compressToEncodedURIComponent`, uncompressed8) +} + +decompressFromEncodedURIComponent <- function(compressed8) { + .Call(`_shinylive_decompressFromEncodedURIComponent`, compressed8) +} diff --git a/R/utils.R b/R/utils.R index 6eb6f79..f7d0e46 100644 --- a/R/utils.R +++ b/R/utils.R @@ -1,3 +1,5 @@ +#' @useDynLib shinylive, .registration = TRUE + assert_nzchar_string <- function(x) { stopifnot(is.character(x) && nchar(x) > 0) invisible(TRUE) diff --git a/src/code.cpp b/src/code.cpp index 04ab900..0472a4b 100644 --- a/src/code.cpp +++ b/src/code.cpp @@ -1,6 +1,31 @@ #include +#include #include "lz-string.hpp" using namespace cpp11; [[cpp11::register]] -void fun() {} +std::string compressToEncodedURIComponent(std::string uncompressed8) { + std::wstring_convert, char16_t> converter_8_to_16; + std::u16string uncompressed16 = converter_8_to_16.from_bytes(uncompressed8); + + auto compressed16 = lzstring::compressToEncodedURIComponent(uncompressed16); + + std::wstring_convert, char16_t> converter_16_to_8; + std::string compressed8 = converter_16_to_8.to_bytes(compressed16); + + return compressed8; +} + + +[[cpp11::register]] +std::string decompressFromEncodedURIComponent(std::string compressed8) { + std::wstring_convert, char16_t> converter_8_to_16; + std::u16string compressed16 = converter_8_to_16.from_bytes(compressed8); + + auto uncompressed16 = lzstring::decompressFromEncodedURIComponent(compressed16); + + std::wstring_convert, char16_t> converter_16_to_8; + std::string uncompressed8 = converter_16_to_8.to_bytes(uncompressed16); + + return uncompressed8; +} diff --git a/src/cpp11.cpp b/src/cpp11.cpp new file mode 100644 index 0000000..0b1b695 --- /dev/null +++ b/src/cpp11.cpp @@ -0,0 +1,35 @@ +// Generated by cpp11: do not edit by hand +// clang-format off + + +#include "cpp11/declarations.hpp" +#include + +// code.cpp +std::string compressToEncodedURIComponent(std::string uncompressed8); +extern "C" SEXP _shinylive_compressToEncodedURIComponent(SEXP uncompressed8) { + BEGIN_CPP11 + return cpp11::as_sexp(compressToEncodedURIComponent(cpp11::as_cpp>(uncompressed8))); + END_CPP11 +} +// code.cpp +std::string decompressFromEncodedURIComponent(std::string compressed8); +extern "C" SEXP _shinylive_decompressFromEncodedURIComponent(SEXP compressed8) { + BEGIN_CPP11 + return cpp11::as_sexp(decompressFromEncodedURIComponent(cpp11::as_cpp>(compressed8))); + END_CPP11 +} + +extern "C" { +static const R_CallMethodDef CallEntries[] = { + {"_shinylive_compressToEncodedURIComponent", (DL_FUNC) &_shinylive_compressToEncodedURIComponent, 1}, + {"_shinylive_decompressFromEncodedURIComponent", (DL_FUNC) &_shinylive_decompressFromEncodedURIComponent, 1}, + {NULL, NULL, 0} +}; +} + +extern "C" attribute_visible void R_init_shinylive(DllInfo* dll){ + R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); + R_useDynamicSymbols(dll, FALSE); + R_forceSymbols(dll, TRUE); +} diff --git a/src/lz-string.hpp b/src/lz-string.hpp index 8268cdd..41f0b4b 100644 --- a/src/lz-string.hpp +++ b/src/lz-string.hpp @@ -33,6 +33,7 @@ using string = std::u16string; namespace __inner { const string keyStrBase64{_U("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=")}; + const string keyStrUriSafe{_U("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$")}; const string::value_type equal{_U('=')}; int charCodeAt(const string& str, int pos) @@ -533,6 +534,27 @@ namespace __inner } // namespace __inner +string compressToEncodedURIComponent(const string& input) +{ + if (input.empty()) return {}; + using namespace __inner; + auto res = _compress(input, 6, [](int a) { return keyStrBase64.at(a); }); + return res; +} + + +string decompressFromEncodedURIComponent(const string& input) +{ + if (input.empty()) return {}; + using namespace __inner; + string input1 = input; + // std::replace(input1.begin(), input1.end(), ' ', '+'); + std::unordered_map baseReverseDic; + for (int i = 0; i < keyStrUriSafe.length(); ++i) baseReverseDic[keyStrUriSafe.at(i)] = i; + return _decompress(input1.length(), 32, [&](int index) { return baseReverseDic[input.at(index)]; }); +} + + // clang-format off string compressToBase64(const string& input) {