From 1b804c7a3193093ffe07540b08caa3ea29dd0cd6 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Thu, 11 Dec 2025 22:17:21 +0300 Subject: [PATCH] Implement initial version of C++20 module `boost.lexical_cast` (#84) --- .github/workflows/ci.yml | 61 ++++++++++++++++++- CMakeLists.txt | 30 +++++++-- doc/lexical_cast.qbk | 37 +++++++++++ include/boost/lexical_cast.hpp | 10 +++ .../boost/lexical_cast/bad_lexical_cast.hpp | 10 +++ .../boost/lexical_cast/detail/buffer_view.hpp | 8 +++ include/boost/lexical_cast/detail/config.hpp | 22 +++++++ .../lexical_cast/detail/converter_lexical.hpp | 20 ++++-- .../detail/converter_lexical_streams.hpp | 32 +++++++--- .../lexical_cast/detail/converter_numeric.hpp | 10 +++ include/boost/lexical_cast/detail/inf_nan.hpp | 8 +++ .../lexical_cast/detail/is_character.hpp | 11 +++- .../detail/lcast_basic_unlockedbuf.hpp | 9 +++ .../detail/lcast_char_constants.hpp | 7 +++ .../detail/lcast_precision.hpp | 14 ++++- .../detail/lcast_unsigned_converters.hpp | 10 +++ .../boost/lexical_cast/detail/widest_char.hpp | 10 ++- .../lexical_cast/try_lexical_convert.hpp | 15 ++++- modules/boost_lexical_cast.cppm | 57 +++++++++++++++++ modules/usage_sample.cpp | 16 +++++ test/cmake_subdir_test/CMakeLists.txt | 53 ++++++++++++++++ test/float_types_test.cpp | 1 + test/integral_types_test.cpp | 1 + test/lexical_cast_old.hpp | 2 +- test/pointers_test.cpp | 2 + test/vc8_bug_test.cpp | 1 + 26 files changed, 429 insertions(+), 28 deletions(-) create mode 100644 include/boost/lexical_cast/detail/config.hpp rename include/boost/{ => lexical_cast}/detail/lcast_precision.hpp (86%) create mode 100644 modules/boost_lexical_cast.cppm create mode 100644 modules/usage_sample.cpp create mode 100644 test/cmake_subdir_test/CMakeLists.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cca8d6f..b9b063e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,6 +37,10 @@ jobs: - toolset: clang cxxstd: "11,14,17,20" os: macos-13 + - toolset: clang-19 + cxxstd: "20,23" + os: ubuntu-24.04 + install: clang-19 llvm-19 libclang-rt-19-dev libc++-19-dev libc++abi-19-dev clang-tools-19 runs-on: ${{matrix.os}} @@ -70,6 +74,32 @@ jobs: python tools/boostdep/depinst/depinst.py --include benchmark --include example --include examples --include tools --git_args "--depth 10 --jobs 3" $LIBRARY ./bootstrap.sh ./b2 -j4 variant=debug tools/inspect + - name: Run modules tests wihtout 'import std;' + + + if: ${{matrix.toolset == 'clang-19'}} + run: | + cd ../boost-root/libs/lexical_cast + mkdir build_module + cd build_module + cmake -DBOOST_USE_MODULES=1 -GNinja -DCMAKE_CXX_COMPILER=clang++-19 ../test/cmake_subdir_test/ + cmake --build . + ctest -V + cd .. + rm -rf build_module + + - name: Run modules tests + if: false + # if: ${{matrix.toolset == 'clang-19'}} + run: | + cd ../boost-root/libs/lexical_cast + mkdir build_module + cd build_module + cmake -DBUILD_TESTING=1 -DBOOST_USE_MODULES=1 -DCMAKE_CXX_COMPILER=clang++-19 -DCMAKE_CXX_FLAGS=-stdlib=libc++ -DCMAKE_EXE_LINKER_FLAGS=-stdlib=libc++ -DCMAKE_CXX_STANDARD=23 -DCMAKE_EXPERIMENTAL_CXX_IMPORT_STD=0e5b6991-d74f-4b3d-a41c-cf096e0b2508 -G Ninja ../test/cmake_subdir_test/ + cmake --build . + ctest -V + cd .. + rm -rf build_module - name: Run CMake tests if: ${{matrix.toolset == 'gcc-14'}} @@ -173,8 +203,35 @@ jobs: cmake -DBUILD_TESTING=1 -DBOOST_INCLUDE_LIBRARIES=lexical_cast .. cmake --build . --target tests --config Debug ctest --output-on-failure --no-tests=error -C Debug - cd .. - rm -rf __build + + - name: Run modules tests + if: false + #if: ${{matrix.toolset == 'msvc-14.3'}} + shell: cmd + run: | + choco install --no-progress ninja + call "C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Auxiliary/Build/vcvarsall.bat" x64 + cd ../boost-root/libs/lexical_cast + rm -rf build_module + mkdir build_module + cd build_module + cmake -DBOOST_USE_MODULES=1 -DCMAKE_CXX_STANDARD=23 -DCMAKE_EXPERIMENTAL_CXX_IMPORT_STD=0e5b6991-d74f-4b3d-a41c-cf096e0b2508 -G Ninja ../test/cmake_subdir_test/ + cmake --build . + ctest --no-tests=error -V + + - name: Run modules tests wihtout 'import std;' + if: ${{matrix.toolset == 'msvc-14.3'}} + shell: cmd + run: | + choco install --no-progress ninja + call "C:/Program Files/Microsoft Visual Studio/2022/Enterprise/VC/Auxiliary/Build/vcvarsall.bat" x64 + cd ../boost-root/libs/lexical_cast + rm -rf build_module + mkdir build_module + cd build_module + cmake -DBOOST_USE_MODULES=1 -DCMAKE_CXX_STANDARD=20 -G Ninja ../test/cmake_subdir_test/ + cmake --build . + ctest --no-tests=error -V - name: Run tests shell: cmd diff --git a/CMakeLists.txt b/CMakeLists.txt index 93143c2..0dd0a35 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,23 +3,43 @@ # Distributed under the Boost Software License, Version 1.0. # https://www.boost.org/LICENSE_1_0.txt -cmake_minimum_required(VERSION 3.5...3.16) +cmake_minimum_required(VERSION 3.5...4.0) project(boost_lexical_cast VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX) -add_library(boost_lexical_cast INTERFACE) -add_library(Boost::lexical_cast ALIAS boost_lexical_cast) -target_include_directories(boost_lexical_cast INTERFACE include) +if (BOOST_USE_MODULES) + add_library(boost_lexical_cast) + target_sources(boost_lexical_cast PUBLIC + FILE_SET modules_public TYPE CXX_MODULES FILES + ${CMAKE_CURRENT_LIST_DIR}/modules/boost_lexical_cast.cppm + ) + target_compile_features(boost_lexical_cast PUBLIC cxx_std_20) + target_compile_definitions(boost_lexical_cast PUBLIC BOOST_USE_MODULES) + if (CMAKE_CXX_COMPILER_IMPORT_STD) + target_compile_definitions(boost_lexical_cast PRIVATE BOOST_LEXICAL_CAST_USE_STD_MODULE) + message(STATUS "Using `import std;`") + else() + message(STATUS "`import std;` is not awailable") + endif() + set(__scope PUBLIC) +else() + add_library(boost_lexical_cast INTERFACE) + set(__scope INTERFACE) +endif() + +target_include_directories(boost_lexical_cast ${__scope} include) target_link_libraries(boost_lexical_cast - INTERFACE + ${__scope} Boost::config Boost::container Boost::core Boost::throw_exception ) +add_library(Boost::lexical_cast ALIAS boost_lexical_cast) + if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/doc/lexical_cast.qbk b/doc/lexical_cast.qbk index 1cf6a37..2f67b3d 100644 --- a/doc/lexical_cast.qbk +++ b/doc/lexical_cast.qbk @@ -233,8 +233,45 @@ limitation of compiler options that you use. [endsect] +[section C++20 module] + +[caution C++20 module support is on early stage, targets, flags and behavior may change in the future] + +If using modern CMake define CMake option `-DBOOST_USE_MODULES=1` to build a C++20 module and +make the `Boost::lexical_cast` CMake target provide it. After that an explicit usage of C++20 module `boost.lexical_cast` is allowed: + +[import ../modules/usage_sample.cpp] +[lexical_cast_module_example] + +The `Boost::lexical_cast` CMake target gives an ability to mix includes and imports of the library in different translation units. Moreover, +if `BOOST_USE_MODULES` macro is defined then all the `boost/lexical_cast...` includes implicitly do `import boost.lexical_cast;` to give all the +benefits of modules without changing the existing code. + +[note For better compile times make sure that `import std;` is available when building the `boost.lexical_cast` module (in CMake logs there should be + a 'Using `import std;`' message). ] + +If not using CMake, then the module could be build manually from the `modules/boost_lexical_cast.cppm` file. + +For manual module build the following commands could be used for clang compiler: + +``` +cd lexical_cast/modules +clang++ -I ../include -std=c++20 --precompile -x c++-module boost_lexical_cast.cppm +``` + +After that, the module could be used in the following way: + +``` +clang++ -std=c++20 -fmodule-file=boost_lexical_cast.pcm boost_lexical_cast.pcm usage_sample.cpp +``` + +[endsect] + [section Changes] +* [*boost 1.91.0 :] + * Added C++20 modules support. + * [*boost 1.86.0 :] * Fixed conversion of `std::basic_string_view` and `boost::basic_string_view` diff --git a/include/boost/lexical_cast.hpp b/include/boost/lexical_cast.hpp index 1e61e76..96fe093 100644 --- a/include/boost/lexical_cast.hpp +++ b/include/boost/lexical_cast.hpp @@ -18,10 +18,16 @@ #ifndef BOOST_LEXICAL_CAST_INCLUDED #define BOOST_LEXICAL_CAST_INCLUDED +#include + +#if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + +#ifndef BOOST_LEXICAL_CAST_INTERFACE_UNIT #include #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once #endif +#endif #if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING) #define BOOST_LCAST_NO_WCHAR_T @@ -34,6 +40,7 @@ namespace boost { +BOOST_LEXICAL_CAST_BEGIN_MODULE_EXPORT template inline Target lexical_cast(const Source &arg) { @@ -94,9 +101,12 @@ namespace boost ); } +BOOST_LEXICAL_CAST_END_MODULE_EXPORT } // namespace boost #undef BOOST_LCAST_NO_WCHAR_T +#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + #endif // BOOST_LEXICAL_CAST_INCLUDED diff --git a/include/boost/lexical_cast/bad_lexical_cast.hpp b/include/boost/lexical_cast/bad_lexical_cast.hpp index 11eba7b..0b52ecf 100644 --- a/include/boost/lexical_cast/bad_lexical_cast.hpp +++ b/include/boost/lexical_cast/bad_lexical_cast.hpp @@ -18,6 +18,11 @@ #ifndef BOOST_LEXICAL_CAST_BAD_LEXICAL_CAST_HPP #define BOOST_LEXICAL_CAST_BAD_LEXICAL_CAST_HPP +#include + +#if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + +#ifndef BOOST_LEXICAL_CAST_INTERFACE_UNIT #include #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once @@ -26,9 +31,11 @@ #include #include #include +#endif namespace boost { +BOOST_LEXICAL_CAST_BEGIN_MODULE_EXPORT // exception used to indicate runtime lexical_cast failure class BOOST_SYMBOL_VISIBLE bad_lexical_cast : // workaround MSVC bug with std::bad_cast when _HAS_EXCEPTIONS == 0 @@ -80,6 +87,7 @@ namespace boost const type_info_t *target; #endif }; +BOOST_LEXICAL_CAST_END_MODULE_EXPORT namespace conversion { namespace detail { #ifdef BOOST_NO_TYPEID @@ -97,4 +105,6 @@ namespace boost } // namespace boost +#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + #endif // BOOST_LEXICAL_CAST_BAD_LEXICAL_CAST_HPP diff --git a/include/boost/lexical_cast/detail/buffer_view.hpp b/include/boost/lexical_cast/detail/buffer_view.hpp index 36624c6..fc330da 100644 --- a/include/boost/lexical_cast/detail/buffer_view.hpp +++ b/include/boost/lexical_cast/detail/buffer_view.hpp @@ -7,12 +7,18 @@ #ifndef BOOST_LEXICAL_CAST_DETAIL_BUFFER_VIEW_HPP #define BOOST_LEXICAL_CAST_DETAIL_BUFFER_VIEW_HPP +#include + +#if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + +#ifndef BOOST_LEXICAL_CAST_INTERFACE_UNIT #include #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once #endif #include +#endif namespace boost { namespace conversion { namespace detail { @@ -55,5 +61,7 @@ namespace boost { namespace conversion { namespace detail { }}} // namespace boost::conversion::detail +#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + #endif // BOOST_LEXICAL_CAST_DETAIL_BUFFER_VIEW_HPP diff --git a/include/boost/lexical_cast/detail/config.hpp b/include/boost/lexical_cast/detail/config.hpp new file mode 100644 index 0000000..b32812b --- /dev/null +++ b/include/boost/lexical_cast/detail/config.hpp @@ -0,0 +1,22 @@ +// Copyright Antony Polukhin, 2021-2025. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_LEXICAL_CAST_DETAIL_CONFIG_HPP +#define BOOST_LEXICAL_CAST_DETAIL_CONFIG_HPP + +#ifdef BOOST_LEXICAL_CAST_INTERFACE_UNIT +# define BOOST_LEXICAL_CAST_BEGIN_MODULE_EXPORT export { +# define BOOST_LEXICAL_CAST_END_MODULE_EXPORT } +#else +# define BOOST_LEXICAL_CAST_BEGIN_MODULE_EXPORT +# define BOOST_LEXICAL_CAST_END_MODULE_EXPORT +#endif + +#if defined(BOOST_USE_MODULES) && !defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) +import boost.lexical_cast; +#endif + +#endif // #ifndef BOOST_LEXICAL_CAST_DETAIL_CONFIG_HPP diff --git a/include/boost/lexical_cast/detail/converter_lexical.hpp b/include/boost/lexical_cast/detail/converter_lexical.hpp index dd292b3..e402f61 100644 --- a/include/boost/lexical_cast/detail/converter_lexical.hpp +++ b/include/boost/lexical_cast/detail/converter_lexical.hpp @@ -18,6 +18,11 @@ #ifndef BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP #define BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP +#include + +#if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + +#ifndef BOOST_LEXICAL_CAST_INTERFACE_UNIT #include #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once @@ -27,15 +32,11 @@ #define BOOST_LCAST_NO_WCHAR_T #endif +#include #include #include #include #include -#include - -#include -#include -#include #include @@ -43,9 +44,14 @@ #include #endif -#include #include +#endif // #ifndef BOOST_LEXICAL_CAST_INTERFACE_UNIT + +#include +#include +#include +#include #include namespace boost { @@ -479,5 +485,7 @@ namespace boost { #undef BOOST_LCAST_NO_WCHAR_T +#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + #endif // BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP diff --git a/include/boost/lexical_cast/detail/converter_lexical_streams.hpp b/include/boost/lexical_cast/detail/converter_lexical_streams.hpp index 545d3cc..85da9d4 100644 --- a/include/boost/lexical_cast/detail/converter_lexical_streams.hpp +++ b/include/boost/lexical_cast/detail/converter_lexical_streams.hpp @@ -18,12 +18,16 @@ #ifndef BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_STREAMS_HPP #define BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_STREAMS_HPP +#include + +#if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + +#ifndef BOOST_LEXICAL_CAST_INTERFACE_UNIT #include #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once #endif - #if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_WSTRING) #define BOOST_LCAST_NO_WCHAR_T #endif @@ -33,9 +37,8 @@ #include #include #include + #include -#include -#include #include #include @@ -58,21 +61,28 @@ #include #endif -#include -#include -#include -#include -#include - -#include #include +#ifndef BOOST_NO_CWCHAR +# include +#endif +#include #include #ifndef BOOST_NO_CWCHAR # include #endif +#endif // #ifndef BOOST_LEXICAL_CAST_INTERFACE_UNIT + +#include +#include +#include +#include +#include +#include +#include + // Forward declarations namespace boost { template @@ -747,5 +757,7 @@ namespace boost { namespace detail { namespace lcast { #undef BOOST_LCAST_NO_WCHAR_T +#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + #endif // BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_HPP diff --git a/include/boost/lexical_cast/detail/converter_numeric.hpp b/include/boost/lexical_cast/detail/converter_numeric.hpp index 1d22ae5..eb4163c 100644 --- a/include/boost/lexical_cast/detail/converter_numeric.hpp +++ b/include/boost/lexical_cast/detail/converter_numeric.hpp @@ -18,6 +18,11 @@ #ifndef BOOST_LEXICAL_CAST_DETAIL_CONVERTER_NUMERIC_HPP #define BOOST_LEXICAL_CAST_DETAIL_CONVERTER_NUMERIC_HPP +#include + +#if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + +#ifndef BOOST_LEXICAL_CAST_INTERFACE_UNIT #include #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once @@ -26,6 +31,9 @@ #include #include #include + +#endif // #ifndef BOOST_LEXICAL_CAST_INTERFACE_UNIT + #include namespace boost { namespace detail { @@ -176,5 +184,7 @@ struct dynamic_num_converter_impl }} // namespace boost::detail +#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + #endif // BOOST_LEXICAL_CAST_DETAIL_CONVERTER_NUMERIC_HPP diff --git a/include/boost/lexical_cast/detail/inf_nan.hpp b/include/boost/lexical_cast/detail/inf_nan.hpp index 68546e6..943f625 100644 --- a/include/boost/lexical_cast/detail/inf_nan.hpp +++ b/include/boost/lexical_cast/detail/inf_nan.hpp @@ -18,6 +18,11 @@ #ifndef BOOST_LEXICAL_CAST_DETAIL_INF_NAN_HPP #define BOOST_LEXICAL_CAST_DETAIL_INF_NAN_HPP +#include + +#if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + +#ifndef BOOST_LEXICAL_CAST_INTERFACE_UNIT #include #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once @@ -32,6 +37,7 @@ #include #include #include +#endif // #ifndef BOOST_LEXICAL_CAST_INTERFACE_UNIT #include @@ -183,5 +189,7 @@ namespace boost { #undef BOOST_LCAST_NO_WCHAR_T +#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + #endif // BOOST_LEXICAL_CAST_DETAIL_INF_NAN_HPP diff --git a/include/boost/lexical_cast/detail/is_character.hpp b/include/boost/lexical_cast/detail/is_character.hpp index ff7d0df..4994c47 100644 --- a/include/boost/lexical_cast/detail/is_character.hpp +++ b/include/boost/lexical_cast/detail/is_character.hpp @@ -18,13 +18,20 @@ #ifndef BOOST_LEXICAL_CAST_DETAIL_IS_CHARACTER_HPP #define BOOST_LEXICAL_CAST_DETAIL_IS_CHARACTER_HPP -#include +#include +#if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + +#ifndef BOOST_LEXICAL_CAST_INTERFACE_UNIT #include #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once #endif +#include + +#endif // #ifndef BOOST_LEXICAL_CAST_INTERFACE_UNIT + namespace boost { namespace detail { // returns true, if T is one of the character types @@ -47,5 +54,7 @@ using is_character = std::integral_constant< }} +#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + #endif // BOOST_LEXICAL_CAST_DETAIL_IS_CHARACTER_HPP diff --git a/include/boost/lexical_cast/detail/lcast_basic_unlockedbuf.hpp b/include/boost/lexical_cast/detail/lcast_basic_unlockedbuf.hpp index 141d3c6..fdae8eb 100644 --- a/include/boost/lexical_cast/detail/lcast_basic_unlockedbuf.hpp +++ b/include/boost/lexical_cast/detail/lcast_basic_unlockedbuf.hpp @@ -9,6 +9,12 @@ #ifndef BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_BASIC_UNLOCKEDBUF_HPP #define BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_BASIC_UNLOCKEDBUF_HPP +#include + +#if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + +#ifndef BOOST_LEXICAL_CAST_INTERFACE_UNIT + #include #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once @@ -25,6 +31,7 @@ #ifndef BOOST_NO_CWCHAR # include #endif +#endif // #ifndef BOOST_LEXICAL_CAST_INTERFACE_UNIT namespace boost { namespace detail { namespace lcast { @@ -69,5 +76,7 @@ namespace boost { namespace detail { namespace lcast { }}} // namespace boost::detail::lcast +#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + #endif // BOOST_LEXICAL_CAST_DETAIL_CONVERTER_LEXICAL_BASIC_UNLOCKEDBUF_HPP diff --git a/include/boost/lexical_cast/detail/lcast_char_constants.hpp b/include/boost/lexical_cast/detail/lcast_char_constants.hpp index d6b5cf2..211e9ed 100644 --- a/include/boost/lexical_cast/detail/lcast_char_constants.hpp +++ b/include/boost/lexical_cast/detail/lcast_char_constants.hpp @@ -18,10 +18,16 @@ #ifndef BOOST_LEXICAL_CAST_DETAIL_LCAST_CHAR_CONSTANTS_HPP #define BOOST_LEXICAL_CAST_DETAIL_LCAST_CHAR_CONSTANTS_HPP +#include + +#if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + +#ifndef BOOST_LEXICAL_CAST_INTERFACE_UNIT #include #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once #endif +#endif // #ifndef BOOST_LEXICAL_CAST_INTERFACE_UNIT namespace boost { @@ -41,6 +47,7 @@ namespace boost } } // namespace boost +#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) #endif // BOOST_LEXICAL_CAST_DETAIL_LCAST_CHAR_CONSTANTS_HPP diff --git a/include/boost/detail/lcast_precision.hpp b/include/boost/lexical_cast/detail/lcast_precision.hpp similarity index 86% rename from include/boost/detail/lcast_precision.hpp rename to include/boost/lexical_cast/detail/lcast_precision.hpp index e555141..372deab 100644 --- a/include/boost/detail/lcast_precision.hpp +++ b/include/boost/lexical_cast/detail/lcast_precision.hpp @@ -8,11 +8,21 @@ #ifndef BOOST_DETAIL_LCAST_PRECISION_HPP_INCLUDED #define BOOST_DETAIL_LCAST_PRECISION_HPP_INCLUDED +#include + +#if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + +#ifndef BOOST_LEXICAL_CAST_INTERFACE_UNIT +#include +#ifdef BOOST_HAS_PRAGMA_ONCE +# pragma once +#endif + #include #include #include -#include +#endif // #ifndef BOOST_LEXICAL_CAST_INTERFACE_UNIT namespace boost { namespace detail { @@ -79,5 +89,7 @@ inline void lcast_set_precision(std::ios_base& stream, Source*, Target*) }} +#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + #endif // BOOST_DETAIL_LCAST_PRECISION_HPP_INCLUDED diff --git a/include/boost/lexical_cast/detail/lcast_unsigned_converters.hpp b/include/boost/lexical_cast/detail/lcast_unsigned_converters.hpp index 275ea36..85f81a2 100644 --- a/include/boost/lexical_cast/detail/lcast_unsigned_converters.hpp +++ b/include/boost/lexical_cast/detail/lcast_unsigned_converters.hpp @@ -18,6 +18,11 @@ #ifndef BOOST_LEXICAL_CAST_DETAIL_LCAST_UNSIGNED_CONVERTERS_HPP #define BOOST_LEXICAL_CAST_DETAIL_LCAST_UNSIGNED_CONVERTERS_HPP +#include + +#if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + +#ifndef BOOST_LEXICAL_CAST_INTERFACE_UNIT #include #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once @@ -49,6 +54,9 @@ #include #include +#endif // #ifndef BOOST_LEXICAL_CAST_INTERFACE_UNIT + +#include namespace boost { @@ -294,5 +302,7 @@ namespace boost } } // namespace boost +#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + #endif // BOOST_LEXICAL_CAST_DETAIL_LCAST_UNSIGNED_CONVERTERS_HPP diff --git a/include/boost/lexical_cast/detail/widest_char.hpp b/include/boost/lexical_cast/detail/widest_char.hpp index b086eba..9b7e536 100644 --- a/include/boost/lexical_cast/detail/widest_char.hpp +++ b/include/boost/lexical_cast/detail/widest_char.hpp @@ -18,13 +18,19 @@ #ifndef BOOST_LEXICAL_CAST_DETAIL_WIDEST_CHAR_HPP #define BOOST_LEXICAL_CAST_DETAIL_WIDEST_CHAR_HPP -#include +#include +#if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + +#ifndef BOOST_LEXICAL_CAST_INTERFACE_UNIT #include #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once #endif +#include + +#endif // #ifndef BOOST_LEXICAL_CAST_INTERFACE_UNIT namespace boost { namespace detail { @@ -37,5 +43,7 @@ using widest_char = std::conditional< }} // namespace boost::detail +#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + #endif // BOOST_LEXICAL_CAST_DETAIL_WIDEST_CHAR_HPP diff --git a/include/boost/lexical_cast/try_lexical_convert.hpp b/include/boost/lexical_cast/try_lexical_convert.hpp index 2acc3cd..be16ad7 100644 --- a/include/boost/lexical_cast/try_lexical_convert.hpp +++ b/include/boost/lexical_cast/try_lexical_convert.hpp @@ -18,13 +18,19 @@ #ifndef BOOST_LEXICAL_CAST_TRY_LEXICAL_CONVERT_HPP #define BOOST_LEXICAL_CAST_TRY_LEXICAL_CONVERT_HPP -#include +#include +#if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + +#ifndef BOOST_LEXICAL_CAST_INTERFACE_UNIT #include #ifdef BOOST_HAS_PRAGMA_ONCE # pragma once #endif +#include +#endif + #include #include #include @@ -45,6 +51,8 @@ namespace boost { namespace conversion { namespace detail { +BOOST_LEXICAL_CAST_BEGIN_MODULE_EXPORT + template inline bool try_lexical_convert(const Source& arg, Target& result) { @@ -78,15 +86,20 @@ namespace boost { result ); } +BOOST_LEXICAL_CAST_END_MODULE_EXPORT }} // namespace conversion::detail namespace conversion { +BOOST_LEXICAL_CAST_BEGIN_MODULE_EXPORT // ADL barrier using ::boost::conversion::detail::try_lexical_convert; +BOOST_LEXICAL_CAST_END_MODULE_EXPORT } } // namespace boost +#endif // #if !defined(BOOST_USE_MODULES) || defined(BOOST_LEXICAL_CAST_INTERFACE_UNIT) + #endif // BOOST_LEXICAL_CAST_TRY_LEXICAL_CONVERT_HPP diff --git a/modules/boost_lexical_cast.cppm b/modules/boost_lexical_cast.cppm new file mode 100644 index 0000000..55507c1 --- /dev/null +++ b/modules/boost_lexical_cast.cppm @@ -0,0 +1,57 @@ +// Copyright (c) 2016-2025 Antony Polukhin +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// To compile manually use a command like the folowing: +// clang++ -I ../include -std=c++20 --precompile -x c++-module boost_lexical_cast.cppm + +module; + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifndef BOOST_LEXICAL_CAST_USE_STD_MODULE +#include +#include +#include +#include +#include +#ifndef BOOST_NO_CWCHAR +# include +#endif +#include +#include +#include +#ifndef BOOST_NO_STD_LOCALE +# include +#endif +#include +#include +#include +#include +#include +#endif + +#define BOOST_LEXICAL_CAST_INTERFACE_UNIT + +export module boost.lexical_cast; + +#ifdef BOOST_LEXICAL_CAST_USE_STD_MODULE +import std; +#endif + +#ifdef __clang__ +# pragma clang diagnostic ignored "-Winclude-angled-in-module-purview" +#endif + +#include diff --git a/modules/usage_sample.cpp b/modules/usage_sample.cpp new file mode 100644 index 0000000..71a85fe --- /dev/null +++ b/modules/usage_sample.cpp @@ -0,0 +1,16 @@ +// Copyright (c) 2024-2025 Antony Polukhin +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// To compile manually use a command like the following: +// clang++ -std=c++20 -fmodule-file=lexical_cast.pcm lexical_cast.pcm usage_sample.cpp + +//[lexical_cast_module_example +import boost.lexical_cast; + +int main() { + return boost::lexical_cast("0"); +} +//] + diff --git a/test/cmake_subdir_test/CMakeLists.txt b/test/cmake_subdir_test/CMakeLists.txt new file mode 100644 index 0000000..b84f35e --- /dev/null +++ b/test/cmake_subdir_test/CMakeLists.txt @@ -0,0 +1,53 @@ +# Copyright (c) 2016-2025 Antony Polukhin +# Distributed under the Boost Software License, Version 1.0. +# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt + +cmake_minimum_required(VERSION 3.5...4.0) + +project(lexical_cast_subdir_test LANGUAGES CXX) + +add_subdirectory(../../../assert boostorg/assert) +add_subdirectory(../../../core boostorg/core) +add_subdirectory(../../../config boostorg/config) +add_subdirectory(../../../container boostorg/container) +add_subdirectory(../../../container_hash boostorg/container_hash) +add_subdirectory(../../../detail boostorg/detail) +add_subdirectory(../../../intrusive boostorg/intrusive) +add_subdirectory(../../../move boostorg/move) +add_subdirectory(../../../static_assert boostorg/static_assert) +add_subdirectory(../../../throw_exception boostorg/throw_exception) +add_subdirectory(../../../type_traits boostorg/type_traits) + +add_subdirectory(../../ boostorg/lexical_cast) + +enable_testing() + +if (BOOST_USE_MODULES) + add_executable(boost_lexical_cast_module_usage ../modules/usage_sample.cpp) + target_link_libraries(boost_lexical_cast_module_usage PRIVATE Boost::lexical_cast) + add_test(NAME boost_lexical_cast_module_usage COMMAND boost_lexical_cast_module_usage) +endif() + +list(APPEND RUN_TESTS_SOURCES + lexical_cast_test.cpp + loopback_test.cpp + abstract_test.cpp + noncopyable_test.cpp + vc8_bug_test.cpp + implicit_convert.cpp + float_types_test.cpp + inf_nan_test.cpp + containers_test.cpp + pointers_test.cpp + integral_types_test.cpp + stream_detection_test.cpp + try_lexical_convert.cpp +) + +foreach (testsourcefile ${RUN_TESTS_SOURCES}) + get_filename_component(testname ${testsourcefile} NAME_WLE) + add_executable(${PROJECT_NAME}_${testname} ../${testsourcefile}) + target_link_libraries(${PROJECT_NAME}_${testname} Boost::lexical_cast Boost::type_traits Boost::core) + add_test(NAME ${PROJECT_NAME}_${testname} COMMAND ${PROJECT_NAME}_${testname}) +endforeach() + diff --git a/test/float_types_test.cpp b/test/float_types_test.cpp index 3ff0b72..541ceb8 100644 --- a/test/float_types_test.cpp +++ b/test/float_types_test.cpp @@ -15,6 +15,7 @@ #include "lexical_cast_old.hpp" #endif +#include #include #include diff --git a/test/integral_types_test.cpp b/test/integral_types_test.cpp index cbaaeda..721bdee 100644 --- a/test/integral_types_test.cpp +++ b/test/integral_types_test.cpp @@ -29,6 +29,7 @@ #include #include +#include #include #include #include diff --git a/test/lexical_cast_old.hpp b/test/lexical_cast_old.hpp index 207c697..caa16ca 100644 --- a/test/lexical_cast_old.hpp +++ b/test/lexical_cast_old.hpp @@ -34,7 +34,6 @@ #include #include #include -#include #include #ifdef BOOST_NO_STRINGSTREAM @@ -43,6 +42,7 @@ #include #endif +#include #include #include diff --git a/test/pointers_test.cpp b/test/pointers_test.cpp index c06003f..94a997f 100644 --- a/test/pointers_test.cpp +++ b/test/pointers_test.cpp @@ -12,6 +12,8 @@ #include +#include + #if defined(BOOST_NO_STRINGSTREAM) typedef std::strstream ss_t; #else diff --git a/test/vc8_bug_test.cpp b/test/vc8_bug_test.cpp index 281c7e5..6ceadba 100644 --- a/test/vc8_bug_test.cpp +++ b/test/vc8_bug_test.cpp @@ -18,6 +18,7 @@ #include #include +#include #ifdef BOOST_MSVC # pragma warning(disable: 4127) // conditional expression is constant