Skip to content

Commit

Permalink
New cpp11::messages with opt-in fmt formatting (#213)
Browse files Browse the repository at this point in the history
Co-authored-by: Benjamin Kietzman <bengilgit@gmail.com>
  • Loading branch information
sbearrows and bkietz authored Jul 23, 2021
1 parent d412399 commit e51bcce
Show file tree
Hide file tree
Showing 8 changed files with 94 additions and 0 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* Error messages now output original file name rather than the temporary file name (@sbearrows, #194)
* Fixed bug when running `cpp_source()` on the same file more than once (@sbearrows, #202)
* Removed internal instances of `cpp11::stop()` and replaced with C++ exceptions (@sbearrows, #203)
* Added `cpp11::messages()` feature with {fmt} library formatting for non-error messages (@sbearrows, #208)
* Names of named lists are now resized along with the list elements (@sbearrows, #206)
* Added optionally formatting to `stop()` and `warning()` using {fmt} library (@sbearrows, #169)

Expand Down
8 changes: 8 additions & 0 deletions cpp11test/R/cpp11.R
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ my_warning <- function(mystring, myarg) {
invisible(.Call(`_cpp11test_my_warning`, mystring, myarg))
}

my_message <- function(mystring, myarg) {
invisible(.Call(`_cpp11test_my_message`, mystring, myarg))
}

my_stop_n1fmt <- function(mystring) {
invisible(.Call(`_cpp11test_my_stop_n1fmt`, mystring))
}
Expand All @@ -32,6 +36,10 @@ my_warning_n2fmt <- function(mystring, myarg) {
invisible(.Call(`_cpp11test_my_warning_n2fmt`, mystring, myarg))
}

my_message_nfmt <- function(mystring, myarg) {
invisible(.Call(`_cpp11test_my_message_nfmt`, mystring, myarg))
}

remove_altrep <- function(x) {
.Call(`_cpp11test_remove_altrep`, x)
}
Expand Down
18 changes: 18 additions & 0 deletions cpp11test/src/cpp11.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ extern "C" SEXP _cpp11test_my_warning(SEXP mystring, SEXP myarg) {
return R_NilValue;
END_CPP11
}
// errors_fmt.cpp
void my_message(std::string mystring, std::string myarg);
extern "C" SEXP _cpp11test_my_message(SEXP mystring, SEXP myarg) {
BEGIN_CPP11
my_message(cpp11::as_cpp<cpp11::decay_t<std::string>>(mystring), cpp11::as_cpp<cpp11::decay_t<std::string>>(myarg));
return R_NilValue;
END_CPP11
}
// errors.cpp
void my_stop_n1fmt(std::string mystring);
extern "C" SEXP _cpp11test_my_stop_n1fmt(SEXP mystring) {
Expand Down Expand Up @@ -68,6 +76,14 @@ extern "C" SEXP _cpp11test_my_warning_n2fmt(SEXP mystring, SEXP myarg) {
return R_NilValue;
END_CPP11
}
// errors.cpp
void my_message_nfmt(std::string mystring, std::string myarg);
extern "C" SEXP _cpp11test_my_message_nfmt(SEXP mystring, SEXP myarg) {
BEGIN_CPP11
my_message_nfmt(cpp11::as_cpp<cpp11::decay_t<std::string>>(mystring), cpp11::as_cpp<cpp11::decay_t<std::string>>(myarg));
return R_NilValue;
END_CPP11
}
// find-intervals.cpp
SEXP remove_altrep(SEXP x);
extern "C" SEXP _cpp11test_remove_altrep(SEXP x) {
Expand Down Expand Up @@ -386,6 +402,8 @@ static const R_CallMethodDef CallEntries[] = {
{"_cpp11test_gibbs_rcpp", (DL_FUNC) &_cpp11test_gibbs_rcpp, 2},
{"_cpp11test_gibbs_rcpp2", (DL_FUNC) &_cpp11test_gibbs_rcpp2, 2},
{"_cpp11test_grow_", (DL_FUNC) &_cpp11test_grow_, 1},
{"_cpp11test_my_message", (DL_FUNC) &_cpp11test_my_message, 2},
{"_cpp11test_my_message_nfmt", (DL_FUNC) &_cpp11test_my_message_nfmt, 2},
{"_cpp11test_my_stop", (DL_FUNC) &_cpp11test_my_stop, 2},
{"_cpp11test_my_stop_n1fmt", (DL_FUNC) &_cpp11test_my_stop_n1fmt, 1},
{"_cpp11test_my_stop_n2fmt", (DL_FUNC) &_cpp11test_my_stop_n2fmt, 2},
Expand Down
4 changes: 4 additions & 0 deletions cpp11test/src/errors.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "cpp11/function.hpp"
#include "cpp11/protect.hpp"
using namespace cpp11;

Expand All @@ -11,3 +12,6 @@ using namespace cpp11;
[[cpp11::register]] void my_warning_n2fmt(std::string mystring, std::string myarg) {
cpp11::warning(mystring, myarg.c_str());
}
[[cpp11::register]] void my_message_nfmt(std::string mystring, std::string myarg) {
cpp11::message(mystring, myarg.c_str());
}
4 changes: 4 additions & 0 deletions cpp11test/src/errors_fmt.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#define CPP11_USE_FMT
#include "cpp11/function.hpp"
#include "cpp11/protect.hpp"
using namespace cpp11;

Expand All @@ -8,3 +9,6 @@ using namespace cpp11;
[[cpp11::register]] void my_warning(std::string mystring, std::string myarg) {
cpp11::warning(mystring, myarg);
}
[[cpp11::register]] void my_message(std::string mystring, std::string myarg) {
cpp11::message(mystring, myarg);
}
14 changes: 14 additions & 0 deletions cpp11test/tests/testthat/test_formatted_errors.R
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ test_that("cpp11::warning formatting works", {
test2 <- c("failed", "passed")
expect_warning(my_warning("You {}", test2[2]), "You passed", fixed = TRUE)
})
test_that("cpp11::message formatting works", {
test1 <- "message"
expect_message(my_message("This is a {}", test1), "This is a message", fixed = TRUE)

test2 <- c("great", "super")
expect_message(my_message("You're {}", test2[2]), "You're super", fixed = TRUE)
})
test_that("cpp11::stop works without including the fmt library", {
test1 <- "error"
expect_error(my_stop_n1fmt("This is a stop"), "This is a stop", fixed = TRUE)
Expand All @@ -23,3 +30,10 @@ test_that("cpp11::warning works without including the fmt library", {
expect_warning(my_warning_n1fmt("This is a warning"), "This is a warning", fixed = TRUE)
expect_warning(my_warning_n2fmt("This is a %s", test1), "This is a warning", fixed = TRUE)
})
test_that("cpp11::message works without including the fmt library", {
test1 <- "message"
expect_message(my_message_nfmt("This is a %s", test1), "This is a message", fixed = TRUE)

test2 <- c("great", "super")
expect_message(my_message_nfmt("You're %s", test2[2]), "You're super", fixed = TRUE)
})
36 changes: 36 additions & 0 deletions inst/include/cpp11/function.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <string.h> // for strcmp

#include <stdio.h> // for snprintf
#include <string> // for string, basic_string
#include <utility> // for forward

Expand Down Expand Up @@ -73,4 +74,39 @@ class package {

SEXP data_;
};

static auto R_message = cpp11::package("base")["message"];

#ifdef CPP11_USE_FMT
template <typename... Args>
void message(const char* fmt_arg, Args... args) {
std::string msg = fmt::format(fmt_arg, args...);
R_message(msg.c_str());
}

template <typename... Args>
void message(const std::string& fmt_arg, Args... args) {
std::string msg = fmt::format(fmt_arg, args...);
R_message(msg.c_str());
}
#else
template <typename... Args>
void message(const char* fmt_arg, Args... args) {
char buff[1024];
int msg = std::snprintf(buff, 1024, fmt_arg, args...);
if (msg >= 0 && msg < 1024) {
R_message(buff);
}
}

template <typename... Args>
void message(const std::string& fmt_arg, Args... args) {
char buff[1024];
int msg = std::snprintf(buff, 1024, fmt_arg.c_str(), args...);
if (msg >= 0 && msg < 1024) {
R_message(buff);
}
}
#endif

} // namespace cpp11
9 changes: 9 additions & 0 deletions tests/testthat/cpp11.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#include "cpp11/declarations.hpp"
using namespace cpp11;
// single_27.cpp
int foo();
extern "C" SEXP _single_27_foo() {
BEGIN_CPP11
return cpp11::as_sexp(foo());
END_CPP11
}

0 comments on commit e51bcce

Please sign in to comment.