135 Commits

Author SHA1 Message Date
Jean-Louis Leroy
83bc8d2c68 final_virtual_ptr: add sanity checks 2025-11-02 12:35:01 -05:00
Jean-Louis Leroy
ba6d178f34 final_virtual_ptr: fix const-related bug 2025-11-01 14:13:44 -04:00
Alexander Grund
d59abed109 Fix CMake subdir test
* Fix CMake subdir test

`add_test(main main)` treats the 2nd argument as the command to run.

The one-argument (or named argument variant) supports resolving target names so it will always find it

* Use named arguments for subdir-add_test
2025-11-01 11:28:11 -04:00
Jean-Louis Leroy
d5ccc9edaa CI: exclude clang-7 2025-10-31 14:01:22 -04:00
Jean-Louis Leroy
d9edbe9607 Revert "work around old compiler constexpr glitch"
This reverts commit 3ef66b4b0f.
2025-10-31 13:49:37 -04:00
Jean-Louis Leroy
3ef66b4b0f work around old compiler constexpr glitch 2025-10-31 13:13:22 -04:00
Jean-Louis Leroy
f7d47fbd35 pass compiler to policies' initialize() 2025-10-30 17:02:54 -04:00
Jean-Louis Leroy
e5762bd6e6 tests: reinstate warnings-as-errors on clang+windows 2025-10-29 10:46:45 -04:00
Jean-Louis Leroy
d057945a09 fix warning 2025-10-28 14:11:19 -04:00
Jean-Louis Leroy
0bda0fee49 CML: prefix targets with "boost_openmethod-" 2025-10-28 11:17:39 -04:00
Jean-Louis Leroy
36d88320ba disable warnings for unit test lib for clang+windows 2025-10-28 11:17:39 -04:00
Jean-Louis Leroy
9fdc1274c1 fix warning 2025-10-27 17:28:02 -04:00
Jean-Louis Leroy
8617f71a05 more CML fixes for integration in super-project 2025-10-27 15:10:57 -04:00
Jean-Louis Leroy
af52a803d6 CML: add headers as source only if cmake >= 3.19 2025-10-27 11:33:56 -04:00
Jean-Louis Leroy
b31bee24b2 remove leftovers from win32 dll experiment 2025-10-25 14:53:17 -04:00
Jean-Louis Leroy
e78199e8a0 fix virtual_type doc 2025-10-25 14:51:46 -04:00
Jean-Louis Leroy
a2d69a97d2 fix add_step_by_step (msbuild) 2025-10-25 13:53:26 -04:00
Jean-Louis Leroy
826188ec01 CI: temporarily remove readme from paths-ignore 2025-10-25 12:31:14 -04:00
Jean-Louis Leroy
c9b682a679 readme: remaining 'template' -> 'openmethod' 2025-10-25 12:31:14 -04:00
Jean-Louis Leroy
6540e23971 b2: treat warnings as errors, fix the few remaining 2025-10-25 11:33:30 -04:00
Jean-Louis Leroy
4249f86bd7 update post-mrdocs script 2025-10-24 15:52:31 -04:00
Jean-Louis Leroy
19e0ff771b doc: fix redirect 2025-10-24 15:52:31 -04:00
joaquintides
f259ee4c7e adjusted working directory inside build_antora.sh 2025-10-22 19:26:12 +02:00
joaquintides
3392f1a636 updated package[-lock].json as per files in boostorg/url 2025-10-22 17:16:07 +02:00
joaquintides
81f4046b9b added Jamfile for Antora docgen 2025-10-22 08:14:44 -04:00
joaquintides
dc62c59f09 changed Antora output directory to doc/html 2025-10-22 08:14:44 -04:00
joaquintides
6c77104d9e removed Asciidoc-related scaffolding 2025-10-22 08:14:44 -04:00
Jean-Louis Leroy
c32fe5ef17 nav.doc: advanced_features.adoc does not exist (yet) 2025-10-21 17:29:28 -04:00
Jean-Louis Leroy
796eed633e ci: fix doc build 2025-10-21 17:29:28 -04:00
Jean-Louis Leroy
386f6979b7 b2: require cxx17 in test Jamfile 2025-10-21 14:54:06 -04:00
Jean-Louis Leroy
666e0c3da1 more b2 fixes 2025-10-21 13:50:46 -04:00
Jean-Louis Leroy
e6be4be05d remove .gitmodules 2025-10-21 13:38:21 -04:00
Jean-Louis Leroy
eb0c5804f6 fix b2 project name 2025-10-21 13:33:59 -04:00
Jean-Louis Leroy
3ef25b2463 ci: run antora job only for master@boostorg and feature/doc@jll63 2025-10-21 13:06:15 -04:00
Jean-Louis Leroy
00abd9176b fix adoc-mrdocs xrefs 2025-10-21 13:04:05 -04:00
Jean-Louis Leroy
9ecf9158f9 basics.adoc: include cpp fragments 2025-10-21 12:50:46 -04:00
Jean-Louis Leroy
c7bc263e81 improve odr_violation doc 2025-10-20 18:29:11 -04:00
Jean-Louis Leroy
f1819cd8b8 improve doc 2025-10-20 18:03:29 -04:00
Jean-Louis Leroy
c9c0972edd improve doc 2025-10-20 17:52:52 -04:00
Jean-Louis Leroy
fc17021a77 small doc fix 2025-10-20 12:24:44 -04:00
Jean-Louis Leroy
9ae95df2af small doc improvements 2025-10-19 18:18:50 -04:00
Jean-Louis Leroy
98319c4797 fix coverity violations 2025-10-19 18:11:21 -04:00
Jean-Louis Leroy
36270d4d05 static_assert against repeated inheritance 2025-10-19 16:05:54 -04:00
Jean-Louis Leroy
fa19da8c4b doc: mostly custom RTTI 2025-10-19 15:03:09 -04:00
Jean-Louis Leroy
5dd55f2141 doc: mostly virtual_, some minor changes elsewhere 2025-10-18 14:16:37 -04:00
Jean-Louis Leroy
838dc1d261 improve Core API doc 2025-10-16 19:00:52 -04:00
Jean-Louis Leroy
e3c76f07f7 work around MrDocs bug wrt macros in requirements 2025-10-16 19:00:52 -04:00
Jean-Louis Leroy
40350dd854 pass initialize() options as arguments 2025-10-16 19:00:52 -04:00
Jean-Louis Leroy
68fc3f56ad doc 2025-10-15 17:45:59 -04:00
Jean-Louis Leroy
397ccb6dde more multiple dispatch doc 2025-10-14 23:13:07 -04:00
Jean-Louis Leroy
4ecde2e91d simplify abort message for bad calls 2025-10-14 23:11:57 -04:00
Jean-Louis Leroy
efbc135a59 fix type_ids of virtual_ptr args in bad_call 2025-10-14 23:07:16 -04:00
Jean-Louis Leroy
830c3ce71c README: remove Azure column 2025-10-13 20:56:58 -04:00
Jean-Louis Leroy
c4f967f025 more validations 2025-10-13 20:47:30 -04:00
Jean-Louis Leroy
626c74960a doc 2025-10-13 20:45:23 -04:00
joaquintides
1b94d2948e no-op update to ci.yml to trigger CI 2025-10-07 19:34:00 +02:00
joaquintides
9a04e30506 launched CI 2025-10-07 19:30:26 +02:00
joaquintides
6433a6791b updated Coverity links 2025-10-07 19:17:39 +02:00
Jean-Louis Leroy
41c462986b more doc 2025-10-05 19:21:07 -04:00
Jean-Louis Leroy
b41f40f1d1 work around msvc glitch 2025-10-05 19:15:54 -04:00
Jean-Louis Leroy
adc15fcd53 vptr_map: bugfix: vptr_map accumulates with multiple initialize() 2025-10-05 19:15:54 -04:00
Jean-Louis Leroy
8595067b5c improve dynamic loading example 2025-10-05 19:15:54 -04:00
Jean-Louis Leroy
5a6670fcf6 more doc 2025-10-05 19:10:47 -04:00
Jean-Louis Leroy
627f3c1c0e fix init_bad_call 2025-09-28 21:28:46 -04:00
Jean-Louis Leroy
4b80801c97 rework macros 2025-09-28 21:28:46 -04:00
Jean-Louis Leroy
4fceb9a6fa lot of doc work, but also rework code 2025-09-28 16:08:11 -04:00
Jean-Louis Leroy
5c3187816d ci.yml: adopt reusable workflow 2025-09-26 18:49:38 -04:00
Jean-Louis Leroy
0b71a75a47 ci: coverity 2025-09-23 18:52:01 -04:00
Jean-Louis Leroy
e309695f61 2 renames and reformat 2025-09-20 15:21:18 -04:00
Jean-Louis Leroy
7d5557fb18 better compile-time error messages 2025-09-20 14:16:03 -04:00
Jean-Louis Leroy
1c0e69b94c shared_virtual_ptr moves or copies like std::shared_ptr 2025-09-20 14:16:03 -04:00
Jean-Louis Leroy
0fdca389a8 cml: catch up with DynamicBitset 2025-09-20 14:16:03 -04:00
Jean-Louis Leroy
f6172e4262 rework and doc smart pointers 2025-09-20 14:16:03 -04:00
Jean-Louis Leroy
3bec1ee519 doc, more tests for shared_ptr traits, fixes 2025-09-20 14:16:03 -04:00
Jean-Louis Leroy
b905379285 link into reference 2025-09-20 14:16:03 -04:00
Jean-Louis Leroy
1cf37e79b5 xref out of mrdocs 2025-09-20 14:16:03 -04:00
Jean-Louis Leroy
f36ac792cf doc 2025-09-20 14:16:03 -04:00
Jean-Louis Leroy
81690dca4a chasing msvc warnings 2025-09-20 14:15:35 -04:00
Jean-Louis Leroy
4b3bc74de2 GHA: windows-2019 image is gone, remove msvc 14-2 2025-09-16 17:50:50 -04:00
Jean-Louis Leroy
a22089f597 after move to boostorg, don't force boost-ci branch anymore 2025-09-16 17:50:50 -04:00
Jean-Louis Leroy
bfa003e42c GHA: change repo clone path after move to boostorg 2025-09-16 17:41:13 -04:00
joaquintides
34ebad0e90 added 32-bit mode to MSVC pipelines 2025-09-16 17:31:06 -04:00
joaquintides
d21dcb0b52 removed older compilers 2025-09-16 17:31:06 -04:00
joaquintides
45a5769238 disambiguated pipeline names 2025-09-16 17:31:06 -04:00
joaquintides
f58d92bf94 removed pre-C++17 jobs 2025-09-16 17:31:06 -04:00
joaquintides
aa15a7ab5d set execution permissions for drone.sh 2025-09-16 17:31:06 -04:00
joaquintides
b179cce168 added Drone support 2025-09-16 17:31:06 -04:00
Jean-Louis Leroy
11b43d2472 avoid reference to null in virtual_ptr comparison 2025-09-14 17:03:21 -04:00
Jean-Louis Leroy
0545d7e8ea more doc work, with some changes prompted by the doc 2025-09-14 15:28:18 -04:00
Jean-Louis Leroy
31b48568cb doc, compiler to registry, simplify policies 2025-09-05 15:28:45 -04:00
Jean-Louis Leroy
baff0d3f23 with_vptr -> inplace_vptr 2025-07-12 10:19:35 -04:00
Jean-Louis Leroy
0416b9b888 CI: windows-2019 is gone, use windows-2022 2025-07-07 16:50:50 -04:00
Jean-Louis Leroy
6a9ccf170b static checks for invalid method params 2025-06-30 17:54:19 -04:00
Jean-Louis Leroy
489f1d27d8 use static library version of Boost.Test 2025-06-30 17:07:35 -04:00
Jean-Louis Leroy
83c8ab9afd CI: adopt boost-cli GHA 2025-06-30 17:07:35 -04:00
Jean-Louis Leroy
44475ab117 use boost-ci README template 2025-06-29 12:07:25 -04:00
Jean-Louis Leroy
bfa9c01b3d Revert ".appveyor.yml"
This reverts commit 0038f21569.
2025-06-29 11:06:53 -04:00
Jean-Louis Leroy
0038f21569 .appveyor.yml 2025-06-29 10:54:38 -04:00
Jean-Louis Leroy
4a9b9e439d .codecov.yml 2025-06-29 10:36:56 -04:00
Jean-Louis Leroy
88832cc96c BOOST_OPENMETHOD_NAME -> BOOST_OPENMETHOD_ID 2025-06-21 14:30:07 -04:00
Jean-Louis Leroy
8e439f2934 fix signed/unsigned warning 2025-06-21 14:16:43 -04:00
Jean-Louis Leroy
1c971c5fc9 scope boost_openmethod_vptr(with_vptr) in registry 2025-06-21 14:10:40 -04:00
Jean-Louis Leroy
a078c9c002 examples -> example 2025-06-21 13:58:51 -04:00
Jean-Louis Leroy
9edce6902b openmethod_error needs not be polymorphic 2025-06-21 11:05:12 -04:00
Jean-Louis Leroy
38140e57ae enable sanitizers 2025-06-21 11:05:12 -04:00
Jean-Louis Leroy
d352a55d58 fix warnings 2025-06-21 11:05:12 -04:00
Jean-Louis Leroy
a0720ca8b6 registry scoped boost_openmethod_vptr 2025-06-21 08:29:00 -04:00
Jean-Louis Leroy
e1658db6d1 remove unnecessary reinterpret_cast 2025-06-19 17:42:55 -04:00
Jean-Louis Leroy
22fc7e8fd7 rework error reporting 2025-06-19 17:25:56 -04:00
Jean-Louis Leroy
ac1e0efb1c rework policy helpers 2025-06-19 12:14:44 -04:00
Jean-Louis Leroy
c1f3f603ca runtime_checks: initialize() called 2025-06-16 20:17:21 -04:00
Jean-Louis Leroy
5c1dfd8c64 virtual_ptr: deduction guide for rvalue references 2025-06-15 16:54:35 -04:00
Jean-Louis Leroy
5a58be1aa8 bring back flat headers 2025-06-14 13:15:21 -04:00
Jean-Louis Leroy
8ec027c55a do not alias virtual_ptr in global namespace, 'aliases' namespace 2025-06-14 12:17:26 -04:00
Jean-Louis Leroy
e92a241c73 make n2216 resolution an opt-in 2025-06-09 08:11:49 -04:00
Jean-Louis Leroy
97766ef47a fix throw_error_handler 2025-06-09 08:11:49 -04:00
Jean-Louis Leroy
179967f9c2 fix MSVC warnings 2025-06-01 15:04:28 -04:00
Jean-Louis Leroy
ae60941daf handle deferred RTTI without UB 2025-06-01 13:49:50 -04:00
Jean-Louis Leroy
e8c57b44ff MSVC: compile with /bigobj 2025-06-01 13:49:50 -04:00
Jean-Louis Leroy
ded8ceabfa README 2025-05-31 11:13:41 -04:00
Jean-Louis Leroy
efc8cbff52 add method::has_next, and have macros delegate to it 2025-05-26 15:32:37 -04:00
Jean-Louis Leroy
2f9734b403 use union for dispatch data instead of uintptr_t 2025-05-26 15:32:37 -04:00
Jean-Louis Leroy
e26798bd2f uniform method - core 2025-05-25 17:11:20 -04:00
Jean-Louis Leroy
a64bd54c18 vectored_error_handler -> default_error_handler 2025-05-20 17:58:41 -04:00
Jean-Louis Leroy
186bf508c2 CI: do not publish flat headers 2025-05-19 19:09:00 -04:00
Jean-Louis Leroy
9571fefb17 fix flattening 2025-05-19 19:00:55 -04:00
Jean-Louis Leroy
1c8bbd22d2 rework policies 2025-05-19 18:45:57 -04:00
Jean-Louis Leroy
921fb312d5 rework policies 2025-05-19 18:45:57 -04:00
Jean-Louis Leroy
da937900d9 fix indirect virtual_ptr::final 2025-05-19 18:45:57 -04:00
Jean-Louis Leroy
e80d443dbf rework policies 2025-05-19 18:45:57 -04:00
Jean-Louis Leroy
dba92d1d39 rework policies 2025-05-19 18:45:57 -04:00
Jean-Louis Leroy
0b44fc5973 rework policies 2025-05-19 18:45:57 -04:00
Jean-Louis Leroy
40c90777aa fix inheritance lattice deduction 2025-05-13 20:30:17 -04:00
Jean-Louis Leroy
e8ec2611cb un-version flat directory 2025-05-13 20:30:17 -04:00
Jean-Louis Leroy
93e0388ab1 after boost review 2025-05-10 11:01:41 -04:00
280 changed files with 88924 additions and 8954 deletions

23
.codecov.yml Normal file
View File

@@ -0,0 +1,23 @@
# Copyright 2019 - 2021 Alexander Grund
# 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)
#
# Sample codecov configuration file. Edit as required
codecov:
max_report_age: off
require_ci_to_pass: yes
notify:
# Increase this if you have multiple coverage collection jobs
after_n_builds: 1
wait_for_ci: yes
# Change how pull request comments look
comment:
layout: "reach,diff,flags,files,footer"
# Ignore specific files or folders. Glob patterns are supported.
# See https://docs.codecov.com/docs/ignoring-paths
ignore:
- extra/**/*
# - test/**/*

354
.drone.jsonnet Normal file
View File

@@ -0,0 +1,354 @@
# Copyright 2022 Peter Dimov
# Distributed under the Boost Software License, Version 1.0.
# https://www.boost.org/LICENSE_1_0.txt
local library = "openmethod";
local triggers =
{
branch: [ "master", "develop", "feature/*", "fix/*" ]
};
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',
'wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -',
] +
(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 18.04 GCC 8 32/64",
"cppalliance/droneubuntu1804:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-8', CXXSTD: '17', ADDRMD: '32,64' },
"g++-8-multilib",
),
linux_pipeline(
"Linux 20.04 GCC 9* 32/64",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '17,2a', ADDRMD: '32,64' },
),
linux_pipeline(
"Linux 20.04 GCC 9* ARM64",
"cppalliance/droneubuntu2004:multiarch",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '17,2a' },
arch="arm64",
),
linux_pipeline(
"Linux 20.04 GCC 9* S390x",
"cppalliance/droneubuntu2004:multiarch",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '17,2a' },
arch="s390x",
),
linux_pipeline(
"Linux 20.04 GCC 10 32/64",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-10', CXXSTD: '17,20', ADDRMD: '32,64' },
"g++-10-multilib",
),
linux_pipeline(
"Linux 22.04 GCC 11* 32/64",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '17,2a', ADDRMD: '32,64' },
),
linux_pipeline(
"Linux 22.04 GCC 12 32/64 C++11-14",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '17,20', ADDRMD: '32,64' },
"g++-12-multilib",
),
linux_pipeline(
"Linux 22.04 GCC 12 32/64 C++17-20",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '2b', ADDRMD: '32,64' },
"g++-12-multilib",
),
linux_pipeline(
"Linux 24.04 GCC 13 32/64 UBSAN C++17-20",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '17,20', ADDRMD: '32,64' } + ubsan,
"g++-13-multilib",
),
linux_pipeline(
"Linux 24.04 GCC 13 32/64 UBSAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '2b', ADDRMD: '32,64' } + ubsan,
"g++-13-multilib",
),
linux_pipeline(
"Linux 24.04 GCC 13 32 ASAN C++17-20",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '17,20', ADDRMD: '32' } + asan,
"g++-13-multilib",
),
linux_pipeline(
"Linux 24.04 GCC 13 32 ASAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '2b', ADDRMD: '32' } + asan,
"g++-13-multilib",
),
linux_pipeline(
"Linux 24.04 GCC 14 UBSAN C++17",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '17' } + ubsan,
"g++-14-multilib",
),
linux_pipeline(
"Linux 24.04 GCC 14 UBSAN C++20",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '20' } + ubsan,
"g++-14-multilib",
),
linux_pipeline(
"Linux 24.04 GCC 14 UBSAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '2b' } + ubsan,
"g++-14-multilib",
),
linux_pipeline(
"Linux 24.04 GCC 14 ASAN C++17",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '17' } + asan,
"g++-14-multilib",
),
linux_pipeline(
"Linux 24.04 GCC 14 ASAN C++20",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '20' } + asan,
"g++-14-multilib",
),
linux_pipeline(
"Linux 24.04 GCC 14 ASAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-14', CXXSTD: '2b' } + asan,
"g++-14-multilib",
),
linux_pipeline(
"Linux 20.04 Clang 7",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-7', CXXSTD: '17' },
"clang-7",
),
linux_pipeline(
"Linux 20.04 Clang 8",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-8', CXXSTD: '17' },
"clang-8",
),
linux_pipeline(
"Linux 20.04 Clang 9",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-9', CXXSTD: '17,2a' },
"clang-9",
),
linux_pipeline(
"Linux 20.04 Clang 10",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-10', CXXSTD: '17,2a' },
"clang-10",
),
linux_pipeline(
"Linux 20.04 Clang 11",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-11', CXXSTD: '17,2a' },
"clang-11",
),
linux_pipeline(
"Linux 20.04 Clang 12",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-12', CXXSTD: '17,2a' },
"clang-12",
),
linux_pipeline(
"Linux 22.04 Clang 13",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-13', CXXSTD: '17,20' },
"clang-13",
),
linux_pipeline(
"Linux 22.04 Clang 14",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '17,20,2b' },
"clang-14",
),
linux_pipeline(
"Linux 22.04 Clang 15",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-15', CXXSTD: '17,20,2b' },
"clang-15",
),
linux_pipeline(
"Linux 24.04 Clang 16",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-16', CXXSTD: '17,20,2b' },
"clang-16",
),
linux_pipeline(
"Linux 24.04 Clang 17 UBSAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-17', CXXSTD: '17,20,2b' } + ubsan,
"clang-17",
),
linux_pipeline(
"Linux 24.04 Clang 17 ASAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-17', CXXSTD: '17,20,2b' } + asan,
"clang-17",
),
linux_pipeline(
"Linux 24.04 Clang 18 UBSAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-18', CXXSTD: '17,20,2b' } + ubsan,
"clang-18",
),
linux_pipeline(
"Linux 24.04 Clang 18 ASAN",
"cppalliance/droneubuntu2404:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-18', CXXSTD: '17,20,2b' } + asan,
"clang-18",
),
macos_pipeline(
"MacOS 10.15 Xcode 12.2 UBSAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '17,2a' } + ubsan,
),
macos_pipeline(
"MacOS 10.15 Xcode 12.2 ASAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '17,2a' } + asan,
),
macos_pipeline(
"MacOS 12.4 Xcode 13.4.1 UBSAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '17,20,2b', LINK: 'static' } + 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: '17,20,2b' } + asan,
xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64",
),
windows_pipeline(
"Windows VS2019 msvc-14.2",
"cppalliance/dronevs2019",
{ TOOLSET: 'msvc-14.2', CXXSTD: '17,20,latest', ADDRMD: '32,64' },
),
windows_pipeline(
"Windows VS2022 msvc-14.3",
"cppalliance/dronevs2022:1",
{ TOOLSET: 'msvc-14.3', CXXSTD: '17,20,latest', ADDRMD: '32,64' },
),
]

24
.drone/drone.bat Normal file
View File

@@ -0,0 +1,24 @@
@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
mkdir -p libs\%LIBRARY% & REM remove when/if the library makes it into Boost
xcopy /s /e /q %DRONE_BUILD_DIR% libs\%LIBRARY%\
python tools/boostdep/depinst/depinst.py -I examples %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

26
.drone/drone.sh Executable file
View File

