inception

This commit is contained in:
Jean-Louis Leroy
2017-10-16 12:32:07 -04:00
commit 5e0fa8ee4b
151 changed files with 17049 additions and 0 deletions

136
.clang-format Normal file
View File

@@ -0,0 +1,136 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: AlwaysBreak
AlignConsecutiveMacros: false
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: false
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: true
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
- Regex: '.*'
Priority: 1
SortPriority: 0
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentCaseLabels: false
IndentGotoLabels: true
#IndentPPDirectives: true
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Left
ReflowComments: false
SortIncludes: false
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
Standard: Latest
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseCRLF: false
UseTab: Never
...

33
.clang-tidy Normal file
View File

@@ -0,0 +1,33 @@
---
Checks: 'clang-diagnostic-*,clang-analyzer-*,modernize-use-trailing-return-type'
WarningsAsErrors: ''
HeaderFileExtensions:
- ''
- h
- hh
- hpp
- hxx
ImplementationFileExtensions:
- c
- cc
- cpp
- cxx
ExcludeHeaderFilterRegex: ''
FormatStyle: file
User: jll
CheckOptions:
cert-dcl16-c.NewSuffixes: 'L;LL;LU;LLU'
cert-err33-c.AllowCastToVoid: 'true'
cert-err33-c.CheckedFunctions: '^::aligned_alloc;^::asctime_s;^::at_quick_exit;^::atexit;^::bsearch;^::bsearch_s;^::btowc;^::c16rtomb;^::c32rtomb;^::calloc;^::clock;^::cnd_broadcast;^::cnd_init;^::cnd_signal;^::cnd_timedwait;^::cnd_wait;^::ctime_s;^::fclose;^::fflush;^::fgetc;^::fgetpos;^::fgets;^::fgetwc;^::fopen;^::fopen_s;^::fprintf;^::fprintf_s;^::fputc;^::fputs;^::fputwc;^::fputws;^::fread;^::freopen;^::freopen_s;^::fscanf;^::fscanf_s;^::fseek;^::fsetpos;^::ftell;^::fwprintf;^::fwprintf_s;^::fwrite;^::fwscanf;^::fwscanf_s;^::getc;^::getchar;^::getenv;^::getenv_s;^::gets_s;^::getwc;^::getwchar;^::gmtime;^::gmtime_s;^::localtime;^::localtime_s;^::malloc;^::mbrtoc16;^::mbrtoc32;^::mbsrtowcs;^::mbsrtowcs_s;^::mbstowcs;^::mbstowcs_s;^::memchr;^::mktime;^::mtx_init;^::mtx_lock;^::mtx_timedlock;^::mtx_trylock;^::mtx_unlock;^::printf_s;^::putc;^::putwc;^::raise;^::realloc;^::remove;^::rename;^::scanf;^::scanf_s;^::setlocale;^::setvbuf;^::signal;^::snprintf;^::snprintf_s;^::sprintf;^::sprintf_s;^::sscanf;^::sscanf_s;^::strchr;^::strerror_s;^::strftime;^::strpbrk;^::strrchr;^::strstr;^::strtod;^::strtof;^::strtoimax;^::strtok;^::strtok_s;^::strtol;^::strtold;^::strtoll;^::strtoul;^::strtoull;^::strtoumax;^::strxfrm;^::swprintf;^::swprintf_s;^::swscanf;^::swscanf_s;^::thrd_create;^::thrd_detach;^::thrd_join;^::thrd_sleep;^::time;^::timespec_get;^::tmpfile;^::tmpfile_s;^::tmpnam;^::tmpnam_s;^::tss_create;^::tss_get;^::tss_set;^::ungetc;^::ungetwc;^::vfprintf;^::vfprintf_s;^::vfscanf;^::vfscanf_s;^::vfwprintf;^::vfwprintf_s;^::vfwscanf;^::vfwscanf_s;^::vprintf_s;^::vscanf;^::vscanf_s;^::vsnprintf;^::vsnprintf_s;^::vsprintf;^::vsprintf_s;^::vsscanf;^::vsscanf_s;^::vswprintf;^::vswprintf_s;^::vswscanf;^::vswscanf_s;^::vwprintf_s;^::vwscanf;^::vwscanf_s;^::wcrtomb;^::wcschr;^::wcsftime;^::wcspbrk;^::wcsrchr;^::wcsrtombs;^::wcsrtombs_s;^::wcsstr;^::wcstod;^::wcstof;^::wcstoimax;^::wcstok;^::wcstok_s;^::wcstol;^::wcstold;^::wcstoll;^::wcstombs;^::wcstombs_s;^::wcstoul;^::wcstoull;^::wcstoumax;^::wcsxfrm;^::wctob;^::wctrans;^::wctype;^::wmemchr;^::wprintf_s;^::wscanf;^::wscanf_s;'
cert-oop54-cpp.WarnOnlyIfThisHasSuspiciousField: 'false'
cert-str34-c.DiagnoseSignedUnsignedCharComparisons: 'false'
cppcoreguidelines-non-private-member-variables-in-classes.IgnoreClassesWithAllMemberVariablesBeingPublic: 'true'
google-readability-braces-around-statements.ShortStatementLines: '1'
google-readability-function-size.StatementThreshold: '800'
google-readability-namespace-comments.ShortNamespaceLines: '10'
google-readability-namespace-comments.SpacesBeforeComments: '2'
llvm-else-after-return.WarnOnConditionVariables: 'false'
llvm-else-after-return.WarnOnUnfixable: 'false'
llvm-qualified-auto.AddConstToQualified: 'false'
SystemHeaders: false
...

122
.github/workflows/main.yml vendored Normal file
View File

@@ -0,0 +1,122 @@
# 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:
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 # or specific "vX.X.X" version tag for this action
with:
path: build_outputs_folder/
- name: Deploy to GitHub Pages
uses: actions/deploy-pages@v4

15
.github/workflows/probe.yml vendored Normal file
View File

@@ -0,0 +1,15 @@
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++

28
.gitignore vendored Normal file
View File

