Compare commits

...

141 Commits

Author SHA1 Message Date
Peter Dimov
4959611e09 Avoid msvc-14.0 constexpr errors in enum_to_string 2025-12-15 19:39:46 +02:00
Peter Dimov
a722380b2a Update revision history 2025-12-15 13:16:33 +02:00
Peter Dimov
dfd9182bf3 Replace the lambda in enum_to_string with a struct to enable C++14 constexpr. Refs #60. Refs #61. 2025-12-15 12:37:40 +02:00
Peter Dimov
f1774f3d02 Make enum_to_string constexpr; add enum_to_string_test_cx.cpp. Refs #60. Refs #61. 2025-12-15 12:28:44 +02:00
Peter Dimov
7c0d234267 Update ci.yml 2025-12-11 15:49:41 +02:00
Peter Dimov
6e4b7f5a07 Update .drone.jsonnet 2025-11-14 23:19:03 +02:00
Peter Dimov
0a40d3b824 Move C++20 detection to detail/config.hpp; disable C++20 use for Clang < 13. 2025-11-14 23:10:11 +02:00
Peter Dimov
644a984a61 Avoid https://gcc.gnu.org/bugzilla/show_bug.cgi?id=122688 2025-11-14 23:10:11 +02:00
Peter Dimov
43ee545507 Move enum descriptors computation into decltype under C++20. Fixes #58. 2025-11-14 23:10:11 +02:00
Peter Dimov
54b73c7ca7 Add test for describe_enumerators on a nested enum before the enclosing class is complete. Refs #58. 2025-11-14 23:10:11 +02:00
Peter Dimov
ee215421cb Update appveyor.yml 2025-11-14 14:32:49 +02:00
Peter Dimov
2864875eef Disable C4996 from JSON on msvc-14.0 2025-10-22 16:03:41 +03:00
Peter Dimov
1a63fc6ffb Update cmake_subdir_test/CMakeLists.txt to reflect Core changes 2025-10-22 11:24:17 +03:00
Peter Dimov
373db78411 Make mod_any_access an inline variable, because of modules. Closes #57. 2025-10-22 11:00:36 +03:00
Peter Dimov
5858ccb775 Merge pull request #56 from sigbjorn/feature/extend-pp-for-each-limit
Extended limit for describe/detail/pp_for_each.hpp from 52 to 64
2025-08-17 10:18:55 +03:00
Peter Dimov
ba01c60d56 Update .drone.jsonnet 2025-08-17 01:16:13 +03:00
Peter Dimov
ecd2b0456b Remove windows-2019 from GHA 2025-08-16 21:35:16 +03:00
sigbjorn
362a266b7d Extended limit for describe/detail/pp_for_each.hpp from 52 to 64 including test, #55 2025-08-08 10:52:00 +02:00
Peter Dimov
b64177c39f Update ci.yml 2025-05-25 17:11:44 +03:00
Peter Dimov
ddff876eea Update .drone.jsonnet 2024-12-13 13:47:35 +02:00
Peter Dimov
112c33a793 Apply Node20 workaround 2024-12-13 13:46:26 +02:00
Peter Dimov
22f497d1ad Update ci.yml 2024-12-13 13:45:37 +02:00
Peter Dimov
3da6a1e295 Update ci.yml 2024-10-14 02:06:21 +03:00
Peter Dimov
ff76bbb90b Merge pull request #47 from qchateau/develop
Support parameter packs for bases in BOOST_DESCRIBE_CLASS
2024-10-14 01:51:27 +03:00
Peter Dimov
18e7c01359 Update JSON examples for JSON 1.81+ 2024-09-09 20:23:58 +03:00
Peter Dimov
777bdec2e9 Update examples.adoc for JSON 1.81+ 2024-09-09 20:21:03 +03:00
Peter Dimov
f39d32150d Use link=static for JSON, Serialization under UBSan 2024-08-22 01:53:28 +03:00
Peter Dimov
f8f7af29d5 Update .drone.jsonnet 2024-08-21 21:51:41 +03:00
Peter Dimov
89b5caef8d Add VERBATIM to add_custom_target 2024-08-21 21:49:52 +03:00
Peter Dimov
2fb95498ea Update build.jam, test/Jamfile 2024-08-21 20:59:01 +03:00
Peter Dimov
8a0ade0ad0 Merge branch 'modular' of https://github.com/grafikrobot/boostorg.describe into feature/modular-b2 2024-08-21 20:54:19 +03:00
Peter Dimov
1508f66184 Update .drone.jsonnet 2024-08-21 19:01:46 +03:00
Peter Dimov
ac298922b0 Update ci.yml 2024-08-21 18:18:20 +03:00
Rene Rivera
86099f1d78 Move inter-lib dependencies to a project variable and into the build targets. 2024-07-23 22:34:24 -05:00
Rene Rivera
d25e48348e Update copyright dates. 2024-07-20 22:52:05 -05:00
Rene Rivera
76c036a2d7 Change all <source> references to <library>. 2024-07-20 19:38:12 -05:00
Rene Rivera
879d4b2a22 Bump B2 require to 5.2 2024-06-14 11:33:55 -05:00
Rene Rivera
202203112b Add requires-b2 check to top-level build file. 2024-05-05 09:00:01 -05:00
Rene Rivera
882b168de8 Sync from upstream. 2024-04-20 15:34:25 -05:00
Peter Dimov
1ddee6c39a Revert "Update doc/Jamfile"
This reverts commit 9899acb4c9.
2024-04-16 22:36:26 +03:00
Peter Dimov
9899acb4c9 Update doc/Jamfile 2024-04-16 22:17:19 +03:00
Rene Rivera
84ce044885 Switch to library requirements instead of source. As source puts extra source in install targets. 2024-03-29 21:15:58 -05:00
Rene Rivera
120b9edaed Sync from upstream. 2024-03-23 16:03:15 -05:00
Peter Dimov
50719b2123 Update .drone.jsonnet 2024-03-23 20:27:08 +02:00
Peter Dimov
8f3b04a3d9 Disable warnings-as-errors=on in serialization.cpp for MSVC as well 2024-03-23 20:22:22 +02:00
Quentin Chateau
2e63564776 Support parameter packs for bases in BOOST_DESCRIBE_CLASS 2024-03-22 22:47:46 +01:00
Rene Rivera
9da33c4629 Make the library modular usable. 2024-03-11 08:32:57 -05:00
Peter Dimov
fad199e782 Merge pull request #44 from denzor200/actualize_fmt
Actualize examples to build with latest `fmt`
2023-12-13 17:29:06 +02:00
Peter Dimov
e005f6950c Update ci.yml 2023-12-13 17:12:12 +02:00
Denis Mikhailov
2e5dcc80b2 Update fmtlib_enum_formatter.cpp 2023-11-25 22:22:10 +01:00
Denis Mikhailov
ba1459ac84 Update fmtlib_class_formatter.cpp 2023-11-25 22:21:33 +01:00
Peter Dimov
c89e4dd3db Update json_rpc example to work on both versions of Boost.JSON 2023-09-26 00:53:40 +03:00
Peter Dimov
3047e5a72f Document the new overload of enum_from_string 2023-09-09 19:07:05 +03:00
Peter Dimov
cfddb57d3a Add an overload of enum_from_string that takes a string-like type (such as string_view). Fixes #41. 2023-09-09 18:52:41 +03:00
Peter Dimov
6e7d49c6e1 Do not use -Werror with Serialization under GCC 2023-09-09 17:57:18 +03:00
Peter Dimov
cc2281054e {"world"} is now string in Boost.JSON, not array 2023-09-09 17:23:26 +03:00
Peter Dimov
215042b480 Update ci.yml 2023-09-09 17:03:54 +03:00
Peter Dimov
a0eafb0810 Merge branch 'fix-deprecated-inline-static-variables' of https://github.com/Romain-Geissler-1A/describe into feature/pr-40 2023-05-21 04:51:35 +03:00
Peter Dimov
1692c3e5d6 Update ci.yml 2023-05-21 04:05:26 +03:00
Romain Geissler
b54fda5469 Fix -Wdeprecated warnings when compiling with C++ >= 17 (ie with inline variables).
Example of warning we get:
/data/mwrep/res/osp/Boost/23-0-0-0/include/boost/describe/members.hpp:89:81: error: redundant redeclaration of 'constexpr' static data member 'boost::describe::detail::update_modifiers<T, Bm>::fn<D>::pointer' [-Werror=deprecated]
 89 | template<class T, unsigned Bm> template<class D> constexpr decltype(D::pointer) update_modifiers<T, Bm>::fn<D>::pointer;
    | ^~~~~~~~~~~~~~~~~~~~~~~ /data/mwrep/res/osp/Boost/23-0-0-0/include/boost/describe/members.hpp:83:47: note: previous declaration of 'boost::describe::detail::update_modifiers<T, Bm>::fn<D>::pointer'
 83 | static constexpr decltype(D::pointer) pointer = D::pointer;
    | ^~~~~~~
