From 60391652fa92b7a237583f00c863caa78ab8a0f1 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Thu, 15 Aug 2024 10:59:07 +0300 Subject: [PATCH] Initial support for C++20 modules (#177) --- CMakeLists.txt | 13 +++--- doc/pfr.qbk | 34 ++++++++++++++ include/boost/pfr/config.hpp | 8 ++++ include/boost/pfr/core.hpp | 4 ++ include/boost/pfr/core_name.hpp | 4 ++ include/boost/pfr/detail/core14_classic.hpp | 4 ++ include/boost/pfr/detail/core14_loophole.hpp | 4 ++ include/boost/pfr/detail/core17_generated.hpp | 5 +++ .../boost/pfr/detail/core_name20_static.hpp | 5 +++ include/boost/pfr/detail/detectors.hpp | 4 ++ include/boost/pfr/detail/fields_count.hpp | 4 ++ .../boost/pfr/detail/for_each_field_impl.hpp | 4 ++ include/boost/pfr/detail/functional.hpp | 4 ++ include/boost/pfr/detail/io.hpp | 6 +++ .../detail/make_flat_tuple_of_references.hpp | 5 +++ .../pfr/detail/make_integer_sequence.hpp | 4 ++ .../boost/pfr/detail/offset_based_getter.hpp | 5 +++ .../boost/pfr/detail/possible_reflectable.hpp | 4 ++ include/boost/pfr/detail/rvalue_t.hpp | 4 ++ include/boost/pfr/detail/sequence_tuple.hpp | 4 ++ include/boost/pfr/detail/size_array.hpp | 6 ++- include/boost/pfr/detail/stdarray.hpp | 4 ++ include/boost/pfr/detail/stdtuple.hpp | 4 ++ .../pfr/detail/tie_from_structure_tuple.hpp | 4 ++ include/boost/pfr/detail/unsafe_declval.hpp | 4 ++ include/boost/pfr/functors.hpp | 4 ++ include/boost/pfr/io.hpp | 8 ++++ include/boost/pfr/io_fields.hpp | 8 ++++ include/boost/pfr/ops.hpp | 3 ++ include/boost/pfr/ops_fields.hpp | 5 +++ include/boost/pfr/traits.hpp | 4 ++ include/boost/pfr/traits_fwd.hpp | 4 ++ include/boost/pfr/tuple_size.hpp | 4 ++ misc/generate_cpp17.py | 5 +++ module/CMakeLists.txt | 37 ++++++++++++++++ module/pfr.cppm | 44 +++++++++++++++++++ module/usage_sample.cpp | 31 +++++++++++++ module/usage_test_mu1.cpp | 27 ++++++++++++ module/usage_test_mu2.cpp | 32 ++++++++++++++ 39 files changed, 361 insertions(+), 6 deletions(-) create mode 100644 module/CMakeLists.txt create mode 100644 module/pfr.cppm create mode 100644 module/usage_sample.cpp create mode 100644 module/usage_test_mu1.cpp create mode 100644 module/usage_test_mu2.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d8a636f..7bdbd78 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,6 @@ -# Generated by `boostdep --cmake pfr` # Copyright 2020 Peter Dimov +# Copyright (c) 2016-2024 Antony Polukhin +# # Distributed under the Boost Software License, Version 1.0. # https://www.boost.org/LICENSE_1_0.txt @@ -12,9 +13,11 @@ add_library(Boost::pfr ALIAS boost_pfr) target_include_directories(boost_pfr INTERFACE include) -if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt") - - add_subdirectory(test) - +if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.28.0" AND BUILD_MODULE) + add_subdirectory(module) +endif() + +if (BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt") + add_subdirectory(test) endif() diff --git a/doc/pfr.qbk b/doc/pfr.qbk index a06f212..567d2e9 100644 --- a/doc/pfr.qbk +++ b/doc/pfr.qbk @@ -549,6 +549,40 @@ parameters provided to `BOOST_PFR_CORE_NAME_PARSING` macro [*and] the initial ou [endsect] +[section PFR as a C++20 module] + +[caution C++20 PFR module support is on early stage, targets and flags may change in the future] + +If using CMake of version 3.28.0 or higher define CMake option `-DBUILD_MODULE=1` +to make the `Boost::pfr_module` and `Boost::pfr_module_migration` libraries +available. With `Boost::pfr_module` C++20 module Boost.PFR could be used: + +[import ../module/usage_sample.cpp] +[pfr_module_example] + +The `Boost::pfr_module_migration` CMake target gives an ability to +mix includes and imports of the PFR library in different translation units. + +If not using CMake, then the module could be build manually from the +`module/pfr.cppm` file. If mixing of includes in imports is desired, additionally +define `BOOST_PFR_ATTACH_TO_GLOBAL_MODULE` preprocessor macro to attach all the +module entities to a global module and avoid ODR issues. + +For manual module build the following commands could be used for clang compiler: + +``` +cd pfr/module +clang++ -I ../include -std=c++20 --precompile -x c++-module pfr.cppm +``` + +After that, the module could be used in the following way: + +``` +clang++ -std=c++20 -fmodule-file=pfr.pcm pfr.pcm usage_sample.cpp +``` + +[endsect] + [section How it works] [h2 Fields count detection and getting references to members] diff --git a/include/boost/pfr/config.hpp b/include/boost/pfr/config.hpp index 253ebc0..9d41055 100644 --- a/include/boost/pfr/config.hpp +++ b/include/boost/pfr/config.hpp @@ -145,4 +145,12 @@ #undef BOOST_PFR_NOT_SUPPORTED +#ifndef BOOST_PFR_BEGIN_MODULE_EXPORT +# define BOOST_PFR_BEGIN_MODULE_EXPORT +#endif + +#ifndef BOOST_PFR_END_MODULE_EXPORT +# define BOOST_PFR_END_MODULE_EXPORT +#endif + #endif // BOOST_PFR_CONFIG_HPP diff --git a/include/boost/pfr/core.hpp b/include/boost/pfr/core.hpp index 5a8e1df..555e165 100644 --- a/include/boost/pfr/core.hpp +++ b/include/boost/pfr/core.hpp @@ -29,6 +29,8 @@ namespace boost { namespace pfr { +BOOST_PFR_BEGIN_MODULE_EXPORT + /// \brief Returns reference or const reference to a field with index `I` in \aggregate `val`. /// Overload taking the type `U` returns reference or const reference to a field /// with provided type `U` in \aggregate `val` if there's only one field of such type in `val`. @@ -260,6 +262,8 @@ constexpr detail::tie_from_structure_tuple tie_from_structure(Eleme return detail::tie_from_structure_tuple(args...); } +BOOST_PFR_END_MODULE_EXPORT + }} // namespace boost::pfr #endif // BOOST_PFR_CORE_HPP diff --git a/include/boost/pfr/core_name.hpp b/include/boost/pfr/core_name.hpp index 8b0d012..0b11d54 100644 --- a/include/boost/pfr/core_name.hpp +++ b/include/boost/pfr/core_name.hpp @@ -33,6 +33,8 @@ namespace boost { namespace pfr { +BOOST_PFR_BEGIN_MODULE_EXPORT + /// \brief Returns name of a field with index `I` in \aggregate `T`. /// /// \b Example: @@ -82,6 +84,8 @@ names_as_array() noexcept { ); } +BOOST_PFR_END_MODULE_EXPORT + }} // namespace boost::pfr #endif // BOOST_PFR_CORE_NAME_HPP diff --git a/include/boost/pfr/detail/core14_classic.hpp b/include/boost/pfr/detail/core14_classic.hpp index 3dcf3f4..38b7ecb 100644 --- a/include/boost/pfr/detail/core14_classic.hpp +++ b/include/boost/pfr/detail/core14_classic.hpp @@ -9,8 +9,12 @@ #include +#ifdef BOOST_PFR_HAS_STD_MODULE +import std; +#else #include #include // metaprogramming stuff +#endif #include #include diff --git a/include/boost/pfr/detail/core14_loophole.hpp b/include/boost/pfr/detail/core14_loophole.hpp index bac7672..895af18 100644 --- a/include/boost/pfr/detail/core14_loophole.hpp +++ b/include/boost/pfr/detail/core14_loophole.hpp @@ -24,8 +24,12 @@ #include +#ifdef BOOST_PFR_HAS_STD_MODULE +import std; +#else #include #include +#endif #include #include diff --git a/include/boost/pfr/detail/core17_generated.hpp b/include/boost/pfr/detail/core17_generated.hpp index ed1fa45..9330584 100644 --- a/include/boost/pfr/detail/core17_generated.hpp +++ b/include/boost/pfr/detail/core17_generated.hpp @@ -21,7 +21,12 @@ #include #include + +#ifdef BOOST_PFR_HAS_STD_MODULE +import std; +#else #include // for std::conditional_t, std::is_reference +#endif namespace boost { namespace pfr { namespace detail { diff --git a/include/boost/pfr/detail/core_name20_static.hpp b/include/boost/pfr/detail/core_name20_static.hpp index 18edad2..8b8f470 100644 --- a/include/boost/pfr/detail/core_name20_static.hpp +++ b/include/boost/pfr/detail/core_name20_static.hpp @@ -19,10 +19,15 @@ #include #include #include + +#ifdef BOOST_PFR_HAS_STD_MODULE +import std; +#else #include #include #include #include // for std::addressof +#endif namespace boost { namespace pfr { namespace detail { diff --git a/include/boost/pfr/detail/detectors.hpp b/include/boost/pfr/detail/detectors.hpp index db41237..2dba11a 100644 --- a/include/boost/pfr/detail/detectors.hpp +++ b/include/boost/pfr/detail/detectors.hpp @@ -9,8 +9,12 @@ #include +#ifdef BOOST_PFR_HAS_STD_MODULE +import std; +#else #include #include +#endif namespace boost { namespace pfr { namespace detail { ///////////////////// `value` is true if Detector does not compile (SFINAE) diff --git a/include/boost/pfr/detail/fields_count.hpp b/include/boost/pfr/detail/fields_count.hpp index 8d1354e..a16b194 100644 --- a/include/boost/pfr/detail/fields_count.hpp +++ b/include/boost/pfr/detail/fields_count.hpp @@ -12,9 +12,13 @@ #include #include +#ifdef BOOST_PFR_HAS_STD_MODULE +import std; +#else #include // CHAR_BIT #include #include // metaprogramming stuff +#endif #ifdef __clang__ # pragma clang diagnostic push diff --git a/include/boost/pfr/detail/for_each_field_impl.hpp b/include/boost/pfr/detail/for_each_field_impl.hpp index dc9db77..c9d801e 100644 --- a/include/boost/pfr/detail/for_each_field_impl.hpp +++ b/include/boost/pfr/detail/for_each_field_impl.hpp @@ -9,7 +9,11 @@ #include +#ifdef BOOST_PFR_HAS_STD_MODULE +import std; +#else #include // metaprogramming stuff +#endif #include #include diff --git a/include/boost/pfr/detail/functional.hpp b/include/boost/pfr/detail/functional.hpp index a78e303..90ae983 100644 --- a/include/boost/pfr/detail/functional.hpp +++ b/include/boost/pfr/detail/functional.hpp @@ -9,8 +9,12 @@ #include +#ifdef BOOST_PFR_HAS_STD_MODULE +import std; +#else #include #include +#endif #include diff --git a/include/boost/pfr/detail/io.hpp b/include/boost/pfr/detail/io.hpp index ff860ab..58eed5e 100644 --- a/include/boost/pfr/detail/io.hpp +++ b/include/boost/pfr/detail/io.hpp @@ -10,6 +10,10 @@ #include #include + +#ifdef BOOST_PFR_HAS_STD_MODULE +import std; +#else #include // stream operators #include @@ -19,6 +23,8 @@ # endif #endif +#endif + namespace boost { namespace pfr { namespace detail { inline auto quoted_helper(const std::string& s) noexcept { diff --git a/include/boost/pfr/detail/make_flat_tuple_of_references.hpp b/include/boost/pfr/detail/make_flat_tuple_of_references.hpp index ecc63f7..8db4560 100644 --- a/include/boost/pfr/detail/make_flat_tuple_of_references.hpp +++ b/include/boost/pfr/detail/make_flat_tuple_of_references.hpp @@ -9,7 +9,12 @@ #include +#ifdef BOOST_PFR_HAS_STD_MODULE +import std; +#else #include // metaprogramming stuff +#endif + #include #include #include diff --git a/include/boost/pfr/detail/make_integer_sequence.hpp b/include/boost/pfr/detail/make_integer_sequence.hpp index 3e17872..3992807 100644 --- a/include/boost/pfr/detail/make_integer_sequence.hpp +++ b/include/boost/pfr/detail/make_integer_sequence.hpp @@ -10,9 +10,13 @@ #include +#ifdef BOOST_PFR_HAS_STD_MODULE +import std; +#else #include #include #include +#endif namespace boost { namespace pfr { namespace detail { diff --git a/include/boost/pfr/detail/offset_based_getter.hpp b/include/boost/pfr/detail/offset_based_getter.hpp index d557cd9..2412324 100644 --- a/include/boost/pfr/detail/offset_based_getter.hpp +++ b/include/boost/pfr/detail/offset_based_getter.hpp @@ -10,9 +10,14 @@ #include +#ifdef BOOST_PFR_HAS_STD_MODULE +import std; +#else #include #include #include // std::addressof +#endif + #include #include #include diff --git a/include/boost/pfr/detail/possible_reflectable.hpp b/include/boost/pfr/detail/possible_reflectable.hpp index a47c2ce..9081d30 100644 --- a/include/boost/pfr/detail/possible_reflectable.hpp +++ b/include/boost/pfr/detail/possible_reflectable.hpp @@ -10,7 +10,11 @@ #include #include +#ifdef BOOST_PFR_HAS_STD_MODULE +import std; +#else #include // for std::is_aggregate +#endif namespace boost { namespace pfr { namespace detail { diff --git a/include/boost/pfr/detail/rvalue_t.hpp b/include/boost/pfr/detail/rvalue_t.hpp index 0044eea..23d25e4 100644 --- a/include/boost/pfr/detail/rvalue_t.hpp +++ b/include/boost/pfr/detail/rvalue_t.hpp @@ -7,8 +7,12 @@ #define BOOST_PFR_DETAIL_RVALUE_T_HPP #pragma once +#ifdef BOOST_PFR_HAS_STD_MODULE +import std; +#else #include #include // std::enable_if_t +#endif // This header provides aliases rvalue_t and lvalue_t. // diff --git a/include/boost/pfr/detail/sequence_tuple.hpp b/include/boost/pfr/detail/sequence_tuple.hpp index 5032b86..0217c21 100644 --- a/include/boost/pfr/detail/sequence_tuple.hpp +++ b/include/boost/pfr/detail/sequence_tuple.hpp @@ -10,8 +10,12 @@ #include #include +#ifdef BOOST_PFR_HAS_STD_MODULE +import std; +#else #include // metaprogramming stuff #include // std::size_t +#endif ///////////////////// Tuple that holds its values in the supplied order namespace boost { namespace pfr { namespace detail { namespace sequence_tuple { diff --git a/include/boost/pfr/detail/size_array.hpp b/include/boost/pfr/detail/size_array.hpp index f9c174e..35c4377 100644 --- a/include/boost/pfr/detail/size_array.hpp +++ b/include/boost/pfr/detail/size_array.hpp @@ -9,7 +9,11 @@ #include -#include // metaprogramming stuff +#ifdef BOOST_PFR_HAS_STD_MODULE +import std; +#else +#include +#endif namespace boost { namespace pfr { namespace detail { diff --git a/include/boost/pfr/detail/stdarray.hpp b/include/boost/pfr/detail/stdarray.hpp index c791f42..77202b7 100644 --- a/include/boost/pfr/detail/stdarray.hpp +++ b/include/boost/pfr/detail/stdarray.hpp @@ -9,10 +9,14 @@ #include +#ifdef BOOST_PFR_HAS_STD_MODULE +import std; +#else #include // metaprogramming stuff #include #include // for std::common_type_t #include +#endif #include diff --git a/include/boost/pfr/detail/stdtuple.hpp b/include/boost/pfr/detail/stdtuple.hpp index 71424e0..94a8444 100644 --- a/include/boost/pfr/detail/stdtuple.hpp +++ b/include/boost/pfr/detail/stdtuple.hpp @@ -9,8 +9,12 @@ #include +#ifdef BOOST_PFR_HAS_STD_MODULE +import std; +#else #include // metaprogramming stuff #include +#endif #include diff --git a/include/boost/pfr/detail/tie_from_structure_tuple.hpp b/include/boost/pfr/detail/tie_from_structure_tuple.hpp index 9411848..4d78b5b 100644 --- a/include/boost/pfr/detail/tie_from_structure_tuple.hpp +++ b/include/boost/pfr/detail/tie_from_structure_tuple.hpp @@ -16,7 +16,11 @@ #include #include +#ifdef BOOST_PFR_HAS_STD_MODULE +import std; +#else #include +#endif namespace boost { namespace pfr { namespace detail { diff --git a/include/boost/pfr/detail/unsafe_declval.hpp b/include/boost/pfr/detail/unsafe_declval.hpp index a204a2a..0969229 100644 --- a/include/boost/pfr/detail/unsafe_declval.hpp +++ b/include/boost/pfr/detail/unsafe_declval.hpp @@ -9,7 +9,11 @@ #include +#ifdef BOOST_PFR_HAS_STD_MODULE +import std; +#else #include +#endif namespace boost { namespace pfr { namespace detail { diff --git a/include/boost/pfr/functors.hpp b/include/boost/pfr/functors.hpp index 2baf88a..e44ded0 100644 --- a/include/boost/pfr/functors.hpp +++ b/include/boost/pfr/functors.hpp @@ -35,6 +35,8 @@ /// \b Synopsis: namespace boost { namespace pfr { +BOOST_PFR_BEGIN_MODULE_EXPORT + ///////////////////// Comparisons /// \brief std::equal_to like comparator that returns \forcedlink{eq}(x, y) @@ -216,6 +218,8 @@ template struct hash { } }; +BOOST_PFR_END_MODULE_EXPORT + }} // namespace boost::pfr #endif // BOOST_PFR_FUNCTORS_HPP diff --git a/include/boost/pfr/io.hpp b/include/boost/pfr/io.hpp index 920c89a..1c50772 100644 --- a/include/boost/pfr/io.hpp +++ b/include/boost/pfr/io.hpp @@ -67,6 +67,8 @@ struct io_impl { T value; }; +BOOST_PFR_BEGIN_MODULE_EXPORT + template enable_not_ostreamable_t, T> operator<<(std::basic_ostream& out, io_impl&& x) { return out << boost::pfr::io_fields(std::forward(x.value)); @@ -87,8 +89,12 @@ enable_istreamable_t, T> operator>>(std::basic_ return in >> x.value; } +BOOST_PFR_END_MODULE_EXPORT + } // namespace detail +BOOST_PFR_BEGIN_MODULE_EXPORT + /// IO manipulator to read/write \aggregate `value` using its IO stream operators or using \forcedlink{io_fields} if operators are not available. /// /// \b Example: @@ -108,6 +114,8 @@ auto io(T&& value) noexcept { return detail::io_impl{std::forward(value)}; } +BOOST_PFR_END_MODULE_EXPORT + }} // namespace boost::pfr #endif // BOOST_PFR_IO_HPP diff --git a/include/boost/pfr/io_fields.hpp b/include/boost/pfr/io_fields.hpp index 753cace..4ccd1ee 100644 --- a/include/boost/pfr/io_fields.hpp +++ b/include/boost/pfr/io_fields.hpp @@ -118,6 +118,8 @@ std::basic_istream& operator>>(std::basic_istream& i return in; } +BOOST_PFR_BEGIN_MODULE_EXPORT + template std::basic_istream& operator>>(std::basic_istream& in, io_fields_impl&& ) { static_assert(sizeof(T) && false, "====================> Boost.PFR: Attempt to use istream operator on a boost::pfr::io_fields wrapped type T with const qualifier."); @@ -130,8 +132,12 @@ std::basic_istream& operator>>(std::basic_istream& i return in; } +BOOST_PFR_END_MODULE_EXPORT + } // namespace detail +BOOST_PFR_BEGIN_MODULE_EXPORT + /// IO manipulator to read/write \aggregate `value` field-by-field. /// /// \b Example: @@ -159,6 +165,8 @@ auto io_fields(T&& value) noexcept { return detail::io_fields_impl{std::forward(value)}; } +BOOST_PFR_END_MODULE_EXPORT + }} // namespace boost::pfr #endif // BOOST_PFR_IO_FIELDS_HPP diff --git a/include/boost/pfr/ops.hpp b/include/boost/pfr/ops.hpp index 4d9e9b3..a1839f8 100644 --- a/include/boost/pfr/ops.hpp +++ b/include/boost/pfr/ops.hpp @@ -77,6 +77,7 @@ namespace detail { >; } // namespace detail +BOOST_PFR_BEGIN_MODULE_EXPORT /// \brief Compares lhs and rhs for equality using their own comparison and conversion operators; if no operators available returns \forcedlink{eq_fields}(lhs, rhs). /// @@ -182,6 +183,8 @@ constexpr detail::enable_hashable_t hash_value(const T& value) { return std::hash{}(value); } +BOOST_PFR_END_MODULE_EXPORT + }} // namespace boost::pfr #endif // BOOST_PFR_OPS_HPP diff --git a/include/boost/pfr/ops_fields.hpp b/include/boost/pfr/ops_fields.hpp index c34895c..92215a4 100644 --- a/include/boost/pfr/ops_fields.hpp +++ b/include/boost/pfr/ops_fields.hpp @@ -33,6 +33,8 @@ /// \b Synopsis: namespace boost { namespace pfr { +BOOST_PFR_BEGIN_MODULE_EXPORT + /// Does a field-by-field equality comparison. /// /// \returns `L == R && tuple_size_v == tuple_size_v`, where `L` and @@ -122,6 +124,9 @@ namespace boost { namespace pfr { return result; #endif } + +BOOST_PFR_END_MODULE_EXPORT + }} // namespace boost::pfr #endif // BOOST_PFR_OPS_HPP diff --git a/include/boost/pfr/traits.hpp b/include/boost/pfr/traits.hpp index c490339..75f105f 100644 --- a/include/boost/pfr/traits.hpp +++ b/include/boost/pfr/traits.hpp @@ -19,6 +19,8 @@ namespace boost { namespace pfr { +BOOST_PFR_BEGIN_MODULE_EXPORT + /// Has a static const member variable `value` when it is known that type T can or can't be reflected using Boost.PFR; otherwise, there is no member variable. /// Every user may (and in some difficult cases - should) specialize is_reflectable on his own. /// @@ -54,6 +56,8 @@ using is_implicitly_reflectable = std::integral_constant< bool, boost::pfr::deta template constexpr bool is_implicitly_reflectable_v = is_implicitly_reflectable::value; +BOOST_PFR_END_MODULE_EXPORT + }} // namespace boost::pfr #endif // BOOST_PFR_TRAITS_HPP diff --git a/include/boost/pfr/traits_fwd.hpp b/include/boost/pfr/traits_fwd.hpp index c015e9d..59148f1 100644 --- a/include/boost/pfr/traits_fwd.hpp +++ b/include/boost/pfr/traits_fwd.hpp @@ -11,9 +11,13 @@ namespace boost { namespace pfr { +BOOST_PFR_BEGIN_MODULE_EXPORT + template struct is_reflectable; +BOOST_PFR_END_MODULE_EXPORT + }} // namespace boost::pfr #endif // BOOST_PFR_DETAIL_TRAITS_FWD_HPP diff --git a/include/boost/pfr/tuple_size.hpp b/include/boost/pfr/tuple_size.hpp index bf5c5d8..b092418 100644 --- a/include/boost/pfr/tuple_size.hpp +++ b/include/boost/pfr/tuple_size.hpp @@ -22,6 +22,8 @@ /// \b Synopsis: namespace boost { namespace pfr { +BOOST_PFR_BEGIN_MODULE_EXPORT + /// Has a static const member variable `value` that contains fields count in a T. /// Works for any T that satisfies \aggregate. /// @@ -43,6 +45,8 @@ using tuple_size = detail::size_t_< boost::pfr::detail::fields_count() >; template constexpr std::size_t tuple_size_v = tuple_size::value; +BOOST_PFR_END_MODULE_EXPORT + }} // namespace boost::pfr #endif // BOOST_PFR_TUPLE_SIZE_HPP diff --git a/misc/generate_cpp17.py b/misc/generate_cpp17.py index 7826246..a937293 100644 --- a/misc/generate_cpp17.py +++ b/misc/generate_cpp17.py @@ -38,7 +38,12 @@ PROLOGUE = """// Copyright (c) 2016-2024 Antony Polukhin #include #include + +#ifdef BOOST_PFR_HAS_STD_MODULE +import std; +#else #include // for std::conditional_t, std::is_reference +#endif namespace boost { namespace pfr { namespace detail { diff --git a/module/CMakeLists.txt b/module/CMakeLists.txt new file mode 100644 index 0000000..0aee51b --- /dev/null +++ b/module/CMakeLists.txt @@ -0,0 +1,37 @@ +# Copyright (c) 2016-2024 Antony Polukhin +# +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt + +cmake_minimum_required(VERSION 3.28) + +function (_add_boost_pfr_module_impl NAME) + add_library(${NAME}) + target_compile_features(${NAME} PUBLIC cxx_std_20) + target_sources(${NAME} PUBLIC + FILE_SET modules_public TYPE CXX_MODULES FILES + ${CMAKE_CURRENT_LIST_DIR}/pfr.cppm + ) +endfunction() + +function (add_boost_pfr_module NAME) + _add_boost_pfr_module_impl(${NAME}) + target_include_directories(${NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/../include) + + _add_boost_pfr_module_impl(${NAME}_migration) + target_include_directories(${NAME}_migration PUBLIC ${CMAKE_CURRENT_LIST_DIR}/../include) + target_compile_definitions(${NAME}_migration PRIVATE BOOST_PFR_ATTACH_TO_GLOBAL_MODULE) +endfunction() + +add_boost_pfr_module(boost_pfr_module) +add_library(Boost::pfr_module ALIAS boost_pfr_module) +add_library(Boost::pfr_module_migration ALIAS boost_pfr_module_migration) + +if (BUILD_TESTING) + add_executable(boost_pfr_module_usage usage_sample.cpp) + target_link_libraries(boost_pfr_module_usage PRIVATE Boost::pfr_module) + + # Make sure that mixing includes and imports is fine for different TU + add_executable(boost_pfr_module_usage_mu usage_test_mu1.cpp usage_test_mu2.cpp) + target_link_libraries(boost_pfr_module_usage_mu PRIVATE Boost::pfr_module_migration) +endif() diff --git a/module/pfr.cppm b/module/pfr.cppm new file mode 100644 index 0000000..a0fd648 --- /dev/null +++ b/module/pfr.cppm @@ -0,0 +1,44 @@ +// Copyright (c) 2016-2024 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 pfr.cppm + +#define BOOST_PFR_BEGIN_MODULE_EXPORT export { +#define BOOST_PFR_END_MODULE_EXPORT } + +#ifndef BOOST_PFR_HAS_STD_MODULE +module; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +export module Boost.PFR; + +#ifdef BOOST_PFR_HAS_STD_MODULE +import std; +#endif + +#ifdef __clang__ +# pragma clang diagnostic ignored "-Winclude-angled-in-module-purview" +#endif + +#ifdef BOOST_PFR_ATTACH_TO_GLOBAL_MODULE +extern "C++" { +#include +} +#else +#include +#endif diff --git a/module/usage_sample.cpp b/module/usage_sample.cpp new file mode 100644 index 0000000..16e69ec --- /dev/null +++ b/module/usage_sample.cpp @@ -0,0 +1,31 @@ +// Copyright (c) 2016-2024 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++ -std=c++20 -fmodule-file=pfr.pcm pfr.pcm usage_sample.cpp + +//[pfr_module_example +#include +#include +#include + +import Boost.PFR; + +struct some_person { + std::string name; + unsigned birth_year; +}; + +int main() { + some_person val{"Edgar Allan Poe", 1809}; + + std::cout << boost::pfr::get<0>(val) // No macro! + << " was born in " << boost::pfr::get<1>(val); // Works with any aggregate! + + std::cout << '\n' << boost::pfr::io(val); // Outputs: {"Edgar Allan Poe", 1809} + std::cout << "\n." << boost::pfr::get_name<0, some_person>() + << '=' << val.name << '\n'; // Outputs: .name=Edgar Allan Poe +} +//] diff --git a/module/usage_test_mu1.cpp b/module/usage_test_mu1.cpp new file mode 100644 index 0000000..ceb1855 --- /dev/null +++ b/module/usage_test_mu1.cpp @@ -0,0 +1,27 @@ +// Copyright (c) 2016-2024 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++ -std=c++20 -fmodule-file=pfr.pcm pfr.pcm usage_sample.cpp + +#include + +#include + +struct some_person { + std::string name; + unsigned birth_year; +}; + +void mu1_act() { + some_person val{"Edgar Allan Poe", 1809}; + + std::cout << boost::pfr::get<0>(val) // No macro! + << " was born in " << boost::pfr::get<1>(val); // Works with any aggregate! + + std::cout << '\n' << boost::pfr::io(val); // Outputs: {"Edgar Allan Poe", 1809} + std::cout << "\n." << boost::pfr::get_name<0, some_person>() + << '=' << val.name << '\n'; // Outputs: .name=Edgar Allan Poe +} diff --git a/module/usage_test_mu2.cpp b/module/usage_test_mu2.cpp new file mode 100644 index 0000000..c215de9 --- /dev/null +++ b/module/usage_test_mu2.cpp @@ -0,0 +1,32 @@ +// Copyright (c) 2016-2024 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++ -std=c++20 -fmodule-file=pfr.pcm pfr.pcm usage_sample.cpp + +#include +#include + +import Boost.PFR; + +struct some_person { + std::string name; + unsigned birth_year; +}; + +void mu1_act(); + +int main() { + mu1_act(); + + some_person val{"Joseph Brodsky", 1940}; + + std::cout << boost::pfr::get<0>(val) // No macro! + << " was born in " << boost::pfr::get<1>(val); // Works with any aggregate! + + std::cout << '\n' << boost::pfr::io(val); + std::cout << "\n." << boost::pfr::get_name<0, some_person>() + << '=' << val.name << '\n'; +}