@@ -0,0 +1,26 @@
#!/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
mkdir -p libs/$LIBRARY # remove when/if the library makes it into Boost
git submodule update --init tools/boostdep
cp -r $DRONE_BUILD_DIR/* libs/$LIBRARY
python tools/boostdep/depinst/depinst.py -I examples $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} ${LINK:+link=$LINK}

127
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,127 @@
#
# Copyright 2020-2021 Peter Dimov
# Copyright 2021 Andrey Semashev
# Copyright 2021-2024 Alexander Grund
# Copyright 2022-2025 James E. King III
#
# 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)
#
# This workflow uses the Boost.CI reusable workflow which builds a variety of
# configurations of your project, runs tests, and generates code coverage reports.
#
# To use it, copy this file into your repository as `.github/workflows/ci.yml` and
# customize it appropriately.
#
---
name: Boost.CI
permissions:
id-token: write
pages: write
on:
pull_request:
push:
branches:
- master
- develop
- bugfix/**
- feature/**
- fix/**
- github/**
- pr/**
paths-ignore:
- LICENSE
- meta/**
# - README.md
jobs:
call-boost-ci:
name: Run Boost.CI
uses: boostorg/boost-ci/.github/workflows/reusable.yml@master
with:
exclude_cxxstd: '98,03,0x,11,14'
exclude_compiler: gcc-4.9,gcc-5,gcc-6,gcc-7,clang-3.9,clang-4.0,clang-5.0,clang-6.0,clang-7,clang-16
# exclude clang-16 because it seems to use the c++14 standard library on ubuntu-24.04:
# include/c++/14/bits/stl_pair.h:410:35: error: no matching function for call to 'get'
# maybe similar to this: https://github.com/actions/runner-images/issues/9679
secrets:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
COVERITY_SCAN_NOTIFICATION_EMAIL: ${{ secrets.COVERITY_SCAN_NOTIFICATION_EMAIL }}
COVERITY_SCAN_TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }}
antora:
name: Antora docs
strategy:
matrix:
include:
- { name: Windows, os: windows-latest }
- { name: Ubuntu, os: ubuntu-latest }
- { name: macOS, os: macos-15 }
runs-on: ${{ matrix.os }}
defaults:
run:
shell: bash
steps:
- name: Install packages
uses: alandefreitas/cpp-actions/package-install@v1.8.8
with:
apt-get: git cmake
- name: Clone Boost.OpenMethod
uses: actions/checkout@v4
- name: Clone Boost
uses: alandefreitas/cpp-actions/boost-clone@v1.8.8
id: boost-clone
with:
branch: ${{ (github.ref_name == 'master' && github.ref_name) || 'develop' }}
boost-dir: ../boost-source
scan-modules-dir: .
scan-modules-ignore: openmethod
- uses: actions/setup-node@v4
with:
node-version: 18
- name: Setup Ninja
if: runner.os == 'Windows'
uses: seanmiddleditch/gha-setup-ninja@v5
- name: Build Antora docs
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git config --global --add safe.directory "$(pwd)"
cd ..
BOOST_SRC_DIR="$(pwd)/boost-source"
export BOOST_SRC_DIR
cd openmethod
cd doc
bash ./build_antora.sh
# Antora returns zero even if it fails, so we check if the site directory exists.
if [ ! -d "html" ]
then
echo "Antora build failed"
exit 1
fi
- name: Create Antora docs artifact
uses: actions/upload-artifact@v4
with:
name: antora-docs-${{ matrix.name }}
path: doc/html
- name: Upload static files as artifact
if: matrix.os == 'ubuntu-latest'
uses: actions/upload-pages-artifact@v3
with:
path: doc/html
- name: Deploy to GitHub Pages (jll63)
if: matrix.os == 'ubuntu-latest' && github.repository_owner == 'jll63' && github.ref_name == 'feature/doc'
uses: actions/deploy-pages@v4

View File

@@ -1,123 +0,0 @@
# Copyright (c) 2018-2025 Jean-Louis Leroy
# 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)
# CI is quite simple at the moment. It will be improved and made more
# comprehensive, probably similar to Boost.Unordered.
name: CI
env:
BUILD_TYPE: Debug Release
permissions:
contents: 'read'
pages: 'write'
id-token: 'write'
on: [push, pull_request, workflow_dispatch]
jobs:
Ubuntu:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
config: [Debug, Release]
compiler: [clang++, g++]
steps:
- uses: actions/checkout@v4
- name: Install clang++
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh $1
if: matrix.compiler == 'clang++'
- name: Install Boost
run: sudo apt-get install -y libboost-all-dev
- name: Configure
run: cmake -DCMAKE_BUILD_TYPE=${{ matrix.config }} -DCMAKE_CXX_COMPILER=${{ matrix.compiler }} -DBUILD_TESTING=1 -DBUILD_EXAMPLES=1 -Bbuild
- name: Build
run: cmake --build build
- name: Test
run: |
ctest --test-dir build --rerun-failed --output-on-failure
Windows:
runs-on: windows-latest
strategy:
fail-fast: false
matrix:
config: [Debug, Release]
steps:
- uses: actions/checkout@v3
- uses: ilammy/msvc-dev-cmd@v1
- name: Install boost
uses: MarkusJx/install-boost@v2
id: install-boost
with:
boost_version: 1.87.0
- name: Configure
run: |
cmake -DCMAKE_BUILD_TYPE=${{ matrix.config }} -DBUILD_TESTING=1 -DBUILD_EXAMPLES=1 -Bbuild -DBoost_DIR=${{ steps.install-boost.outputs.BOOST_ROOT }} -DBoost_INCLUDE_DIR=${{steps.install-boost.outputs.BOOST_ROOT}}\include -DBoost_LIBRARY_DIRS=${{steps.install-boost.outputs.BOOST_ROOT}}\lib
env:
BOOST_ROOT: ${{ steps.install-boost.outputs.BOOST_ROOT }}
- name: Build
run: cmake --build build --config ${{ matrix.config }}
- name: Test
run: |
ctest --test-dir build --rerun-failed --output-on-failure -C ${{ matrix.config }}
MacOS:
runs-on: macos-latest
strategy:
fail-fast: false
matrix:
config: [Debug, Release]
steps:
- uses: actions/checkout@v3
- uses: ilammy/msvc-dev-cmd@v1
- name: Install boost
run: brew install boost
- name: Configure
run: |
cmake -DCMAKE_BUILD_TYPE=${{ matrix.config }} -DBUILD_TESTING=1 -DBUILD_EXAMPLES=1 -Bbuild
- name: Build
run: |
cmake --build build
- name: Test
run: |
ctest --test-dir build --rerun-failed --output-on-failure
Artifacts:
if: github.ref_name == 'master'
runs-on: ubuntu-latest
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- uses: actions/checkout@v4
- name: Install asciidoctor
run: |
sudo apt-get install asciidoctor
asciidoctor doc/openmethod.adoc -o build_outputs_folder/index.html
- name: Generate documentation
run: |
sudo apt-get install asciidoctor
asciidoctor doc/openmethod.adoc -o build_outputs_folder/index.html
- name: Build flat headers
run: |
mkdir -p build_outputs_folder/boost/openmethod
python3 dev/flatten.py \
build_outputs_folder/boost/openmethod.hpp \
include/boost/openmethod.hpp \
include/boost/openmethod/unique_ptr.hpp \
include/boost/openmethod/shared_ptr.hpp \
include/boost/openmethod/compiler.hpp
python3 dev/flatten.py \
build_outputs_folder/boost/openmethod/policies.hpp \
include/boost/openmethod/policies.hpp
- name: Upload static files as artifact
uses: actions/upload-pages-artifact@v3
with:
path: build_outputs_folder/
- name: Deploy to GitHub Pages
uses: actions/deploy-pages@v4

View File

@@ -1,15 +0,0 @@
name: Probe Workflow
on:
workflow_dispatch:
jobs:
probe:
runs-on: ubuntu-latest
steps:
- name: List available compilers
run: |
lsb_release -a
apt list --installed | grep clang
apt list --installed | grep g++

2
.gitignore vendored
View File

@@ -4,6 +4,7 @@ build/
builds/
**/#*#
dependencies/*
Dependencies/*
extern/*
tests/benchmarks_parameters.hpp
**/vcpkg_installed
@@ -26,3 +27,4 @@ fetch_and_include/
tmpinst/
CMakeFiles/
build/

View File