2023-05-20 23:41:18 +00:00
Peter Dimov
311cab7565 Update documentation 2022-10-30 02:02:43 +03:00
Peter Dimov
b5df0b2ee9 Reorder includes to work around an odd msvc-14.0 bug 2022-10-29 04:08:38 +03:00
Peter Dimov
1e32c60dff Update hash_value example for 1.81 2022-10-29 03:36:47 +03:00
Peter Dimov
0d8de0aae7 Enable JSON tests with msvc-14.0, as it's supported now 2022-10-28 07:01:24 +03:00
Peter Dimov
8ff96dcd9e Add pedantic_members_test 2022-10-28 06:31:01 +03:00
Peter Dimov
7a06d512dc Move BOOST_DESCRIBE_ENUM(modifiers) to modifier_description.hpp, to allow modifiers.hpp inclusion under -pedantic 2022-10-28 06:28:16 +03:00
Peter Dimov
2deab4c35c Add pedantic_bases_test 2022-10-28 06:19:17 +03:00
Peter Dimov
8a982de483 Add pedantic_enumerators_test 2022-10-28 06:06:24 +03:00
Peter Dimov
f8c2b7d2d9 Add comments to unnamed_namespace_test, unnamed_namespace_test2 2022-10-28 05:56:46 +03:00
Peter Dimov
5d13049e06 Use __attribute__((unused)) instead of [[maybe_unused]]; earlier Clangs don't have [[maybe_unused]], and it's a pedantic warning before C++17 2022-10-28 05:29:31 +03:00
Peter Dimov
df0f16a85b Do not set BOOST_DESCRIBE_CXX11 for g++ 4.7, as its C++11 support is not good enough 2022-10-28 05:24:46 +03:00
Peter Dimov
81d924fff2 Add Drone support 2022-10-28 04:28:58 +03:00
Peter Dimov
a1557028b3 Update ci.yml 2022-10-20 18:42:54 +03:00
Peter Dimov
6bf8045bac Disable warning 4100 under msvc-14.0 2022-10-20 18:27:14 +03:00
Peter Dimov
973bdf1725 Remove global -wd4100 2022-10-20 18:23:00 +03:00
Peter Dimov
f6bf0c4f1e Replace macos-10.15 with macos-11 in ci.yml 2022-09-29 20:40:21 +03:00
Peter Dimov
c156466e2b Fix operator test failures 2022-09-29 20:11:07 +03:00
Peter Dimov
9273e7c0af Add member functions to X in operator_eq_test, operator_lt_test 2022-09-29 20:07:59 +03:00
Peter Dimov
ef9c38f90c Update documentation 2022-06-21 20:19:56 +03:00
Peter Dimov
6749a0f46a Disable msvc-12.0 and below warnings in bases_test.cpp 2022-06-21 19:31:06 +03:00
Peter Dimov
c8c46bfdf7 Disable -Wrestrict in pm_to_string.cpp for GCC 12 2022-06-21 18:02:06 +03:00
Peter Dimov
ccfed27ddd Update .yml files 2022-06-21 17:06:42 +03:00
Peter Dimov
21de045f39 Remove extra semicolons in tests 2022-06-21 16:34:26 +03:00
Peter Dimov
4b65c35009 Remove extra semicolon in modifiers.hpp 2022-06-21 16:28:22 +03:00
Peter Dimov
574c1736a3 Merge pull request #28 from ecatmur/nested-poison
Poison BOOST_DESCRIBE_ENUM in class scope
2022-02-19 03:46:58 +02:00
Peter Dimov
c0fd54e1f7 Update documentation and README 2022-02-19 03:17:58 +02:00
Peter Dimov
2a50e32645 Add CMake jobs to ci.yml 2022-02-19 02:50:35 +02:00
Peter Dimov
71c9a5100e Update fmtlib examples 2022-02-14 06:48:59 +02:00
Peter Dimov
1614c16be7 Update ci.yml 2022-02-13 03:35:13 +02:00
Peter Dimov
dd950f77fe Use [listing] for sample outputs 2022-02-13 03:07:58 +02:00
Peter Dimov
0be3b2833d Add sample outputs to examples 2022-02-13 01:55:11 +02:00
Peter Dimov
3ac03da76f Added example/fmtlib_enum_formatter.cpp 2022-02-13 01:36:39 +02:00
Peter Dimov
0eb2c9eb25 Rename fmtlib_formatter.cpp to fmtlib_class_formatter.cpp 2022-02-13 01:30:22 +02:00
Peter Dimov
4ccae397a7 Update revision history 2022-02-02 20:47:02 +02:00
Peter Dimov
dae1e8246a Add printing member pointers example 2022-02-02 20:40:01 +02:00
Peter Dimov
8d10118745 Add fmtlib formatter example 2022-02-01 06:22:24 +02:00
Peter Dimov
74089b76c3 Update appveyor.yml 2021-12-22 06:57:16 +02:00
Ed Catmur
d64c9fb141 Create nested_enum_fail.cpp 2021-12-21 17:11:43 +00:00
Ed Catmur
abc8b0236d Create enum_nested_fail.cpp 2021-12-21 17:11:19 +00:00
Ed Catmur
dd76e316d3 Update Jamfile 2021-12-21 17:08:53 +00:00
Ed Catmur
acf2e56c34 Poison BOOST_DESCRIBE_ENUM in class scope
try to inform the user that they should use BOOST_DESCRIBE_NESTED_ENUM instead
2021-12-21 17:07:14 +00:00
Peter Dimov
811003ea0c g++ 4.8 doesn't like static union members either 2021-12-15 03:40:34 +02:00
Peter Dimov
bd8be41591 Add !is_union<T>::value to examples 2021-12-15 02:14:56 +02:00
Peter Dimov
f9477bc177 Disable operators for unions because their behavior is undefined 2021-12-15 02:00:20 +02:00
Peter Dimov
d98f4d1f40 Disable union tests for C++03 because static members are not allowed 2021-12-15 01:49:52 +02:00
Peter Dimov
2e3b6a6791 Test BOOST_DESCRIBE_CLASS with a union 2021-12-15 01:41:54 +02:00
Peter Dimov
fabf5c7115 Allow unions in BOOST_DESCRIBE_STRUCT (refs #21) 2021-12-15 01:33:06 +02:00
Peter Dimov
ec7aec2b3d Add msvc-14.0 to GHA 2021-12-11 20:15:03 +02:00
Peter Dimov
fc458d48c7 Change internal functions to take T** instead of T* to prevent derived to base conversions (closes #22) 2021-12-11 19:28:16 +02:00
Peter Dimov
6cc4ddafd7 Test non-described classes derived from described ones (refs #22) 2021-12-11 19:14:19 +02:00
Peter Dimov
ed1175b33a Merge branch 'maybe-unused' of https://github.com/ecatmur/describe into feature/pr-24 2021-11-17 02:22:16 +02:00
Peter Dimov
d4ebe0943e Add test for enums and classes in unnamed namespaces (refs #23) 2021-11-17 02:20:22 +02:00
Ed Catmur
1fa144623d Sprinkle [[maybe_unused]] on descriptors
Suppresses Wunused-function / Wunneeded-internal-declaration (clang) on internal-linkage types

https://github.com/boostorg/describe/issues/23
2021-11-16 21:35:33 +00:00
Peter Dimov
5032f55ac1 Update categories in libraries.json 2021-11-08 00:34:30 +02:00
Peter Dimov
71bfb07be2 Add example/struct_to_tuple.cpp 2021-10-28 01:28:07 +03:00
Peter Dimov
fc15f03c34 Add {zwsp} to long header names 2021-10-27 06:51:54 +03:00
Peter Dimov
2fc0e817ad Document descriptor_by_pointer 2021-10-27 06:24:09 +03:00
Peter Dimov
84fe8aa21e Add descriptor_by_pointer 2021-10-27 06:09:54 +03:00
Peter Dimov
003b2bdc50 Document descriptor_by_name 2021-10-27 05:42:38 +03:00
Peter Dimov
8437f2e62e Fix msvc-14.0 2021-10-27 04:31:35 +03:00
Peter Dimov
448174f346 Add descriptor_by_name 2021-10-27 04:13:29 +03:00
Peter Dimov
2935bca3b1 Update README, implementation section 2021-10-26 18:46:12 +03:00
Peter Dimov
e407d4da19 Document operators 2021-10-26 17:39:59 +03:00
Peter Dimov
2accb05ce5 Reset os.width in operator<< 2021-10-26 17:32:21 +03:00
Peter Dimov
128e3667d6 Add operators.hpp 2021-10-26 07:09:30 +03:00
Peter Dimov
8cf28d7b6e Include enum_from_string.hpp in describe.hpp 2021-10-26 06:21:56 +03:00
Peter Dimov
7397e8d66a Document enum_from_string 2021-10-26 05:40:26 +03:00
Peter Dimov
c3f16f3332 Add enum_from_string.hpp 2021-10-26 05:33:14 +03:00
Peter Dimov
890c1afcda Bump workaround in class_template_test.cpp 2021-10-26 04:18:37 +03:00
Peter Dimov
caa4cb6bf0 Bump workarounds in members_test7.cpp 2021-10-26 04:17:26 +03:00
Peter Dimov
ffa4790292 Add msvc-14.3 to ci.yml 2021-10-26 04:15:50 +03:00
Peter Dimov
f7d2f12cd4 Document enum_to_string 2021-10-26 04:13:18 +03:00
Peter Dimov
53d577428e Make enum_to_string noexcept 2021-10-26 04:12:58 +03:00
Peter Dimov
9c351a463f Add enum_to_string.hpp 2021-10-25 20:22:14 +03:00
Peter Dimov
af01484087 Document has_* 2021-10-25 20:08:13 +03:00
Peter Dimov
d5e79ee67d Remove superfluous semicolons 2021-10-25 19:53:53 +03:00
Peter Dimov
300ea0bebe Add has_describe_members 2021-10-25 18:45:26 +03:00
Peter Dimov
5a4c425f32 Add has_describe_bases 2021-10-25 18:40:38 +03:00
Peter Dimov
fe23aeeee4 Update ci.yml 2021-10-25 18:01:19 +03:00
Peter Dimov
daaec68db6 Update ci.yml 2021-10-25 17:40:36 +03:00
Peter Dimov
b6c41956ec Add has_describe_enumerators 2021-10-25 17:36:58 +03:00
74 changed files with 4058 additions and 194 deletions

455
.drone.jsonnet Normal file
View File

@@ -0,0 +1,455 @@
# Copyright 2022 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
local library = "describe";
local triggers =
{
branch: [ "master", "develop", "feature/*" ]
};
local ubsan = { UBSAN: '1', UBSAN_OPTIONS: 'print_stacktrace=1' };
local asan = { ASAN: '1' };
local linux_pipeline(name, image, environment, packages = "", sources = [], arch = "amd64") =
{
name: name,
kind: "pipeline",
type: "docker",
trigger: triggers,
platform:
{
os: "linux",
arch: arch
},
steps:
[
{
name: "everything",
image: image,
environment: environment,
commands:
[
'set -e',
'uname -a',
'echo $DRONE_STAGE_MACHINE',
] +
(if sources != [] then [ ('apt-add-repository "' + source + '"') for source in sources ] else []) +
(if packages != "" then [ 'apt-get update', 'apt-get -y install ' + packages ] else []) +
[
'export LIBRARY=' + library,
'./.drone/drone.sh',
]
}
]
};
local macos_pipeline(name, environment, xcode_version = "12.2", osx_version = "catalina", arch = "amd64") =
{
name: name,
kind: "pipeline",
type: "exec",
trigger: triggers,
platform: {
"os": "darwin",
"arch": arch
},
node: {
"os": osx_version
},
steps: [
{
name: "everything",
environment: environment + { "DEVELOPER_DIR": "/Applications/Xcode-" + xcode_version + ".app/Contents/Developer" },
commands:
[
'export LIBRARY=' + library,
'./.drone/drone.sh',
]
}
]
};
local windows_pipeline(name, image, environment, arch = "amd64") =
{
name: name,
kind: "pipeline",
type: "docker",
trigger: triggers,
platform:
{
os: "windows",
arch: arch
},
"steps":
[
{
name: "everything",
image: image,
environment: environment,
commands:
[
'cmd /C .drone\\\\drone.bat ' + library,
]
}
]
};
[
linux_pipeline(
"Linux 14.04 GCC 4.4",
"cppalliance/droneubuntu1404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-4.4', CXXSTD: '98,0x' },
"g++-4.4",
[ "ppa:ubuntu-toolchain-r/test" ],
),
linux_pipeline(
"Linux 14.04 GCC 4.6",
"cppalliance/droneubuntu1404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-4.6', CXXSTD: '98,0x' },
"g++-4.6",
[ "ppa:ubuntu-toolchain-r/test" ],
),
linux_pipeline(
"Linux 14.04 GCC 4.7",
"cppalliance/droneubuntu1404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-4.7', CXXSTD: '98,0x' },
"g++-4.7",
[ "ppa:ubuntu-toolchain-r/test" ],
),
linux_pipeline(
"Linux 14.04 GCC 4.8*",
"cppalliance/droneubuntu1404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11' },
),
linux_pipeline(
"Linux 14.04 GCC 4.9",
"cppalliance/droneubuntu1404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-4.9', CXXSTD: '03,11' },
"g++-4.9",
[ "ppa:ubuntu-toolchain-r/test" ],
),
linux_pipeline(
"Linux 16.04 GCC 5*",
"cppalliance/droneubuntu1604:1",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,1z' },
),
linux_pipeline(
"Linux 18.04 GCC 6",
"cppalliance/droneubuntu1804:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-6', CXXSTD: '03,11,14,1z' },
"g++-6",
),
linux_pipeline(
"Linux 18.04 GCC 7*",
"cppalliance/droneubuntu1804:1",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17' },
),
linux_pipeline(
"Linux 18.04 GCC 8",
"cppalliance/droneubuntu1804:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-8', CXXSTD: '03,11,14,17,2a' },
"g++-8",
),
linux_pipeline(
"Linux 20.04 GCC 9*",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a' },
),
linux_pipeline(
"Linux 20.04 GCC 10",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-10', CXXSTD: '03,11,14,17,2a' },
"g++-10",
),
linux_pipeline(
"Linux 22.04 GCC 11*",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a' },
),
linux_pipeline(
"Linux 22.04 GCC 12",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '03,11,14,17,20,2b' },
"g++-12",
),
linux_pipeline(
"Linux 24.04 GCC 13",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '03,11,14,17,20,2b' },
"g++-13",
),
linux_pipeline(
"Linux 24.04 GCC 14 UBSAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '03,11,14,17,20,2b' } + ubsan,
"g++-14",
),
linux_pipeline(
"Linux 24.04 GCC 14 ASAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '03,11,14,17,20,2b' } + asan,
"g++-14",
),
linux_pipeline(
"Linux 25.04 GCC 15",
"cppalliance/droneubuntu2504:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-15', CXXSTD: '03,11,14,17,20,23,2c' },
"g++-15",
),
linux_pipeline(
"Linux 16.04 Clang 3.5",
"cppalliance/droneubuntu1604:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-3.5', CXXSTD: '03,11' },
"clang-3.5",
),
linux_pipeline(
"Linux 16.04 Clang 3.6",
"cppalliance/droneubuntu1604:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-3.6', CXXSTD: '03,11,14' },
"clang-3.6",
),
linux_pipeline(
"Linux 16.04 Clang 3.7",
"cppalliance/droneubuntu1604:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-3.7', CXXSTD: '03,11,14' },
"clang-3.7",
),
linux_pipeline(
"Linux 16.04 Clang 3.8",
"cppalliance/droneubuntu1604:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-3.8', CXXSTD: '03,11,14' },
"clang-3.8",
),
linux_pipeline(
"Linux 18.04 Clang 3.9",
"cppalliance/droneubuntu1804:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-3.9', CXXSTD: '03,11,14' },
"clang-3.9",
),
linux_pipeline(
"Linux 18.04 Clang 4.0",
"cppalliance/droneubuntu1804:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-4.0', CXXSTD: '03,11,14' },
"clang-4.0",
),
linux_pipeline(
"Linux 18.04 Clang 5.0",
"cppalliance/droneubuntu1804:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-5.0', CXXSTD: '03,11,14' },
"clang-5.0",
),
linux_pipeline(
"Linux 18.04 Clang 6.0",
"cppalliance/droneubuntu1804:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-6.0', CXXSTD: '03,11,14,17' },
"clang-6.0",
),
linux_pipeline(
"Linux 20.04 Clang 7",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-7', CXXSTD: '03,11,14,17' },
"clang-7",
),
linux_pipeline(
"Linux 20.04 Clang 8",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-8', CXXSTD: '03,11,14,17' },
"clang-8",
),
linux_pipeline(
"Linux 20.04 Clang 9",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-9', CXXSTD: '03,11,14,17,2a' },
"clang-9",
),
linux_pipeline(
"Linux 20.04 Clang 10",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-10', CXXSTD: '03,11,14,17,2a' },
"clang-10",
),
linux_pipeline(
"Linux 20.04 Clang 11",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-11', CXXSTD: '03,11,14,17,2a' },
"clang-11",
),
linux_pipeline(
"Linux 20.04 Clang 12",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-12', CXXSTD: '03,11,14,17,2a' },
"clang-12",
),
linux_pipeline(
"Linux 22.04 Clang 13",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-13', CXXSTD: '03,11,14,17,20,2b' },
"clang-13",
),
linux_pipeline(
"Linux 22.04 Clang 14",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14,17,20,2b' },
"clang-14",
),
linux_pipeline(
"Linux 22.04 Clang 15",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-15', CXXSTD: '03,11,14,17,20,2b' },
"clang-15",
),
linux_pipeline(
"Linux 24.04 Clang 16",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-16', CXXSTD: '03,11,14,17,20,2b' },
"clang-16",
),
linux_pipeline(
"Linux 24.04 Clang 17",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-17', CXXSTD: '03,11,14,17,20,2b' },
"clang-17",
),
linux_pipeline(
"Linux 24.04 Clang 18 UBSAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-18', CXXSTD: '03,11,14,17,20,2b' } + ubsan,
"clang-18",
),
linux_pipeline(
"Linux 24.04 Clang 18 ASAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-18', CXXSTD: '03,11,14,17,20,2b' } + asan,
"clang-18",
),
linux_pipeline(
"Linux 24.04 Clang 19",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-19', CXXSTD: '03,11,14,17,20,2b' },
"clang-19",
),
linux_pipeline(
"Linux 24.04 Clang 20",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-20', CXXSTD: '03,11,14,17,20,23,2c' },
"clang-20",
),
linux_pipeline(
"Linux 25.10 Clang 21",
"cppalliance/droneubuntu2510:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-21', CXXSTD: '03,11,14,17,20,23,2c' },
"clang-21",
),
macos_pipeline(
"MacOS 10.15 Xcode 12.2 UBSAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,1z' } + ubsan,
),
macos_pipeline(
"MacOS 10.15 Xcode 12.2 ASAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,1z' } + asan,
),
macos_pipeline(
"MacOS 12.4 Xcode 13.2.1 UBSAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,17,20,2b' } + ubsan,
xcode_version = "13.2.1", osx_version = "monterey", arch = "arm64",
),
macos_pipeline(
"MacOS 12.4 Xcode 13.2.1 ASAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,17,20,2b' } + asan,
xcode_version = "13.2.1", osx_version = "monterey", arch = "arm64",
),
macos_pipeline(
"MacOS 12.4 Xcode 13.4.1 UBSAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,17,20,2b' } + ubsan,
xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64",
),
macos_pipeline(
"MacOS 12.4 Xcode 13.4.1 ASAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,17,20,2b' } + asan,
xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64",
),
macos_pipeline(
"MacOS 14 Xcode 16.2.0 UBSAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,17,20,2b' } + ubsan,
xcode_version = "16.2.0", osx_version = "sonoma", arch = "arm64",
),
macos_pipeline(
"MacOS 14 Xcode 16.2.0 ASAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,17,20,2b' } + asan,
xcode_version = "16.2.0", osx_version = "sonoma", arch = "arm64",
),
windows_pipeline(
"Windows VS2015 msvc-14.0",
"cppalliance/dronevs2015",
{ TOOLSET: 'msvc-14.0', CXXSTD: '14,latest', B2_DONT_EMBED_MANIFEST: '1' },
),
windows_pipeline(
"Windows VS2017 msvc-14.1",
"cppalliance/dronevs2017",
{ TOOLSET: 'msvc-14.1', CXXSTD: '14,17,latest' },
),
windows_pipeline(
"Windows VS2019 msvc-14.2",
"cppalliance/dronevs2019",
{ TOOLSET: 'msvc-14.2', CXXSTD: '14,17,20,latest' },
),
windows_pipeline(
"Windows VS2022 msvc-14.3",
"cppalliance/dronevs2022:1",
{ TOOLSET: 'msvc-14.3', CXXSTD: '14,17,20,latest' },
),
]

23
.drone/drone.bat Normal file
View File

@@ -0,0 +1,23 @@
@REM Copyright 2022 Peter Dimov
@REM Distributed under the Boost Software License, Version 1.0.
@REM https://www.boost.org/LICENSE_1_0.txt
@ECHO ON
set LIBRARY=%1
set DRONE_BUILD_DIR=%CD%
set BOOST_BRANCH=develop
if "%DRONE_BRANCH%" == "master" set BOOST_BRANCH=master
cd ..
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
git submodule update --init tools/boostdep
xcopy /s /e /q %DRONE_BUILD_DIR% libs\%LIBRARY%\
python tools/boostdep/depinst/depinst.py -I example %LIBRARY%
cmd /c bootstrap
b2 -d0 headers
if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD%
b2 -j3 libs/%LIBRARY%/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release embed-manifest-via=linker

25
.drone/drone.sh Executable file
View File

@@ -0,0 +1,25 @@
#!/bin/bash
# Copyright 2022 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
set -ex
export PATH=~/.local/bin:/usr/local/bin:$PATH
DRONE_BUILD_DIR=$(pwd)
BOOST_BRANCH=develop
if [ "$DRONE_BRANCH" = "master" ]; then BOOST_BRANCH=master; fi
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
git submodule update --init tools/boostdep
cp -r $DRONE_BUILD_DIR/* libs/$LIBRARY
python tools/boostdep/depinst/depinst.py -I example $LIBRARY
./bootstrap.sh
./b2 -d0 headers
echo "using $TOOLSET : : $COMPILER ;" > ~/user-config.jam
./b2 -j3 libs/$LIBRARY/test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release ${ADDRMD:+address-model=$ADDRMD} ${UBSAN:+undefined-sanitizer=norecover debug-symbols=on} ${ASAN:+address-sanitizer=norecover debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS}

View File

@@ -19,115 +19,216 @@ jobs:
include:
- toolset: gcc-4.8
cxxstd: "03,11"
os: ubuntu-16.04
container: ubuntu:18.04
os: ubuntu-latest
install: g++-4.8
- toolset: gcc-4.9
cxxstd: "03,11"
os: ubuntu-16.04
install: g++-4.9
- toolset: gcc-5
cxxstd: "03,11,14,14-gnu,1z,1z-gnu"
os: ubuntu-16.04
container: ubuntu:18.04
os: ubuntu-latest
install: g++-5
- toolset: gcc-6
cxxstd: "03,11,14,14-gnu,1z,1z-gnu"
os: ubuntu-16.04
container: ubuntu:18.04
os: ubuntu-latest
install: g++-6
- toolset: gcc-7
cxxstd: "03,11,14,14-gnu,17,17-gnu"
os: ubuntu-18.04
container: ubuntu:20.04
os: ubuntu-latest
install: g++-7
- toolset: gcc-8
cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04
container: ubuntu:20.04
os: ubuntu-latest
install: g++-8
- toolset: gcc-9
cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04
container: ubuntu:20.04
os: ubuntu-latest
- toolset: gcc-10
cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04
os: ubuntu-22.04
install: g++-10
- toolset: gcc-11
cxxstd: "03,11,14,17,2a"
os: ubuntu-18.04
install: g++-11
- toolset: clang
compiler: clang++-3.5
cxxstd: "03,11"
os: ubuntu-16.04
install: clang-3.5
- toolset: clang
compiler: clang++-3.6
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-3.6
- toolset: clang
compiler: clang++-3.7
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-3.7
- toolset: clang
compiler: clang++-3.8
cxxstd: "03,11,14"
os: ubuntu-16.04
install: clang-3.8
os: ubuntu-22.04
- toolset: gcc-12
cxxstd: "03,11,14,17,20,2b"
os: ubuntu-22.04
install: g++-12
- toolset: gcc-13
cxxstd: "03,11,14,17,20,2b"
container: ubuntu:24.04
os: ubuntu-latest
install: g++-13
- toolset: gcc-14
cxxstd: "03,11,14,17,20,2b"
container: ubuntu:24.04
os: ubuntu-latest
install: g++-14
- toolset: gcc-15
cxxstd: "03,11,14,17,20,23,2c"
container: ubuntu:25.10
os: ubuntu-latest
install: g++-15
- toolset: clang
compiler: clang++-3.9
cxxstd: "03,11,14"
os: ubuntu-16.04
container: ubuntu:18.04
os: ubuntu-latest
install: clang-3.9
- toolset: clang
compiler: clang++-4.0
cxxstd: "03,11,14"
os: ubuntu-16.04
container: ubuntu:18.04
os: ubuntu-latest
install: clang-4.0
- toolset: clang
compiler: clang++-5.0
cxxstd: "03,11,14,1z"
os: ubuntu-16.04
cxxstd: "03,11,14"
container: ubuntu:18.04
os: ubuntu-latest
install: clang-5.0
- toolset: clang
compiler: clang++-6.0
cxxstd: "03,11,14,17"
os: ubuntu-18.04
container: ubuntu:20.04
os: ubuntu-latest
install: clang-6.0
- toolset: clang
compiler: clang++-7
cxxstd: "03,11,14,17"
os: ubuntu-18.04
container: ubuntu:20.04
os: ubuntu-latest
install: clang-7
- toolset: clang
compiler: clang++-8
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
cxxstd: "03,11,14,17"
container: ubuntu:20.04
os: ubuntu-latest
install: clang-8
- toolset: clang
compiler: clang++-9
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
container: ubuntu:20.04
os: ubuntu-latest
install: clang-9
- toolset: clang
compiler: clang++-10
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
container: ubuntu:20.04
os: ubuntu-latest
install: clang-10
- toolset: clang
compiler: clang++-11
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
container: ubuntu:20.04
os: ubuntu-latest
install: clang-11
- toolset: clang
compiler: clang++-12
cxxstd: "03,11,14,17,2a"
os: ubuntu-20.04
container: ubuntu:20.04
os: ubuntu-latest
install: clang-12
- toolset: clang
cxxstd: "03,11,14,17,2a"
os: macos-10.15
compiler: clang++-13
cxxstd: "03,11,14,17,20,2b"
container: ubuntu:22.04
os: ubuntu-latest
install: clang-13
- toolset: clang
compiler: clang++-14
cxxstd: "03,11,14,17,20,2b"
container: ubuntu:22.04
os: ubuntu-latest
install: clang-14
- toolset: clang
compiler: clang++-15
cxxstd: "03,11,14,17,20,2b"
container: ubuntu:22.04
os: ubuntu-latest
install: clang-15
- toolset: clang
compiler: clang++-16
cxxstd: "03,11,14,17,20,2b"
container: ubuntu:24.04
os: ubuntu-latest
install: clang-16
- toolset: clang
compiler: clang++-17
cxxstd: "03,11,14,17,20,2b"
container: ubuntu:24.04
os: ubuntu-latest
install: clang-17
- toolset: clang
compiler: clang++-18
cxxstd: "03,11,14,17,20,2b"
container: ubuntu:24.04
os: ubuntu-latest
install: clang-18
- toolset: clang
compiler: clang++-19
cxxstd: "03,11,14,17,20,2b"
container: ubuntu:24.04
os: ubuntu-latest
install: clang-19
- toolset: clang
compiler: clang++-20
cxxstd: "03,11,14,17,20,23,2c"
container: ubuntu:24.04
os: ubuntu-latest
install: clang-20
- toolset: clang
compiler: clang++-21
cxxstd: "03,11,14,17,20,23,2c"
container: ubuntu:25.10
os: ubuntu-latest
install: clang-21
- toolset: clang
cxxstd: "03,11,14,17,20,2b"
os: macos-14
- toolset: clang
cxxstd: "03,11,14,17,20,2b"
os: macos-15
- toolset: clang
cxxstd: "03,11,14,17,20,23,2c"
os: macos-26
runs-on: ${{matrix.os}}
container:
image: ${{matrix.container}}
volumes:
- /node20217:/node20217:rw,rshared
- ${{ startsWith(matrix.container, 'ubuntu:1') && '/node20217:/__e/node20:ro,rshared' || ' ' }}
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v2
- name: Setup container environment
if: matrix.container
run: |
apt-get update
apt-get -y install sudo python3 git g++ curl xz-utils
- name: Install nodejs20glibc2.17
if: ${{ startsWith( matrix.container, 'ubuntu:1' ) }}
run: |
curl -LO https://archives.boost.io/misc/node/node-v20.9.0-linux-x64-glibc-217.tar.xz
tar -xf node-v20.9.0-linux-x64-glibc-217.tar.xz --strip-components 1 -C /node20217
ldd /__e/node20/bin/node
- uses: actions/checkout@v4
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
run: |
sudo apt-get update
sudo apt-get -y install ${{matrix.install}}
- name: Setup Boost
run: |
@@ -148,7 +249,7 @@ jobs:
mkdir -p libs/$LIBRARY
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" -I example $LIBRARY
python3 tools/boostdep/depinst/depinst.py --git_args "--jobs 3" -I example $LIBRARY
./bootstrap.sh
./b2 -d0 headers
@@ -167,28 +268,28 @@ jobs:
fail-fast: false
matrix:
include:
- toolset: msvc-14.1
cxxstd: "14,17,latest"
- toolset: msvc-14.3
cxxstd: "14,17,20,latest"
addrmd: 32,64
os: windows-2016
- toolset: msvc-14.2
cxxstd: "14,17,latest"
addrmd: 32,64
os: windows-2019
- toolset: msvc-14.2
cxxstd: "14,17,latest"
os: windows-2022
- toolset: msvc-14.3
cxxstd: "14,17,20,latest"
addrmd: 32,64
cxxflags: "-Zc:preprocessor"
os: windows-2019
os: windows-2022
- toolset: clang-win
cxxstd: "14,17,latest"
addrmd: 32,64
os: windows-2022
- toolset: gcc
cxxstd: "03,11,14,17,2a"
addrmd: 64
os: windows-2019
os: windows-2022
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Setup Boost
shell: cmd
@@ -217,4 +318,343 @@ jobs:
run: |
cd ../boost-root
if not "${{matrix.cxxflags}}" == "" set CXXFLAGS=cxxflags=${{matrix.cxxflags}}
b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} %CXXFLAGS% variant=debug,release
b2 -j3 libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} %CXXFLAGS% variant=debug,release embed-manifest-via=linker
posix-cmake-subdir:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-22.04
- os: ubuntu-24.04
- os: macos-14
- os: macos-15
- os: macos-26
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v4
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
- name: Use library with add_subdirectory
run: |
cd ../boost-root/libs/$LIBRARY/test/cmake_subdir_test
mkdir __build__ && cd __build__
cmake ..
cmake --build .
ctest --output-on-failure --no-tests=error
posix-cmake-install:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-22.04
- os: ubuntu-24.04
- os: macos-14
- os: macos-15
- os: macos-26
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v4
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
- name: Configure
run: |
cd ../boost-root
mkdir __build__ && cd __build__
cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DCMAKE_INSTALL_PREFIX=~/.local ..
- name: Install
run: |
cd ../boost-root/__build__
cmake --build . --target install
- name: Use the installed library
run: |
cd ../boost-root/libs/$LIBRARY/test/cmake_install_test && mkdir __build__ && cd __build__
cmake -DCMAKE_INSTALL_PREFIX=~/.local ..
cmake --build .
ctest --output-on-failure --no-tests=error
posix-cmake-test:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-22.04
- os: ubuntu-24.04
- os: macos-14
- os: macos-15
- os: macos-26
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v4
- name: Install packages
if: matrix.install
run: sudo apt install ${{matrix.install}}
- name: Setup Boost
run: |
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
LIBRARY=${GITHUB_REPOSITORY#*/}
echo LIBRARY: $LIBRARY
echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV
echo GITHUB_BASE_REF: $GITHUB_BASE_REF
echo GITHUB_REF: $GITHUB_REF
REF=${GITHUB_BASE_REF:-$GITHUB_REF}
REF=${REF#refs/heads/}
echo REF: $REF
BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true
echo BOOST_BRANCH: $BOOST_BRANCH
cd ..
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" $LIBRARY
- name: Configure
run: |
cd ../boost-root
mkdir __build__ && cd __build__
cmake -DBOOST_INCLUDE_LIBRARIES=$LIBRARY -DBUILD_TESTING=ON ..
- name: Build tests
run: |
cd ../boost-root/__build__
cmake --build . --target tests
- name: Run tests
run: |
cd ../boost-root/__build__
ctest --output-on-failure --no-tests=error
windows-cmake-subdir:
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v4
- name: Setup Boost
shell: cmd
run: |
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
echo LIBRARY: %LIBRARY%
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
echo GITHUB_REF: %GITHUB_REF%
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
set BOOST_BRANCH=develop
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
echo BOOST_BRANCH: %BOOST_BRANCH%
cd ..
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
- name: Use library with add_subdirectory (Debug)
shell: cmd
run: |
cd ../boost-root/libs/%LIBRARY%/test/cmake_subdir_test
mkdir __build__ && cd __build__
cmake ..
cmake --build . --config Debug
ctest --output-on-failure --no-tests=error -C Debug
- name: Use library with add_subdirectory (Release)
shell: cmd
run: |
cd ../boost-root/libs/%LIBRARY%/test/cmake_subdir_test/__build__
cmake --build . --config Release
ctest --output-on-failure --no-tests=error -C Release
windows-cmake-install:
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v4
- name: Setup Boost
shell: cmd
run: |
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
echo LIBRARY: %LIBRARY%
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
echo GITHUB_REF: %GITHUB_REF%
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
set BOOST_BRANCH=develop
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
echo BOOST_BRANCH: %BOOST_BRANCH%
cd ..
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
- name: Configure
shell: cmd
run: |
cd ../boost-root
mkdir __build__ && cd __build__
cmake -DBOOST_INCLUDE_LIBRARIES=%LIBRARY% -DCMAKE_INSTALL_PREFIX=C:/cmake-prefix ..
- name: Install (Debug)
shell: cmd
run: |
cd ../boost-root/__build__
cmake --build . --target install --config Debug
- name: Install (Release)
shell: cmd
run: |
cd ../boost-root/__build__
cmake --build . --target install --config Release
- name: Use the installed library (Debug)
shell: cmd
run: |
cd ../boost-root/libs/%LIBRARY%/test/cmake_install_test && mkdir __build__ && cd __build__
cmake -DCMAKE_INSTALL_PREFIX=C:/cmake-prefix ..
cmake --build . --config Debug
ctest --output-on-failure --no-tests=error -C Debug
- name: Use the installed library (Release)
shell: cmd
run: |
cd ../boost-root/libs/%LIBRARY%/test/cmake_install_test/__build__
cmake --build . --config Release
ctest --output-on-failure --no-tests=error -C Release
windows-cmake-test:
strategy:
fail-fast: false
matrix:
include:
- os: windows-latest
runs-on: ${{matrix.os}}
steps:
- uses: actions/checkout@v4
- name: Setup Boost
shell: cmd
run: |
echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY%
for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi
echo LIBRARY: %LIBRARY%
echo LIBRARY=%LIBRARY%>>%GITHUB_ENV%
echo GITHUB_BASE_REF: %GITHUB_BASE_REF%
echo GITHUB_REF: %GITHUB_REF%
if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF%
set BOOST_BRANCH=develop
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
echo BOOST_BRANCH: %BOOST_BRANCH%
cd ..
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
cd boost-root
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
git submodule update --init tools/boostdep
python tools/boostdep/depinst/depinst.py --git_args "--jobs 3" %LIBRARY%
- name: Configure
shell: cmd
run: |
cd ../boost-root
mkdir __build__ && cd __build__
cmake -DBOOST_INCLUDE_LIBRARIES=%LIBRARY% -DBUILD_TESTING=ON ..
- name: Build tests (Debug)
shell: cmd
run: |
cd ../boost-root/__build__
cmake --build . --target tests --config Debug
- name: Run tests (Debug)
shell: cmd
run: |
cd ../boost-root/__build__
ctest --output-on-failure --no-tests=error -C Debug
- name: Build tests (Release)
shell: cmd
run: |
cd ../boost-root/__build__
cmake --build . --target tests --config Release
- name: Run tests (Release)
shell: cmd
run: |
cd ../boost-root/__build__
ctest --output-on-failure --no-tests=error -C Release

View File

@@ -8,10 +8,10 @@ for more information and usage examples.
## Supported Compilers
* GCC 5 or later with `-std=c++14` or above
* Clang 3.6 or later with `-std=c++14` or above
* Visual Studio 2015, 2017, 2019
* Clang 3.9 or later with `-std=c++14` or above
* Visual Studio 2015 or later
Tested on [Travis](https://travis-ci.org/github/pdimov/describe/) and
Tested on [Github Actions](https://github.com/boostorg/describe/actions) and
[Appveyor](https://ci.appveyor.com/project/pdimov/describe).
## License

View File

@@ -1,4 +1,4 @@
# Copyright 2016-2020 Peter Dimov
# Copyright 2016-2021 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
@@ -15,27 +15,23 @@ branches:
environment:
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
TOOLSET: msvc-14.0
TOOLSET: msvc-9.0,msvc-10.0,msvc-11.0
ADDRMD: 32
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
TOOLSET: msvc-12.0,msvc-14.0
ADDRMD: 32,64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
TOOLSET: msvc-14.1
CXXSTD: 14,17
ADDRMD: 32,64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
TOOLSET: clang-win
CXXSTD: 14,17,latest
ADDRMD: 32,64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
TOOLSET: msvc-14.2
CXXSTD: 14,17,latest
CXXSTD: 14,17,20,latest
ADDRMD: 32,64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
TOOLSET: clang-win
CXXSTD: 14,17,latest
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
TOOLSET: msvc-14.2
CXXSTD: 14,17,latest
CXXSTD: 14,17,20,latest
ADDRMD: 32,64
CXXFLAGS: -Zc:preprocessor
install:
- set BOOST_BRANCH=develop

20
build.jam Normal file
View File

@@ -0,0 +1,20 @@
# Copyright 2023-2024 René Ferdinand Rivera Morell
# Copyright 2024 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
require-b2 5.2 ;
constant boost_dependencies :
/boost/mp11//boost_mp11
;
project /boost/describe ;
explicit
[ alias boost_describe : : : : <include>include <library>$(boost_dependencies) ]
[ alias all : boost_describe test ]
;
call-if : boost-library describe
;

View File

@@ -9,6 +9,7 @@ Peter Dimov
:toc: left
:toclevels: 4
:idprefix:
:listing-caption: Code Example
:docinfo: private-footer
:source-highlighter: rouge
:source-language: c++
@@ -16,6 +17,7 @@ Peter Dimov
:leveloffset: +1
include::describe/overview.adoc[]
include::describe/changes.adoc[]
include::describe/enums.adoc[]
include::describe/classes.adoc[]
include::describe/examples.adoc[]

43
doc/describe/changes.adoc Normal file
View File

@@ -0,0 +1,43 @@
////
Copyright 2021 Peter Dimov
Distributed under the Boost Software License, Version 1.0.
https://www.boost.org/LICENSE_1_0.txt
////
[#changes]
# Revision History
:idprefix:
## Changes in Boost 1.91.0
* Under {cpp}20, described nested enums now work when the enclosing class is still incomplete. (Thanks to Julien Blanc.)
* Made `enum_to_string` constexpr. (Thanks to Julien Blanc.)
## Changes in Boost 1.84.0
* Added an overload of `enum_from_string` that takes a string view, to avoid
the need for null termination.
## Changes in Boost 1.81.0
* To allow the inclusion of `enumerators.hpp`, `bases.hpp`, and `members.hpp`
when the option `-pedantic` is used, the invocation of `BOOST_DESCRIBE_ENUM`
has been moved from `modifiers.hpp` into a separate header,
`modifier_description.hpp`. As a consequence, `modifiers.hpp` no longer
includes `enum.hpp`. Code that has been relying on this implicit inclusion
may fail, and will need to be fixed to include `enum.hpp`.
## Changes in Boost 1.79.0
* Enabled unions in `BOOST_DESCRIBE_STRUCT` and updated examples to check `std::is_union<T>`.
* Added example of defining a `fmtlib` class formatter.
* Added example of defining a `fmtlib` enum formatter.
* Added example of printing pointers to members.
## Changes in Boost 1.78.0
* Added `has_describe_enumerators`, `has_describe_bases`, `has_describe_members`.
* Added `enum_to_string`, `enum_from_string`.
* Added relational and stream insertion operators.
* Added `descriptor_by_name`, `descriptor_by_pointer`.
* Added `struct_to_tuple` example.

View File

@@ -8,5 +8,5 @@ https://www.boost.org/LICENSE_1_0.txt
# Copyright and License
:idprefix:
This documentation is copyright 2020 Peter Dimov and is distributed under
This documentation is copyright 2020, 2021 Peter Dimov and is distributed under
the http://www.boost.org/LICENSE_1_0.txt[Boost Software License, Version 1.0].

View File

@@ -19,6 +19,15 @@ descriptors using `mp11::mp_for_each` and prints them.
include::../../example/printing_enums_ct.cpp[lines=5..-1]
----
Sample output:
[listing]
----
v1: 11
v2: 12
v3: 5
----
[#example_printing_enums_rt]
## Printing Enumerators with a Run Time Loop
@@ -31,41 +40,70 @@ an ordinary `for` loop, instead of `mp_for_each`.
include::../../example/printing_enums_rt.cpp[lines=5..-1]
----
Sample output:
[listing]
----
v1: 0
v2: 1
v3: 2
v4: 3
v5: 4
v6: 5
----
[#example_enum_to_string]
## enum_to_string
This example shows a function that, given an enumerator
value, returns its name.
Providing `enum_to_string` in a library is made difficult
by the fact that the desired behavior when the passed value
does not correspond to a named enumerator varies depending
on the specific use case. But, since defining the function
is trivial when `describe_enumerators` is available, every
user can easily have his own.
This specific example elects to return `"(unnamed)"` when
the enum value doesn't have a name.
value, returns its name. If the value does not correspond
to a named value, the function returns `"(unnamed)"`.
[source]
----
include::../../example/enum_to_string.cpp[lines=5..-1]
----
Sample output:
[listing]
----
E(3): v1
E(0): (unnamed)
----
Since release 1.78.0, the library provides `enum_to_string`.
It differs from the one in the example by having a second
parameter that determines what should be returned when the
value doesn't correspond to a named enumerator.
[#example_string_to_enum]
## string_to_enum
The opposite of the previous example; returns an enumerator
value when given the enumerator name. The same problem exists
here with respect to the error handling strategy when the string
passed does not correspond to any enumerator name. This example
throws an exception.
value when given the enumerator name. When the string passed
does not correspond to any enumerator name, throws an exception.
[source]
----
include::../../example/string_to_enum.cpp[lines=5..-1]
----
Sample output:
[listing]
----
v1: 0
v2: 1
v3: 2
v4: Invalid enumerator name 'v4' for enum type 'enum E'
----
Since release 1.78.0, the library provides `enum_from_string`.
It differs from the function in the example by signaling failure
by a `bool` return value instead of using exceptions. The
enumerator value is assigned to the output argument.
[#example_print_function]
## Defining a Universal Print Function
@@ -86,6 +124,34 @@ change its state and hence cannot violate its invariant.)
include::../../example/print_function.cpp[lines=5..-1]
----
Sample output:
[listing]
----
{{.m1 = 1}, {.m2 = 2}, .m1 = 3, .m2 = 4}
----
Since release 1.78.0, this universal `operator<<` is supplied
by the library, in the `boost::describe::operators` namespace.
It's enabled by means of a using declaration in the namespace
containing the described application types, like in the example
below:
```
namespace app
{
struct X
{
int a = 1;
};
BOOST_DESCRIBE_STRUCT(X, (), (a))
using boost::describe::operators::operator<<;
}
```
[#example_hash_value]
## Implementing hash_value
@@ -97,11 +163,25 @@ calling `boost::hash_combine` on each.
The overload is defined in namespace `app` in order to apply
to all annotated classes also defined in `app`.
NOTE: Since release 1.81.0, Boost.ContainerHash provides its
own, built-in, support for described classes, by having an
overload of `boost::hash_value` very similar to the one given
below. Consequently, when using Boost 1.81.0 or later, you
don't need the below `hash_value` function, as it will cause
an ambiguity.
[source]
----
include::../../example/hash_value.cpp[lines=5..-1]
----
Sample output:
[listing]
----
12526671134390370097
----
[#example_equality]
## Implementing operator==
@@ -117,6 +197,56 @@ to all annotated classes also defined in `app`.
include::../../example/equality.cpp[lines=5..-1]
----
Sample output:
[listing]
----
true false
----
Since release 1.78.0, this universal `operator==` is supplied
by the library, in the `boost::describe::operators` namespace.
It's enabled by means of a using declaration in the namespace
containing the described application types, like in the example
below:
```
namespace app
{
struct X
{
int a = 1;
};
BOOST_DESCRIBE_STRUCT(X, (), (a))
using boost::describe::operators::operator==;
}
```
The rest of the relational operators are also provided and can
be enabled similarly.
[#example_struct_to_tuple]
## struct_to_tuple
This example defines a function `struct_to_tuple` that takes
a described class type as an argument and returns a tuple of
all its public members.
[source]
----
include::../../example/struct_to_tuple.cpp[lines=5..-1]
----
Sample output:
[listing]
----
std::tuple<int, float>: 1, 3.14
----
[#example_to_json]
## Automatic Conversion to JSON
@@ -133,11 +263,23 @@ The presence of private members is taken as an indication that
a universal conversion is not suitable, so the overload is
disabled in this case using `std::enable_if_t`.
NOTE: Since release 1.81.0, Boost.JSON provides its
own, built-in, support for described classes. Consequently,
when using Boost 1.81.0 or later, you don't need the below
`tag_invoke` function.
[source]
----
include::../../example/to_json.cpp[lines=5..-1]
----
Sample output:
[listing]
----
{"v":[{"x":1,"y":2},{"x":3,"y":4}],"m":{"k1":{"x":5,"y":6},"k2":{"x":7,"y":8}}}
----
[#example_from_json]
## Automatic Conversion from JSON
@@ -145,11 +287,24 @@ Like the previous example, but in the other direction. Defines
a `tag_invoke` overload that converts a `boost::json::value` to
an annotated struct.
NOTE: Since release 1.81.0, Boost.JSON provides its
own, built-in, support for described classes. Consequently,
when using Boost 1.81.0 or later, you don't need the below
`tag_invoke` function.
[source]
----
include::../../example/from_json.cpp[lines=5..-1]
----
Sample output:
[listing]
----
jv: {"x":1,"y":2}
a: { 1, 2 }
----
[#example_serialization]
## Automatic Serialization
@@ -162,6 +317,49 @@ support to annotated classes.
include::../../example/serialization.cpp[lines=5..-1]
----
Sample output:
[listing]
----
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<!DOCTYPE boost_serialization>
<boost_serialization signature="serialization::archive" version="19">
<c1 class_id="0" tracking_level="0" version="0">
<v class_id="1" tracking_level="0" version="0">
<count>3</count>
<item_version>0</item_version>
<item class_id="2" tracking_level="0" version="0">
<base.1 class_id="3" tracking_level="0" version="0">
<x>1</x>
</base.1>
<base.2 class_id="4" tracking_level="0" version="0">
<y>2</y>
</base.2>
</item>
<item>
<base.1>
<x>3</x>
</base.1>
<base.2>
<y>4</y>
</base.2>
</item>
<item>
<base.1>
<x>5</x>
</base.1>
<base.2>
<y>6</y>
</base.2>
</item>
</v>
</c1>
</boost_serialization>
22 serialization::archive 19 0 0 0 0 3 0 0 0 0 0 1 0 0 2 3 4 5 6
----
[#example_json_rpc]
## Automatic JSON RPC
@@ -175,6 +373,14 @@ in a `boost::json::value`.
include::../../example/json_rpc.cpp[lines=5..-1]
----
Sample output:
[listing]
----
"Hello, world!"
3
----
[#example_console]
## Interactive Variable Console
@@ -186,3 +392,120 @@ for converting the variables to and from a string form.
----
include::../../example/console.cpp[lines=9..-1]
----
Sample output:
[listing]
----
> help
"Enter a variable name ('x', 'y', 'v', or 'm') to print its value; enter variable=value to assign a new value to a variable. Values are in JSON format."
> x
1
> y
3.14E0
> v
[1,2,3]
> m
{"BTC":4.489868E4,"ETH":1.38657E3}
> x="hello"
Error: not a number [boost.json:15]
> x=3.14
Error: not exact [boost.json:16]
> x=4
> x
4
> y=6.28
> y
6.28E0
> v=["hello", "world"]
Error: not a number [boost.json:15]
> v=[1.2, 3.4]
Error: not exact [boost.json:16]
> v=[11, 27]
> c
Error: 'c': no such variable
> v
[11,27]
> m={"BTC": 42139.07, "ETH": 2912.00}
> m
{"BTC":4.213907E4,"ETH":2.912E3}
----
[#example_fmtlib_class_formatter]
## `fmtlib` Class Formatter
This example defines a universal https://github.com/fmtlib/fmt[`fmtlib`]
formatter that works on any class or struct type that has been described
with `BOOST_DESCRIBE_STRUCT` or `BOOST_DESCRIBE_CLASS`. It's similar to
<<example_print_function,the universal print function shown above>>.
[source]
----
include::../../example/fmtlib_class_formatter.cpp[lines=5..-1]
----
Sample output:
[listing]
----
{ { .r=255, .g=192, .b=16 }, .first={ .x=1, .y=2 }, .last={ .x=3, .y=4 } }
----
[#example_fmtlib_enum_formatter]
## `fmtlib` Enum Formatter
This example defines a https://github.com/fmtlib/fmt[`fmtlib`] formatter
for described enums.
[source]
----
include::../../example/fmtlib_enum_formatter.cpp[lines=5..-1]
----
Sample output:
[listing]
----
____v1____
____7_____
----
[#example_pm_to_string]
## Printing Pointers to Members
This example defines an `operator<<` overload for pointers to members.
[source]
----
include::../../example/pm_to_string.cpp[lines=9..-1]
----
Sample output:
[listing]
----
&X::m [int]
&X::f [int() const]
&Y::m [int]
&X::f [int() const]
&Y::g [int() const]
&Z::(unknown) [void()]
----

View File

@@ -15,11 +15,11 @@ https://boost.org/libs/mp11[Boost.Mp11].
## Supported Compilers
* GCC 5 or later with `-std=c++14` or above
* Clang 3.6 or later with `-std=c++14` or above
* Visual Studio 2015, 2017, 2019
* Clang 3.9 or later with `-std=c++14` or above
* Visual Studio 2015 or later
Tested on https://travis-ci.org/github/pdimov/describe[Travis] and
https://ci.appveyor.com/project/pdimov/describe[Appveyor].
Tested on https://github.com/boostorg/describe/actions[Github Actions]
and https://ci.appveyor.com/project/pdimov/describe[Appveyor].
## Limitations

View File

@@ -88,7 +88,7 @@ enum class E: Base { v1, v2, ..., vN };
BOOST_DESCRIBE_ENUM(E, v1, v2, ..., vN)
```
## <boost/describe/enumerators.hpp>
## <boost/describe/{zwsp}enumerators{zwsp}.hpp>
```
namespace boost {
@@ -96,6 +96,8 @@ namespace describe {
template<class E> using describe_enumerators = /*...*/;
template<class E> using has_describe_enumerators = /*...*/;
} }
```
@@ -116,6 +118,14 @@ struct Di
```
where `vi` is the i-th enumerator.
If `E` is not a described enumeration type, `describe_enumerators<E>` causes
a substitution failure.
### has_describe_enumerators<E>
`has_describe_enumerators<E>::value` is `true` when `E` is a described
enumeration type, `false` otherwise.
## <boost/describe/class.hpp>
```
@@ -200,7 +210,7 @@ enum modifiers
mod_function = 32,
mod_any_member = 64,
mod_inherited = 128,
mod_hidden = 256,
mod_hidden = 256
};
constexpr modifiers mod_any_access = static_cast<modifiers>( mod_public | mod_protected | mod_private );
@@ -224,6 +234,12 @@ following flags:
* `mod_inherited` - includes members of base classes
* `mod_hidden` - includes hidden inherited members
## <boost/describe/{zwsp}modifier_description.hpp>
The header `modifier_description.hpp` includes `modifiers.hpp` and invokes
`BOOST_DESCRIBE_ENUM` on `modifiers`, allowing `describe_enumerators<modifiers>`
to work.
## <boost/describe/bases.hpp>
```
@@ -232,6 +248,8 @@ namespace describe {
template<class T, unsigned M> using describe_bases = /*...*/;
template<class T> using has_describe_bases = /*...*/;
} }
```
@@ -257,6 +275,18 @@ where `type` is the type of the base class, and `modifiers` are a bitwise-or
combination of `mod_public`, `mod_protected`, `mod_private`, and `mod_virtual`
that reflects the properties of the base class.
If `T` is not a described class type, `describe_bases<T, M>` causes a
substitution failure.
### has_describe_bases<T>
`has_describe_bases<T>::value` is `true` when `T` is a described class type,
`false` otherwise.
Since the library does not provide a way to describe bases and members separately,
`has_describe_bases` and `has_describe_members` are, in practice, synonyms. They
are provided separately for consistency.
## <boost/describe/members.hpp>
```
@@ -265,6 +295,8 @@ namespace describe {
template<class T, unsigned M> using describe_members = /*...*/;
template<class T> using has_describe_members = /*...*/;
} }
```
@@ -294,6 +326,195 @@ member, and `modifiers` are a bitwise-or combination of `mod_public`,
`mod_protected`, `mod_private`, `mod_static`, `mod_function`, `mod_inherited`,
and `mod_hidden` that reflects the properties of the member.
If `T` is not a described class type, `describe_members<T, M>` causes a
substitution failure.
### has_describe_members<T>
`has_describe_members<T>::value` is `true` when `T` is a described class type,
`false` otherwise.
Since the library does not provide a way to describe bases and members separately,
`has_describe_bases` and `has_describe_members` are, in practice, synonyms. They
are provided separately for consistency.
## <boost/describe/{zwsp}enum_to_string{zwsp}.hpp>
```
namespace boost {
namespace describe {
template<class E> char const * enum_to_string( E e, char const * def ) noexcept;
} }
```
### enum_to_string
The function `enum_to_string` returns the name of the enumerator `e`. `E` must
be a described enumeration type. If `e` does not correspond to one of the described
values, the function returns `def`.
## <boost/describe/{zwsp}enum_from_string{zwsp}.hpp>
```
namespace boost {
namespace describe {
template<class E> bool enum_from_string( char const * name, E & e ) noexcept;
template<class S, class E> bool enum_from_string( S const & name, E & e ) noexcept;
} }
```
### enum_from_string
The function `enum_from_string` assigns to `e` the enumerator value corresponding
to `name` and returns `true`. `E` must be a described enumeration type. If `name`
does not correspond to one of the described values, the function returns `false`.
The second overload only participates in overload resolution when `S` is a
string-like type such as `std::string` or `std::string_view`. String-like types
are recognized by the presence of nested `value_type` and `traits_type` typedefs
and are expected to have a non-throwing `operator==` taking `char const*`.
## <boost/describe/operators.hpp>
```
namespace boost {
namespace describe {
namespace operators {
template<class T> bool operator==( T const& t1, T const& t2 );
template<class T> bool operator!=( T const& t1, T const& t2 );
template<class T> bool operator<( T const& t1, T const& t2 );
template<class T> bool operator>( T const& t1, T const& t2 );
template<class T> bool operator<=( T const& t1, T const& t2 );
template<class T> bool operator>=( T const& t1, T const& t2 );
template<class T, class Ch, class Tr>
std::basic_ostream<Ch, Tr>&
operator<<( std::basic_ostream<Ch, Tr>& os, T const& t );
} } }
```
The header `<boost/describe/operators.hpp>` defines generic operators for
described class types. They are used by bringing them into the namespace
containing the described types via a using declaration, as in the example
below:
```
namespace app
{
struct X
{
int a = 1;
};
BOOST_DESCRIBE_STRUCT(X, (), (a))
using boost::describe::operators::operator==;
using boost::describe::operators::operator!=;
using boost::describe::operators::operator<<;
}
```
### operator==
If all bases and members compare equal, returns `true`, otherwise `false`.
### operator!=
Returns the negation of `operator==`.
### operator<
Performs a lexicographical comparison over the bases and members in sequence
using `operator<` and returns the result.
### operator>
Returns the result of `operator<` with the arguments reversed.
### operator\<=
Returns the negated result of `operator>`.
### operator>=
Returns the negated result of `operator<`.
### operator<<
Outputs a representation of `t` to `os` by recursively using `operator<<`
to output all bases and then all members.
## <boost/describe/{zwsp}descriptor_by_name{zwsp}.hpp>
```
namespace boost {
namespace describe {
#define BOOST_DESCRIBE_MAKE_NAME(s) /*...*/
template<class L, class N> using descriptor_by_name = /*...*/;
} }
```
### BOOST_DESCRIBE_MAKE_NAME
The macro `BOOST_DESCRIBE_MAKE_NAME` creates a type that identifies the
name given as an argument. It should be used as follows:
```
using N = BOOST_DESCRIBE_MAKE_NAME(some_member);
```
### descriptor_by_name
`descriptor_by_name<L, N>` searches the descriptor list `L` for the member
with the name identified by `N`. `N` should be a type created by
`BOOST_DESCRIBE_MAKE_NAME` as in the above example. `L` is intended to be
a list returned by `describe_members`, although since enumerator descriptors
also have `::name`, a list returned by `describe_enumerators` will work as
well.
.Using descriptor_by_name
```
using L = describe_members<SomeType, mod_any_access>;
using N = BOOST_DESCRIBE_MAKE_NAME(some_member);
using D = descriptor_by_name<L, N>; // descriptor for SomeType::some_member
```
## <boost/describe/{zwsp}descriptor_by_pointer{zwsp}.hpp>
```
namespace boost {
namespace describe {
template<class L, auto Pm> using descriptor_by_pointer = /*...*/;
} }
```
### descriptor_by_pointer
`descriptor_by_pointer<L, Pm>` searches the descriptor list `L` for the member
pointer `Pm`. `L` should be a list returned by `describe_members`.
Since `auto` template parameters are a {cpp}17 feature, using
`descriptor_by_pointer` requires {cpp}17.
.Using descriptor_by_pointer
```
using L = describe_members<X, mod_any_access>;
using D = descriptor_by_pointer<L, &X::a>; // descriptor for X::a
```
## <boost/describe.hpp>
This convenience header includes all the headers previously

View File

@@ -13,7 +13,8 @@ namespace app
{
template<class T,
class Bd = describe_bases<T, mod_any_access>,
class Md = describe_members<T, mod_any_access>>
class Md = describe_members<T, mod_any_access>,
class En = std::enable_if_t<!std::is_union<T>::value> >
bool operator==( T const& t1, T const& t2 )
{
bool r = true;

View File

@@ -0,0 +1,101 @@
// Copyright 2022 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe.hpp>
#include <boost/mp11.hpp>
#include <fmt/format.h>
#include <type_traits>
template<class T> struct fmt::formatter<T, char, std::enable_if_t<
boost::describe::has_describe_bases<T>::value &&
boost::describe::has_describe_members<T>::value &&
!std::is_union<T>::value>>
{
constexpr auto parse( format_parse_context& ctx )
{
auto it = ctx.begin(), end = ctx.end();
if( it != end && *it != '}' )
{
throw_format_error( "invalid format" );
}
return it;
}
auto format( T const& t, format_context& ctx ) const
{
using namespace boost::describe;
using Bd = describe_bases<T, mod_any_access>;
using Md = describe_members<T, mod_any_access>;
auto out = ctx.out();
*out++ = '{';
bool first = true;
boost::mp11::mp_for_each<Bd>([&](auto D){
if( !first )
{
*out++ = ',';
}
first = false;
out = fmt::format_to( out, " {}",
(typename decltype(D)::type const&)t );
});
boost::mp11::mp_for_each<Md>([&](auto D){
if( !first )
{
*out++ = ',';
}
first = false;
out = fmt::format_to( out, " .{}={}",
D.name, t.*D.pointer );
});
if( !first )
{
*out++ = ' ';
}
*out++ = '}';
return out;
}
};
struct point
{
int x, y;
};
BOOST_DESCRIBE_STRUCT( point, (), (x, y) )
struct color
{
unsigned char r, g, b;
};
BOOST_DESCRIBE_STRUCT( color, (), (r, g, b) )
struct line: color
{
point first, last;
};
BOOST_DESCRIBE_STRUCT( line, (color), (first, last) )
int main()
{
fmt::print( "{}\n", line{ { 255, 192, 16 }, { 1, 2 }, { 3, 4 } } );
}

View File

@@ -0,0 +1,60 @@
// Copyright 2022 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe.hpp>
#include <fmt/format.h>
#include <type_traits>
template<class T> struct fmt::formatter<T, char, std::enable_if_t<
boost::describe::has_describe_enumerators<T>::value>>
{
private:
using U = std::underlying_type_t<T>;
fmt::formatter<fmt::string_view, char> sf_;
fmt::formatter<U, char> nf_;
public:
constexpr auto parse( format_parse_context& ctx )
{
auto i1 = sf_.parse( ctx );
auto i2 = nf_.parse( ctx );
if( i1 != i2 )
{
throw_format_error( "invalid format" );
}
return i1;
}
auto format( T const& t, format_context& ctx ) const
{
char const * s = boost::describe::enum_to_string( t, 0 );
if( s )
{
return sf_.format( s, ctx );
}
else
{
return nf_.format( static_cast<U>( t ), ctx );
}
}
};
enum E1
{
v1, v2, v3 = 11
};
BOOST_DESCRIBE_ENUM( E1, v1, v2, v3 )
int main()
{
fmt::print( "{:_^10}\n", E1::v1 );
fmt::print( "{:_^10}\n", (E1)7 );
}

View File

@@ -5,11 +5,14 @@
#include <boost/describe.hpp>
#include <boost/mp11.hpp>
#include <boost/json.hpp>
#include <boost/version.hpp>
#include <type_traits>
namespace app
{
#if BOOST_VERSION < 108100
template<class T> void extract( boost::json::object const & obj, char const * name, T & value )
{
value = boost::json::value_to<T>( obj.at( name ) );
@@ -19,7 +22,7 @@ template<class T,
class D1 = boost::describe::describe_members<T,
boost::describe::mod_public | boost::describe::mod_protected>,
class D2 = boost::describe::describe_members<T, boost::describe::mod_private>,
class En = std::enable_if_t<boost::mp11::mp_empty<D2>::value> >
class En = std::enable_if_t<boost::mp11::mp_empty<D2>::value && !std::is_union<T>::value> >
T tag_invoke( boost::json::value_to_tag<T> const&, boost::json::value const& v )
{
@@ -36,6 +39,8 @@ template<class T,
return t;
}
#endif
struct A
{
int x;

View File

@@ -1,11 +1,12 @@
// Copyright 2021 Peter Dimov
// Copyright 2021, 2022 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/container_hash/hash.hpp>
#include <boost/describe.hpp>
#include <boost/mp11.hpp>
#include <boost/container_hash/hash.hpp>
#include <boost/variant2/variant.hpp>
#include <boost/version.hpp>
#include <vector>
using namespace boost::describe;
@@ -13,9 +14,12 @@ using namespace boost::describe;
namespace app
{
#if BOOST_VERSION < 108100
template<class T,
class Bd = describe_bases<T, mod_any_access>,
class Md = describe_members<T, mod_any_access>>
class Md = describe_members<T, mod_any_access>,
class En = std::enable_if_t<!std::is_union<T>::value> >
std::size_t hash_value( T const & t )
{
std::size_t r = 0;
@@ -36,6 +40,8 @@ template<class T,
return r;
}
#endif
struct A
{
int x = 1;

View File

@@ -34,7 +34,7 @@ template<class C1, class C2, class R, class... A>
template<class C>
boost::json::value
call( C & c, boost::string_view method, boost::json::value const & args )
call( C & c, boost::string_view method, boost::json::array const & args )
{
using Fd = boost::describe::describe_members<C,
boost::describe::mod_public | boost::describe::mod_function>;
@@ -46,7 +46,7 @@ template<class C>
if( !found && method == D.name)
{
result = call_impl( c, D.pointer, args.as_array() );
result = call_impl( c, D.pointer, args );
found = true;
}

125
example/pm_to_string.cpp Normal file
View File

@@ -0,0 +1,125 @@
// Copyright 2022 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#if defined(__GNUC__) && __GNUC__ == 12
# pragma GCC diagnostic ignored "-Wrestrict" // false positive
#endif
#include <boost/describe.hpp>
#include <boost/mp11.hpp>
#include <boost/core/type_name.hpp>
#include <string>
#include <ostream>
namespace detail
{
template<class T1, class T2>
constexpr auto equals( T1 t1, T2 t2, int ) -> decltype( t1 == t2 )
{
return t1 == t2;
}
template<class T1, class T2>
constexpr bool equals( T1 /*t1*/, T2 /*t2*/, long )
{
return false;
}
using namespace boost::describe;
template<class T, class C,
class L = describe_members<C, mod_any_access | mod_any_member>>
char const* get_member_name( T C::* pm, int )
{
char const * name = nullptr;
boost::mp11::mp_for_each<L>([&](auto D){
if( equals( D.pointer, pm, 0 ) ) name = D.name;
});
return name;
}
template<class T, class C>
char const* get_member_name( T C::* /*pm*/, long )
{
return nullptr;
}
} // namespace detail
template<class T, class C>
std::string pm_to_string( T C::* pm )
{
char const * name = ::detail::get_member_name( pm, 0 );
if( name == nullptr ) name = "(unknown)";
return "&" + boost::core::type_name<C>() + "::" + name
+ " [" + boost::core::type_name<T>() + "]";
}
template<class T, class C>
std::ostream& operator<<( std::ostream& os, T C::* pm )
{
os << pm_to_string( pm );
return os;
}
struct X
{
int m;
int f() const { return m; }
};
BOOST_DESCRIBE_STRUCT(X, (), (m, f))
struct Y: public X
{
int m;
int g() const { return -m; }
};
BOOST_DESCRIBE_STRUCT(Y, (X), (m, g))
struct Z
{
void h() {}
};
#if !defined(_MSC_VER) || defined(__clang__)
// MSVC doesn't support BOOST_DESCRIBE_CLASS inside
// templates until 2022 in C++20 mode
template<class T1, class T2> struct pair
{
T1 first;
T2 second;
BOOST_DESCRIBE_CLASS(pair, (), (first, second), (), ())
};
#endif
#include <iostream>
int main()
{
std::cout << &X::m << std::endl;
std::cout << &X::f << std::endl;
std::cout << &Y::m << std::endl;
std::cout << &Y::f << std::endl;
std::cout << &Y::g << std::endl;
std::cout << &Z::h << std::endl;
#if !defined(_MSC_VER) || defined(__clang__)
std::cout << &pair<int, float>::second << std::endl;
#endif
}

View File

@@ -10,7 +10,8 @@ using namespace boost::describe;
template<class T,
class Bd = describe_bases<T, mod_any_access>,
class Md = describe_members<T, mod_any_access>>
class Md = describe_members<T, mod_any_access>,
class En = std::enable_if_t<!std::is_union<T>::value> >
std::ostream& operator<<( std::ostream & os, T const & t )
{
os << "{";

View File

@@ -24,8 +24,8 @@ template<class Archive, class T,
class D3 = boost::describe::describe_members<T,
boost::describe::mod_public | boost::describe::mod_protected>,
class D4 = boost::describe::describe_members<T, boost::describe::mod_private>,
class En = std::enable_if_t<
boost::mp11::mp_empty<D2>::value && boost::mp11::mp_empty<D4>::value> >
class En = std::enable_if_t< boost::mp11::mp_empty<D2>::value &&
boost::mp11::mp_empty<D4>::value && !std::is_union<T>::value> >
void serialize( Archive & ar, T & t, boost::serialization::version_type )
{

View File

@@ -0,0 +1,57 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe.hpp>
#include <tuple>
namespace desc = boost::describe;
template<class T, template<class...> class L, class... D>
auto struct_to_tuple_impl( T const& t, L<D...> )
{
return std::make_tuple( t.*D::pointer... );
}
template<class T,
class Dm = desc::describe_members<T,
desc::mod_public | desc::mod_inherited>,
class En = std::enable_if_t<!std::is_union<T>::value> >
auto struct_to_tuple( T const& t )
{
return struct_to_tuple_impl( t, Dm() );
}
#include <boost/core/type_name.hpp>
#include <iostream>
struct X
{
int a = 1;
};
BOOST_DESCRIBE_STRUCT(X, (), (a))
struct Y
{
float b = 3.14f;
};
BOOST_DESCRIBE_STRUCT(Y, (), (b))
struct Z: X, Y
{
};
BOOST_DESCRIBE_STRUCT(Z, (X, Y), ())
int main()
{
Z z;
auto tp = struct_to_tuple( z );
std::cout <<
boost::core::type_name<decltype(tp)>() << ": "
<< std::get<0>(tp) << ", " << std::get<1>(tp);
}

View File

@@ -5,6 +5,7 @@
#include <boost/describe.hpp>
#include <boost/mp11.hpp>
#include <boost/json.hpp>
#include <boost/version.hpp>
#include <type_traits>
#include <vector>
#include <map>
@@ -12,11 +13,13 @@
namespace app
{
#if BOOST_VERSION < 108100
template<class T,
class D1 = boost::describe::describe_members<T,
boost::describe::mod_public | boost::describe::mod_protected>,
class D2 = boost::describe::describe_members<T, boost::describe::mod_private>,
class En = std::enable_if_t<boost::mp11::mp_empty<D2>::value> >
class En = std::enable_if_t<boost::mp11::mp_empty<D2>::value && !std::is_union<T>::value> >
void tag_invoke( boost::json::value_from_tag const&, boost::json::value& v, T const & t )
{
@@ -29,6 +32,8 @@ template<class T,
});
}
#endif
struct A
{
int x;

View File

@@ -11,5 +11,11 @@
#include <boost/describe/enum.hpp>
#include <boost/describe/class.hpp>
#include <boost/describe/modifiers.hpp>
#include <boost/describe/enum_to_string.hpp>
#include <boost/describe/enum_from_string.hpp>
#include <boost/describe/operators.hpp>
#include <boost/describe/descriptor_by_name.hpp>
#include <boost/describe/descriptor_by_pointer.hpp>
#include <boost/describe/modifier_description.hpp>
#endif // #ifndef BOOST_DESCRIBE_HPP_INCLUDED

View File

@@ -1,16 +1,18 @@
#ifndef BOOST_DESCRIBE_BASES_HPP_INCLUDED
#define BOOST_DESCRIBE_BASES_HPP_INCLUDED
// Copyright 2020 Peter Dimov
// Copyright 2020, 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/modifiers.hpp>
#include <boost/describe/detail/void_t.hpp>
#include <boost/describe/detail/config.hpp>
#if defined(BOOST_DESCRIBE_CXX11)
#include <boost/mp11/algorithm.hpp>
#include <type_traits>
namespace boost
{
@@ -19,17 +21,27 @@ namespace describe
namespace detail
{
template<class T> using _describe_bases = decltype( boost_base_descriptor_fn( static_cast<T*>(0) ) );
template<class T> using _describe_bases = decltype( boost_base_descriptor_fn( static_cast<T**>(0) ) );
template<unsigned M> struct base_filter
{
template<class T> using fn = mp11::mp_bool< ( M & mod_any_access & T::modifiers ) != 0 >;
};
template<class T, class En = void> struct has_describe_bases: std::false_type
{
};
template<class T> struct has_describe_bases<T, void_t<_describe_bases<T>>>: std::true_type
{
};
} // namespace detail
template<class T, unsigned M> using describe_bases = mp11::mp_copy_if_q<detail::_describe_bases<T>, detail::base_filter<M>>;
template<class T> using has_describe_bases = detail::has_describe_bases<T>;
} // namespace describe
} // namespace boost

View File

@@ -34,7 +34,7 @@ namespace describe
friend BOOST_DESCRIBE_PRIVATE_MEMBERS(C, BOOST_DESCRIBE_PP_UNPACK Private)
#define BOOST_DESCRIBE_STRUCT(C, Bases, Members) \
static_assert(std::is_class<C>::value, "BOOST_DESCRIBE_STRUCT should only be used with class types"); \
static_assert(std::is_class<C>::value || std::is_union<C>::value, "BOOST_DESCRIBE_STRUCT should only be used with class types"); \
BOOST_DESCRIBE_BASES(C, BOOST_DESCRIBE_PP_UNPACK Bases) \
BOOST_DESCRIBE_PUBLIC_MEMBERS(C, BOOST_DESCRIBE_PP_UNPACK Members) \
BOOST_DESCRIBE_PROTECTED_MEMBERS(C) \
@@ -54,17 +54,17 @@ namespace describe
#define BOOST_DESCRIBE_PRIVATE_MEMBERS_(...) BOOST_DESCRIBE_PRIVATE_MEMBERS(__VA_ARGS__)
#define BOOST_DESCRIBE_CLASS(C, Bases, Public, Protected, Private) \
friend BOOST_DESCRIBE_BASES_(C BOOST_DESCRIBE_PP_UNPACK Bases) \
friend BOOST_DESCRIBE_PUBLIC_MEMBERS_(C BOOST_DESCRIBE_PP_UNPACK Public) \
friend BOOST_DESCRIBE_PROTECTED_MEMBERS_(C BOOST_DESCRIBE_PP_UNPACK Protected) \
friend BOOST_DESCRIBE_PRIVATE_MEMBERS_(C BOOST_DESCRIBE_PP_UNPACK Private)
BOOST_DESCRIBE_MAYBE_UNUSED friend BOOST_DESCRIBE_BASES_(C BOOST_DESCRIBE_PP_UNPACK Bases) \
BOOST_DESCRIBE_MAYBE_UNUSED friend BOOST_DESCRIBE_PUBLIC_MEMBERS_(C BOOST_DESCRIBE_PP_UNPACK Public) \
BOOST_DESCRIBE_MAYBE_UNUSED friend BOOST_DESCRIBE_PROTECTED_MEMBERS_(C BOOST_DESCRIBE_PP_UNPACK Protected) \
BOOST_DESCRIBE_MAYBE_UNUSED friend BOOST_DESCRIBE_PRIVATE_MEMBERS_(C BOOST_DESCRIBE_PP_UNPACK Private)
#define BOOST_DESCRIBE_STRUCT(C, Bases, Members) \
static_assert(std::is_class<C>::value, "BOOST_DESCRIBE_STRUCT should only be used with class types"); \
BOOST_DESCRIBE_BASES_(C BOOST_DESCRIBE_PP_UNPACK Bases) \
BOOST_DESCRIBE_PUBLIC_MEMBERS_(C BOOST_DESCRIBE_PP_UNPACK Members) \
BOOST_DESCRIBE_PROTECTED_MEMBERS_(C) \
BOOST_DESCRIBE_PRIVATE_MEMBERS_(C)
static_assert(std::is_class<C>::value || std::is_union<C>::value, "BOOST_DESCRIBE_STRUCT should only be used with class types"); \
BOOST_DESCRIBE_MAYBE_UNUSED BOOST_DESCRIBE_BASES_(C BOOST_DESCRIBE_PP_UNPACK Bases) \
BOOST_DESCRIBE_MAYBE_UNUSED BOOST_DESCRIBE_PUBLIC_MEMBERS_(C BOOST_DESCRIBE_PP_UNPACK Members) \
BOOST_DESCRIBE_MAYBE_UNUSED BOOST_DESCRIBE_PROTECTED_MEMBERS_(C) \
BOOST_DESCRIBE_MAYBE_UNUSED BOOST_DESCRIBE_PRIVATE_MEMBERS_(C)
#endif

View File

@@ -0,0 +1,41 @@
#ifndef BOOST_DESCRIBE_DESCRIPTOR_BY_NAME_HPP_INCLUDED
#define BOOST_DESCRIBE_DESCRIPTOR_BY_NAME_HPP_INCLUDED
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/detail/cx_streq.hpp>
#include <boost/describe/detail/config.hpp>
#if defined(BOOST_DESCRIBE_CXX14)
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/bind.hpp>
#include <boost/mp11/integral.hpp>
namespace boost
{
namespace describe
{
namespace detail
{
template<class D, class N> using match_by_name = mp11::mp_bool<cx_streq(N::name(), D::name)>;
#define BOOST_DESCRIBE_MAKE_NAME_IMPL2(s, k) struct _boost_name_##s##_##k { static constexpr char const * name() { return #s; } }
#define BOOST_DESCRIBE_MAKE_NAME_IMPL(s, k) BOOST_DESCRIBE_MAKE_NAME_IMPL2(s, k)
} // namespace detail
#define BOOST_DESCRIBE_MAKE_NAME(s) BOOST_DESCRIBE_MAKE_NAME_IMPL(s, __LINE__)
template<class L, class N> using descriptor_by_name = mp11::mp_at<L, mp11::mp_find_if_q<L, mp11::mp_bind_back<detail::match_by_name, N>>>;
} // namespace describe
} // namespace boost
#endif // defined(BOOST_DESCRIBE_CXX14)
#endif // #ifndef BOOST_DESCRIBE_DESCRIPTOR_BY_NAME_HPP_INCLUDED

View File

@@ -0,0 +1,48 @@
#ifndef BOOST_DESCRIBE_DESCRIPTOR_BY_POINTER_HPP_INCLUDED
#define BOOST_DESCRIBE_DESCRIPTOR_BY_POINTER_HPP_INCLUDED
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/detail/config.hpp>
#if defined(__cpp_nontype_template_parameter_auto) && __cpp_nontype_template_parameter_auto >= 201606L
#include <boost/mp11/algorithm.hpp>
#include <boost/mp11/bind.hpp>
#include <boost/mp11/integral.hpp>
namespace boost
{
namespace describe
{
namespace detail
{
template<class Pm> constexpr bool cx_pmeq( Pm p1, Pm p2 )
{
return p1 == p2;
}
template<class Pm1, class Pm2> constexpr bool cx_pmeq( Pm1, Pm2 )
{
return false;
}
template<auto Pm> struct match_by_pointer
{
template<class D> using fn = mp11::mp_bool< cx_pmeq( D::pointer, Pm ) >;
};
} // namespace detail
template<class L, auto Pm> using descriptor_by_pointer = mp11::mp_at<L, mp11::mp_find_if_q<L, detail::match_by_pointer<Pm>>>;
} // namespace describe
} // namespace boost
#endif // __cpp_nontype_template_parameter_auto
#endif // #ifndef BOOST_DESCRIBE_DESCRIPTOR_BY_POINTER_HPP_INCLUDED

View File

@@ -26,27 +26,23 @@ template<class C, class B> struct base_descriptor
static constexpr unsigned modifiers = compute_base_modifiers<C, B>();
};
#ifndef __cpp_inline_variables
template<class C, class B> constexpr unsigned base_descriptor<C, B>::modifiers;
template<class... T> auto base_descriptor_fn_impl( int, T... )
{
return list<T...>();
}
#define BOOST_DESCRIBE_BASE_IMPL(C, B) , boost::describe::detail::base_descriptor<C, B>()
#if defined(_MSC_VER) && !defined(__clang__)
#define BOOST_DESCRIBE_BASES(C, ...) inline auto boost_base_descriptor_fn( C * ) \
{ return boost::describe::detail::base_descriptor_fn_impl( 0 BOOST_DESCRIBE_PP_FOR_EACH(BOOST_DESCRIBE_BASE_IMPL, C, __VA_ARGS__) ); }
#else
#define BOOST_DESCRIBE_BASES(C, ...) inline auto boost_base_descriptor_fn( C * ) \
{ return boost::describe::detail::base_descriptor_fn_impl( 0 BOOST_DESCRIBE_PP_FOR_EACH(BOOST_DESCRIBE_BASE_IMPL, C, ##__VA_ARGS__) ); }
#endif
// bases_descriptor
template<typename ...>
struct bases_descriptor_impl;
template<class C, class ...Bs>
struct bases_descriptor_impl<C, list<Bs...>>
{
using type = list<base_descriptor<C, Bs>...>;
};
#define BOOST_DESCRIBE_BASES(C, ...) inline auto boost_base_descriptor_fn( C** ) \
{ return typename boost::describe::detail::bases_descriptor_impl<C, boost::describe::detail::list<__VA_ARGS__>>::type(); }
} // namespace detail
} // namespace describe
} // namespace boost

View File

@@ -19,6 +19,10 @@
# define BOOST_DESCRIBE_CXX11
# if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 7
# undef BOOST_DESCRIBE_CXX11
# endif
#endif
#if defined(BOOST_DESCRIBE_CXX11)
@@ -27,4 +31,34 @@
# define BOOST_DESCRIBE_CONSTEXPR_OR_CONST const
#endif
#if defined(__clang__)
# define BOOST_DESCRIBE_MAYBE_UNUSED __attribute__((unused))
#else
# define BOOST_DESCRIBE_MAYBE_UNUSED
#endif
#if defined(__cpp_inline_variables) && __cpp_inline_variables >= 201606L
# define BOOST_DESCRIBE_INLINE_VARIABLE inline
#else
# define BOOST_DESCRIBE_INLINE_VARIABLE
#endif
#define BOOST_DESCRIBE_INLINE_CONSTEXPR BOOST_DESCRIBE_INLINE_VARIABLE BOOST_DESCRIBE_CONSTEXPR_OR_CONST
#if __cplusplus >= 202002L || ( defined(_MSVC_LANG) && _MSVC_LANG >= 202002L )
# define BOOST_DESCRIBE_CXX20
// Clang 13.0 is needed for unevaluated lambdas
# if defined(__clang__) && __clang_major__ < 13
# undef BOOST_DESCRIBE_CXX20
# endif
// Apple Clang 13.1 is Clang 13.0
# if defined(__clang__) && defined(__apple_build_version__) && __clang_major__ == 13 && __clang_minor__ < 1
# undef BOOST_DESCRIBE_CXX20
# endif
#endif
#endif // #ifndef BOOST_DESCRIBE_DETAIL_CONFIG_HPP_INCLUDED

View File

@@ -0,0 +1,30 @@
#ifndef BOOST_DESCRIBE_DETAIL_CX_STREQ_HPP_INCLUDED
#define BOOST_DESCRIBE_DETAIL_CX_STREQ_HPP_INCLUDED
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/detail/config.hpp>
#if defined(BOOST_DESCRIBE_CXX11)
namespace boost
{
namespace describe
{
namespace detail
{
constexpr bool cx_streq( char const * s1, char const * s2 )
{
return s1[0] == s2[0] && ( s1[0] == 0 || cx_streq( s1 + 1, s2 + 1 ) );
}
} // namespace detail
} // namespace describe
} // namespace boost
#endif // defined(BOOST_DESCRIBE_CXX11)
#endif // #ifndef BOOST_DESCRIBE_DETAIL_CX_STREQ_HPP_INCLUDED

View File

@@ -35,9 +35,11 @@ template<class D, unsigned M> struct member_descriptor
static constexpr unsigned modifiers = M | add_static_modifier( D::pointer() ) | add_function_modifier( D::pointer() );
};
#ifndef __cpp_inline_variables
template<class D, unsigned M> constexpr decltype(D::pointer()) member_descriptor<D, M>::pointer;
template<class D, unsigned M> constexpr decltype(D::name()) member_descriptor<D, M>::name;
template<class D, unsigned M> constexpr unsigned member_descriptor<D, M>::modifiers;
#endif
template<unsigned M, class... T> auto member_descriptor_fn_impl( int, T... )
{
@@ -53,24 +55,24 @@ template<class C, class F> constexpr auto mfn( F * p ) { return p; }
#if defined(_MSC_VER) && !defined(__clang__)
#define BOOST_DESCRIBE_PUBLIC_MEMBERS(C, ...) inline auto boost_public_member_descriptor_fn( C * ) \
#define BOOST_DESCRIBE_PUBLIC_MEMBERS(C, ...) inline auto boost_public_member_descriptor_fn( C** ) \
{ return boost::describe::detail::member_descriptor_fn_impl<boost::describe::mod_public>( 0 BOOST_DESCRIBE_PP_FOR_EACH(BOOST_DESCRIBE_MEMBER_IMPL, C, __VA_ARGS__) ); }
#define BOOST_DESCRIBE_PROTECTED_MEMBERS(C, ...) inline auto boost_protected_member_descriptor_fn( C * ) \
#define BOOST_DESCRIBE_PROTECTED_MEMBERS(C, ...) inline auto boost_protected_member_descriptor_fn( C** ) \
{ return boost::describe::detail::member_descriptor_fn_impl<boost::describe::mod_protected>( 0 BOOST_DESCRIBE_PP_FOR_EACH(BOOST_DESCRIBE_MEMBER_IMPL, C, __VA_ARGS__) ); }
#define BOOST_DESCRIBE_PRIVATE_MEMBERS(C, ...) inline auto boost_private_member_descriptor_fn( C * ) \
#define BOOST_DESCRIBE_PRIVATE_MEMBERS(C, ...) inline auto boost_private_member_descriptor_fn( C** ) \
{ return boost::describe::detail::member_descriptor_fn_impl<boost::describe::mod_private>( 0 BOOST_DESCRIBE_PP_FOR_EACH(BOOST_DESCRIBE_MEMBER_IMPL, C, __VA_ARGS__) ); }
#else
#define BOOST_DESCRIBE_PUBLIC_MEMBERS(C, ...) inline auto boost_public_member_descriptor_fn( C * ) \
#define BOOST_DESCRIBE_PUBLIC_MEMBERS(C, ...) inline auto boost_public_member_descriptor_fn( C** ) \
{ return boost::describe::detail::member_descriptor_fn_impl<boost::describe::mod_public>( 0 BOOST_DESCRIBE_PP_FOR_EACH(BOOST_DESCRIBE_MEMBER_IMPL, C, ##__VA_ARGS__) ); }
#define BOOST_DESCRIBE_PROTECTED_MEMBERS(C, ...) inline auto boost_protected_member_descriptor_fn( C * ) \
#define BOOST_DESCRIBE_PROTECTED_MEMBERS(C, ...) inline auto boost_protected_member_descriptor_fn( C** ) \
{ return boost::describe::detail::member_descriptor_fn_impl<boost::describe::mod_protected>( 0 BOOST_DESCRIBE_PP_FOR_EACH(BOOST_DESCRIBE_MEMBER_IMPL, C, ##__VA_ARGS__) ); }
#define BOOST_DESCRIBE_PRIVATE_MEMBERS(C, ...) inline auto boost_private_member_descriptor_fn( C * ) \
#define BOOST_DESCRIBE_PRIVATE_MEMBERS(C, ...) inline auto boost_private_member_descriptor_fn( C** ) \
{ return boost::describe::detail::member_descriptor_fn_impl<boost::describe::mod_private>( 0 BOOST_DESCRIBE_PP_FOR_EACH(BOOST_DESCRIBE_MEMBER_IMPL, C, ##__VA_ARGS__) ); }
#endif

View File

@@ -60,11 +60,35 @@
#define BOOST_DESCRIBE_PP_FOR_EACH_50(F, a, x, ...) BOOST_DESCRIBE_PP_EXPAND(BOOST_DESCRIBE_PP_CALL(F, a, x) BOOST_DESCRIBE_PP_FOR_EACH_49(F, a, __VA_ARGS__))
#define BOOST_DESCRIBE_PP_FOR_EACH_51(F, a, x, ...) BOOST_DESCRIBE_PP_EXPAND(BOOST_DESCRIBE_PP_CALL(F, a, x) BOOST_DESCRIBE_PP_FOR_EACH_50(F, a, __VA_ARGS__))
#define BOOST_DESCRIBE_PP_FOR_EACH_52(F, a, x, ...) BOOST_DESCRIBE_PP_EXPAND(BOOST_DESCRIBE_PP_CALL(F, a, x) BOOST_DESCRIBE_PP_FOR_EACH_51(F, a, __VA_ARGS__))
#define BOOST_DESCRIBE_PP_FOR_EACH_53(F, a, x, ...) BOOST_DESCRIBE_PP_EXPAND(BOOST_DESCRIBE_PP_CALL(F, a, x) BOOST_DESCRIBE_PP_FOR_EACH_52(F, a, __VA_ARGS__))
#define BOOST_DESCRIBE_PP_FOR_EACH_54(F, a, x, ...) BOOST_DESCRIBE_PP_EXPAND(BOOST_DESCRIBE_PP_CALL(F, a, x) BOOST_DESCRIBE_PP_FOR_EACH_53(F, a, __VA_ARGS__))
#define BOOST_DESCRIBE_PP_FOR_EACH_55(F, a, x, ...) BOOST_DESCRIBE_PP_EXPAND(BOOST_DESCRIBE_PP_CALL(F, a, x) BOOST_DESCRIBE_PP_FOR_EACH_54(F, a, __VA_ARGS__))
#define BOOST_DESCRIBE_PP_FOR_EACH_56(F, a, x, ...) BOOST_DESCRIBE_PP_EXPAND(BOOST_DESCRIBE_PP_CALL(F, a, x) BOOST_DESCRIBE_PP_FOR_EACH_55(F, a, __VA_ARGS__))
#define BOOST_DESCRIBE_PP_FOR_EACH_57(F, a, x, ...) BOOST_DESCRIBE_PP_EXPAND(BOOST_DESCRIBE_PP_CALL(F, a, x) BOOST_DESCRIBE_PP_FOR_EACH_56(F, a, __VA_ARGS__))
#define BOOST_DESCRIBE_PP_FOR_EACH_58(F, a, x, ...) BOOST_DESCRIBE_PP_EXPAND(BOOST_DESCRIBE_PP_CALL(F, a, x) BOOST_DESCRIBE_PP_FOR_EACH_57(F, a, __VA_ARGS__))
#define BOOST_DESCRIBE_PP_FOR_EACH_59(F, a, x, ...) BOOST_DESCRIBE_PP_EXPAND(BOOST_DESCRIBE_PP_CALL(F, a, x) BOOST_DESCRIBE_PP_FOR_EACH_58(F, a, __VA_ARGS__))
#define BOOST_DESCRIBE_PP_FOR_EACH_60(F, a, x, ...) BOOST_DESCRIBE_PP_EXPAND(BOOST_DESCRIBE_PP_CALL(F, a, x) BOOST_DESCRIBE_PP_FOR_EACH_59(F, a, __VA_ARGS__))
#define BOOST_DESCRIBE_PP_FOR_EACH_61(F, a, x, ...) BOOST_DESCRIBE_PP_EXPAND(BOOST_DESCRIBE_PP_CALL(F, a, x) BOOST_DESCRIBE_PP_FOR_EACH_60(F, a, __VA_ARGS__))
#define BOOST_DESCRIBE_PP_FOR_EACH_62(F, a, x, ...) BOOST_DESCRIBE_PP_EXPAND(BOOST_DESCRIBE_PP_CALL(F, a, x) BOOST_DESCRIBE_PP_FOR_EACH_61(F, a, __VA_ARGS__))
#define BOOST_DESCRIBE_PP_FOR_EACH_63(F, a, x, ...) BOOST_DESCRIBE_PP_EXPAND(BOOST_DESCRIBE_PP_CALL(F, a, x) BOOST_DESCRIBE_PP_FOR_EACH_62(F, a, __VA_ARGS__))
#define BOOST_DESCRIBE_PP_FOR_EACH_64(F, a, x, ...) BOOST_DESCRIBE_PP_EXPAND(BOOST_DESCRIBE_PP_CALL(F, a, x) BOOST_DESCRIBE_PP_FOR_EACH_63(F, a, __VA_ARGS__))
#define BOOST_DESCRIBE_PP_FE_EXTRACT(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, V, ...) V
#define BOOST_DESCRIBE_PP_FE_EXTRACT(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, V, ...) V
#define BOOST_DESCRIBE_PP_FOR_EACH(F, ...) \
BOOST_DESCRIBE_PP_EXPAND(BOOST_DESCRIBE_PP_EXPAND(BOOST_DESCRIBE_PP_FE_EXTRACT(__VA_ARGS__, \
BOOST_DESCRIBE_PP_FOR_EACH_64, \
BOOST_DESCRIBE_PP_FOR_EACH_63, \
BOOST_DESCRIBE_PP_FOR_EACH_62, \
BOOST_DESCRIBE_PP_FOR_EACH_61, \
BOOST_DESCRIBE_PP_FOR_EACH_60, \
BOOST_DESCRIBE_PP_FOR_EACH_59, \
BOOST_DESCRIBE_PP_FOR_EACH_58, \
BOOST_DESCRIBE_PP_FOR_EACH_57, \
BOOST_DESCRIBE_PP_FOR_EACH_56, \
BOOST_DESCRIBE_PP_FOR_EACH_55, \
BOOST_DESCRIBE_PP_FOR_EACH_54, \
BOOST_DESCRIBE_PP_FOR_EACH_53, \
BOOST_DESCRIBE_PP_FOR_EACH_52, \
BOOST_DESCRIBE_PP_FOR_EACH_51, \
BOOST_DESCRIBE_PP_FOR_EACH_50, \

View File

@@ -0,0 +1,32 @@
#ifndef BOOST_DESCRIBE_DETAIL_VOID_T_HPP_INCLUDED
#define BOOST_DESCRIBE_DETAIL_VOID_T_HPP_INCLUDED
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/detail/config.hpp>
#if defined(BOOST_DESCRIBE_CXX11)
namespace boost
{
namespace describe
{
namespace detail
{
template<class...> struct make_void
{
using type = void;
};
template<class... T> using void_t = typename make_void<T...>::type;
} // namespace detail
} // namespace describe
} // namespace boost
#endif // defined(BOOST_DESCRIBE_CXX11)
#endif // #ifndef BOOST_DESCRIBE_DETAIL_VOID_T_HPP_INCLUDED

View File

@@ -32,17 +32,36 @@ template<class D> struct enum_descriptor
static constexpr decltype(D::name()) name = D::name();
};
#ifndef __cpp_inline_variables
// GCC requires these definitions
template<class D> constexpr decltype(D::value()) enum_descriptor<D>::value;
template<class D> constexpr decltype(D::name()) enum_descriptor<D>::name;
#endif
template<class... T> auto enum_descriptor_fn_impl( int, T... )
{
return list<enum_descriptor<T>...>();
}
#if defined(BOOST_DESCRIBE_CXX20)
template<auto V, auto N> struct enum_desc
{
static constexpr auto value() noexcept { return V; }
static constexpr auto name() noexcept { return N(); }
};
#define BOOST_DESCRIBE_ENUM_BEGIN(E) \
inline auto boost_enum_descriptor_fn( E* ) \
inline decltype( boost::describe::detail::enum_descriptor_fn_impl( 0
#define BOOST_DESCRIBE_ENUM_ENTRY(E, e) , boost::describe::detail::enum_desc<E::e, []{ return #e; }>{}
#define BOOST_DESCRIBE_ENUM_END(E) ) ) boost_enum_descriptor_fn( E** ) { return {}; }
#else
#define BOOST_DESCRIBE_ENUM_BEGIN(E) \
inline auto boost_enum_descriptor_fn( E** ) \
{ return boost::describe::detail::enum_descriptor_fn_impl( 0
#define BOOST_DESCRIBE_ENUM_ENTRY(E, e) , []{ struct _boost_desc { \
@@ -51,11 +70,14 @@ template<class... T> auto enum_descriptor_fn_impl( int, T... )
#define BOOST_DESCRIBE_ENUM_END(E) ); }
#endif
} // namespace detail
#if defined(_MSC_VER) && !defined(__clang__)
#define BOOST_DESCRIBE_ENUM(E, ...) \
namespace should_use_BOOST_DESCRIBE_NESTED_ENUM {} \
static_assert(std::is_enum<E>::value, "BOOST_DESCRIBE_ENUM should only be used with enums"); \
BOOST_DESCRIBE_ENUM_BEGIN(E) \
BOOST_DESCRIBE_PP_FOR_EACH(BOOST_DESCRIBE_ENUM_ENTRY, E, __VA_ARGS__) \
@@ -70,14 +92,15 @@ template<class... T> auto enum_descriptor_fn_impl( int, T... )
#else
#define BOOST_DESCRIBE_ENUM(E, ...) \
namespace should_use_BOOST_DESCRIBE_NESTED_ENUM {} \
static_assert(std::is_enum<E>::value, "BOOST_DESCRIBE_ENUM should only be used with enums"); \
BOOST_DESCRIBE_ENUM_BEGIN(E) \
BOOST_DESCRIBE_MAYBE_UNUSED BOOST_DESCRIBE_ENUM_BEGIN(E) \
BOOST_DESCRIBE_PP_FOR_EACH(BOOST_DESCRIBE_ENUM_ENTRY, E, ##__VA_ARGS__) \
BOOST_DESCRIBE_ENUM_END(E)
#define BOOST_DESCRIBE_NESTED_ENUM(E, ...) \
static_assert(std::is_enum<E>::value, "BOOST_DESCRIBE_NESTED_ENUM should only be used with enums"); \
friend BOOST_DESCRIBE_ENUM_BEGIN(E) \
BOOST_DESCRIBE_MAYBE_UNUSED friend BOOST_DESCRIBE_ENUM_BEGIN(E) \
BOOST_DESCRIBE_PP_FOR_EACH(BOOST_DESCRIBE_ENUM_ENTRY, E, ##__VA_ARGS__) \
BOOST_DESCRIBE_ENUM_END(E)

View File

@@ -0,0 +1,77 @@
#ifndef BOOST_DESCRIBE_ENUM_FROM_STRING_HPP_INCLUDED
#define BOOST_DESCRIBE_ENUM_FROM_STRING_HPP_INCLUDED
// Copyright 2020, 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/detail/config.hpp>
#if defined(BOOST_DESCRIBE_CXX14)
#include <boost/describe/enumerators.hpp>
#include <boost/mp11/algorithm.hpp>
#include <cstring>
#include <type_traits>
#if defined(_MSC_VER) && _MSC_VER == 1900
# pragma warning(push)
# pragma warning(disable: 4100) // unreferenced formal parameter
#endif
namespace boost
{
namespace describe
{
template<class E, class De = describe_enumerators<E>>
bool enum_from_string( char const* name, E& e ) noexcept
{
bool found = false;
mp11::mp_for_each<De>([&](auto D){
if( !found && std::strcmp( D.name, name ) == 0 )
{
found = true;
e = D.value;
}
});
return found;
}
template<class S, class E, class De = describe_enumerators<E>,
class En = std::enable_if_t<
std::is_same<typename S::value_type, char>::value &&
std::is_same<typename S::traits_type::char_type, char>::value
>
>
bool enum_from_string( S const& name, E& e ) noexcept
{
bool found = false;
mp11::mp_for_each<De>([&](auto D){
if( !found && name == D.name )
{
found = true;
e = D.value;
}
});
return found;
}
} // namespace describe
} // namespace boost
#if defined(_MSC_VER) && _MSC_VER == 1900
# pragma warning(pop)
#endif
#endif // defined(BOOST_DESCRIBE_CXX14)
#endif // #ifndef BOOST_DESCRIBE_ENUM_FROM_STRING_HPP_INCLUDED

View File

@@ -0,0 +1,66 @@
#ifndef BOOST_DESCRIBE_ENUM_TO_STRING_HPP_INCLUDED
#define BOOST_DESCRIBE_ENUM_TO_STRING_HPP_INCLUDED
// Copyright 2020, 2021, 2025 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/detail/config.hpp>
#if defined(BOOST_DESCRIBE_CXX14)
#include <boost/describe/enumerators.hpp>
#include <boost/mp11/algorithm.hpp>
#if defined(_MSC_VER) && _MSC_VER == 1900
# pragma warning(push)
# pragma warning(disable: 4100) // unreferenced formal parameter
#endif
namespace boost
{
namespace describe
{
namespace detail
{
// [&](auto D){ if( e == D.value ) r = D.name; }
// except constexpr under C++14
template<class E> struct ets_lambda
{
E e;
char const** pr;
template<class D> constexpr void operator()( D d ) const noexcept
{
if( e == d.value ) *pr = d.name;
}
};
} // namespace detail
template<class E, class De = describe_enumerators<E>>
#if !( defined(_MSC_VER) && _MSC_VER == 1900 )
constexpr
#endif
char const* enum_to_string( E e, char const* def ) noexcept
{
char const* r = def;
mp11::mp_for_each<De>( detail::ets_lambda<E>{ e, &r } );
return r;
}
} // namespace describe
} // namespace boost
#if defined(_MSC_VER) && _MSC_VER == 1900
# pragma warning(pop)
#endif
#endif // defined(BOOST_DESCRIBE_CXX14)
#endif // #ifndef BOOST_DESCRIBE_ENUM_TO_STRING_HPP_INCLUDED

View File

@@ -1,20 +1,42 @@
#ifndef BOOST_DESCRIBE_ENUMERATORS_HPP_INCLUDED
#define BOOST_DESCRIBE_ENUMERATORS_HPP_INCLUDED
// Copyright 2020 Peter Dimov
// Copyright 2020, 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/detail/void_t.hpp>
#include <boost/describe/detail/config.hpp>
#if defined(BOOST_DESCRIBE_CXX11)
#include <type_traits>
namespace boost
{
namespace describe
{
template<class E> using describe_enumerators = decltype( boost_enum_descriptor_fn( static_cast<E*>(0) ) );
// describe_enumerators<E>
template<class E> using describe_enumerators = decltype( boost_enum_descriptor_fn( static_cast<E**>(0) ) );
// has_describe_enumerators<E>
namespace detail
{
template<class E, class En = void> struct has_describe_enumerators: std::false_type
{
};
template<class E> struct has_describe_enumerators<E, void_t<describe_enumerators<E>>>: std::true_type
{
};
} // namespace detail
template<class E> using has_describe_enumerators = detail::has_describe_enumerators<E>;
} // namespace describe
} // namespace boost

View File

@@ -7,6 +7,9 @@
#include <boost/describe/modifiers.hpp>
#include <boost/describe/bases.hpp>
#include <boost/describe/detail/void_t.hpp>
#include <boost/describe/detail/cx_streq.hpp>
#include <boost/describe/detail/config.hpp>
#if defined(BOOST_DESCRIBE_CXX11)
@@ -15,6 +18,7 @@
#include <boost/mp11/integral.hpp>
#include <boost/mp11/list.hpp>
#include <boost/mp11/bind.hpp>
#include <type_traits>
namespace boost
{
@@ -25,9 +29,9 @@ namespace detail
// _describe_members<T>
template<class T> using _describe_public_members = decltype( boost_public_member_descriptor_fn( static_cast<T*>(0) ) );
template<class T> using _describe_protected_members = decltype( boost_protected_member_descriptor_fn( static_cast<T*>(0) ) );
template<class T> using _describe_private_members = decltype( boost_private_member_descriptor_fn( static_cast<T*>(0) ) );
template<class T> using _describe_public_members = decltype( boost_public_member_descriptor_fn( static_cast<T**>(0) ) );
template<class T> using _describe_protected_members = decltype( boost_protected_member_descriptor_fn( static_cast<T**>(0) ) );
template<class T> using _describe_private_members = decltype( boost_private_member_descriptor_fn( static_cast<T**>(0) ) );
template<class T> using _describe_members = mp11::mp_append<_describe_public_members<T>, _describe_protected_members<T>, _describe_private_members<T>>;
@@ -57,11 +61,6 @@ template<template<class...> class L, class T, class V> struct describe_inherited
using type = L<>;
};
constexpr bool cx_streq( char const * s1, char const * s2 )
{
return s1[0] == s2[0] && ( s1[0] == 0 || cx_streq( s1 + 1, s2 + 1 ) );
}
template<class D1, class D2> using name_matches = mp11::mp_bool< cx_streq( D1::name, D2::name ) >;
template<class D, class L> using name_is_hidden = mp11::mp_any_of_q<L, mp11::mp_bind_front<name_matches, D>>;
@@ -87,9 +86,11 @@ template<class T, unsigned Bm> struct update_modifiers
};
};
#ifndef __cpp_inline_variables
template<class T, unsigned Bm> template<class D> constexpr decltype(D::pointer) update_modifiers<T, Bm>::fn<D>::pointer;
template<class T, unsigned Bm> template<class D> constexpr decltype(D::name) update_modifiers<T, Bm>::fn<D>::name;
template<class T, unsigned Bm> template<class D> constexpr unsigned update_modifiers<T, Bm>::fn<D>::modifiers;
#endif
template<class D> struct gather_virtual_bases_impl;
template<class D> using gather_virtual_bases = typename gather_virtual_bases_impl<D>::type;
@@ -136,10 +137,22 @@ template<unsigned M> struct member_filter
>;
};
// has_describe_members
template<class T, class En = void> struct has_describe_members: std::false_type
{
};
template<class T> struct has_describe_members<T, void_t<_describe_members<T>>>: std::true_type
{
};
} // namespace detail
template<class T, unsigned M> using describe_members = mp11::mp_copy_if_q<detail::describe_members<T, M>, detail::member_filter<M>>;
template<class T> using has_describe_members = detail::has_describe_members<T>;
} // namespace describe
} // namespace boost

View File

@@ -0,0 +1,30 @@
#ifndef BOOST_DESCRIBE_MODIFIER_DESCRIPTION_HPP_INCLUDED
#define BOOST_DESCRIBE_MODIFIER_DESCRIPTION_HPP_INCLUDED
// Copyright 2020, 2022 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/modifiers.hpp>
#include <boost/describe/enum.hpp>
namespace boost
{
namespace describe
{
BOOST_DESCRIBE_ENUM(modifiers,
mod_public,
mod_protected,
mod_private,
mod_virtual,
mod_static,
mod_function,
mod_any_member,
mod_inherited,
mod_hidden)
} // namespace describe
} // namespace boost
#endif // #ifndef BOOST_DESCRIBE_MODIFIER_DESCRIPTION_HPP_INCLUDED

View File

@@ -5,7 +5,7 @@
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/enum.hpp>
#include <boost/describe/detail/config.hpp>
namespace boost
{
@@ -22,21 +22,10 @@ enum modifiers
mod_function = 32,
mod_any_member = 64,
mod_inherited = 128,
mod_hidden = 256,
mod_hidden = 256
};
BOOST_DESCRIBE_ENUM(modifiers,
mod_public,
mod_protected,
mod_private,
mod_virtual,
mod_static,
mod_function,
mod_any_member,
mod_inherited,
mod_hidden);
BOOST_DESCRIBE_CONSTEXPR_OR_CONST modifiers mod_any_access = static_cast<modifiers>( mod_public | mod_protected | mod_private );
BOOST_DESCRIBE_INLINE_CONSTEXPR modifiers mod_any_access = static_cast<modifiers>( mod_public | mod_protected | mod_private );
} // namespace describe
} // namespace boost

View File

@@ -0,0 +1,179 @@
#ifndef BOOST_DESCRIBE_OPERATORS_HPP_INCLUDED
#define BOOST_DESCRIBE_OPERATORS_HPP_INCLUDED
// Copyright 2020, 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/detail/config.hpp>
#if defined(BOOST_DESCRIBE_CXX14)
#include <boost/describe/bases.hpp>
#include <boost/describe/members.hpp>
#include <boost/describe/modifiers.hpp>
#include <boost/mp11/algorithm.hpp>
#include <type_traits>
#include <iosfwd>
#if defined(_MSC_VER) && _MSC_VER == 1900
# pragma warning(push)
# pragma warning(disable: 4100) // unreferenced formal parameter
#endif
namespace boost
{
namespace describe
{
namespace detail
{
template<class T,
class Bd = describe::describe_bases<T, mod_any_access>,
class Md = describe::describe_members<T, mod_any_access>>
bool eq( T const& t1, T const& t2 )
{
bool r = true;
mp11::mp_for_each<Bd>([&](auto D){
using B = typename decltype(D)::type;
r = r && (B const&)t1 == (B const&)t2;
});
mp11::mp_for_each<Md>([&](auto D){
r = r && t1.*D.pointer == t2.*D.pointer;
});
return r;
}
template<class T,
class Bd = describe::describe_bases<T, mod_any_access>,
class Md = describe::describe_members<T, mod_any_access>>
bool lt( T const& t1, T const& t2 )
{
int r = 0;
mp11::mp_for_each<Bd>([&](auto D){
using B = typename decltype(D)::type;
if( r == 0 && (B const&)t1 < (B const&)t2 ) r = -1;
if( r == 0 && (B const&)t2 < (B const&)t1 ) r = +1;
});
mp11::mp_for_each<Md>([&](auto D){
if( r == 0 && t1.*D.pointer < t2.*D.pointer ) r = -1;
if( r == 0 && t2.*D.pointer < t1.*D.pointer ) r = +1;
});
return r < 0;
}
template<class Os, class T,
class Bd = describe::describe_bases<T, mod_any_access>,
class Md = describe::describe_members<T, mod_any_access>>
void print( Os& os, T const& t )
{
os << "{";
bool first = true;
mp11::mp_for_each<Bd>([&](auto D){
if( !first ) { os << ", "; }
first = false;
using B = typename decltype(D)::type;
os << (B const&)t;
});
mp11::mp_for_each<Md>([&](auto D){
if( !first ) { os << ", "; }
first = false;
os << "." << D.name << " = " << t.*D.pointer;
});
os << "}";
}
} // namespace detail
namespace operators
{
template<class T> std::enable_if_t<
has_describe_bases<T>::value && has_describe_members<T>::value && !std::is_union<T>::value, bool>
operator==( T const& t1, T const& t2 )
{
return detail::eq( t1, t2 );
}
template<class T> std::enable_if_t<
has_describe_bases<T>::value && has_describe_members<T>::value && !std::is_union<T>::value, bool>
operator!=( T const& t1, T const& t2 )
{
return !detail::eq( t1, t2 );
}
template<class T> std::enable_if_t<
has_describe_bases<T>::value && has_describe_members<T>::value && !std::is_union<T>::value, bool>
operator<( T const& t1, T const& t2 )
{
return detail::lt( t1, t2 );
}
template<class T> std::enable_if_t<
has_describe_bases<T>::value && has_describe_members<T>::value && !std::is_union<T>::value, bool>
operator>=( T const& t1, T const& t2 )
{
return !detail::lt( t1, t2 );
}
template<class T> std::enable_if_t<
has_describe_bases<T>::value && has_describe_members<T>::value && !std::is_union<T>::value, bool>
operator>( T const& t1, T const& t2 )
{
return detail::lt( t2, t1 );
}
template<class T> std::enable_if_t<
has_describe_bases<T>::value && has_describe_members<T>::value && !std::is_union<T>::value, bool>
operator<=( T const& t1, T const& t2 )
{
return !detail::lt( t2, t1 );
}
template<class T, class Ch, class Tr> std::enable_if_t<
has_describe_bases<T>::value && has_describe_members<T>::value && !std::is_union<T>::value,
std::basic_ostream<Ch, Tr>&>
operator<<( std::basic_ostream<Ch, Tr>& os, T const& t )
{
os.width( 0 );
detail::print( os, t );
return os;
}
} // namespace operators
} // namespace describe
} // namespace boost
#if defined(_MSC_VER) && _MSC_VER == 1900
# pragma warning(pop)
#endif
#endif // defined(BOOST_DESCRIBE_CXX14)
#endif // #ifndef BOOST_DESCRIBE_OPERATORS_HPP_INCLUDED

View File

@@ -9,6 +9,7 @@
],
"description": "A C++14 reflection library.",
"category": [
"Emulation",
"Metaprogramming"
]
}

View File

@@ -4,12 +4,16 @@
import testing ;
local WERROR = <toolset>msvc:<warnings-as-errors>on <toolset>clang:<warnings-as-errors>on <toolset>gcc:<warnings-as-errors>on ;
project : requirements
<library>/boost/describe//boost_describe
<library>/boost/container_hash//boost_container_hash
<library>/boost/core//boost_core
<library>/boost/variant2//boost_variant2
<warnings>extra
<toolset>msvc:<warnings-as-errors>on
<toolset>clang:<warnings-as-errors>on
<toolset>gcc:<warnings-as-errors>on
<toolset>msvc-14.0:<cxxflags>"-wd4100"
$(WERROR)
<toolset>clang:<cxxflags>"-Wno-unused-private-field" ;
run quick.cpp ;
@@ -48,15 +52,52 @@ compile test_d_type.cpp ;
compile-fail enum_struct_fail.cpp ;
compile-fail struct_enum_fail.cpp ;
compile-fail enum_nested_fail.cpp ;
compile-fail nested_enum_fail.cpp ;
run class_template_test.cpp ;
run has_enumerators_test.cpp ;
run has_bases_test.cpp ;
run has_members_test.cpp ;
run enum_to_string_test.cpp ;
run enum_from_string_test.cpp ;
run operator_eq_test.cpp ;
run operator_lt_test.cpp ;
run descriptor_by_name_test.cpp ;
run descriptor_by_pointer_test.cpp ;
compile unnamed_namespace_test.cpp ;
compile unnamed_namespace_test2.cpp ;
run union_test.cpp ;
run union_test2.cpp ;
run pedantic_enumerators_test.cpp
: : : <warnings>pedantic ;
run pedantic_bases_test.cpp
: : : <warnings>pedantic ;
run pedantic_members_test.cpp
: : : <warnings>pedantic ;
run enum_from_string_test2.cpp ;
compile nested_enum_test2.cpp ;
compile enum_to_string_test_cx.cpp ;
# examples
obj describe_cxx14 : describe_cxx14.cpp ;
explicit describe_cxx14 ;
local CXX14 = [ check-target-builds describe_cxx14 describe_cxx14 : : <build>no ] ;
local CXX14 = [ check-target-builds describe_cxx14 describe_cxx14 : : <build>no ] "<toolset>msvc-14.0:<cxxflags>-wd4100" ;
local JSON = <library>/boost//json/<warnings>off "<toolset>msvc-14.0:<build>no" "<toolset>msvc-14.2:<cxxflags>-wd5104" ;
local SERIALIZATION = <library>/boost//serialization/<warnings>off "-<toolset>clang:<warnings-as-errors>on" ;
local JSON = <library>/boost/json//boost_json/<warnings>off "<toolset>msvc-14.2:<cxxflags>-wd5104" "<toolset>msvc-14.0:<cxxflags>-wd4996" <undefined-sanitizer>norecover:<link>static ;
local SERIALIZATION = <library>/boost/serialization//boost_serialization/<warnings>off -$(WERROR) <undefined-sanitizer>norecover:<link>static ;
run ../example/printing_enums_ct.cpp : : : $(CXX14) ;
run ../example/printing_enums_rt.cpp : : : $(CXX14) ;
@@ -66,7 +107,10 @@ run ../example/print_function.cpp : : : $(CXX14) ;
run ../example/to_json.cpp : : : $(CXX14) $(JSON) ;
run ../example/from_json.cpp : : : $(CXX14) $(JSON) ;
run ../example/serialization.cpp : : : $(CXX14) $(SERIALIZATION) ;
run ../example/json_rpc.cpp : : : $(CXX14) $(JSON) ;
run ../example/json_rpc.cpp : : : $(CXX14) $(JSON) <library>/boost/utility//boost_utility
"<toolset>gcc-14,<cxxstd>14:<build>no" ; # mysterious segmentation fault
run ../example/hash_value.cpp : : : $(CXX14) ;
run ../example/equality.cpp : : : $(CXX14) ;
link ../example/console.cpp : $(CXX14) $(JSON) ;
link ../example/console.cpp : $(CXX14) $(JSON) <library>/boost/utility//boost_utility ;
run ../example/struct_to_tuple.cpp : : : $(CXX14) ;
run ../example/pm_to_string.cpp : : : $(CXX14) ;

View File

@@ -7,6 +7,11 @@
#include <boost/core/lightweight_test.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#if defined(_MSC_VER) && _MSC_VER < 1900
# pragma warning(disable: 4510) // default constructor could not be generated
# pragma warning(disable: 4610) // struct can never be instantiated
#endif
struct X
{
};
@@ -57,6 +62,14 @@ int main() {}
#include <boost/mp11.hpp>
template<typename ...Bases>
struct ZT: Bases...
{
BOOST_DESCRIBE_CLASS(ZT, (Bases...), (), (), ());
};
using Z = ZT<X1, X2, X3>;
int main()
{
using namespace boost::describe;
@@ -146,6 +159,21 @@ int main()
BOOST_TEST_EQ( (mp_at_c<L, 1>::modifiers), mod_private | mod_virtual );
}
{
using L = describe_bases<Z, mod_any_access>;
BOOST_TEST_EQ( mp_size<L>::value, 3 );
BOOST_TEST_TRAIT_SAME( typename mp_at_c<L, 0>::type, X1 );
BOOST_TEST_EQ( (mp_at_c<L, 0>::modifiers), mod_public );
BOOST_TEST_TRAIT_SAME( typename mp_at_c<L, 1>::type, X2 );
BOOST_TEST_EQ( (mp_at_c<L, 1>::modifiers), mod_public );
BOOST_TEST_TRAIT_SAME( typename mp_at_c<L, 2>::type, X3 );
BOOST_TEST_EQ( (mp_at_c<L, 2>::modifiers), mod_public );
}
return boost::report_errors();
}

View File

@@ -54,9 +54,9 @@ int main() {}
BOOST_PRAGMA_MESSAGE("Skipping test because BOOST_MSVC is below 1920")
int main() {}
#elif defined(BOOST_MSVC) && BOOST_MSVC >= 1920 && BOOST_MSVC < 1930 && _MSVC_LANG <= 201703L
#elif defined(BOOST_MSVC) && BOOST_MSVC >= 1920 && BOOST_MSVC < 1940 && _MSVC_LANG <= 201703L
BOOST_PRAGMA_MESSAGE("Skipping test because BOOST_MSVC is 192x and _MSVC_LANG is 201703L or below")
BOOST_PRAGMA_MESSAGE("Skipping test because BOOST_MSVC is 192x or 193x and _MSVC_LANG is 201703L or below")
int main() {}
#else

View File

@@ -0,0 +1,17 @@
# Copyright 2018, 2019, 2022 Peter Dimov
# 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...3.20)
project(cmake_install_test LANGUAGES CXX)
find_package(boost_describe REQUIRED)
add_executable(main main.cpp)
target_link_libraries(main Boost::describe)
enable_testing()
add_test(main main)
add_custom_target(check VERBATIM COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $<CONFIG>)

View File

@@ -0,0 +1,49 @@
// Copyright 2017, 2020, 2021, 2022 Peter Dimov.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe.hpp>
#include <cassert>
#define BOOST_TEST(expr) assert(expr)
#define BOOST_TEST_EQ(x1, x2) assert((x1)==(x2))
struct X
{
int m;
};
BOOST_DESCRIBE_STRUCT(X, (), (m))
struct Y: public X
{
void m() {}
};
BOOST_DESCRIBE_STRUCT(Y, (X), (m))
#if !defined(BOOST_DESCRIBE_CXX14)
#pragma message "Skipping test because C++14 is not available"
int main()
{
}
#else
BOOST_DEFINE_ENUM(E, v1, v2, v3)
#include <boost/mp11.hpp>
int main()
{
using namespace boost::describe;
using namespace boost::mp11;
BOOST_TEST_EQ( (mp_size< describe_enumerators<E> >::value), 3 );
BOOST_TEST_EQ( (mp_size< describe_bases<Y, mod_any_access> >::value), 1 );
BOOST_TEST_EQ( (mp_size< describe_members<Y, mod_any_access | mod_inherited | mod_hidden> >::value), 1 );
}
#endif // !defined(BOOST_DESCRIBE_CXX14)

View File

@@ -0,0 +1,22 @@
# Copyright 2018-2022 Peter Dimov
# 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...3.20)
project(cmake_subdir_test LANGUAGES CXX)
add_subdirectory(../.. boostorg/describe)
add_subdirectory(../../../assert boostorg/assert)
add_subdirectory(../../../config boostorg/config)
add_subdirectory(../../../core boostorg/core)
add_subdirectory(../../../mp11 boostorg/mp11)
add_subdirectory(../../../throw_exception boostorg/throw_exception)
add_executable(quick ../quick.cpp)
target_link_libraries(quick Boost::describe Boost::core)
enable_testing()
add_test(quick quick)
add_custom_target(check VERBATIM COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure --no-tests=error -C $<CONFIG>)

View File

@@ -0,0 +1,64 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/descriptor_by_name.hpp>
#include <boost/describe/class.hpp>
#include <boost/describe/members.hpp>
#include <boost/core/lightweight_test.hpp>
#if !defined(BOOST_DESCRIBE_CXX14)
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("Skipping test because C++14 is not available")
int main() {}
#else
struct X
{
int a = 1;
int b = 2;
};
BOOST_DESCRIBE_STRUCT(X, (), (a, b))
struct Y
{
int a = 1;
int c = 3;
};
BOOST_DESCRIBE_STRUCT(Y, (), (a, c))
int main()
{
{
using L = boost::describe::describe_members<X, boost::describe::mod_any_access>;
using Na = BOOST_DESCRIBE_MAKE_NAME( a );
using Da = boost::describe::descriptor_by_name<L, Na>;
BOOST_TEST_CSTR_EQ( Da::name, "a" );
using Nb = BOOST_DESCRIBE_MAKE_NAME( b );
using Db = boost::describe::descriptor_by_name<L, Nb>;
BOOST_TEST_CSTR_EQ( Db::name, "b" );
}
{
using L = boost::describe::describe_members<Y, boost::describe::mod_any_access>;
using Na = BOOST_DESCRIBE_MAKE_NAME( a );
using Da = boost::describe::descriptor_by_name<L, Na>;
BOOST_TEST_CSTR_EQ( Da::name, "a" );
using Nc = BOOST_DESCRIBE_MAKE_NAME( c );
using Dc = boost::describe::descriptor_by_name<L, Nc>;
BOOST_TEST_CSTR_EQ( Dc::name, "c" );
}
return boost::report_errors();
}
#endif // !defined(BOOST_DESCRIBE_CXX14)

View File

@@ -0,0 +1,65 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/descriptor_by_pointer.hpp>
#include <boost/describe/class.hpp>
#include <boost/describe/members.hpp>
#include <boost/core/lightweight_test.hpp>
#if !defined(__cpp_nontype_template_parameter_auto) || __cpp_nontype_template_parameter_auto < 201606L
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("Skipping test because __cpp_nontype_template_parameter_auto is not defined")
int main() {}
#else
struct X
{
int a = 1;
float b = 3.14f;
};
BOOST_DESCRIBE_STRUCT(X, (), (a, b))
struct Y: public X
{
long a = 2;
double c = 3.14;
};
BOOST_DESCRIBE_STRUCT(Y, (X), (a, c))
int main()
{
using namespace boost::describe;
{
using L = describe_members<X, mod_any_access>;
using Da = descriptor_by_pointer<L, &X::a>;
BOOST_TEST_CSTR_EQ( Da::name, "a" );
using Db = descriptor_by_pointer<L, &X::b>;
BOOST_TEST_CSTR_EQ( Db::name, "b" );
}
{
using L = describe_members<Y, mod_any_access | mod_inherited>;
using Da = descriptor_by_pointer<L, &Y::a>;
BOOST_TEST_CSTR_EQ( Da::name, "a" );
using Db = descriptor_by_pointer<L, &Y::b>;
BOOST_TEST_CSTR_EQ( Db::name, "b" );
using Dc = descriptor_by_pointer<L, &Y::c>;
BOOST_TEST_CSTR_EQ( Dc::name, "c" );
}
return boost::report_errors();
}
#endif // __cpp_nontype_template_parameter_auto

View File

@@ -0,0 +1,62 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/enum_from_string.hpp>
#include <boost/describe/enum.hpp>
#include <boost/core/lightweight_test.hpp>
#if !defined(BOOST_DESCRIBE_CXX14)
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("Skipping test because C++14 is not available")
int main() {}
#else
enum E1 { v101 = 101, v102 = 102 };
BOOST_DESCRIBE_ENUM(E1, v101, v102)
enum class E2 { v201 = 201, v202 = 202 };
BOOST_DESCRIBE_ENUM(E2, v201, v202)
BOOST_DEFINE_ENUM(E3, v301, v302)
BOOST_DEFINE_ENUM_CLASS(E4, v401, v402)
int main()
{
using boost::describe::enum_from_string;
{
E1 w{};
BOOST_TEST( enum_from_string( "v101", w ) ) && BOOST_TEST_EQ( w, v101 );
BOOST_TEST( enum_from_string( "v102", w ) ) && BOOST_TEST_EQ( w, v102 );
BOOST_TEST_NOT( enum_from_string( "v103", w ) );
}
{
E2 w{};
BOOST_TEST( enum_from_string( "v201", w ) ) && BOOST_TEST_EQ( (int)w, (int)E2::v201 );
BOOST_TEST( enum_from_string( "v202", w ) ) && BOOST_TEST_EQ( (int)w, (int)E2::v202 );
BOOST_TEST_NOT( enum_from_string( "v203", w ) );
}
{
E3 w{};
BOOST_TEST( enum_from_string( "v301", w ) ) && BOOST_TEST_EQ( w, v301 );
BOOST_TEST( enum_from_string( "v302", w ) ) && BOOST_TEST_EQ( w, v302 );
BOOST_TEST_NOT( enum_from_string( "v303", w ) );
}
{
E4 w{};
BOOST_TEST( enum_from_string( "v401", w ) ) && BOOST_TEST_EQ( (int)w, (int)E4::v401 );
BOOST_TEST( enum_from_string( "v402", w ) ) && BOOST_TEST_EQ( (int)w, (int)E4::v402 );
BOOST_TEST_NOT( enum_from_string( "v403", w ) );
}
return boost::report_errors();
}
#endif // !defined(BOOST_DESCRIBE_CXX14)

View File

@@ -0,0 +1,78 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/enum_from_string.hpp>
#include <boost/describe/enum.hpp>
#include <boost/core/detail/string_view.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/config.hpp>
#if !defined(BOOST_DESCRIBE_CXX14)
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("Skipping test because C++14 is not available")
int main() {}
#else
enum E1 { v101 = 101, v102 = 102 };
BOOST_DESCRIBE_ENUM(E1, v101, v102)
enum class E2 { v201 = 201, v202 = 202 };
BOOST_DESCRIBE_ENUM(E2, v201, v202)
BOOST_DEFINE_ENUM(E3, v301, v302)
BOOST_DEFINE_ENUM_CLASS(E4, v401, v402)
template<class St> void test()
{
using boost::describe::enum_from_string;
{
E1 w{};
BOOST_TEST( enum_from_string( St( "v101" ), w ) ) && BOOST_TEST_EQ( w, v101 );
BOOST_TEST( enum_from_string( St( "v102" ), w ) ) && BOOST_TEST_EQ( w, v102 );
BOOST_TEST_NOT( enum_from_string( St( "v103" ), w ) );
}
{
E2 w{};
BOOST_TEST( enum_from_string( St( "v201" ), w ) ) && BOOST_TEST_EQ( (int)w, (int)E2::v201 );
BOOST_TEST( enum_from_string( St( "v202" ), w ) ) && BOOST_TEST_EQ( (int)w, (int)E2::v202 );
BOOST_TEST_NOT( enum_from_string( St( "v203" ), w ) );
}
{
E3 w{};
BOOST_TEST( enum_from_string( St( "v301" ), w ) ) && BOOST_TEST_EQ( w, v301 );
BOOST_TEST( enum_from_string( St( "v302" ), w ) ) && BOOST_TEST_EQ( w, v302 );
BOOST_TEST_NOT( enum_from_string( St( "v303" ), w ) );
}
{
E4 w{};
BOOST_TEST( enum_from_string( St( "v401" ), w ) ) && BOOST_TEST_EQ( (int)w, (int)E4::v401 );
BOOST_TEST( enum_from_string( St( "v402" ), w ) ) && BOOST_TEST_EQ( (int)w, (int)E4::v402 );
BOOST_TEST_NOT( enum_from_string( St( "v403" ), w ) );
}
}
#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
# include <string_view>
#endif
int main()
{
test<std::string>();
test<boost::core::string_view>();
#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW)
test<std::string_view>();
#endif
return boost::report_errors();
}
#endif // !defined(BOOST_DESCRIBE_CXX14)

18
test/enum_nested_fail.cpp Normal file
View File

@@ -0,0 +1,18 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/enum.hpp>
#if !defined(BOOST_DESCRIBE_CXX14)
#error "Skipping test because C++14 is not available"
#else
struct S1 {
enum E1 {};
BOOST_DESCRIBE_ENUM(E1)
};
#endif // !defined(BOOST_DESCRIBE_CXX14)

View File

@@ -0,0 +1,41 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/enum_to_string.hpp>
#include <boost/describe/enum.hpp>
#include <boost/core/lightweight_test.hpp>
#if !defined(BOOST_DESCRIBE_CXX14)
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("Skipping test because C++14 is not available")
int main() {}
#else
enum E1 { v1 };
BOOST_DESCRIBE_ENUM(E1, v1)
enum class E2 { v2 };
BOOST_DESCRIBE_ENUM(E2, v2)
BOOST_DEFINE_ENUM(E3, v3)
BOOST_DEFINE_ENUM_CLASS(E4, v4)
int main()
{
using boost::describe::enum_to_string;
BOOST_TEST_CSTR_EQ( enum_to_string( v1, "" ), "v1" );
BOOST_TEST_CSTR_EQ( enum_to_string( E2::v2, "" ), "v2" );
BOOST_TEST_CSTR_EQ( enum_to_string( static_cast<E2>( 14 ), "__def__" ), "__def__" );
BOOST_TEST_CSTR_EQ( enum_to_string( v3, "" ), "v3" );
BOOST_TEST_CSTR_EQ( enum_to_string( E4::v4, "" ), "v4" );
BOOST_TEST_EQ( enum_to_string( static_cast<E4>( 14 ), 0 ), static_cast<char const*>( 0 ) );
return boost::report_errors();
}
#endif // !defined(BOOST_DESCRIBE_CXX14)

View File

@@ -0,0 +1,32 @@
// Copyright 2021, 2025 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/enum_to_string.hpp>
#include <boost/describe/enum.hpp>
#include <boost/describe/detail/cx_streq.hpp>
#include <boost/config/pragma_message.hpp>
#if !defined(BOOST_DESCRIBE_CXX14)
BOOST_PRAGMA_MESSAGE("Skipping test because C++14 is not available")
#elif defined(_MSC_VER) && _MSC_VER == 1900
BOOST_PRAGMA_MESSAGE("Skipping test because _MSC_VER == 1900")
#else
#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)
BOOST_DEFINE_ENUM_CLASS(E, v1, v2, v3)
using boost::describe::enum_to_string;
using boost::describe::detail::cx_streq;
STATIC_ASSERT( cx_streq( enum_to_string( E::v1, "" ), "v1" ) );
STATIC_ASSERT( cx_streq( enum_to_string( E::v2, "" ), "v2" ) );
STATIC_ASSERT( cx_streq( enum_to_string( E::v3, "" ), "v3" ) );
STATIC_ASSERT( cx_streq( enum_to_string( (E)17, "def" ), "def" ) );
#endif // !defined(BOOST_DESCRIBE_CXX14)

View File

@@ -11,9 +11,9 @@ enum E1
v1_1 = 5
};
BOOST_DESCRIBE_ENUM(E1, v1_1);
BOOST_DESCRIBE_ENUM(E1, v1_1)
BOOST_DEFINE_ENUM(E3, v3_1, v3_2, v3_3);
BOOST_DEFINE_ENUM(E3, v3_1, v3_2, v3_3)
#if !defined(BOOST_DESCRIBE_CXX11)
@@ -30,12 +30,12 @@ enum class E2
v2_2 = 7
};
BOOST_DESCRIBE_ENUM(E2, v2_1, v2_2);
BOOST_DESCRIBE_ENUM(E2, v2_1, v2_2)
BOOST_DEFINE_FIXED_ENUM(E4, int, v4_1, v4_2, v4_3, v4_4);
BOOST_DEFINE_FIXED_ENUM(E4, int, v4_1, v4_2, v4_3, v4_4)
BOOST_DEFINE_ENUM_CLASS(E5, v5_1, v5_2, v5_3, v5_4, v5_5);
BOOST_DEFINE_FIXED_ENUM_CLASS(E6, int, v6_1, v6_2, v6_3, v6_4, v6_5, v6_6);
BOOST_DEFINE_ENUM_CLASS(E5, v5_1, v5_2, v5_3, v5_4, v5_5)
BOOST_DEFINE_FIXED_ENUM_CLASS(E6, int, v6_1, v6_2, v6_3, v6_4, v6_5, v6_6)
#if !defined(BOOST_DESCRIBE_CXX14)

60
test/has_bases_test.cpp Normal file
View File

@@ -0,0 +1,60 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/bases.hpp>
#include <boost/describe/class.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#if !defined(BOOST_DESCRIBE_CXX11)
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("Skipping test because C++11 is not available")
int main() {}
#else
struct X1 {};
BOOST_DESCRIBE_STRUCT(X1, (), ())
class X2
{
BOOST_DESCRIBE_CLASS(X2, (), (), (), ())
};
struct X3 {};
class X4 {};
union X5 {};
struct X6: X1 {};
struct X7: X2 {};
int main()
{
using boost::describe::has_describe_bases;
#if defined(BOOST_DESCRIBE_CXX14)
BOOST_TEST_TRAIT_TRUE((has_describe_bases<X1>));
BOOST_TEST_TRAIT_TRUE((has_describe_bases<X2>));
#else
BOOST_TEST_TRAIT_FALSE((has_describe_bases<X1>));
BOOST_TEST_TRAIT_FALSE((has_describe_bases<X2>));
#endif
BOOST_TEST_TRAIT_FALSE((has_describe_bases<X3>));
BOOST_TEST_TRAIT_FALSE((has_describe_bases<X4>));
BOOST_TEST_TRAIT_FALSE((has_describe_bases<X5>));
BOOST_TEST_TRAIT_FALSE((has_describe_bases<X6>));
BOOST_TEST_TRAIT_FALSE((has_describe_bases<X7>));
BOOST_TEST_TRAIT_FALSE((has_describe_bases<int>));
BOOST_TEST_TRAIT_FALSE((has_describe_bases<void>));
return boost::report_errors();
}
#endif // !defined(BOOST_DESCRIBE_CXX11)

View File

@@ -0,0 +1,58 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/enumerators.hpp>
#include <boost/describe/enum.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#if !defined(BOOST_DESCRIBE_CXX11)
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("Skipping test because C++11 is not available")
int main() {}
#else
enum E1 { v1 };
BOOST_DESCRIBE_ENUM(E1, v1)
enum class E2 { v2 };
BOOST_DESCRIBE_ENUM(E2, v2)
BOOST_DEFINE_ENUM(E3, v3)
BOOST_DEFINE_ENUM_CLASS(E4, v4)
enum E5 { v5 };
enum class E6 { v6 };
int main()
{
using boost::describe::has_describe_enumerators;
#if defined(BOOST_DESCRIBE_CXX14)
BOOST_TEST_TRAIT_TRUE((has_describe_enumerators<E1>));
BOOST_TEST_TRAIT_TRUE((has_describe_enumerators<E2>));
BOOST_TEST_TRAIT_TRUE((has_describe_enumerators<E3>));
BOOST_TEST_TRAIT_TRUE((has_describe_enumerators<E4>));
#else
BOOST_TEST_TRAIT_FALSE((has_describe_enumerators<E1>));
BOOST_TEST_TRAIT_FALSE((has_describe_enumerators<E2>));
BOOST_TEST_TRAIT_FALSE((has_describe_enumerators<E3>));
BOOST_TEST_TRAIT_FALSE((has_describe_enumerators<E4>));
#endif
BOOST_TEST_TRAIT_FALSE((has_describe_enumerators<E5>));
BOOST_TEST_TRAIT_FALSE((has_describe_enumerators<E6>));
BOOST_TEST_TRAIT_FALSE((has_describe_enumerators<int>));
BOOST_TEST_TRAIT_FALSE((has_describe_enumerators<void>));
return boost::report_errors();
}
#endif // !defined(BOOST_DESCRIBE_CXX11)

60
test/has_members_test.cpp Normal file
View File

@@ -0,0 +1,60 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/members.hpp>
#include <boost/describe/class.hpp>
#include <boost/core/lightweight_test_trait.hpp>
#if !defined(BOOST_DESCRIBE_CXX11)
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("Skipping test because C++11 is not available")
int main() {}
#else
struct X1 {};
BOOST_DESCRIBE_STRUCT(X1, (), ())
class X2
{
BOOST_DESCRIBE_CLASS(X2, (), (), (), ())
};
struct X3 {};
class X4 {};
union X5 {};
struct X6: X1 {};
struct X7: X2 {};
int main()
{
using boost::describe::has_describe_members;
#if defined(BOOST_DESCRIBE_CXX14)
BOOST_TEST_TRAIT_TRUE((has_describe_members<X1>));
BOOST_TEST_TRAIT_TRUE((has_describe_members<X2>));
#else
BOOST_TEST_TRAIT_FALSE((has_describe_members<X1>));
BOOST_TEST_TRAIT_FALSE((has_describe_members<X2>));
#endif
BOOST_TEST_TRAIT_FALSE((has_describe_members<X3>));
BOOST_TEST_TRAIT_FALSE((has_describe_members<X4>));
BOOST_TEST_TRAIT_FALSE((has_describe_members<X5>));
BOOST_TEST_TRAIT_FALSE((has_describe_members<X6>));
BOOST_TEST_TRAIT_FALSE((has_describe_members<X7>));
BOOST_TEST_TRAIT_FALSE((has_describe_members<int>));
BOOST_TEST_TRAIT_FALSE((has_describe_members<void>));
return boost::report_errors();
}
#endif // !defined(BOOST_DESCRIBE_CXX11)

View File

@@ -59,7 +59,7 @@ int main()
using D1 = mp_at_c<L, 0>;
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1930)
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1940)
// https://developercommunity.visualstudio.com/content/problem/1186002/constexpr-pointer-to-member-has-incorrect-value.html
BOOST_TEST( D1::pointer == &C::m2 );
#endif
@@ -79,7 +79,7 @@ int main()
BOOST_TEST_CSTR_EQ( D1::name, "m1" );
BOOST_TEST_EQ( D1::modifiers, mod_public | mod_inherited );
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1930)
#if !BOOST_WORKAROUND(BOOST_MSVC, < 1940)
BOOST_TEST( D2::pointer == &C::m2 );
#endif
BOOST_TEST_CSTR_EQ( D2::name, "m2" );

16
test/nested_enum_fail.cpp Normal file
View File

@@ -0,0 +1,16 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/enum.hpp>
#if !defined(BOOST_DESCRIBE_CXX14)
#error "Skipping test because C++14 is not available"
#else
enum E1 {};
BOOST_DESCRIBE_NESTED_ENUM(E1);
#endif // !defined(BOOST_DESCRIBE_CXX14)

View File

@@ -0,0 +1,24 @@
// Copyright 2025 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/enumerators.hpp>
#include <boost/describe/enum.hpp>
#include <boost/config.hpp>
#include <boost/config/pragma_message.hpp>
#if !defined(BOOST_DESCRIBE_CXX20)
BOOST_PRAGMA_MESSAGE("Skipping test because BOOST_DESCRIBE_CXX20 isn't defined")
#else
struct X
{
enum E { v1 };
BOOST_DESCRIBE_NESTED_ENUM(E, v1)
using L = boost::describe::describe_enumerators<E>;
};
#endif

93
test/operator_eq_test.cpp Normal file
View File

@@ -0,0 +1,93 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/operators.hpp>
#include <boost/describe/class.hpp>
#include <boost/core/lightweight_test.hpp>
#if !defined(BOOST_DESCRIBE_CXX14)
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("Skipping test because C++14 is not available")
int main() {}
#else
namespace app
{
struct X
{
void f() const {}
static void g() {}
};
BOOST_DESCRIBE_STRUCT(X, (), (f, g))
using boost::describe::operators::operator==;
using boost::describe::operators::operator<<;
struct Y
{
int a = 1;
};
BOOST_DESCRIBE_STRUCT(Y, (), (a))
using boost::describe::operators::operator==;
using boost::describe::operators::operator!=;
using boost::describe::operators::operator<<;
struct Z: X, Y
{
int b = 4;
};
BOOST_DESCRIBE_STRUCT(Z, (X, Y), (b))
using boost::describe::operators::operator==;
using boost::describe::operators::operator!=;
using boost::describe::operators::operator<<;
} // namespace app
int main()
{
using app::X;
{
X x1, x2;
BOOST_TEST_EQ( x1, x2 );
}
using app::Y;
{
Y y1, y2, y3;
y3.a = 2;
BOOST_TEST_EQ( y1, y2 );
BOOST_TEST_NE( y1, y3 );
}
using app::Z;
{
Z z1, z2, z3, z4;
z3.a = 2;
z4.b = 3;
BOOST_TEST_EQ( z1, z2 );
BOOST_TEST_NE( z1, z3 );
BOOST_TEST_NE( z1, z4 );
BOOST_TEST_NE( z3, z4 );
}
return boost::report_errors();
}
#endif // !defined(BOOST_DESCRIBE_CXX14)

101
test/operator_lt_test.cpp Normal file
View File

@@ -0,0 +1,101 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/operators.hpp>
#include <boost/describe/class.hpp>
#include <boost/core/lightweight_test.hpp>
#if !defined(BOOST_DESCRIBE_CXX14)
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("Skipping test because C++14 is not available")
int main() {}
#else
namespace app
{
struct X
{
void f() const {}
static void g() {}
};
BOOST_DESCRIBE_STRUCT(X, (), (f, g))
using boost::describe::operators::operator<=;
using boost::describe::operators::operator>=;
using boost::describe::operators::operator<<;
struct Y
{
int a = 1;
};
BOOST_DESCRIBE_STRUCT(Y, (), (a))
using boost::describe::operators::operator<;
using boost::describe::operators::operator>;
using boost::describe::operators::operator<=;
using boost::describe::operators::operator>=;
using boost::describe::operators::operator<<;
struct Z: X, Y
{
int b = 4;
};
BOOST_DESCRIBE_STRUCT(Z, (X, Y), (b))
using boost::describe::operators::operator<;
using boost::describe::operators::operator>;
using boost::describe::operators::operator<=;
using boost::describe::operators::operator>=;
using boost::describe::operators::operator<<;
} // namespace app
#define TEST_EQ(x, y) BOOST_TEST_LE(x, y); BOOST_TEST_GE(x, y); BOOST_TEST_NOT((x) < (y)); BOOST_TEST_NOT((x) > (y))
#define TEST_LT(x, y) BOOST_TEST_LT(x, y); BOOST_TEST_LE(x, y); BOOST_TEST_GT(y, x); BOOST_TEST_GE(y, x)
int main()
{
using app::X;
{
X x1, x2;
TEST_EQ( x1, x2 );
}
using app::Y;
{
Y y1, y2, y3;
y3.a = 2;
TEST_EQ( y1, y2 );
TEST_LT( y1, y3 );
}
using app::Z;
{
Z z1, z2, z3, z4;
z3.a = 2;
z4.b = 3;
TEST_EQ( z1, z2 );
TEST_LT( z1, z3 );
TEST_LT( z4, z1 );
TEST_LT( z4, z3 );
}
return boost::report_errors();
}
#endif // !defined(BOOST_DESCRIBE_CXX14)

View File

@@ -0,0 +1,19 @@
// Copyright 2022 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/bases.hpp>
#include <boost/core/lightweight_test_trait.hpp>
struct X {};
int main()
{
#if defined(BOOST_DESCRIBE_CXX11)
BOOST_TEST_TRAIT_FALSE((boost::describe::has_describe_bases<X>));
#endif
return boost::report_errors();
}

View File

@@ -0,0 +1,19 @@
// Copyright 2022 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/enumerators.hpp>
#include <boost/core/lightweight_test_trait.hpp>
enum E {};
int main()
{
#if defined(BOOST_DESCRIBE_CXX11)
BOOST_TEST_TRAIT_FALSE((boost::describe::has_describe_enumerators<E>));
#endif
return boost::report_errors();
}

View File

@@ -0,0 +1,19 @@
// Copyright 2022 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/members.hpp>
#include <boost/core/lightweight_test_trait.hpp>
struct X {};
int main()
{
#if defined(BOOST_DESCRIBE_CXX11)
BOOST_TEST_TRAIT_FALSE((boost::describe::has_describe_members<X>));
#endif
return boost::report_errors();
}

View File

@@ -70,6 +70,19 @@ char const * s49 = BOOST_DESCRIBE_PP_FOR_EACH(F1, ~, a, b, c, d, e, f, g, h, i,
char const * s50 = BOOST_DESCRIBE_PP_FOR_EACH(F1, ~, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X);
char const * s51 = BOOST_DESCRIBE_PP_FOR_EACH(F1, ~, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y);
char const * s52 = BOOST_DESCRIBE_PP_FOR_EACH(F1, ~, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z);
char const * s53 = BOOST_DESCRIBE_PP_FOR_EACH(F1, ~, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, 1);
char const * s54 = BOOST_DESCRIBE_PP_FOR_EACH(F1, ~, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, 1, 2);
char const * s55 = BOOST_DESCRIBE_PP_FOR_EACH(F1, ~, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, 1, 2, 3);
char const * s56 = BOOST_DESCRIBE_PP_FOR_EACH(F1, ~, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, 1, 2, 3, 4);
char const * s57 = BOOST_DESCRIBE_PP_FOR_EACH(F1, ~, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, 1, 2, 3, 4, 5);
char const * s58 = BOOST_DESCRIBE_PP_FOR_EACH(F1, ~, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, 1, 2, 3, 4, 5, 6);
char const * s59 = BOOST_DESCRIBE_PP_FOR_EACH(F1, ~, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, 1, 2, 3, 4, 5, 6, 7);
char const * s60 = BOOST_DESCRIBE_PP_FOR_EACH(F1, ~, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, 1, 2, 3, 4, 5, 6, 7, 8);
char const * s61 = BOOST_DESCRIBE_PP_FOR_EACH(F1, ~, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, 1, 2, 3, 4, 5, 6, 7, 8, 9);
char const * s62 = BOOST_DESCRIBE_PP_FOR_EACH(F1, ~, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0);
char const * s63 = BOOST_DESCRIBE_PP_FOR_EACH(F1, ~, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, @);
char const * s64 = BOOST_DESCRIBE_PP_FOR_EACH(F1, ~, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, @, _);
int main()
{
@@ -126,6 +139,18 @@ int main()
BOOST_TEST_CSTR_EQ( s50, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWX" );
BOOST_TEST_CSTR_EQ( s51, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXY" );
BOOST_TEST_CSTR_EQ( s52, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" );
BOOST_TEST_CSTR_EQ( s53, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1" );
BOOST_TEST_CSTR_EQ( s54, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12" );
BOOST_TEST_CSTR_EQ( s55, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123" );
BOOST_TEST_CSTR_EQ( s56, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234" );
BOOST_TEST_CSTR_EQ( s57, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12345" );
BOOST_TEST_CSTR_EQ( s58, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456" );
BOOST_TEST_CSTR_EQ( s59, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567" );
BOOST_TEST_CSTR_EQ( s60, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ12345678" );
BOOST_TEST_CSTR_EQ( s61, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456789" );
BOOST_TEST_CSTR_EQ( s62, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890" );
BOOST_TEST_CSTR_EQ( s63, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890@" );
BOOST_TEST_CSTR_EQ( s64, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890@_" );
return boost::report_errors();
}

79
test/union_test.cpp Normal file
View File

@@ -0,0 +1,79 @@
// Copyright 2020, 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/members.hpp>
#include <boost/describe/class.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/config/pragma_message.hpp>
#if !defined(BOOST_DESCRIBE_CXX11)
BOOST_PRAGMA_MESSAGE("Skipping test because C++11 is not available")
int main() {}
#elif defined(__GNUC__) && __GNUC__ < 5
BOOST_PRAGMA_MESSAGE("Skipping test because g++ 4.8")
int main() {}
#else
union A
{
int m1;
static int m2;
int f1() const { return m1; }
static int f2() { return m2; }
};
BOOST_DESCRIBE_STRUCT(A, (), (m1, m2, f1, f2))
int A::m2;
#if !defined(BOOST_DESCRIBE_CXX14)
BOOST_PRAGMA_MESSAGE("Skipping test because C++14 is not available")
int main() {}
#else
#include <boost/mp11.hpp>
int main()
{
using namespace boost::describe;
using namespace boost::mp11;
{
using L = describe_members<A, mod_any_access | mod_any_member>;
BOOST_TEST_EQ( mp_size<L>::value, 4 );
using D1 = mp_at_c<L, 0>;
using D2 = mp_at_c<L, 1>;
using D3 = mp_at_c<L, 2>;
using D4 = mp_at_c<L, 3>;
BOOST_TEST( D1::pointer == &A::m1 );
BOOST_TEST_CSTR_EQ( D1::name, "m1" );
BOOST_TEST_EQ( D1::modifiers, mod_public );
BOOST_TEST( D2::pointer == &A::m2 );
BOOST_TEST_CSTR_EQ( D2::name, "m2" );
BOOST_TEST_EQ( D2::modifiers, mod_public | mod_static );
BOOST_TEST( D3::pointer == &A::f1 );
BOOST_TEST_CSTR_EQ( D3::name, "f1" );
BOOST_TEST_EQ( D3::modifiers, mod_public | mod_function );
BOOST_TEST( D4::pointer == &A::f2 );
BOOST_TEST_CSTR_EQ( D4::name, "f2" );
BOOST_TEST_EQ( D4::modifiers, mod_public | mod_static | mod_function );
}
return boost::report_errors();
}
#endif // !defined(BOOST_DESCRIBE_CXX14)
#endif // !defined(BOOST_DESCRIBE_CXX11)

153
test/union_test2.cpp Normal file
View File

@@ -0,0 +1,153 @@
// Copyright 2020, 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
#include <boost/describe/members.hpp>
#include <boost/describe/class.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/config/pragma_message.hpp>
#if !defined(BOOST_DESCRIBE_CXX11)
BOOST_PRAGMA_MESSAGE("Skipping test because C++11 is not available")
int main() {}
#elif defined(__GNUC__) && __GNUC__ < 5
BOOST_PRAGMA_MESSAGE("Skipping test because g++ 4.8")
int main() {}
#else
union A
{
public:
int m1;
static int m2;
int f1() const { return m1; }
static int f2() { return m2; }
protected:
int m3;
static int m4;
int f3() const { return m3; }
static int f4() { return m4; }
private:
int m5;
static int m6;
int f5() const { return m5; }
static int f6() { return m6; }
BOOST_DESCRIBE_CLASS(A, (), (m1, m2, f1, f2), (m3, m4, f3, f4), (m5, m6, f5, f6))
friend int main();
};
int A::m2;
int A::m4;
int A::m6;
#if !defined(BOOST_DESCRIBE_CXX14)
BOOST_PRAGMA_MESSAGE("Skipping test because C++14 is not available")
int main() {}
#else
#include <boost/mp11.hpp>
int main()
{
using namespace boost::describe;
using namespace boost::mp11;
{
using L = describe_members<A, mod_public | mod_any_member>;
BOOST_TEST_EQ( mp_size<L>::value, 4 );
using D1 = mp_at_c<L, 0>;
using D2 = mp_at_c<L, 1>;
using D3 = mp_at_c<L, 2>;
using D4 = mp_at_c<L, 3>;
BOOST_TEST( D1::pointer == &A::m1 );
BOOST_TEST_CSTR_EQ( D1::name, "m1" );
BOOST_TEST_EQ( D1::modifiers, mod_public );
BOOST_TEST( D2::pointer == &A::m2 );
BOOST_TEST_CSTR_EQ( D2::name, "m2" );
BOOST_TEST_EQ( D2::modifiers, mod_public | mod_static );
BOOST_TEST( D3::pointer == &A::f1 );
BOOST_TEST_CSTR_EQ( D3::name, "f1" );
BOOST_TEST_EQ( D3::modifiers, mod_public | mod_function );
BOOST_TEST( D4::pointer == &A::f2 );
BOOST_TEST_CSTR_EQ( D4::name, "f2" );
BOOST_TEST_EQ( D4::modifiers, mod_public | mod_static | mod_function );
}
{
using L = describe_members<A, mod_protected | mod_any_member>;
BOOST_TEST_EQ( mp_size<L>::value, 4 );
using D1 = mp_at_c<L, 0>;
using D2 = mp_at_c<L, 1>;
using D3 = mp_at_c<L, 2>;
using D4 = mp_at_c<L, 3>;
BOOST_TEST( D1::pointer == &A::m3 );
BOOST_TEST_CSTR_EQ( D1::name, "m3" );
BOOST_TEST_EQ( D1::modifiers, mod_protected );
BOOST_TEST( D2::pointer == &A::m4 );
BOOST_TEST_CSTR_EQ( D2::name, "m4" );
BOOST_TEST_EQ( D2::modifiers, mod_protected | mod_static );
BOOST_TEST( D3::pointer == &A::f3 );
BOOST_TEST_CSTR_EQ( D3::name, "f3" );
BOOST_TEST_EQ( D3::modifiers, mod_protected | mod_function );
BOOST_TEST( D4::pointer == &A::f4 );
BOOST_TEST_CSTR_EQ( D4::name, "f4" );
BOOST_TEST_EQ( D4::modifiers, mod_protected | mod_static | mod_function );
}
{
using L = describe_members<A, mod_private | mod_any_member>;
BOOST_TEST_EQ( mp_size<L>::value, 4 );
using D1 = mp_at_c<L, 0>;
using D2 = mp_at_c<L, 1>;
using D3 = mp_at_c<L, 2>;
using D4 = mp_at_c<L, 3>;
BOOST_TEST( D1::pointer == &A::m5 );
BOOST_TEST_CSTR_EQ( D1::name, "m5" );
BOOST_TEST_EQ( D1::modifiers, mod_private );
BOOST_TEST( D2::pointer == &A::m6 );
BOOST_TEST_CSTR_EQ( D2::name, "m6" );
BOOST_TEST_EQ( D2::modifiers, mod_private | mod_static );
BOOST_TEST( D3::pointer == &A::f5 );
BOOST_TEST_CSTR_EQ( D3::name, "f5" );
BOOST_TEST_EQ( D3::modifiers, mod_private | mod_function );
BOOST_TEST( D4::pointer == &A::f6 );
BOOST_TEST_CSTR_EQ( D4::name, "f6" );
BOOST_TEST_EQ( D4::modifiers, mod_private | mod_static | mod_function );
}
return boost::report_errors();
}
#endif // !defined(BOOST_DESCRIBE_CXX14)
#endif // !defined(BOOST_DESCRIBE_CXX11)

View File

@@ -0,0 +1,37 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
// Tests that -Wunused-function is not emitted under Clang
#include <boost/describe.hpp>
#if !defined(BOOST_DESCRIBE_CXX14)
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("Skipping test because C++14 is not available")
#else
namespace
{
enum E { v };
BOOST_DESCRIBE_ENUM(E, v)
struct S
{
};
BOOST_DESCRIBE_STRUCT(S, (), ())
class C
{
BOOST_DESCRIBE_CLASS(C, (), (), (), ())
};
} // namespace
#endif // !defined(BOOST_DESCRIBE_CXX14)

View File

@@ -0,0 +1,47 @@
// Copyright 2021 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
// Tests that -Wunneeded-internal-declaration is not emitted under Clang
#include <boost/describe.hpp>
#if !defined(BOOST_DESCRIBE_CXX14)
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("Skipping test because C++14 is not available")
#else
namespace
{
enum E { v };
BOOST_DESCRIBE_ENUM(E, v)
struct X
{
};
BOOST_DESCRIBE_STRUCT(X, (), ())
class Y
{
BOOST_DESCRIBE_CLASS(Y, (), (), (), ())
};
} // namespace
using namespace boost::describe;
using L1 = describe_enumerators<E>;
using L2 = describe_bases<X, mod_any_access>;
using L3 = describe_members<X, mod_any_access>;
using L4 = describe_bases<Y, mod_any_access>;
using L5 = describe_members<Y, mod_any_access>;
#endif // !defined(BOOST_DESCRIBE_CXX14)