diff --git a/.github/workflows/macos.yaml b/.github/workflows/macos.yaml index c86c6350e..40c40340a 100644 --- a/.github/workflows/macos.yaml +++ b/.github/workflows/macos.yaml @@ -14,7 +14,8 @@ jobs: strategy: matrix: include: - - {os: macOS-latest} + - {os: macos-latest} + - {os: macos-13} #- {os: ubuntu-latest} runs-on: ${{ matrix.os }} @@ -24,10 +25,7 @@ jobs: uses: actions/checkout@v4 - name: Setup - uses: eddelbuettel/github-actions/r-ci-setup@master - - - name: Bootstrap - run: ./run.sh bootstrap + uses: eddelbuettel/github-actions/r-ci@master - name: Dependencies run: ./run.sh install_deps diff --git a/ChangeLog b/ChangeLog index af2bb1c3a..c7b2d6368 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2025-03-15 Dirk Eddelbuettel + + * DESCRIPTION (Version, Date): Roll micro version and date + * inst/include/Rcpp/config.h: Idem + + * inst/include/Rcpp/platform/compiler.h: Simplified and shortened + establishing C++11 as baseline; further PRs to complete this + * inst/include/Rcpp/String.h: Unconditionally use std::hash with C++11 + * inst/include/Rcpp/wrap.h: Unconditionally use static_assert + * inst/include/Rcpp/sugar/functions/sapply.h: Use std::result_of + (with C++11 or C++14) or std::invoke_result (C++17 or later) + * inst/include/Rcpp/sugar/functions/table.h: Use std::map + * inst/include/Rcpp/sugar/sets.h: Use std::unordered_{set,map} + * man/evalCpp.Rd: Update example + * src/api.cpp: Simplify rcpp_capabilities assignment + 2025-03-13 Dirk Eddelbuettel * DESCRIPTION (Version, Date): Roll micro version and date diff --git a/DESCRIPTION b/DESCRIPTION index 0b6488a1d..c6707f3f2 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: Rcpp Title: Seamless R and C++ Integration -Version: 1.0.14.6 -Date: 2025-03-13 +Version: 1.0.14.7 +Date: 2025-03-15 Authors@R: c(person("Dirk", "Eddelbuettel", role = c("aut", "cre"), email = "edd@debian.org", comment = c(ORCID = "0000-0001-6419-907X")), person("Romain", "Francois", role = "aut", diff --git a/inst/include/Rcpp/String.h b/inst/include/Rcpp/String.h index 8316acee1..f1cb751cd 100644 --- a/inst/include/Rcpp/String.h +++ b/inst/include/Rcpp/String.h @@ -734,24 +734,14 @@ namespace Rcpp { } // Rcpp -/** hash can be in std or std::tr1 */ -#if defined(RCPP_USING_CXX11) || defined(HAS_TR1) -namespace std -{ -#ifndef RCPP_USING_CXX11 -namespace tr1 { -#endif +/** hash via std */ +namespace std { template <> - struct hash - { + struct hash { size_t operator()(const Rcpp::String & s) const{ return hash()(s.get_cstring()); } }; -#ifndef RCPP_USING_CXX11 -} -#endif } -#endif #endif diff --git a/inst/include/Rcpp/config.h b/inst/include/Rcpp/config.h index 639a46204..7c3288061 100644 --- a/inst/include/Rcpp/config.h +++ b/inst/include/Rcpp/config.h @@ -30,7 +30,7 @@ #define RCPP_VERSION_STRING "1.0.14" // the current source snapshot (using four components, if a fifth is used in DESCRIPTION we ignore it) -#define RCPP_DEV_VERSION RcppDevVersion(1,0,14,6) -#define RCPP_DEV_VERSION_STRING "1.0.14.6" +#define RCPP_DEV_VERSION RcppDevVersion(1,0,14,7) +#define RCPP_DEV_VERSION_STRING "1.0.14.7" #endif diff --git a/inst/include/Rcpp/internal/wrap.h b/inst/include/Rcpp/internal/wrap.h index 50faa1d86..92ad009eb 100644 --- a/inst/include/Rcpp/internal/wrap.h +++ b/inst/include/Rcpp/internal/wrap.h @@ -522,18 +522,12 @@ namespace Rcpp { * quite a cryptic message */ template - inline SEXP wrap_dispatch_unknown_iterable(const T& object, ::Rcpp::traits::false_type) { - RCPP_DEBUG_1("wrap_dispatch_unknown_iterable<%s>(., false )", DEMANGLE(T)) - // here we know that T is not convertible to SEXP - #ifdef HAS_STATIC_ASSERT - static_assert(!sizeof(T), "cannot convert type to SEXP"); - #else - // leave the cryptic message - SEXP x = object; - return x; - #endif - return R_NilValue; // -Wall - } + inline SEXP wrap_dispatch_unknown_iterable(const T& object, ::Rcpp::traits::false_type) { + RCPP_DEBUG_1("wrap_dispatch_unknown_iterable<%s>(., false )", DEMANGLE(T)) + // here we know that T is not convertible to SEXP + static_assert(!sizeof(T), "cannot convert type to SEXP"); + return R_NilValue; // -Wall + } template inline SEXP wrap_dispatch_unknown_iterable__logical(const T& object, ::Rcpp::traits::true_type) { @@ -936,7 +930,7 @@ namespace Rcpp { if (v != NULL) return Rf_mkString(v); else - return R_NilValue; // #nocov + return R_NilValue; // #nocov } /** diff --git a/inst/include/Rcpp/platform/compiler.h b/inst/include/Rcpp/platform/compiler.h index bf60b189d..0248a9116 100644 --- a/inst/include/Rcpp/platform/compiler.h +++ b/inst/include/Rcpp/platform/compiler.h @@ -1,8 +1,6 @@ -// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*- -// // compiler.h: Rcpp R/C++ interface class library -- check compiler // -// Copyright (C) 2012 - 2013 Dirk Eddelbuettel, Romain Francois, and Kevin Ushey +// Copyright (C) 2012 - 2025 Dirk Eddelbuettel, Romain Francois, and Kevin Ushey // // This file is part of Rcpp. // @@ -24,173 +22,30 @@ // NB: A vast list valid identifiers is at these wiki pages: // http://sourceforge.net/p/predef/wiki/Home/ - -#undef GOOD_COMPILER_FOR_RCPP -#ifdef __GNUC__ -#define GOOD_COMPILER_FOR_RCPP -#endif -#ifdef __SUNPRO_CC -#define GOOD_COMPILER_FOR_RCPP -#endif -#ifdef __clang__ -#define GOOD_COMPILER_FOR_RCPP -#endif -#ifdef __INTEL_COMPILER -#define GOOD_COMPILER_FOR_RCPP -#endif - -#ifndef GOOD_COMPILER_FOR_RCPP -# error "This compiler is not supported" -#endif - -#ifdef __GNUC__ - #define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) - // g++ 4.5 does not seem to like some of the fast indexing - #if GCC_VERSION >= 40500 - #define IS_GCC_450_OR_LATER - #endif - // g++ 4.6 switches from exception_defines.h to bits/exception_defines.h - #if GCC_VERSION < 40600 - #define IS_EARLIER_THAN_GCC_460 - #endif - #if GCC_VERSION >= 40600 - #define IS_GCC_460_OR_LATER - #endif -#endif - -// Check for the presence of C++0x (or later) support -#if defined(__GXX_EXPERIMENTAL_CXX0X__) || (__cplusplus >= 201103L) - #define RCPP_USING_CXX0X_OR_LATER +#if !defined(__GNUC__) && !defined(__SUNPRO_CC) && !defined(__clang__) && !defined(__INTEL_COMPILER) +#error "This compiler is not supported" #endif -// Check C++0x/11 features -#if defined(__INTEL_COMPILER) - #if __cplusplus >= 201103L - #define RCPP_USING_CXX11 - #if __INTEL_COMPILER >= 1210 - #define HAS_VARIADIC_TEMPLATES - #endif - #if __INTEL_COMPILER >= 1100 - #define HAS_STATIC_ASSERT - #endif - #endif -#elif defined(__clang__) - #if __cplusplus >= 201103L - #define RCPP_USING_CXX11 - #if __has_feature(cxx_variadic_templates) - #define HAS_VARIADIC_TEMPLATES - #endif - #if __has_feature(cxx_static_assert) - #define HAS_STATIC_ASSERT - #endif - #endif -#elif defined(__GNUC__) - #ifdef __GXX_EXPERIMENTAL_CXX0X__ - #if GCC_VERSION >= 40300 - #define HAS_VARIADIC_TEMPLATES - #define HAS_STATIC_ASSERT - #endif - #endif - #if GCC_VERSION >= 40800 && __cplusplus >= 201103L - #define RCPP_USING_CXX11 - #endif +// Simpler test and minimal standard: C++11 or else we die +#if __cplusplus < 201103L +#error "The C++ compilation standard is too old: use C++11 or newer." #endif -// Check C++0x headers +// C++11 features -- that used to be carefully tested for or worked around via CXX0X / TR1 +// These defines are all planned to get removed just how a number have already been removed. One at a time... +#define RCPP_USING_CXX11 +#define HAS_VARIADIC_TEMPLATES #include -#if defined(__INTEL_COMPILER) || (defined(__GNUC__) && !defined(__clang__)) - #if defined(__GLIBCXX__) && defined(__GXX_EXPERIMENTAL_CXX0X__) - #if GCC_VERSION >= 40400 - #define HAS_CXX0X_UNORDERED_MAP - #define HAS_CXX0X_UNORDERED_SET - #define HAS_CXX0X_INITIALIZER_LIST - #endif - #endif -#elif defined(__clang__) - #if __cplusplus >= 201103L - #if __has_include() - #define HAS_CXX0X_UNORDERED_MAP - #endif - #if __has_include() - #define HAS_CXX0X_UNORDERED_SET - #endif - #if __has_include() - #define HAS_CXX0X_INITIALIZER_LIST - #endif - #endif -#endif - -// Check TR1 Headers -#if defined(__INTEL_COMPILER) || (defined(__GNUC__) && !defined(__clang__)) - #if defined(__GLIBCXX__) - #if GCC_VERSION >= 40400 || ( GCC_VERSION >= 40201 && defined(__APPLE__) ) - #define HAS_TR1_UNORDERED_MAP - #define HAS_TR1_UNORDERED_SET - #endif - #endif -#elif defined(__clang__) - #if __cplusplus >= 201103L - #if __has_include() - #define HAS_TR1_UNORDERED_MAP - #endif - #if __has_include() - #define HAS_TR1_UNORDERED_SET - #endif - #endif -#endif - -#if defined(HAS_TR1_UNORDERED_MAP) && defined(HAS_TR1_UNORDERED_SET) -#define HAS_TR1 -#endif - -// Conditionally include headers -#ifdef HAS_CXX0X_INITIALIZER_LIST #include -#endif - -#ifdef RCPP_USING_CXX11 - #if defined(HAS_CXX0X_UNORDERED_MAP) - #include - #define RCPP_USING_UNORDERED_MAP - #define RCPP_UNORDERED_MAP std::unordered_map - #else - #include - #define RCPP_USING_MAP - #define RCPP_UNORDERED_MAP std::map - #endif - #if defined(HAS_CXX0X_UNORDERED_SET) - #include - #define RCPP_USING_UNORDERED_SET - #define RCPP_UNORDERED_SET std::unordered_set - #else - #include - #define RCPP_USING_SET - #define RCPP_UNORDERED_SET std::set - #endif -#else - #if defined(HAS_TR1_UNORDERED_MAP) - #include - #define RCPP_USING_TR1_UNORDERED_MAP - #define RCPP_UNORDERED_MAP std::tr1::unordered_map - #else - #include - #define RCPP_USING_MAP - #define RCPP_UNORDERED_MAP std::map - #endif - #if defined(HAS_TR1_UNORDERED_SET) - #include - #define RCPP_USING_TR1_UNORDERED_SET - #define RCPP_UNORDERED_SET std::tr1::unordered_set - #else - #include - #define RCPP_USING_SET - #define RCPP_UNORDERED_SET std::set - #endif -#endif - -#ifdef __GNUC__ +#include +#define RCPP_USING_UNORDERED_MAP +#define RCPP_UNORDERED_MAP std::unordered_map +#include +#define RCPP_USING_UNORDERED_SET +#define RCPP_UNORDERED_SET std::unordered_set + +#if defined(__GNUC__) #define RCPP_HAS_DEMANGLING #endif - #endif diff --git a/inst/include/Rcpp/sugar/functions/sapply.h b/inst/include/Rcpp/sugar/functions/sapply.h index 49ed29a3e..f5ee94449 100644 --- a/inst/include/Rcpp/sugar/functions/sapply.h +++ b/inst/include/Rcpp/sugar/functions/sapply.h @@ -21,9 +21,8 @@ #ifndef Rcpp__sugar__sapply_h #define Rcpp__sugar__sapply_h -#if defined(RCPP_USING_CXX0X_OR_LATER) - #include // ::std::result_of -#endif +// This used to be conditional on a define and test in compiler.h +#include // ::std::result_of namespace Rcpp{ namespace sugar{ @@ -31,7 +30,7 @@ namespace sugar{ template struct sapply_application_result_of { -#if defined(RCPP_USING_CXX0X_OR_LATER) +#if __cplusplus >= 201103L #if __cplusplus < 201703L // deprecated by C++17, removed by C++2020, see https://en.cppreference.com/w/cpp/types/result_of typedef typename ::std::result_of::type type; @@ -40,9 +39,10 @@ struct sapply_application_result_of typedef typename ::std::invoke_result::type type; #endif #else + // TODO this else branch can likely go typedef typename ::Rcpp::traits::result_of::type type; #endif -} ; +}; // template // using sapply_application_result_of_t = typename sapply_application_result_of::type; diff --git a/inst/include/Rcpp/sugar/functions/table.h b/inst/include/Rcpp/sugar/functions/table.h index 2cd647ca5..74cb01b20 100644 --- a/inst/include/Rcpp/sugar/functions/table.h +++ b/inst/include/Rcpp/sugar/functions/table.h @@ -1,8 +1,6 @@ -// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 8 -*- -// // table.h: Rcpp R/C++ interface class library -- table match // -// Copyright (C) 2012 - 2013 Dirk Eddelbuettel, Romain Francois, and Kevin Ushey +// Copyright (C) 2012 - 2025 Dirk Eddelbuettel, Romain Francois, and Kevin Ushey // // This file is part of Rcpp. // @@ -55,36 +53,6 @@ class Grabber{ R_xlen_t index ; } ; -// we define a different Table class depending on whether we are using -// std::map or not -#ifdef RCPP_USING_MAP - -template -class Table { -public: - typedef typename Rcpp::traits::storage_type::type STORAGE ; - - Table( const TABLE_T& table ): hash() { - std::for_each( table.begin(), table.end(), Inserter(hash) ) ; - } - - inline operator IntegerVector() const { - R_xlen_t n = hash.size() ; - IntegerVector result = no_init(n) ; - CharacterVector names = no_init(n) ; - std::for_each( hash.begin(), hash.end(), Grabber(result, names) ) ; - result.names() = names ; - return result ; - } - -private: - typedef RCPP_UNORDERED_MAP >HASH ; - typedef CountInserter Inserter ; - HASH hash ; -}; - -#else - template class Table { public: @@ -118,8 +86,6 @@ class Table { }; -#endif // USING_RCPP_MAP - } // sugar template @@ -130,4 +96,3 @@ inline IntegerVector table( const VectorBase& x ){ } // Rcpp #endif - diff --git a/inst/include/Rcpp/sugar/sets.h b/inst/include/Rcpp/sugar/sets.h index fa432bfd1..e1aaaec2e 100644 --- a/inst/include/Rcpp/sugar/sets.h +++ b/inst/include/Rcpp/sugar/sets.h @@ -1,8 +1,6 @@ -// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 8 -*- -// // sets.h: Rcpp R/C++ interface class library -- // -// Copyright (C) 2012 Dirk Eddelbuettel and Romain Francois +// Copyright (C) 2012 - 2025 Dirk Eddelbuettel and Romain Francois // // This file is part of Rcpp. // @@ -22,40 +20,17 @@ #ifndef Rcpp__sugar__sets_h #define Rcpp__sugar__sets_h -#if __cplusplus >= 201103L - #define RCPP_UNORDERED_SET std::unordered_set - #define RCPP_UNORDERED_MAP std::unordered_map - - namespace std { - template<> - struct hash { - std::size_t operator()(const Rcpp::String& key) const { - return pointer_hasher( key.get_sexp() ) ; - } - hash pointer_hasher ; - }; - } - -#elif defined(HAS_TR1_UNORDERED_SET) - #define RCPP_UNORDERED_SET std::tr1::unordered_set - #define RCPP_UNORDERED_MAP std::tr1::unordered_map +#define RCPP_UNORDERED_SET std::unordered_set +#define RCPP_UNORDERED_MAP std::unordered_map - namespace std { - namespace tr1 { - template<> - struct hash { - std::size_t operator()(const Rcpp::String& key) const { - return pointer_hasher( key.get_sexp() ) ; - } - hash pointer_hasher ; - }; +namespace std { + template<> + struct hash { + std::size_t operator()(const Rcpp::String& key) const { + return pointer_hasher( key.get_sexp() ) ; } - } - - -#else - #define RCPP_UNORDERED_SET std::set - #define RCPP_UNORDERED_MAP std::map -#endif + hash pointer_hasher ; + }; +} #endif diff --git a/inst/include/Rcpp/vector/Vector.h b/inst/include/Rcpp/vector/Vector.h index bd9b5ba80..3feb8995c 100644 --- a/inst/include/Rcpp/vector/Vector.h +++ b/inst/include/Rcpp/vector/Vector.h @@ -236,11 +236,9 @@ class Vector : std::transform( first, last, begin(), func) ; } -#ifdef HAS_CXX0X_INITIALIZER_LIST Vector( std::initializer_list list ) { assign( list.begin() , list.end() ) ; } -#endif template Vector& operator=( const T& x) { diff --git a/man/evalCpp.Rd b/man/evalCpp.Rd index d3285f6ad..49ce082e7 100644 --- a/man/evalCpp.Rd +++ b/man/evalCpp.Rd @@ -5,16 +5,16 @@ Evaluate a C++ Expression } \description{ -Evaluates a C++ expression. This creates a C++ function using -\code{\link{cppFunction}} and calls it to get the result. +Evaluates a C++ expression. This creates a C++ function using +\code{\link{cppFunction}} and calls it to get the result. } \usage{ -evalCpp(code, depends = character(), plugins = character(), includes = character(), +evalCpp(code, depends = character(), plugins = character(), includes = character(), rebuild = FALSE, cacheDir = getOption("rcpp.cache.dir", tempdir()), showOutput = verbose, verbose = getOption("verbose")) -areMacrosDefined(names, depends = character(), includes = character(), - rebuild = FALSE, showOutput = verbose, +areMacrosDefined(names, depends = character(), includes = character(), + rebuild = FALSE, showOutput = verbose, verbose = getOption("verbose")) } \arguments{ @@ -47,10 +47,10 @@ see \code{\link{cppFunction}} } } \note{ - The result type of the C++ expression must be compatible with \code{Rcpp::wrap}. + The result type of the C++ expression must be compatible with \code{Rcpp::wrap}. } \value{ - The result of the evaluated C++ expression. + The result of the evaluated C++ expression. } \seealso{ \code{\link{sourceCpp}}, \code{\link{cppFunction}} @@ -58,10 +58,11 @@ see \code{\link{cppFunction}} \examples{ \dontrun{ -evalCpp( "__cplusplus" ) -evalCpp( "std::numeric_limits::max()" ) - -areMacrosDefined( c("__cplusplus", "HAS_TR1" ) ) +evalCpp("__cplusplus") +evalCpp("std::numeric_limits::max()") + +# areMacrosDefined is no longer exported but accessible via ':::' +Rcpp:::areMacrosDefined(c("__cplusplus", "RCPP_VERSION")) } } diff --git a/src/api.cpp b/src/api.cpp index 62c1773f6..dbd02cd4d 100644 --- a/src/api.cpp +++ b/src/api.cpp @@ -171,32 +171,12 @@ SEXP as_character_externalptr(SEXP xp) { SEXP rcpp_capabilities() { Shield cap(Rf_allocVector(LGLSXP, 13)); Shield names(Rf_allocVector(STRSXP, 13)); - #ifdef HAS_VARIADIC_TEMPLATES - LOGICAL(cap)[0] = TRUE; - #else - LOGICAL(cap)[0] = FALSE; - #endif - #ifdef HAS_CXX0X_INITIALIZER_LIST - LOGICAL(cap)[1] = TRUE; - #else - LOGICAL(cap)[1] = FALSE; - #endif - /* exceptions are always supported */ - LOGICAL(cap)[2] = TRUE; - - #ifdef HAS_TR1_UNORDERED_MAP - LOGICAL(cap)[3] = TRUE; - #else - LOGICAL(cap)[3] = FALSE; - #endif - - #ifdef HAS_TR1_UNORDERED_SET - LOGICAL(cap)[4] = TRUE; - #else - LOGICAL(cap)[4] = FALSE; - #endif - - LOGICAL(cap)[5] = TRUE; + LOGICAL(cap)[0] = TRUE; // HAS_VARIADIC_TEMPLATES + LOGICAL(cap)[1] = TRUE; // HAS_CXX0X_INITIALIZER_LIST + LOGICAL(cap)[2] = TRUE; /* exceptions are always supported */ + LOGICAL(cap)[3] = TRUE; // HAS_TR1_UNORDERED_MAP + LOGICAL(cap)[4] = TRUE; // HAS_TR1_UNORDERED_SET + LOGICAL(cap)[5] = TRUE; // Modules (TODO respect header choice ?) #ifdef RCPP_HAS_DEMANGLING LOGICAL(cap)[6] = TRUE; @@ -204,7 +184,7 @@ SEXP rcpp_capabilities() { LOGICAL(cap)[6] = FALSE; #endif - LOGICAL(cap)[7] = FALSE; + LOGICAL(cap)[7] = FALSE; // Classic API #ifdef RCPP_HAS_LONG_LONG_TYPES LOGICAL(cap)[8] = TRUE; @@ -212,23 +192,9 @@ SEXP rcpp_capabilities() { LOGICAL(cap)[8] = FALSE; #endif - #ifdef HAS_CXX0X_UNORDERED_MAP - LOGICAL(cap)[9] = TRUE; - #else - LOGICAL(cap)[9] = FALSE; - #endif - - #ifdef HAS_CXX0X_UNORDERED_SET - LOGICAL(cap)[10] = TRUE; - #else - LOGICAL(cap)[10] = FALSE; - #endif - - #ifdef RCPP_USING_CXX11 - LOGICAL(cap)[11] = TRUE; - #else - LOGICAL(cap)[11] = FALSE; - #endif + LOGICAL(cap)[9] = TRUE; // HAS_CXX0X_UNORDERED_MAP + LOGICAL(cap)[10] = TRUE; // HAS_CXX0X_UNORDERED_SET + LOGICAL(cap)[11] = TRUE; // RCPP_USING_CXX11 #ifdef RCPP_NEW_DATE_DATETIME_VECTORS LOGICAL(cap)[12] = TRUE;