diff --git a/.evergreen/abi-compliance-check-test.sh b/.evergreen/abi-compliance-check-test.sh index d359840b89..8837e5cf00 100755 --- a/.evergreen/abi-compliance-check-test.sh +++ b/.evergreen/abi-compliance-check-test.sh @@ -22,20 +22,13 @@ command -V abi-compliance-checker >/dev/null mkdir cxx-abi cxx-noabi -cat >cxx-abi/old.xml <old.xml < ${old_ver:?} - - ../install/old/include/bsoncxx/ - ../install/old/include/mongocxx/ - - - - /v_noabi/ - - ../install/old/lib @@ -44,26 +37,13 @@ cat >cxx-abi/old.xml < - - bsoncxx/enums/ - /config/ - DOC -cat >cxx-abi/new.xml <new.xml < ${new_ver:?} - - ../install/new/include/mongocxx/ - ../install/new/include/bsoncxx/ - - - - /v_noabi/ - - ../install/new/lib @@ -72,59 +52,67 @@ cat >cxx-abi/new.xml < +DOC + + { + cat < - bsoncxx/enums/ - /config/ + bsoncxx/v_noabi/bsoncxx/enums/ + bsoncxx/v_noabi/bsoncxx/config/ + + + bsoncxx::detail + bsoncxx::v_noabi::detail + bsoncxx::v_noabi::stdx::detail + + DOC + } | tee -a old.xml new.xml >/dev/null -cat >cxx-noabi/old.xml < - ${old_ver:?} - + cat old.xml | tee cxx-abi/old.xml cxx-noabi/old.xml >/dev/null + cat new.xml | tee cxx-abi/new.xml cxx-noabi/new.xml >/dev/null + rm old.xml new.xml +fi +# Append sections specific to each ABI test. +if true; then + cat >>cxx-abi/old.xml < + ../install/old/include/bsoncxx/ + ../install/old/include/mongocxx/ + + + + /v_noabi/ + +DOC + + cat >>cxx-noabi/old.xml < ../install/old/include/bsoncxx/v_noabi ../install/old/include/mongocxx/v_noabi +DOC - - ../install/old/lib - - - - ../install/old/include/ - + cat >>cxx-abi/new.xml < + ../install/new/include/mongocxx/ + ../install/new/include/bsoncxx/ + - - bsoncxx/enums/ - /config/ - + + /v_noabi/ + DOC -cat >cxx-noabi/new.xml < - ${new_ver:?} - - + cat >>cxx-noabi/new.xml < ../install/new/include/bsoncxx/v_noabi ../install/new/include/mongocxx/v_noabi - - - ../install/new/lib - - - - ../install/new/include/ - - - - bsoncxx/enums/ - /config/ - DOC +fi # Allow task to upload the HTML report despite failed status. echo "Generating stable ABI report..." diff --git a/.evergreen/abidiff-test.sh b/.evergreen/abidiff-test.sh index bac301f3c2..cc4ea1de2b 100755 --- a/.evergreen/abidiff-test.sh +++ b/.evergreen/abidiff-test.sh @@ -10,15 +10,15 @@ export PATH PATH="${working_dir:?}/install/bin:${PATH:-}" declare -a common_flags -flags=( +common_flags=( --headers-dir1 install/old/include --headers-dir2 install/new/include - --non-reachable-types - --fail-no-debug-info + --fail-no-debug-info # Ensure debug info is present for our libs. + --no-unreferenced-symbols # Not interested in symbols not owned by our libs. ) -declare -a abi_flags=("${common_flags[@]}" --suppressions cxx-abi/abignore) -declare -a noabi_flags=("${common_flags[@]}" --suppressions cxx-noabi/abignore) +declare -a abi_flags=("${common_flags[@]:?}" --suppressions cxx-abi/abignore) +declare -a noabi_flags=("${common_flags[@]:?}" --suppressions cxx-noabi/abignore) command -V abidiff >/dev/null @@ -37,18 +37,24 @@ DOC cat >cxx-noabi/abignore <>cxx-abi/bsoncxx.txt +echo "---" >>cxx-abi/mongocxx.txt +echo "---" >>cxx-noabi/bsoncxx.txt +echo "---" >>cxx-noabi/mongocxx.txt + # Allow task to upload the diff reports despite failed status. echo "Comparing stable ABI for bsoncxx..." -if ! abidiff "${abi_flags[@]}" install/old/lib/libbsoncxx.so install/new/lib/libbsoncxx.so &>cxx-abi/bsoncxx.txt; then +if ! abidiff "${abi_flags[@]:?}" install/old/lib/libbsoncxx.so install/new/lib/libbsoncxx.so >>cxx-abi/bsoncxx.txt; then declare status status='{"status":"failed", "type":"test", "should_continue":true, "desc":"abidiff returned an error for bsoncxx (stable)"}' curl -sS -d "${status:?}" -H "Content-Type: application/json" -X POST localhost:2285/task_status || true @@ -57,7 +63,7 @@ echo "Comparing stable ABI for bsoncxx... done." # Allow task to upload the diff reports despite failed status. echo "Comparing stable ABI for mongocxx..." -if ! abidiff "${abi_flags[@]}" install/old/lib/libmongocxx.so install/new/lib/libmongocxx.so &>cxx-abi/mongocxx.txt; then +if ! abidiff "${abi_flags[@]:?}" install/old/lib/libmongocxx.so install/new/lib/libmongocxx.so >>cxx-abi/mongocxx.txt; then declare status status='{"status":"failed", "type":"test", "should_continue":true, "desc":"abidiff returned an error for mongocxx (stable)"}' curl -sS -d "${status:?}" -H "Content-Type: application/json" -X POST localhost:2285/task_status || true @@ -65,15 +71,15 @@ fi echo "Comparing stable ABI for mongocxx... done." echo "Comparing unstable ABI for bsoncxx..." -abidiff "${noabi_flags[@]}" install/old/lib/libbsoncxx.so install/new/lib/libbsoncxx.so &>cxx-noabi/bsoncxx.txt || true +abidiff "${noabi_flags[@]:?}" install/old/lib/libbsoncxx.so install/new/lib/libbsoncxx.so >>cxx-noabi/bsoncxx.txt || true echo "Comparing unstable ABI for bsoncxx... done." echo "Comparing unstable ABI for mongocxx..." -abidiff "${noabi_flags[@]}" install/old/lib/libmongocxx.so install/new/lib/libmongocxx.so &>cxx-noabi/mongocxx.txt || true +abidiff "${noabi_flags[@]:?}" install/old/lib/libmongocxx.so install/new/lib/libmongocxx.so >>cxx-noabi/mongocxx.txt || true echo "Comparing unstable ABI for mongocxx... done." # Ensure files have content even when abidiff produces no output. -printf "\n" >>cxx-abi/bsoncxx.txt -printf "\n" >>cxx-abi/mongocxx.txt -printf "\n" >>cxx-noabi/bsoncxx.txt -printf "\n" >>cxx-noabi/mongocxx.txt +echo "---" >>cxx-abi/bsoncxx.txt +echo "---" >>cxx-abi/mongocxx.txt +echo "---" >>cxx-noabi/bsoncxx.txt +echo "---" >>cxx-noabi/mongocxx.txt diff --git a/.evergreen/compile.sh b/.evergreen/compile.sh index 96a9d6cd40..0753bdcce1 100755 --- a/.evergreen/compile.sh +++ b/.evergreen/compile.sh @@ -69,14 +69,13 @@ export CMAKE_BUILD_PARALLEL_LEVEL if command -V ccache 2>/dev/null; then export CMAKE_CXX_COMPILER_LAUNCHER=ccache - - # Allow reuse of ccache compilation results between different build directories. - export CCACHE_BASEDIR CCACHE_NOHASHDIR - CCACHE_BASEDIR="$(pwd)" - CCACHE_NOHASHDIR=1 # Allow reuse of ccache compilation results between different build directories. export CCACHE_BASEDIR CCACHE_NOHASHDIR - CCACHE_BASEDIR="$(pwd)" + if [[ "${OSTYPE:?}" == "cygwin" ]]; then + CCACHE_BASEDIR="$(cygpath -aw "$(pwd)")" + else + CCACHE_BASEDIR="$(pwd)" + fi CCACHE_NOHASHDIR=1 fi @@ -116,7 +115,7 @@ case "${OSTYPE:?}" in cygwin) case "${generator:-}" in *2015*) cmake_flags+=("-DBOOST_ROOT=C:/local/boost_1_60_0") ;; - *2017*|*2019*) cmake_flags+=("-DCMAKE_CXX_STANDARD=17") ;; + *2017* | *2019*) cmake_flags+=("-DCMAKE_CXX_STANDARD=17") ;; *) echo "missing explicit CMake Generator on Windows distro" 1>&2 exit 1 diff --git a/.mci.yml b/.mci.yml index 45b05adb5e..1c0eb58057 100644 --- a/.mci.yml +++ b/.mci.yml @@ -952,7 +952,11 @@ tasks: # Allow reuse of ccache compilation results between different build directories. export CCACHE_BASEDIR CCACHE_NOHASHDIR - CCACHE_BASEDIR="$(pwd)" + if [[ "${OSTYPE:?}" == "cygwin" ]]; then + CCACHE_BASEDIR="$(cygpath -aw "$(pwd)")" + else + CCACHE_BASEDIR="$(pwd)" + fi CCACHE_NOHASHDIR=1 fi command -v "$cmake_binary" diff --git a/CHANGELOG.md b/CHANGELOG.md index f9107bfb1f..03c5ed499d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ Changes prior to 3.9.0 are documented as [release notes on GitHub](https://githu - Forward headers providing non-defining declarations of bsoncxx and mongocxx class types. - Note: user-defined forward declarations of any library entity has not been, and is still not, supported. To obtain the declaration or definition of a library entity, always include the corresponding header. +- The CMake option `ENABLE_BSONCXX_USE_POLY_IMPLS` (OFF by default) allows selecting bsoncxx implementations of C++17 polyfills by default when no polyfill library is requested. +- The CMake option `BSONCXX_POLY_USE_IMPLS` (OFF by default) allows selecting bsoncxx implementations of C++17 polyfills instead of external libraries or the C++ standard library. ### Changed diff --git a/CMakeLists.txt b/CMakeLists.txt index b0084b4285..6d6e7877df 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,9 +20,7 @@ endif() project(MONGO_CXX_DRIVER LANGUAGES CXX) -if(NOT DEFINED BUILD_TESTING) - set(BUILD_TESTING OFF) # Set this to OFF by default -endif() +option(BUILD_TESTING "Include test targets in the \"all\" target") if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.8.2") @@ -157,6 +155,9 @@ option(BUILD_SHARED_LIBS_WITH_STATIC_MONGOC OFF ) +# Allow the user to opt into using bsoncxx implementations for C++17 polyfills by default. +option(ENABLE_BSONCXX_POLY_USE_IMPLS "Enable using bsoncxx implementations of C++17 polyfills for pre-C++17 configurations by default" OFF) + if(DEFINED CACHE{ENABLE_ABI_TAG_IN_LIBRARY_FILENAMES} AND NOT MSVC) message(WARNING "ENABLE_ABI_TAG_IN_LIBRARY_FILENAMES is an MSVC-only option and will be ignored by the current configuration") unset(ENABLE_ABI_TAG_IN_LIBRARY_FILENAMES CACHE) @@ -475,6 +476,10 @@ if(NOT(TARGET dist OR TARGET distcheck)) list(APPEND polyfill_flags "-DBSONCXX_POLY_USE_BOOST=${BSONCXX_POLY_USE_BOOST}") endif() + if(NOT "${BSONCXX_POLY_USE_IMPLS}" STREQUAL "") + list(APPEND polyfill_flags "-DBSONCXX_POLY_USE_IMPLS=${BSONCXX_POLY_USE_IMPLS}") + endif() + if(NOT "${BSONCXX_POLY_USE_STD}" STREQUAL "") list(APPEND polyfill_flags "-DBSONCXX_POLY_USE_STD=${BSONCXX_POLY_USE_STD}") endif() diff --git a/cmake/BsoncxxUtil.cmake b/cmake/BsoncxxUtil.cmake index e4f2a27467..a1d9ab6b5f 100644 --- a/cmake/BsoncxxUtil.cmake +++ b/cmake/BsoncxxUtil.cmake @@ -62,7 +62,7 @@ function(bsoncxx_add_library TARGET OUTPUT_NAME LINK_TYPE) set(polyfill "m") elseif(BSONCXX_POLY_USE_BOOST) set(polyfill "b") - elseif(0) # CXX-2796: reserved for bsoncxx implementations as polyfill. + elseif(BSONCXX_POLY_USE_IMPLS) set(polyfill "i") elseif(BSONCXX_POLY_USE_STD) set(polyfill "s") diff --git a/cmake/make_dist/MakeDistCheck.cmake b/cmake/make_dist/MakeDistCheck.cmake index 08fcd19c2d..8021d1246a 100644 --- a/cmake/make_dist/MakeDistCheck.cmake +++ b/cmake/make_dist/MakeDistCheck.cmake @@ -1,22 +1,23 @@ -include (MakeDistFiles) +include(MakeDistFiles) -function (RUN_DIST_CHECK PACKAGE_PREFIX EXT) +function(RUN_DIST_CHECK PACKAGE_PREFIX EXT) + set(tarball ${PACKAGE_PREFIX}.tar${EXT}) - set (tarball ${PACKAGE_PREFIX}.tar${EXT}) - if (NOT EXISTS ${tarball}) - message (FATAL_ERROR "Can't find dist tarball '${tarball}'") - endif () + if(NOT EXISTS ${tarball}) + message(FATAL_ERROR "Can't find dist tarball '${tarball}'") + endif() # Remove the directory to which we're about to extract - file (REMOVE_RECURSE ${PACKAGE_PREFIX}) + file(REMOVE_RECURSE ${PACKAGE_PREFIX}) # Untar the distribution we want to check - set (TAR_OPTION "zxf") - if (${EXT} STREQUAL ".bz2") - set (TAR_OPTION "jxf") - endif () + set(TAR_OPTION "zxf") + + if(${EXT} STREQUAL ".bz2") + set(TAR_OPTION "jxf") + endif() - execute_process_and_check_result ( + execute_process_and_check_result( COMMAND ${CMAKE_COMMAND} -E tar ${TAR_OPTION} ${tarball} WORKING_DIRECTORY . ERROR_MSG "Command to untar ${tarball} failed." @@ -27,40 +28,50 @@ function (RUN_DIST_CHECK PACKAGE_PREFIX EXT) message (FATAL_ERROR "Expected tarball to contain a `build/VERSION_CURRENT` file, but it does not") endif () - set (BUILD_DIR "_cmake_build") - set (INSTALL_DIR "_cmake_install") - file (REMOVE_RECURSE ${BUILD_DIR} ${INSTALL_DIR}) + set(BUILD_DIR "_cmake_build") + set(INSTALL_DIR "_cmake_install") + file(REMOVE_RECURSE ${BUILD_DIR} ${INSTALL_DIR}) - file (MAKE_DIRECTORY ${BUILD_DIR} ${INSTALL_DIR}) + file(MAKE_DIRECTORY ${BUILD_DIR} ${INSTALL_DIR}) # Ensure distcheck inherits polyfill library selection. set(polyfill_flags "") - if (NOT "${CMAKE_CXX_STANDARD}" STREQUAL "") + + if(NOT "${CMAKE_CXX_STANDARD}" STREQUAL "") list(APPEND polyfill_flags "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}") - endif () - if (NOT "${BOOST_ROOT}" STREQUAL "") + endif() + + if(NOT "${BOOST_ROOT}" STREQUAL "") list(APPEND polyfill_flags "-DBOOST_ROOT=${BOOST_ROOT}") - endif () - if (NOT "${BSONCXX_POLY_USE_MNMLSTC}" STREQUAL "") + endif() + + if(NOT "${BSONCXX_POLY_USE_MNMLSTC}" STREQUAL "") list(APPEND polyfill_flags "-DBSONCXX_POLY_USE_MNMLSTC=${BSONCXX_POLY_USE_MNMLSTC}") endif() - if (NOT "${BSONCXX_POLY_USE_SYSTEM_MNMLSTC}" STREQUAL "") + + if(NOT "${BSONCXX_POLY_USE_SYSTEM_MNMLSTC}" STREQUAL "") list(APPEND polyfill_flags "-DBSONCXX_POLY_USE_SYSTEM_MNMLSTC=${BSONCXX_POLY_USE_SYSTEM_MNMLSTC}") endif() - if (NOT "${BSONCXX_POLY_USE_BOOST}" STREQUAL "") + + if(NOT "${BSONCXX_POLY_USE_BOOST}" STREQUAL "") list(APPEND polyfill_flags "-DBSONCXX_POLY_USE_BOOST=${BSONCXX_POLY_USE_BOOST}") endif() - if (NOT "${BSONCXX_POLY_USE_STD}" STREQUAL "") + + if(NOT "${BSONCXX_POLY_USE_IMPLS}" STREQUAL "") + list(APPEND polyfill_flags "-DBSONCXX_POLY_USE_IMPLS=${BSONCXX_POLY_USE_IMPLS}") + endif() + + if(NOT "${BSONCXX_POLY_USE_STD}" STREQUAL "") list(APPEND polyfill_flags "-DBSONCXX_POLY_USE_STD=${BSONCXX_POLY_USE_STD}") endif() - execute_process_and_check_result ( + execute_process_and_check_result( COMMAND ${CMAKE_COMMAND} -E echo "Configuring distcheck with CMake flags: ${polyfill_flags}" WORKING_DIRECTORY . ERROR_MSG "Failed to echo polyfill flags" ) - execute_process_and_check_result ( + execute_process_and_check_result( COMMAND ${CMAKE_COMMAND} -S ../${PACKAGE_PREFIX} -B . @@ -75,29 +86,28 @@ function (RUN_DIST_CHECK PACKAGE_PREFIX EXT) ) # Run make in the build directory - separate_arguments (build_opts) - execute_process_and_check_result ( + separate_arguments(build_opts) + execute_process_and_check_result( COMMAND ${CMAKE_COMMAND} --build . WORKING_DIRECTORY ${BUILD_DIR} ERROR_MSG "Make build failed." ) # Run make install - execute_process_and_check_result ( + execute_process_and_check_result( COMMAND ${CMAKE_COMMAND} --build . --target install WORKING_DIRECTORY ${BUILD_DIR} ERROR_MSG "Make install failed." ) # Run make dist - execute_process_and_check_result ( + execute_process_and_check_result( COMMAND ${CMAKE_COMMAND} --build . --target dist WORKING_DIRECTORY ${BUILD_DIR} ERROR_MSG "Make dist failed." ) - message ("distcheck complete.") - -endfunction () + message("distcheck complete.") +endfunction() -run_dist_check (${PACKAGE_PREFIX} .gz) +run_dist_check(${PACKAGE_PREFIX} .gz) diff --git a/docs/content/mongocxx-v3/api-abi-versioning.md b/docs/content/mongocxx-v3/api-abi-versioning.md index c67f871a8f..9206193516 100644 --- a/docs/content/mongocxx-v3/api-abi-versioning.md +++ b/docs/content/mongocxx-v3/api-abi-versioning.md @@ -49,11 +49,12 @@ followed by a suffix describing the toolset and runtime library used to build th Some examples of common DSO filenames expected to be generated include: -* mongocxx-v_noabi-rhs-x64-v142-md.dll (release build configuration) -* mongocxx-v_noabi-dhs-x64-v142-mdd.dll (debug build configuration) -* mongocxx-v_noabi-rts-x64-v142-md.dll (link with mongoc statically) -* mongocxx-v_noabi-rhm-x64-v142-md.dll (mnmlstc/core polyfill library) -* mongocxx-v_noabi-rhb-x64-v142-md.dll (Boost polyfill library) +* `mongocxx-v_noabi-rhs-x64-v142-md.dll` (release build configuration) +* `mongocxx-v_noabi-dhs-x64-v142-mdd.dll` (debug build configuration) +* `mongocxx-v_noabi-rts-x64-v142-md.dll` (link with mongoc statically) +* `mongocxx-v_noabi-rhi-x64-v142-md.dll` (bsoncxx polyfill library) +* `mongocxx-v_noabi-rhm-x64-v142-md.dll` (mnmlstc/core polyfill library) +* `mongocxx-v_noabi-rhb-x64-v142-md.dll` (Boost polyfill library) This allows libraries built with different build configurations (and different runtime library requirements) to be built and installed without conflicting with each other. diff --git a/docs/content/mongocxx-v3/installation/linux.md b/docs/content/mongocxx-v3/installation/linux.md index 96c7a7cb73..5d234cec2c 100644 --- a/docs/content/mongocxx-v3/installation/linux.md +++ b/docs/content/mongocxx-v3/installation/linux.md @@ -9,30 +9,7 @@ title = "Linux" ### Step 1: Choose a C++17 polyfill -The mongocxx driver uses the C++17 features `std::optional` and -`std::string_view`. To compile the mongocxx driver for pre-C++17, you -must choose one of the following implementations for these features: - - MNMLSTC/core (*default for non-Windows platforms*) - Select with `-DBSONCXX_POLY_USE_MNMLSTC=1`. **NOTE**: This option - vendors a header-only installation of MNMLSTC/core into the bsoncxx - library installation and will therefore download MLNMLSTC from GitHub - during the build process. If you already have an available version of - MNMLSTC on your system, you can avoid the download step by using - `-DBSONCXX_POLY_USE_SYSTEM_MNMLSTC`. - - Boost (*default for Windows platforms*) - Select with `-DBSONCXX_POLY_USE_BOOST=1`. This is currently the - only option if you are using a version of MSVC that does not support - C++17. - -Most users should be fine sticking with the default. However, if you -have an existing application which makes heavy use of one of the -available libraries, you may prefer to build the mongocxx driver -against the same library. - -**DO NOT** change your project's polyfill if you need to create a -stable binary interface. +First, [choose a C++17 polyfill library]({{< ref "/mongocxx-v3/polyfill-selection" >}}). ### Step 2: Download the latest version of the mongocxx driver. diff --git a/docs/content/mongocxx-v3/installation/macos.md b/docs/content/mongocxx-v3/installation/macos.md index d8e78796e7..906e24f025 100644 --- a/docs/content/mongocxx-v3/installation/macos.md +++ b/docs/content/mongocxx-v3/installation/macos.md @@ -9,30 +9,7 @@ title = "macOS" ### Step 1: Choose a C++17 polyfill -The mongocxx driver uses the C++17 features `std::optional` and -`std::string_view`. To compile the mongocxx driver for pre-C++17, you -must choose one of the following implementations for these features: - - MNMLSTC/core (*default for non-Windows platforms*) - Select with `-DBSONCXX_POLY_USE_MNMLSTC=1`. **NOTE**: This option - vendors a header-only installation of MNMLSTC/core into the bsoncxx - library installation and will therefore download MLNMLSTC from GitHub - during the build process. If you already have an available version of - MNMLSTC on your system, you can avoid the download step by using - `-DBSONCXX_POLY_USE_SYSTEM_MNMLSTC`. - - Boost (*default for Windows platforms*) - Select with `-DBSONCXX_POLY_USE_BOOST=1`. This is currently the - only option if you are using a version of MSVC that does not support - C++17. - -Most users should be fine sticking with the default. However, if you -have an existing application which makes heavy use of one of the -available libraries, you may prefer to build the mongocxx driver -against the same library. - -**DO NOT** change your project's polyfill if you need to create a -stable binary interface. +First, [choose a C++17 polyfill library]({{< ref "/mongocxx-v3/polyfill-selection" >}}). ### Step 2: Download the latest version of the mongocxx driver. diff --git a/docs/content/mongocxx-v3/installation/windows.md b/docs/content/mongocxx-v3/installation/windows.md index f76c3bd3a8..59923c5dec 100644 --- a/docs/content/mongocxx-v3/installation/windows.md +++ b/docs/content/mongocxx-v3/installation/windows.md @@ -9,30 +9,7 @@ title = "Windows" ### Step 1: Choose a C++17 polyfill -The mongocxx driver uses the C++17 features `std::optional` and -`std::string_view`. To compile the mongocxx driver for pre-C++17, you -must choose one of the following implementations for these features: - - MNMLSTC/core (*default for non-Windows platforms*) - Select with `-DBSONCXX_POLY_USE_MNMLSTC=1`. **NOTE**: This option - vendors a header-only installation of MNMLSTC/core into the bsoncxx - library installation and will therefore download MLNMLSTC from GitHub - during the build process. If you already have an available version of - MNMLSTC on your system, you can avoid the download step by using - `-DBSONCXX_POLY_USE_SYSTEM_MNMLSTC`. - - Boost (*default for Windows platforms*) - Select with `-DBSONCXX_POLY_USE_BOOST=1`. This is currently the - only option if you are using a version of MSVC that does not support - C++17. - -Most users should be fine sticking with the default. However, if you -have an existing application which makes heavy use of one of the -available libraries, you may prefer to build the mongocxx driver -against the same library. - -**DO NOT** change your project's polyfill if you need to create a -stable binary interface. +First, [choose a C++17 polyfill library]({{< ref "/mongocxx-v3/polyfill-selection" >}}). ### Step 2: Download the latest version of the mongocxx driver. diff --git a/docs/content/mongocxx-v3/polyfill-selection.md b/docs/content/mongocxx-v3/polyfill-selection.md new file mode 100644 index 0000000000..1dba2b8d02 --- /dev/null +++ b/docs/content/mongocxx-v3/polyfill-selection.md @@ -0,0 +1,59 @@ ++++ +date = "2024-02-20T00:00:00-00:00" +title = "Choosing a C++17 Polyfill" +[menu.main] + identifier = "mongocxx3-polyfill-selection" + parent = "mongocxx3" + weight = 8 ++++ + +The mongocxx driver uses C++17 features `std::optional` and `std::string_view`. +To use the C++17 standard library implementations for these features, set +the CMake configuration variable `CMAKE_CXX_STANDARD` to 17 or higher. +Otherwise, to compile the mongocxx driver for pre-C++17 configurations, a +polyfill library implementation must be selected from the following options +(note: "default" refers to **pre-C++17** configurations when no polyfill library +is explicitly selected): + +* bsoncxx (*default only when `-DENABLE_BSONCXX_POLY_USE_IMPLS=ON`*) + + Select with `-DBSONCXX_POLY_USE_IMPLS=ON`. This option is most recommended, as + it does not require additional external library dependencies. To enable + selecting this option by default for pre-C++17 configurations when no other + options are specified, set `ENABLE_BSONCXX_POLY_USE_IMPLS=ON` (this option + will be set to ON by default in an upcoming major release). + +* MNMLSTC/core (*default for non-Windows platforms*) + + **This option is deprecated and will be removed in an upcoming major release.** + Select with `-DBSONCXX_POLY_USE_MNMLSTC=1`. **NOTE**: This option vendors a + header-only installation of MNMLSTC/core into the bsoncxx library installation + and will therefore download MLNMLSTC from GitHub during the configuration + process. If you already have an available version of MNMLSTC on your system, + you can avoid the download step by using `-DBSONCXX_POLY_USE_SYSTEM_MNMLSTC`. + +* Boost (*default for Windows platforms*) + + **This option is deprecated and will be removed in an upcoming major release.** + Select with `-DBSONCXX_POLY_USE_BOOST=1`. This is currently the only + non-bsoncxx option if you are using a version of MSVC that does not support + C++17. + +Most users should use default behavior with `-DENABLE_BSONCXX_POLY_USE_IMPLS=ON`. +However, if you have a preference for one of the external polyfill libraries +(e.g. already a dependency being used by your application), you may prefer to +explicitly select that external polyfill library rather than rely on default +selection behavior. + +**NOTE**: C++ standard conformance and supported behavior of polyfill features +may vary depending on the selected polyfill library. The purpose of these +polyfills is to support pre-C++17 configurations by providing stand-ins for +their C++17 equivalents. Therefore we recommend using the C++17 standard +library whenever possible by setting `-DCMAKE_CXX_STANDARD=17` or newer. + +**WARNING**: the choice of polyfill library has a direct impact on the public +API and ABI for the mongocxx library. Changing the polyfill can lead to both +source-breaking changes (during compilation) and binary-breaking changes (during +linking or execution). To limit reliance on polyfill-specific configuration or +behavior, avoid using `stdx::string_view` and `stdx::optional` with +non-mongocxx library interfaces. diff --git a/src/bsoncxx/CMakeLists.txt b/src/bsoncxx/CMakeLists.txt index 4031852123..ce53a716a2 100644 --- a/src/bsoncxx/CMakeLists.txt +++ b/src/bsoncxx/CMakeLists.txt @@ -20,6 +20,7 @@ set(BSONCXX_VERSION_NO_EXTRA ${BSONCXX_VERSION_MAJOR}.${BSONCXX_VERSION_MINOR}.$ set(BSONCXX_VERSION ${BSONCXX_VERSION_NO_EXTRA}${BSONCXX_VERSION_EXTRA}) message(STATUS "bsoncxx version: ${BSONCXX_VERSION}") +option(BSONCXX_POLY_USE_IMPLS "Use bsoncxx implementations for stdx polyfills" OFF) option(BSONCXX_POLY_USE_MNMLSTC "Use MNMLSTC/core for stdx polyfills" OFF) option(BSONCXX_POLY_USE_SYSTEM_MNMLSTC "Obtain mnmlstc/core from system" OFF) option(BSONCXX_POLY_USE_BOOST "Use boost for stdx polyfills" OFF) @@ -30,7 +31,7 @@ set(BSONCXX_OUTPUT_BASENAME "bsoncxx" CACHE STRING "Output bsoncxx library base # Count how many polyfill options are true-ish set(BSONCXX_POLY_OPTIONS_SET 0) -foreach(BSONCXX_POLY_OPTION ${BSONCXX_POLY_USE_MNMLSTC} ${BSONCXX_POLY_USE_BOOST} ${BSONCXX_POLY_USE_STD}) +foreach(BSONCXX_POLY_OPTION ${BSONCXX_POLY_USE_IMPLS} ${BSONCXX_POLY_USE_MNMLSTC} ${BSONCXX_POLY_USE_BOOST} ${BSONCXX_POLY_USE_STD}) if(${BSONCXX_POLY_OPTION}) MATH(EXPR BSONCXX_POLY_OPTIONS_SET "${BSONCXX_POLY_OPTIONS_SET}+1") endif() @@ -45,15 +46,23 @@ elseif(BSONCXX_POLY_OPTIONS_SET EQUAL 0) # If we are in C++17 mode, use the C++17 versions set(BSONCXX_POLY_USE_STD ON) message(STATUS "Auto-configuring bsoncxx to use C++17 std library polyfills since C++17 is active and user didn't specify otherwise") + elseif(ENABLE_BSONCXX_POLY_USE_IMPLS) + # If enabled, use bsoncxx implementations instead of external libraries. + set(BSONCXX_POLY_USE_IMPLS ON) + message(STATUS "Auto-configuring bsoncxx to use its own polyfill implementations since C++17 is inactive") elseif(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") # Otherwise, since MSVC can't handle MNMLSTC, default to boost set(BSONCXX_POLY_USE_BOOST ON) message(STATUS "Auto-configuring bsoncxx to use boost std library polyfills since C++17 is inactive and compiler is MSVC") + message(DEPRECATION "Default selection of external polyfill libraries is deprecated and will be removed in an upcoming major release. Set ENABLE_BSONCXX_POLY_USE_IMPLS=ON to enable recommended behavior.") else() # Otherwise, we are on a platform that can handle MNMLSTC set(BSONCXX_POLY_USE_MNMLSTC ON) message(STATUS "Auto-configuring bsoncxx to use MNMLSTC for polyfills since C++17 is inactive") + message(DEPRECATION "Default selection of external polyfill libraries is deprecated and will be removed in an upcoming major release. Set ENABLE_BSONCXX_POLY_USE_IMPLS=ON to enable recommended behavior.") endif() +elseif(BSONCXX_POLY_USE_MNMLSTC OR BSONCXX_POLY_USE_BOOST) + message(DEPRECATION "Support for external polyfill libraries is deprecated and will be removed in an upcoming major release. Set BSONCXX_POLY_USE_IMPLS=ON (pre-C++17) or set CMAKE_CXX_STANDARD=17 (or newer) to select recommended behavior.") endif() # It doesn't make sense to say we aren't using MNMLSTC but then diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/postlude.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/postlude.hpp index 1c1b915f5a..81524a1e87 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/postlude.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/postlude.hpp @@ -30,6 +30,10 @@ BSONCXX_POP_WARNINGS(); #pragma pop_macro("BSONCXX_POLY_USE_SYSTEM_MNMLSTC") #undef BSONCXX_POLY_USE_BOOST #pragma pop_macro("BSONCXX_POLY_USE_BOOST") +#undef BSONCXX_POLY_USE_IMPLS +#pragma pop_macro("BSONCXX_POLY_USE_IMPLS") +#undef BSONCXX_POLY_USE_STD +#pragma pop_macro("BSONCXX_POLY_USE_STD") // version.hpp (generated by CMake) #undef BSONCXX_VERSION_EXTRA diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/prelude.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/prelude.hpp index 2f154c437f..edfb84d38c 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/prelude.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/config/prelude.hpp @@ -73,6 +73,10 @@ #undef BSONCXX_POLY_USE_SYSTEM_MNMLSTC #pragma push_macro("BSONCXX_POLY_USE_BOOST") #undef BSONCXX_POLY_USE_BOOST +#pragma push_macro("BSONCXX_POLY_USE_IMPLS") +#undef BSONCXX_POLY_USE_IMPLS +#pragma push_macro("BSONCXX_POLY_USE_STD") +#undef BSONCXX_POLY_USE_STD // version.hpp (generated by CMake) #pragma push_macro("BSONCXX_VERSION_EXTRA") diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/make_unique.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/make_unique.hpp index 770fd69196..c05f21a590 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/make_unique.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/make_unique.hpp @@ -14,19 +14,30 @@ #pragma once -#include #include + +#include + +#pragma push_macro("BSONCXX_DETAIL_USE_STD_MAKE_UNIQUE") +#undef BSONCXX_DETAIL_USE_STD_MAKE_UNIQUE + +#if (defined(__cplusplus) && __cplusplus >= 201402L) || \ + (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) +#define BSONCXX_DETAIL_USE_STD_MAKE_UNIQUE +#endif + +// Only define bsoncxx implementation details when necessary. +#if !defined(BSONCXX_DETAIL_USE_STD_MAKE_UNIQUE) || !defined(__cpp_lib_smart_ptr_for_overwrite) + +#include #include #include #include -#include - namespace bsoncxx { namespace v_noabi { namespace stdx { - namespace detail { // Switch backend of make_unique by the type we are creating. @@ -84,6 +95,22 @@ template struct make_unique_impl {}; } // namespace detail +} // namespace stdx +} // namespace v_noabi +} // namespace bsoncxx + +#endif // !defined(BSONCXX_DETAIL_USE_STD_MAKE_UNIQUE) || + // !defined(__cpp_lib_smart_ptr_for_overwrite) + +namespace bsoncxx { +namespace v_noabi { +namespace stdx { + +// Unlike other C++17 polyfill features, this is a C++14 feature. +// Use feature testing rather than polyfill library selection macros. +#if defined(BSONCXX_DETAIL_USE_STD_MAKE_UNIQUE) +using ::std::make_unique; +#else /// Equivalent to `std::make_unique(args...)` where `T` is a non-array type. template make_unique(std::size_t count) { return Impl::make(std::true_type{}, count); } +#endif + +// Unlike other C++17 polyfill features, this is a C++20 feature. +// Use feature testing rather than polyfill library selection macros. +#if defined(__cpp_lib_smart_ptr_for_overwrite) +using ::std::make_unique_for_overwrite; +#else + /// Equivalent to `std::make_unique_for_overwrite()` where `T` is a non-array type. template , @@ -127,10 +162,14 @@ std::unique_ptr make_unique_for_overwrite(std::size_t count) { return Impl::make(std::false_type{}, count); } +#endif + } // namespace stdx } // namespace v_noabi } // namespace bsoncxx +#pragma pop_macro("BSONCXX_DETAIL_USE_STD_MAKE_UNIQUE") + #include namespace bsoncxx { diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/optional.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/optional.hpp index eb9db49474..f6c9608b57 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/optional.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/optional.hpp @@ -14,6 +14,73 @@ #pragma once +#include + +#if defined(BSONCXX_POLY_USE_MNMLSTC) + +#include + +namespace bsoncxx { +namespace v_noabi { +namespace stdx { + +using ::core::in_place; +using ::core::in_place_t; +using ::core::make_optional; +using ::core::nullopt; +using ::core::nullopt_t; +using ::core::optional; + +} // namespace stdx +} // namespace v_noabi +} // namespace bsoncxx + +#elif defined(BSONCXX_POLY_USE_BOOST) + +#include +#include +#include + +namespace bsoncxx { +namespace v_noabi { +namespace stdx { + +#if BOOST_VERSION >= 106300 +using in_place_t = ::boost::in_place_init_t; +const in_place_t in_place{::boost::in_place_init}; +#endif + +using ::boost::optional; +using nullopt_t = ::boost::none_t; + +const nullopt_t nullopt{::boost::none}; +using ::boost::make_optional; + +} // namespace stdx +} // namespace v_noabi +} // namespace bsoncxx + +#elif defined(BSONCXX_POLY_USE_STD) + +#include + +namespace bsoncxx { +namespace v_noabi { +namespace stdx { + +using ::std::in_place; +using ::std::in_place_t; +using ::std::make_optional; +using ::std::nullopt; +using ::std::nullopt_t; +using ::std::optional; + +} // namespace stdx +} // namespace v_noabi +} // namespace bsoncxx + +#elif defined(BSONCXX_POLY_USE_IMPLS) + #include #include #include @@ -23,10 +90,8 @@ #include #include -#include "./operators.hpp" -#include "./type_traits.hpp" - -#include +#include +#include namespace bsoncxx { @@ -771,13 +836,21 @@ struct hash> } // namespace std +#else +#error "Cannot find a valid polyfill for optional" +#endif + #include namespace bsoncxx { namespace stdx { +// Only Boost prior to 1.63 does not provide an `std::in_place` equivalent. +#if !defined(BOOST_VERSION) || BOOST_VERSION >= 106300 using ::bsoncxx::v_noabi::stdx::in_place; using ::bsoncxx::v_noabi::stdx::in_place_t; +#endif + using ::bsoncxx::v_noabi::stdx::make_optional; using ::bsoncxx::v_noabi::stdx::nullopt; using ::bsoncxx::v_noabi::stdx::nullopt_t; diff --git a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp index 785e873d77..74bba0d239 100644 --- a/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp +++ b/src/bsoncxx/include/bsoncxx/v_noabi/bsoncxx/stdx/string_view.hpp @@ -14,6 +14,92 @@ #pragma once +#include + +#if defined(BSONCXX_POLY_USE_MNMLSTC) + +#include + +namespace bsoncxx { +namespace v_noabi { +namespace stdx { + +using ::core::basic_string_view; +using ::core::string_view; + +} // namespace stdx +} // namespace v_noabi +} // namespace bsoncxx + +#elif defined(BSONCXX_POLY_USE_BOOST) + +#include + +#if BOOST_VERSION >= 106100 + +#include + +namespace bsoncxx { +namespace v_noabi { +namespace stdx { + +using ::boost::basic_string_view; +using ::boost::string_view; + +} // namespace stdx +} // namespace v_noabi +} // namespace bsoncxx + +#else + +#include + +namespace bsoncxx { +namespace v_noabi { +namespace stdx { + +template > +using basic_string_view = ::boost::basic_string_ref; +using string_view = ::boost::string_ref; + +} // namespace stdx +} // namespace v_noabi +} // namespace bsoncxx + +#endif + +#elif defined(BSONCXX_POLY_USE_STD_EXPERIMENTAL) + +#include + +namespace bsoncxx { +namespace v_noabi { +namespace stdx { + +using ::std::experimental::basic_string_view; +using ::std::experimental::string_view; + +} // namespace stdx +} // namespace v_noabi +} // namespace bsoncxx + +#elif defined(BSONCXX_POLY_USE_STD) + +#include + +namespace bsoncxx { +namespace v_noabi { +namespace stdx { + +using ::std::basic_string_view; +using ::std::string_view; + +} // namespace stdx +} // namespace v_noabi +} // namespace bsoncxx + +#elif defined(BSONCXX_POLY_USE_IMPLS) + #include #include #include @@ -25,18 +111,6 @@ #include #include -#include - -#ifdef __has_include -#if __has_include() -#include -#endif -#endif - -#ifdef __cpp_lib_string_view -#include -#endif - namespace bsoncxx { namespace v_noabi { namespace stdx { @@ -502,17 +576,6 @@ using string_view = basic_string_view; } // namespace v_noabi } // namespace bsoncxx -namespace bsoncxx { -namespace stdx { - -using ::bsoncxx::v_noabi::stdx::basic_string_view; -using ::bsoncxx::v_noabi::stdx::string_view; - -} // namespace stdx -} // namespace bsoncxx - -#include - namespace std { template @@ -525,4 +588,19 @@ struct hash> } }; -} // namespace std \ No newline at end of file +} // namespace std + +#else +#error "Cannot find a valid polyfill for string_view" +#endif + +#include + +namespace bsoncxx { +namespace stdx { + +using ::bsoncxx::v_noabi::stdx::basic_string_view; +using ::bsoncxx::v_noabi::stdx::string_view; + +} // namespace stdx +} // namespace bsoncxx diff --git a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/config/config.hpp.in b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/config/config.hpp.in index 545d9a58aa..a80c180a19 100644 --- a/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/config/config.hpp.in +++ b/src/bsoncxx/lib/bsoncxx/v_noabi/bsoncxx/config/config.hpp.in @@ -15,6 +15,7 @@ #cmakedefine BSONCXX_POLY_USE_MNMLSTC #cmakedefine BSONCXX_POLY_USE_SYSTEM_MNMLSTC #cmakedefine BSONCXX_POLY_USE_BOOST +#cmakedefine BSONCXX_POLY_USE_IMPLS #cmakedefine BSONCXX_POLY_USE_STD #define BSONCXX_INLINE_NAMESPACE_BEGIN inline namespace v_noabi { diff --git a/src/bsoncxx/test/CMakeLists.txt b/src/bsoncxx/test/CMakeLists.txt index b980f72567..56abda1e1c 100644 --- a/src/bsoncxx/test/CMakeLists.txt +++ b/src/bsoncxx/test/CMakeLists.txt @@ -81,6 +81,8 @@ if(ENABLE_MACRO_GUARD_TESTS) BSONCXX_POLY_USE_MNMLSTC BSONCXX_POLY_USE_SYSTEM_MNMLSTC BSONCXX_POLY_USE_BOOST + BSONCXX_POLY_USE_IMPLS + BSONCXX_POLY_USE_STD BSONCXX_VERSION_EXTRA # version.hpp (generated by CMake) BSONCXX_VERSION_MAJOR BSONCXX_VERSION_MINOR diff --git a/src/bsoncxx/test/catch.hh b/src/bsoncxx/test/catch.hh index 8f5e3421cf..4fb9916880 100644 --- a/src/bsoncxx/test/catch.hh +++ b/src/bsoncxx/test/catch.hh @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/src/bsoncxx/test/optional.test.cpp b/src/bsoncxx/test/optional.test.cpp index bfa0c83cfa..c83912f3d5 100644 --- a/src/bsoncxx/test/optional.test.cpp +++ b/src/bsoncxx/test/optional.test.cpp @@ -12,6 +12,12 @@ #include #include +#include + +// Each polyfill library has some set of features that are not conformant with the standard +// specification (inconsistent, missing, etc.). Limit testing to bsoncxx implementation and stdlib. +#if defined(BSONCXX_POLY_USE_IMPLS) || defined(BSONCXX_POLY_USE_STD) + using bsoncxx::stdx::in_place; using bsoncxx::stdx::nullopt; using bsoncxx::stdx::optional; @@ -70,49 +76,52 @@ struct not_copyable { not_copyable& operator=(not_copyable&&) = default; }; +// Improve quality of error messages on failure (in particular for MSVC). +#define STATIC_ASSERT_EXPR(expr) static_assert((expr), "expected: " #expr) +#define STATIC_ASSERT_EXPR_EQUAL(a, b) static_assert((a) == (b), "expected: " #a " == " #b) +#define STATIC_ASSERT_EXPR_IMPLIES(a, b) static_assert((!(a) || (b)), "expected: " #a " -> " #b) + +#if defined(BSONCXX_POLY_USE_STD) +// Deliberately weaken assertions for stdlib implementations to accomodate for differences in +// behavior. +#define STATIC_ASSERT_EXPR_ALIKE(a, b) STATIC_ASSERT_EXPR_IMPLIES(a, b) +#else +#define STATIC_ASSERT_EXPR_ALIKE(a, b) STATIC_ASSERT_EXPR_EQUAL(a, b) +#endif + template -bool assert_sameness() { - static_assert(Trait::value == Trait>::value, "Fail"); +bool assert_alikeness() { + STATIC_ASSERT_EXPR_ALIKE(Trait::value, Trait>::value); return true; } template bool check_convert_alike() { - static_assert(std::is_convertible::value // - == std::is_convertible::value, - "fail"); - static_assert(std::is_convertible::value // - == std::is_convertible::value, - "fail"); - static_assert(std::is_convertible::value // - == std::is_convertible::value, - "fail"); - static_assert(std::is_convertible::value // - == std::is_convertible::value, - "fail"); - static_assert(std::is_convertible::value // - == std::is_convertible::value, - "fail"); + STATIC_ASSERT_EXPR_ALIKE((std::is_convertible::value), + (std::is_convertible::value)); + STATIC_ASSERT_EXPR_ALIKE((std::is_convertible::value), + (std::is_convertible::value)); + STATIC_ASSERT_EXPR_ALIKE((std::is_convertible::value), + (std::is_convertible::value)); + STATIC_ASSERT_EXPR_ALIKE((std::is_convertible::value), + (std::is_convertible::value)); + STATIC_ASSERT_EXPR_ALIKE((std::is_convertible::value), + (std::is_convertible::value)); return true; } template bool check_construct_alike() { - static_assert(std::is_constructible::value // - == std::is_constructible::value, - "fail"); - static_assert(std::is_constructible::value // - == std::is_constructible::value, - "fail"); - static_assert(std::is_constructible::value // - == std::is_constructible::value, - "fail"); - static_assert(std::is_constructible::value // - == std::is_constructible::value, - "fail"); - static_assert(std::is_constructible::value // - == std::is_constructible::value, - "fail"); + STATIC_ASSERT_EXPR_ALIKE((std::is_constructible::value), + (std::is_constructible::value)); + STATIC_ASSERT_EXPR_ALIKE((std::is_constructible::value), + (std::is_constructible::value)); + STATIC_ASSERT_EXPR_ALIKE((std::is_constructible::value), + (std::is_constructible::value)); + STATIC_ASSERT_EXPR_ALIKE((std::is_constructible::value), + (std::is_constructible::value)); + STATIC_ASSERT_EXPR_ALIKE((std::is_constructible::value), + (std::is_constructible::value)); return true; } @@ -126,55 +135,53 @@ bool check_conversions() { template bool static_checks() { - assert_sameness(); - assert_sameness(); - assert_sameness(); - assert_sameness(); - assert_sameness(); - assert_sameness(); - assert_sameness(); - assert_sameness(); - static_assert(bsoncxx::detail::is_equality_comparable>::value == - bsoncxx::detail::is_equality_comparable::value, - "fail"); - static_assert(bsoncxx::detail::is_totally_ordered_with>::value == - bsoncxx::detail::is_totally_ordered>::value, - "fail"); - static_assert( - std::is_constructible, T>::value == std::is_constructible::value, "fail"); - static_assert(std::is_constructible, bsoncxx::stdx::nullopt_t>{}, "fail"); + assert_alikeness(); + assert_alikeness(); + assert_alikeness(); + assert_alikeness(); + assert_alikeness(); + assert_alikeness(); + assert_alikeness(); + assert_alikeness(); + STATIC_ASSERT_EXPR_ALIKE((bsoncxx::detail::is_equality_comparable::value), + (bsoncxx::detail::is_equality_comparable>::value)); + STATIC_ASSERT_EXPR_ALIKE((bsoncxx::detail::is_totally_ordered::value), + (bsoncxx::detail::is_totally_ordered_with>::value)); + STATIC_ASSERT_EXPR_ALIKE((std::is_constructible::value), + (std::is_constructible, T>::value)); + STATIC_ASSERT_EXPR((std::is_constructible, bsoncxx::stdx::nullopt_t>::value)); // Assert we return proper reference types - static_assert(std::is_same>, T&&>{}, "fail"); - static_assert(std::is_same const>, const T&&>{}, "fail"); - static_assert(std::is_same const&>, const T&>{}, "fail"); - static_assert(std::is_same&>, T&>{}, "fail"); + STATIC_ASSERT_EXPR((std::is_same>, T&&>::value)); + STATIC_ASSERT_EXPR((std::is_same const>, const T&&>::value)); + STATIC_ASSERT_EXPR((std::is_same const&>, const T&>::value)); + STATIC_ASSERT_EXPR((std::is_same&>, T&>::value)); // .value() - static_assert(std::is_same>, T&&>{}, "fail"); - static_assert(std::is_same const>, const T&&>{}, "fail"); - static_assert(std::is_same const&>, const T&>{}, "fail"); - static_assert(std::is_same&>, T&>{}, "fail"); + STATIC_ASSERT_EXPR((std::is_same>, T&&>::value)); + STATIC_ASSERT_EXPR((std::is_same const>, const T&&>::value)); + STATIC_ASSERT_EXPR((std::is_same const&>, const T&>::value)); + STATIC_ASSERT_EXPR((std::is_same&>, T&>::value)); // operator-> - static_assert(std::is_same>, T*>{}, "fail"); - static_assert(std::is_same const>, const T*>{}, "fail"); - static_assert(std::is_same const&>, const T*>{}, "fail"); - static_assert(std::is_same&>, T*>{}, "fail"); + STATIC_ASSERT_EXPR((std::is_same>, T*>::value)); + STATIC_ASSERT_EXPR((std::is_same const>, const T*>::value)); + STATIC_ASSERT_EXPR((std::is_same const&>, const T*>::value)); + STATIC_ASSERT_EXPR((std::is_same&>, T*>::value)); return check_conversions(); } } // namespace -static_assert(bsoncxx::detail::is_totally_ordered{}, "fail"); -static_assert(bsoncxx::detail::is_totally_ordered{}, "fail"); -static_assert(!bsoncxx::detail::is_totally_ordered{}, "fail"); +STATIC_ASSERT_EXPR(bsoncxx::detail::is_totally_ordered::value); +STATIC_ASSERT_EXPR(bsoncxx::detail::is_totally_ordered::value); +STATIC_ASSERT_EXPR(!bsoncxx::detail::is_totally_ordered::value); #ifndef NO_LWG_2543 -static_assert(is_hashable>::value, "fail"); -static_assert(!is_hashable>::value, "fail"); +STATIC_ASSERT_EXPR(is_hashable>::value); +STATIC_ASSERT_EXPR(!is_hashable>::value); #endif // Having this static_assert appear prior to static_checks prevents a later static assert error // that occurs only on MSVC 19.29 (VS2019). Obviously. -static_assert(bsoncxx::detail::is_totally_ordered>{}, "fail"); +STATIC_ASSERT_EXPR(bsoncxx::detail::is_totally_ordered>::value); // It's a useful check on its own, but now you are cursed with this knowledge just as I have been. // pain. @@ -604,7 +611,10 @@ struct in_place_convertible { }; TEST_CASE("optional conversions") { - static_assert(!std::is_constructible, optional>{}, "fail"); + // Some stdlib implementations do not forbid this ctor correctly. +#if defined(BSONCXX_POLY_USE_IMPLS) + STATIC_ASSERT_EXPR((!std::is_constructible, optional>::value)); +#endif // defined(BSONCXX_POLY_USE_IMPLS) optional s1(bsoncxx::stdx::in_place); CHECK(s1 == ""); @@ -619,3 +629,5 @@ TEST_CASE("optional conversions") { CHECK(string == c_str); CHECK(string2 == c_str); } + +#endif // defined(BSONCXX_POLY_USE_IMPLS) || defined(BSONCXX_POLY_USE_STD) diff --git a/src/bsoncxx/test/string_view.test.cpp b/src/bsoncxx/test/string_view.test.cpp index 9c14d773c4..c9600208de 100644 --- a/src/bsoncxx/test/string_view.test.cpp +++ b/src/bsoncxx/test/string_view.test.cpp @@ -19,6 +19,8 @@ #include #include +#include + namespace stdx = bsoncxx::stdx; using stdx::string_view; @@ -28,6 +30,10 @@ static_assert(std::is_constructible::value, "fail"); static_assert(std::is_convertible::value, "fail"); static_assert(std::is_constructible::value, "fail"); +// Each polyfill library has some set of features that are not conformant with the standard +// specification (inconsistent, missing, etc.). Limit testing to bsoncxx implementation and stdlib. +#if defined(BSONCXX_POLY_USE_IMPLS) || defined(BSONCXX_POLY_USE_STD) + TEST_CASE("string_view: Default constructor") { (void)string_view(); string_view s; @@ -214,4 +220,6 @@ TEST_CASE("Convert to/from std::string_view") { bson_sv = std_sv; CHECK(bson_sv == std_sv); } -#endif \ No newline at end of file +#endif + +#endif // defined(BSONCXX_POLY_USE_IMPLS) || defined(BSONCXX_POLY_USE_STD) diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/private/libbson.cpp b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/private/libbson.cpp index 46e2175b0c..0052242690 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/private/libbson.cpp +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/private/libbson.cpp @@ -31,20 +31,41 @@ void doc_to_bson_t(const bsoncxx::v_noabi::document::view& doc, bson_t* bson) { } // namespace -scoped_bson_t::scoped_bson_t(bsoncxx::stdx::optional doc) - : _is_initialized{doc} { +scoped_bson_t::scoped_bson_t(bsoncxx::document::view_or_value doc) + : _is_initialized{true}, _doc{std::move(doc)} { + doc_to_bson_t(*_doc, &_bson); +} + +void scoped_bson_t::init_from_static(bsoncxx::document::view_or_value doc) { + _is_initialized = true; + _doc = std::move(doc); + doc_to_bson_t(*_doc, &_bson); +} + +scoped_bson_t::scoped_bson_t(bsoncxx::document::view doc) + : scoped_bson_t(bsoncxx::document::view_or_value(doc)) {} + +void scoped_bson_t::init_from_static(bsoncxx::document::view doc) { + this->init_from_static(bsoncxx::document::view_or_value(doc)); +} + +scoped_bson_t::scoped_bson_t(bsoncxx::document::value doc) + : scoped_bson_t(bsoncxx::document::view_or_value(std::move(doc))) {} + +void scoped_bson_t::init_from_static(bsoncxx::document::value doc) { + this->init_from_static(bsoncxx::document::view_or_value(std::move(doc))); +} + +scoped_bson_t::scoped_bson_t(bsoncxx::stdx::optional doc) { if (doc) { - _doc = std::move(doc); - doc_to_bson_t(*_doc, &_bson); + this->init_from_static(std::move(*doc)); } } void scoped_bson_t::init_from_static( bsoncxx::v_noabi::stdx::optional doc) { if (doc) { - _is_initialized = true; - _doc = std::move(doc); - doc_to_bson_t(*_doc, &_bson); + this->init_from_static(std::move(*doc)); } } diff --git a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/private/libbson.hh b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/private/libbson.hh index 288c1e0d8e..ae1bce3606 100644 --- a/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/private/libbson.hh +++ b/src/mongocxx/lib/mongocxx/v_noabi/mongocxx/private/libbson.hh @@ -53,9 +53,51 @@ class MONGOCXX_TEST_API scoped_bson_t { scoped_bson_t(); // - // Constructs a new scoped_bson_t from an optional document view_or_value. + // Constructs a new scoped_bson_t from the provided document. // - // The internal bson_t is initialized if the optional is populated. + // The internal bson_t is considered initialized. + // + explicit scoped_bson_t(bsoncxx::document::view_or_value doc); + + // + // Initializes a bson_t from the provided document. + // + // The internal bson_t is considered initialized. + // + void init_from_static(bsoncxx::document::view_or_value doc); + + // + // Constructs a new scoped_bson_t from the provided document. + // + // The internal bson_t is considered initialized. + // + explicit scoped_bson_t(bsoncxx::document::view doc); + + // + // Initializes a bson_t from the provided document. + // + // The internal bson_t is considered initialized. + // + void init_from_static(bsoncxx::document::view doc); + + // + // Constructs a new scoped_bson_t from the provided document. + // + // The internal bson_t is considered initialized. + // + explicit scoped_bson_t(bsoncxx::document::value doc); + + // + // Initializes a bson_t from the provided document. + // + // The internal bson_t is considered initialized. + // + void init_from_static(bsoncxx::document::value doc); + + // + // Constructs a new scoped_bson_t from the provided optional document. + // + // The internal bson_t is initialized if the optional contains a document. // explicit scoped_bson_t( bsoncxx::v_noabi::stdx::optional doc); @@ -63,7 +105,7 @@ class MONGOCXX_TEST_API scoped_bson_t { // // Initializes a bson_t from the provided optional document. // - // The internal bson_t is initialized if the optional is populated. + // The internal bson_t is initialized if the optional contains a document. // void init_from_static( bsoncxx::v_noabi::stdx::optional doc); @@ -111,7 +153,7 @@ class MONGOCXX_TEST_API scoped_bson_t { private: bson_t _bson; - bool _is_initialized; + bool _is_initialized = false; // If we are passed a value created on-the-fly, we'll need to own this. bsoncxx::v_noabi::stdx::optional _doc;