@@ -0,0 +1,28 @@
.hrefs
.rtags
build/
builds/
**/#*#
dependencies/*
extern/*
tests/benchmarks_parameters.hpp
**/vcpkg_installed
.venv/
build/*
__build__/*
# ides
.vscode/
.vs/
CMakeSettings.json
_deps/
export/
fetch_and_include/
tmpinst/
CMakeFiles/

0
.gitmodules vendored Normal file
View File

45
CMakeLists.txt Normal file
View File

@@ -0,0 +1,45 @@
# 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)
cmake_minimum_required(VERSION 3.10)
if(POLICY CMP0167)
cmake_policy(SET CMP0074 NEW)
endif()
if(POLICY CMP0167)
cmake_policy(SET CMP0167 NEW)
endif()
project(boost_openmethod VERSION 1.87.0 LANGUAGES CXX)
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
endif()
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_library(boost_openmethod INTERFACE)
add_library(Boost::openmethod ALIAS boost_openmethod)
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)
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()

1
CODEOWNERS Normal file
View File

@@ -0,0 +1 @@
* @jll63

23
LICENSE Normal file
View File

@@ -0,0 +1,23 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

16
README.md Normal file
View File

@@ -0,0 +1,16 @@
# Boost.OpenMethod
THIS IS NOT A BOOST LIBRARY (yet).
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.
The documentation is [here](https://jll63.github.io/Boost.OpenMethod/).
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.

View File

@@ -0,0 +1,68 @@
#include <iostream>
#include <vector>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
struct Animal {
const char* name;
Animal(const char* name) : name(name) {
}
};
struct Dog : Animal {
using Animal::Animal;
};
struct Cat : Animal {
using Animal::Animal;
};
BOOST_OPENMETHOD_CLASSES(Animal, Dog, Cat);
using boost::openmethod::virtual_ptr;
BOOST_OPENMETHOD(
meet, (virtual_ptr<Animal>, virtual_ptr<Animal>, std::ostream&), void);
BOOST_OPENMETHOD_OVERRIDE(
meet, (virtual_ptr<Cat> a1, virtual_ptr<Cat> a2, std::ostream& os), void) {
os << a1->name << " ignores " << a2->name << "\n";
}
BOOST_OPENMETHOD_OVERRIDE(
meet, (virtual_ptr<Dog> a1, virtual_ptr<Cat> a2, std::ostream& os), void) {
os << a1->name << " chases " << a2->name << "\n";
}
BOOST_OPENMETHOD_OVERRIDE(
meet, (virtual_ptr<Cat> a1, virtual_ptr<Dog> a2, std::ostream& os), void) {
os << a1->name << " runs away from " << a2->name << "\n";
}
BOOST_OPENMETHOD_OVERRIDE(
meet, (virtual_ptr<Dog> a1, virtual_ptr<Dog> a2, std::ostream& os), void) {
os << a1->name << " wags tail at " << a2->name << "\n";
}
void meet_animals(
const std::vector<virtual_ptr<Animal>>& animals, std::ostream& os) {
for (auto animal : animals) {
for (auto other : animals) {
if (&animal != &other) {
meet(animal, other, os);
}
}
}
}
int main() {
boost::openmethod::initialize();
Dog hector{"Hector"}, snoopy{"Snoopy"};
Cat felix{"Felix"}, sylvester{"Sylvester"};
std::vector<virtual_ptr<Animal>> animals = {
virtual_ptr<Dog>::final(hector), virtual_ptr<Cat>::final(felix),
virtual_ptr<Cat>::final(sylvester), virtual_ptr<Dog>::final(snoopy)};
meet_animals(animals, std::cout);
}

69
ce/2-method-vptr.cpp Normal file
View File

@@ -0,0 +1,69 @@
#include <iostream>
#include <vector>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
struct Animal {
const char* name;
Animal(const char* name) : name(name) {
}
virtual ~Animal() {
}
};
struct Dog : Animal {
using Animal::Animal;
};
struct Cat : Animal {
using Animal::Animal;
};
BOOST_OPENMETHOD_CLASSES(Animal, Dog, Cat);
using boost::openmethod::virtual_ptr;
BOOST_OPENMETHOD(
meet, (virtual_ptr<Animal>, virtual_ptr<Animal>, std::ostream&), void);
BOOST_OPENMETHOD_OVERRIDE(
meet, (virtual_ptr<Cat> a1, virtual_ptr<Cat> a2, std::ostream& os), void) {
os << a1->name << " ignores " << a2->name << "\n";
}
BOOST_OPENMETHOD_OVERRIDE(
meet, (virtual_ptr<Dog> a1, virtual_ptr<Cat> a2, std::ostream& os), void) {
os << a1->name << " chases " << a2->name << "\n";
}
BOOST_OPENMETHOD_OVERRIDE(
meet, (virtual_ptr<Cat> a1, virtual_ptr<Dog> a2, std::ostream& os), void) {
os << a1->name << " runs away from " << a2->name << "\n";
}
BOOST_OPENMETHOD_OVERRIDE(
meet, (virtual_ptr<Dog> a1, virtual_ptr<Dog> a2, std::ostream& os), void) {
os << a1->name << " wags tail at " << a2->name << "\n";
}
void meet_animals(
const std::vector<virtual_ptr<Animal>>& animals, std::ostream& os) {
for (auto animal : animals) {
for (auto other : animals) {
if (&animal != &other) {
meet(animal, other, os);
}
}
}
}
int main() {
boost::openmethod::initialize();
Dog hector{"Hector"}, snoopy{"Snoopy"};
Cat felix{"Felix"}, sylvester{"Sylvester"};
std::vector<virtual_ptr<Animal>> animals = {
hector, felix, sylvester, snoopy};
meet_animals(animals, std::cout);
}

61
ce/2-method.cpp Normal file
View File

@@ -0,0 +1,61 @@
#include <iostream>
#include <vector>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
struct Animal {
const char* name;
Animal(const char* name) : name(name) {
}
virtual ~Animal() {
}
};
struct Dog : Animal {
using Animal::Animal;
};
struct Cat : Animal {
using Animal::Animal;
};
BOOST_OPENMETHOD_CLASSES(Animal, Dog, Cat);
BOOST_OPENMETHOD(
meet, (virtual_<Animal&>, virtual_<Animal&>, std::ostream&), void);
BOOST_OPENMETHOD_OVERRIDE(meet, (Cat & a1, Cat& a2, std::ostream& os), void) {
os << a1.name << " ignores " << a2.name << "\n";
}
BOOST_OPENMETHOD_OVERRIDE(meet, (Dog & a1, Cat& a2, std::ostream& os), void) {
os << a1.name << " chases " << a2.name << "\n";
}
BOOST_OPENMETHOD_OVERRIDE(meet, (Cat & a1, Dog& a2, std::ostream& os), void) {
os << a1.name << " runs away from " << a2.name << "\n";
}
BOOST_OPENMETHOD_OVERRIDE(meet, (Dog & a1, Dog& a2, std::ostream& os), void) {
os << a1.name << " wags tail at " << a2.name << "\n";
}
void meet_animals(const std::vector<Animal*>& animals, std::ostream& os) {
for (auto animal : animals) {
for (auto other : animals) {
if (&animal != &other) {
meet(*animal, *other, os);
}
}
}
}
int main() {
boost::openmethod::initialize();
Dog hector{"Hector"}, snoopy{"Snoopy"};
Cat felix{"Felix"}, sylvester{"Sylvester"};
std::vector<Animal*> animals = {&hector, &felix, &sylvester, &snoopy};
meet_animals(animals, std::cout);
}

28
ce/CMakeLists.txt Normal file
View File

@@ -0,0 +1,28 @@
# Copyright (c) 2018-2024 Jean-Louis Leroy
# Distributed under the Boost Software License, Version 1.0.
# See accompanying filce_e LICENSE_1_0.txt
# or copy at hce_ttp://www.boost.oce_rg/LICENSE_1_0.txt)
add_executable(ce_virtual virtual.cpp)
add_test(NAME ce_virtual COMMAND ce_virtual)
add_executable(ce_uni-method uni-method.cpp)
add_test(NAME ce_uni-method COMMAND ce_uni-method)
add_executable(ce_uni-method-vptr uni-method-vptr.cpp)
add_test(NAME ce_uni-method-vptr COMMAND ce_uni-method-vptr)
add_executable(ce_virtual-double virtual-double.cpp)
add_test(NAME ce_virtual-double COMMAND ce_virtual-double)
add_executable(ce_2-method 2-method.cpp)
add_test(NAME ce_2-method COMMAND ce_2-method)
add_executable(ce_2-method-vptr 2-method-vptr.cpp)
add_test(NAME ce_2-method-vptr COMMAND ce_2-method-vptr)
add_executable(ce_2-method-vptr-final 2-method-vptr-final.cpp)
add_test(NAME ce_2-method-vptr-fince_al COMMAND ce_2-method-vptr-final)
add_executable(ce_uni-method-vptr-final uni-method-vptr-final.cpp)
add_test(NAME ce_uni-method-vptr-fce_inal COMMAND ce_uni-method-vptr-final)

26
ce/README.md Normal file
View File

@@ -0,0 +1,26 @@
# YOMM2 on Compiler Explorer
YOMM2 is available on Compiler Explorer. Make sure that you also select Boost
version 1.74 or above, and you probably want to add the `-O3 -DNDEBUG` compiler
switches.
The following examples are available:
* The [examples](https://jll63.github.io/yomm2/ce/slides.html) from the slides.
* The matrix example from the GitHub langing page.
The following examples use the diff mode to compare open methods with the
equivalent (closed) virtual function based approaches.
* [virtual function call vs uni-method call via plain reference](https://jll63.github.io/yomm2/ce/vf-vs-1m-ref.html)
* [virtual function call vs uni-method call via virtual_ptr ](https://jll63.github.io/yomm2/ce/vf-vs-1m-vptr.html)
* [double dispatch vs multi-method call via plain reference](https://jll63.github.io/yomm2/ce/2d-vs-2m-ref.html)
* [double dispatch vs multi-method call via virtual_ptr ](https://jll63.github.io/yomm2/ce/2d-vs-2m-vptr.html)
YOMM2 can also [add polymorphic operations to non-polymorphic
classes](https://jll63.github.io/yomm2/ce/vptr-final.html).
When `virtual_ptr` is used in combination with generated static offsets, method
dispatch matches the speed of virtual functions. It is also possible to generate
dispatch data that can be installed without calling `update`, a fairly expensive
operaiton. See [this example](https://jll63.github.io/yomm2/ce/generator.html).

View File

@@ -0,0 +1,55 @@
#include <iostream>
#include <vector>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
struct Animal {
const char* name;
Animal(const char* name) : name(name) {
}
};
struct Dog : Animal {
using Animal::Animal;
};
struct Cat : Animal {
using Animal::Animal;
};
BOOST_OPENMETHOD_CLASSES(Animal, Dog, Cat);
using boost::openmethod::final_virtual_ptr;
using boost::openmethod::virtual_ptr;
BOOST_OPENMETHOD(poke, (virtual_ptr<Animal>, std::ostream&), void);
BOOST_OPENMETHOD_OVERRIDE(
poke, (virtual_ptr<Cat> animal, std::ostream& os), void) {
os << animal->name << " hisses.\n";
}
BOOST_OPENMETHOD_OVERRIDE(
poke, (virtual_ptr<Dog> animal, std::ostream& os), void) {
os << animal->name << " barks.\n";
}
void poke_animals(
const std::vector<virtual_ptr<Animal>>& animals, std::ostream& os) {
for (auto animal : animals) {
poke(animal, os);
}
}
int main() {
boost::openmethod::initialize();
Dog hector{"Hector"}, snoopy{"Snoopy"};
Cat felix{"Felix"}, sylvester{"Sylvester"};
std::vector<virtual_ptr<Animal>> animals = {
final_virtual_ptr(hector), virtual_ptr<Cat>::final(felix),
final_virtual_ptr(sylvester), virtual_ptr<Dog>::final(snoopy)};
poke_animals(animals, std::cout);
}

54
ce/uni-method-vptr.cpp Normal file
View File

@@ -0,0 +1,54 @@
#include <iostream>
#include <vector>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
struct Animal {
const char* name;
Animal(const char* name) : name(name) {
}
virtual ~Animal() {
}
};
struct Dog : Animal {
using Animal::Animal;
};
struct Cat : Animal {
using Animal::Animal;
};
BOOST_OPENMETHOD_CLASSES(Animal, Dog, Cat);
using boost::openmethod::virtual_ptr;
BOOST_OPENMETHOD(poke, (virtual_ptr<Animal>, std::ostream&), void);
BOOST_OPENMETHOD_OVERRIDE(
poke, (virtual_ptr<Cat> animal, std::ostream& os), void) {
os << animal->name << " hisses.\n";
}
BOOST_OPENMETHOD_OVERRIDE(
poke, (virtual_ptr<Dog> animal, std::ostream& os), void) {
os << animal->name << " barks.\n";
}
void poke_animals(
const std::vector<virtual_ptr<Animal>>& animals, std::ostream& os) {
for (auto animal : animals) {
poke(animal, os);
}
}
int main() {
boost::openmethod::initialize();
Dog hector{"Hector"}, snoopy{"Snoopy"};
Cat felix{"Felix"}, sylvester{"Sylvester"};
std::vector<virtual_ptr<Animal>> animals = {
hector, felix, sylvester, snoopy};
poke_animals(animals, std::cout);
}

48
ce/uni-method.cpp Normal file
View File

@@ -0,0 +1,48 @@
#include <iostream>
#include <vector>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
struct Animal {
const char* name;
Animal(const char* name) : name(name) {
}
virtual ~Animal() {
}
};
struct Dog : Animal {
using Animal::Animal;
};
struct Cat : Animal {
using Animal::Animal;
};
BOOST_OPENMETHOD_CLASSES(Animal, Dog, Cat);
BOOST_OPENMETHOD(poke, (virtual_<Animal&>, std::ostream&), void);
BOOST_OPENMETHOD_OVERRIDE(poke, (Cat & animal, std::ostream& os), void) {
os << animal.name << " hisses.\n";
}
BOOST_OPENMETHOD_OVERRIDE(poke, (Dog & animal, std::ostream& os), void) {
os << animal.name << " barks.\n";
}
void poke_animals(const std::vector<Animal*>& animals, std::ostream& os) {
for (auto animal : animals) {
poke(*animal, os);
}
}
int main() {
boost::openmethod::initialize();
Dog hector{"Hector"}, snoopy{"Snoopy"};
Cat felix{"Felix"}, sylvester{"Sylvester"};
std::vector<Animal*> animals = {&hector, &felix, &sylvester, &snoopy};
poke_animals(animals, std::cout);
}

69
ce/virtual-double.cpp Normal file
View File

@@ -0,0 +1,69 @@
#include <iostream>
#include <vector>
struct Cat;
struct Dog;
struct Animal {
const char* name;
Animal(const char* name) : name(name) {
}
virtual ~Animal() {
}
virtual void meet(Animal& other, std::ostream& os) = 0;
virtual void meet_cat(Cat& other, std::ostream& os) = 0;
virtual void meet_dog(Dog& other, std::ostream& os) = 0;
};
struct Cat : Animal {
using Animal::Animal;
void meet(Animal& other, std::ostream& os) override;
void meet_cat(Cat& other, std::ostream& os) override;
void meet_dog(Dog& other, std::ostream& os) override;
};
struct Dog : Animal {
using Animal::Animal;
void meet(Animal& other, std::ostream& os) override;
void meet_cat(Cat& other, std::ostream& os) override;
void meet_dog(Dog& other, std::ostream& os) override;
};
void meet_animals(const std::vector<Animal*>& animals, std::ostream& os) {
for (auto animal : animals) {
for (auto other : animals) {
if (animal != other) {
animal->meet(*other, os);
}
}
}
}
int main() {
Dog hector{"Hector"}, snoopy{"Snoopy"};
Cat felix{"Felix"}, sylvester{"Sylvester"};
std::vector<Animal*> animals = {&hector, &felix, &sylvester, &snoopy};
meet_animals(animals, std::cout);
}
void Cat::meet(Animal& other, std::ostream& os) {
other.meet_cat(*this, os);
}
void Cat::meet_cat(Cat& other, std::ostream& os) {
os << name << " ignores " << other.name << "\n";
}
void Cat::meet_dog(Dog& other, std::ostream& os) {
os << name << " runs away from " << other.name << "\n";
}
void Dog::meet(Animal& other, std::ostream& os) {
other.meet_dog(*this, os);
}
void Dog::meet_cat(Cat& other, std::ostream& os) {
os << name << " chases " << other.name << "\n";
}
void Dog::meet_dog(Dog& other, std::ostream& os) {
os << name << " wags tail at " << other.name << "\n";
}

38
ce/virtual.cpp Normal file
View File

@@ -0,0 +1,38 @@
#include <iostream>
#include <vector>
struct Animal {
const char* name;
Animal(const char* name) : name(name) {
}
virtual ~Animal() {
}
virtual void poke(std::ostream& os) = 0;
};
struct Dog : Animal {
using Animal::Animal;
void poke(std::ostream& os) override {
os << name << " barks.\n";
}
};
struct Cat : Animal {
using Animal::Animal;
void poke(std::ostream& os) override {
os << name << " hisses.\n";
}
};
void poke_animals(const std::vector<Animal*>& animals, std::ostream& os) {
for (auto animal : animals) {
animal->poke(os);
}
}
int main() {
Dog hector{"Hector"}, snoopy{"Snoopy"};
Cat felix{"Felix"}, sylvester{"Sylvester"};
std::vector<Animal*> animals = {&hector, &felix, &sylvester, &snoopy};
poke_animals(animals, std::cout);
}

137
clang-llvm Normal file
View File

@@ -0,0 +1,137 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: false
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: MultiLine
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
- Regex: '.*'
Priority: 1
SortPriority: 0
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentCaseLabels: false
IndentGotoLabels: true
IndentPPDirectives: None
IndentWidth: 2
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
Standard: Latest
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseCRLF: false
UseTab: Never
...

5
dev/ci-pre-configure-clang Executable file
View File

@@ -0,0 +1,5 @@
#!/bin/bash
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh $1

40
dev/flatten.py Normal file
View File

@@ -0,0 +1,40 @@
#!/usr/bin/python3
import argparse
from pathlib import Path
import re
parser = argparse.ArgumentParser()
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':
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:
return
done.add(header)
with input.open() as ifh:
for line in ifh:
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)
with args.output.open('w') as ofh:
done = set()
for input in args.input:
flatten(input.absolute(), ofh, done)

8
dev/reformat Executable file
View File

@@ -0,0 +1,8 @@
#!/bin/bash
cd "$(dirname $0)/.."
srcs=$(find include examples test \
-name '*.?pp' | grep -v cmake_fetchcontent | grep -v /CMakeFiles)
clang-format -i --verbose $srcs

98
dev/v2-boost.py Normal file
View File

@@ -0,0 +1,98 @@
#!/usr/bin/python3
import os
from pathlib import Path
import re
from subprocess import check_call
import subprocess
import sys
BOOST_NAME = "openmethod"
BOOST_INCLUDE = Path("include", "boost", BOOST_NAME)
BOOST_OPENMETHOD_PATH = Path.home().joinpath("dev", "boost", "libs", BOOST_NAME)
YOMM2_V2_PATH = Path.home().joinpath("dev", "yomm2")
YOMM2_DIRS = "include/yorel/yomm2 tests examples ce".split()
SKIP = [
"cute",
"keywords",
"benchmark",
"pss1",
"lab",
"manual_call",
"generator",
"containers",
"conan",
"vcpkg",
"README",
"cmakeyomm2",
"templates",
]
REPLACE = (
("YOREL_YOMM2_", f"BOOST_{BOOST_NAME.upper()}_"),
("YOMM2_", f"BOOST_{BOOST_NAME.upper()}_"),
("yOMM2_", f"BOOST_{BOOST_NAME.upper()}_DETAIL_"),
("BOOST_OPENMETHOD_METHOD", "BOOST_OPENMETHOD"),
("#include <yorel/yomm2/", f"#include <boost/{BOOST_NAME}/"),
("<boost/openmethod/keywords.hpp>", "<boost/openmethod.hpp>"),
("yorel", "boost"),
("yomm2", "openmethod"),
("YOMM2_DECLARE|declare_method", "BOOST_OPENMETHOD"),
("YOMM2_DEFINE|define_method", "BOOST_OPENMETHOD_OVERRIDE"),
("YOMM2_CLASS(ES)?|register_class(es)?", "BOOST_OPENMETHOD_CLASSES"),
)
git = f"git diff --name-only -- boost test examples"
print(git)
modified = subprocess.check_output(git.split(), encoding="ascii")
if modified:
sys.exit("Unstaged changes:\n" + modified)
git = f"git -C {YOMM2_V2_PATH} rev-parse --abbrev-ref HEAD"
print(git)
version = subprocess.check_output(git.split(), encoding="ascii").strip()
if version != "v2":
sys.exit(f"Source directory is at version {version}, v2 is required.\n")
def skip(path):
for skip in SKIP:
if skip in str(path):
return True
return False
for dir in YOMM2_DIRS:
for from_path in (YOMM2_V2_PATH / dir).rglob("*.?pp"):
if skip(from_path):
continue
with from_path.open() as f:
content = f.read()
content = re.sub(r'#include "(yorel/yomm2/[^"])+"', r"#include <\1>", content)
for replace in REPLACE:
content = re.sub(*replace, content)
to_path = Path(
str(from_path)
.replace(str(YOMM2_V2_PATH), str(BOOST_OPENMETHOD_PATH))
.replace("yorel/yomm2", f"boost/{BOOST_NAME}")
.replace("tests/", "test/")
)
print(f"{from_path} -> {to_path}...")
to_path.parent.mkdir(parents=True, exist_ok=True)
with to_path.open("w") as f:
f.write(content)
check_call(["clang-format", "-i", str(to_path)])
print("done")

39
dev/yomm2filt Executable file
View File

@@ -0,0 +1,39 @@
#!/usr/bin/env python3
import argparse
import fileinput
import re
from subprocess import Popen, PIPE
import threading
parser = argparse.ArgumentParser()
parser.add_argument("-s", "--scope", help="do not simplify scopes")
parser.add_argument("-y", "--prefix", help="do not remove YOMM2 prefixes")
parser.add_argument("-p", "--policy", help="do not remove policy")
parser.add_argument("files", nargs="*", default=("-"))
args = parser.parse_args()
def process(fh):
while True:
line = fh.readline()
if not line:
return
if not args.prefix:
line = re.sub(r"\s*,\s*yorel::yomm2::policy::\w+", "", line)
if not args.scope:
line = re.sub(r"(\w+::)+", "", line)
if not args.prefix:
line = re.sub(r"YoMm2_S_", "", line)
print(line, end="")
i = 0
with Popen(
"/usr/bin/c++filt --types".split(), stdin=PIPE, stdout=PIPE, encoding="ascii"
) as cppfilt:
demangler = threading.Thread(target=process, args=[cppfilt.stdout])
demangler.start()
for line in fileinput.input(files=args.files):
print(line, file=cppfilt.stdin, end="")
cppfilt.stdin.close()
demangler.join()

43
doc/BOOST_OPENMETHOD.adoc Normal file
View File

@@ -0,0 +1,43 @@
[#BOOST_OPENMETHOD]
## BOOST_OPENMETHOD
### Synopsis
Defined in <boost/openmethod/macros.hpp>.
```c++
BOOST_OPENMETHOD(NAME, (PARAMETERS...), RETURN_TYPE [, POLICY]);
```
### Description
Declares a method.
### Effects
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: 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

@@ -0,0 +1,23 @@
[#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

@@ -0,0 +1,22 @@
[#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

@@ -0,0 +1,19 @@
[#BOOST_OPENMETHOD_INLINE_OVERRIDE]
## BOOST_OPENMETHOD_INLINE_OVERRIDE
### Synopsis
Defined in <boost/openmethod/macros.hpp>.
```c++
BOOST_OPENMETHOD_INLINE_OVERRIDE(NAME, (PARAMETERS...), RETURN_TYPE) {
// body
}
```
### Description
`BOOST_OPENMETHOD_INLINE_OVERRIDE` performs the same function as
`BOOST_OPENMETHOD_OVERRIDE`, except that the overrider is defined inline.

View File

@@ -0,0 +1,17 @@
[#BOOST_OPENMETHOD_NAME]
## BOOST_OPENMETHOD_NAME
### Synopsis
Defined in <boost/openmethod/macros/name.hpp>.
```c++
#define BOOST_OPENMETHOD_NAME(NAME) boost_openmethod_#NAME
```
### Description
Generate a long name from a short name, hopefully avoiding conflicts with
user-defined names.

View File

@@ -0,0 +1,59 @@
[#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.

View File

@@ -0,0 +1,16 @@
## BOOST_OPENMETHOD_OVERRIDERS
### Synopsis
Defined in <boost/openmethod/macros.hpp>.
```c++
#define BOOST_OPENMETHOD_OVERRIDERS(NAME) \
BOOST_PP_CAT(BOOST_OPENMETHOD_NAME(NAME), _overriders)
```
### Description
`BOOST_OPENMETHOD_OVERRIDERS` expands to the name of the class template that
contains the overriders for all the methods with a given name.

View File

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

19
doc/Jamfile Normal file
View File

@@ -0,0 +1,19 @@
# 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 ;

18
doc/abstract_policy.adoc Normal file
View File

@@ -0,0 +1,18 @@
## abstract_policy
### Synopsis
Defined in <boost/openmethod/policies/basic_policy.hpp>.
```c++
namespace boost::openmethod::policies {
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
and the (optional) policy class.

View File

@@ -0,0 +1,34 @@
## basic_error_output
### Synopsis
Defined in <boost/openmethod/policies/basic_error_output.hpp>.
```c++
namespace boost::openmethod::policies {
template<class Policy, typename Stream = /*unspecified*/>
struct basic_error_output : virtual error_output {
static Stream error_stream;
};
}
```
### Description
`basic_error_output` is an implementation of `error_output` that writes error
messages to a `RestrictedOutputStream`.
### Members
#### error_stream
```c++
Stream error_stream;
```
Initialized by the default constructor of `Stream`. It is the responsibility of
the program to initializate it if needed, e.g., for a `std::ofstream`, to open
it.

144
doc/basic_policy.adoc Normal file
View File

@@ -0,0 +1,144 @@
## basic_policy
### Synopsis
Defined in <boost/openmethod/policies/basic_policy.hpp>.
```c++
namespace boost::openmethod {
namespace policies {
template<class Policy, class... Facets>
struct basic_policy : virtual abstract_policy,
virtual domain<Policy>,
virtual Facets... {
template<class Facet>
static constexpr bool has_facet = /*unspecified*/;
template<class NewPolicy>
using fork = /*unspecified*/;
template<class... MoreFacets>
using add = /*unspecified*/;
template<class Base, class Facet>
using replace = /*unspecified*/;
template<class Base>
using remove = /*unspecified*/;
};
struct release : basic_policy<release, ...> {};
struct debug : release::add<...> {};
} // policies
#ifdef NDEBUG
using default_policy = policies::release;
#else
using default_policy = policies::debug;
#endif
} // boost::openmethod
```
### 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
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.
### Members
#### has_facet
```c++
template<class Facet>
static constexpr bool has_facet;
```
Evaluates to `true` if _Policy_ contains _Facet_.
#### fork
```c++
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.
#### add
```c++
template<class... MoreFacets>
using add;
```
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.
#### replace
```c++
template<class Base, class NewFacet>
using replace;
```
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.
The original policy and the new one share static variables.
#### 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.
### Non-members
#### release
```c++
struct release;
```
A policy that contains facet implementations `std_rtti`, `fast_perfect_hash`,
`vptr_vector` and `vectored_error_handler`.
#### debug
```c++
struct debug;
```
The `release` policy with additional facet 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
An alias for `release` if `NDEBUG` is defined, and for `debug` otherwise.