@@ -1,49 +1,194 @@
# Copyright (c) 2018-2025 Jean-Louis Leroy
# 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)
#
# Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
# Copyright (c) 2021 DMitry Arkhipov (grisumbras@gmail.com)
# Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com)
#
# 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)
#
# Official repository: https://github.com/boostorg/openmethod
#
cmake_minimum_required(VERSION 3.10)
#-------------------------------------------------
#
# Project
#
#-------------------------------------------------
if(POLICY CMP0167)
cmake_policy(SET CMP0074 NEW)
cmake_minimum_required(VERSION 3.8...3.20)
set(BOOST_OPENMETHOD_VERSION 1)
if (BOOST_SUPERPROJECT_VERSION)
set(BOOST_OPENMETHOD_VERSION ${BOOST_SUPERPROJECT_VERSION})
endif ()
project(boost_openmethod VERSION "${BOOST_OPENMETHOD_VERSION}" LANGUAGES CXX)
set(BOOST_OPENMETHOD_IS_ROOT OFF)
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
set(BOOST_OPENMETHOD_IS_ROOT ON)
endif ()
set(__ignore__ ${CMAKE_C_COMPILER})
#-------------------------------------------------
#
# Options
#
#-------------------------------------------------
option(BOOST_OPENMETHOD_BUILD_TESTS "Build boost::openmethod tests even if BUILD_TESTING is OFF" OFF)
option(BOOST_OPENMETHOD_BUILD_EXAMPLES "Build boost::openmethod examples" ${BOOST_OPENMETHOD_IS_ROOT})
option(BOOST_OPENMETHOD_MRDOCS_BUILD "Build the target for MrDocs: see mrdocs.yml" OFF)
option(BOOST_OPENMETHOD_WARNINGS_AS_ERRORS "Treat warnings as errors" OFF)
# Check if environment variable BOOST_SRC_DIR is set
if (NOT DEFINED BOOST_SRC_DIR AND DEFINED ENV{BOOST_SRC_DIR})
set(DEFAULT_BOOST_SRC_DIR "$ENV{BOOST_SRC_DIR}")
else ()
set(DEFAULT_BOOST_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../..")
endif ()
set(BOOST_SRC_DIR ${DEFAULT_BOOST_SRC_DIR} CACHE STRING "Boost source dir to use when running CMake from this directory")
#-------------------------------------------------
#
# Boost modules
#
#-------------------------------------------------
# The boost super-project requires one explicit dependency per-line.
set(
BOOST_OPENMETHOD_DEPENDENCIES
Boost::assert
Boost::config
Boost::core
Boost::dynamic_bitset
Boost::mp11
Boost::preprocessor
)
foreach (BOOST_OPENMETHOD_DEPENDENCY ${BOOST_OPENMETHOD_DEPENDENCIES})
if (BOOST_OPENMETHOD_DEPENDENCY MATCHES "^[ ]*Boost::([A-Za-z0-9_]+)[ ]*$")
list(APPEND BOOST_OPENMETHOD_INCLUDE_LIBRARIES ${CMAKE_MATCH_1})
endif ()
endforeach ()
# Conditional dependencies
if (NOT BOOST_OPENMETHOD_MRDOCS_BUILD)
if (BUILD_TESTING OR BOOST_OPENMETHOD_BUILD_TESTS)
set(BOOST_OPENMETHOD_UNIT_TEST_LIBRARIES test)
endif()
if (BOOST_OPENMETHOD_BUILD_EXAMPLES)
set(BOOST_OPENMETHOD_EXAMPLE_LIBRARIES dll)
endif()
endif()
# Complete dependency list
set(BOOST_INCLUDE_LIBRARIES ${BOOST_OPENMETHOD_INCLUDE_LIBRARIES} ${BOOST_OPENMETHOD_UNIT_TEST_LIBRARIES} ${BOOST_OPENMETHOD_EXAMPLE_LIBRARIES})
set(BOOST_EXCLUDE_LIBRARIES openmethod)
if(POLICY CMP0167)
cmake_policy(SET CMP0167 NEW)
endif()
#-------------------------------------------------
#
# Add Boost Subdirectory
#
#-------------------------------------------------
if (BOOST_OPENMETHOD_IS_ROOT)
set(CMAKE_FOLDER Dependencies)
# Find absolute BOOST_SRC_DIR
if (NOT IS_ABSOLUTE ${BOOST_SRC_DIR})
set(BOOST_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${BOOST_SRC_DIR}")
endif ()
project(boost_openmethod VERSION 1.87.0 LANGUAGES CXX)
# Validate BOOST_SRC_DIR
set(BOOST_SRC_DIR_IS_VALID ON)
foreach (F "CMakeLists.txt" "Jamroot" "boost-build.jam" "bootstrap.sh" "libs")
if (NOT EXISTS "${BOOST_SRC_DIR}/${F}")
message(STATUS "${BOOST_SRC_DIR}/${F} does not exist. Fallback to find_package.")
set(BOOST_SRC_DIR_IS_VALID OFF)
break()
endif ()
endforeach ()
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
endif()
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# Create Boost interface targets
if (BOOST_SRC_DIR_IS_VALID)
# From BOOST_SRC_DIR
if (BUILD_SHARED_LIBS)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
endif()
set(BOOST_EXCLUDE_LIBRARIES ${PROJECT_NAME})
set(PREV_BUILD_TESTING ${BUILD_TESTING})
set(BUILD_TESTING OFF CACHE BOOL "Build the tests." FORCE)
add_subdirectory(${BOOST_SRC_DIR} Dependencies/boost EXCLUDE_FROM_ALL)
set(BUILD_TESTING ${PREV_BUILD_TESTING} CACHE BOOL "Build the tests." FORCE)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${BOOST_SRC_DIR}/tools/cmake/include")
else ()
# From Boost Package
find_package(Boost REQUIRED COMPONENTS container)
foreach (BOOST_INCLUDE_LIBRARY ${BOOST_INCLUDE_LIBRARIES})
if (NOT TARGET Boost::${BOOST_INCLUDE_LIBRARY})
add_library(Boost::${BOOST_INCLUDE_LIBRARY} ALIAS Boost::headers)
endif ()
endforeach ()
endif ()
unset(CMAKE_FOLDER)
endif ()
#-------------------------------------------------
#
# Library
#
#-------------------------------------------------
file(GLOB_RECURSE BOOST_OPENMETHOD_HEADERS CONFIGURE_DEPENDS include/boost/*.hpp)
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/include/boost PREFIX "" FILES ${BOOST_OPENMETHOD_HEADERS})
function(boost_openmethod_setup_properties target)
target_link_libraries(${target} INTERFACE ${BOOST_OPENMETHOD_DEPENDENCIES})
endfunction()
add_library(boost_openmethod INTERFACE)
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.19)
target_sources(boost_openmethod PRIVATE ${BOOST_OPENMETHOD_HEADERS})
endif()
add_library(Boost::openmethod ALIAS boost_openmethod)
target_include_directories(boost_openmethod INTERFACE "${PROJECT_SOURCE_DIR}/include")
boost_openmethod_setup_properties(boost_openmethod)
target_compile_features(boost_openmethod INTERFACE cxx_std_17)
target_include_directories(boost_openmethod INTERFACE include)
find_package(Boost COMPONENTS)
target_link_libraries(boost_openmethod INTERFACE Boost::boost)
if(MSVC)
add_compile_options(/EHsc /FAs)
if (BOOST_OPENMETHOD_MRDOCS_BUILD)
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/mrdocs.cpp" "#include <boost/openmethod.hpp>\n")
foreach (HEADER ${BOOST_OPENMETHOD_HEADERS})
string(REPLACE "${PROJECT_SOURCE_DIR}/include/" "" HEADER "${HEADER}")
file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/mrdocs.cpp" "#include <${HEADER}>\n")
endforeach()
add_library(boost_openmethod_mrdocs "${CMAKE_CURRENT_BINARY_DIR}/mrdocs.cpp")
target_include_directories(boost_openmethod_mrdocs PUBLIC "${PROJECT_SOURCE_DIR}/include")
boost_openmethod_setup_properties(boost_openmethod_mrdocs)
target_link_libraries(boost_openmethod_mrdocs PUBLIC Boost::openmethod)
target_compile_definitions(boost_openmethod_mrdocs PUBLIC BOOST_OPENMETHOD_MRDOCS)
return()
endif()
if(GCC)
add_compile_options(-fPIC -fvisibility=hidden -Wno-deprecated-declarations -Wall -Wextra)
endif()
#-------------------------------------------------
#
# Tests
#
#-------------------------------------------------
if (BUILD_TESTING OR BOOST_OPENMETHOD_BUILD_TESTS)
enable_testing()
add_subdirectory(test)
if (BOOST_OPENMETHOD_IS_ROOT)
add_custom_target(all_with_tests ALL DEPENDS tests)
endif()
endif ()
if(BUILD_TESTING)
message(STATUS "Building tests")
include(CTest)
enable_testing()
add_subdirectory(test)
endif()
if(BUILD_EXAMPLES)
message(STATUS "Building examples")
add_subdirectory(examples)
endif()
#-------------------------------------------------
#
# Examples
#
#-------------------------------------------------
if (BOOST_OPENMETHOD_BUILD_EXAMPLES)
enable_testing()
add_subdirectory(doc/modules/ROOT/examples)
endif ()

View File

@@ -1,16 +1,31 @@
# Boost.OpenMethod
### License
THIS IS NOT A BOOST LIBRARY (yet).
Distributed under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt).
The content of this repository is derived from YOMM2. It has been adapted to
Boost naming conventions for the purpose of being reviewed for inclusion in the
Boost C++ libraries.
### Properties
The documentation is [here](https://jll63.github.io/Boost.OpenMethod/).
* C++17
* Header-Only
You can experiment with the library on Compiler Explorer by including
`<https://jll63.github.io/Boost.OpenMethod/boost/openmethod.hpp>`. It also
includes the headers for the compiler, `shared_ptr` and `unique_ptr`. For
example, here is the last iteration of the [AST
example](https://godbolt.org/z/cPjzfanc8) from the tutorial. Don't forget to
turn on optimizations (`-O2 -DNDEBUG`) and to select the Boost library.
### Build Status
Branch | GH Actions | Coverity Scan | codecov.io | Deps | Docs | Tests |
:-------------: | ---------- | -------------- | ---------- | ---- | ---- | ----- |
[`master`](https://github.com/jll63/openmethod/tree/master) | [![CI](https://github.com/jll63/openmethod/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/jll63/openmethod/actions/workflows/ci.yml) | [![Coverity Scan Build Status](https://scan.coverity.com/projects/32486/badge.svg)](https://scan.coverity.com/projects/boostorg-openmethod) | [![codecov](https://codecov.io/gh/jll63/openmethod/branch/master/graph/badge.svg)](https://codecov.io/gh/jll63/openmethod/branch/master) | [![Deps](https://img.shields.io/badge/deps-master-brightgreen.svg)](https://pdimov.github.io/boostdep-report/master/openmethod.html) | [![Documentation](https://img.shields.io/badge/docs-master-brightgreen.svg)](https://www.boost.org/doc/libs/master/libs/openmethod/doc/html/openmethod.html) | [![Enter the Matrix](https://img.shields.io/badge/matrix-master-brightgreen.svg)](http://www.boost.org/development/tests/master/developer/openmethod.html)
[`develop`](https://github.com/jll63/openmethod/tree/develop) | [![CI](https://github.com/jll63/openmethod/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/jll63/openmethod/actions/workflows/ci.yml) | [![Coverity Scan Build Status](https://scan.coverity.com/projects/32486/badge.svg)](https://scan.coverity.com/projects/boostorg-openmethod) | [![codecov](https://codecov.io/gh/jll63/openmethod/branch/develop/graph/badge.svg)](https://codecov.io/gh/jll63/openmethod/branch/develop) | [![Deps](https://img.shields.io/badge/deps-develop-brightgreen.svg)](https://pdimov.github.io/boostdep-report/develop/openmethod.html) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](https://www.boost.org/doc/libs/develop/libs/openmethod/doc/html/openmethod.html) | [![Enter the Matrix](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](http://www.boost.org/development/tests/develop/developer/openmethod.html)
### Directories
| Name | Purpose |
| ----------- | ------------------------------ |
| `doc` | documentation |
| `example` | examples |
| `include` | headers |
| `test` | unit tests |
### More information
* [Ask questions](http://stackoverflow.com/questions/ask?tags=c%2B%2B,boost,boost-openmethod)
* [Report bugs](https://github.com/jll63/openmethod/issues): Be sure to mention Boost version, platform and compiler you're using. A small compilable code sample to reproduce the problem is always good as well.
* Submit your patches as pull requests against **develop** branch. Note that by submitting patches you agree to license your modifications under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt).
* Discussions about the library are held on the [Boost developers mailing list](http://www.boost.org/community/groups.html#main). Be sure to read the [discussion policy](http://www.boost.org/community/policy.html) before posting and add the `[openmethod]` tag at the beginning of the subject line.

View File

@@ -13,14 +13,14 @@ constant boost_dependencies
/boost/preprocessor//boost_preprocessor
;
project /boost/open_method ;
project /boost/openmethod ;
alias boost_open_method
alias boost_openmethod
: usage-requirements
<include>include
<library>$(boost_dependencies)
;
alias all : boost_open_method test ;
alias all : boost_openmethod test ;
explicit all ;
call-if : boost-library open_method ;
call-if : boost-library openmethod ;

View File

@@ -1,7 +1,7 @@
#include <iostream>
#include <vector>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
#include <boost/openmethod/initialize.hpp>
struct Animal {
const char* name;

View File

@@ -1,7 +1,7 @@
#include <iostream>
#include <vector>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
#include <boost/openmethod/initialize.hpp>
struct Animal {
const char* name;

View File

@@ -1,7 +1,7 @@
#include <iostream>
#include <vector>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
#include <boost/openmethod/initialize.hpp>
struct Animal {
const char* name;

View File

@@ -2,7 +2,7 @@
#include <vector>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
#include <boost/openmethod/initialize.hpp>
struct Animal {
const char* name;

View File

@@ -1,7 +1,7 @@
#include <iostream>
#include <vector>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
#include <boost/openmethod/initialize.hpp>
struct Animal {
const char* name;

View File

@@ -1,7 +1,7 @@
#include <iostream>
#include <vector>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
#include <boost/openmethod/initialize.hpp>
struct Animal {
const char* name;

View File

@@ -5,19 +5,20 @@ from pathlib import Path
import re
parser = argparse.ArgumentParser()
parser.add_argument('output', type=Path)
parser.add_argument('input', nargs="+", type=Path)
parser.add_argument("output", type=Path)
parser.add_argument("input", nargs="+", type=Path)
args = parser.parse_args()
prefix = args.input[0].absolute()
while prefix.name != 'boost':
while prefix.name != "boost":
assert prefix.parent != prefix
prefix = prefix.parent
prefix = prefix.parent
skip = len(str(prefix)) + 1
def flatten(input, output, done):
header = str(input)[skip:]
if header in done:
@@ -25,16 +26,22 @@ def flatten(input, output, done):
done.add(header)
with input.open() as ifh:
for line in ifh:
if input.name != "openmethod.hpp" and re.match(
r"#include <(boost/openmethod/core\.hpp+)>", line
):
continue
if m := re.match(r"#include <(boost/openmethod/[^>]+)>", line):
include = m[1]
print(file=output)
flatten(prefix / include, output, done)
print(file=output)
else:
output.write(line)
continue
output.write(line)
with args.output.open('w') as ofh:
with args.output.open("w") as ofh:
done = set()
for input in args.input:
flatten(input.absolute(), ofh, done)

11
dev/flatten.sh Executable file
View File

@@ -0,0 +1,11 @@
#!/bin/bash
mkdir -p build_outputs_folder/boost/openmethod
python3 dev/flatten.py build_outputs_folder/boost/openmethod.hpp \
include/boost/openmethod.hpp
for header in core compiler shared_ptr unique_ptr; do
python3 dev/flatten.py "build_outputs_folder/boost/openmethod/$header.hpp" \
"include/boost/openmethod/$header.hpp"
done

12
dev/local-flat.sh Executable file
View File

@@ -0,0 +1,12 @@
mkdir -p flat/boost/openmethod
python3 dev/flatten.py \
flat/boost/openmethod.hpp \
include/boost/openmethod.hpp \
include/boost/openmethod/interop/std_unique_ptr.hpp \
include/boost/openmethod/interop/std_shared_ptr.hpp \
include/boost/openmethod/initialize.hpp
python3 dev/flatten.py \
flat/boost/openmethod/registry.hpp \
include/boost/openmethod/registry.hpp \
include/boost/openmethod/policies/*.hpp \
include/boost/openmethod/default_registry.hpp

6
doc/.gitignore vendored Normal file
View File

@@ -0,0 +1,6 @@
temp
out.txt
qbk/reference.qbk
node_modules
build
reference-output

View File

@@ -1,43 +0,0 @@
[#BOOST_OPENMETHOD]
## BOOST_OPENMETHOD
### Synopsis
Defined in <boost/openmethod/macros.hpp>.
```c++
BOOST_OPENMETHOD(NAME, (PARAMETERS...), RETURN_TYPE [, POLICY]);
```
### Description
Declares a method.
The macro expands to several constructs:
* A `struct` forward declaration that acts as the method's identifier:
```c++
struct BOOST_OPENMETHOD_NAME(NAME);
```
* An inline function template, constrained to take the same `PARAMETERS`,
without the `virtual_` decorators, returning a `RETURN_TYPE`. The function
forwards to +
`method<BOOST_OPENMETHOD_NAME(NAME)(PARAMETERS...), RETURN_TYPE, POLICY>::fn`.
* A guide function used to match overriders with the method:
```c++
auto BOOST_OPENMETHOD_NAME(NAME)_guide(...)
-> ::boost::openmethod::method<
BOOST_OPENMETHOD_NAME(NAME)(PARAMETERS...), RETURN_TYPE [, POLICY]>;
```
NOTE: `NAME` must be an *identifier*. Qualified names are not allowed.
NOTE: The default value for `POLICY` is the value of
`BOOST_OPENMETHOD_DEFAULT_POLICY` at the point `<boost/openmethod/core.hpp>` is
included. Changing the value of this symbol has no effect after that point.

View File

@@ -1,23 +0,0 @@
[#BOOST_OPENMETHOD_CLASSES]
## BOOST_OPENMETHOD_CLASSES
### Synopsis
Defined in <boost/openmethod/macros.hpp>.
```c++
BOOST_OPENMETHOD_CLASSES(CLASSES...[, POLICY]);
```
### Description
Register `CLASSES` in POLICY.
NOTE: The default value for `POLICY` is the value of
`BOOST_OPENMETHOD_DEFAULT_POLICY` when `<boost/openmethod/core.hpp>` is
included. Subsequently changing it has no retroactive effect.
This macro is a wrapper around `use_classes`; see its documentation for more
details.

View File

@@ -1,52 +0,0 @@
## BOOST_OPENMETHOD_DECLARE_OVERRIDER
### Synopsis
Defined in <boost/openmethod/macros.hpp>.
```c++
#define BOOST_OPENMETHOD_DECLARE_OVERRIDER(NAME, (PARAMETERS...), RETURN_TYPE)
```
### Description
Declares an overrider for a method.
The method is deduced from a call to a method guide function with the
overrider's arguments.
The macro creates several entities in the current scope.
* A class template that acts as a container for the overriders of the methods
called `NAME`:
```c++
template<typename...> BOOST_OPENMETHOD_OVERRIDERS(NAME);
```
* A specialization of the container template for the overrider:
```c++
struct BOOST_OPENMETHOD_OVERRIDERS(NAME)<RETURN_TYPE(PARAMETERS...)> {
static auto fn(PARAMETERS...) -> RETURN_TYPE;
static auto has_next() -> bool;
template<typename... Args>
static auto next(typename... Args) -> RETURN_TYPE;
};
```
where:
* `fn` is the overrider function.
* `has_next()` returns `true` if a less specialized overrider exists.
* `next(Args... args)` calls the next most specialized overrider via the
pointer stored in the method's `next<fn>` member variable.
`BOOST_OPENMETHOD_DECLARE_OVERRIDER` can be called in a header file, with a
semicolon after the call. It can be called in a header file, but not multiple
times in the same translation unit.
NOTE: `NAME` must be an *identifier*. Qualified names are not allowed.

View File

@@ -1,22 +0,0 @@
[#BOOST_OPENMETHOD_DEFAULT_POLICY]
## BOOST_OPENMETHOD_DEFAULT_POLICY
### Description
The name of the default policy.
`BOOST_OPENMETHOD_DEFAULT_POLICY` is the default value for the `Policy` template
parameter of `method`, `use_classes`, and other constructs defined in
`<boost/openmethod/core.hpp>`. If it is not defined,
`::boost::openmethod::policy::default_policy` is used.
`BOOST_OPENMETHOD_DEFAULT_POLICY` can be defined by a program to change the
default policy globally. Once `<boost/openmethod/core.hpp>` has been included,
redefining the symbol has no effect. To override the default policy, proceed as
follows:
1. Include headers under `boost/openmethod/policies/` as needed.
2. Create a policy class, and set `BOOST_OPENMETHOD_DEFAULT_POLICY`.
3. Include `<boost/openmethod/core.hpp>`.

View File

@@ -1,18 +0,0 @@
## BOOST_OPENMETHOD_DEFINE_OVERRIDER
### Synopsis
Defined in <boost/openmethod/macros.hpp>.
```c++
#define BOOST_OPENMETHOD_DEFINE_OVERRIDER(NAME, (PARAMETERS...), RETURN_TYPE)
```
### Description
Defines the body of an overrider declared with
`BOOST_OPENMETHOD_DECLARE_OVERRIDER`. It should be called in an implementation
file, and followed by a function body.
NOTE: `NAME` must be an *identifier*. Qualified names are not allowed.

View File

@@ -1,14 +0,0 @@
## BOOST_OPENMETHOD_GUIDE
### Synopsis
Defined in <boost/openmethod/macros.hpp>.
```c++
#define BOOST_OPENMETHOD_GUIDE(NAME) /* unspecified */
```
### Description
Expands to the name of the guide function used to match overriders to methods.

View File

@@ -1,61 +0,0 @@
[#BOOST_OPENMETHOD_OVERRIDE]
## BOOST_OPENMETHOD_OVERRIDE
### Synopsis
Defined in <boost/openmethod/macros.hpp>.
```c++
BOOST_OPENMETHOD_OVERRIDE(NAME, (PARAMETERS...), RETURN_TYPE) {
// body
}
```
### Description
`BOOST_OPENMETHOD_OVERRIDE` adds an overrider to a method.
The method is deduced from a call to a method guide function with the
overrider's arguments.
The macro creates several entities in the current scope.
* A class template that acts as a container for the overriders of the methods
called `NAME`:
```c++
template<typename...> BOOST_OPENMETHOD_OVERRIDERS(NAME);
```
* A specialization of the container template for the overrider:
```c++
struct BOOST_OPENMETHOD_OVERRIDERS(NAME)<RETURN_TYPE(PARAMETERS...)> {
static auto fn(PARAMETERS...) -> RETURN_TYPE;
static auto has_next() -> bool;
template<typename... Args>
static auto next(typename... Args) -> RETURN_TYPE;
};
```
where:
* `fn` is the overrider function.
* `has_next()` returns `true` if a less specialized overrider exists.
* `next(Args... args)` calls the next most specialized overrider via the
pointer stored in the method's `next<fn>` member variable.
Finally, the macro starts the definition of the overrider function:
```c++
auto BOOST_OPENMETHOD_OVERRIDERS(NAME)<RETURN_TYPE(PARAMETERS...)>::fn(
PARAMETERS...) -> RETURN_TYPE
```
The block following the call to the macro is the body of the function.
NOTE: `NAME` must be an *identifier*. Qualified names are not allowed.

View File

@@ -1,16 +0,0 @@
[#BOOST_OPENMETHOD_REGISTER]
## BOOST_OPENMETHOD_REGISTER
### Synopsis
Defined in <boost/openmethod/macros.hpp>.
```c++
BOOST_OPENMETHOD_REGISTER(TYPE);
```
### Description
Creates a static instance of `TYPE`, using a unique generated name.

View File

@@ -1,19 +0,0 @@
# Copyright 2018-2024 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)
project doc/openmethod ;
using asciidoctor ;
html index.html : openmethod.adoc : <asciidoctor-attribute>stylesheet=zajo-dark.css <asciidoctor-attribute>linkcss ;
install html_ : index.html skin.png zajo-dark.css zajo-light.css rouge-github.css : <location>html ;
# pdf openmethod.pdf : openmethod.adoc : <asciidoctor-doctype>book <asciidoctor-attribute>pdf-themesdir=. <asciidoctor-attribute>pdf-theme=openmethod ;
# install pdf_ : openmethod.pdf : <location>html ;
alias boostdoc ;
explicit boostdoc ;
alias boostrelease : html_ ;
explicit boostrelease ;

57
doc/Jamfile.v2 Normal file
View File

@@ -0,0 +1,57 @@
import generate ;
import path ;
import property-set ;
import virtual-target ;
path-constant HERE : . ;
make html/index.html : build_antora.sh : @run-script ;
generate files-to-install : html/index.html : <generating-rule>@delayed-glob ;
install install
: files-to-install
: <location>html
<install-source-root>html/openmethod
;
explicit html/index.html files-to-install ;
# this runs the antora script
actions run-script
{
bash $(>)
}
# this globs after its sources are created
rule delayed-glob ( project name : property-set : sources * )
{
for local src in $(sources)
{
# the next line causes the source to be generated immediately
# and not later (which it normally would)
UPDATE_NOW [ $(src).actualize ] ;
}
# we need to construct the path to the globbed directory;
# this path would be <current-project>/antora
local root = [ path.root html [ $(project).location ] ] ;
local files ;
# actual globbing happens here
for local file in [ path.glob-tree $(root) : * ]
{
# we have to skip directories, because our match expression accepts anything
if [ CHECK_IF_FILE $(file) ]
{
# we construct a list of targets to copy
files += [ virtual-target.from-file $(file:D=) : $(file:D) : $(project) ] ;
}
}
# we prepend empty usage requirements to the result
return [ property-set.empty ] $(files) ;
}
###############################################################################
alias boostdoc ;
explicit boostdoc ;
alias boostrelease : install ;
explicit boostrelease ;

View File

@@ -14,5 +14,5 @@ struct abstract_policy {};
### Description
`abstract_policy` is a required base class for a policy. It makes it possible
for meta-functions such as `use_classes` to discriminate between user classes
for metafunctions such as `use_classes` to discriminate between user classes
and the (optional) policy class.

32
doc/antora.yml Normal file
View File

@@ -0,0 +1,32 @@
#
# Copyright (c) 2023 Alan de Freitas (alandefreitas@gmail.com)
#
# 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)
#
# Official repository: https://github.com/boostorg/openmethod
#
name: openmethod
version: ~
title: Boost.OpenMethod
start_page: index.adoc
asciidoc:
attributes:
source-language: asciidoc@
table-caption: false
nav:
- modules/ROOT/nav.adoc
ext:
cpp-reference:
config: doc/mrdocs.yml
cpp-tagfiles:
files:
- file: ./doc/tagfiles/boost-openmethod-doxygen.tag.xml
base_url: 'xref:reference:'
- file: ./doc/tagfiles/boost-openmethod-macros-doxygen.tag.xml
base_url: 'xref:reference:'
using-namespaces:
- boost::openmethod
- boost::openmethod::policies
- boost::openmethod::aliases

View File

@@ -3,8 +3,6 @@
### Synopsis
Defined in <boost/openmethod/policies/basic_policy.hpp>.
```c++
namespace boost::openmethod {
@@ -13,19 +11,16 @@ namespace policies {
template<class Policy, class... Facets>
struct basic_policy : abstract_policy, domain<Policy>, Facets... {
template<class Facet>
static constexpr bool has_facet = /*unspecified*/;
static constexpr bool has = /*unspecified*/;
template<class NewPolicy>
using fork = /*unspecified*/;
template<class... MoreFacets>
using add = /*unspecified*/;
template<class... Facets>
using with = /*unspecified*/;
template<class Base, class Facet>
using replace = /*unspecified*/;
template<class Base>
using remove = /*unspecified*/;
template<class... Facets>
using without = /*unspecified*/;
};
struct release : basic_policy<release, ...> {};
@@ -35,33 +30,36 @@ struct debug : release::add<...> {};
} // policies
#ifdef NDEBUG
using default_policy = policies::release;
using default_registry = policies::release;
#else
using default_policy = policies::debug;
using default_registry = policies::debug;
#endif
} // boost::openmethod
```
### Headers
Defined in <boost/openmethod/policies/basic_policy.hpp>. Also available via
`<boost/openmethod/core.hpp>` and `<boost/openmethod.hpp>`.
### Description
`basic_policy` implements a policy, which consists of a a collection of methods,
classes, dispatch data, and facets, which specify how to obtain a pointer to a
classes, dispatch data, and policys, which specify how to obtain a pointer to a
v-table from an object, how to report errors, whether to perform runtime sanity
checks, etc.
Some of these functionalities require static variables local to the policy.
Forthis reason, `basic_policy` uses the CRTP pattern to provide ensure that two
different policies - and the facets they contain - get their own copies of the
static state.
`basic_policy` has state. It uses the Curiously Recurring Template Pattern to
allow distinct policies to have distinct sets of static variables.
### Members
#### has_facet
#### has
```c++
template<class Facet>
static constexpr bool has_facet;
static constexpr bool has;
```
Evaluates to `true` if _Policy_ contains _Facet_.
@@ -73,46 +71,56 @@ template<class NewPolicy>
using fork;
```
Creates a new policy from an existing one. _NewPolicy_, and the facets it
contains, do not share static variables with the original _Policy_. The new
policy does not retain any knowledge of the classes and methods registered in
the original.
Creates a new policy from an existing one. _NewPolicy_ does not share static
variables with the original _Policy_. The new policy does not retain any
knowledge of the classes and methods registered in the original.
#### add
`fork` forks the policys in the policy as well: any policy instantiated from a
class template is assumed to take a policy as its first template argument. The
template is re-instantiated with the new policy as the first arguments, while
the other arguments remain the same.
#### with
```c++
template<class... MoreFacets>
using add;
template<class... Facets>
using with;
```
Creates a new policy by adding _MoreFacets_ to the original policy's collection
of facets. The original policy and the new one share static variables.
Requires:: _Facets_ is a list of classes that derive from `policy`.
#### replace
Returns:: A new policy containing _Facets_, and the policys from the original
that do not have the same category as _Facets_.
Examples::
* `struct dyn_load : default_registry::fork<dyn_load>::with<indirect_vptr> {};` +
Creates a policy just like `default_registry`, with an extra indirection added
to the v-table pointers. This policy is suitable for use with dynamic loading.
* `struct release_with_diags : release::fork<release_with_diags>::with<basic_error_output<release_with_diags>> {};` +
Creates a policy just like `release`, except that it prints a diagnostic
message before terminating with `abort()`.
* `struct default_throw : default_registry::fork<default_throw>::with<throw_error_handler> {};` +
Creates a policy just like `default_registry`, except that it reports errors by
throwing exceptions, instead of calling a `std::function` like the default
error handler does.
#### without
```c++
template<class Base, class NewFacet>
using replace;
template<class... Facets>
using without;
```
Creates a new policy by replacing the facet in _Policy_ that derives from _Base_
with _NewFacet_. It is not an error if _policy_ does not contain such a facet;
in that case, the new policy contains the same facet as the original one.
Requires:: _Facets_ is a list of policy categories.
The original policy and the new one share static variables.
Returns:: A new policy containing the policys from the original that do not have
the same category as _Facets_.
#### remove
```c++
template<class Base>
using remove;
```
Creates a new policy by removing the facet in _Policy_ that derives from _Base_.
It is not an error if _policy_ does not contain such a facet; in that case, the
new policy contains the same facet as the original one.
The original policy and the new one share static variables.
Examples::
* `struct use_map : default_registry::fork<use_map>::with<vptr_map<use_map>>::without<type_hash> {};` +
Creates a policy just like `default_registry`, except that it stores pointers to
v-table in a `std::unordered_map`. Also removes the hash function, since it
will not be used.
### Non-members
@@ -122,8 +130,8 @@ The original policy and the new one share static variables.
struct release;
```
A policy that contains facet implementations `std_rtti`, `fast_perfect_hash`,
`vptr_vector` and `vectored_error_handler`.
A policy that contains policys `std_rtti`, `fast_perfect_hash`, `vptr_vector` and
`default_error_handler`.
#### debug
@@ -131,12 +139,12 @@ A policy that contains facet implementations `std_rtti`, `fast_perfect_hash`,
struct debug;
```
The `release` policy with additional facet implementations `runtime_checks`,
The `release` policy with additional policy implementations `runtime_checks`,
`basic_error_output` and basic_trace_output.
NOTE: `debug` extends `release` but it does not a fork it. Both policies use the
same `domain`.
#### default_policy
#### default_registry
An alias for `release` if `NDEBUG` is defined, and for `debug` otherwise.

40
doc/build_antora.sh Executable file
View File

@@ -0,0 +1,40 @@
#!/bin/bash
#
# Copyright (c) 2023 Alan de Freitas (alandefreitas@gmail.com)
#
# 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)
#
# Official repository: https://github.com/boostorg/openmethod
#
set -e
if [ $# -eq 0 ]
then
echo "No playbook supplied, using default playbook"
PLAYBOOK="local-playbook.yml"
else
PLAYBOOK=$1
fi
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
cd "$SCRIPT_DIR"
echo "Building documentation with Antora..."
echo "Installing npm dependencies..."
npm ci
echo "Building docs in custom dir..."
PATH="$(pwd)/node_modules/.bin:${PATH}"
export PATH
npx antora --clean --fetch "$PLAYBOOK" --stacktrace --log-level all
echo "Fixing links to non-mrdocs URIs..."
for f in $(find html -name '*.html'); do
perl -i -pe 's{&lcub;&lcub;(.*?)&rcub;&rcub;}{<a href="../../../$1.html">$1</a>}g' "$f"
done
echo "Done"

View File

@@ -1,92 +0,0 @@
## Core API
OpenMethod provides a macro-free interface: the core API. This is useful in
certain situations, for example when combining open-methods and templates.
Let's rewrite the Animals example using the core API. An open-method is
implemented as an instance of the `method` template. Its parameters are a
function signature and a return type:
[source,c++]
----
#include <boost/openmethod/core.hpp>
using namespace boost::openmethod;
class poke_openmethod;
using poke = method<
poke_openmethod(std::ostream&, virtual_<Animal&>), void>;
----
The `poke_openmethod` class acts as the method's identifier: it separates it
from other methods with the same signature. The exact name does not really
matter, and the class needs not be defined, only declared. Inventing a class
name can get tedious, so OpenMethod provides a macro for that:
[source,c++]
----
include::{examplesdir}/core_api.cpp[tag=method]
----
NOTE: BOOST_OPENMETHOD and associated macros use `BOOST_OPENMETHOD_NAME` in
their implementation. This makes it possible to mix the "macro" and "core"
styles.
We call the method via the nested function object `fn`:
[source,c++]
----
poke::fn(std::cout, animal);
----
Overriders are ordinary functions, added to a method using the nested template
`override`:
[source,c++]
----
include::{examplesdir}/core_api.cpp[tag=poke_cat]
----
NOTE: `override` can register multiple overriders.
In C++26, we will be able to use `_` instead of inventing a one-time-use
identifier. In the meantime, OpenMethod provides a small convenience macro:
[source,c++]
----
include::{examplesdir}/core_api.cpp[tag=poke_dog]
----
`next` is available from the method's nested `next` template:
[source,c++]
----
include::{examplesdir}/core_api.cpp[tag=poke_bulldog]
----
NOTE: Since the function uses itself as a template argument in its body, its
return type cannot be deduced. It must be specified explicitly, either by using
the old function declaration style or a trailing return type.
Why not call `poke_dog` directly? We could; however, keep in mind that, in a
real program, a translation unit is not necessarily aware of the overriders
added elsewhere - especially in presence of dynamic loading.
We register the classes with `use_classes`:
[source,c++]
----
include::{examplesdir}/core_api.cpp[tag=use_classes]
----
Finally, we call the method via the static member of the method class `fn`:
[source,c++]
----
include::{examplesdir}/core_api.cpp[tag=main]
----

View File

@@ -1,170 +0,0 @@
## Custom RTTI
Stock policies use the `std_rtti` implementation of `rtti`. Here is its full
source:
[source,c++]
----
struct std_rtti : rtti {
template<class Class>
static constexpr auto is_polymorphic = std::is_polymorphic_v<Class>;
template<typename T>
static type_id static_type() {
return reinterpret_cast<type_id>(&typeid(T));
}
template<typename T>
static type_id dynamic_type(const T& obj) {
return reinterpret_cast<type_id>(&typeid(obj));
}
template<class Stream>
static void type_name(type_id type, Stream& stream) {
stream << reinterpret_cast<const std::type_info*>(type)->name();
}
static std::type_index type_index(type_id type) {
return std::type_index(*reinterpret_cast<const std::type_info*>(type));
}
template<typename D, typename B>
static D dynamic_cast_ref(B&& obj) {
return dynamic_cast<D>(obj);
}
};
----
* `is_polymorphic` is used to check if a class is polymorphic. This template is
required.
* `static_type` is used by class registration, by `virtual_ptr`{empty}'s "final"
constructs, and to format error and trace messages. `T` is not restricted to
the classes that appear as virtual parameters. This function is required.
* `dynamic_type` is used to locate the v-table for an object. This function is
usually required. If only the `virtual_ptr` "final" constructs are used, or
if `boost_openmethod_vptr` is provided for all the classes in the policy, it
can be omitted.
* `type_name` writes a representation of `type` to `stream`. It is used to format
error and trace messages. `Stream` is a lighweight version of `std::ostream`
with reduced functionality. It only supports insertion of `const char*`,
`std::string_view`, pointers and `std::size_t`. This function is optional;
if it is not provided, "type_id(_type_)" is used.
* `type_index` returns an object that _uniquely_ identifies a class. Some forms
of RTTI (most notably, C++'s `typeid` operator) do not guarantee that the
type information object for a class is unique within the same program. This
function is optional; if not provided, `type` is assumed to be unique, and
used as is.
* `dynamic_cast_ref` casts `obj` to class `D`. `B&&` is either a lvalue reference
(possibly cv-qualified) or a rvalue reference. `D` has the same reference
category (and cv-qualifier if applicable) as `B`. This function is required
only in presence of virtual inheritance.
Consider a custom RTTI implementation:
[source,c++]
----
struct Animal {
Animal(unsigned type) : type(type) {
}
virtual ~Animal() = default;
unsigned type;
static constexpr unsigned static_type = 1;
};
struct Cat : Animal {
Cat() : Animal(static_type) {
}
static constexpr unsigned static_type = 2;
};
// ditto for Dog
----
This scheme has an interesting property: its type ids are monotonically
allocated in a small, dense range. Thus, we don't need to hash them. We can use
them as indexes in the table of vptrs.
This time we are going to replace the default policy globally. First we need to
define the custom RTTI facet. We must _not_ include
`<boost/openmethod/core.hpp>` or any header that includes it yet.
Here is the facet implementation:
[source,c++]
----
include::{examplesdir}/custom_rtti.cpp[tag=facet]
----
This facet is quite minimal. It does not support virtual inheritance. It would
not produce good error or trace messages, because types would be represented by
their integer ids.
This time we create a policy from scratch. For that we use the `basic_policy`
CRTP template:
[source,c++]
----
include::{examplesdir}/custom_rtti.cpp[tag=policy]
----
Next, we include the main header. Because `BOOST_OPENMETHOD_DEFAULT_POLICY` is
defined, its value is used for the default policy. Then comes the usual example.
[source,c++]
----
include::{examplesdir}/custom_rtti.cpp[tag=example]
----
This programs works even if standard RTTI is disabled.
## Deferred RTTI
In the previous example, the RTTI system assigns types id statically. It is more
common to allocate them using a global counter, manipulated by static
constructors. This is a problem, because `static_type` is used by class
registration. It may read the custom type ids _before_ they are have been
initialized.
The solution is to add the `deferred_static_rtti` facet to the policy; it defers
reading the type information until `initialize` is called.
This time let's support virtual inheritance as well. First the domain classes:
[source,c++]
----
include::{examplesdir}/deferred_custom_rtti.cpp[tag=classes]
// ditto for Dog
----
The rtti facet is the same, with one more function:
[source,c++]
----
struct custom_rtti : bom::policies::rtti {
// as before
include::{examplesdir}/deferred_custom_rtti.cpp[tag=dynamic_cast_ref]
};
----
Finally, the policy contains an additional facet - `deferred_static_rtti`:
[source,c++]
----
struct custom_policy
: bom::policies::basic_policy<
custom_policy, custom_rtti,
bom::policies::deferred_static_rtti, // <-- additional facet
bom::policies::vptr_vector<custom_policy>> {};
----
The example is the same as in the previous section.

View File

@@ -1,15 +1,15 @@
## vectored_error_handler
## default_error_handler
### Synopsis
Defined in <boost/openmethod/policies/vectored_error_handler.hpp>.
Defined in <boost/openmethod/policies/default_error_handler.hpp>.
```c++
namespace boost::openmethod::policies {
template<class Policy>
class vectored_error_handler : public error_handler {
class default_error_handler : public error_handler {
public:
using error_variant = std::variant<
openmethod_error, not_implemented_error, unknown_class_error,
@@ -27,7 +27,7 @@ class vectored_error_handler : public error_handler {
### Description
`vectored_error_handler` is an implementation of `error_handler` that calls a
`default_error_handler` is an implementation of `error_handler` that calls a
`std::function` to handle the error.
### Members
@@ -40,7 +40,7 @@ static auto error(const Error& error) -> void;
```
Calls the function last set via `set_error_handler` or, if it was never called,
and if _Policy_ contains an `error_output` facet, use it to print a description
and if _Policy_ contains an `output` policy, use it to print a description
of `error`.
#### error

View File

@@ -15,11 +15,11 @@ struct deferred_static_rtti : rtti {};
### Description
`deferred_static_rtti` is a facet that defers collection of static type ids.
`deferred_static_rtti` is a policy that defers collection of static type ids.
Some custom RTTI systems rely on static constructors to assign type ids.
OpenMethod itself relies on static constructors to register classes, methods and
overriders, calling the `static_type` function from the `rtti` facet in the
overriders, calling the `static_type` function from the `rtti` policy in the
process. This can result in collecting the type ids _before_ they have been
initialized. Adding this facet to a policy moves the collection of type ids to
initialized. Adding this policy to a policy moves the collection of type ids to
`initialize`.

View File

@@ -1,73 +0,0 @@
## Dynamic Loading
OpenMethod supports dynamic loading on operating systems that are capable of
handling C++ templates correctly during dynamic link. A dynamic library can add
classes, methods and overriders to an existing policy. `initialize` must then be
called to rebuild the dispatch tables.
This leads to a problem: any `virtual_ptr` in existence before `initialize` is
called again becomes invalid. This also applies to vptrs that are stored inside
objects by `with_vptr`.
NOTE: This applies only to cases where a dynamic library adds to an _existing_
policy. Even if the dynamic library itself uses open-methods, for example as an
implementation detail, but it uses its own policy, there is no issue.
The solution is to use a policy that contains the `indirect_vptr` facet. Instead
of storing the vptr directly, it stores a reference to the vptr.
Here is an example:
[source,c++]
----
include::{examplesdir}/dl.hpp[tag=header]
----
NOTE: The policy must be passed to the method as well as the
`virtual_ptr`{empty}s.
The `indirect_vptr` facet tells `virtual_ptr` to use a _reference_ to the vptr,
instead of its value. Even tough the value of the vptr changes when `initialize`
is called, the vptrs are stored in the same place (the policy's
`static_vptr<Class>` variables).
We can now register the classes and and provide an overrider:
[source,c++]
----
include::{examplesdir}/dl_main.cpp[tag=main]
----
It is not necessary to pass the policy to `BOOST_OPENMETHOD_CLASSES`, because
`indirect_vptr` does not have any state. As for `BOOST_OPENMETHOD_OVERRIDE`, it
deduces the policy from the method.
At this point we only have one overrider. Animals of all species ignore one
another:
[source,c++]
----
include::{examplesdir}/dl_main.cpp[tag=before_dlopen]
----
Let's load a dynamic library containing this code:
[source,c++]
----
include::{examplesdir}/dl_shared.cpp[tag=dl_shared]
----
Now back to `main`:
[source,c++]
----
include::{examplesdir}/dl_main.cpp[tag=dlopen]
----
After unloading the library, we must call `initialize` again:
[source,c++]
----
include::{examplesdir}/dl_main.cpp[tag=after_dlclose]
----

View File

@@ -6,17 +6,14 @@
Defined in <boost/openmethod/policies/basic_policy.hpp>.
```c++
namespace boost::openmethod::policies {
namespace boost::openmethod {
namespace policies {
struct error_handler;
}
```
Defined in <boost/openmethod/types.hpp>.
```c++
namespace boost::openmethod {
struct openmethod_error {};
@@ -40,15 +37,15 @@ struct type_mismatch_error : openmethod_error {
type_id type;
};
} // boost::openmethod::policies
}
```
### Description
`error_handler` is a facet that handles errors.
`error_handler` is a policy that handles errors.
When an error is encountered, either during `initialize` or method dispatch, the
program is terminated via a call to `abort`. If this facet is present in the
program is terminated via a call to `abort`. If this policy is present in the
policy, its `error` function is called with an error object. It can prevent
termination by throwing an exception.

View File

@@ -1,55 +0,0 @@
## Error Handling
When an error is encountered, the program is terminated by a call to `abort`. If
the policy contains an `error_handler` facet, it provides an `error` member
function (or overloaded functions) to be called with an object identifying the
error. The `release` and `debug` policies implement the error facet with
`vectored_error_handler`, which wraps the error object in a variant, and calls a
handler via a `std::function`. By default, it prints a description of the error
to `stderr` in the `debug` policy, and does nothing in the `release` policy. The
handler can be set with `set_error_handler`:
[source,c++]
----
include::{examplesdir}/vectored_error_handler.cpp[tag=example]
----
Output:
[source,console]
----
spin
not implemented
spin
----
We can also replace the `error_handler` facet with our own. For example:
[source,c++]
----
include::{examplesdir}/throw_error_handler.cpp[tag=example]
----
[source,console]
----
spin
not implemented
spin
----
Stock facet `throw_error_handler` does this for all the exception types:
```c++
namespace boost::openmethod::policies {
struct throw_error_handler : error_handler {
template<class Error>
[[noreturn]] static auto error(const Error& error) -> void {
throw error;
}
};
} // namespace boost::openmethod::policies
```

View File

@@ -1,5 +1,5 @@
## error_output
## output
### Synopsis
@@ -8,21 +8,21 @@ Defined in <boost/openmethod/policies/basic_policy.hpp>.
```c++
namespace boost::openmethod::policies {
struct error_output : facet {};
struct output : policy {};
} // boost::openmethod::policies
```
### Description
`error_output` is a facet that provides a stream for writing error messages.
`output` is a policy that provides a stream for writing error messages.
### Requirements
#### error_stream
```c++
static RestrictedOutputStream error_stream;
static LightweightOutputStream error_stream;
```
A static variable that satisfies the requirements of `RestrictedOutputStream`.
A static variable that satisfies the requirements of `LightweightOutputStream`.

View File

@@ -1,31 +0,0 @@
## facet
### Synopsis
Defined in <boost/openmethod/policies/basic_policy.hpp>.
```c++
namespace boost::openmethod::policies {
struct facet {
static auto finalize() -> void;
};
} // boost::openmethod::policies
```
### Description
`facet` is the base class of all facets. It provides an empty `finalize` static
function which can be overriden (via shadowing) by derived classes.
### Members
#### finalize
```c++
static auto finalize() -> void;
```
Does nothing.

View File

@@ -1,31 +0,0 @@
## Friendship
We can use overrider containers to grant friendship to a specific overrider, or
to all the overriders of a method. The name of the container template is
returned by `BOOST_OPENMETHOD_OVERRIDERS`. The template argument for a
specialization is the signature of the overrider. For example, the overrider of
`poke` for `Cat` is:
[source,c++]
----
BOOST_OPENMETHOD_OVERRIDERS(poke)<
void(std::ostream& os, virtual_ptr<Cat> cat)>::fn;
----
We can thus grant friendship to all the overriders of `poke`:
[source,c++]
----
include::{examplesdir}/friendship.cpp[tag=friend_all]
----
Be aware, though, that the overriders of _any_ method called `poke` - with any
signature - are granted friendship.
We can also befriendto individual overriders:
[source,c++]
----
include::{examplesdir}/friendship.cpp[tag=friend]
----

3
doc/gentags.sh Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
mrdocs && cp reference-output/reference.tag.xml tagfiles/boost-openmethod-doxygen.tag.xml

View File

@@ -1,193 +0,0 @@
## Headers and Namespaces
Most real-life programs will be organized in multiple files and multiple
namespaces. OpenMethod interacts with headers and namespaces very naturally,
unless using-directives are avoided. In that case, there are a few things to be
aware of.
Let's break the Animals example into headers and namespaces. First we put
`Animal` in its own header and namespace:
[source,c++]
----
include::{examplesdir}/headers_namespaces/animal.hpp[]
----
`BOOST_OPENMETHOD` can be placed in a header file. It adds several constructs to
the current namespace:
* It declares (but does not define) a `struct` named after the method.
* It declares (but does not define) a _guide_ function. It is also named after
the method, and it has the same signature (with the `virtual_` decorators
stripped). It is used to match methods and overriders. It is never defined and
it is "called" only in a non-evaluated context.
* It defines an inline function with the same name and signature as the
method (with the `virtual_` decorators stripped).
Next, let's implement the `Cat` class, and a derived class, `Chhetah`, in the
`felines` namespace:
[source,c++]
----
include::{examplesdir}/headers_namespaces/cat.hpp[]
----
[source,c++]
----
include::{examplesdir}/headers_namespaces/cat.cpp[]
----
`BOOST_OPENMETHOD_CLASSES` should be placed in an implementation file. It can
also go in a header file, but this wastes space, as the same registrar will be
created in every translation unit that includes the header. It doesn't matter
which namespace the macro is called in. It can take be used with any class name
in scope, or with qualified names.
`BOOST_OPENMETHOD_OVERRIDE` uses the guide function declared by
`BOOST_OPENMETHOD` to locate a method that can be called with the same arguments
as the overrider itself. It "calls" the guide function in a non-evaluated
context, passing it a `std::ostream&` and a `virtual_ptr<Cat>`. The return type
of the guide function is the method to add the overrider to. Exactly one guide
function must match. The normal rules of overload resolution apply. In this
case, the guide function is found via argument dependant lookup (ADL).
The macro adds several constructs to the current namespace:
* It declares (but does not define) a `struct` template with one type parameter,
named after the method. The template acts like a container for overriders.
* It specializes the template for the signature of the overrider. Inside the
struct, it defines the `next` and `has_next` members, and a static function
called `fn`. The block following the macro is the body of the `fn` function.
It follows that `BOOST_OPENMETHOD_OVERRIDE` should be placed in an
implementation file. `BOOST_OPENMETHOD_INLINE_OVERRIDE` works like
`BOOST_OPENMETHOD_OVERRIDE`, but it defines the `fn` function as inline, so it
can be used in a header file.
The overrider for Cats can be accessed in the same translation unit, after it
has been defined, using the `BOOST_OPENMETHOD_OVERRIDER` macro. It expands to
the specialization of the overrider container for the overrider's signature. We
call the static `fn` function to call the overrider.
NOTE: The Cheetah overrider calls the specific overrider for `Cat`, for
illustration purpose. It is usually better to call `next` instead.
Let's implement the `Dog` class, in the `canines` namespace. This time we want
the overrider to be accessible in other translation units. We can declare an
overrider with `BOOST_OPENMETHOD_DECLARE_OVERRIDER`, without actually defining
the static function `fn` just yet.
[source,c++]
----
include::{examplesdir}/headers_namespaces/dog.hpp[]
----
Unlike function declarations, which can occur multiple times in a TU, an
overrider declaration cannot. For example, this is illegal:
```c++
BOOST_OPENMETHOD_DECLARE_OVERRIDER(
poke, (std::ostream&, virtual_ptr<Dog>), void);
BOOST_OPENMETHOD_DECLARE_OVERRIDER(
poke, (std::ostream&, virtual_ptr<Dog>), void);
```
Now we use `BOOST_OPENMETHOD_DEFINE_OVERRIDER` to define the overrider:
[source,c++]
----
include::{examplesdir}/headers_namespaces/dog.cpp[]
----
Let's look at the main program now. It derived `Bulldog` from `Dog` and provides
an overrider for the new class:
[source,c++]
----
include::{examplesdir}/headers_namespaces/main.cpp[]
----
Again ADL plays a role: it helps the overrider (and `main`) to locate the `poke`
method.
This example is the "happy scenario", where namespaces are used conservatively.
The `OVERRIDE` macros don't interact well with `using` directives. For example
this code:
```c++
using namespace animals;
using namespace canines;
using namespace felines;
struct Bulldog : Dog {
using Dog::Dog;
};
BOOST_OPENMETHOD_CLASSES(Dog, Bulldog);
BOOST_OPENMETHOD_OVERRIDE(
poke, (std::ostream & os, virtual_ptr<Bulldog> dog), void) {
next(os, dog);
os << " and bites back";
}
```
...will fail to compile, with an error like "reference to
'poke_boost_openmethod_overriders' is ambiguous". That is because the overrider
containers exist in both the canides and felides namespaces, with the same name.
Finally, the names passed as first arguments to the BOOST_OPENMETHOD and
BOOST_OPENMETHOD_OVERRIDE macros must be identifiers. Qualified names are not
allowed. Consider:
```c++
using animals::Animal;
namespace app_specific_behavior {
BOOST_OPENMETHOD(
meet, (std::ostream&, virtual_ptr<Animal>, virtual_ptr<Animal>), void);
} // namespace app_specific_behavior
BOOST_OPENMETHOD_OVERRIDE(
meet, (std::ostream& os, virtual_ptr<Animal>, virtual_ptr<Animal>), void) {
os << "ignore";
}
```
Here, the guide function cannot be found, even via ADL. We get an error like
"use of undeclared identifier 'meet_boost_openmethod_guide'". How do we solve
this? We might be tempted to use a qualified name:
`app_specific_behavior::meet`:
```c++
BOOST_OPENMETHOD_OVERRIDE(
app_specific_behavior::meet,
(std::ostream& os, virtual_ptr<Animal>, virtual_ptr<Animal>), void) {
os << "ignore";
}
```
But `BOOST_OPENMETHOD_OVERRIDE` also uses the name to derive the overrider
container's name, using preprocessor token pasting, resulting in an invalid
declaration error.
We need to do is to make `BOOST_OPENMETHOD_OVERRIDE` "see" the guide function.
Its name is returned by macro `BOOST_OPENMETHOD_GUIDE(NAME)`. We can use a
using-declaration to bring the guide function into the current scope:
```c++
using app_specific_behavior::BOOST_OPENMETHOD_GUIDE(meet);
BOOST_OPENMETHOD_OVERRIDE(
meet, (std::ostream& os, virtual_ptr<Animal>, virtual_ptr<Animal>), void) {
os << "ignore";
}
```

View File

@@ -1,103 +0,0 @@
## Hello World
Consider the following program, intended to demonstrate the basics of virtual
functions:
[source,c++]
----
include::{examplesdir}/virtual_func.cpp[tag=code]
----
We are going to rewrite this using open-methods.
First we remove the `poke` virtual functions from the domain classes:
[source,c++]
----
include::{examplesdir}/hello_world.cpp[tag=domain_classes]
----
Note that the Animal classes do not depend on iostreams anymore. This is a major
advantage of open-methods over virtual functions: they make it possible to
better organize dependencies.
Let's implement `poke`. First we need to include the library's main header. It
defines a few macros, and injects a name - `virtual_ptr` - in the global
namespace.
[source,c++]
----
include::{examplesdir}/hello_world.cpp[tag=method]
----
This defines a free function called `poke`, which takes two arguments. The first
is the `ostream`. The second argument corresponds to the implicit `this` pointer
in a virtual function. It is now an explicit argument. Just like with virtual
functions, the exact function to execute is selected on the basis of the
argument's _dynamic_ type.
Unlike virtual functions, there is no such thing as a pure open-method that
would make a class abstract. It is not possible to determine if an overrider is
available from looking at just the current translation unit.
Let's add overriders for `Cat` and `Dog`:
[source,c++]
----
include::{examplesdir}/hello_world.cpp[tag=overriders]
----
`Bulldog::poke` calls the `poke` it overrides in its `Dog` base. The equivalent
for open-methods is `next`, a function that is available only inside the body of
an overrider. It calls the next most specific overrider, i.e. what would have
been called if the overrider did not exist.
[source,c++]
----
include::{examplesdir}/hello_world.cpp[tag=next]
----
All classes involved in open-method calls need to be registered using the
`BOOST_OPENMETHOD_CLASSES` macro:
[source,c++]
----
include::{examplesdir}/hello_world.cpp[tag=classes]
----
Classes can be registered incrementally, as long as all the direct bases of a
class are listed with it in some call(s) to `BOOST_OPENMETHOD_CLASSES`. For
example, `Bulldog` can be added in a second call, as long as `Dog` is listed as
well:
[source,c++]
----
// in animals.cpp
BOOST_OPENMETHOD_CLASSES(Animal, Cat, Dog);
// in bulldog.cpp
BOOST_OPENMETHOD_CLASSES(Dog, Bulldog);
----
`boost::openmethod::initialize();` must be called before any open-method call.
It builds the dispatch tables. Typically this is done in `main`:
[source,c++]
----
include::{examplesdir}/hello_world.cpp[tag=main,indent=0]
----
We call `poke` like any ordinary function. We can pass it the animals by
reference, because `virtual_ptr` has a conversion constructor for that:
[source,c++]
----
include::{examplesdir}/hello_world.cpp[tag=call]
----
NOTE: `virtual_ptr` is more like a reference than a pointer: it cannot be null,
and it cannot be re-assigned. The only reason why it is not called `virtual_ref`
is to save the name in case it becomes possible to overload the dot operator in
future versions of C++.

View File

@@ -1,199 +0,0 @@
.highlight table td { padding: 5px; }
.highlight table pre { margin: 0; }
.highlight .cm {
color: #999988;
font-style: italic;
}
.highlight .cp {
color: #999999;
font-weight: bold;
}
.highlight .c1 {
color: #999988;
font-style: italic;
}
.highlight .cs {
color: #999999;
font-weight: bold;
font-style: italic;
}
.highlight .c, .highlight .cd {
color: #999988;
font-style: italic;
}
.highlight .err {
}
.highlight .gd {
color: #000000;
background-color: #ffdddd;
}
.highlight .ge {
color: #000000;
font-style: italic;
}
.highlight .gr {
color: #aa0000;
}
.highlight .gh {
color: #999999;
}
.highlight .gi {
color: #000000;
background-color: #ddffdd;
}
.highlight .go {
color: #888888;
}
.highlight .gp {
color: #555555;
}
.highlight .gs {
font-weight: bold;
}
.highlight .gu {
color: #aaaaaa;
}
.highlight .gt {
color: #aa0000;
}
.highlight .kc {
font-weight: bold;
}
.highlight .kd {
font-weight: bold;
}
.highlight .kn {
font-weight: bold;
}
.highlight .kp {
font-weight: bold;
}
.highlight .kr {
font-weight: bold;
}
.highlight .kt {
color: #445588;
font-weight: bold;
}
.highlight .k, .highlight .kv {
font-weight: bold;
}
.highlight .mf {
color: #009999;
}
.highlight .mh {
color: #009999;
}
.highlight .il {
color: #009999;
}
.highlight .mi {
color: #009999;
}
.highlight .mo {
color: #009999;
}
.highlight .m, .highlight .mb, .highlight .mx {
color: #009999;
}
.highlight .sb {
color: #d14;
}
.highlight .sc {
color: #d14;
}
.highlight .sd {
color: #d14;
}
.highlight .s2 {
color: #d14;
}
.highlight .se {
color: #d14;
}
.highlight .sh {
color: #d14;
}
.highlight .si {
color: #d14;
}
.highlight .sx {
color: #d14;
}
.highlight .sr {
color: #009926;
}
.highlight .s1 {
color: #d14;
}
.highlight .ss {
color: #990073;
}
.highlight .s {
color: #d14;
}
.highlight .na {
color: #008080;
}
.highlight .bp {
color: #999999;
}
.highlight .nb {
color: #0086B3;
}
.highlight .nc {
color: #445588;
font-weight: bold;
}
.highlight .no {
color: #008080;
}
.highlight .nd {
color: #3c5d5d;
font-weight: bold;
}
.highlight .ni {
color: #800080;
}
.highlight .ne {
color: #990000;
font-weight: bold;
}
.highlight .nf {
color: #990000;
font-weight: bold;
}
.highlight .nl {
color: #990000;
font-weight: bold;
}
.highlight .nn {
color: #555555;
}
.highlight .nt {
color: #000080;
}
.highlight .vc {
color: #008080;
}
.highlight .vg {
color: #008080;
}
.highlight .vi {
color: #008080;
}
.highlight .nv {
color: #008080;
}
.highlight .ow {
font-weight: bold;
}
.highlight .o {
font-weight: bold;
}
.highlight .o {
font-weight: bold;
}
.highlight .w {
color: #bbbbbb;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

View File

@@ -1,478 +0,0 @@
/* Asciidoctor default stylesheet | MIT License | http://asciidoctor.org */
/* Uncomment @import statement below to use as custom stylesheet */
/*@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700";*/
/* Zajo's custom font import. The rest of the customizations are at the bottom of this css file, which is otherwise kept unchanged */
@import "https://fonts.googleapis.com/css?family=Anonymous+Pro|Istok+Web|Quicksand|Poiret+One";
article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}
audio,canvas,video{display:inline-block}
audio:not([controls]){display:none;height:0}
script{display:none!important}
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}
a{background:transparent}
a:focus{outline:thin dotted}
a:active,a:hover{outline:0}
h1{font-size:2em;margin:.67em 0}
abbr[title]{border-bottom:1px dotted}
b,strong{font-weight:bold}
dfn{font-style:italic}
hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}
mark{background:#ff0;color:#000}
code,kbd,pre,samp{font-family:monospace;font-size:1em}
pre{white-space:pre-wrap}
q{quotes:"\201C" "\201D" "\2018" "\2019"}
small{font-size:80%}
sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
sup{top:-.5em}
sub{bottom:-.25em}
img{border:0}
svg:not(:root){overflow:hidden}
figure{margin:0}
fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
legend{border:0;padding:0}
button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
button,input{line-height:normal}
button,select{text-transform:none}
button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
button[disabled],html input[disabled]{cursor:default}
input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
textarea{overflow:auto;vertical-align:top}
table{border-collapse:collapse;border-spacing:0}
*,*::before,*::after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
html,body{font-size:100%}
body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto;tab-size:4;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
a:hover{cursor:pointer}
img,object,embed{max-width:100%;height:auto}
object,embed{height:100%}
img{-ms-interpolation-mode:bicubic}
.left{float:left!important}
.right{float:right!important}
.text-left{text-align:left!important}
.text-right{text-align:right!important}
.text-center{text-align:center!important}
.text-justify{text-align:justify!important}
.hide{display:none}
img,object,svg{display:inline-block;vertical-align:middle}
textarea{height:auto;min-height:50px}
select{width:100%}
.center{margin-left:auto;margin-right:auto}
.stretch{width:100%}
.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0;direction:ltr}
a{color:#2156a5;text-decoration:underline;line-height:inherit}
a:hover,a:focus{color:#1d4b8f}
a img{border:none}
p{font-family:inherit;font-weight:400;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
p aside{font-size:.875em;line-height:1.35;font-style:italic}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
h1{font-size:2.125em}
h2{font-size:1.6875em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
h4,h5{font-size:1.125em}
h6{font-size:1em}
hr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0}
em,i{font-style:italic;line-height:inherit}
strong,b{font-weight:bold;line-height:inherit}
small{font-size:60%;line-height:inherit}
code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
ul,ol{margin-left:1.5em}
ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em}
ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}
ul.square{list-style-type:square}
ul.circle{list-style-type:circle}
ul.disc{list-style-type:disc}
ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
dl dt{margin-bottom:.3125em;font-weight:bold}
dl dd{margin-bottom:1.25em}
abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help}
abbr{text-transform:none}
blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)}
blockquote cite::before{content:"\2014 \0020"}
blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)}
blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
@media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
h1{font-size:2.75em}
h2{font-size:2.3125em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
h4{font-size:1.4375em}}
table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede}
table thead,table tfoot{background:#f7f8f7}
table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
table tr.even,table tr.alt,table tr:nth-of-type(even){background:#f8f8f7}
table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
.clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table}
.clearfix::after,.float-group::after{clear:both}
*:not(pre)>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background-color:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed;word-wrap:break-word}
*:not(pre)>code.nobreak{word-wrap:normal}
*:not(pre)>code.nowrap{white-space:nowrap}
pre,pre>code{line-height:1.45;color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;text-rendering:optimizeSpeed}
em em{font-style:normal}
strong strong{font-weight:400}
.keyseq{color:rgba(51,51,51,.8)}
kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background-color:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
.keyseq kbd:first-child{margin-left:0}
.keyseq kbd:last-child{margin-right:0}
.menuseq,.menuref{color:#000}
.menuseq b:not(.caret),.menuref{font-weight:inherit}
.menuseq{word-spacing:-.02em}
.menuseq b.caret{font-size:1.25em;line-height:.8}
.menuseq i.caret{font-weight:bold;text-align:center;width:.45em}
b.button::before,b.button::after{position:relative;top:-1px;font-weight:400}
b.button::before{content:"[";padding:0 3px 0 2px}
b.button::after{content:"]";padding:0 2px 0 3px}
p a>code:hover{color:rgba(0,0,0,.9)}
#header,#content,#footnotes,#footer{width:100%;margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
#header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table}
#header::after,#content::after,#footnotes::after,#footer::after{clear:both}
#content{margin-top:1.25em}
#content::before{content:none}
#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf}
#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px}
#header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap}
#header .details span:first-child{margin-left:-.125em}
#header .details span.email a{color:rgba(0,0,0,.85)}
#header .details br{display:none}
#header .details br+span::before{content:"\00a0\2013\00a0"}
#header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
#header .details br+span#revremark::before{content:"\00a0|\00a0"}
#header #revnumber{text-transform:capitalize}
#header #revnumber::after{content:"\00a0"}
#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #dddddf;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
#toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em}
#toc>ul{margin-left:.125em}
#toc ul.sectlevel0>li>a{font-style:italic}
#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
#toc li{line-height:1.3334;margin-top:.3334em}
#toc a{text-decoration:none}
#toc a:active{text-decoration:underline}
#toctitle{color:#7a2518;font-size:1.2em}
@media screen and (min-width:768px){#toctitle{font-size:1.375em}
body.toc2{padding-left:15em;padding-right:0}
#toc.toc2{margin-top:0!important;background-color:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
#toc.toc2>ul{font-size:.9em;margin-bottom:0}
#toc.toc2 ul ul{margin-left:0;padding-left:1em}
#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
body.toc2.toc-right{padding-left:0;padding-right:15em}
body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}}
@media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
#toc.toc2{width:20em}
#toc.toc2 #toctitle{font-size:1.375em}
#toc.toc2>ul{font-size:.95em}
#toc.toc2 ul ul{padding-left:1.25em}
body.toc2.toc-right{padding-left:0;padding-right:20em}}
#content #toc{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
#content #toc>:first-child{margin-top:0}
#content #toc>:last-child{margin-bottom:0}
#footer{max-width:100%;background-color:rgba(0,0,0,.8);padding:1.25em}
#footer-text{color:rgba(255,255,255,.8);line-height:1.44}
#content{margin-bottom:.625em}
.sect1{padding-bottom:.625em}
@media screen and (min-width:768px){#content{margin-bottom:1.25em}
.sect1{padding-bottom:1.25em}}
.sect1:last-child{padding-bottom:0}
.sect1+.sect1{border-top:1px solid #e7e7e9}
#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
#content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
table.tableblock.fit-content>caption.title{white-space:nowrap;width:0}
.paragraph.lead>p,#preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)}
table.tableblock #preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:inherit}
.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
.admonitionblock>table td.icon{text-align:center;width:80px}
.admonitionblock>table td.icon img{max-width:none}
.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(0,0,0,.6)}
.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
.exampleblock>.content{border-style:solid;border-width:1px;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;-webkit-border-radius:4px;border-radius:4px}
.exampleblock>.content>:first-child{margin-top:0}
.exampleblock>.content>:last-child{margin-bottom:0}
.sidebarblock{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
.sidebarblock>:first-child{margin-top:0}
.sidebarblock>:last-child{margin-bottom:0}
.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
.literalblock pre,.listingblock pre:not(.highlight),.listingblock pre[class="highlight"],.listingblock pre[class^="highlight "],.listingblock pre.CodeRay,.listingblock pre.prettyprint{background:#f7f7f8}
.sidebarblock .literalblock pre,.sidebarblock .listingblock pre:not(.highlight),.sidebarblock .listingblock pre[class="highlight"],.sidebarblock .listingblock pre[class^="highlight "],.sidebarblock .listingblock pre.CodeRay,.sidebarblock .listingblock pre.prettyprint{background:#f2f1f1}
.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{-webkit-border-radius:4px;border-radius:4px;word-wrap:break-word;overflow-x:auto;padding:1em;font-size:.8125em}
@media screen and (min-width:768px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:.90625em}}
@media screen and (min-width:1280px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:1em}}
.literalblock pre.nowrap,.literalblock pre.nowrap pre,.listingblock pre.nowrap,.listingblock pre.nowrap pre{white-space:pre;word-wrap:normal}
.literalblock.output pre{color:#f7f7f8;background-color:rgba(0,0,0,.9)}
.listingblock pre.highlightjs{padding:0}
.listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px}
.listingblock pre.prettyprint{border-width:0}
.listingblock>.content{position:relative}
.listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:#999}
.listingblock:hover code[data-lang]::before{display:block}
.listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:#999}
.listingblock.terminal pre .command:not([data-prompt])::before{content:"$"}
table.pyhltable{border-collapse:separate;border:0;margin-bottom:0;background:none}
table.pyhltable td{vertical-align:top;padding-top:0;padding-bottom:0;line-height:1.45}
table.pyhltable td.code{padding-left:.75em;padding-right:0}
pre.pygments .lineno,table.pyhltable td:not(.code){color:#999;padding-left:0;padding-right:.5em;border-right:1px solid #dddddf}
pre.pygments .lineno{display:inline-block;margin-right:.25em}
table.pyhltable .linenodiv{background:none!important;padding-right:0!important}
.quoteblock{margin:0 1em 1.25em 1.5em;display:table}
.quoteblock>.title{margin-left:-1.5em;margin-bottom:.75em}
.quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
.quoteblock blockquote{margin:0;padding:0;border:0}
.quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
.quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right}
.verseblock{margin:0 1em 1.25em}
.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
.verseblock pre strong{font-weight:400}
.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
.quoteblock .attribution br,.verseblock .attribution br{display:none}
.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}
.quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none}
.quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0}
.quoteblock.abstract{margin:0 1em 1.25em;display:block}
.quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center}
.quoteblock.excerpt,.quoteblock .quoteblock{margin:0 0 1.25em;padding:0 0 .25em 1em;border-left:.25em solid #dddddf}
.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem}
.quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;text-align:left;margin-right:0}
table.tableblock{max-width:100%;border-collapse:separate}
p.tableblock:last-child{margin-bottom:0}
td.tableblock>.content{margin-bottom:-1.25em}
table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
table.grid-all>thead>tr>.tableblock,table.grid-all>tbody>tr>.tableblock{border-width:0 1px 1px 0}
table.grid-all>tfoot>tr>.tableblock{border-width:1px 1px 0 0}
table.grid-cols>*>tr>.tableblock{border-width:0 1px 0 0}
table.grid-rows>thead>tr>.tableblock,table.grid-rows>tbody>tr>.tableblock{border-width:0 0 1px}
table.grid-rows>tfoot>tr>.tableblock{border-width:1px 0 0}
table.grid-all>*>tr>.tableblock:last-child,table.grid-cols>*>tr>.tableblock:last-child{border-right-width:0}
table.grid-all>tbody>tr:last-child>.tableblock,table.grid-all>thead:last-child>tr>.tableblock,table.grid-rows>tbody>tr:last-child>.tableblock,table.grid-rows>thead:last-child>tr>.tableblock{border-bottom-width:0}
table.frame-all{border-width:1px}
table.frame-sides{border-width:0 1px}
table.frame-topbot,table.frame-ends{border-width:1px 0}
table.stripes-all tr,table.stripes-odd tr:nth-of-type(odd){background:#f8f8f7}
table.stripes-none tr,table.stripes-odd tr:nth-of-type(even){background:none}
th.halign-left,td.halign-left{text-align:left}
th.halign-right,td.halign-right{text-align:right}
th.halign-center,td.halign-center{text-align:center}
th.valign-top,td.valign-top{vertical-align:top}
th.valign-bottom,td.valign-bottom{vertical-align:bottom}
th.valign-middle,td.valign-middle{vertical-align:middle}
table thead th,table tfoot th{font-weight:bold}
tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7}
tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
p.tableblock>code:only-child{background:none;padding:0}
p.tableblock{font-size:1em}
td>div.verse{white-space:pre}
ol{margin-left:1.75em}
ul li ol{margin-left:1.5em}
dl dd{margin-left:1.125em}
dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none}
ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em}
ul.unstyled,ol.unstyled{margin-left:0}
ul.checklist{margin-left:.625em}
ul.checklist li>p:first-child>.fa-square-o:first-child,ul.checklist li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em}
ul.checklist li>p:first-child>input[type="checkbox"]:first-child{margin-right:.25em}
ul.inline{display:-ms-flexbox;display:-webkit-box;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em}
ul.inline>li{margin-left:1.25em}
.unstyled dl dt{font-weight:400;font-style:normal}
ol.arabic{list-style-type:decimal}
ol.decimal{list-style-type:decimal-leading-zero}
ol.loweralpha{list-style-type:lower-alpha}
ol.upperalpha{list-style-type:upper-alpha}
ol.lowerroman{list-style-type:lower-roman}
ol.upperroman{list-style-type:upper-roman}
ol.lowergreek{list-style-type:lower-greek}
.hdlist>table,.colist>table{border:0;background:none}
.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}
td.hdlist1{font-weight:bold;padding-bottom:1.25em}
.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
.colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top}
.colist td:not([class]):first-child img{max-width:none}
.colist td:not([class]):last-child{padding:.25em 0}
.thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd}
.imageblock.left{margin:.25em .625em 1.25em 0}
.imageblock.right{margin:.25em 0 1.25em .625em}
.imageblock>.title{margin-bottom:0}
.imageblock.thumb,.imageblock.th{border-width:6px}
.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
.image.left{margin-right:.625em}
.image.right{margin-left:.625em}
a.image{text-decoration:none;display:inline-block}
a.image object{pointer-events:none}
sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}
sup.footnote a,sup.footnoteref a{text-decoration:none}
sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0}
#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em}
#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em}
#footnotes .footnote:last-of-type{margin-bottom:0}
#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
.gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0}
.gist .file-data>table td.line-data{width:99%}
div.unbreakable{page-break-inside:avoid}
.big{font-size:larger}
.small{font-size:smaller}
.underline{text-decoration:underline}
.overline{text-decoration:overline}
.line-through{text-decoration:line-through}
.aqua{color:#00bfbf}
.aqua-background{background-color:#00fafa}
.black{color:#000}
.black-background{background-color:#000}
.blue{color:#0000bf}
.blue-background{background-color:#0000fa}
.fuchsia{color:#bf00bf}
.fuchsia-background{background-color:#fa00fa}
.gray{color:#606060}
.gray-background{background-color:#7d7d7d}
.green{color:#006000}
.green-background{background-color:#007d00}
.lime{color:#00bf00}
.lime-background{background-color:#00fa00}
.maroon{color:#600000}
.maroon-background{background-color:#7d0000}
.navy{color:#000060}
.navy-background{background-color:#00007d}
.olive{color:#606000}
.olive-background{background-color:#7d7d00}
.purple{color:#600060}
.purple-background{background-color:#7d007d}
.red{color:#bf0000}
.red-background{background-color:#fa0000}
.silver{color:#909090}
.silver-background{background-color:#bcbcbc}
.teal{color:#006060}
.teal-background{background-color:#007d7d}
.white{color:#bfbfbf}
.white-background{background-color:#fafafa}
.yellow{color:#bfbf00}
.yellow-background{background-color:#fafa00}
span.icon>.fa{cursor:default}
a span.icon>.fa{cursor:inherit}
.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
.admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c}
.admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
.admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900}
.admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400}
.admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000}
.conum[data-value]{display:inline-block;color:#fff!important;background-color:rgba(0,0,0,.8);-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
.conum[data-value] *{color:#fff!important}
.conum[data-value]+b{display:none}
.conum[data-value]::after{content:attr(data-value)}
pre .conum[data-value]{position:relative;top:-.125em}
b.conum *{color:inherit!important}
.conum:not([data-value]):empty{display:none}
dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
h1,h2,p,td.content,span.alt{letter-spacing:-.01em}
p strong,td.content strong,div.footnote strong{letter-spacing:-.005em}
p,blockquote,dt,td.content,span.alt{font-size:1.0625rem}
p{margin-bottom:1.25rem}
.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
.exampleblock>.content{background-color:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc}
.print-only{display:none!important}
@page{margin:1.25cm .75cm}
@media print{*{-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important}
html{font-size:80%}
a{color:inherit!important;text-decoration:underline!important}
a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important}
a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
abbr[title]::after{content:" (" attr(title) ")"}
pre,blockquote,tr,img,object,svg{page-break-inside:avoid}
thead{display:table-header-group}
svg{max-width:100%}
p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}
h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}
#toc,.sidebarblock,.exampleblock>.content{background:none!important}
#toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important}
body.book #header{text-align:center}
body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em}
body.book #header .details{border:0!important;display:block;padding:0!important}
body.book #header .details span:first-child{margin-left:0!important}
body.book #header .details br{display:block}
body.book #header .details br+span::before{content:none!important}
body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
.listingblock code[data-lang]::before{display:block}
#footer{padding:0 .9375em}
.hide-on-print{display:none!important}
.print-only{display:block!important}
.hide-for-print{display:none!important}
.show-for-print{display:inherit!important}}
@media print,amzn-kf8{#header>h1:first-child{margin-top:1.25rem}
.sect1{padding:0!important}
.sect1+.sect1{border:0}
#footer{background:none}
#footer-text{color:rgba(0,0,0,.6);font-size:.9em}}
@media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}}
/* Zajo's customizations applied on top of the standard asciidoctor css above */
h1{font-size:4em}
h2{font-size:1.74em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.5em}
h4{font-size:1.2em}
h5{font-size:1em}
h6{font-size:1em}
#toc {text-align:left}
#toc ul code{font-size:111%}
#toc a:hover code {color:#00cc99}
a:focus{outline:0}
.colist td{color:rgba(255,255,255,.67)}
body{text-align:left; background:#202020;color:rgba(255,255,255,.67);padding:0;margin:0;font-family:"Istok Web","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto;tab-size:4;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#a0a0a0;font-weight:400;margin-top:0;margin-bottom:.25em}
.literalblock pre,.listingblock pre:not(.highlight),.listingblock pre[class="highlight"],.listingblock pre[class^="highlight "],.listingblock pre.CodeRay,.listingblock pre.prettyprint{background:#101010}
table{background:#202020;margin-bottom:1.25em;border:solid 1px #dedede}
table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(255,255,255,.67)}
table tr.even,table tr.alt,table tr:nth-of-type(even){background:#202020}
table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{color:rgba(255,255,255,.67)}
th{background-color:#404040}
a{color:#FFFFFF;text-decoration:underline;line-height:inherit}
a:hover{color:#00cc99}
a:focus{color:#FFFFFF}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Quicksand","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#00cc99;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.4em}
code{font-family:"Anonymous Pro","DejaVu Sans Mono",monospace;font-weight:400;color:black}
*:not(pre)>code{font-size:1.0em;font-style:normal!important;letter-spacing:0;padding:0 0;word-spacing:-.15em;background-color:transparent;-webkit-border-radius:0;border-radius:0;line-height:1.45;text-rendering:optimizeLegibility;word-wrap:break-word;color:white}
pre,pre>code{line-height:1.45;color:rgba(255,255,255,.67);font-family:"Anonymous Pro","DejaVu Sans Mono",monospace;font-weight:400;text-rendering:optimizeLegibility;font-size:1.05em;background-color:#101010}
a:not(pre)>code:hover {color:#00cc99}
kbd{font-family:"Anonymous Pro","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background-color:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
h1 code{color:#00cc99; font-size:113%}
h2 code{color:#00cc99; font-size:113%}
h3 code{color:#00cc99; font-size:113%}
h4 code{color:#00cc99; font-size:113%}
h5 code{color:#00cc99; font-size:113%}
#header>h1:first-child{font-family:"Poiret One";color:#00cc99;margin-top:2.25rem;margin-bottom:0;letter-spacing:-.07em}
#author{color:#a366ff}
#toc ul{font-family:"Quicksand","DejaVu Sans",sans-serif;list-style-type:none}
#toc a:hover{color:#00cc99}
#toc.toc2{background-color:#404040}
.admonitionblock td.icon .icon-note::before{content:"\f05a";color:#00cc99}
.admonitionblock td.icon .icon-tip::before{content:"\f0eb";color:#00cc99;text-shadow:none}
.admonitionblock td.icon .icon-warning::before{content:"\f071";color:#a366ff}
.admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#a366ff}
.admonitionblock td.icon .icon-important::before{content:"\f06a";color:#a366ff}
.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(255,255,255,.67)}
.conum[data-value]{display:inline-block;color:black!important;background-color:#d9d9d9;-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
.exampleblock>.content{background-color:#404040;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc}
.quoteblock {background-color:#404040}
.quoteblock blockquote,.quoteblock p{color:rgba(255,255,255,.67);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify;background-color:#404040}
.quoteblock blockquote::before{margin-left:-.8em;color:#00cc99}
.quoteblock blockquote{font-family:"Istok Web","DejaVu Serif"; font-size:1.0625rem; padding:0.5em}
.quoteblock .attribution{padding-top:.75ex;margin-top:0;margin-right:0;padding-right:.5ex;text-align:right;background-color:#202020}
.text-right{margin-top:-1em}

View File

@@ -1,468 +0,0 @@
/* Asciidoctor default stylesheet | MIT License | http://asciidoctor.org */
/* Uncomment @import statement below to use as custom stylesheet */
/*@import "https://fonts.googleapis.com/css?family=Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,400italic,700,700italic%7CDroid+Sans+Mono:400,700";*/
/* Zajo's custom font import. The rest of the customizations are at the bottom of this css file, which is otherwise kept unchanged */
@import "https://fonts.googleapis.com/css?family=Anonymous+Pro|Istok+Web|Quicksand|Poiret+One";
article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}
audio,canvas,video{display:inline-block}
audio:not([controls]){display:none;height:0}
script{display:none!important}
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}
a{background:transparent}
a:focus{outline:thin dotted}
a:active,a:hover{outline:0}
h1{font-size:2em;margin:.67em 0}
abbr[title]{border-bottom:1px dotted}
b,strong{font-weight:bold}
dfn{font-style:italic}
hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}
mark{background:#ff0;color:#000}
code,kbd,pre,samp{font-family:monospace;font-size:1em}
pre{white-space:pre-wrap}
q{quotes:"\201C" "\201D" "\2018" "\2019"}
small{font-size:80%}
sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
sup{top:-.5em}
sub{bottom:-.25em}
img{border:0}
svg:not(:root){overflow:hidden}
figure{margin:0}
fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}
legend{border:0;padding:0}
button,input,select,textarea{font-family:inherit;font-size:100%;margin:0}
button,input{line-height:normal}
button,select{text-transform:none}
button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}
button[disabled],html input[disabled]{cursor:default}
input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}
textarea{overflow:auto;vertical-align:top}
table{border-collapse:collapse;border-spacing:0}
*,*::before,*::after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}
html,body{font-size:100%}
body{background:#fff;color:rgba(0,0,0,.8);padding:0;margin:0;font-family:"Noto Serif","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto;tab-size:4;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
a:hover{cursor:pointer}
img,object,embed{max-width:100%;height:auto}
object,embed{height:100%}
img{-ms-interpolation-mode:bicubic}
.left{float:left!important}
.right{float:right!important}
.text-left{text-align:left!important}
.text-right{text-align:right!important}
.text-center{text-align:center!important}
.text-justify{text-align:justify!important}
.hide{display:none}
img,object,svg{display:inline-block;vertical-align:middle}
textarea{height:auto;min-height:50px}
select{width:100%}
.center{margin-left:auto;margin-right:auto}
.stretch{width:100%}
.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#7a2518;font-weight:400;margin-top:0;margin-bottom:.25em}
div,dl,dt,dd,ul,ol,li,h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6,pre,form,p,blockquote,th,td{margin:0;padding:0;direction:ltr}
a{color:#2156a5;text-decoration:underline;line-height:inherit}
a:hover,a:focus{color:#1d4b8f}
a img{border:none}
p{font-family:inherit;font-weight:400;font-size:1em;line-height:1.6;margin-bottom:1.25em;text-rendering:optimizeLegibility}
p aside{font-size:.875em;line-height:1.35;font-style:italic}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Open Sans","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#ba3925;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.0125em}
h1 small,h2 small,h3 small,#toctitle small,.sidebarblock>.content>.title small,h4 small,h5 small,h6 small{font-size:60%;color:#e99b8f;line-height:0}
h1{font-size:2.125em}
h2{font-size:1.6875em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.375em}
h4,h5{font-size:1.125em}
h6{font-size:1em}
hr{border:solid #dddddf;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0}
em,i{font-style:italic;line-height:inherit}
strong,b{font-weight:bold;line-height:inherit}
small{font-size:60%;line-height:inherit}
code{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;color:rgba(0,0,0,.9)}
ul,ol,dl{font-size:1em;line-height:1.6;margin-bottom:1.25em;list-style-position:outside;font-family:inherit}
ul,ol{margin-left:1.5em}
ul li ul,ul li ol{margin-left:1.25em;margin-bottom:0;font-size:1em}
ul.square li ul,ul.circle li ul,ul.disc li ul{list-style:inherit}
ul.square{list-style-type:square}
ul.circle{list-style-type:circle}
ul.disc{list-style-type:disc}
ol li ul,ol li ol{margin-left:1.25em;margin-bottom:0}
dl dt{margin-bottom:.3125em;font-weight:bold}
dl dd{margin-bottom:1.25em}
abbr,acronym{text-transform:uppercase;font-size:90%;color:rgba(0,0,0,.8);border-bottom:1px dotted #ddd;cursor:help}
abbr{text-transform:none}
blockquote{margin:0 0 1.25em;padding:.5625em 1.25em 0 1.1875em;border-left:1px solid #ddd}
blockquote cite{display:block;font-size:.9375em;color:rgba(0,0,0,.6)}
blockquote cite::before{content:"\2014 \0020"}
blockquote cite a,blockquote cite a:visited{color:rgba(0,0,0,.6)}
blockquote,blockquote p{line-height:1.6;color:rgba(0,0,0,.85)}
@media screen and (min-width:768px){h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2}
h1{font-size:2.75em}
h2{font-size:2.3125em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.6875em}
h4{font-size:1.4375em}}
table{background:#fff;margin-bottom:1.25em;border:solid 1px #dedede}
table thead,table tfoot{background:#f7f8f7}
table thead tr th,table thead tr td,table tfoot tr th,table tfoot tr td{padding:.5em .625em .625em;font-size:inherit;color:rgba(0,0,0,.8);text-align:left}
table tr th,table tr td{padding:.5625em .625em;font-size:inherit;color:rgba(0,0,0,.8)}
table tr.even,table tr.alt,table tr:nth-of-type(even){background:#f8f8f7}
table thead tr th,table tfoot tr th,table tbody tr td,table tr td,table tfoot tr td{display:table-cell;line-height:1.6}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{line-height:1.2;word-spacing:-.05em}
h1 strong,h2 strong,h3 strong,#toctitle strong,.sidebarblock>.content>.title strong,h4 strong,h5 strong,h6 strong{font-weight:400}
.clearfix::before,.clearfix::after,.float-group::before,.float-group::after{content:" ";display:table}
.clearfix::after,.float-group::after{clear:both}
*:not(pre)>code{font-size:.9375em;font-style:normal!important;letter-spacing:0;padding:.1em .5ex;word-spacing:-.15em;background-color:#f7f7f8;-webkit-border-radius:4px;border-radius:4px;line-height:1.45;text-rendering:optimizeSpeed;word-wrap:break-word}
*:not(pre)>code.nobreak{word-wrap:normal}
*:not(pre)>code.nowrap{white-space:nowrap}
pre,pre>code{line-height:1.45;color:rgba(0,0,0,.9);font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;font-weight:400;text-rendering:optimizeSpeed}
em em{font-style:normal}
strong strong{font-weight:400}
.keyseq{color:rgba(51,51,51,.8)}
kbd{font-family:"Droid Sans Mono","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background-color:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
.keyseq kbd:first-child{margin-left:0}
.keyseq kbd:last-child{margin-right:0}
.menuseq,.menuref{color:#000}
.menuseq b:not(.caret),.menuref{font-weight:inherit}
.menuseq{word-spacing:-.02em}
.menuseq b.caret{font-size:1.25em;line-height:.8}
.menuseq i.caret{font-weight:bold;text-align:center;width:.45em}
b.button::before,b.button::after{position:relative;top:-1px;font-weight:400}
b.button::before{content:"[";padding:0 3px 0 2px}
b.button::after{content:"]";padding:0 2px 0 3px}
p a>code:hover{color:rgba(0,0,0,.9)}
#header,#content,#footnotes,#footer{width:100%;margin-left:auto;margin-right:auto;margin-top:0;margin-bottom:0;max-width:62.5em;*zoom:1;position:relative;padding-left:.9375em;padding-right:.9375em}
#header::before,#header::after,#content::before,#content::after,#footnotes::before,#footnotes::after,#footer::before,#footer::after{content:" ";display:table}
#header::after,#content::after,#footnotes::after,#footer::after{clear:both}
#content{margin-top:1.25em}
#content::before{content:none}
#header>h1:first-child{color:rgba(0,0,0,.85);margin-top:2.25rem;margin-bottom:0}
#header>h1:first-child+#toc{margin-top:8px;border-top:1px solid #dddddf}
#header>h1:only-child,body.toc2 #header>h1:nth-last-child(2){border-bottom:1px solid #dddddf;padding-bottom:8px}
#header .details{border-bottom:1px solid #dddddf;line-height:1.45;padding-top:.25em;padding-bottom:.25em;padding-left:.25em;color:rgba(0,0,0,.6);display:-ms-flexbox;display:-webkit-flex;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap}
#header .details span:first-child{margin-left:-.125em}
#header .details span.email a{color:rgba(0,0,0,.85)}
#header .details br{display:none}
#header .details br+span::before{content:"\00a0\2013\00a0"}
#header .details br+span.author::before{content:"\00a0\22c5\00a0";color:rgba(0,0,0,.85)}
#header .details br+span#revremark::before{content:"\00a0|\00a0"}
#header #revnumber{text-transform:capitalize}
#header #revnumber::after{content:"\00a0"}
#content>h1:first-child:not([class]){color:rgba(0,0,0,.85);border-bottom:1px solid #dddddf;padding-bottom:8px;margin-top:0;padding-top:1rem;margin-bottom:1.25rem}
#toc{border-bottom:1px solid #e7e7e9;padding-bottom:.5em}
#toc>ul{margin-left:.125em}
#toc ul.sectlevel0>li>a{font-style:italic}
#toc ul.sectlevel0 ul.sectlevel1{margin:.5em 0}
#toc ul{font-family:"Open Sans","DejaVu Sans",sans-serif;list-style-type:none}
#toc li{line-height:1.3334;margin-top:.3334em}
#toc a{text-decoration:none}
#toc a:active{text-decoration:underline}
#toctitle{color:#7a2518;font-size:1.2em}
@media screen and (min-width:768px){#toctitle{font-size:1.375em}
body.toc2{padding-left:15em;padding-right:0}
#toc.toc2{margin-top:0!important;background-color:#f8f8f7;position:fixed;width:15em;left:0;top:0;border-right:1px solid #e7e7e9;border-top-width:0!important;border-bottom-width:0!important;z-index:1000;padding:1.25em 1em;height:100%;overflow:auto}
#toc.toc2 #toctitle{margin-top:0;margin-bottom:.8rem;font-size:1.2em}
#toc.toc2>ul{font-size:.9em;margin-bottom:0}
#toc.toc2 ul ul{margin-left:0;padding-left:1em}
#toc.toc2 ul.sectlevel0 ul.sectlevel1{padding-left:0;margin-top:.5em;margin-bottom:.5em}
body.toc2.toc-right{padding-left:0;padding-right:15em}
body.toc2.toc-right #toc.toc2{border-right-width:0;border-left:1px solid #e7e7e9;left:auto;right:0}}
@media screen and (min-width:1280px){body.toc2{padding-left:20em;padding-right:0}
#toc.toc2{width:20em}
#toc.toc2 #toctitle{font-size:1.375em}
#toc.toc2>ul{font-size:.95em}
#toc.toc2 ul ul{padding-left:1.25em}
body.toc2.toc-right{padding-left:0;padding-right:20em}}
#content #toc{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
#content #toc>:first-child{margin-top:0}
#content #toc>:last-child{margin-bottom:0}
#footer{max-width:100%;background-color:rgba(0,0,0,.8);padding:1.25em}
#footer-text{color:rgba(255,255,255,.8);line-height:1.44}
#content{margin-bottom:.625em}
.sect1{padding-bottom:.625em}
@media screen and (min-width:768px){#content{margin-bottom:1.25em}
.sect1{padding-bottom:1.25em}}
.sect1:last-child{padding-bottom:0}
.sect1+.sect1{border-top:1px solid #e7e7e9}
#content h1>a.anchor,h2>a.anchor,h3>a.anchor,#toctitle>a.anchor,.sidebarblock>.content>.title>a.anchor,h4>a.anchor,h5>a.anchor,h6>a.anchor{position:absolute;z-index:1001;width:1.5ex;margin-left:-1.5ex;display:block;text-decoration:none!important;visibility:hidden;text-align:center;font-weight:400}
#content h1>a.anchor::before,h2>a.anchor::before,h3>a.anchor::before,#toctitle>a.anchor::before,.sidebarblock>.content>.title>a.anchor::before,h4>a.anchor::before,h5>a.anchor::before,h6>a.anchor::before{content:"\00A7";font-size:.85em;display:block;padding-top:.1em}
#content h1:hover>a.anchor,#content h1>a.anchor:hover,h2:hover>a.anchor,h2>a.anchor:hover,h3:hover>a.anchor,#toctitle:hover>a.anchor,.sidebarblock>.content>.title:hover>a.anchor,h3>a.anchor:hover,#toctitle>a.anchor:hover,.sidebarblock>.content>.title>a.anchor:hover,h4:hover>a.anchor,h4>a.anchor:hover,h5:hover>a.anchor,h5>a.anchor:hover,h6:hover>a.anchor,h6>a.anchor:hover{visibility:visible}
#content h1>a.link,h2>a.link,h3>a.link,#toctitle>a.link,.sidebarblock>.content>.title>a.link,h4>a.link,h5>a.link,h6>a.link{color:#ba3925;text-decoration:none}
#content h1>a.link:hover,h2>a.link:hover,h3>a.link:hover,#toctitle>a.link:hover,.sidebarblock>.content>.title>a.link:hover,h4>a.link:hover,h5>a.link:hover,h6>a.link:hover{color:#a53221}
.audioblock,.imageblock,.literalblock,.listingblock,.stemblock,.videoblock{margin-bottom:1.25em}
.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{text-rendering:optimizeLegibility;text-align:left;font-family:"Noto Serif","DejaVu Serif",serif;font-size:1rem;font-style:italic}
table.tableblock.fit-content>caption.title{white-space:nowrap;width:0}
.paragraph.lead>p,#preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:1.21875em;line-height:1.6;color:rgba(0,0,0,.85)}
table.tableblock #preamble>.sectionbody>[class="paragraph"]:first-of-type p{font-size:inherit}
.admonitionblock>table{border-collapse:separate;border:0;background:none;width:100%}
.admonitionblock>table td.icon{text-align:center;width:80px}
.admonitionblock>table td.icon img{max-width:none}
.admonitionblock>table td.icon .title{font-weight:bold;font-family:"Open Sans","DejaVu Sans",sans-serif;text-transform:uppercase}
.admonitionblock>table td.content{padding-left:1.125em;padding-right:1.25em;border-left:1px solid #dddddf;color:rgba(0,0,0,.6)}
.admonitionblock>table td.content>:last-child>:last-child{margin-bottom:0}
.exampleblock>.content{border-style:solid;border-width:1px;border-color:#e6e6e6;margin-bottom:1.25em;padding:1.25em;background:#fff;-webkit-border-radius:4px;border-radius:4px}
.exampleblock>.content>:first-child{margin-top:0}
.exampleblock>.content>:last-child{margin-bottom:0}
.sidebarblock{border-style:solid;border-width:1px;border-color:#e0e0dc;margin-bottom:1.25em;padding:1.25em;background:#f8f8f7;-webkit-border-radius:4px;border-radius:4px}
.sidebarblock>:first-child{margin-top:0}
.sidebarblock>:last-child{margin-bottom:0}
.sidebarblock>.content>.title{color:#7a2518;margin-top:0;text-align:center}
.exampleblock>.content>:last-child>:last-child,.exampleblock>.content .olist>ol>li:last-child>:last-child,.exampleblock>.content .ulist>ul>li:last-child>:last-child,.exampleblock>.content .qlist>ol>li:last-child>:last-child,.sidebarblock>.content>:last-child>:last-child,.sidebarblock>.content .olist>ol>li:last-child>:last-child,.sidebarblock>.content .ulist>ul>li:last-child>:last-child,.sidebarblock>.content .qlist>ol>li:last-child>:last-child{margin-bottom:0}
.literalblock pre,.listingblock pre:not(.highlight),.listingblock pre[class="highlight"],.listingblock pre[class^="highlight "],.listingblock pre.CodeRay,.listingblock pre.prettyprint{background:#f7f7f8}
.sidebarblock .literalblock pre,.sidebarblock .listingblock pre:not(.highlight),.sidebarblock .listingblock pre[class="highlight"],.sidebarblock .listingblock pre[class^="highlight "],.sidebarblock .listingblock pre.CodeRay,.sidebarblock .listingblock pre.prettyprint{background:#f2f1f1}
.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{-webkit-border-radius:4px;border-radius:4px;word-wrap:break-word;overflow-x:auto;padding:1em;font-size:.8125em}
@media screen and (min-width:768px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:.90625em}}
@media screen and (min-width:1280px){.literalblock pre,.literalblock pre[class],.listingblock pre,.listingblock pre[class]{font-size:1em}}
.literalblock pre.nowrap,.literalblock pre.nowrap pre,.listingblock pre.nowrap,.listingblock pre.nowrap pre{white-space:pre;word-wrap:normal}
.literalblock.output pre{color:#f7f7f8;background-color:rgba(0,0,0,.9)}
.listingblock pre.highlightjs{padding:0}
.listingblock pre.highlightjs>code{padding:1em;-webkit-border-radius:4px;border-radius:4px}
.listingblock pre.prettyprint{border-width:0}
.listingblock>.content{position:relative}
.listingblock code[data-lang]::before{display:none;content:attr(data-lang);position:absolute;font-size:.75em;top:.425rem;right:.5rem;line-height:1;text-transform:uppercase;color:#999}
.listingblock:hover code[data-lang]::before{display:block}
.listingblock.terminal pre .command::before{content:attr(data-prompt);padding-right:.5em;color:#999}
.listingblock.terminal pre .command:not([data-prompt])::before{content:"$"}
table.pyhltable{border-collapse:separate;border:0;margin-bottom:0;background:none}
table.pyhltable td{vertical-align:top;padding-top:0;padding-bottom:0;line-height:1.45}
table.pyhltable td.code{padding-left:.75em;padding-right:0}
pre.pygments .lineno,table.pyhltable td:not(.code){color:#999;padding-left:0;padding-right:.5em;border-right:1px solid #dddddf}
pre.pygments .lineno{display:inline-block;margin-right:.25em}
table.pyhltable .linenodiv{background:none!important;padding-right:0!important}
.quoteblock{margin:0 1em 1.25em 1.5em;display:table}
.quoteblock>.title{margin-left:-1.5em;margin-bottom:.75em}
.quoteblock blockquote,.quoteblock p{color:rgba(0,0,0,.85);font-size:1.15rem;line-height:1.75;word-spacing:.1em;letter-spacing:0;font-style:italic;text-align:justify}
.quoteblock blockquote{margin:0;padding:0;border:0}
.quoteblock blockquote::before{content:"\201c";float:left;font-size:2.75em;font-weight:bold;line-height:.6em;margin-left:-.6em;color:#7a2518;text-shadow:0 1px 2px rgba(0,0,0,.1)}
.quoteblock blockquote>.paragraph:last-child p{margin-bottom:0}
.quoteblock .attribution{margin-top:.75em;margin-right:.5ex;text-align:right}
.verseblock{margin:0 1em 1.25em}
.verseblock pre{font-family:"Open Sans","DejaVu Sans",sans;font-size:1.15rem;color:rgba(0,0,0,.85);font-weight:300;text-rendering:optimizeLegibility}
.verseblock pre strong{font-weight:400}
.verseblock .attribution{margin-top:1.25rem;margin-left:.5ex}
.quoteblock .attribution,.verseblock .attribution{font-size:.9375em;line-height:1.45;font-style:italic}
.quoteblock .attribution br,.verseblock .attribution br{display:none}
.quoteblock .attribution cite,.verseblock .attribution cite{display:block;letter-spacing:-.025em;color:rgba(0,0,0,.6)}
.quoteblock.abstract blockquote::before,.quoteblock.excerpt blockquote::before,.quoteblock .quoteblock blockquote::before{display:none}
.quoteblock.abstract blockquote,.quoteblock.abstract p,.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{line-height:1.6;word-spacing:0}
.quoteblock.abstract{margin:0 1em 1.25em;display:block}
.quoteblock.abstract>.title{margin:0 0 .375em;font-size:1.15em;text-align:center}
.quoteblock.excerpt,.quoteblock .quoteblock{margin:0 0 1.25em;padding:0 0 .25em 1em;border-left:.25em solid #dddddf}
.quoteblock.excerpt blockquote,.quoteblock.excerpt p,.quoteblock .quoteblock blockquote,.quoteblock .quoteblock p{color:inherit;font-size:1.0625rem}
.quoteblock.excerpt .attribution,.quoteblock .quoteblock .attribution{color:inherit;text-align:left;margin-right:0}
table.tableblock{max-width:100%;border-collapse:separate}
p.tableblock:last-child{margin-bottom:0}
td.tableblock>.content{margin-bottom:-1.25em}
table.tableblock,th.tableblock,td.tableblock{border:0 solid #dedede}
table.grid-all>thead>tr>.tableblock,table.grid-all>tbody>tr>.tableblock{border-width:0 1px 1px 0}
table.grid-all>tfoot>tr>.tableblock{border-width:1px 1px 0 0}
table.grid-cols>*>tr>.tableblock{border-width:0 1px 0 0}
table.grid-rows>thead>tr>.tableblock,table.grid-rows>tbody>tr>.tableblock{border-width:0 0 1px}
table.grid-rows>tfoot>tr>.tableblock{border-width:1px 0 0}
table.grid-all>*>tr>.tableblock:last-child,table.grid-cols>*>tr>.tableblock:last-child{border-right-width:0}
table.grid-all>tbody>tr:last-child>.tableblock,table.grid-all>thead:last-child>tr>.tableblock,table.grid-rows>tbody>tr:last-child>.tableblock,table.grid-rows>thead:last-child>tr>.tableblock{border-bottom-width:0}
table.frame-all{border-width:1px}
table.frame-sides{border-width:0 1px}
table.frame-topbot,table.frame-ends{border-width:1px 0}
table.stripes-all tr,table.stripes-odd tr:nth-of-type(odd){background:#f8f8f7}
table.stripes-none tr,table.stripes-odd tr:nth-of-type(even){background:none}
th.halign-left,td.halign-left{text-align:left}
th.halign-right,td.halign-right{text-align:right}
th.halign-center,td.halign-center{text-align:center}
th.valign-top,td.valign-top{vertical-align:top}
th.valign-bottom,td.valign-bottom{vertical-align:bottom}
th.valign-middle,td.valign-middle{vertical-align:middle}
table thead th,table tfoot th{font-weight:bold}
tbody tr th{display:table-cell;line-height:1.6;background:#f7f8f7}
tbody tr th,tbody tr th p,tfoot tr th,tfoot tr th p{color:rgba(0,0,0,.8);font-weight:bold}
p.tableblock>code:only-child{background:none;padding:0}
p.tableblock{font-size:1em}
td>div.verse{white-space:pre}
ol{margin-left:1.75em}
ul li ol{margin-left:1.5em}
dl dd{margin-left:1.125em}
dl dd:last-child,dl dd:last-child>:last-child{margin-bottom:0}
ol>li p,ul>li p,ul dd,ol dd,.olist .olist,.ulist .ulist,.ulist .olist,.olist .ulist{margin-bottom:.625em}
ul.checklist,ul.none,ol.none,ul.no-bullet,ol.no-bullet,ol.unnumbered,ul.unstyled,ol.unstyled{list-style-type:none}
ul.no-bullet,ol.no-bullet,ol.unnumbered{margin-left:.625em}
ul.unstyled,ol.unstyled{margin-left:0}
ul.checklist{margin-left:.625em}
ul.checklist li>p:first-child>.fa-square-o:first-child,ul.checklist li>p:first-child>.fa-check-square-o:first-child{width:1.25em;font-size:.8em;position:relative;bottom:.125em}
ul.checklist li>p:first-child>input[type="checkbox"]:first-child{margin-right:.25em}
ul.inline{display:-ms-flexbox;display:-webkit-box;display:flex;-ms-flex-flow:row wrap;-webkit-flex-flow:row wrap;flex-flow:row wrap;list-style:none;margin:0 0 .625em -1.25em}
ul.inline>li{margin-left:1.25em}
.unstyled dl dt{font-weight:400;font-style:normal}
ol.arabic{list-style-type:decimal}
ol.decimal{list-style-type:decimal-leading-zero}
ol.loweralpha{list-style-type:lower-alpha}
ol.upperalpha{list-style-type:upper-alpha}
ol.lowerroman{list-style-type:lower-roman}
ol.upperroman{list-style-type:upper-roman}
ol.lowergreek{list-style-type:lower-greek}
.hdlist>table,.colist>table{border:0;background:none}
.hdlist>table>tbody>tr,.colist>table>tbody>tr{background:none}
td.hdlist1,td.hdlist2{vertical-align:top;padding:0 .625em}
td.hdlist1{font-weight:bold;padding-bottom:1.25em}
.literalblock+.colist,.listingblock+.colist{margin-top:-.5em}
.colist td:not([class]):first-child{padding:.4em .75em 0;line-height:1;vertical-align:top}
.colist td:not([class]):first-child img{max-width:none}
.colist td:not([class]):last-child{padding:.25em 0}
.thumb,.th{line-height:0;display:inline-block;border:solid 4px #fff;-webkit-box-shadow:0 0 0 1px #ddd;box-shadow:0 0 0 1px #ddd}
.imageblock.left{margin:.25em .625em 1.25em 0}
.imageblock.right{margin:.25em 0 1.25em .625em}
.imageblock>.title{margin-bottom:0}
.imageblock.thumb,.imageblock.th{border-width:6px}
.imageblock.thumb>.title,.imageblock.th>.title{padding:0 .125em}
.image.left,.image.right{margin-top:.25em;margin-bottom:.25em;display:inline-block;line-height:0}
.image.left{margin-right:.625em}
.image.right{margin-left:.625em}
a.image{text-decoration:none;display:inline-block}
a.image object{pointer-events:none}
sup.footnote,sup.footnoteref{font-size:.875em;position:static;vertical-align:super}
sup.footnote a,sup.footnoteref a{text-decoration:none}
sup.footnote a:active,sup.footnoteref a:active{text-decoration:underline}
#footnotes{padding-top:.75em;padding-bottom:.75em;margin-bottom:.625em}
#footnotes hr{width:20%;min-width:6.25em;margin:-.25em 0 .75em;border-width:1px 0 0}
#footnotes .footnote{padding:0 .375em 0 .225em;line-height:1.3334;font-size:.875em;margin-left:1.2em;margin-bottom:.2em}
#footnotes .footnote a:first-of-type{font-weight:bold;text-decoration:none;margin-left:-1.05em}
#footnotes .footnote:last-of-type{margin-bottom:0}
#content #footnotes{margin-top:-.625em;margin-bottom:0;padding:.75em 0}
.gist .file-data>table{border:0;background:#fff;width:100%;margin-bottom:0}
.gist .file-data>table td.line-data{width:99%}
div.unbreakable{page-break-inside:avoid}
.big{font-size:larger}
.small{font-size:smaller}
.underline{text-decoration:underline}
.overline{text-decoration:overline}
.line-through{text-decoration:line-through}
.aqua{color:#00bfbf}
.aqua-background{background-color:#00fafa}
.black{color:#000}
.black-background{background-color:#000}
.blue{color:#0000bf}
.blue-background{background-color:#0000fa}
.fuchsia{color:#bf00bf}
.fuchsia-background{background-color:#fa00fa}
.gray{color:#606060}
.gray-background{background-color:#7d7d7d}
.green{color:#006000}
.green-background{background-color:#007d00}
.lime{color:#00bf00}
.lime-background{background-color:#00fa00}
.maroon{color:#600000}
.maroon-background{background-color:#7d0000}
.navy{color:#000060}
.navy-background{background-color:#00007d}
.olive{color:#606000}
.olive-background{background-color:#7d7d00}
.purple{color:#600060}
.purple-background{background-color:#7d007d}
.red{color:#bf0000}
.red-background{background-color:#fa0000}
.silver{color:#909090}
.silver-background{background-color:#bcbcbc}
.teal{color:#006060}
.teal-background{background-color:#007d7d}
.white{color:#bfbfbf}
.white-background{background-color:#fafafa}
.yellow{color:#bfbf00}
.yellow-background{background-color:#fafa00}
span.icon>.fa{cursor:default}
a span.icon>.fa{cursor:inherit}
.admonitionblock td.icon [class^="fa icon-"]{font-size:2.5em;text-shadow:1px 1px 2px rgba(0,0,0,.5);cursor:default}
.admonitionblock td.icon .icon-note::before{content:"\f05a";color:#19407c}
.admonitionblock td.icon .icon-tip::before{content:"\f0eb";text-shadow:1px 1px 2px rgba(155,155,0,.8);color:#111}
.admonitionblock td.icon .icon-warning::before{content:"\f071";color:#bf6900}
.admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#bf3400}
.admonitionblock td.icon .icon-important::before{content:"\f06a";color:#bf0000}
.conum[data-value]{display:inline-block;color:#fff!important;background-color:rgba(0,0,0,.8);-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
.conum[data-value] *{color:#fff!important}
.conum[data-value]+b{display:none}
.conum[data-value]::after{content:attr(data-value)}
pre .conum[data-value]{position:relative;top:-.125em}
b.conum *{color:inherit!important}
.conum:not([data-value]):empty{display:none}
dt,th.tableblock,td.content,div.footnote{text-rendering:optimizeLegibility}
h1,h2,p,td.content,span.alt{letter-spacing:-.01em}
p strong,td.content strong,div.footnote strong{letter-spacing:-.005em}
p,blockquote,dt,td.content,span.alt{font-size:1.0625rem}
p{margin-bottom:1.25rem}
.sidebarblock p,.sidebarblock dt,.sidebarblock td.content,p.tableblock{font-size:1em}
.exampleblock>.content{background-color:#fffef7;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc}
.print-only{display:none!important}
@page{margin:1.25cm .75cm}
@media print{*{-webkit-box-shadow:none!important;box-shadow:none!important;text-shadow:none!important}
html{font-size:80%}
a{color:inherit!important;text-decoration:underline!important}
a.bare,a[href^="#"],a[href^="mailto:"]{text-decoration:none!important}
a[href^="http:"]:not(.bare)::after,a[href^="https:"]:not(.bare)::after{content:"(" attr(href) ")";display:inline-block;font-size:.875em;padding-left:.25em}
abbr[title]::after{content:" (" attr(title) ")"}
pre,blockquote,tr,img,object,svg{page-break-inside:avoid}
thead{display:table-header-group}
svg{max-width:100%}
p,blockquote,dt,td.content{font-size:1em;orphans:3;widows:3}
h2,h3,#toctitle,.sidebarblock>.content>.title{page-break-after:avoid}
#toc,.sidebarblock,.exampleblock>.content{background:none!important}
#toc{border-bottom:1px solid #dddddf!important;padding-bottom:0!important}
body.book #header{text-align:center}
body.book #header>h1:first-child{border:0!important;margin:2.5em 0 1em}
body.book #header .details{border:0!important;display:block;padding:0!important}
body.book #header .details span:first-child{margin-left:0!important}
body.book #header .details br{display:block}
body.book #header .details br+span::before{content:none!important}
body.book #toc{border:0!important;text-align:left!important;padding:0!important;margin:0!important}
body.book #toc,body.book #preamble,body.book h1.sect0,body.book .sect1>h2{page-break-before:always}
.listingblock code[data-lang]::before{display:block}
#footer{padding:0 .9375em}
.hide-on-print{display:none!important}
.print-only{display:block!important}
.hide-for-print{display:none!important}
.show-for-print{display:inherit!important}}
@media print,amzn-kf8{#header>h1:first-child{margin-top:1.25rem}
.sect1{padding:0!important}
.sect1+.sect1{border:0}
#footer{background:none}
#footer-text{color:rgba(0,0,0,.6);font-size:.9em}}
@media amzn-kf8{#header,#content,#footnotes,#footer{padding:0}}
/* Zajo's customizations applied on top of the standard asciidoctor css above */
h1{font-size:4em}
h2{font-size:1.74em}
h3,#toctitle,.sidebarblock>.content>.title{font-size:1.5em}
h4{font-size:1.2em}
h5{font-size:1em}
h6{font-size:1em}
#toc {text-align:left}
#toc ul code{font-size:111%}
#toc a:hover code {color:#4101a7}
a:focus{outline:0}
.colist td{color:rgba(0,0,0,.67)}
body{text-align:left; background:#fff;color:rgba(0,0,0,.67);padding:0;margin:0;font-family:"Istok Web","DejaVu Serif",serif;font-weight:400;font-style:normal;line-height:1;position:relative;cursor:auto;tab-size:4;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}
.subheader,.admonitionblock td.content>.title,.audioblock>.title,.exampleblock>.title,.imageblock>.title,.listingblock>.title,.literalblock>.title,.stemblock>.title,.openblock>.title,.paragraph>.title,.quoteblock>.title,table.tableblock>.title,.verseblock>.title,.videoblock>.title,.dlist>.title,.olist>.title,.ulist>.title,.qlist>.title,.hdlist>.title{line-height:1.45;color:#a0a0a0;font-weight:400;margin-top:0;margin-bottom:.25em}
a{color:#000000;text-decoration:underline;line-height:inherit}
a:hover{color:#4101a7}
a:focus{color:#000000}
h1,h2,h3,#toctitle,.sidebarblock>.content>.title,h4,h5,h6{font-family:"Quicksand","DejaVu Sans",sans-serif;font-weight:300;font-style:normal;color:#4101a7;text-rendering:optimizeLegibility;margin-top:1em;margin-bottom:.5em;line-height:1.4em}
code{font-family:"Anonymous Pro","DejaVu Sans Mono",monospace;font-weight:400;color:black}
*:not(pre)>code{font-size:1.0em;font-style:normal!important;letter-spacing:0;padding:0 0;word-spacing:-.15em;background-color:transparent;-webkit-border-radius:0;border-radius:0;line-height:1.45;text-rendering:optimizeLegibility;word-wrap:break-word}
pre,pre>code{line-height:1.45;color:rgba(0,0,0,.9);font-family:"Anonymous Pro","DejaVu Sans Mono",monospace;font-weight:400;text-rendering:optimizeLegibility;font-size:1.05em;background-color:#f7f8f7}
a:not(pre)>code:hover {color:#4101a7}
kbd{font-family:"Anonymous Pro","DejaVu Sans Mono",monospace;display:inline-block;color:rgba(0,0,0,.8);font-size:.65em;line-height:1.45;background-color:#f7f7f7;border:1px solid #ccc;-webkit-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em white inset;box-shadow:0 1px 0 rgba(0,0,0,.2),0 0 0 .1em #fff inset;margin:0 .15em;padding:.2em .5em;vertical-align:middle;position:relative;top:-.1em;white-space:nowrap}
h1 code{color:#4101a7; font-size:113%}
h2 code{color:#4101a7; font-size:113%}
h3 code{color:#4101a7; font-size:113%}
h4 code{color:#4101a7; font-size:113%}
h5 code{color:#4101a7; font-size:113%}
#header>h1:first-child{font-family:"Poiret One";color:#ff5100;margin-top:2.25rem;margin-bottom:0;letter-spacing:-.07em}
#author{color: #4101a7;}
#toc ul{font-family:"Quicksand","DejaVu Sans",sans-serif;list-style-type:none}
#toc a:hover{color:#4101a7}
#toc.toc2{background-color:#f7f8f7}
.admonitionblock td.icon .icon-note::before{content:"\f05a";color:#606060}
.admonitionblock td.icon .icon-tip::before{content:"\f0eb";color:#606060;text-shadow:none}
.admonitionblock td.icon .icon-warning::before{content:"\f071";color:#ff5100}
.admonitionblock td.icon .icon-caution::before{content:"\f06d";color:#ff5100}
.admonitionblock td.icon .icon-important::before{content:"\f06a";color:#ff5100}
.conum[data-value]{display:inline-block;color:#fff!important;background-color:#606060;-webkit-border-radius:100px;border-radius:100px;text-align:center;font-size:.75em;width:1.67em;height:1.67em;line-height:1.67em;font-family:"Open Sans","DejaVu Sans",sans-serif;font-style:normal;font-weight:bold}
.exampleblock>.content{background-color:#ffffff;border-color:#e0e0dc;-webkit-box-shadow:0 1px 4px #e0e0dc;box-shadow:0 1px 4px #e0e0dc}
.quoteblock blockquote::before{margin-left:-.8em;color:#4101a7}
.quoteblock blockquote{font-family:"Istok Web","DejaVu Serif"; font-size:1.0625rem; padding:0.5em}
.text-right{margin-top:-1em}

View File

@@ -3,13 +3,13 @@
### Synopsis
Defined in `<boost/openmethod/compiler.hpp>`.
Defined in `<boost/openmethod/initialize.hpp>`.
```c++
namespace boost::openmethod {
template<class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY>
auto compiler<Policy>::initialize() -> /*unspecified*/;
template<class Policy = BOOST_OPENMETHOD_DEFAULT_REGISTRY>
auto initialize() -> /*unspecified*/;
}
```
@@ -37,12 +37,12 @@ combination of virtual arguments.
### Synopsis
Defined in `<boost/openmethod/compiler.hpp>`.
Defined in `<boost/openmethod/initialize.hpp>`.
```c++
namespace boost::openmethod {
template<class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY>
template<class Policy = BOOST_OPENMETHOD_DEFAULT_REGISTRY>
auto finalize() -> void;
}
@@ -51,7 +51,7 @@ auto finalize() -> void;
### Description
De-allocates the resources allocated by `initialize` for the `Policy`, including
resources allocated by the facets in `Policy`. Resources are de-allocated in an
resources allocated by the policys in `Policy`. Resources are de-allocated in an
arbitrary order. It is not necessary to call `finalize` between calls to
`initialize`. It is provided mainly for the benefit of memory leak detection
schemes.

View File

@@ -9,11 +9,11 @@ the Expression Problem:
to add new operations on the existing types, and new types to the existing
operations, without modifying existing code?
Open-methods also address the banana-gorilla-jungle problem:
Open-methods also address the banana-gorilla-shared problem:
> The problem with object-oriented languages is theyve got all this implicit
environment that they carry around with them. You wanted a banana but what you
got was a gorilla holding the banana and the entire jungle. — Joe Armstrong,
got was a gorilla holding the banana and the entire shared. — Joe Armstrong,
creator of Erlang progamming language
As a bonus, open-methods can take more than one argument into account when

57
doc/local-playbook.yml Normal file
View File

@@ -0,0 +1,57 @@
#
# Copyright (c) 2023 Alan de Freitas (alandefreitas@gmail.com)
#
# 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)
#
# Official repository: https://github.com/boostorg/openmethod
#
# An antora playbook used for local development
# The playbook includes Boost.OpenMethod as its only component
site:
title: Boost.OpenMethod
url: https://antora.cppalliance.org/develop/lib/doc
start_page: openmethod::index.adoc
robots: allow
keys:
repo_url: 'https://github.com/boostorg/openmethod'
content:
sources:
- url: ..
start_path: doc
edit_url: 'https://github.com/boostorg/openmethod/edit/{refname}/{path}'
ui:
bundle:
url: https://github.com/boostorg/website-v2-docs/releases/download/ui-master/ui-bundle.zip
snapshot: true
output:
dir: html
antora:
extensions:
- require: '@antora/lunr-extension' # https://gitlab.com/antora/antora-lunr-extension
index_latest_only: true
- require: '@cppalliance/antora-cpp-tagfiles-extension'
cpp-tagfiles:
using-namespaces:
- 'boost::'
- require: '@cppalliance/antora-cpp-reference-extension'
dependencies:
- name: 'boost'
repo: 'https://github.com/boostorg/boost.git'
tag: 'develop'
variable: 'BOOST_SRC_DIR'
system-env: 'BOOST_SRC_DIR'
asciidoc:
attributes:
# Enable pagination
page-pagination: ''
extensions:
- '@cppalliance/asciidoctor-boost-links'
- '@asciidoctor/tabs'

View File

@@ -9,7 +9,7 @@ namespace boost::openmethod {
template<
typename Method, typename ReturnType,
class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY>
class Policy = BOOST_OPENMETHOD_DEFAULT_REGISTRY>
class method;
template<typename Name, typename... Parameters, typename ReturnType, class Policy>

View File

@@ -15,13 +15,13 @@ struct minimal_rtti : rtti {
### Description
`minimal_rtti` is an implementation of the `rtti` facet that only uses static
`minimal_rtti` is an implementation of the `rtti` policy that only uses static
type information.
`minimal_rtti` provides the only function strictly required for the `rtti`
facet.
policy.
This facet can be used in programs that call methods solely via
This policy can be used in programs that call methods solely via
`virtual_ptr`{empty}s created with the "final" constructs. Virtual inheritance
is not supported. Classes are not required to be polymorphic.
@@ -35,7 +35,7 @@ template<class Class>
static constexpr bool is_polymorphic = false;
```
This facet does not support polymorphic classes.
This policy does not support polymorphic classes.
#### static_type

View File

@@ -0,0 +1,66 @@
# Copyright (c) 2018-2024 Jean-Louis Leroy
# 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)
message(STATUS "Boost.OpenMethod: building examples")
if (CMAKE_BUILD_TYPE STREQUAL "Release")
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-save-temps=obj -masm=intel)
endif()
endif()
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
add_compile_definitions(BOOST_OPENMETHOD_ENABLE_RUNTIME_CHECKS)
endif()
file(GLOB cpp_files "*.cpp")
foreach (cpp ${cpp_files})
get_filename_component(stem ${cpp} NAME_WE)
set(test_target "boost_openmethod-${stem}")
add_executable(${test_target} ${cpp})
target_link_libraries(${test_target} PRIVATE Boost::openmethod Boost::unit_test_framework)
add_test(NAME ${test_target} COMMAND ${test_target})
add_dependencies(tests ${test_target})
endforeach()
function(boost_openmethod_add_step_by_step dir)
set(add_test "")
if(ARGC GREATER 1)
set(add_test "${ARGV1}")
else()
set(add_test "ON")
endif()
file(GLOB subdirs "${dir}/*")
foreach (subdir ${subdirs})
string(REGEX REPLACE ".*/" "" subex ${subdir})
file(GLOB cpp_files "${subdir}/*.cpp")
set(target "boost_openmethod-${dir}_${subex}")
add_executable(${target} ${cpp_files})
target_link_libraries(${target} PRIVATE Boost::openmethod)
set(output_dir openmethod/${dir}/${subex})
set_target_properties(${target} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${output_dir}"
LIBRARY_OUTPUT_DIRECTORY "${output_dir}"
ARCHIVE_OUTPUT_DIRECTORY "${output_dir}"
)
if(${add_test})
add_test(NAME "${target}" COMMAND "${target}")
endif()
add_dependencies(tests "${target}")
endforeach()
endfunction()
boost_openmethod_add_step_by_step(rolex)
boost_openmethod_add_step_by_step(ambiguities OFF)
boost_openmethod_add_step_by_step(core_api)
boost_openmethod_add_step_by_step(custom_rtti)
boost_openmethod_add_step_by_step(virtual_ptr_alt)
if (NOT WIN32)
add_subdirectory(shared_libs)
endif()

View File

@@ -8,11 +8,10 @@
#include <string>
#include <boost/openmethod.hpp>
#include <boost/openmethod/shared_ptr.hpp>
#include <boost/openmethod/compiler.hpp>
#include <boost/openmethod/interop/std_shared_ptr.hpp>
#include <boost/openmethod/initialize.hpp>
using boost::openmethod::make_shared_virtual;
using boost::openmethod::shared_virtual_ptr;
using namespace boost::openmethod::aliases;
using std::cout;
using std::string;
@@ -42,8 +41,8 @@ struct Times : Node {
shared_virtual_ptr<const Node> left, right;
};
struct Integer : Node {
explicit Integer(int value) : value(value) {
struct Variable : Node {
explicit Variable(int value) : value(value) {
}
int value;
};
@@ -51,23 +50,23 @@ struct Integer : Node {
// =============================================================================
// add behavior to existing classes, without changing them
BOOST_OPENMETHOD_CLASSES(Node, Plus, Times, Integer);
BOOST_OPENMETHOD_CLASSES(Node, Plus, Times, Variable);
// -----------------------------------------------------------------------------
// evaluate
BOOST_OPENMETHOD(value, (virtual_ptr<const Node>), int);
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<const Plus> expr), int) {
return value(expr->left) + value(expr->right);
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<const Plus> node), int) {
return value(node->left) + value(node->right);
}
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<const Times> expr), int) {
return value(expr->left) * value(expr->right);
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<const Times> node), int) {
return value(node->left) * value(node->right);
}
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<const Integer> expr), int) {
return expr->value;
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<const Variable> node), int) {
return node->value;
}
// -----------------------------------------------------------------------------
@@ -75,16 +74,16 @@ BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<const Integer> expr), int) {
BOOST_OPENMETHOD(as_forth, (virtual_ptr<const Node>), string);
BOOST_OPENMETHOD_OVERRIDE(as_forth, (virtual_ptr<const Plus> expr), string) {
return as_forth(expr->left) + " " + as_forth(expr->right) + " +";
BOOST_OPENMETHOD_OVERRIDE(as_forth, (virtual_ptr<const Plus> node), string) {
return as_forth(node->left) + " " + as_forth(node->right) + " +";
}
BOOST_OPENMETHOD_OVERRIDE(as_forth, (virtual_ptr<const Times> expr), string) {
return as_forth(expr->left) + " " + as_forth(expr->right) + " *";
BOOST_OPENMETHOD_OVERRIDE(as_forth, (virtual_ptr<const Times> node), string) {
return as_forth(node->left) + " " + as_forth(node->right) + " *";
}
BOOST_OPENMETHOD_OVERRIDE(as_forth, (virtual_ptr<const Integer> expr), string) {
return std::to_string(expr->value);
BOOST_OPENMETHOD_OVERRIDE(as_forth, (virtual_ptr<const Variable> node), string) {
return std::to_string(node->value);
}
// -----------------------------------------------------------------------------
@@ -92,16 +91,16 @@ BOOST_OPENMETHOD_OVERRIDE(as_forth, (virtual_ptr<const Integer> expr), string) {
BOOST_OPENMETHOD(as_lisp, (virtual_ptr<const Node>), string);
BOOST_OPENMETHOD_OVERRIDE(as_lisp, (virtual_ptr<const Plus> expr), string) {
return "(plus " + as_lisp(expr->left) + " " + as_lisp(expr->right) + ")";
BOOST_OPENMETHOD_OVERRIDE(as_lisp, (virtual_ptr<const Plus> node), string) {
return "(plus " + as_lisp(node->left) + " " + as_lisp(node->right) + ")";
}
BOOST_OPENMETHOD_OVERRIDE(as_lisp, (virtual_ptr<const Times> expr), string) {
return "(times " + as_lisp(expr->left) + " " + as_lisp(expr->right) + ")";
BOOST_OPENMETHOD_OVERRIDE(as_lisp, (virtual_ptr<const Times> node), string) {
return "(times " + as_lisp(node->left) + " " + as_lisp(node->right) + ")";
}
BOOST_OPENMETHOD_OVERRIDE(as_lisp, (virtual_ptr<const Integer> expr), string) {
return std::to_string(expr->value);
BOOST_OPENMETHOD_OVERRIDE(as_lisp, (virtual_ptr<const Variable> node), string) {
return std::to_string(node->value);
}
// -----------------------------------------------------------------------------
@@ -109,14 +108,14 @@ BOOST_OPENMETHOD_OVERRIDE(as_lisp, (virtual_ptr<const Integer> expr), string) {
auto main() -> int {
boost::openmethod::initialize();
shared_virtual_ptr<Node> expr = make_shared_virtual<Times>(
make_shared_virtual<Integer>(2),
shared_virtual_ptr<Node> node = make_shared_virtual<Times>(
make_shared_virtual<Variable>(2),
make_shared_virtual<Plus>(
make_shared_virtual<Integer>(3), make_shared_virtual<Integer>(4)));
make_shared_virtual<Variable>(3), make_shared_virtual<Variable>(4)));
cout << as_forth(expr) << " = " << as_lisp(expr) << " = " << value(expr)
cout << as_forth(node) << " = " << as_lisp(node) << " = " << value(node)
<< "\n";
// error_output:
// output:
// 2 3 4 + * = (times 2 (plus 3 4)) = 14
return 0;

View File

@@ -8,7 +8,9 @@
#include <string>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
#include <boost/openmethod/initialize.hpp>
using boost::openmethod::virtual_ptr;
struct Character {
virtual ~Character() {
@@ -42,35 +44,31 @@ BOOST_OPENMETHOD(
std::string);
BOOST_OPENMETHOD_OVERRIDE(
fight,
(virtual_ptr<Character> x, virtual_ptr<Creature> y, virtual_ptr<Banana> z),
fight, (virtual_ptr<Character>, virtual_ptr<Creature>, virtual_ptr<Banana>),
std::string) {
return "are you insane?";
}
BOOST_OPENMETHOD_OVERRIDE(
fight,
(virtual_ptr<Character> x, virtual_ptr<Creature> y, virtual_ptr<Axe> z),
fight, (virtual_ptr<Character>, virtual_ptr<Creature>, virtual_ptr<Axe>),
std::string) {
return "not agile enough to wield";
}
BOOST_OPENMETHOD_OVERRIDE(
fight,
(virtual_ptr<Warrior> x, virtual_ptr<Creature> y, virtual_ptr<Axe> z),
fight, (virtual_ptr<Warrior>, virtual_ptr<Creature>, virtual_ptr<Axe>),
std::string) {
return "and cuts it into pieces";
}
BOOST_OPENMETHOD_OVERRIDE(
fight, (virtual_ptr<Warrior> x, virtual_ptr<Dragon> y, virtual_ptr<Axe> z),
fight, (virtual_ptr<Warrior>, virtual_ptr<Dragon>, virtual_ptr<Axe>),
std::string) {
return "and dies a honorable death";
}
BOOST_OPENMETHOD_OVERRIDE(
fight,
(virtual_ptr<Character> x, virtual_ptr<Dragon> y, virtual_ptr<Hands> z),
fight, (virtual_ptr<Character>, virtual_ptr<Dragon>, virtual_ptr<Hands>),
std::string) {
return "Congratulations! You have just vainquished a dragon with your bare "
"hands"

View File

@@ -0,0 +1,38 @@
// Copyright (c) 2018-2025 Jean-Louis Leroy
// 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)
// clang-format off
// tag::content[]
#include <boost/openmethod.hpp>
#include <boost/openmethod/initialize.hpp>
#include <iostream>
struct Matrix { virtual ~Matrix() = default; };
struct DenseMatrix : Matrix {};
struct SparseMatrix : Matrix {};
BOOST_OPENMETHOD_CLASSES(Matrix, DenseMatrix, SparseMatrix);
using boost::openmethod::virtual_ptr;
BOOST_OPENMETHOD(
add, (virtual_ptr<const Matrix>, virtual_ptr<const Matrix>), void);
BOOST_OPENMETHOD_OVERRIDE(
add, (virtual_ptr<const Matrix>, virtual_ptr<const SparseMatrix>), void) {
}
BOOST_OPENMETHOD_OVERRIDE(
add, (virtual_ptr<const SparseMatrix>, virtual_ptr<const Matrix>), void) {
}
int main() {
boost::openmethod::initialize();
SparseMatrix a, b;
add(a, b);
}
// end::content[]

View File

@@ -0,0 +1,42 @@
// Copyright (c) 2018-2025 Jean-Louis Leroy
// 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)
// clang-format off
#include <boost/openmethod.hpp>
#include <boost/openmethod/initialize.hpp>
#include <iostream>
struct Matrix { virtual ~Matrix() = default; };
struct DenseMatrix : Matrix {};
struct SparseMatrix : Matrix {};
BOOST_OPENMETHOD_CLASSES(Matrix, DenseMatrix, SparseMatrix);
using boost::openmethod::virtual_ptr;
BOOST_OPENMETHOD(
add, (virtual_ptr<const Matrix>, virtual_ptr<const Matrix>), void);
BOOST_OPENMETHOD_OVERRIDE(
add, (virtual_ptr<const Matrix>, virtual_ptr<const SparseMatrix>), void) {
}
BOOST_OPENMETHOD_OVERRIDE(
add, (virtual_ptr<const SparseMatrix>, virtual_ptr<const Matrix>), void) {
}
// tag::content[]
BOOST_OPENMETHOD_OVERRIDE(
add, (virtual_ptr<const SparseMatrix>, virtual_ptr<const SparseMatrix>), void) {
}
// end::content[]
int main() {
boost::openmethod::initialize();
SparseMatrix a, b;
add(a, b);
}

View File

@@ -0,0 +1,90 @@
// Copyright (c) 2018-2025 Jean-Louis Leroy
// 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)
// clang-format off
// tag::content[]
struct Node {
virtual ~Node() {}
virtual int value() const = 0;
};
struct Variable : Node {
Variable(int value) : v(value) {}
int value() const override { return v; }
int v;
};
struct Plus : Node {
Plus(const Node& left, const Node& right) : left(left), right(right) {}
int value() const override { return left.value() + right.value(); }
const Node& left; const Node& right;
};
struct Times : Node {
Times(const Node& left, const Node& right) : left(left), right(right) {}
int value() const override { return left.value() * right.value(); }
const Node& left; const Node& right;
};
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// library code
// =============================================================================
// application code
// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
#include <boost/openmethod.hpp>
#include <boost/openmethod/initialize.hpp>
#include <iostream>
using boost::openmethod::virtual_ptr;
BOOST_OPENMETHOD(postfix, (virtual_ptr<const Node> node, std::ostream& os), void);
// tag::variable_overrider[]
BOOST_OPENMETHOD_OVERRIDE(
postfix, (virtual_ptr<const Variable> var, std::ostream& os), void) {
os << var->v;
}
// end::variable_overrider[]
// tag::plus_overrider[]
BOOST_OPENMETHOD_OVERRIDE(
postfix, (virtual_ptr<const Plus> plus, std::ostream& os), void) {
postfix(plus->left, os);
os << ' ';
postfix(plus->right, os);
os << " +";
}
// end::plus_overrider[]
BOOST_OPENMETHOD_OVERRIDE(
postfix, (virtual_ptr<const Times> times, std::ostream& os), void) {
postfix(times->left, os);
os << ' ';
postfix(times->right, os);
os << " *";
}
// tag::class_registration[]
BOOST_OPENMETHOD_CLASSES(Node, Variable, Plus, Times);
// end::class_registration[]
int main() {
boost::openmethod::initialize();
Variable a{2}, b{3}, c{4};
Plus d{a, b}; Times e{d, c};
postfix(e, std::cout);
std::cout << " = " << e.value() << "\n"; // 2 3 + 4 * = 20
}
// end::content[]
void call_via_ref(const Node& node, std::ostream& os) {
postfix(node, os);
}
void call_via_virtual_ptr(virtual_ptr<const Node> node, std::ostream& os) {
postfix(node, os);
}

View File

@@ -0,0 +1,86 @@
// Copyright (c) 2018-2025 Jean-Louis Leroy
// 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)
// clang-format off
// tag::content[]
#include <boost/openmethod.hpp>
using namespace boost::openmethod::aliases;
struct Node {
};
struct Variable : Node {
Variable(int value) : v(value) {}
int v;
};
struct Plus : Node {
Plus(virtual_ptr<const Node> left, virtual_ptr<const Node> right)
: left(left), right(right) {}
virtual_ptr<const Node> left, right;
};
struct Times : Node {
Times(virtual_ptr<const Node> left, virtual_ptr<const Node> right)
: left(left), right(right) {}
virtual_ptr<const Node> left, right;
};
#include <iostream>
using boost::openmethod::virtual_ptr;
BOOST_OPENMETHOD(value, (virtual_ptr<const Node>), int);
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<const Variable> node), int) {
return node->v;
}
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<const Plus> node), int) {
return value(node->left) + value(node->right);
}
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<const Times> node), int) {
return value(node->left) * value(node->right);
}
BOOST_OPENMETHOD(postfix, (virtual_ptr<const Node> node, std::ostream& os), void);
BOOST_OPENMETHOD_OVERRIDE(
postfix, (virtual_ptr<const Variable> var, std::ostream& os), void) {
os << var->v;
}
BOOST_OPENMETHOD_OVERRIDE(
postfix, (virtual_ptr<const Plus> plus, std::ostream& os), void) {
postfix(plus->left, os);
os << ' ';
postfix(plus->right, os);
os << " +";
}
BOOST_OPENMETHOD_OVERRIDE(
postfix, (virtual_ptr<const Times> times, std::ostream& os), void) {
postfix(times->left, os);
os << ' ';
postfix(times->right, os);
os << " *";
}
BOOST_OPENMETHOD_CLASSES(Node, Variable, Plus, Times);
#include <boost/openmethod/initialize.hpp>
int main() {
boost::openmethod::initialize();
Variable a{2}, b{3}, c{4};
Plus d{final_virtual_ptr(a), final_virtual_ptr(b)};
Times e{final_virtual_ptr(d), final_virtual_ptr(c)};
auto root = final_virtual_ptr(e);
postfix(root, std::cout);
std::cout << " = " << value(root) << "\n"; // 2 3 + 4 * = 20
}
// end::content[]

View File

@@ -0,0 +1,80 @@
// Copyright (c) 2018-2025 Jean-Louis Leroy
// 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)
// clang-format off
// tag::content[]
#include <boost/openmethod.hpp>
#include <boost/openmethod/interop/std_unique_ptr.hpp>
using namespace boost::openmethod::aliases;
struct Node {
virtual ~Node() {}
virtual int value() const = 0;
};
struct Variable : Node {
Variable(int value) : v(value) {}
int value() const override { return v; }
int v;
};
struct Plus : Node {
Plus(unique_virtual_ptr<const Node> left, unique_virtual_ptr<const Node> right)
: left(std::move(left)), right(std::move(right)) {}
int value() const override { return left->value() + right->value(); }
unique_virtual_ptr<const Node> left, right;
};
struct Times : Node {
Times(unique_virtual_ptr<const Node> left, unique_virtual_ptr<const Node> right)
: left(std::move(left)), right(std::move(right)) {}
int value() const override { return left->value() * right->value(); }
unique_virtual_ptr<const Node> left, right;
};
#include <iostream>
BOOST_OPENMETHOD(postfix, (virtual_ptr<const Node> node, std::ostream& os), void);
BOOST_OPENMETHOD_OVERRIDE(
postfix, (virtual_ptr<const Variable> var, std::ostream& os), void) {
os << var->v;
}
BOOST_OPENMETHOD_OVERRIDE(
postfix, (virtual_ptr<const Plus> plus, std::ostream& os), void) {
postfix(plus->left, os);
os << ' ';
postfix(plus->right, os);
os << " +";
}
BOOST_OPENMETHOD_OVERRIDE(
postfix, (virtual_ptr<const Times> times, std::ostream& os), void) {
postfix(times->left, os);
os << ' ';
postfix(times->right, os);
os << " *";
}
BOOST_OPENMETHOD_CLASSES(Node, Variable, Plus, Times);
#include <boost/openmethod/initialize.hpp>
int main() {
boost::openmethod::initialize();
auto a = std::make_unique<Variable>(2);
auto b = std::make_unique<Variable>(3);
auto c = std::make_unique<Variable>(4);
auto d = make_unique_virtual<Plus>(std::move(a), std::move(b));
auto e = make_unique_virtual<Times>(std::move(d), std::move(c));
postfix(e, std::cout);
std::cout << " = " << e->value() << "\n"; // 2 3 + 4 * = 20
}
// end::content[]

View File

@@ -0,0 +1,39 @@
// Copyright (c) 2018-2025 Jean-Louis Leroy
// 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)
// clang-format off
// tag::content[]
#include <iostream>
struct Node {
virtual ~Node() {}
virtual int value() const = 0;
};
struct Variable : Node {
Variable(int value) : v(value) {}
int value() const override { return v; }
int v;
};
struct Plus : Node {
Plus(const Node& left, const Node& right) : left(left), right(right) {}
int value() const override { return left.value() + right.value(); }
const Node& left; const Node& right;
};
struct Times : Node {
Times(const Node& left, const Node& right) : left(left), right(right) {}
int value() const override { return left.value() * right.value(); }
const Node& left; const Node& right;
};
int main() {
Variable a{2}, b{3}, c{4};
Plus d{a, b}; Times e{d, c};
std::cout << e.value() << "\n"; // 20
}
// end::content[]

View File

@@ -0,0 +1,52 @@
// Copyright (c) 2018-2025 Jean-Louis Leroy
// 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)
// clang-format off
// tag::all[]
#include <iostream>
struct Node {
virtual ~Node() {}
virtual int value() const = 0;
virtual void postfix(std::ostream& os) const = 0;
};
struct Variable : Node {
Variable(int value) : v(value) {}
int value() const override { return v; }
virtual void postfix(std::ostream& os) const override { os << v; }
int v;
};
struct Plus : Node {
Plus(const Node& left, const Node& right) : left(left), right(right) {}
int value() const override { return left.value() + right.value(); }
void postfix(std::ostream& os) const override {
left.postfix(os); os << ' '; right.postfix(os); os << " +";
}
const Node& left; const Node& right;
};
struct Times : Node {
Times(const Node& left, const Node& right) : left(left), right(right) {}
int value() const override { return left.value() * right.value(); }
void postfix(std::ostream& os) const override {
left.postfix(os); os << ' '; right.postfix(os); os << " *";
}
const Node& left; const Node& right;
};
int main() {
Variable a{2}, b{3}, c{4};
Plus d{a, b}; Times e{d, c};
e.postfix(std::cout);
std::cout << " = " << e.value() << "\n"; // 2 3 + 4 * = 20
}
// end::all[]
void call_virtual_function(const Node& node, std::ostream& os) {
node.postfix(os);
}

View File

@@ -0,0 +1,75 @@
// Copyright (c) 2018-2025 Jean-Louis Leroy
// 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)
// clang-format off
// tag::content[]
#include <boost/openmethod.hpp>
using boost::openmethod::virtual_ptr;
struct Node {
virtual ~Node() {}
virtual int value() const = 0;
};
struct Variable : Node {
Variable(int value) : v(value) {}
int value() const override { return v; }
int v;
};
struct Plus : Node {
Plus(virtual_ptr<const Node> left, virtual_ptr<const Node> right)
: left(left), right(right) {}
int value() const override { return left->value() + right->value(); }
virtual_ptr<const Node> left, right;
};
struct Times : Node {
Times(virtual_ptr<const Node> left, virtual_ptr<const Node> right)
: left(left), right(right) {}
int value() const override { return left->value() * right->value(); }
virtual_ptr<const Node> left, right;
};
#include <iostream>
using boost::openmethod::virtual_ptr;
BOOST_OPENMETHOD(postfix, (virtual_ptr<const Node> node, std::ostream& os), void);
BOOST_OPENMETHOD_OVERRIDE(
postfix, (virtual_ptr<const Variable> var, std::ostream& os), void) {
os << var->v;
}
BOOST_OPENMETHOD_OVERRIDE(
postfix, (virtual_ptr<const Plus> plus, std::ostream& os), void) {
postfix(plus->left, os);
os << ' ';
postfix(plus->right, os);
os << " +";
}
BOOST_OPENMETHOD_OVERRIDE(
postfix, (virtual_ptr<const Times> times, std::ostream& os), void) {
postfix(times->left, os);
os << ' ';
postfix(times->right, os);
os << " *";
}
BOOST_OPENMETHOD_CLASSES(Node, Variable, Plus, Times);
#include <boost/openmethod/initialize.hpp>
int main() {
boost::openmethod::initialize();
Variable a{2}, b{3}, c{4};
Plus d{a, b}; Times e{d, c};
postfix(e, std::cout);
std::cout << " = " << e.value() << "\n"; // 2 3 + 4 * = 20
}
// end::content[]

View File

@@ -7,7 +7,9 @@
// Example for Wikipedia
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
#include <boost/openmethod/initialize.hpp>
using boost::openmethod::virtual_ptr;
class Thing {
public:
@@ -24,31 +26,32 @@ BOOST_OPENMETHOD_CLASSES(Thing, Spaceship, Asteroid);
BOOST_OPENMETHOD(collideWith, (virtual_ptr<Thing>, virtual_ptr<Thing>), void);
BOOST_OPENMETHOD_OVERRIDE(
collideWith, (virtual_ptr<Thing> left, virtual_ptr<Thing> right), void) {
collideWith, (virtual_ptr<Thing> /*left*/, virtual_ptr<Thing> /*right*/),
void) {
// default collision handling
}
BOOST_OPENMETHOD_OVERRIDE(
collideWith, (virtual_ptr<Asteroid> left, virtual_ptr<Asteroid> right),
void) {
collideWith,
(virtual_ptr<Asteroid> /*left*/, virtual_ptr<Asteroid> /*right*/), void) {
// handle Asteroid-Asteroid collision
}
BOOST_OPENMETHOD_OVERRIDE(
collideWith, (virtual_ptr<Asteroid> left, virtual_ptr<Spaceship> right),
void) {
collideWith,
(virtual_ptr<Asteroid> /*left*/, virtual_ptr<Spaceship> /*right*/), void) {
// handle Asteroid-Spaceship collision
}
BOOST_OPENMETHOD_OVERRIDE(
collideWith, (virtual_ptr<Spaceship> left, virtual_ptr<Asteroid> right),
void) {
collideWith,
(virtual_ptr<Spaceship> /*left*/, virtual_ptr<Asteroid> /*right*/), void) {
// handle Spaceship-Asteroid collision
}
BOOST_OPENMETHOD_OVERRIDE(
collideWith, (virtual_ptr<Spaceship> left, virtual_ptr<Spaceship> right),
void) {
collideWith,
(virtual_ptr<Spaceship> /*left*/, virtual_ptr<Spaceship> /*right*/), void) {
// handle Spaceship-Spaceship collision
}

View File

@@ -0,0 +1,99 @@
// Copyright (c) 2018-2025 Jean-Louis Leroy
// 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)
#include <iostream>
#include <boost/openmethod/initialize.hpp>
#include <boost/openmethod/core.hpp>
struct Node {
virtual ~Node() {
}
virtual int value() const = 0;
};
struct Variable : Node {
Variable(int value) : v(value) {
}
int value() const override {
return v;
}
int v;
};
struct Plus : Node {
Plus(const Node& left, const Node& right) : left(left), right(right) {
}
int value() const override {
return left.value() + right.value();
}
const Node& left;
const Node& right;
};
struct Times : Node {
Times(const Node& left, const Node& right) : left(left), right(right) {
}
int value() const override {
return left.value() * right.value();
}
const Node& left;
const Node& right;
};
using namespace boost::openmethod;
// tag::method[]
#include <boost/openmethod/macros.hpp>
struct BOOST_OPENMETHOD_ID(postfix);
using postfix = method<
BOOST_OPENMETHOD_ID(postfix),
void(virtual_ptr<const Node> node, std::ostream& os)>;
// end::method[]
// tag::variable_overrider[]
auto postfix_variable(virtual_ptr<const Variable> node, std::ostream& os) {
os << node->v;
}
static postfix::override<postfix_variable> override_postfix_variable;
// end::variable_overrider[]
// tag::binary_overriders[]
#include <boost/openmethod/macros.hpp>
auto postfix_plus(virtual_ptr<const Plus> node, std::ostream& os) {
postfix::fn(node->left, os);
os << ' ';
postfix::fn(node->right, os);
os << " +";
}
auto postfix_times(virtual_ptr<const Times> node, std::ostream& os) {
postfix::fn(node->left, os);
os << ' ';
postfix::fn(node->right, os);
os << " *";
}
BOOST_OPENMETHOD_REGISTER(postfix::override<postfix_plus, postfix_times>);
// end::binary_overriders[]
// tag::use_classes[]
BOOST_OPENMETHOD_REGISTER(use_classes<Node, Variable, Plus, Times>);
// end::use_classes[]
// tag::main[]
auto main() -> int {
boost::openmethod::initialize();
Variable a{2}, b{3}, c{4};
Plus d{a, b};
Times e{d, c};
postfix::fn(e, std::cout);
std::cout << " = " << e.value() << "\n"; // 2 3 + 4 * = 20
}
// end::main[]

View File

@@ -0,0 +1,77 @@
// Copyright (c) 2018-2025 Jean-Louis Leroy
// 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)
// clang-format off
#include <iostream>
// tag::classes[]
#include <boost/openmethod.hpp>
#include <boost/openmethod/initialize.hpp>
struct Node {
virtual ~Node() {}
virtual int value() const = 0;
};
struct Variable : Node {
Variable(int value) : v(value) {}
int value() const override { return v; }
int v;
};
template<typename Op>
struct BinaryOp : Node {
BinaryOp(const Node& left, const Node& right) : left(left), right(right) {}
int value() const override { return Op()(left.value(), right.value()); }
const Node& left;
const Node& right;
};
// end::classes[]
using namespace boost::openmethod;
// tag::method[]
BOOST_OPENMETHOD(
postfix, (virtual_ptr<const Node> node, std::ostream& os), void);
BOOST_OPENMETHOD_OVERRIDE(
postfix, (virtual_ptr<const Variable> var, std::ostream& os), void) {
os << var->v;
}
// end::method[]
// tag::postfix_binary[]
template<class BinaryOp, char Op>
auto postfix_binary(virtual_ptr<const BinaryOp> node, std::ostream& os) {
postfix(node->left, os);
os << ' ';
postfix(node->right, os);
os << " " << Op;
}
// end::postfix_binary[]
// tag::add_postfix_binary[]
BOOST_OPENMETHOD_TYPE(
postfix, (virtual_ptr<const Node> node, std::ostream& os), void)::
override<
postfix_binary<BinaryOp<std::plus<int>>, '+'>,
postfix_binary<
BinaryOp<std::multiplies<int>>, '*'>> add_binary_overriders;
// end::add_postfix_binary[]
// tag::main[]
BOOST_OPENMETHOD_CLASSES(
Node, Variable, BinaryOp<std::plus<int>>, BinaryOp<std::multiplies<int>>);
auto main() -> int {
boost::openmethod::initialize();
Variable a{2}, b{3}, c{4};
BinaryOp<std::plus<int>> d{a, b};
BinaryOp<std::multiplies<int>> e{d, c};
postfix(e, std::cout);
std::cout << " = " << e.value() << "\n"; // 2 3 + 4 * = 20
}
// end::main[]

View File

@@ -3,6 +3,10 @@
// See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifdef _MSC_VER
#pragma warning(disable : 4312)
#endif
struct Animal {
Animal(unsigned type) : type(type) {
}
@@ -27,59 +31,63 @@ struct Dog : Animal {
static constexpr unsigned static_type = 3;
};
#include <boost/openmethod/policies/basic_policy.hpp>
#include <boost/openmethod/preamble.hpp>
#include <boost/openmethod/policies/vptr_vector.hpp>
// tag::facet[]
// tag::policy[]
namespace bom = boost::openmethod;
struct custom_rtti : bom::policies::rtti {
template<class T>
static constexpr bool is_polymorphic = std::is_base_of_v<Animal, T>;
template<class Registry>
struct fn : bom::policies::rtti::defaults {
template<class T>
static constexpr bool is_polymorphic = std::is_base_of_v<Animal, T>;
template<typename T>
static auto static_type() -> bom::type_id {
if constexpr (is_polymorphic<T>) {
return T::static_type;
} else {
return 0;
template<typename T>
static auto static_type() -> bom::type_id {
if constexpr (is_polymorphic<T>) {
return reinterpret_cast<bom::type_id>(T::static_type);
} else {
return nullptr;
}
}
}
template<typename T>
static auto dynamic_type(const T& obj) -> bom::type_id {
if constexpr (is_polymorphic<T>) {
return obj.type;
} else {
return 0;
template<typename T>
static auto dynamic_type(const T& obj) -> bom::type_id {
if constexpr (is_polymorphic<T>) {
return reinterpret_cast<bom::type_id>(obj.type);
} else {
return nullptr;
}
}
}
};
};
// end::facet[]
// tag::policy[]
struct custom_policy : bom::policies::basic_policy<
custom_policy, custom_rtti,
bom::policies::vptr_vector<custom_policy>> {};
#define BOOST_OPENMETHOD_DEFAULT_POLICY custom_policy
// end::policy[]
// tag::registry[]
struct custom_registry
: bom::registry<custom_rtti, bom::policies::vptr_vector> {};
#define BOOST_OPENMETHOD_DEFAULT_REGISTRY custom_registry
// end::registry[]
// tag::example[]
#include <iostream>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
#include <boost/openmethod/initialize.hpp>
using boost::openmethod::virtual_ptr;
BOOST_OPENMETHOD(poke, (std::ostream&, virtual_ptr<Animal>), void);
BOOST_OPENMETHOD_OVERRIDE(
poke, (std::ostream & os, virtual_ptr<Cat> cat), void) {
poke, (std::ostream & os, virtual_ptr<Cat> /*cat*/), void) {
os << "hiss";
}
BOOST_OPENMETHOD_OVERRIDE(
poke, (std::ostream & os, virtual_ptr<Dog> dog), void) {
poke, (std::ostream & os, virtual_ptr<Dog> /*dog*/), void) {
os << "bark";
}

View File

@@ -0,0 +1,124 @@
// Copyright (c) 2018-2025 Jean-Louis Leroy
// 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)
// clang-format off
// tag::classes[]
struct Node {
virtual ~Node() {}
virtual int value() const = 0;
// our custom RTTI:
Node(unsigned type) : type(type) {}
unsigned type;
static constexpr unsigned static_type = 1;
};
struct Variable : Node {
static constexpr unsigned static_type = 2;
Variable(int value) : Node(static_type), v(value) {}
int value() const override { return v; }
int v;
};
struct Plus : Node {
static constexpr unsigned static_type = 3;
Plus(const Node& left, const Node& right)
: Node(static_type), left(left), right(right) {}
int value() const override { return left.value() + right.value(); }
const Node& left; const Node& right;
};
struct Times : Node {
static constexpr unsigned static_type = 4;
Times(const Node& left, const Node& right)
: Node(static_type), left(left), right(right) {}
int value() const override { return left.value() * right.value(); }
const Node& left; const Node& right;
};
// end::classes[]
// tag::policy[]
#include <boost/openmethod/preamble.hpp>
#include <boost/openmethod/policies/vptr_vector.hpp>
struct custom_rtti : boost::openmethod::policies::rtti {
template<class Registry>
struct fn : defaults {
template<class T>
static constexpr bool is_polymorphic = std::is_base_of_v<Node, T>;
using type_id = boost::openmethod::type_id; // for brevity
template<typename T>
static auto static_type() {
if constexpr (is_polymorphic<T>) {
return reinterpret_cast<type_id>(T::static_type);
} else {
return reinterpret_cast<type_id>(0);
}
}
template<typename T>
static auto dynamic_type(const T& obj) {
if constexpr (is_polymorphic<T>) {
return reinterpret_cast<type_id>(obj.type);
} else {
return reinterpret_cast<type_id>(0);
}
}
};
};
// end::policy[]
// tag::registry[]
struct custom_registry : boost::openmethod::registry<
custom_rtti, boost::openmethod::policies::vptr_vector> {};
#define BOOST_OPENMETHOD_DEFAULT_REGISTRY custom_registry
// end::registry[]
#include <boost/openmethod.hpp>
#include <boost/openmethod/initialize.hpp>
#include <iostream>
using boost::openmethod::virtual_ptr;
BOOST_OPENMETHOD(postfix, (virtual_ptr<const Node> node, std::ostream& os), void);
BOOST_OPENMETHOD_OVERRIDE(
postfix, (virtual_ptr<const Variable> var, std::ostream& os), void) {
os << var->v;
}
BOOST_OPENMETHOD_OVERRIDE(
postfix, (virtual_ptr<const Plus> plus, std::ostream& os), void) {
postfix(plus->left, os);
os << ' ';
postfix(plus->right, os);
os << " +";
}
BOOST_OPENMETHOD_OVERRIDE(
postfix, (virtual_ptr<const Times> times, std::ostream& os), void) {
postfix(times->left, os);
os << ' ';
postfix(times->right, os);
os << " *";
}
BOOST_OPENMETHOD_CLASSES(Node, Variable, Plus, Times);
int main() {
boost::openmethod::initialize();
Variable a{2}, b{3}, c{4};
Plus d{a, b}; Times e{d, c};
postfix(e, std::cout);
std::cout << " = " << e.value() << "\n"; // 2 3 + 4 * = 20
}
// end::content[]
void call_via_ref(const Node& node, std::ostream& os) {
postfix(node, os);
}

View File

@@ -0,0 +1,118 @@
// Copyright (c) 2018-2025 Jean-Louis Leroy
// 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)
// clang-format off
// tag::classes[]
struct Node {
Node(unsigned type) : type(type) {}
unsigned type;
static unsigned last_type;
static unsigned static_type;
};
struct Variable : Node {
static unsigned static_type;
Variable(int value) : Node(static_type), v(value) {}
int v;
};
struct Plus : Node {
static unsigned static_type;
Plus(const Node& left, const Node& right)
: Node(static_type), left(left), right(right) {}
const Node& left; const Node& right;
};
struct Times : Node {
static unsigned static_type;
Times(const Node& left, const Node& right)
: Node(static_type), left(left), right(right) {}
const Node& left; const Node& right;
};
// end::classes[]
// tag::policy[]
#include <boost/openmethod/preamble.hpp>
#include <boost/openmethod/policies/vptr_vector.hpp>
// note: vvvvvvvvvvvvvvvv
struct custom_rtti : boost::openmethod::policies::deferred_static_rtti {
template<class Registry>
struct fn : defaults {
template<class T>
static constexpr bool is_polymorphic = std::is_base_of_v<Node, T>;
using type_id = boost::openmethod::type_id; // for brevity
template<typename T>
static auto static_type() {
if constexpr (is_polymorphic<T>) {
return reinterpret_cast<type_id>(T::static_type);
} else {
return reinterpret_cast<type_id>(0);
}
}
template<typename T>
static auto dynamic_type(const T& obj) {
if constexpr (is_polymorphic<T>) {
return reinterpret_cast<type_id>(obj.type);
} else {
return reinterpret_cast<type_id>(0);
}
}
};
};
// end::policy[]
// tag::registry[]
struct custom_registry : boost::openmethod::registry<
custom_rtti, boost::openmethod::policies::vptr_vector> {};
#define BOOST_OPENMETHOD_DEFAULT_REGISTRY custom_registry
// end::registry[]
#include <boost/openmethod.hpp>
#include <boost/openmethod/initialize.hpp>
#include <iostream>
using boost::openmethod::virtual_ptr;
BOOST_OPENMETHOD(value, (virtual_ptr<const Node>), int);
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<const Plus> node), int) {
return value(node->left) + value(node->right);
}
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<const Times> node), int) {
return value(node->left) * value(node->right);
}
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<const Variable> node), int) {
return node->v;
}
BOOST_OPENMETHOD_CLASSES(Node, Variable, Plus, Times);
// tag::type_ids[]
unsigned Node::last_type = 0;
unsigned Node::static_type = ++Node::last_type;
unsigned Variable::static_type = ++Node::last_type;
unsigned Plus::static_type = ++Node::last_type;
unsigned Times::static_type = ++Node::last_type;
// end::type_ids[]
int main() {
boost::openmethod::initialize();
Variable a{2}, b{3}, c{4};
Plus d{a, b}; Times e{d, c};
std::cout << value(e) << "\n"; // 2 3 + 4 * = 20
}
// end::content[]
auto call_via_ref(const Node& node, std::ostream& os) {
return value(node);
}

View File

@@ -8,7 +8,9 @@
#include <variant>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
#include <boost/openmethod/initialize.hpp>
using boost::openmethod::virtual_ptr;
struct Animal {
virtual ~Animal() = default;
@@ -22,7 +24,7 @@ BOOST_OPENMETHOD_CLASSES(Animal, Cat, Dog);
BOOST_OPENMETHOD(trick, (std::ostream&, virtual_ptr<Animal>), void);
BOOST_OPENMETHOD_OVERRIDE(
trick, (std::ostream & os, virtual_ptr<Dog> dog), void) {
trick, (std::ostream & os, virtual_ptr<Dog> /*dog*/), void) {
os << "spin\n";
}
@@ -30,12 +32,11 @@ auto main() -> int {
namespace bom = boost::openmethod;
bom::initialize();
bom::default_policy::set_error_handler(
[](const bom::default_policy::error_variant& error) {
if (std::holds_alternative<bom::not_implemented_error>(error)) {
throw std::runtime_error("not implemented");
}
});
bom::default_registry::error_handler::set([](const auto& error) {
if (std::holds_alternative<bom::no_overrider>(error)) {
throw std::runtime_error("not implemented");
}
});
Cat felix;
Dog hector, snoopy;

View File

@@ -3,6 +3,10 @@
// See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifdef _MSC_VER
#pragma warning(disable : 4312)
#endif
// tag::classes[]
struct custom_type_info {
static unsigned last;
@@ -72,65 +76,71 @@ struct Dog : virtual Animal {
static custom_type_info type_info;
};
#include <boost/openmethod/policies/basic_policy.hpp>
#include <boost/openmethod/preamble.hpp>
#include <boost/openmethod/policies/vptr_vector.hpp>
namespace bom = boost::openmethod;
struct custom_rtti : bom::policies::rtti {
template<typename T>
static auto static_type() -> bom::type_id {
if constexpr (std::is_base_of_v<Animal, T>) {
return T::type_info.id;
} else {
return 0;
}
}
// tag::registry[]
struct custom_rtti : bom::policies::deferred_static_rtti {
template<class Registry>
struct fn : defaults {
template<class T>
static constexpr bool is_polymorphic = std::is_base_of_v<Animal, T>;
template<typename T>
static auto dynamic_type(const T& obj) -> bom::type_id {
if constexpr (std::is_base_of_v<Animal, T>) {
return obj.type;
} else {
return 0;
template<typename T>
static auto static_type() -> bom::type_id {
if constexpr (std::is_base_of_v<Animal, T>) {
return reinterpret_cast<bom::type_id>(T::type_info.id);
} else {
return 0;
}
}
}
// tag::dynamic_cast_ref[]
// to support virtual inheritance:
template<typename Derived, typename Base>
static auto dynamic_cast_ref(Base&& obj) -> Derived {
using base_type = std::remove_reference_t<Base>;
if constexpr (std::is_base_of_v<Animal, base_type>) {
return *obj.template cast<std::remove_reference_t<Derived>>();
} else {
abort(); // not supported
template<typename T>
static auto dynamic_type(const T& obj) -> bom::type_id {
if constexpr (std::is_base_of_v<Animal, T>) {
return reinterpret_cast<bom::type_id>(obj.type);
} else {
return nullptr;
}
}
}
// end::dynamic_cast_ref[]
// to support virtual inheritance:
template<typename Derived, typename Base>
static auto dynamic_cast_ref(Base&& obj) -> Derived {
using base_type = std::remove_reference_t<Base>;
if constexpr (std::is_base_of_v<Animal, base_type>) {
return *obj.template cast<std::remove_reference_t<Derived>>();
} else {
abort(); // not supported
}
}
};
};
struct custom_policy
: bom::policies::basic_policy<
custom_policy, custom_rtti, bom::policies::deferred_static_rtti,
bom::policies::vptr_vector<custom_policy>> {};
struct custom_registry : bom::registry<custom_rtti, bom::policies::vptr_vector> {
};
// end::registry[]
#define BOOST_OPENMETHOD_DEFAULT_POLICY custom_policy
#define BOOST_OPENMETHOD_DEFAULT_REGISTRY custom_registry
#include <iostream>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
#include <boost/openmethod/initialize.hpp>
using boost::openmethod::virtual_ptr;
BOOST_OPENMETHOD(poke, (std::ostream&, virtual_ptr<Animal>), void);
BOOST_OPENMETHOD_OVERRIDE(
poke, (std::ostream & os, virtual_ptr<Cat> cat), void) {
poke, (std::ostream & os, virtual_ptr<Cat> /*cat*/), void) {
os << "hiss";
}
BOOST_OPENMETHOD_OVERRIDE(
poke, (std::ostream & os, virtual_ptr<Dog> dog), void) {
poke, (std::ostream & os, virtual_ptr<Dog> /*dog*/), void) {
os << "bark";
}

View File

@@ -9,6 +9,8 @@
#include <string>
#include <boost/openmethod.hpp>
using boost::openmethod::virtual_ptr;
#ifdef FRIEND_ALL
// tag::friend_all[]
@@ -37,7 +39,7 @@ class Animal {
class Cat;
class Dog;
template<typename> struct BOOST_OPENMETHOD_OVERRIDERS(poke);
template<typename...> struct BOOST_OPENMETHOD_OVERRIDERS(poke);
class Animal {
// ...
@@ -82,7 +84,7 @@ BOOST_OPENMETHOD_OVERRIDE(
BOOST_OPENMETHOD_CLASSES(Animal, Cat, Dog);
#include <boost/openmethod/compiler.hpp>
#include <boost/openmethod/initialize.hpp>
auto main() -> int {
boost::openmethod::initialize();

View File

@@ -9,6 +9,8 @@
#include <string>
#include <boost/openmethod.hpp>
using boost::openmethod::virtual_ptr;
#ifdef FRIEND_ALL
// tag::friend_all[]
@@ -41,7 +43,7 @@ BOOST_OPENMETHOD(poke, (std::ostream&, virtual_ptr<Animal>), void);
namespace pets {
struct Cat;
struct Dog;
template<typename> struct BOOST_OPENMETHOD_OVERRIDERS(poke);
template<typename...> struct BOOST_OPENMETHOD_OVERRIDERS(poke);
} // namespace pets
namespace core {
@@ -96,7 +98,7 @@ BOOST_OPENMETHOD_CLASSES(core::Animal, Cat, Dog);
} // namespace pets
// end::friend[]
#include <boost/openmethod/compiler.hpp>
#include <boost/openmethod/initialize.hpp>
auto main() -> int {
boost::openmethod::initialize();

View File

@@ -15,7 +15,8 @@ struct Animal {
virtual ~Animal() = default;
};
BOOST_OPENMETHOD(poke, (std::ostream&, virtual_ptr<Animal>), void);
BOOST_OPENMETHOD(
poke, (std::ostream&, boost::openmethod::virtual_ptr<Animal>), void);
} // namespace animals

View File

@@ -5,6 +5,8 @@
#include "cat.hpp"
using boost::openmethod::virtual_ptr;
namespace felines {
BOOST_OPENMETHOD_CLASSES(animals::Animal, Cat, Cheetah);

View File

@@ -8,7 +8,7 @@ namespace canines {
BOOST_OPENMETHOD_CLASSES(animals::Animal, Dog);
BOOST_OPENMETHOD_DEFINE_OVERRIDER(
poke, (std::ostream & os, virtual_ptr<Dog> dog), void) {
poke, (std::ostream & os, boost::openmethod::virtual_ptr<Dog> dog), void) {
os << dog->name << " barks";
}

View File

@@ -13,7 +13,7 @@ struct Dog : animals::Animal {
};
BOOST_OPENMETHOD_DECLARE_OVERRIDER(
poke, (std::ostream & os, virtual_ptr<Dog> dog), void);
poke, (std::ostream & os, boost::openmethod::virtual_ptr<Dog> dog), void);
} // namespace canines

View File

@@ -1,11 +1,13 @@
#include <iostream>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
#include <boost/openmethod/initialize.hpp>
#include "animal.hpp"
#include "cat.hpp"
#include "dog.hpp"
using boost::openmethod::virtual_ptr;
struct Bulldog : canines::Dog {
using Dog::Dog;
};

View File

@@ -1,6 +1,6 @@
#include <iostream>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
#include <boost/openmethod/initialize.hpp>
#include "animal.hpp"
#include "cat.hpp"

View File

@@ -1,6 +1,6 @@
#include <iostream>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
#include <boost/openmethod/initialize.hpp>
#include "animal.hpp"
#include "cat.hpp"

View File

@@ -31,6 +31,8 @@ struct Bulldog : Dog {
#include <iostream>
#include <boost/openmethod.hpp>
using boost::openmethod::virtual_ptr;
BOOST_OPENMETHOD(
poke, // method name
(std::ostream&, virtual_ptr<Animal>), // method signature
@@ -77,7 +79,7 @@ BOOST_OPENMETHOD_OVERRIDE(
// Add definitions for specific pairs of animals.
BOOST_OPENMETHOD_OVERRIDE(
encounter,
(std::ostream & os, virtual_ptr<Dog> dog1, virtual_ptr<Dog> dog2), void) {
(std::ostream & os, virtual_ptr<Dog> /*dog1*/, virtual_ptr<Dog> /*dog2*/), void) {
os << "Both wag tails";
}
@@ -95,7 +97,7 @@ BOOST_OPENMETHOD_OVERRIDE(
// end::multi[]
// tag::main[]
#include <boost/openmethod/compiler.hpp>
#include <boost/openmethod/initialize.hpp>
// only needed in the file that calls boost::openmethod::initialize()
auto main() -> int {

View File

@@ -0,0 +1,42 @@
// Copyright (c) 2018-2025 Jean-Louis Leroy
// 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)
#include <iostream>
#include <memory>
#include <boost/openmethod.hpp>
#include <boost/openmethod/inplace_vptr.hpp>
#include <boost/openmethod/initialize.hpp>
using namespace boost::openmethod;
struct Animal : inplace_vptr_base<Animal> {};
struct Cat : Animal, inplace_vptr_derived<Cat, Animal> {};
struct Dog : Animal, inplace_vptr_derived<Dog, Animal> {};
BOOST_OPENMETHOD(
poke, (virtual_<Animal&> animal, std::ostream& os), void);
BOOST_OPENMETHOD_OVERRIDE(poke, (Cat&, std::ostream& os), void) {
os << "hiss\n";
}
BOOST_OPENMETHOD_OVERRIDE(poke, (Dog&, std::ostream& os), void) {
os << "bark\n";
}
int main() {
initialize();
std::unique_ptr<Animal> a = std::make_unique<Cat>();
std::unique_ptr<Animal> b = std::make_unique<Dog>();
poke(*a, std::cout); // hiss
poke(*b, std::cout); // bark
return 0;
}

View File

@@ -9,8 +9,8 @@
#include <typeinfo>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
#include <boost/openmethod/shared_ptr.hpp>
#include <boost/openmethod/initialize.hpp>
#include <boost/openmethod/interop/std_shared_ptr.hpp>
using std::make_shared;
using std::shared_ptr;
@@ -18,6 +18,7 @@ using std::string;
using boost::openmethod::make_shared_virtual;
using boost::openmethod::shared_virtual_ptr;
using boost::openmethod::virtual_ptr;
struct matrix {
virtual ~matrix() {
@@ -27,13 +28,13 @@ struct matrix {
};
struct dense_matrix : matrix {
virtual auto at(int row, int col) const -> double {
virtual auto at(int /*row*/, int /*col*/) const -> double {
return 0;
}
};
struct diagonal_matrix : matrix {
virtual auto at(int row, int col) const -> double {
virtual auto at(int /*row*/, int /*col*/) const -> double {
return 0;
}
};
@@ -42,13 +43,12 @@ BOOST_OPENMETHOD_CLASSES(matrix, dense_matrix, diagonal_matrix);
BOOST_OPENMETHOD(to_json, (virtual_ptr<const matrix>), string);
BOOST_OPENMETHOD_OVERRIDE(
to_json, (virtual_ptr<const dense_matrix> m), string) {
BOOST_OPENMETHOD_OVERRIDE(to_json, (virtual_ptr<const dense_matrix>), string) {
return "json for dense matrix...";
}
BOOST_OPENMETHOD_OVERRIDE(
to_json, (virtual_ptr<const diagonal_matrix> m), string) {
to_json, (virtual_ptr<const diagonal_matrix>), string) {
return "json for diagonal matrix...";
}
@@ -62,7 +62,8 @@ BOOST_OPENMETHOD(
// catch-all matrix * matrix -> dense_matrix
BOOST_OPENMETHOD_OVERRIDE(
times,
(shared_virtual_ptr<const matrix> a, shared_virtual_ptr<const matrix> b),
(shared_virtual_ptr<const matrix> /*a*/,
shared_virtual_ptr<const matrix> /*b*/),
shared_virtual_ptr<const dense_matrix>) {
return make_shared<const dense_matrix>();
}
@@ -70,8 +71,8 @@ BOOST_OPENMETHOD_OVERRIDE(
// diagonal_matrix * diagonal_matrix -> diagonal_matrix
BOOST_OPENMETHOD_OVERRIDE(
times,
(shared_virtual_ptr<const diagonal_matrix> a,
shared_virtual_ptr<const diagonal_matrix> b),
(shared_virtual_ptr<const diagonal_matrix> /*a*/,
shared_virtual_ptr<const diagonal_matrix> /*b*/),
shared_virtual_ptr<const diagonal_matrix>) {
return make_shared_virtual<diagonal_matrix>();
}
@@ -90,13 +91,13 @@ BOOST_OPENMETHOD(
// catch-all matrix * scalar -> dense_matrix
BOOST_OPENMETHOD_OVERRIDE(
times, (double a, shared_virtual_ptr<const matrix> b),
times, (double /*a*/, shared_virtual_ptr<const matrix> /*b*/),
shared_virtual_ptr<const dense_matrix>) {
return make_shared_virtual<dense_matrix>();
}
BOOST_OPENMETHOD_OVERRIDE(
times, (double a, shared_virtual_ptr<const diagonal_matrix> b),
times, (double /*a*/, shared_virtual_ptr<const diagonal_matrix> /*b*/),
shared_virtual_ptr<const diagonal_matrix>) {
return make_shared_virtual<diagonal_matrix>();
}
@@ -130,7 +131,7 @@ auto main() -> int {
shared_ptr<const matrix> b = make_shared<diagonal_matrix>();
double s = 1;
#ifndef _MSC_VER
#ifdef BOOST_CLANG
#pragma clang diagnostic ignored "-Wpotentially-evaluated-expression"
#endif

View File

@@ -10,7 +10,9 @@
#include <iostream>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
#include <boost/openmethod/initialize.hpp>
using boost::openmethod::virtual_ptr;
using namespace std;
@@ -37,8 +39,7 @@ BOOST_OPENMETHOD(
inspect, (virtual_ptr<const Vehicle>, virtual_ptr<const Inspector>), void);
BOOST_OPENMETHOD_OVERRIDE(
inspect, (virtual_ptr<const Vehicle> v, virtual_ptr<const Inspector> i),
void) {
inspect, (virtual_ptr<const Vehicle>, virtual_ptr<const Inspector>), void) {
cout << "Inspect vehicle.\n";
}

View File

@@ -0,0 +1,18 @@
// Copyright (c) 2018-2025 Jean-Louis Leroy
// 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)
// tag::content[]
// employee.cpp
#include "roles.hpp"
#include <boost/openmethod.hpp>
BOOST_OPENMETHOD_OVERRIDE(
pay, (boost::openmethod::virtual_ptr<const Employee>), double) {
return 5000.0;
}
BOOST_OPENMETHOD_CLASSES(Employee)
// end::content[]

View File

@@ -0,0 +1,23 @@
// Copyright (c) 2018-2025 Jean-Louis Leroy
// 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)
// tag::content[]
// main.cpp
#include "roles.hpp"
#include <iostream>
#include <boost/openmethod/initialize.hpp>
int main() {
boost::openmethod::initialize();
Employee bill;
Salesman bob; bob.sales = 100'000.0;
std::cout << "pay bill: $" << pay(bill) << "\n"; // pay bill: $5000
std::cout << "pay bob: $" << pay(bob) << "\n"; // pay bob: $10000
}
// end::content[]

View File

@@ -0,0 +1,23 @@
// Copyright (c) 2018-2025 Jean-Louis Leroy
// 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)
// tag::content[]
// roles.hpp
#ifndef ROLES_HPP
#define ROLES_HPP
#include <boost/openmethod.hpp>
struct Employee { virtual ~Employee() = default; };
struct Salesman : Employee {
double sales = 0.0;
};
BOOST_OPENMETHOD(pay, (boost::openmethod::virtual_ptr<const Employee>), double);
#endif // ROLES_HPP
// end::content[]

View File

@@ -0,0 +1,19 @@
// Copyright (c) 2018-2025 Jean-Louis Leroy
// 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)
// tag::content[]
// salesman.cpp
#include "roles.hpp"
#include <boost/openmethod.hpp>
BOOST_OPENMETHOD_OVERRIDE(
pay, (boost::openmethod::virtual_ptr<const Salesman> emp), double) {
return next(emp) + emp->sales * 0.05; // base + commission
}
BOOST_OPENMETHOD_CLASSES(Employee, Salesman)
// end::content[]

View File

@@ -0,0 +1,16 @@
// Copyright (c) 2018-2025 Jean-Louis Leroy
// 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)
// tag::content[]
#include "roles.hpp"
#include <boost/openmethod.hpp>
BOOST_OPENMETHOD_DEFINE_OVERRIDER(
pay, (boost::openmethod::virtual_ptr<const Employee>), double) {
return 5000.0;
}
BOOST_OPENMETHOD_CLASSES(Employee)
// end::content[]

View File

@@ -0,0 +1,23 @@
// Copyright (c) 2018-2025 Jean-Louis Leroy
// 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)
// tag::content[]
// main.cpp
#include "roles.hpp"
#include <iostream>
#include <boost/openmethod/initialize.hpp>
int main() {
boost::openmethod::initialize();
Employee bill;
Salesman bob; bob.sales = 100'000.0;
std::cout << "pay bill: $" << pay(bill) << "\n"; // pay bill: $5000
std::cout << "pay bob: $" << pay(bob) << "\n"; // pay bob: $10000
}
// end::content[]

View File

@@ -0,0 +1,26 @@
// Copyright (c) 2018-2025 Jean-Louis Leroy
// 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)
// tag::content[]
// roles.hpp
#ifndef ROLES_HPP
#define ROLES_HPP
#include <boost/openmethod.hpp>
struct Employee { virtual ~Employee() = default; };
struct Salesman : Employee {
double sales = 0.0;
};
BOOST_OPENMETHOD(pay, (boost::openmethod::virtual_ptr<const Employee>), double);
BOOST_OPENMETHOD_DECLARE_OVERRIDER(
pay, (boost::openmethod::virtual_ptr<const Employee>), double);
#endif // ROLES_HPP
// end::content[]

View File

@@ -0,0 +1,19 @@
// Copyright (c) 2018-2025 Jean-Louis Leroy
// 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)
#include "roles.hpp"
#include <boost/openmethod.hpp>
// tag::content[]
BOOST_OPENMETHOD_OVERRIDE(
pay, (boost::openmethod::virtual_ptr<const Salesman> emp), double) {
return BOOST_OPENMETHOD_OVERRIDER(
pay, (boost::openmethod::virtual_ptr<const Employee> emp),
double)::fn(emp) +
emp->sales * 0.05; // base + commission
}
// end::content[]
BOOST_OPENMETHOD_CLASSES(Employee, Salesman)

View File

@@ -0,0 +1,11 @@
// Copyright (c) 2018-2025 Jean-Louis Leroy
// 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)
// tag::content[]
#include "roles.hpp"
#include <boost/openmethod.hpp>
BOOST_OPENMETHOD_CLASSES(Employee)
// end::content[]

Some files were not shown because too many files have changed in this diff Show More