diff --git a/cpp11test/src/cpp11.cpp b/cpp11test/src/cpp11.cpp index 1ef645ac..b4304d76 100644 --- a/cpp11test/src/cpp11.cpp +++ b/cpp11test/src/cpp11.cpp @@ -5,6 +5,7 @@ #include using namespace Rcpp; #include "cpp11/declarations.hpp" +#include // add.cpp SEXP cpp11_add_vec_for_(cpp11::writable::doubles x, double num); @@ -444,7 +445,7 @@ static const R_CallMethodDef CallEntries[] = { }; } -extern "C" void R_init_cpp11test(DllInfo* dll){ +extern "C" attribute_visible void R_init_cpp11test(DllInfo* dll){ R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); R_forceSymbols(dll, TRUE); diff --git a/cpp11test/src/test-nameof.cpp b/cpp11test/src/test-nameof.cpp new file mode 100644 index 00000000..c7101dad --- /dev/null +++ b/cpp11test/src/test-nameof.cpp @@ -0,0 +1,21 @@ +#include "cpp11/nameof.hpp" + +#include + +struct Global; + +namespace ns { +struct Namespaced; +} // namespace ns + +context("nameof-C++") { + test_that("nameof works") { + expect_true(cpp11::nameof() == "Global"); + expect_true(cpp11::nameof() == "ns::Namespaced"); + expect_true(cpp11::nameof(/*strip_namespace=*/true) == "Namespaced"); + + // namespace for local scope structs is compiler dependent + struct Local; + expect_true(cpp11::nameof(/*strip_namespace=*/true) == "Local"); + } +} diff --git a/inst/include/cpp11/nameof.hpp b/inst/include/cpp11/nameof.hpp new file mode 100644 index 00000000..920df35c --- /dev/null +++ b/inst/include/cpp11/nameof.hpp @@ -0,0 +1,82 @@ +/// Distributed under the Boost Software License, Version 1.0. (See +/// http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include + +namespace cpp11 { +namespace detail { + +#ifdef _MSC_VER +#define ARROW_PRETTY_FUNCTION __FUNCSIG__ +#else +#define ARROW_PRETTY_FUNCTION __PRETTY_FUNCTION__ +#endif + +template +const char* raw() { + return ARROW_PRETTY_FUNCTION; +} + +template +size_t raw_sizeof() { + return sizeof(ARROW_PRETTY_FUNCTION); +} + +#undef ARROW_PRETTY_FUNCTION + +constexpr bool starts_with(char const* haystack, char const* needle) { + return needle[0] == '\0' || + (haystack[0] == needle[0] && starts_with(haystack + 1, needle + 1)); +} + +constexpr size_t search(char const* haystack, char const* needle) { + return haystack[0] == '\0' || starts_with(haystack, needle) + ? 0 + : search(haystack + 1, needle) + 1; +} + +const size_t typename_prefix = search(raw(), "double"); + +template +size_t struct_class_prefix() { +#ifdef _MSC_VER + return starts_with(raw() + typename_prefix, "struct ") + ? 7 + : starts_with(raw() + typename_prefix, "class ") ? 6 : 0; +#else + return 0; +#endif +} + +template +size_t typename_length() { + // raw_sizeof() - raw_sizeof() == + // (length of T's name) - strlen("double") + // (length of T's name) == + // raw_sizeof() - raw_sizeof() + strlen("double") + return raw_sizeof() - struct_class_prefix() - raw_sizeof() + 6; +} + +template +const char* typename_begin() { + return raw() + struct_class_prefix() + typename_prefix; +} + +} // namespace detail + +template +std::string nameof(bool strip_namespace = false) { + std::string name{detail::typename_begin(), detail::typename_length()}; + if (strip_namespace) { + auto i = name.find_last_of("::"); + if (i != std::string::npos) { + name = name.substr(i + 1); + } + } + return name; +} + +} // namespace cpp11