View File

@@ -0,0 +1,43 @@
## basic_trace_output
### Synopsis
Defined in <boost/openmethod/policies/basic_trace_output.hpp>.
```c++
namespace boost::openmethod::policies {
template<class Policy, typename Stream = /*unspecified*/>
struct basic_trace_output : virtual trace_output {
static bool trace_enabled;
static Stream trace_stream;
};
}
```
### Description
`basic_error_output` is an implementation of `trace_output` that writes error
messages to a `RestrictedOutputStream`.
### Members
#### trace_enabled
```c++
static bool trace_enabled;
```
Set to `true` if environment variable `BOOST_OPENMETHOD_TRACE` is set to `1`.
#### trace_stream
```c++
static Stream trace_stream;
```
Initialized by the default constructor of `Stream`. It is the responsibility of
the program to prepare it for output if needed, e.g., for a `std::ofstream`, to
open it.

92
doc/core_api.adoc Normal file
View File

@@ -0,0 +1,92 @@
## 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]
----

163
doc/custom_rtti.adoc Normal file
View File

@@ -0,0 +1,163 @@
## Custom RTTI
Stock policies use the `std_rtti` implementation of `rtti`. Here is its full
source:
[source,c++]
----
struct std_rtti : rtti {
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);
}
};
----
* `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]
----
Now we can include the "core" header and write the example:
[source,c++]
----
include::{examplesdir}/custom_rtti.cpp[tag=example]
----
This programs compiles 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

@@ -0,0 +1,25 @@
## deferred_static_rtti
### Synopsis
Defined in <boost/openmethod/policies/basic_policy.hpp>.
```c++
namespace boost::openmethod::policies {
struct deferred_static_rtti : virtual rtti {};
}
```
### Description
`deferred_static_rtti` is a facet 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
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
`initialize`.

12
doc/docinfo.html Normal file
View File

@@ -0,0 +1,12 @@
<meta name="keywords" content="c++,error handling,open source">
<meta name="description" content="Lightweight Error Augmentation Framework">
<link rel="stylesheet" href="./zajo-light.css" disabled=true>
<script>
function switch_style()
{
var i, tag;
for( i=0, tag=document.getElementsByTagName("link"); i<tag.length; i++ )
if( tag[i].rel.indexOf("stylesheet")!=-1 && tag[i].href.includes("zajo-") )
tag[i].disabled = !tag[i].disabled;
}
</script>

34
doc/domain.adoc Normal file
View File

@@ -0,0 +1,34 @@
## domain
### Synopsis
Defined in <boost/openmethod/policies/basic_policy.hpp>.
```c++
namespace boost::openmethod::policies {
template<class Policy>
struct domain {
template<class Class> static vptr_type static_vptr;
// unspecified members
};
}
```
### Description
`domain` is a registry of classes and methods registered in a _Policy_,
and their dispatch tables.
### Members
#### static_vptr
```c++
template<class Class>
static vptr_type static_vptr;
```
Contains the pointer to the v-table for _Class_. Set by `initialize`.

63
doc/error_handler.adoc Normal file
View File

@@ -0,0 +1,63 @@
## error_handler
### Synopsis
Defined in <boost/openmethod/policies/basic_policy.hpp>.
```c++
namespace boost::openmethod::policies {
struct error_handler;
}
```
Defined in <boost/openmethod/types.hpp>.
```c++
namespace boost::openmethod {
struct openmethod_error {};
struct not_implemented_error : openmethod_error {
type_id method;
std::size_t arity;
static constexpr std::size_t max_types = 16;
type_id types[max_types];
};
struct unknown_class_error : openmethod_error {
type_id type;
};
struct hash_search_error : openmethod_error {
std::size_t attempts;
std::size_t buckets;
};
struct type_mismatch_error : openmethod_error {
type_id type;
};
} // boost::openmethod::policies
```
### Description
`error_handler` is a facet 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
policy, its `error` function is called with an error object. It can prevent
termination by throwing an exception.
### Requirements
Implementations of `error_handler` must provide the following functions:
#### error
```c++
| static auto error(const T&) -> void;
```

55
doc/error_handling.adoc Normal file
View File

@@ -0,0 +1,55 @@
## 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
```

28
doc/error_output.adoc Normal file
View File

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

39
doc/friendship.adoc Normal file
View File

@@ -0,0 +1,39 @@
## Friendship
Overriders are implemented as static functions located in specializations of a
template named after the method, declared in the same scope. Macro
`BOOST_OPENMETHOD_OVERRIDERS` returns that name. 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` - even with
a different signature - are granted friendship.
We can also grant friendship to individual overriders:
[source,c++]
----
include::{examplesdir}/friendship.cpp[tag=friend]
----
// If the overriders exist in a different namespace, we must take into account that
// the overriders template is declared in the current namespace.
// [source,c++]
// ----
// include::{examplesdir}/friendship_across_namespaces.cpp[tag=friend]
// ----

37
doc/headers.adoc Normal file
View File

@@ -0,0 +1,37 @@
### <boost/openmethod.hpp>
### <boost/openmethod/core.hpp>
### <boost/openmethod/shared_ptr.hpp>
### <boost/openmethod/unique_ptr.hpp>
### <boost/openmethod/compiler.hpp>
### <boost/openmethod/policies.hpp>
### <boost/openmethod/macros.hpp>
### <boost/openmethod/macros/register.hpp>
### <boost/openmethod/macros/name.hpp>
### <boost/openmethod/policies/basic_policy.hpp>
### <boost/openmethod/policies/vectored_error_handler.hpp>
### <boost/openmethod/policies/std_rtti.hpp>
### <boost/openmethod/policies/basic_trace_output.hpp>
### <boost/openmethod/policies/basic_error_output.hpp>
### <boost/openmethod/policies/basic_indirect_vptr.hpp>
### <boost/openmethod/policies/vptr_map.hpp>
### <boost/openmethod/policies/fast_perfect_hash.hpp>
### <boost/openmethod/policies/vptr_vector.hpp>
### <boost/openmethod/policies/throw_error.hpp>

103
doc/hello_world.adoc Normal file
View File

@@ -0,0 +1,103 @@
## 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++.

199
doc/html/rouge-github.css Normal file
View File

@@ -0,0 +1,199 @@
.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;
}

BIN
doc/html/skin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

478
doc/html/zajo-dark.css Normal file
View File

@@ -0,0 +1,478 @@
/* 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}

468
doc/html/zajo-light.css Normal file
View File

@@ -0,0 +1,468 @@
/* 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}

61
doc/introduction.adoc Normal file
View File

@@ -0,0 +1,61 @@
# Introduction
Open-methods are similar to virtual functions, but they are not required to be
members of a class. By being both free and virtual, they provide a solution to
the Expression Problem:
> Given a set of types, and a set of operations on these types, is it possible
to add new operations on the existing types, and new types to the existing
operations, without modifying existing code?
As a bonus, open-methods can take more than one argument into account when
selecting the appropriate function to call - aka multiple dispatch. For that
reason, open-methods are often called multi-methods, but that term is
misleading, as it suggests that the feature is useful only when multiple
dispatch is needed. In reality,
https://openaccess.wgtn.ac.nz/articles/thesis/Multiple_Dispatch_in_Practice/16959112/1[it
has been observed] that, in large systems written in languages that support
multi-methods, most methods use single-dispatch. The real benefit is in the
solution to the Expression Problem.
Open-methods were introduced by the Common Lisp Object System, and they are
native to many languages: Clojure, Julia, Dylan, TADS, Cecil, Diesel, Nice, etc.
Bjarne Stroustrup wanted open-methods in C++ almost from the beginning. In D&E
he writes:
> I repeatedly considered a mechanism for a virtual function call based on more
than one object, often called multi-methods. I rejected multi-methods with
regret because I liked the idea, but couldnt find an acceptable form under
which to accept it. [...] Multi-methods is one of the interesting what-ifs of
C++. Could I have designed and implemented them well enough at the time? Would
their applications have been important enough to warrant the effort? What other
work might have been left undone to provide the time to design and implement
multi-methods? Since about 1985, I have always felt some twinge of regret for
not providing multi-methods (Stroustrup, 1994, The Design and Evolution of
C{plus}{plus}, 13.8).
Circa 2007, he and his PhD students Peter Pirkelbauer and Yuriy Solodkyy wrote a
series of papers and a prototype implementation based on the EDG compiler.
Unfortunately, open-methods never made it into the standard. Stroustrup bemoans,
in a more recent paper:
> In retrospect, I dont think that the object-oriented notation (e.g., x.f(y))
should ever have been introduced. The traditional mathematical notation f(x,y)
is sufficient. As a side benefit, the mathematical notation would naturally have
given us multi-methods, thereby saving us from the visitor pattern workaround
(Stroustrup, 2020, Thriving in a Crowded and ChangingWorld: C++ 20062020).
This library implements the features described in the
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2216.pdf[N2216 paper],
with some
extensions:
* a mechanism for calling the next most specialized overrider
* support for smart pointers
* customization points for RTTI, error handling, tracing, smart pointers...
Multiple and virtual inheritance are supported, with the exception of repeated
inheritance.

62
doc/map_vptr.adoc Normal file
View File

@@ -0,0 +1,62 @@
## vptr_map
### Synopsis
```c++
namespace boost::openmethod::policies {
### Synopsis
template<
class Policy, bool IndirectVptr,
class Map = std::unordered_map<
type_id,
std::conditional_t<IndirectVptr, const vptr_type*, vptr_type>>>
class vptr_map : extern_vptr {
static Map vptrs;
template<typename ForwardIterator>
static auto register_vptrs(ForwardIterator first, ForwardIterator last) -> void;
template<class Class>
static auto dynamic_vptr(const Class& arg) -> const vptr_type&;
};
}
```
### Description
`vptr_map` is an implementation of `external_vptr that stores the pointers to
the v-tables in a map.
`Policy` is the policy containing the facet.
`Map` is an `AssociativeContainer`. The `mapped_type` is a pointer to a
`vptr_type` if `UseIndirectVptrs` is `void`, or a pointer to a `vptr_type` if
`UseIndirectVptrs` is `indirect_vptr`.
### Members
#### register_vptrs
```c++
template<typename ForwardIterator>
auto register_vptrs(ForwardIterator first, ForwardIterator last) -> void;
```
Stores the pointers to v-tables in a _Map_.
#### dynamic_vptr
```c++
template<class Class>
auto dynamic_vptr(const Class& object) -> const vptr_type&;
```
Returns a pointer to the v-table for `object` (by reference).
If _Policy_ contains the `runtime_checks` facet, checks if _Class_ is
registered. If it is not, and _Policy_ contains a `error_handler` facet, calls
its `error` function; then calls `abort`.

152
doc/method.adoc Normal file
View File

@@ -0,0 +1,152 @@
## method
### Synopsis
```c++
namespace boost::openmethod {
template<
typename Method, typename ReturnType,
class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY>
class method;
template<typename Name, typename... Parameters, typename ReturnType, class Policy>
class method<Name(Parameters...), ReturnType, Policy> {
public:
using function_type = ReturnType (*)(CallParameters...);
auto operator()(CallParameters... args) const -> ReturnType;
static method fn;
template<auto... Functions>
struct override;
template<auto Overrider>
static function_type next;
private:
method();
method(const method&) = delete;
method(method&&) = delete;
~method();
};
}
```
### Description
`method` implements an open-method that takes a parameter list - `Parameters` -
and returns a `ReturnType`. `Name` can be any type. Its purpose is to make it
possible to have multiple methods with the same signature. Typically, `Name` is
a class whose name reflects the method's purpose.
`Parameters` must contain at least one virtual parameter, i.e. a parameter that
has a type in the form `virtual_ptr<T,{nbsp}Policy>` or `virtual_<T>`. The
dynamic types of the virtual arguments (the arguments corresponding to virtual
parameters in the method's signature) are taken into account to select the
overrider to call.
A `method` is attached to a `Policy`, which influences several parts of the
dispatch mechanism - for example, how to obtain a v-table pointer for an object,
how to report errors, whether to perform sanity checks, etc.
### Members
#### constructor
```c++
method();
```
Add the method to the list of methods registered in `Policy`.
The constructor is private. The only instance is the static member variable
`fn`.
#### destructor
```c++
~method();
```
Remove the method from the list of methods registered in `Policy`.
#### operator()
```c++
auto operator()(CallParameters... args) const -> ReturnType;
```
Call the method with the arguments `args`.
`CallParameters` are the `Parameters` without the `virtual_` decorators. Note
that `virtual_ptr`{empty}s are preserved.
The overrider is selected in a process similar to overloaded function
resolution, with extra rules to handle ambiguities. It proceeds as follows:
1. Form the set of all applicable overriders. An overrider is applicable if it
can be called with the arguments passed to the method.
2. If the set is empty, call the error handler (if present in the policy), then
terminate the program with `abort`
3. Remove the overriders that are dominated by other overriders in the set.
Overrider A dominates overrider B if any of its virtual formal parameters is
more specialized than B's, and if none of B's virtual parameters is more
specialized than A's.
4. If the resulting set contains only one overrider, call it.
5. If the return type is a registered polymorphic type, remove all the
overriders that return a less specific type than the others.
6. If the resulting set contains only one overrider, call it.
7. Otherwise, call one of the remaining overriders. Which overrider is selected
is not specified, but it is the same across calls with the same arguments
types.
For each virtual argument `arg`, the dispatch mechanism calls
`virtual_traits::peek(arg)` and deduces the v-table pointer from the `result`,
using the first of the following methods that applies:
1. If `result` is a `virtual_ptr`, get the pointer to the v-table from it.
2. If a function named `boost_openmethod_vptr` that takes `result` and returns a
`vptr_type` exists, call it.
3. Call `Policy::dynamic_vptr(result)`.
#### fn
```c++
static method fn;
```
The `method`{empty}'s unique instance. The method is called via the call
operator on `fn`: `method::fn(args...)`.
#### override
```c++
template<auto... Functions>
struct override;
```
Add _Functions_ to the overriders of `method`.
#### next
```c++
template<auto Overrider>
static function_type next;
```
Pointer to the next most specialized overrider after _Overrider_, i.e. the
overrider that would be called for the same tuple of virtual arguments if
_Overrider_ was not present. Set to `nullptr` if no such overrider exists.

64
doc/method_override.adoc Normal file
View File

@@ -0,0 +1,64 @@
[#method_override]
## method::override
### Synopsis
```c++
namespace boost::openmethod {
template<typename Signature, typename ReturnType, class Policy>
template<auto... Functions>
struct method<Signature, ReturnType, Policy>::override {
override();
~override();
};
}
```
Usage:
```c++
method<Signature, ReturnType, Policy>::override<Functions...> some_unique_name;
// at file scope
```
### Description
`override`, instantiated as a static object, add one or more overriders to an
open-method.
_Functions_ must fulfill the following requirements:
* Have the same number of formal parameters as the method.
* Each parameter in the same position as a `virtual_ptr<T>` in the method's
parameter list must be a `virtual_ptr<U>`, where _U_ is covariant with _T_. The
_Policy_ of the `virtual_ptr`{empty}s must be the same as the method's _Policy_.
* Each formal parameter in the same position as a `virtual_` parameter must have
a type that is covariant with the type of the method's parameter.
* All other formal parameters must have the same type as the method's
corresponding parameters.
* The return type of the overrider must be the same as the method's return type
or, if it is a polymorphic type, covariant with the method's return type.
### Members
#### constructor
```c++
override<Functions>::override();
```
Add _Functions_ to the overriders of `method`.
#### Destructor
```c++
override<Functions>::~method();
```
Remove _Functions_ from the overriders of `method`.

35
doc/minimal_rtti.adoc Normal file
View File

@@ -0,0 +1,35 @@
## minimal_rtti
### Synopsis
```c++
struct minimal_rtti : virtual rtti {
template<typename Class>
static auto static_type() -> type_id;
};
```
### Description
`minimal_rtti` is an implementation of the `rtti` facet that only uses static
type information.
`minimal_rtti` provides the only function strictly required for the `rtti`
facet.
This facet 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.
### Members
#### static_type
```c++
template<class Class>
static auto static_type() -> type_id;
```
Returns the address of a local static `char` variable, cast to `type_id`.

View File

@@ -0,0 +1,20 @@
## Multiple Dispatch
A method can have more than one `virtual_ptr` parameter. For example:
[source,c++]
----
include::{examplesdir}/hello_world.cpp[tag=multi]
----
[source,c++]
----
include::{examplesdir}/hello_world.cpp[tag=multi_call,indent=0]
----
The appropriate overrider is selected using a process similar to overload
resolution, with fallback options. If one overrider is more specialized than all
the others, call it. Otherwise, the return type is used as a tie-breaker, _if_
it is covariant with the return type of the base method. If there is still no
unique best overrider, one of the best overriders is chosen arbitrarily.

View File

@@ -0,0 +1,7 @@
## Multiple Inheritance
Multiple inheritance is supported, with the exception of repeated inheritance.
Virtual inheritance is supported, but it incurs calls to `dynamic_cast` to cast
the method's arguments to the types required by the overrider.

28
doc/openmethod-theme.yml Normal file
View File

@@ -0,0 +1,28 @@
extends: default
base:
font:
color: #404040
literal:
font:
family: Courier
color: #000000
admonition:
icon:
note:
stroke-color: #000000
tip:
stroke-color: #000000
warning:
stroke-color: #FF5100
important:
stroke-color: #FF5100
caution:
stroke-color: #FF5100
conum:
font:
glyphs: circled
color: #000000
link:
text-decoration: underline
text-decoration-width: 0.5
font-color: #000000

19
doc/openmethod.adoc Normal file
View File

@@ -0,0 +1,19 @@
# Boost.OpenMethod
Jean-Louis Leroy
:toc: left
:toclevels: 3
:idprefix:
:listing-caption: Code Example
:table-caption: Illustration
:docinfo: private-footer
:source-highlighter: rouge
:source-language: c++
:leveloffset: +1
include::introduction.adoc[]
include::tutorial.adoc[]
include::reference.adoc[]
:leveloffset: -1

102
doc/performance.adoc Normal file
View File

@@ -0,0 +1,102 @@
## Performance
Open-methods are almost as fast as ordinary virtual member functions when
compiled with optimization.
clang compiles the following code:
[source,c++]
----
include::{examplesdir}/hello_world.cpp[tag=call_poke_via_ref]
----
...to this on the x64 architecture (variable names have been shortened for
readability):
[source,asm]
----
mov rax, qword ptr [rsi]
mov rdx, qword ptr [rip + hash_mult]
imul rdx, qword ptr [rax - 8]
movzx ecx, byte ptr [rip + hash_shift]
shr rdx, cl
mov rax, qword ptr [rip + vptrs]
mov rax, qword ptr [rax + 8*rdx]
mov rcx, qword ptr [rip + poke::slots_strides]
mov rax, qword ptr [rax + 8*rcx]
jmp rax
----
llvm-mca estimates a throughput of 4 cycles per dispatch. Comparatively, calling
a native virtual functions takes one cycle. However, the difference is amortized
by the time spent passing the arguments and returning from the function; plus,
of course, executing the body of the function.
Micro benchmarks suggest that dispatching an open-methods with a single virtual
argument is between 30% and 50% slower than calling the equivalent virtual
function, with an empty body and no other arguments.
However, `call_poke` does two things: it constructs a `virtual_ptr<Animal>` from
an `Animal&`; and then it calls the method. The construction of the
`virtual_ptr` is the costly part, as it involves a hash table lookup. Once that
price has been paid, the `virtual_ptr` can be used multiple times. It is passed
to the overrider, which can make further method calls through it. It can be
stored in variables in place of plain pointers.
Let's look at another example: an AST for an arithmetic calculator:
[source,c++]
----
include::{examplesdir}/ast.cpp[tag=ast]
----
The `Negate` overrider compiles to:
[source,asm]
----
mov rdi, qword ptr [rsi + 8]
mov rsi, qword ptr [rsi + 16]
mov rax, qword ptr [rip + value::slots_strides]
call qword ptr [rdi + 8*rax]
neg eax
pop rcx
----
The first two instructions read the `virtual_ptr` from `this` - placing its
content in registers `rdi` and `rsi`.
The next two instructions are the method call proper. According to llvm-mca,
they take one cycle - the same as a native virtual function call.
When we create the `Plus` and `Negate` nodes, we call the conversion
constructors of `virtual_ptr<Node>`, which occur the cost of hash table lookups.
However, in this example, we know the exact types of the objects. In that case,
we can use `final_virtual_ptr` to construct the `virtual_ptr` using a single
instruction. For example:
[source,c++]
----
include::{examplesdir}/ast.cpp[tag=final,indent=0]
----
...compiles to:
```asm
;; construct Literal
lea rax, [rip + vtable for Literal+16]
mov qword ptr [rsp], rax
mov dword ptr [rsp+8], 1
;; construct Negate
mov rax, qword ptr [rip+static_vptr<Literal>] ; address of openmethod v-table
lea rcx, [rip+vtable for Negate+16] ; address of native v-table
mov qword ptr [rsp+16], rcx ; set native v-table
mov qword ptr [rsp+24], rax ; set openmethod v-table
mov rax, rsp ; address of 'one'
mov qword ptr [rsp+32], rax ; set vptr object pointer to 'one'
```
`final_virtual_ptr` does not require its argument to have a polymorphic type.

91
doc/policies.adoc Normal file
View File

@@ -0,0 +1,91 @@
## Policies and Facets
Methods and classes are scoped in a policy. A method can only reference classes
registered in the same policy. If a class is used as a virtual parameter in
methods using different policies, it must be registered with each of them.
Class templates `use_classes`, `method`, `virtual_ptr`, and macros
`BOOST_OPENMETHOD` and `BOOST_OPENMETHOD_CLASSES`, accept an additional
argument, a policy class, which defaults to `policies::debug` in debug builds,
and `policies::release` in release builds.
A policy has a collection of _facets_. Facets control how type information is
obtained, how vptrs are fetched, how errors are handled and printed, etc. Some
are used in `initialize` and method dispatch; some are used by other facets in
the same policy as part of their implementation. See the reference for a list of
facets and stock implementations. Policies and facets are placed in the
`boost::openmethod::policies` namespace. Two policies are provided by the
library: `release` and `debug`.
`release` contains the following facets:
[cols="1,1,1"]
|===
|facet |implementation |role
| rtti
| std_rtti
| provides type information for classes and objects
| vptr
| vptr_vector
| stores vptrs in a global vector
| type_hash
| fast_perfect_hash
| hash type id to an index in a vector
| error_handler
| vectored_error_handler
| calls a handler via a `std::function`
|===
`policies::debug` contains the same facets as `release`, plus a few more:
[cols="1,1,1"]
|===
|facet |implementation |role
| runtime_checks
| (itself)
| enables runtime checks
| error_output
| basic_error_output
| prints error descriptions to `stderr`
| trace_output
| basic_trace_output
| enables `initialize` to print information about dispatch table construction to `stderr`
|===
Policies, and some facets, have static variables. When it is the case, they are
implemented as CRTP classes.
Policies can be created from scratch, using the `basic_policy` template, or by
adding or removing facets from existing policies. For example, `policies::debug`
is a tweak of `policies::release`:
[source,c++]
----
namespace boost::openmethod::policies {
struct debug : release::add<
runtime_checks, basic_error_output<debug>,
basic_trace_output<debug>> {};
}
----
`boost::openmethod::default_policy` is an alias to `release` or `debug`,
depending on the value of preprocessor symbols `NDEBUG`. The default policy can
be overriden by defining the macroprocessor symbol
`BOOST_OPENMETHOD_DEFAULT_POLICY` _before_ including
`<boost/openmethod/core.hpp>`. The value of the symbol is used as a default
template parameter for `use_classes`, `method`, `virtual_ptr`, and others. Once
the `core` header has been included, changing `BOOST_OPENMETHOD_DEFAULT_POLICY`
has no effect. See below for examples.

45
doc/reference.adoc Normal file
View File

@@ -0,0 +1,45 @@
# Reference
:toc:
:toc-title:
:idprefix: ref_
// include::headers.adoc[]
include::BOOST_OPENMETHOD.adoc[]
include::BOOST_OPENMETHOD_OVERRIDE.adoc[]
include::BOOST_OPENMETHOD_INLINE_OVERRIDE.adoc[]
include::BOOST_OPENMETHOD_REGISTER.adoc[]
include::BOOST_OPENMETHOD_CLASSES.adoc[]
include::BOOST_OPENMETHOD_DEFAULT_POLICY.adoc[]
include::BOOST_OPENMETHOD_NAME.adoc[]
include::BOOST_OPENMETHOD_OVERRIDERS.adoc[]
include::typedefs.adoc[]
include::method.adoc[]
include::method_override.adoc[]
include::virtual_ptr.adoc[]
include::virtual_traits.adoc[]
include::use_classes.adoc[]
include::virtual_.adoc[]
include::with_vptr.adoc[]
include::abstract_policy.adoc[]
include::domain.adoc[]
include::basic_policy.adoc[]
include::rtti.adoc[]
include::std_rtti.adoc[]
include::deferred_static_rtti.adoc[]
include::minimal_rtti.adoc[]
include::vptr.adoc[]
include::vector_vptr.adoc[]
include::map_vptr.adoc[]
include::type_hash.adoc[]
include::error_handler.adoc[]
include::vectored_error_handler.adoc[]
include::throw_error_handler.adoc[]
include::error_output.adoc[]
include::basic_error_output.adoc[]
include::trace_output.adoc[]
include::basic_trace_output.adoc[]
include::restricted_output_stream.adoc[]

View File

@@ -0,0 +1,35 @@
## RestrictedOutputStream
### Description
RestrictedOutputStream is a concept describing a `std::ostream`-like class with
a reduced set of operations.
While convenient, `std::ostream` and its implementations constitute a sizeable
piece of code, which may make it unsuitable for certain applications. OpenMethod
uses a small subset of the operations supported by `std::ostream`. By default,
the library uses a lightweight implementation based on the C stream functions.
Implementations of `RestrictedOutputStream` provide the following functions:
[cols="a,a", options="header"]
|===
| Name
| Description
| RestrictedOutputStream& operator<<(RestrictedOutputStream& os, const char* str)
| Write a null-terminated string `str` to `os`
| RestrictedOutputStream& operator<<(RestrictedOutputStream& os, const std::string_view& view)
| Write a view to `os
| RestrictedOutputStream& operator<<(RestrictedOutputStream& os, const void* value)
| Write a representation of a pointer to `os`
| RestrictedOutputStream& operator<<(RestrictedOutputStream& os, std::size_t value)
| Write an unsigned integer to `os`
|===

199
doc/rouge-github.css Normal file
View File

@@ -0,0 +1,199 @@
.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;
}

71
doc/rtti.adoc Normal file
View File

@@ -0,0 +1,71 @@
## rtti
### Synopsis
Defined in <boost/openmethod/policies/basic_policy.hpp>.
```c++
namespace boost::openmethod::policies {
struct rtti {};
} // boost::openmethod::policies
```
### Description
The `rtti` facet provides type information for classes and objects, implements
downcast in presence of virtual inheritance, and writes descriptions of types to
an `ostream`-like object.
### Requirements
#### static_type
```c++
template<class Class>
static auto static_type() -> type_id;
```
Returns a `type_id` for `Class`.
#### dynamic_type
```c++
template<class Class>
static auto dynamic_type(const Class& obj) -> type_id;
```
Returns a `type_id` for an object's dynamic type.
#### type_name
```c++
template<typename Stream>
static auto type_name(type_id type, Stream& stream) -> void;
```
Writes a description of `type` to `stream`.
This requirement is optional. `rtti` provides a default implementation that writes `typeid({type})` to `stream`.
#### type_index
```c++
static auto type_index(type_id type) -> /* unspecified */;
```
Returns a unique key for `type`. Required only for RTTI systems that assign more
than one type "identifiers" to a type. For example, standard RTTI allows
implementations to have multiple instances of `std::type_info` for the same
type.
#### dynamic_cast_ref
```c++
template<typename D, typename B>
static auto dynamic_cast_ref(B&& obj) -> D;
```
Casts `obj` to `D`. Required only if using virtual inheritance.

BIN
doc/skin.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

21
doc/smart_pointers.adoc Normal file
View File

@@ -0,0 +1,21 @@
## Smart Pointers
`virtual_ptr` can also be used in combination with smart pointers.
`virtual_ptr<std::shared_ptr<Class>>` (aliased to `shared_virtual_ptr<Class>`)
and `virtual_ptr<std::unique_ptr<Class>>` (aliased to
`unique_virtual_ptr<Class>`) deliver the convenience of automatic memory
management with the speed of `virtual_ptr`. Convenience functions
`make_shared_virtual` and `make_unique_virtual` create an object and return a
smart virtual_ptr to it. Since the exact type of the object is known, the vptr
is read from a static variable, without incuring the cost of a hash table
lookup.
Here is a variaton of the AST example that uses dynamic allocation and unique
pointers:
[source,c++]
----
include::{examplesdir}/ast_unique_ptr.cpp[tag=ast,indent=0]
----

82
doc/std_rtti.adoc Normal file
View File

@@ -0,0 +1,82 @@
## std_rtti
### Synopsis
Defined in <boost/openmethod/policies/std_rtti.hpp>.
```c++
namespace boost::openmethod::policies {
struct std_rtti : virtual rtti {
template<class Class>
static auto static_type() -> type_id;
template<class Class>
static auto dynamic_type(const Class& obj) -> type_id;
template<typename Stream>
static auto type_name(type_id type, Stream& stream) -> void;
static auto type_index(type_id type) -> std::type_index;
template<typename D, typename B>
static auto dynamic_cast_ref(B&& obj) -> D;
};
} // boost::openmethod::policies
```
### Description
`std_rtti` is an implementation of the `rtti` facet that uses standard RTTI.
### Members
#### static_type
```c++
template<class Class>
static type_id static_type();
```
Return the address of `Class`'s `type_info`, cast to a `type_id`.
#### dynamic_type
```c++
template<class Class>
static type_id dynamic_type(const Class& obj);
```
Return the address of `obj`{empty}'s `type_info`, cast to a `type_id`.
#### type_name
```c++
template<typename Stream>
static void type_name(type_id type, Stream& stream);
```
Write the demangled name of the class identified by `type` to `stream`.
Execute `stream << reinterpret_cast<const std::type_info*>(type)->name()`.
#### type_index
```c++
static /*unspecified*/ type_index(type_id type);
```
Return `std::type_index(*reinterpret_cast<const std::type_info*>(type))`.
The function is required because C++ does *not* guarantee that there is a single
instance of `std::type_info` for each specific type.
#### dynamic_cast_ref
```c++
template<typename Derived, typename Base>
static Derived dynamic_cast_ref(Base&& obj);
```
Cast `obj` using the `dynamic_cast` operator.

View File

@@ -0,0 +1,33 @@
## throw_error_handler
### Synopsis
Defined in <boost/openmethod/policies/throw_error_handler.hpp>.
```c++
namespace boost::openmethod::policies {
struct throw_error_handler : error_handler {
template<class Error>
[[noreturn]] static auto error(const Error& error) -> void;
};
} // boost::openmethod::policies
```
### Description
throw_error_handler is an implementation of the `error_handler` facet that
throws the error as an exception.
### Members
#### error
```c++
template<class Error>
[[noreturn]] static auto error(const Error& error) -> void;
```
Throws `error`.

45
doc/trace_output.adoc Normal file
View File

@@ -0,0 +1,45 @@
## trace_output
### Synopsis
Defined in <boost/openmethod/policies/basic_policy.hpp>.
```c++
namespace boost::openmethod::policies {
struct trace_output {};
}
```
---
### Description
`trace_output` is a facet used to write trace messages.
`initialize` can be directed to describe the classes and methods in a policy,
and how the dispatch tables are built, by including this facet in the policy,
and setting `trace_enabled` to `true`. The content and the format of the
description is not documented, beyond the guarantee that it provides an
exhaustive account of table construction, and may change between major, minor
and patch versions.
### Requirements
#### trace_enabled
```c++
static bool trace_enabled;
```
`true` if tracing is enabled, `false` otherwise.
#### trace_stream
```c++
static RestrictedOutputStream trace_stream;
```
A static variable that satisfies the requirements of `RestrictedOutputStream`.

18
doc/tutorial.adoc Normal file
View File

@@ -0,0 +1,18 @@
[#tutorials]
# Tutorials
:toc:
:toc-title:
:idprefix: tutorials_
:examplesdir: ../examples
include::hello_world.adoc[]
include::multiple_dispatch.adoc[]
include::friendship.adoc[]
include::performance.adoc[]
include::smart_pointers.adoc[]
include::virtual_ptr_alt.adoc[]
include::core_api.adoc[]
include::policies.adoc[]
include::error_handling.adoc[]
include::custom_rtti.adoc[]

98
doc/type_hash.adoc Normal file
View File

@@ -0,0 +1,98 @@
## type_hash
### Synopsis
Defined in <boost/openmethod/policies/basic_policy.hpp>.
```c++
namespace boost::openmethod::policies {
struct type_hash {};
} // boost::openmethod::policies
```
### Description
`type_hash` is a facet that provides a hash function for a fixed set of
`type_id`{empty}s.
### Requirements
### hash_type_id
```c++
static auto hash_type_id(type_id type) -> type_id;
```
Returns the hash of `type`.
#### hash_initialize
```c++
template<typename ForwardIterator>
static auto hash_initialize(ForwardIterator first, ForwardIterator last) -> Report;
```
Finds a hash function for the `type_id`{empty}s in the range `[first, last)`.
`ForwardIterator` is the same as in `vptr_vector::register_vptrs`.
`hash_initialize` returns a `Report` object which is required to have two
members, `first` and `last`, which define the range `[first, last)` of the
possible output values of the hash function.
## fast_perfect_hash
### Synopsis
Defined in <boost/openmethod/policies/fast_perfect_hash.hpp>.
```c++
class fast_perfect_hash : type_hash
{
public:
static auto hash_type_id(type_id type) -> type_id;
template<typename ForwardIterator>
static auto hash_initialize(ForwardIterator first, ForwardIterator last) -> Report;
};
```
### Description
`fast_perfect_hash` implements a very fast, perfect (but not minimal) hash
function for `type_id`{empty}s.
### Members
Find two factors
#### hash_type_id
```c++
static auto hash_type_id(type_id type) -> type_id;
```
Returns `(type * M) >> S`, where `M` and `S` are factors found by
`hash_initialize`.
If the policy has a `runtime_checks` facet, `hash_type_id` checks that `type`
corresponds to a registered class. If not, it reports a `unknown_class_error`
using the policy's error_handler facet, if present, then calls `abort`.
#### hash_initialize
```c++
template<typename ForwardIterator>
auto hash_initialize(ForwardIterator first, ForwardIterator last) -> Report;
```
Finds factors `M` and `S` such that `hash_type_id` is a collision-free hash
function.
If no such factors cannot be found, `hash_initialize` reports a
`hash_search_error` using the policy's error_handler facet, if present, the
calls `abort`.
If the policy has a `trace_output` facet, `hash_initialize` uses it to write a
summary of the search.

37
doc/typedefs.adoc Normal file
View File

@@ -0,0 +1,37 @@
## type_id
### Synopsis
Defined in `<boost/openmethod/policies/basic_policy.hpp>`.
```c++
namespace boost::openmethod {
using type_id = std::uintptr_t;
}
```
### Description
`type_id` is an unsigned integer type used to identify types. It is wide enough
to contain a pointer.
## vptr_type
### Synopsis
Defined in `<boost/openmethod/policies/basic_policy.hpp>`.
```c++
namespace boost::openmethod {
using vptr_type = const /*unspecified*/ *;
}
```
### Description
`vptr_type` is the type of a pointer to a v-table.

58
doc/use_classes.adoc Normal file
View File

@@ -0,0 +1,58 @@
## use_classes
### Synopsis
Defined in <boost/openmethod/core.hpp>.
```c++
namespace boost::openmethod {
template<class... Classes, class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY>
struct use_classes {
use_classes();
~use_classes();
};
}
```
Usage:
```c++
use_classes<Classes...> some_unique_name; // at file scope
```
### Description
`use_classes`, instantiated as a static object, registers `Classes` in `Policy`.
Classes potentially involved in a method definition, an overrider, or a method
call must be registered via `use_classes`. A class may be registered multiple
times. A class and its direct bases must be listed together in one or more
instantiations of `use_classes`.
Virtual and multiple inheritance are supported, as long as they don't result in
a class lattice that contains repeated inheritance.
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.
### Members
#### constructor
```c++
use_classes();
```
Registers `Classes` and their inheritance relationships in `Policy`.
#### destructor
```c++
~use_classes();
```
Removes `Classes` and their inheritance relationships from `Policy`.

58
doc/vector_vptr.adoc Normal file
View File

@@ -0,0 +1,58 @@
## vptr_vector
### Synopsis
Defined in <boost/openmethod/policies/vptr_vector.hpp>.
```c++
namespace boost::openmethod::policies {
template<class Policy, typename UseIndirectVptrs = void>
class vptr_vector : Base {
public:
template<typename ForwardIterator>
static auto register_vptrs(ForwardIterator first, ForwardIterator last) -> void;
template<class Class>
static auto dynamic_vptr(const Class& arg) -> const vptr_type&;
};
}
```
### Description
`vptr_vector` is an implementation or `external_vptr` that keeps the pointers
to the v-tables in a `std::vector`. If `UseIndirectVptrs` is `indirect_vptr`,
stores pointers to pointers to the v-tables.
`Policy` is the policy containing the facet.
### Members
#### register_vptrs
```c++
template<typename ForwardIterator>
auto register_vptrs(ForwardIterator first, ForwardIterator last) -> void;
```
Stores the pointers to v-tables in a vector, indexed by the (possibly hashed)
`type_id`s of the classes registered in `Policy`.
If `Policy` contains a `type_hash` facet, call its `hash_initialize`
function, and uses it to convert the `type_id`{empty}s to an index.
#### dynamic_vptr
```c++
template<class Class>
auto dynamic_vptr(const Class& object) -> const vptr_type&;
```
Returns a pointer to the v-table for `object` (by reference).
Obtains a `type_id` for `object` using `Policy::dynamic_type`. If _Policy_
contains a `type_hash` facet, uses it to convert the result to an index;
otherwise, uses the `type_id` as the index.

View File

@@ -0,0 +1,52 @@
## vectored_error_handler
### Synopsis
Defined in <boost/openmethod/policies/vectored_error_handler.hpp>.
```c++
namespace boost::openmethod::policies {
template<class Policy>
class vectored_error_handler : public error_handler {
public:
using error_variant = std::variant<
openmethod_error, not_implemented_error, unknown_class_error,
hash_search_error, type_mismatch_error, static_slot_error,
static_stride_error>;
using function_type = std::function<void(const error_variant& error)>;
template<class Error>
static auto error(const Error& error) -> void;
static auto set_error_handler(error_handler_type handler) -> function_type;
};
}
```
### Description
`vectored_error_handler` is an implementation of `error_handler` that calls a
`std::function` to handle the error.
### Members
#### error
```c++
template<class Error>
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
of `error`.
#### error
```c++
static auto set_error_handler(function_type handler) -> function_type;
```
Sets `handler` as the function to call in case of error.

24
doc/virtual_.adoc Normal file
View File

@@ -0,0 +1,24 @@
## virtual_
### Synopsis
Defined in `<boost/openmethod/core.hpp>`.
```c++
namespace boost::openmethod {
template<typename T>
struct virtual_;
}
```
### Description
Marks a formal parameter of a method as virtual. Requires a specialization of
`virtual_traits` for `T` and the `Policy` of the method. Specializations for
`T&`, `T&&`, `std::unique_ptr<T>`, `std::shared_ptr<T>` and `const
std::shared_ptr<T>&` are provided. See the documentation of `virtual_traits` for
more information.

289
doc/virtual_ptr.adoc Normal file
View File

@@ -0,0 +1,289 @@
[#virtual_ptr]
:idprefix: virtual_ptr_
## virtual_ptr
### Synopsis
`virtual_ptr` is defined in `<boost/openmethod/core.hpp>`.
```c++
namespace boost::openmethod {
template<class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY>
class virtual_ptr {
public:
static constexpr bool is_smart_ptr = /* see below */;
using element_type = /* see below */;
template<class Other> virtual_ptr(Other& other);
template<class Other> virtual_ptr(const Other& other);
template<class Other> virtual_ptr(Other&& other);
template<class Other>
static auto final(Other&& obj);
auto get() const -> element_type*;
auto operator->() const -> element_type*;
auto operator*() const -> element_type&;
auto pointer() const -> const Class*&;
template<typename Other>
auto cast() const -> virtual_ptr<Other, Policy>;
};
template<class Class>
virtual_ptr(Class&) -> virtual_ptr<Class, BOOST_OPENMETHOD_DEFAULT_POLICY>;
template<class Class>
inline auto final_virtual_ptr(Class& obj) -> virtual_ptr<
Class, BOOST_OPENMETHOD_DEFAULT_POLICY>;
template<class Policy, class Class>
inline auto final_virtual_ptr(Class& obj) -> virtual_ptr<Class, Policy>;
template<class Left, class Right, class Policy>
bool operator==(
const virtual_ptr<Left, Policy>& left,
const virtual_ptr<Right, Policy>& right);
template<class Left, class Right, class Policy>
bool operator!=(
const virtual_ptr<Left, Policy>& left,
const virtual_ptr<Right, Policy>& right);
} // namespace boost::openmethod
```
Defined in `<boost/openmethod/shared_ptr.hpp>`:
```c++
namespace boost::openmethod {
template<class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY>
using shared_virtual_ptr = virtual_ptr<std::shared_ptr<Class>, Policy>;
template<
class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY, typename... T>
inline auto make_shared_virtual(T&&... args);
}
```
Defined in `<boost/openmethod/unique_ptr.hpp>`:
```c++
namespace boost::openmethod {
template<class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY>
using unique_virtual_ptr = virtual_ptr<std::unique_ptr<Class>, Policy>;
template<
class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY, typename... T>
inline auto make_unique_virtual(T&&... args);
}
```
### Description
`virtual_ptr` is a wide pointer that combines a pointer to an object and a
pointer to its v-table. The object pointer can be a plain pointer or a smart
pointer. Specializations of `virtual_traits` are required for smart pointers.
They are provided for `std::unique_ptr` and `std::shared_ptr`.
A plain `virtual_ptr` can be constructed from a reference, a smart pointer, or
another `virtual_ptr`. A smart `virtual_ptr` can be constructed from a smart
pointer or from a smart `virtual_ptr`. Usual conversions - from derived to base,
and from non-const to const - are allowed.
`virtual_ptr` does not have a default constructor, nor a "null" state. In that
respect, it behaves more like a reference than a pointer. The only reason why it
is not called `virtual_ref` is to save the name for the day C++ will support
smart references.
### Members
#### is_smart_ptr
```c++
static constexpr bool is_smart_ptr;
```
`true` if `Class` is a smart pointer, `false` otherwise. The value is derived
from `virtual_traits<Class, Policy>`: if it has a member template called
`rebind`, `Class` is considered a smart pointer.
#### element_type
```c++
using element_type = std::conditional_t<
is_smart_ptr, typename Class::element_type, Class>;
```
The class of the object pointed to.
#### constructors
[source,c++]
----
template<class Other> virtual_ptr(Other& other); // 1
template<class Other> virtual_ptr(const Other& other); // 2
template<class Other> virtual_ptr(Other&& other); // 3
----
(1), (2) If `virtual_ptr` uses a plain pointer, `other` must be a lvalue
reference to an object of a registered class, or to a `virtual_ptr` (plain or
smart). If `virtual_ptr` uses a smart pointer, `other` must be a reference to a smart
pointer, or a smart `virtual_ptr`.
(3) Smart `virtual_ptr` only. Constructs a `virtual_ptr` from a smart pointer or
a smart `virtual_ptr`. The (smart) object pointer is moved from `other`.
If `other` is also a `virtual_ptr`, the v-table pointer is copied from it.
Otherwise, it is deduced from the object. The `Policy` must be the same for both
`virtual_ptr`{empty}s.
#### final
```c++
template<class Other>
static auto final(Other&& obj);
```
Constructs a `virtual_ptr` from a reference to an object, or from a smart
pointer. It is assumed that the static and dynamic types are the same. The
v-table pointer is initialized from the `Policy::static_vptr` for the class,
which needs not be polymorphic.
#### get
```c++
auto get() const -> element_type*;
```
Returns a pointer to the object.
#### operator->
```c++
auto operator->() const -> element_type*;
```
Returns a pointer to the object.
#### operator*
```c++
auto operator*() const -> element_type&;
```
Returns a reference to the object.
#### pointer
```c++
auto pointer() const;
```
Returns a reference to the object pointer, which can be either a plain pointer
or a smart pointer.
#### cast
```c++
template<typename Other>
auto cast() const -> virtual_ptr<Other, Policy>;
```
Returns a `virtual_ptr` to the same object, cast to `Other`.
### Deduction guide
```c++
template<class Class>
virtual_ptr(Class&) -> virtual_ptr<Class, BOOST_OPENMETHOD_DEFAULT_POLICY>;
```
---
### Non-members
#### virtual_shared_ptr
```c++
template<class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY>
using virtual_shared_ptr = virtual_ptr<std::shared_ptr<Class>, Policy>;
```
Convenience alias for `virtual_ptr<std::shared_ptr<Class>, Policy>`.
#### virtual_unique_ptr
```c++
template<class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY>
using virtual_unique_ptr = virtual_ptr<std::unique_ptr<Class>, Policy>;
```
Convenience alias for `virtual_ptr<std::unique_ptr<Class>, Policy>`.
#### final_virtual_ptr
```c++
template<class Policy, class Class>
inline auto final_virtual_ptr(Class&& obj);
template<class Class>
inline auto final_virtual_ptr(Class&& obj);
```
Utility functions, forwarding to `virtual_ptr<Class, Policy>::final`.
If `Policy` is not specified, `BOOST_OPENMETHOD_DEFAULT_POLICY` is used.
#### make_virtual_shared
```c++
template<
class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY, typename... T>
inline auto make_virtual_shared(T&&... args);
```
Creates an object using `std::make_shared` and returns a `virtual_shared_ptr` to
it. The v-table pointer is initialized from the the `Policy::static_vptr` for
the class, which needs not be polymorphic.
#### make_virtual_unique
```c++
template<
class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY, typename... T>
inline auto make_virtual_unique(T&&... args);
```
Creates an object using `std::make_unique` and returns a `virtual_unique_ptr` to
it. The v-table pointer is initialized from the the `Policy::static_vptr` for
the class, which needs not be polymorphic.
#### operator==
```c++
template<class Left, class Right, class Policy>
bool operator==(
const virtual_ptr<Left, Policy>& left,
const virtual_ptr<Right, Policy>& right);
```
Compares two `virtual_ptr` objects for equality.
#### operator!=
```c++
template<class Left, class Right, class Policy>
bool operator!=(
const virtual_ptr<Left, Policy>& left,
const virtual_ptr<Right, Policy>& right);
```
Compares two `virtual_ptr` objects for inequality.

76
doc/virtual_ptr_alt.adoc Normal file
View File

@@ -0,0 +1,76 @@
## Alternatives to virtual_ptr
Virtual arguments can be passed as plain references. In a method declaration,
parameters with a type decorated with `virtual_` are considered in overrider
selection (along with `virtual_ptr` parameters).
For example, the `poke` open-method in the Animals example can be rewritten as:
[source,c++]
----
include::{examplesdir}/virtual_.cpp[tag=virtual_parameter,indent=0]
int main() {
boost::openmethod::initialize();
Cat cat;
poke(std::cout, cat); // hiss
}
----
Note that `virtual_` is not used in the overrider. It is also removed from the
method's signature.
By itself, `virtual_` does not provide any benefits. Passing the virtual
argument by reference almost compiles to the same code as creating a
`virtual_ptr`, using it for one call, then throwing it way. The only difference
is that the virtual argument is passed as one pointer instead of two.
However, we can now customize how the vptr is obtained. When the method sees a
`virtual_` parameter, it looks for a `boost_openmethod_vptr` function that takes
the parameter (by const reference), and returns a `vptr_type`. If one is found,
it is called to obtain the vptr. The vptr for a specific registered class can be
obtained via a variable template `static_vptr`, nested in class `default_policy`
(more on policies below).
In the following example, we embed a vptr in the object, just like the vptr for
native virtual functions:
[source,c++]
----
include::{examplesdir}/virtual_.cpp[tag=virtual_intrusive,indent=0]
int main() {
boost::openmethod::initialize();
Cat cat;
poke(std::cout, cat); // hiss
}
----
NOTE: With this approach, classes need not be polymorphic. A virtual
destructor might be needed for correct destruction of objects, but it is not
required by the library.
The `with_vptr` CRTP class automates the creation and management of embedded
vptrs.
[source,c++]
----
include::{examplesdir}/virtual_.cpp[tag=with_vptr,indent=0]
int main() {
boost::openmethod::initialize();
Cat cat;
poke(std::cout, cat); // hiss
}
----
If `with_vptr` is passed only the class being defined, it adds a vptr to it, and
defines a `boost_openmethod_vptr` friend function. If more classes are passed,
they must be the direct bases of the class potentially involved in open-method
calls. Its constructor and destructor set the vptr to point to the v-table for
the class. `with_vptr` also takes care of registering the classes, so this time
the call to `BOOST_OPENMETHOD_CLASSES` is not needed.

92
doc/virtual_traits.adoc Normal file
View File

@@ -0,0 +1,92 @@
## virtual_traits
### Synopsis
Defined in <boost/openmethod/core.hpp>.
```c++
namespace boost::openmethod {
template<class, class>
struct virtual_traits; // not defined
template<class Class, class Policy>
struct virtual_traits<..., Policy> {
using virtual_type = ...;
static auto peek(const T& arg) -> const ...&;
template<typename Derived> static auto cast(T& obj) -> ...;
template<class Other> using rebind = ...; // for smart virtual pointers
};
}
```
### Description
Specializations of `virtual_traits` provide an interface for `method` and
`virtual_ptr` to manipulate virtual arguments.
### Specializations
Specializations are provided for:
* `virtual_ptr<T, Policy>`
* `const virtual_ptr<T, Policy>&`
* `T&`
* `T&&`
* `std::shared_ptr<T>`: defined in <boost/openmethod/shared_ptr.hpp>
* `const std::shared_ptr<T>&`: defined in <boost/openmethod/shared_ptr.hpp>
* `std::unique_ptr<T>`: defined in <boost/openmethod/unique_ptr.hpp>
### Members
#### virtual_type
```c++
using virtual_type = ...;
```
The class used for method selection. It must be registered in Policy.
For example, `virtual_type` in the following specializations are all `Class`:
* `virtual_traits<virtual_ptr<Class, Policy>>`
* `virtual_traits<const virtual_ptr<std::shared_ptr<Class>&, Policy>`
* `virtual_traits<Class&, Policy>`
* `virtual_traits<const std::shared_ptr<Class>&, Policy>`
#### peek
```c++
static auto peek(T arg) -> const ...&;
```
Returns a value for the purpose of obtaining a v-table pointer for `arg`.
For example, `peek` returns a `const T&` for a `T&`, a `const T&`, a `T&&`, and
a `std::shared_ptr<T>`; and a `const virtual_ptr<Class, Policy>&` for a
`const virtual_ptr<Class, Policy>&`.
#### cast
```c++
template<typename Derived>
static decltype(auto) cast(T& obj);
```
Casts argument `obj` to the type expected by an overrider.
For example, if a method takes a `virtual_<Animal&>`, an overrider for `Cat&`
uses `virtual_traits` to cast a `Animal&` to a `Cat&`.
#### rebind
```c++
template<class Other> using rebind = ...;
```
For smart pointers only. Rebinds the smart pointer to a different type. For
example, `virtual_traits<std::shared_ptr<T>, Policy>::rebind<U>` is
`std::shared_ptr<U>`.

110
doc/vptr.adoc Normal file
View File

@@ -0,0 +1,110 @@
## vptr
### Synopsis
Defined in <boost/openmethod/policies/basic_policy.hpp>.
```c++
namespace boost::openmethod::policies {
struct vptr {};
}
```
### Description
`vptr` is a facet that obtains a pointer to the v-table for an object.
OpenMethod implements method dispatch in a way similar to native virtual
function dispatch: for each virtual argument, fetch a pointer to the dispatch
data (known as the v-table), and use it to select a pointer to a function.
OpenMethod v-tables contain pointers to functions for unary methods, and, for
multi-methods, pointers to, and coordinates in, a multi-dimensional table of
pointers to functions.
The `vptr` facet is used during method call to fetch the vptr for virtual
arguments corresponding to the `virtual_` parameters in the method
declaration. It is also used by the constructor of `virtual_ptr` to obtain a
vptr on the basis of an object's dynamic type.
`virtual_ptr::final`, and the related convenience functions, assume that the
static and dynamic types of their argument are the same. The vptr is obtained
statically from the policy's `static_vptr<Class>` member. It is conceivable
to organize an entire program around the "final" constructs; thus, the `vptr`
facet is optional.
### Requirements
#### dynamic_vptr;
```c++
template<class Class>
static auto dynamic_vptr(const Class& obj) -> const vptr_type&;
```
Returns a pointer to the v-table for `obj`.
NOTE: `dynamic_vptr` _must_ return a reference to the pointer, not a value. This
is required for indirect `virtual_ptr`{empty}s.
## extern_vptr
### Synopsis
```c++
struct extern_vptr : virtual vptr {};
```
### Description
`extern_vptr` is a specialization of `vptr` that stores vptrs outside of the
objects.
### Requirements
The requirements of `vptr`, plus the following.
#### register_vptrs
```c++
template<typename ForwardIterator>
auto register_vptrs(ForwardIterator first, ForwardIterator last) -> void;
```
`ForwardIterator` is a forward iterator over a range of objects that contain
information about the type ids and the vptr of a registered class. They have the
following member functions:
```c++
auto type_id_begin() const -> type_id_forward_iterator;
auto type_id_end() const -> type_id_forward_iterator;
auto vptr() const -> const vptr_type&;
```
`type_id_begin` and `type_id_end` return iterators delimiting a range of
`type_id`s for the class.
`vptr` returns a _reference_ to a _static_ variable containing a pointer to the
v-table for a registered class. Its value is set by `initialize`. While the
value of the variable changes with each call to `initialize`, the variable
itself remains the same.
## indirect_vptr
### Synopsis
```c++
struct indirect_vptr {};
```
### Description
`indirect_vptr` is a facet that makes `virtual_ptr`{empty}s and `with_vptr` use
pointers to pointers to v-tables, instead of straight pointers. As a
consequence, they remain valid after a call to `initialize`.
### Requirements
None. The facet is its own implementation.

77
doc/with_vptr.adoc Normal file
View File

@@ -0,0 +1,77 @@
## with_vptr
### Synopsis
Defined in <boost/openmethod/core.hpp>.
```c++
namespace boost::openmethod {
template<class Class, class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY>
class with_vptr {
protected:
with_vptr();
~with_vptr();
friend auto boost_openmethod_vptr(const Class& obj) -> vptr_type;
};
template<class Class, class Base, class... MoreBases>
class with_vptr {
protected:
with_vptr();
~with_vptr();
friend auto boost_openmethod_vptr(const Class& obj) -> vptr_type;
// if sizeof(MoreBases...) > 0
};
} // namespace boost::openmethod
```
### Description
`with_vptr` is a CRTP class template that embeds and manages a vptr across a
class hierarchy.
If `Class` has no `Bases`, `with_vptr` adds a `boost_openmethod_vptr` private
member to `Class`. In either case, it sets the vptr to the v-table of `Class`
from `Policy`. It also creates a `boost_openmethod_vptr` friend function that
takes a a `const Class&` and returns the embedded vptr.
If `Class` has has more than one base, the `boost_openmethod_vptr` friend
function is also created. It returns one of the embedded vptrs (it doesn't
matter which one, as they all have the same value). This is to resolve
ambiguities
As part of its implementation, `with_vptr` may also declare one or two free
functions (`boost_openmethod_policy` and `boost_openmethod_bases`) at certain
levels of the hierarchy.
### Members
#### constructor
```c++
with_vptr();
```
Sets the vptr to the v-table for Class, obtained from `Policy`. If `Policy`
contains `indirect_vptr`, an additional level of indirection is added, thus
preserving the validity of the pointer across calls to `initialize`.
#### destructor
```c++
~with_vptr();
```
For each `Base`, sets the vptr to the v-table for that base.
#### Free Functions
```c++
auto boost_openmethod_vptr(const Class& obj) -> vptr_type;
```
Returns the vptr embedded in `obj`.

478
doc/zajo-dark.css Normal file
View File

@@ -0,0 +1,478 @@
/* 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}

468
doc/zajo-light.css Normal file
View File

@@ -0,0 +1,468 @@
/* 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}

1
docs Symbolic link
View File

@@ -0,0 +1 @@
doc/html

106
examples/CMakeLists.txt Normal file
View File

@@ -0,0 +1,106 @@
# 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)
if (CMAKE_BUILD_TYPE MATCHES "Release")
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
add_compile_options(-save-temps -masm=intel)
endif()
endif()
add_executable(virtual_func virtual_func.cpp)
target_link_libraries(virtual_func Boost::openmethod)
add_test(NAME virtual_func COMMAND virtual_func)
add_executable(ast ast.cpp)
target_link_libraries(ast Boost::openmethod)
add_test(NAME ast COMMAND ast)
add_executable(ast_unique_ptr ast_unique_ptr.cpp)
target_link_libraries(ast_unique_ptr Boost::openmethod)
add_test(NAME ast_unique_ptr COMMAND ast_unique_ptr)
add_executable(hello_world hello_world.cpp)
target_link_libraries(hello_world Boost::openmethod)
add_test(NAME hello_world COMMAND hello_world)
add_executable(friendship_all friendship.cpp)
target_compile_definitions(friendship_all PRIVATE FRIEND_ALL)
target_link_libraries(friendship_all Boost::openmethod)
add_test(NAME friendship_add COMMAND friendship_all)
add_executable(friendship friendship.cpp)
target_link_libraries(friendship Boost::openmethod)
add_test(NAME friendship COMMAND friendship)
add_executable(friendship_across_namespaces_all friendship_across_namespaces.cpp)
target_compile_definitions(friendship_across_namespaces_all PRIVATE FRIEND_ALL)
target_link_libraries(friendship_across_namespaces_all Boost::openmethod)
add_test(NAME friendship_across_namespaces_all COMMAND friendship_across_namespaces_all)
add_executable(friendship_across_namespaces friendship_across_namespaces.cpp)
target_link_libraries(friendship_across_namespaces Boost::openmethod)
add_test(NAME friendship_across_namespaces COMMAND friendship_across_namespaces)
add_executable(virtual_ptr virtual_ptr.cpp)
target_link_libraries(virtual_ptr Boost::openmethod)
add_test(NAME virtual_ptr COMMAND virtual_ptr)
add_executable(virtual_ virtual_.cpp)
target_link_libraries(virtual_ Boost::openmethod)
add_test(NAME virtual_ COMMAND virtual_)
add_executable(core_api core_api.cpp)
target_link_libraries(core_api Boost::openmethod)
add_test(NAME core_api COMMAND core_api)
add_executable(vectored_error_handler vectored_error_handler.cpp)
target_link_libraries(vectored_error_handler Boost::openmethod)
add_test(NAME vectored_error_handler COMMAND vectored_error_handler)
add_executable(throw_error_handler throw_error_handler.cpp)
target_link_libraries(throw_error_handler Boost::openmethod)
add_test(NAME throw_error_handler COMMAND throw_error_handler)
add_executable(custom_rtti custom_rtti.cpp)
target_link_libraries(custom_rtti Boost::openmethod)
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set_target_properties(custom_rtti PROPERTIES COMPILE_FLAGS "-fno-rtti")
endif()
add_test(NAME custom_rtti COMMAND custom_rtti)
add_executable(deferred_custom_rtti deferred_custom_rtti.cpp)
target_link_libraries(deferred_custom_rtti Boost::openmethod)
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set_target_properties(deferred_custom_rtti PROPERTIES COMPILE_FLAGS "-fno-rtti")
endif()
add_test(NAME deferred_custom_rtti COMMAND deferred_custom_rtti)
add_executable(slides slides.cpp)
target_link_libraries(slides Boost::openmethod)
add_test(NAME slides COMMAND slides)
add_executable(synopsis synopsis.cpp)
target_link_libraries(synopsis Boost::openmethod)
add_test(NAME synopsis COMMAND synopsis)
add_executable(matrix matrix.cpp)
target_link_libraries(matrix Boost::openmethod)
add_test(NAME matrix COMMAND matrix)
add_executable(accept_no_visitors accept_no_visitors.cpp)
target_link_libraries(accept_no_visitors Boost::openmethod)
add_test(NAME accept_no_visitors COMMAND accept_no_visitors)
add_executable(adventure adventure.cpp)
target_link_libraries(adventure Boost::openmethod)
add_test(NAME adventure COMMAND adventure)
add_executable(next next.cpp)
target_link_libraries(next Boost::openmethod)
add_test(NAME next COMMAND next)
add_executable(asteroids asteroids.cpp)
target_link_libraries(asteroids Boost::openmethod)
add_test(NAME asteroids COMMAND asteroids)

View File

@@ -0,0 +1,123 @@
// 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 <string>
#include <boost/openmethod.hpp>
#include <boost/openmethod/shared_ptr.hpp>
#include <boost/openmethod/compiler.hpp>
using boost::openmethod::make_shared_virtual;
using boost::openmethod::shared_virtual_ptr;
using std::cout;
using std::string;
struct Node {
virtual ~Node() {
}
};
struct Plus : Node {
Plus(
shared_virtual_ptr<const Node> left,
shared_virtual_ptr<const Node> right)
: left(left), right(right) {
}
shared_virtual_ptr<const Node> left, right;
};
struct Times : Node {
Times(
shared_virtual_ptr<const Node> left,
shared_virtual_ptr<const Node> right)
: left(left), right(right) {
}
shared_virtual_ptr<const Node> left, right;
};
struct Integer : Node {
explicit Integer(int value) : value(value) {
}
int value;
};
// =============================================================================
// add behavior to existing classes, without changing them
BOOST_OPENMETHOD_CLASSES(Node, Plus, Times, Integer);
// -----------------------------------------------------------------------------
// 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 Times> expr), int) {
return value(expr->left) * value(expr->right);
}
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<const Integer> expr), int) {
return expr->value;
}
// -----------------------------------------------------------------------------
// render as Forth
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 Times> expr), string) {
return as_forth(expr->left) + " " + as_forth(expr->right) + " *";
}
BOOST_OPENMETHOD_OVERRIDE(as_forth, (virtual_ptr<const Integer> expr), string) {
return std::to_string(expr->value);
}
// -----------------------------------------------------------------------------
// render as Lisp
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 Times> expr), string) {
return "(times " + as_lisp(expr->left) + " " + as_lisp(expr->right) + ")";
}
BOOST_OPENMETHOD_OVERRIDE(as_lisp, (virtual_ptr<const Integer> expr), string) {
return std::to_string(expr->value);
}
// -----------------------------------------------------------------------------
int main() {
boost::openmethod::initialize();
shared_virtual_ptr<Node> expr = make_shared_virtual<Times>(
make_shared_virtual<Integer>(2),
make_shared_virtual<Plus>(
make_shared_virtual<Integer>(3), make_shared_virtual<Integer>(4)));
cout << as_forth(expr) << " = " << as_lisp(expr) << " = " << value(expr)
<< "\n";
// error_output:
// 2 3 4 + * = (times 2 (plus 3 4)) = 14
return 0;
}

128
examples/adventure.cpp Normal file
View File

@@ -0,0 +1,128 @@
// 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 <string>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
struct Character {
virtual ~Character() {
}
};
struct Warrior : Character {};
struct Device {
virtual ~Device() {
}
};
struct Hands : Device {};
struct Axe : Device {};
struct Banana : Device {};
struct Creature {
virtual ~Creature() {
}
};
struct Dragon : Creature {};
struct Bear : Creature {};
BOOST_OPENMETHOD_CLASSES(
Character, Warrior, Device, Hands, Axe, Banana, Creature, Dragon, Bear);
BOOST_OPENMETHOD(
fight, (virtual_ptr<Character>, virtual_ptr<Creature>, virtual_ptr<Device>),
std::string);
BOOST_OPENMETHOD_OVERRIDE(
fight,
(virtual_ptr<Character> x, virtual_ptr<Creature> y, virtual_ptr<Banana> z),
std::string) {
return "are you insane?";
}
BOOST_OPENMETHOD_OVERRIDE(
fight,
(virtual_ptr<Character> x, virtual_ptr<Creature> y, virtual_ptr<Axe> z),
std::string) {
return "not agile enough to wield";
}
BOOST_OPENMETHOD_OVERRIDE(
fight,
(virtual_ptr<Warrior> x, virtual_ptr<Creature> y, virtual_ptr<Axe> z),
std::string) {
return "and cuts it into pieces";
}
BOOST_OPENMETHOD_OVERRIDE(
fight, (virtual_ptr<Warrior> x, virtual_ptr<Dragon> y, virtual_ptr<Axe> z),
std::string) {
return "and dies a honorable death";
}
BOOST_OPENMETHOD_OVERRIDE(
fight,
(virtual_ptr<Character> x, virtual_ptr<Dragon> y, virtual_ptr<Hands> z),
std::string) {
return "Congratulations! You have just vainquished a dragon with your bare "
"hands"
" (unbelievable, isn't it?)";
}
int main() {
boost::openmethod::initialize();
std::unique_ptr<Character> bob = std::make_unique<Character>(),
rambo = std::make_unique<Warrior>();
std::unique_ptr<Creature> elliott = std::make_unique<Dragon>(),
paddington = std::make_unique<Bear>();
std::unique_ptr<Device> hands = std::make_unique<Hands>(),
axe = std::make_unique<Axe>(),
chiquita = std::make_unique<Banana>();
std::cout << "bob fights elliot with axe:\n"
<< fight(*bob, *elliott, *axe) << "\n";
// bob fights elliot with axe:
// not agile enough to wield
std::cout << "rambo fights paddington with axe:\n"
<< fight(*rambo, *paddington, *axe) << "\n";
// rambo fights paddington with axe:
// and cuts it into pieces
std::cout << "rambo fights paddington with banana:\n"
<< fight(*rambo, *paddington, *chiquita) << "\n";
// rambo fights paddington with banana:
// are you insane?
std::cout << "rambo fights elliott with axe:\n"
<< fight(*rambo, *elliott, *axe) << "\n";
// rambo fights elliott with axe:
// and dies a honorable death
std::cout << "bob fights elliot with hands:\n"
<< fight(*bob, *elliott, *hands) << "\n";
// bob fights elliot with hands: Congratulations! You have just vainquished
// a dragon with your bare hands (unbelievable, isn't it?)
std::cout << "rambo fights elliot with hands:\n"
<< fight(*rambo, *elliott, *hands) << "\n";
// rambo fights elliot with hands:
// you just killed a dragon with your bare hands. Incredible isn't it?
return 0;
}
auto call_fight(Character& character, Creature& creature, Device& device) {
return fight(character, creature, device);
}

82
examples/ast.cpp Normal file
View File

@@ -0,0 +1,82 @@
// 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::ast[]
#include <iostream>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
struct Node {
virtual ~Node() {}
};
struct Literal : Node {
explicit Literal(int value) : value(value) {}
int value;
};
struct Plus : Node {
Plus(virtual_ptr<Node> left, virtual_ptr<Node> right)
: left(left), right(right) {}
virtual_ptr<Node> left, right;
};
struct Negate : Node {
explicit Negate(virtual_ptr<Node> node) : child(node) {}
virtual_ptr<Node> child;
};
BOOST_OPENMETHOD(value, (virtual_ptr<Node>), int);
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<Literal> node), int) {
return node->value;
}
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<Plus> node), int) {
return value(node->left) + value(node->right);
}
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<Negate> node), int) {
return -value(node->child);
}
BOOST_OPENMETHOD_CLASSES(Node, Literal, Plus, Negate);
int main() {
boost::openmethod::initialize();
Literal one(1), two(2);
Plus sum(one, two);
Negate neg(sum);
std::cout << value(neg) << "\n"; // -3
return 0;
}
// end::ast[]
int negate(virtual_ptr<Node> node) {
return -value(node);
}
#define main alt_main
int main() {
// tag::final[]
Literal one(1);
Negate neg(boost::openmethod::final_virtual_ptr(one));
// end::final[]
std::cout << value(boost::openmethod::final_virtual_ptr(neg)) << "\n"; // -3
return 0;
}

View File

@@ -0,0 +1,71 @@
// 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::ast[]
#include <iostream>
#include <memory>
#include <boost/openmethod.hpp>
#include <boost/openmethod/unique_ptr.hpp>
#include <boost/openmethod/compiler.hpp>
using boost::openmethod::unique_virtual_ptr;
using boost::openmethod::make_unique_virtual;
struct Node {
virtual ~Node() {}
};
struct Literal : Node {
Literal(int value) : value(value) {}
int value;
};
struct Plus : Node {
Plus(unique_virtual_ptr<Node> left, unique_virtual_ptr<Node> right)
: left(std::move(left)), right(std::move(right)) {}
unique_virtual_ptr<Node> left, right;
};
struct Negate : Node {
Negate(unique_virtual_ptr<Node> node) : child(std::move(node)) {}
unique_virtual_ptr<Node> child;
};
BOOST_OPENMETHOD(value, (virtual_ptr<Node>), int);
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<Literal> node), int) {
return node->value;
}
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<Plus> node), int) {
return value(node->left) + value(node->right);
}
BOOST_OPENMETHOD_OVERRIDE(value, (virtual_ptr<Negate> node), int) {
return -value(node->child);
}
BOOST_OPENMETHOD_CLASSES(Node, Literal, Plus, Negate);
int main() {
boost::openmethod::initialize();
auto expr = make_unique_virtual<Negate>(
make_unique_virtual<Plus>(
make_unique_virtual<Literal>(1),
make_unique_virtual<Literal>(2)));
std::cout << value(expr) << "\n"; // -3
return 0;
}
// end::ast[]

68
examples/asteroids.cpp Normal file
View File

@@ -0,0 +1,68 @@
// asteroids.cpp
// 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)
// Example for Wikipedia
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
class Thing {
public:
virtual ~Thing() {
}
};
class Asteroid : public Thing {};
class Spaceship : public Thing {};
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) {
// default collision handling
}
BOOST_OPENMETHOD_OVERRIDE(
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) {
// handle Asteroid-Spaceship collision
}
BOOST_OPENMETHOD_OVERRIDE(
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) {
// handle Spaceship-Spaceship collision
}
int main() {
boost::openmethod::initialize();
Asteroid a1, a2;
Spaceship s1, s2;
collideWith(a1, a2);
collideWith(a1, s1);
collideWith(s1, s2);
collideWith(s1, a1);
return 0;
}

103
examples/core_api.cpp Normal file
View File

@@ -0,0 +1,103 @@
// 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/compiler.hpp>
#include <boost/openmethod/core.hpp>
struct Animal {
virtual ~Animal() = default;
};
struct Cat : Animal {};
struct Dog : Animal {};
struct Bulldog : Dog {};
using namespace boost::openmethod;
// tag::method[]
#include <boost/openmethod/macros/name.hpp>
class BOOST_OPENMETHOD_NAME(poke);
using poke = method<
BOOST_OPENMETHOD_NAME(poke)(std::ostream&, virtual_ptr<Animal>), void>;
// end::method[]
// tag::poke_cat[]
auto poke_cat(std::ostream& os, virtual_ptr<Cat> cat) {
os << "hiss";
}
static poke::override<poke_cat> override_poke_cat;
// end::poke_cat[]
// tag::poke_dog[]
#include <boost/openmethod/macros/register.hpp>
auto poke_dog(std::ostream& os, virtual_ptr<Dog> dog) {
os << "bark";
}
BOOST_OPENMETHOD_REGISTER(poke::override<poke_dog>);
// end::poke_dog[]
// tag::poke_bulldog[]
auto poke_bulldog(std::ostream& os, virtual_ptr<Bulldog> dog) -> void {
poke::next<poke_bulldog>(os, dog);
os << " and bite";
}
BOOST_OPENMETHOD_REGISTER(poke::override<poke_bulldog>);
// end::poke_bulldog[]
class BOOST_OPENMETHOD_NAME(pet);
auto pet_cat(std::ostream& os, virtual_ptr<Cat> cat) {
os << "purr";
}
auto pet_dog(std::ostream& os, virtual_ptr<Dog> dog) {
os << "wag tail";
}
using pet = method<
BOOST_OPENMETHOD_NAME(pet)(std::ostream&, virtual_ptr<Animal>), void>;
BOOST_OPENMETHOD_REGISTER(pet::override<pet_cat, pet_dog>);
// tag::use_classes[]
BOOST_OPENMETHOD_REGISTER(use_classes<Animal, Cat, Dog, Bulldog>);
// end::use_classes[]
// tag::main[]
int main() {
boost::openmethod::initialize();
std::unique_ptr<Animal> a(new Cat);
std::unique_ptr<Animal> b(new Dog);
std::unique_ptr<Animal> c(new Bulldog);
poke::fn(std::cout, *a); // prints "hiss"
std::cout << "\n";
poke::fn(std::cout, *b); // prints "bark"
std::cout << "\n";
poke::fn(std::cout, *c); // prints "bark and bite"
std::cout << "\n";
// end::main[]
pet::fn(std::cout, *a); // prints "purr"
std::cout << "\n";
// tag::main[]
return 0;
// end::main[]
}

99
examples/custom_rtti.cpp Normal file
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)
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;
};
struct Dog : Animal {
Dog() : Animal(static_type) {
}
static constexpr unsigned static_type = 3;
};
#include <boost/openmethod/policies/basic_policy.hpp>
#include <boost/openmethod/policies/vptr_vector.hpp>
// tag::facet[]
namespace bom = boost::openmethod;
struct custom_rtti : bom::policies::rtti {
template<typename T>
static bom::type_id static_type() {
if constexpr (std::is_base_of_v<Animal, T>) {
return T::static_type;
} else {
return 0;
}
}
template<typename T>
static bom::type_id dynamic_type(const T& obj) {
if constexpr (std::is_base_of_v<Animal, T>) {
return obj.type;
} else {
return 0;
}
}
};
// 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::example[]
#include <iostream>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
BOOST_OPENMETHOD(poke, (std::ostream&, virtual_ptr<Animal>), void);
BOOST_OPENMETHOD_OVERRIDE(
poke, (std::ostream & os, virtual_ptr<Cat> cat), void) {
os << "hiss";
}
BOOST_OPENMETHOD_OVERRIDE(
poke, (std::ostream & os, virtual_ptr<Dog> dog), void) {
os << "bark";
}
BOOST_OPENMETHOD_CLASSES(Animal, Cat, Dog);
int main() {
boost::openmethod::initialize();
std::unique_ptr<Animal> a(new Cat);
std::unique_ptr<Animal> b(new Dog);
poke(std::cout, *a); // prints "hiss"
std::cout << "\n";
poke(std::cout, *b); // prints "bark"
std::cout << "\n";
return 0;
}
// end::example[]

View File

@@ -0,0 +1,155 @@
// 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::classes[]
struct custom_type_info {
static unsigned last;
unsigned id = ++last;
};
unsigned custom_type_info::last;
struct Animal {
Animal() {
type = type_info.id;
}
virtual ~Animal() = default;
virtual void* cast_impl(unsigned target) {
if (type_info.id == target) {
return this;
} else {
return nullptr;
}
}
template<class Class>
Class* cast() {
return reinterpret_cast<Class*>(cast_impl(Class::type_info.id));
}
static custom_type_info type_info;
unsigned type;
};
custom_type_info Animal::type_info;
struct Cat : virtual Animal {
Cat() {
type = type_info.id;
}
virtual void* cast_impl(unsigned target) {
if (type_info.id == target) {
return this;
} else {
return Animal::cast_impl(target);
}
}
static custom_type_info type_info;
};
custom_type_info Cat::type_info;
// end::classes[]
struct Dog : virtual Animal {
Dog() {
type = type_info.id;
}
virtual void* cast_impl(unsigned target) {
if (type_info.id == target) {
return this;
} else {
return Animal::cast_impl(target);
}
}
static custom_type_info type_info;
};
#include <boost/openmethod/policies/basic_policy.hpp>
#include <boost/openmethod/policies/vptr_vector.hpp>
namespace bom = boost::openmethod;
struct custom_rtti : bom::policies::rtti {
template<typename T>
static bom::type_id static_type() {
if constexpr (std::is_base_of_v<Animal, T>) {
return T::type_info.id;
} else {
return 0;
}
}
template<typename T>
static bom::type_id dynamic_type(const T& obj) {
if constexpr (std::is_base_of_v<Animal, T>) {
return obj.type;
} else {
return 0;
}
}
// tag::dynamic_cast_ref[]
// to support virtual inheritance:
template<typename Derived, typename Base>
static Derived dynamic_cast_ref(Base&& obj) {
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
}
}
// end::dynamic_cast_ref[]
};
struct custom_policy
: bom::policies::basic_policy<
custom_policy, custom_rtti, bom::policies::deferred_static_rtti,
bom::policies::vptr_vector<custom_policy>> {};
#define BOOST_OPENMETHOD_DEFAULT_POLICY custom_policy
#include <iostream>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
BOOST_OPENMETHOD(poke, (std::ostream&, virtual_ptr<Animal>), void);
BOOST_OPENMETHOD_OVERRIDE(
poke, (std::ostream & os, virtual_ptr<Cat> cat), void) {
os << "hiss";
}
BOOST_OPENMETHOD_OVERRIDE(
poke, (std::ostream & os, virtual_ptr<Dog> dog), void) {
os << "bark";
}
BOOST_OPENMETHOD_CLASSES(Animal, Cat, Dog);
custom_type_info Dog::type_info;
int main() {
boost::openmethod::initialize();
std::unique_ptr<Animal> a(new Cat);
std::unique_ptr<Animal> b(new Dog);
poke(std::cout, *a); // prints "hiss"
std::cout << "\n";
poke(std::cout, *b); // prints "bark"
std::cout << "\n";
return 0;
}
// end::example[]

100
examples/friendship.cpp Normal file
View File

@@ -0,0 +1,100 @@
// 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>
#include <string>
#include <boost/openmethod.hpp>
#ifdef FRIEND_ALL
// tag::friend_all[]
class Cat;
class Dog;
class Animal {
// end::friend_all[]
public:
Animal(std::string name) : name(name) {
}
virtual ~Animal() = default;
// tag::friend_all[]
// ...
private:
std::string name;
template<typename> friend struct BOOST_OPENMETHOD_OVERRIDERS(poke);
};
// end::friend_all[]
#else
// tag::friend[]
class Cat;
class Dog;
template<typename> struct BOOST_OPENMETHOD_OVERRIDERS(poke);
class Animal {
// ...
// end::friend[]
public:
Animal(std::string name) : name(name) {
}
virtual ~Animal() = default;
// tag::friend[]
private:
std::string name;
friend struct BOOST_OPENMETHOD_OVERRIDERS(poke)<void(std::ostream&, virtual_ptr<Cat>)>;
friend struct BOOST_OPENMETHOD_OVERRIDERS(poke)<void(std::ostream&, virtual_ptr<Dog>)>;
};
// end::friend[]
#endif
class Cat : public Animal {
using Animal::Animal;
};
class Dog : public Animal {
using Animal::Animal;
};
class Animal;
BOOST_OPENMETHOD(poke, (std::ostream&, virtual_ptr<Animal>), void);
BOOST_OPENMETHOD_OVERRIDE(
poke, (std::ostream& os, virtual_ptr<Cat> cat), void) {
os << cat->name << " hisses";
}
BOOST_OPENMETHOD_OVERRIDE(
poke, (std::ostream& os, virtual_ptr<Dog> dog), void) {
os << dog->name << " barks";
}
BOOST_OPENMETHOD_CLASSES(Animal, Cat, Dog);
#include <boost/openmethod/compiler.hpp>
int main() {
boost::openmethod::initialize();
std::unique_ptr<Animal> a(new Cat("Felix"));
std::unique_ptr<Animal> b(new Dog("Snoopy"));
poke(std::cout, *a); // Felix hisses
std::cout << ".\n";
poke(std::cout, *b); // Snoopy barks
std::cout << ".\n";
return 0;
}

View File

@@ -0,0 +1,114 @@
// 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>
#include <string>
#include <boost/openmethod.hpp>
#ifdef FRIEND_ALL
// tag::friend_all[]
namespace pets {
template<typename> struct BOOST_OPENMETHOD_OVERRIDERS(poke);
}
namespace core {
class Animal {
// end::friend_all[]
// tag::friend_all[]
public:
Animal(std::string name) : name(name) {
}
virtual ~Animal() = default;
// ...
private:
std::string name;
template<typename> friend struct BOOST_OPENMETHOD_OVERRIDERS(pets::poke);
};
BOOST_OPENMETHOD(poke, (std::ostream&, virtual_ptr<Animal>), void);
}
#else
// tag::friend[]
namespace pets {
struct Cat;
struct Dog;
template<typename> struct BOOST_OPENMETHOD_OVERRIDERS(poke);
} // namespace pets
namespace core {
class Animal {
public:
Animal(std::string name) : name(name) {
}
virtual ~Animal() = default;
// end::friend[]
// tag::friend[]
// ...
private:
std::string name;
friend struct BOOST_OPENMETHOD_OVERRIDERS(pets::poke)<
void(std::ostream&, virtual_ptr<pets::Cat>)>;
friend struct BOOST_OPENMETHOD_OVERRIDERS(pets::poke)<
void(std::ostream&, virtual_ptr<pets::Dog>)>;
};
BOOST_OPENMETHOD(poke, (std::ostream&, virtual_ptr<Animal>), void);
}
// end::friend[]
#endif
// tag::friend[]
namespace pets {
struct Cat : core::Animal {
using Animal::Animal;
};
struct Dog : core::Animal {
using Animal::Animal;
};
BOOST_OPENMETHOD_OVERRIDE(
poke,
(std::ostream & os, virtual_ptr<Cat> cat),
void) {
os << cat->name << " hisses";
}
BOOST_OPENMETHOD_OVERRIDE(
poke, (std::ostream & os, virtual_ptr<Dog> dog), void) {
os << dog->name << " barks";
}
BOOST_OPENMETHOD_CLASSES(core::Animal, Cat, Dog);
} // namespace pets
// end::friend[]
#include <boost/openmethod/compiler.hpp>
int main() {
boost::openmethod::initialize();
std::unique_ptr<core::Animal> a(new pets::Cat("Felix"));
std::unique_ptr<core::Animal> b(new pets::Dog("Snoopy"));
core::poke(std::cout, *a); // Felix hisses
std::cout << ".\n";
core::poke(std::cout, *b); // Snoopy barks
std::cout << ".\n";
return 0;
}

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