mirror of
https://github.com/boostorg/openmethod.git
synced 2026-01-19 04:22:12 +00:00
lot of doc work, but also rework code
This commit is contained in:
@@ -2,8 +2,8 @@ mkdir -p flat/boost/openmethod
|
||||
python3 dev/flatten.py \
|
||||
flat/boost/openmethod.hpp \
|
||||
include/boost/openmethod.hpp \
|
||||
include/boost/openmethod/unique_ptr.hpp \
|
||||
include/boost/openmethod/shared_ptr.hpp \
|
||||
include/boost/openmethod/interop/std_unique_ptr.hpp \
|
||||
include/boost/openmethod/interop/std_shared_ptr.hpp \
|
||||
include/boost/openmethod/initialize.hpp
|
||||
python3 dev/flatten.py \
|
||||
flat/boost/openmethod/registry.hpp \
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
|
||||
## policy
|
||||
|
||||
### Synopsis
|
||||
|
||||
Defined in <boost/openmethod/policies/basic_policy.hpp>.
|
||||
|
||||
```c++
|
||||
namespace boost::openmethod::policies {
|
||||
|
||||
struct policy {
|
||||
static auto finalize() -> void;
|
||||
};
|
||||
|
||||
} // boost::openmethod::policies
|
||||
```
|
||||
|
||||
### Description
|
||||
|
||||
`policy` is the base class of all policys. It provides an empty `finalize` static
|
||||
function which can be overriden (via shadowing) by derived classes.
|
||||
|
||||
### Members
|
||||
|
||||
#### finalize
|
||||
|
||||
```c++
|
||||
static auto finalize() -> void;
|
||||
```
|
||||
|
||||
Does nothing.
|
||||
@@ -1791,7 +1791,7 @@ pointers:</p>
|
||||
#include <memory>
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/unique_ptr.hpp>
|
||||
#include <boost/openmethod/interop/std_unique_ptr.hpp>
|
||||
#include <boost/openmethod/compiler.hpp>
|
||||
|
||||
using namespace boost::openmethod::aliases;
|
||||
@@ -2870,7 +2870,7 @@ stored in the same place (the policy’s <code>static_vptr<Class></cod
|
||||
#include <unistd.h>
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/unique_ptr.hpp>
|
||||
#include <boost/openmethod/interop/std_unique_ptr.hpp>
|
||||
#include <boost/openmethod/compiler.hpp>
|
||||
|
||||
#include "dl.hpp"
|
||||
@@ -3117,7 +3117,7 @@ program.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sect4">
|
||||
<h5 id="ref_boostopenmethodshared_ptr_hpp"><boost/openmethod/shared_ptr.hpp></h5>
|
||||
<h5 id="ref_boostopenmethodshared_ptr_hpp"><boost/openmethod/interop/std_shared_ptr.hpp></h5>
|
||||
<div class="paragraph">
|
||||
<p>Provides support for using <code>std::shared_ptr</code> in place of plain pointers in
|
||||
virtual parameters.</p>
|
||||
@@ -4211,7 +4211,7 @@ auto operator!=(
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Defined in <code><boost/openmethod/shared_ptr.hpp></code>:</p>
|
||||
<p>Defined in <code><boost/openmethod/interop/std_shared_ptr.hpp></code>:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
@@ -4229,7 +4229,7 @@ inline auto make_shared_virtual(T&&... args)
|
||||
</div>
|
||||
</div>
|
||||
<div class="paragraph">
|
||||
<p>Defined in <code><boost/openmethod/unique_ptr.hpp></code>:</p>
|
||||
<p>Defined in <code><boost/openmethod/interop/std_unique_ptr.hpp></code>:</p>
|
||||
</div>
|
||||
<div class="listingblock">
|
||||
<div class="content">
|
||||
@@ -4606,13 +4606,13 @@ struct virtual_traits<..., Policy> {
|
||||
<p><code>T*</code></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>std::shared_ptr<T></code>: defined in <boost/openmethod/shared_ptr.hpp></p>
|
||||
<p><code>std::shared_ptr<T></code>: defined in <boost/openmethod/interop/std_shared_ptr.hpp></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>const std::shared_ptr<T>&</code>: defined in <boost/openmethod/shared_ptr.hpp></p>
|
||||
<p><code>const std::shared_ptr<T>&</code>: defined in <boost/openmethod/interop/std_shared_ptr.hpp></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>std::unique_ptr<T></code>: defined in <boost/openmethod/unique_ptr.hpp></p>
|
||||
<p><code>std::unique_ptr<T></code>: defined in <boost/openmethod/interop/std_unique_ptr.hpp></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -38,7 +38,7 @@ 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
|
||||
If `Class` 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
|
||||
|
||||
@@ -5,111 +5,30 @@
|
||||
|
||||
message(STATUS "Building examples")
|
||||
|
||||
if (CMAKE_BUILD_TYPE MATCHES "Release")
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "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(default_error_handler default_error_handler.cpp)
|
||||
target_link_libraries(default_error_handler Boost::openmethod)
|
||||
add_test(NAME default_error_handler COMMAND default_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")
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_compile_definitions(BOOST_OPENMETHOD_ENABLE_RUNTIME_CHECKS)
|
||||
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)
|
||||
file(GLOB cpp_files "*.cpp")
|
||||
|
||||
add_executable(slides slides.cpp)
|
||||
target_link_libraries(slides Boost::openmethod)
|
||||
add_test(NAME slides COMMAND slides)
|
||||
foreach(cpp ${cpp_files})
|
||||
if(cpp MATCHES "dl_.*\\.cpp")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
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)
|
||||
|
||||
add_executable(static_rtti static_rtti.cpp)
|
||||
target_link_libraries(static_rtti Boost::openmethod)
|
||||
add_test(NAME static_rtti COMMAND static_rtti)
|
||||
cmake_path(REMOVE_EXTENSION cpp LAST_ONLY OUTPUT_VARIABLE stem)
|
||||
string(REGEX REPLACE ".*/" "" stem ${stem})
|
||||
add_executable(${stem} ${cpp})
|
||||
target_link_libraries(${stem} PUBLIC Boost::openmethod Boost::unit_test_framework)
|
||||
add_test(NAME ${stem} COMMAND ${stem})
|
||||
add_dependencies(tests ${stem})
|
||||
endforeach()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
message(STATUS "Building dlopen example")
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <string>
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/shared_ptr.hpp>
|
||||
#include <boost/openmethod/interop/std_shared_ptr.hpp>
|
||||
#include <boost/openmethod/initialize.hpp>
|
||||
|
||||
using namespace boost::openmethod::aliases;
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <memory>
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/unique_ptr.hpp>
|
||||
#include <boost/openmethod/interop/std_unique_ptr.hpp>
|
||||
#include <boost/openmethod/initialize.hpp>
|
||||
|
||||
using namespace boost::openmethod::aliases;
|
||||
|
||||
@@ -31,7 +31,7 @@ struct Dog : Animal {
|
||||
static constexpr unsigned static_type = 3;
|
||||
};
|
||||
|
||||
#include <boost/openmethod/registry.hpp>
|
||||
#include <boost/openmethod/preamble.hpp>
|
||||
#include <boost/openmethod/policies/vptr_vector.hpp>
|
||||
|
||||
// tag::policy[]
|
||||
@@ -65,8 +65,8 @@ struct custom_rtti : bom::policies::rtti {
|
||||
// end::policy[]
|
||||
|
||||
// tag::registry[]
|
||||
struct custom_registry : bom::registry<custom_rtti, bom::policies::vptr_vector> {
|
||||
};
|
||||
struct custom_registry
|
||||
: bom::registry<custom_rtti, bom::policies::vptr_vector> {};
|
||||
|
||||
#define BOOST_OPENMETHOD_DEFAULT_REGISTRY custom_registry
|
||||
// end::registry[]
|
||||
|
||||
@@ -33,7 +33,7 @@ auto main() -> int {
|
||||
bom::initialize();
|
||||
|
||||
bom::default_registry::error_handler::set([](const auto& error) {
|
||||
if (std::holds_alternative<bom::not_implemented_error>(error)) {
|
||||
if (std::holds_alternative<bom::no_overrider>(error)) {
|
||||
throw std::runtime_error("not implemented");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -76,7 +76,7 @@ struct Dog : virtual Animal {
|
||||
static custom_type_info type_info;
|
||||
};
|
||||
|
||||
#include <boost/openmethod/registry.hpp>
|
||||
#include <boost/openmethod/preamble.hpp>
|
||||
#include <boost/openmethod/policies/vptr_vector.hpp>
|
||||
|
||||
namespace bom = boost::openmethod;
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/unique_ptr.hpp>
|
||||
#include <boost/openmethod/interop/std_unique_ptr.hpp>
|
||||
#include <boost/openmethod/initialize.hpp>
|
||||
|
||||
#include "dl.hpp"
|
||||
@@ -32,7 +32,7 @@ BOOST_OPENMETHOD_OVERRIDE(
|
||||
auto main() -> int {
|
||||
using namespace boost::openmethod;
|
||||
|
||||
dynamic::initialize();
|
||||
initialize<dynamic>();
|
||||
|
||||
std::cout << "Before loading library\n";
|
||||
|
||||
@@ -61,7 +61,7 @@ auto main() -> int {
|
||||
|
||||
std::cout << "\nAfter loading library\n";
|
||||
|
||||
dynamic::initialize();
|
||||
initialize<dynamic>();
|
||||
|
||||
auto make_tiger =
|
||||
reinterpret_cast<Animal* (*)()>(dlsym(handle, "make_tiger"));
|
||||
@@ -86,7 +86,7 @@ auto main() -> int {
|
||||
|
||||
std::cout << "\nAfter unloading library\n";
|
||||
|
||||
dynamic::initialize();
|
||||
initialize<dynamic>();
|
||||
|
||||
std::cout << "Gracie encounters Willy -> "
|
||||
<< encounter(gracie, willy); // ignore
|
||||
|
||||
42
doc/modules/ROOT/examples/inplace_vptr.cpp
Normal file
42
doc/modules/ROOT/examples/inplace_vptr.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2018-2025 Jean-Louis Leroy
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See accompanying file LICENSE_1_0.txt
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/inplace_vptr.hpp>
|
||||
#include <boost/openmethod/initialize.hpp>
|
||||
|
||||
using namespace boost::openmethod;
|
||||
|
||||
struct Animal : inplace_vptr_base<Animal> {};
|
||||
|
||||
struct Cat : Animal, inplace_vptr_derived<Cat, Animal> {};
|
||||
|
||||
struct Dog : Animal, inplace_vptr_derived<Dog, Animal> {};
|
||||
|
||||
BOOST_OPENMETHOD(
|
||||
poke, (virtual_<Animal&> animal, std::ostream& os), void);
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(poke, (Cat&, std::ostream& os), void) {
|
||||
os << "hiss\n";
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(poke, (Dog&, std::ostream& os), void) {
|
||||
os << "bark\n";
|
||||
}
|
||||
|
||||
int main() {
|
||||
initialize();
|
||||
|
||||
std::unique_ptr<Animal> a = std::make_unique<Cat>();
|
||||
std::unique_ptr<Animal> b = std::make_unique<Dog>();
|
||||
|
||||
poke(*a, std::cout); // hiss
|
||||
poke(*b, std::cout); // bark
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/initialize.hpp>
|
||||
#include <boost/openmethod/shared_ptr.hpp>
|
||||
#include <boost/openmethod/interop/std_shared_ptr.hpp>
|
||||
|
||||
using std::make_shared;
|
||||
using std::shared_ptr;
|
||||
|
||||
@@ -127,7 +127,7 @@ struct Init {
|
||||
}
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/unique_ptr.hpp>
|
||||
#include <boost/openmethod/interop/std_unique_ptr.hpp>
|
||||
#include <boost/openmethod/initialize.hpp>
|
||||
|
||||
namespace openmethods {
|
||||
|
||||
@@ -14,7 +14,7 @@ struct static_registry
|
||||
#define BOOST_OPENMETHOD_DEFAULT_REGISTRY static_registry
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/unique_ptr.hpp>
|
||||
#include <boost/openmethod/interop/std_unique_ptr.hpp>
|
||||
#include <boost/openmethod/initialize.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
@@ -95,7 +95,7 @@ BOOST_OPENMETHOD_OVERRIDE(
|
||||
|
||||
auto main() -> int {
|
||||
// Initialize the dispatch tables.
|
||||
boost::openmethod::initialize();
|
||||
boost::openmethod::initialize<>();
|
||||
|
||||
// Create a few objects.
|
||||
// Note that the actual classes are type-erased to base class Animal!
|
||||
|
||||
@@ -23,7 +23,7 @@ struct throw_if_not_implemented : bom::policies::error_handler {
|
||||
static auto error(const bom::openmethod_error&) -> void {
|
||||
}
|
||||
|
||||
static auto error(const bom::not_implemented_error& err) -> void {
|
||||
static auto error(const bom::no_overrider& err) -> void {
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
@@ -58,7 +58,7 @@ auto main() -> int {
|
||||
for (auto animal : animals) {
|
||||
try {
|
||||
trick(std::cout, *animal);
|
||||
} catch (bom::not_implemented_error&) {
|
||||
} catch (bom::no_overrider&) {
|
||||
std::cout << "not implemented\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,10 +74,10 @@ namespace inplace_vptr {
|
||||
|
||||
#include <boost/openmethod/inplace_vptr.hpp>
|
||||
|
||||
class Animal : public boost::openmethod::inplace_vptr<Animal> {
|
||||
class Animal : public boost::openmethod::inplace_vptr_base<Animal> {
|
||||
};
|
||||
|
||||
class Cat : public Animal, public boost::openmethod::inplace_vptr<Cat, Animal> {
|
||||
class Cat : public Animal, public boost::openmethod::inplace_vptr_derived<Cat, Animal> {
|
||||
};
|
||||
|
||||
BOOST_OPENMETHOD(poke, (std::ostream&, virtual_<Animal&>), void);
|
||||
|
||||
@@ -12,5 +12,6 @@
|
||||
** xref:custom_rtti.adoc[Custom RTTI]
|
||||
** xref:dynamic_loading.adoc[Dynamic Loading]
|
||||
* Reference
|
||||
** xref:headers.adoc[Headers]
|
||||
** xref:macros.adoc[Macros]
|
||||
** xref:reference:boost/openmethod.adoc[boost::openmethod]
|
||||
** xref:reference:boost/openmethod.adoc[Namespace boost::openmethod]
|
||||
|
||||
@@ -6,35 +6,38 @@
|
||||
Defined in <boost/openmethod/macros.hpp>.
|
||||
|
||||
```c++
|
||||
BOOST_OPENMETHOD(NAME, (PARAMETERS...), RETURN_TYPE [, REGISTRY]);
|
||||
BOOST_OPENMETHOD(ID, (PARAMETERS...), RETURN_TYPE [, REGISTRY]);
|
||||
```
|
||||
|
||||
### Description
|
||||
|
||||
Declare a method.
|
||||
Declares a method.
|
||||
|
||||
The macro expands to several constructs:
|
||||
|
||||
* A `struct` forward declaration that acts as the method's identifier:
|
||||
|
||||
```c++
|
||||
struct BOOST_OPENMETHOD_ID(NAME);
|
||||
struct BOOST_OPENMETHOD_ID(ID);
|
||||
```
|
||||
|
||||
* 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_ID(NAME)(PARAMETERS...), RETURN_TYPE, REGISTRY>::fn`.
|
||||
`method<BOOST_OPENMETHOD_ID(ID)(PARAMETERS...), RETURN_TYPE, REGISTRY>::fn`.
|
||||
|
||||
* A guide function used to match overriders with the method:
|
||||
|
||||
```c++
|
||||
auto BOOST_OPENMETHOD_ID(NAME)_guide(...)
|
||||
auto BOOST_OPENMETHOD_ID(ID)_guide(...)
|
||||
-> ::boost::openmethod::method<
|
||||
BOOST_OPENMETHOD_ID(NAME)(PARAMETERS...), RETURN_TYPE [, REGISTRY]>;
|
||||
BOOST_OPENMETHOD_ID(ID)(PARAMETERS...), RETURN_TYPE [, REGISTRY]>;
|
||||
```
|
||||
|
||||
NOTE: `NAME` must be an *identifier*. Qualified names are not allowed.
|
||||
* A xref:BOOST_OPENMETHOD_REGISTER.adoc[registrar] that adds the method to the
|
||||
registry.
|
||||
|
||||
NOTE: `ID` must be an *identifier*. Qualified names are not allowed.
|
||||
|
||||
NOTE: The default value for `REGISTRY` is the value of
|
||||
`BOOST_OPENMETHOD_DEFAULT_REGISTRY` at the point `<boost/openmethod/core.hpp>` is
|
||||
|
||||
@@ -19,5 +19,5 @@ NOTE: The default value for `REGISTRY` is the value of
|
||||
`BOOST_OPENMETHOD_DEFAULT_REGISTRY` 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
|
||||
This macro is a wrapper around cpp:use_classes[]; see its documentation for more
|
||||
details.
|
||||
|
||||
@@ -11,7 +11,7 @@ Defined in <boost/openmethod/macros.hpp>.
|
||||
|
||||
### Description
|
||||
|
||||
Declare an overrider for a method.
|
||||
Declares an overrider for a method.
|
||||
|
||||
The method is deduced from a call to a method guide function with the
|
||||
overrider's arguments.
|
||||
|
||||
@@ -15,15 +15,22 @@ Defined in `<https://www.github.com/boostorg/openmethod/blob/develop/include/
|
||||
The name of the default registry.
|
||||
|
||||
`BOOST_OPENMETHOD_DEFAULT_REGISTRY` is the default value for the `Registry`
|
||||
template parameter of `method`, `use_classes`, and other constructs defined in
|
||||
`<boost/openmethod/core.hpp>`. If it is not defined,
|
||||
link:reference/boost/openmethod/default_registry.html[`default_registry`] is used.
|
||||
template parameter of cpp:method[], cpp:use_classes[], cpp:virtual_ptr[], and
|
||||
all the constructs that take a registry as a template argument.
|
||||
|
||||
`BOOST_OPENMETHOD_DEFAULT_REGISTRY` can be defined by a program to change the
|
||||
default REGISTRY globally. Once `<boost/openmethod/core.hpp>` has been included,
|
||||
redefining the symbol has no effect. To override the default REGISTRY, proceed as
|
||||
follows:
|
||||
default registry globally, *before* including `<boost/openmethod/core.hpp>`. After that, changing its value has no effect, even on other macros.
|
||||
|
||||
To override the default registry, proceed as follows:
|
||||
|
||||
1. Define a cpp:registry[] class, either from scratch, or by tuning an existing
|
||||
registry. Include `<boost/openmethod/preamble.hpp>`,
|
||||
`<boost/openmethod/default_registry.hpp>`, and headers under
|
||||
`boost/openmethod/policies` as needed.
|
||||
|
||||
2. Set `BOOST_OPENMETHOD_DEFAULT_REGISTRY` to the new registry class.
|
||||
|
||||
1. Include headers under `boost/openmethod/policies/` as needed.
|
||||
2. Create a REGISTRY class, and set `BOOST_OPENMETHOD_DEFAULT_REGISTRY`.
|
||||
3. Include `<boost/openmethod/core.hpp>`.
|
||||
|
||||
NOTE;; Use this feature with caution, as it will cause ODR violations if
|
||||
different translation units define different default registries.
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
Defined in <boost/openmethod/macros.hpp>.
|
||||
|
||||
```c++
|
||||
#define BOOST_OPENMETHOD_DEFINE_OVERRIDER(NAME, (PARAMETERS...), RETURN_TYPE)
|
||||
#define BOOST_OPENMETHOD_DEFINE_OVERRIDER(ID, (PARAMETERS...), RETURN_TYPE)
|
||||
```
|
||||
|
||||
### Description
|
||||
|
||||
Define the body of an overrider declared with
|
||||
`BOOST_OPENMETHOD_DECLARE_OVERRIDER`. It should be called in an implementation
|
||||
file, and followed by a function body.
|
||||
Defines the body of an overrider declared with
|
||||
xref:BOOST_OPENMETHOD_DECLARE_OVERRIDER.adoc[BOOST_OPENMETHOD_DECLARE_OVERRIDER].
|
||||
It should be called in an implementation file, and followed by a function body.
|
||||
|
||||
NOTE: `NAME` must be an *identifier*. Qualified names are not allowed.
|
||||
NOTE: `ID` must be an *identifier*. Qualified names are not allowed.
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
= xref:macros.adoc[Macro] BOOST_OPENMETHOD_ENABLE_RUNTIME_CHECKS
|
||||
|
||||
Enables runtime checks in default_registry.
|
||||
|
||||
== Synopsis
|
||||
|
||||
May be defined by a program before including
|
||||
`<boost/openmethod/default_registry.hpp>` to enable runtime checks.
|
||||
|
||||
== Description
|
||||
|
||||
See cpp:default_registry[] for details.
|
||||
@@ -1,14 +0,0 @@
|
||||
|
||||
## BOOST_OPENMETHOD_GUIDE
|
||||
|
||||
### Synopsis
|
||||
|
||||
Defined in <boost/openmethod/macros.hpp>.
|
||||
|
||||
```c++
|
||||
#define BOOST_OPENMETHOD_GUIDE(NAME) /* unspecified */
|
||||
```
|
||||
|
||||
### Description
|
||||
|
||||
Expands to the name of the guide function used to match overriders to methods.
|
||||
@@ -8,10 +8,12 @@
|
||||
Defined in <boost/openmethod/macros.hpp>.
|
||||
|
||||
```c++
|
||||
#define BOOST_OPENMETHOD_ID(NAME) /* unspecified */
|
||||
#define BOOST_OPENMETHOD_ID(ID) /* unspecified */
|
||||
```
|
||||
|
||||
### Description
|
||||
|
||||
Generates a long, obfuscated name from a short name. All the other names
|
||||
generated by macros are based on this name.
|
||||
|
||||
NOTE: `ID` must be an *identifier*. Qualified names are not allowed.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
Defined in <boost/openmethod/macros.hpp>.
|
||||
|
||||
```c++
|
||||
BOOST_OPENMETHOD_INLINE_OVERRIDE(NAME, (PARAMETERS...), RETURN_TYPE) {
|
||||
BOOST_OPENMETHOD_INLINE_OVERRIDE(ID, (PARAMETERS...), RETURN_TYPE) {
|
||||
// body
|
||||
}
|
||||
```
|
||||
@@ -17,5 +17,3 @@ BOOST_OPENMETHOD_INLINE_OVERRIDE(NAME, (PARAMETERS...), RETURN_TYPE) {
|
||||
|
||||
`BOOST_OPENMETHOD_INLINE_OVERRIDE` performs the same function as
|
||||
`BOOST_OPENMETHOD_OVERRIDE`, except that the overrider is defined inline.
|
||||
|
||||
NOTE: `NAME` must be an *identifier*. Qualified names are not allowed.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
Defined in <boost/openmethod/macros.hpp>.
|
||||
|
||||
```c++
|
||||
BOOST_OPENMETHOD_OVERRIDE(NAME, (PARAMETERS...), RETURN_TYPE) {
|
||||
BOOST_OPENMETHOD_OVERRIDE(ID, (PARAMETERS...), RETURN_TYPE) {
|
||||
// body
|
||||
}
|
||||
```
|
||||
@@ -23,23 +23,23 @@ 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`:
|
||||
called `ID`:
|
||||
|
||||
```c++
|
||||
template<typename...> BOOST_OPENMETHOD_OVERRIDERS(NAME);
|
||||
template<typename...> BOOST_OPENMETHOD_OVERRIDERS(ID);
|
||||
```
|
||||
|
||||
* A specialization of the container template for the overrider:
|
||||
|
||||
+
|
||||
--
|
||||
```c++
|
||||
struct BOOST_OPENMETHOD_OVERRIDERS(NAME)<RETURN_TYPE(PARAMETERS...)> {
|
||||
struct BOOST_OPENMETHOD_OVERRIDERS(ID)<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.
|
||||
@@ -48,14 +48,23 @@ where:
|
||||
|
||||
* `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:
|
||||
[]
|
||||
|
||||
* A xref:BOOST_OPENMETHOD_REGISTER.adoc[registrar] adding the overrider to the
|
||||
method.
|
||||
|
||||
* Finally, the macro starts the definition of the overrider function:
|
||||
--
|
||||
```c++
|
||||
auto BOOST_OPENMETHOD_OVERRIDERS(NAME)<RETURN_TYPE(PARAMETERS...)>::fn(
|
||||
auto BOOST_OPENMETHOD_OVERRIDERS(ID)<RETURN_TYPE(PARAMETERS...)>::fn(
|
||||
PARAMETERS...) -> RETURN_TYPE
|
||||
```
|
||||
--
|
||||
|
||||
The block following the call to the macro is the body of the function.
|
||||
{empty}
|
||||
|
||||
NOTE: `NAME` must be an *identifier*. Qualified names are not allowed.
|
||||
The `{}` block following the call to the macro is the body of the function.
|
||||
|
||||
NOTE: `ID` must be an *identifier*. Qualified names are not allowed.
|
||||
|
||||
@@ -6,10 +6,12 @@
|
||||
Defined in <boost/openmethod/macros.hpp>.
|
||||
|
||||
```c++
|
||||
#define BOOST_OPENMETHOD_OVERRIDER(NAME, (PARAMETERS...), RETURN_TYPE)
|
||||
#define BOOST_OPENMETHOD_OVERRIDER(ID, (PARAMETERS...), RETURN_TYPE)
|
||||
```
|
||||
|
||||
### Description
|
||||
|
||||
Expands to the specialization of the class template that contains the overrider
|
||||
for with the given name, parameter list and return type.
|
||||
|
||||
NOTE: `ID` must be an *identifier*. Qualified names are not allowed.
|
||||
|
||||
@@ -6,11 +6,13 @@
|
||||
Defined in <boost/openmethod/macros.hpp>.
|
||||
|
||||
```c++
|
||||
#define BOOST_OPENMETHOD_OVERRIDERS(NAME) \
|
||||
BOOST_PP_CAT(BOOST_OPENMETHOD_ID(NAME), _overriders)
|
||||
#define BOOST_OPENMETHOD_OVERRIDERS(ID) \
|
||||
BOOST_PP_CAT(BOOST_OPENMETHOD_ID(ID), _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.
|
||||
|
||||
NOTE: `ID` must be an *identifier*. Qualified names are not allowed.
|
||||
|
||||
@@ -13,4 +13,7 @@ BOOST_OPENMETHOD_REGISTER(TYPE);
|
||||
|
||||
### Description
|
||||
|
||||
Creates a static instance of `TYPE`, using a unique generated name.
|
||||
Creates a registrar for `TYPE`, i.e. a static `TYPE` object with a unique
|
||||
generated name. At static initialization time, the object adds itself to a list:
|
||||
methods and class registrations add themselves to a cpp:registry[], and
|
||||
overriders add themselves to a method's overrider list.
|
||||
|
||||
141
doc/modules/ROOT/pages/headers.adoc
Normal file
141
doc/modules/ROOT/pages/headers.adoc
Normal file
@@ -0,0 +1,141 @@
|
||||
[#headers]
|
||||
= xref:headers.adoc[Headers]
|
||||
:toc:
|
||||
|
||||
{empty}
|
||||
|
||||
*NOTE*: The two important headers are:
|
||||
|
||||
* xref:#main[`boost/openmethod.hpp`] to define open-methods and overriders using
|
||||
convenient macros.
|
||||
|
||||
* xref:#initialize[`boost/openmethod.hpp/initialize`] to initialize the library.
|
||||
Typically only included in the translation unit containing `main`.
|
||||
|
||||
The following headers make it possible to use standard smart pointers in virtual
|
||||
parameters:
|
||||
|
||||
* xref:#std_shared_ptr[`boost/openmethod/interop/std_shared_ptr.hpp`] to use
|
||||
`std::shared_ptr` in virtual parameters.
|
||||
|
||||
* xref:#std_unique_ptr[`boost/openmethod/interop/std_unique_ptr.hpp`] to use
|
||||
`std::unique_ptr` in virtual parameters.
|
||||
|
||||
*The other headers are for advanced use*.
|
||||
|
||||
### boost/openmethod/preamble.hpp
|
||||
|
||||
Defines `registry` and stock policies. Also defines all the types and functions
|
||||
necessary to the definition of `registry`.
|
||||
|
||||
Most users should not include this header directly, unless for the purpose of
|
||||
overriding the default registry.
|
||||
|
||||
### boost/openmethod/policies/std_rtti.hpp
|
||||
|
||||
Includes all the headers above.
|
||||
|
||||
Provides an implementation of the `rtti` policy using standard RTTI.
|
||||
|
||||
### boost/openmethod/policies/fast_perfect_hash.hpp
|
||||
|
||||
Includes all the headers above.
|
||||
|
||||
Provides an implementation of the `hash` policy using a fast perfect hash
|
||||
function.
|
||||
|
||||
### boost/openmethod/policies/vptr_vector.hpp
|
||||
|
||||
Includes all the headers above.
|
||||
|
||||
Provides an implementation of the `vptr` policy that stores the v-table pointers
|
||||
in a `std::vector` indexed by type ids, possibly hashed.
|
||||
|
||||
### boost/openmethod/policies/default_error_handler.hpp
|
||||
|
||||
Includes all the headers above.
|
||||
|
||||
Provides an implementation of the `error_handler` policy that calls a
|
||||
`std::function<void(openmethod_error)>` when an error is encountered, and before
|
||||
the library aborts the program.
|
||||
|
||||
### boost/openmethod/policies/stderr_output.hpp
|
||||
|
||||
Includes all the headers above.
|
||||
|
||||
Provides an implementation of the `output` policy that writes diagnostics to
|
||||
the C standard error stream (not using iostreams).
|
||||
|
||||
### boost/openmethod/default_registry.hpp
|
||||
|
||||
Includes all the headers above.
|
||||
|
||||
Defines the default registry, which contains all the stock policies listed
|
||||
above.
|
||||
|
||||
Most users should not include this header directly, unless for the purpose of
|
||||
overriding the default registry.
|
||||
|
||||
### boost/openmethod/core.hpp
|
||||
|
||||
Includes all the headers above.
|
||||
|
||||
Defines the main constructs of the library: methods, overriders and virtual
|
||||
pointers, and mechanisms to implement them. Does not define any public macros
|
||||
apart from `BOOST_OPENMETHOD_DEFAULT_REGISTRY`, if it is not defined already.
|
||||
|
||||
Users with a severe allergy to macros can include this header.
|
||||
|
||||
### boost/openmethod/macros.hpp
|
||||
|
||||
Includes all the headers above.
|
||||
|
||||
Defines the public macros of the library, such as `BOOST_OPENMETHOD`,
|
||||
`BOOST_OPENMETHOD_CLASSES`, etc.
|
||||
|
||||
There is little point in including this header directly, as it has the same
|
||||
effect as including `boost/openmethod.hpp`, which is shorter.
|
||||
|
||||
[#main]
|
||||
### boost/openmethod.hpp
|
||||
|
||||
Includes all the headers above.
|
||||
|
||||
This is the header that most users should include.
|
||||
|
||||
### boost/openmethod/policies/static_rtti.hpp
|
||||
|
||||
Includes `preamble.hpp`.
|
||||
|
||||
Provides a minimal implementation of the `rtti` policy that does not depend on
|
||||
standard RTTI.
|
||||
|
||||
### boost/openmethod/policies/throw_error_handler.hpp
|
||||
|
||||
Includes `preamble.hpp`.
|
||||
|
||||
Provides an implementation of the `error_handler` policy that throws errors as
|
||||
exceptions.
|
||||
|
||||
### boost/openmethod/policies/vptr_map.hpp
|
||||
|
||||
Includes `preamble.hpp`.
|
||||
|
||||
Provides an implementation of the `vptr` policy that stores the v-table pointers
|
||||
in a map (by default a `std::map`) indexed by type ids.
|
||||
|
||||
[#std_shared_ptr]
|
||||
### boost/openmethod/interop/std_shared_ptr.hpp
|
||||
|
||||
Includes `core.hpp`.
|
||||
|
||||
Provides a `virtual_traits` specialization that make it possible to use a
|
||||
`std::shared_ptr` in place of a raw pointer or reference in virtual parameters.
|
||||
|
||||
[#std_unique_ptr]
|
||||
### boost/openmethod/interop/std_unique_ptr.hpp
|
||||
|
||||
Includes `core.hpp`.
|
||||
|
||||
Provides a `virtual_traits` specialization that make it possible to use a
|
||||
`std::unique_ptr` in place of a raw pointer or reference in virtual parameters.
|
||||
@@ -5,27 +5,29 @@
|
||||
[cols=2]
|
||||
|===
|
||||
| Name
|
||||
| Description
|
||||
| Description.
|
||||
| xref:BOOST_OPENMETHOD.adoc[BOOST_OPENMETHOD]
|
||||
| Declare a method
|
||||
| Declare a method.
|
||||
| xref:BOOST_OPENMETHOD_CLASSES.adoc[BOOST_OPENMETHOD_CLASSES]
|
||||
| registers classes
|
||||
| registers classes.
|
||||
| xref:BOOST_OPENMETHOD_DECLARE_OVERRIDER.adoc[BOOST_OPENMETHOD_DECLARE_OVERRIDER]
|
||||
| Declare a method overrider
|
||||
| xref:BOOST_OPENMETHOD_DEFAULT_REGISTRY.adoc[BOOST_OPENMETHOD_DEFAULT_REGISTRY]
|
||||
| Default registry
|
||||
| Declare a method overrider.
|
||||
| xref:BOOST_OPENMETHOD_DEFINE_OVERRIDER.adoc[BOOST_OPENMETHOD_DEFINE_OVERRIDER]
|
||||
| Define the body of a method overrider
|
||||
| Define the body of a method overrider.
|
||||
| xref:BOOST_OPENMETHOD_ID.adoc[BOOST_OPENMETHOD_ID]
|
||||
| Generate a method id
|
||||
| Generate a method id.
|
||||
| xref:BOOST_OPENMETHOD_INLINE_OVERRIDE.adoc[BOOST_OPENMETHOD_INLINE_OVERRIDE]
|
||||
| Add an overrider to a method as an inline function
|
||||
| Add an overrider to a method as an inline function.
|
||||
| xref:BOOST_OPENMETHOD_OVERRIDE.adoc[BOOST_OPENMETHOD_OVERRIDE]
|
||||
| Add an overrider to a method
|
||||
| Add an overrider to a method.
|
||||
| xref:BOOST_OPENMETHOD_OVERRIDER.adoc[BOOST_OPENMETHOD_OVERRIDER]
|
||||
| Return the class template specialization containing an overrider
|
||||
| Return the class template specialization containing an overrider.
|
||||
| xref:BOOST_OPENMETHOD_OVERRIDERS.adoc[BOOST_OPENMETHOD_OVERRIDERS]
|
||||
| Return the class template containing the overriders for all the methods with a given name
|
||||
| Return the class template containing the overriders for all the methods with a given name.
|
||||
| xref:BOOST_OPENMETHOD_REGISTER.adoc[BOOST_OPENMETHOD_REGISTER]
|
||||
| Create a registrar object
|
||||
| Create a registrar object.
|
||||
| xref:BOOST_OPENMETHOD_DEFAULT_REGISTRY.adoc[BOOST_OPENMETHOD_DEFAULT_REGISTRY]
|
||||
| Default registry.
|
||||
| xref:BOOST_OPENMETHOD_ENABLE_RUNTIME_CHECKS.adoc[BOOST_OPENMETHOD_ENABLE_RUNTIME_CHECKS]
|
||||
| Enable runtime checks in method calls.
|
||||
|===
|
||||
|
||||
5
doc/modules/ROOT/pages/virtual_parameter.adoc
Normal file
5
doc/modules/ROOT/pages/virtual_parameter.adoc
Normal file
@@ -0,0 +1,5 @@
|
||||
[#virtual_parameter]
|
||||
= xref:virtual_parameter.adoc[Macros]
|
||||
|
||||
A virtual parameter is a parameter of an open-method that is either a @ref
|
||||
virtual_ptr, or is decorated with @ref virtual_
|
||||
@@ -73,7 +73,7 @@ Provides `intialize` and `finalize`. Typically included only by the translation
|
||||
unit that contains `main`, unless dynamic loading is used in other places in the
|
||||
program.
|
||||
|
||||
#### <boost/openmethod/shared_ptr.hpp>
|
||||
#### <boost/openmethod/interop/std_shared_ptr.hpp>
|
||||
|
||||
Provides support for using `std::shared_ptr` in place of plain pointers in
|
||||
virtual parameters.
|
||||
|
||||
@@ -63,7 +63,7 @@ auto operator!=(
|
||||
} // namespace boost::openmethod
|
||||
```
|
||||
|
||||
Defined in `<boost/openmethod/shared_ptr.hpp>`:
|
||||
Defined in `<boost/openmethod/interop/std_shared_ptr.hpp>`:
|
||||
|
||||
```c++
|
||||
namespace boost::openmethod {
|
||||
@@ -78,7 +78,7 @@ inline auto make_shared_virtual(T&&... args)
|
||||
|
||||
}
|
||||
```
|
||||
Defined in `<boost/openmethod/unique_ptr.hpp>`:
|
||||
Defined in `<boost/openmethod/interop/std_unique_ptr.hpp>`:
|
||||
|
||||
```c++
|
||||
namespace boost::openmethod {
|
||||
|
||||
@@ -36,9 +36,9 @@ Specializations are provided for:
|
||||
* `T&`
|
||||
* `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>
|
||||
* `std::shared_ptr<T>`: defined in <boost/openmethod/interop/std_shared_ptr.hpp>
|
||||
* `const std::shared_ptr<T>&`: defined in <boost/openmethod/interop/std_shared_ptr.hpp>
|
||||
* `std::unique_ptr<T>`: defined in <boost/openmethod/interop/std_unique_ptr.hpp>
|
||||
|
||||
### Members
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <boost/mp11/integral.hpp>
|
||||
#include <boost/mp11/list.hpp>
|
||||
|
||||
#include <boost/openmethod/registry.hpp>
|
||||
#include <boost/openmethod/preamble.hpp>
|
||||
#include <boost/openmethod/default_registry.hpp>
|
||||
|
||||
#ifndef BOOST_OPENMETHOD_DEFAULT_REGISTRY
|
||||
@@ -35,10 +35,6 @@
|
||||
#endif
|
||||
|
||||
//! Main namespace of the OpenMethod library.
|
||||
//!
|
||||
//! @note Names in CamelCase are for exposition only. Blueprints are
|
||||
//! exposition-only classes that describe the requirements for existing classes.
|
||||
|
||||
namespace boost::openmethod {
|
||||
|
||||
#ifdef __MRDOCS__
|
||||
@@ -216,7 +212,9 @@ BOOST_OPENMETHOD_CLOSE_NAMESPACE_DETAIL_UNLESS_MRDOCS
|
||||
//! `Cat&`)
|
||||
//! @li cast the argument to another type (e.g. cast a `Animal&` to a `Cat&`)
|
||||
//!
|
||||
//! Specializations of `virtual_traits` must conform to the @ref VirtualTraits
|
||||
//!
|
||||
//! @par Requirements
|
||||
//! Specializations of `virtual_traits` must implement the members deswcribed to the @ref VirtualTraits
|
||||
//! blueprint.
|
||||
//!
|
||||
//! @tparam T A type referring (in the broad sense) to an instance of a class.
|
||||
@@ -398,13 +396,13 @@ class use_classes {
|
||||
detail::use_classes_tuple_type<Classes...> tuple;
|
||||
};
|
||||
|
||||
void boost_openmethod_vptr(...);
|
||||
|
||||
// =============================================================================
|
||||
// virtual_ptr
|
||||
|
||||
namespace detail {
|
||||
|
||||
void boost_openmethod_vptr(...);
|
||||
|
||||
template<typename, class, typename = void>
|
||||
struct is_smart_ptr_aux : std::false_type {};
|
||||
|
||||
@@ -458,7 +456,7 @@ constexpr bool IsPolymorphic = Registry::rtti::template is_polymorphic<Class>;
|
||||
template<typename Class, class Registry>
|
||||
constexpr bool IsSmartPtr = detail::is_smart_ptr_aux<Class, Registry>::value;
|
||||
|
||||
//! Test if arguments are smart pointers of same type (exposition only)
|
||||
//! Test if arguments are same kind of smart pointers (exposition only)
|
||||
//!
|
||||
//! Evaluates to `true` if `Class` and `Other` are both smart pointers of the
|
||||
//! same type.
|
||||
@@ -509,7 +507,7 @@ constexpr bool has_vptr_fn = std::is_same_v<
|
||||
|
||||
template<class Registry, class ArgType>
|
||||
decltype(auto) acquire_vptr(const ArgType& arg) {
|
||||
Registry::check_initialized();
|
||||
Registry::require_initialized();
|
||||
|
||||
if constexpr (detail::has_vptr_fn<ArgType, Registry>) {
|
||||
return boost_openmethod_vptr(arg, static_cast<Registry*>(nullptr));
|
||||
@@ -539,23 +537,25 @@ inline vptr_type null_vptr = nullptr;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
//! Create a `virtual_ptr` for an object of an exact known type
|
||||
//! Creates a `virtual_ptr` for an object of a known dynamic type.
|
||||
//!
|
||||
//! `final_virtual_ptr` creates a `virtual_ptr` to an object, setting its
|
||||
//! v-table pointer according to the declared type of its argument. It assumes
|
||||
//! 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.
|
||||
//! Creates a @ref virtual_ptr to an object, setting its v-table pointer
|
||||
//! according to the declared type of its argument. Assumes that the static and
|
||||
//! dynamic types are the same. Sets the v-table pointer to the
|
||||
//! @ref registry::static_vptr for the class.
|
||||
//!
|
||||
//! @par Errors If the registry has runtime checks enabled, and the argument is
|
||||
//! a class type that is polymorphic according to the registry's `rtti` policy,
|
||||
//! a check is performed to verify that the static and dynamic types are indeed
|
||||
//! the same. If they are not, and if the registry contains an @ref
|
||||
//! error_handler policy, its
|
||||
//! @ref error function is called with a @ref final_error value, then the
|
||||
//! program is terminated with @ref abort.
|
||||
//! `Class` is _not_ required to be polymorphic.
|
||||
//!
|
||||
//! @tparam Registry The registry in which the class is registered.
|
||||
//! If runtime checks are enabled, and the argument is polymorphic, checks if
|
||||
//! the static and dynamic types are the same. If not, calls the error handler
|
||||
//! with a @ref final_error value, then terminates the program with @ref abort.
|
||||
//!
|
||||
//! @par Errors
|
||||
//!
|
||||
//! @li @ref final_error The static and dynamic types of the object are
|
||||
//! different.
|
||||
//!
|
||||
//! @tparam Registry A @ref registry.
|
||||
//! @tparam Arg The type of the argument.
|
||||
//! @param obj A reference to an object.
|
||||
//! @return A `virtual_ptr<Class, Registry>` pointing to `obj`.
|
||||
@@ -592,6 +592,12 @@ inline auto final_virtual_ptr(Arg&& obj) {
|
||||
Registry::template static_vptr<Class>));
|
||||
}
|
||||
|
||||
//! Create a `virtual_ptr` for an object of a known dynamic type.
|
||||
//!
|
||||
//! This is an overload of `final_virtual_ptr` that uses the default
|
||||
//! registry as the `Registry` template parameter.
|
||||
//!
|
||||
//! @see @ref final_virtual_ptr
|
||||
template<class Arg>
|
||||
inline auto final_virtual_ptr(Arg&& obj) {
|
||||
return final_virtual_ptr<BOOST_OPENMETHOD_DEFAULT_REGISTRY, Arg>(
|
||||
@@ -613,16 +619,14 @@ inline auto final_virtual_ptr(Arg&& obj) {
|
||||
//! "plain" `virtual_ptr` can be constructed from a smart `virtual_ptr`, but not
|
||||
//! the other way around.
|
||||
//!
|
||||
//! TODO: link out from mrdocs to macro documentation
|
||||
//! The default value for `Registry` can be customized by defining the <a href="openmethod/BOOST_OPENMETHOD_DEFAULT_REGISTRY.html">BOOST_OPENMETHOD_DEFAULT_REGISTRY</a>
|
||||
//! The default value for `Registry` can be customized by defining the
|
||||
//! [BOOST_OPENMETHOD_DEFAULT_REGISTRY](../BOOST_OPENMETHOD_DEFAULT_REGISTRY.html)
|
||||
//! preprocessor symbol.
|
||||
//!
|
||||
//! The default value for `Registry` can be customized by defining the
|
||||
//! xref:BOOST_OPENMETHOD_DEFAULT_REGISTRY.adoc[`BOOST_OPENMETHOD_DEFAULT_REGISTRY`]
|
||||
//! preprocessor symbol.
|
||||
//!
|
||||
//! @par Examples
|
||||
//!
|
||||
//! @par Requirements
|
||||
//!
|
||||
//! @li @ref virtual_traits must be specialized for `Class&`.
|
||||
@@ -728,7 +732,7 @@ class virtual_ptr {
|
||||
//! The following errors may occur, depending on the policies selected in
|
||||
//! `Registry`:
|
||||
//!
|
||||
//! @li @ref unknown_class_error
|
||||
//! @li @ref missing_class
|
||||
template<
|
||||
class Other,
|
||||
typename = std::enable_if_t<
|
||||
@@ -778,7 +782,7 @@ class virtual_ptr {
|
||||
//! The following errors may occur, depending on the policies selected in
|
||||
//! `Registry`:
|
||||
//!
|
||||
//! @li @ref unknown_class_error
|
||||
//! @li @ref missing_class
|
||||
template<
|
||||
class Other,
|
||||
typename = std::enable_if_t<
|
||||
@@ -890,7 +894,7 @@ class virtual_ptr {
|
||||
//! The following errors may occur, depending on the policies selected in
|
||||
//! `Registry`:
|
||||
//!
|
||||
//! @li @ref unknown_class_error
|
||||
//! @li @ref missing_class
|
||||
template<
|
||||
class Other,
|
||||
typename = std::enable_if_t<
|
||||
@@ -940,7 +944,7 @@ class virtual_ptr {
|
||||
//! The following errors may occur, depending on the policies selected in
|
||||
//! `Registry`:
|
||||
//!
|
||||
//! @li @ref unknown_class_error
|
||||
//! @li @ref missing_class
|
||||
template<
|
||||
class Other,
|
||||
typename = std::enable_if_t<
|
||||
@@ -1735,16 +1739,40 @@ class virtual_ptr<
|
||||
}
|
||||
};
|
||||
|
||||
//! Construct a `virtual_ptr` from a lvalue reference.
|
||||
//!
|
||||
//! @tparam Class A class type, possibly cv-qualified.
|
||||
//! @param obj A lvalue reference to an object.
|
||||
//! @return A `virtual_ptr<Class>`.
|
||||
template<class Class>
|
||||
virtual_ptr(Class&) -> virtual_ptr<Class, BOOST_OPENMETHOD_DEFAULT_REGISTRY>;
|
||||
virtual_ptr(Class& obj)
|
||||
-> virtual_ptr<Class, BOOST_OPENMETHOD_DEFAULT_REGISTRY>;
|
||||
|
||||
//! Construct a `virtual_ptr` from a xvalue reference.
|
||||
//!
|
||||
//! @tparam Class A class type.
|
||||
//! @param obj A xvalue reference to an object.
|
||||
//! @return A `virtual_ptr<Class>`.
|
||||
template<class Class>
|
||||
virtual_ptr(Class&&) -> virtual_ptr<Class, BOOST_OPENMETHOD_DEFAULT_REGISTRY>;
|
||||
virtual_ptr(Class&& obj)
|
||||
-> virtual_ptr<Class, BOOST_OPENMETHOD_DEFAULT_REGISTRY>;
|
||||
|
||||
// Alas this is not allowed:
|
||||
// template<class Registry, class Class>
|
||||
// virtual_ptr<Registry>(Class&) -> virtual_ptr<Class, Registry>;
|
||||
|
||||
//! Compare two `virtual_ptr`s for equality.
|
||||
//!
|
||||
//! Compare the underlying object pointers for equality. The v-table pointers
|
||||
//! are not compared.
|
||||
//!!
|
||||
//! @tparam Left The type of the left-hand side argument.
|
||||
//! @tparam Right The type of the right-hand side argument.
|
||||
//! @tparam Registry A @ref registry.
|
||||
//! @param left A reference to a `virtual_ptr`.
|
||||
//! @param right A reference to a `virtual_ptr`.
|
||||
//! @return `true` if both `virtual_ptr`s point to the same object or both
|
||||
//! are `nullptr`, `false` otherwise.
|
||||
template<class Left, class Right, class Registry>
|
||||
auto operator==(
|
||||
const virtual_ptr<Left, Registry>& left,
|
||||
@@ -1752,6 +1780,17 @@ auto operator==(
|
||||
return left.pointer() == right.pointer();
|
||||
}
|
||||
|
||||
//! Compare two `virtual_ptr`s for inequality.
|
||||
//!
|
||||
//! Compare the underlying object pointers for inequality. The v-table pointers
|
||||
//! are not compared.
|
||||
//!! @tparam Left The type of the left-hand side argument.
|
||||
//! @tparam Right The type of the right-hand side argument.
|
||||
//! @tparam Registry A @ref registry.
|
||||
//! @param left A reference to a `virtual_ptr`.
|
||||
//! @param right A reference to a `virtual_ptr`.
|
||||
//! @return `true` if both `virtual_ptr`s point to different objects, or one
|
||||
//! is `nullptr` and the other is not, `false` otherwise.
|
||||
template<class Left, class Right, class Registry>
|
||||
auto operator!=(
|
||||
const virtual_ptr<Left, Registry>& left,
|
||||
@@ -1881,9 +1920,9 @@ using overrider_virtual_types = boost::mp11::mp_remove<
|
||||
void>;
|
||||
|
||||
template<class Method, class Rtti, std::size_t Index>
|
||||
struct init_call_error {
|
||||
struct init_bad_call {
|
||||
template<typename Arg, typename... Args>
|
||||
static auto fn(call_error& error, const Arg& arg, const Args&... args) {
|
||||
static auto fn(bad_call& error, const Arg& arg, const Args&... args) {
|
||||
if constexpr (Index == 0u) {
|
||||
error.method = Rtti::template static_type<Method>();
|
||||
error.arity = sizeof...(args);
|
||||
@@ -1899,30 +1938,19 @@ struct init_call_error {
|
||||
|
||||
error.types[Index] = arg_type_id;
|
||||
|
||||
init_call_error<Method, Rtti, Index + 1>::fn(error, args...);
|
||||
init_bad_call<Method, Rtti, Index + 1>::fn(error, args...);
|
||||
}
|
||||
|
||||
static auto fn(call_error&) {
|
||||
static auto fn(bad_call&) {
|
||||
}
|
||||
};
|
||||
|
||||
template<class Method, class Rtti>
|
||||
struct init_call_error<Method, Rtti, call_error::max_types> {
|
||||
static auto fn(call_error&) {
|
||||
struct init_bad_call<Method, Rtti, bad_call::max_types> {
|
||||
static auto fn(bad_call&) {
|
||||
}
|
||||
};
|
||||
|
||||
template<class Method>
|
||||
struct static_offsets;
|
||||
|
||||
template<class Method, typename = void>
|
||||
struct has_static_offsets : std::false_type {};
|
||||
|
||||
template<class Method>
|
||||
struct has_static_offsets<
|
||||
Method, std::void_t<decltype(static_offsets<Method>::slots)>>
|
||||
: std::true_type {};
|
||||
|
||||
template<class Registry>
|
||||
using method_base = std::conditional_t<
|
||||
Registry::has_deferred_static_rtti, deferred_method_info, method_info>;
|
||||
@@ -2040,14 +2068,14 @@ struct validate_method_parameter<
|
||||
//! 1. If `result` is a `virtual_ptr`, get the pointer to the v-table from it.
|
||||
//!
|
||||
//! 2. If `boost_openmethod_vptr` can be called with `result` and a `Registry*`,
|
||||
//! and returns a `vptr_type`, call it.
|
||||
//! and it returns a `vptr_type`, call it.
|
||||
//!
|
||||
//! 3. Call `Registry::rtti::dynamic_vptr(result)`.
|
||||
//!
|
||||
//! @par N2216 Handling of Ambiguous Calls
|
||||
//!
|
||||
//! If `Registry` contains the @ref n2216 policy, ambiguous calls are not an
|
||||
//! error. Instead, the following extra steps are taken to select an
|
||||
//! If `Registry` was initialized with the @ref N2216 option, ambiguous calls
|
||||
//! are not an error. Instead, the following extra steps are taken to select an
|
||||
//! overrider:
|
||||
//!
|
||||
//! 1. If the return type is a registered polymorphic type, remove all the
|
||||
@@ -2122,7 +2150,7 @@ class method<Id, ReturnType(Parameters...), Registry>
|
||||
//! Check if a next most specialized overrider exists
|
||||
//!
|
||||
//! Return `true` if a next most specialized overrider after _Fn_ exists,
|
||||
//! and @ref next can be called without causing a @ref call_error.
|
||||
//! and @ref next can be called without causing a @ref bad_call.
|
||||
//!
|
||||
//! @par Requirements
|
||||
//!
|
||||
@@ -2218,10 +2246,6 @@ class method<Id, ReturnType(Parameters...), Registry>
|
||||
template<typename ArgType>
|
||||
auto vptr(const ArgType& arg) const -> vptr_type;
|
||||
|
||||
template<class Error>
|
||||
auto
|
||||
check_static_offset(std::size_t actual, std::size_t expected) const -> void;
|
||||
|
||||
template<typename MethodArgList, typename ArgType, typename... MoreArgTypes>
|
||||
auto resolve_uni(const ArgType& arg, const MoreArgTypes&... more_args) const
|
||||
-> detail::word;
|
||||
@@ -2334,12 +2358,7 @@ method<Id, ReturnType(Parameters...), Registry>::method() {
|
||||
this->vp_begin = vp_type_ids;
|
||||
this->vp_end = vp_type_ids + Arity;
|
||||
this->not_implemented = reinterpret_cast<void (*)()>(fn_not_implemented);
|
||||
|
||||
if constexpr (Registry::has_n2216) {
|
||||
this->ambiguous = nullptr;
|
||||
} else {
|
||||
this->ambiguous = reinterpret_cast<void (*)()>(fn_ambiguous);
|
||||
}
|
||||
this->ambiguous = reinterpret_cast<void (*)()>(fn_ambiguous);
|
||||
|
||||
Registry::methods.push_back(*this);
|
||||
}
|
||||
@@ -2369,26 +2388,6 @@ method<Id, ReturnType(Parameters...), Registry>::~method() {
|
||||
Registry::methods.remove(*this);
|
||||
}
|
||||
|
||||
template<
|
||||
typename Id, typename... Parameters, typename ReturnType, class Registry>
|
||||
template<class Error>
|
||||
auto method<Id, ReturnType(Parameters...), Registry>::check_static_offset(
|
||||
std::size_t actual, std::size_t expected) const -> void {
|
||||
using namespace detail;
|
||||
|
||||
if constexpr (Registry::has_error_handler) {
|
||||
if (actual != expected) {
|
||||
Error error;
|
||||
error.method = Registry::rtti::template static_type<method>();
|
||||
error.expected = this->slots_strides[0];
|
||||
error.actual = actual;
|
||||
Registry::error_handler::error(error);
|
||||
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// method dispatch
|
||||
|
||||
@@ -2414,7 +2413,7 @@ BOOST_FORCEINLINE
|
||||
const ArgType&... args) const {
|
||||
using namespace detail;
|
||||
|
||||
Registry::check_initialized();
|
||||
Registry::require_initialized();
|
||||
|
||||
void (*pf)();
|
||||
|
||||
@@ -2455,16 +2454,7 @@ method<Id, ReturnType(Parameters...), Registry>::resolve_uni(
|
||||
|
||||
if constexpr (is_virtual<mp_first<MethodArgList>>::value) {
|
||||
vptr_type vtbl = vptr<ArgType>(arg);
|
||||
|
||||
if constexpr (has_static_offsets<method>::value) {
|
||||
if constexpr (Registry::has_runtime_checks) {
|
||||
check_static_offset<static_slot_error>(
|
||||
static_offsets<method>::slots[0], this->slots_strides[0]);
|
||||
}
|
||||
return vtbl[static_offsets<method>::slots[0]];
|
||||
} else {
|
||||
return vtbl[this->slots_strides[0]];
|
||||
}
|
||||
return vtbl[this->slots_strides[0]];
|
||||
} else {
|
||||
return resolve_uni<mp_rest<MethodArgList>>(more_args...);
|
||||
}
|
||||
@@ -2483,17 +2473,7 @@ method<Id, ReturnType(Parameters...), Registry>::resolve_multi_first(
|
||||
|
||||
if constexpr (is_virtual<mp_first<MethodArgList>>::value) {
|
||||
vptr_type vtbl = vptr<ArgType>(arg);
|
||||
std::size_t slot;
|
||||
|
||||
if constexpr (has_static_offsets<method>::value) {
|
||||
slot = static_offsets<method>::slots[0];
|
||||
if constexpr (Registry::has_runtime_checks) {
|
||||
check_static_offset<static_slot_error>(
|
||||
static_offsets<method>::slots[0], this->slots_strides[0]);
|
||||
}
|
||||
} else {
|
||||
slot = this->slots_strides[0];
|
||||
}
|
||||
std::size_t slot = this->slots_strides[0];
|
||||
|
||||
// The first virtual parameter is special. Since its stride is
|
||||
// 1, there is no need to store it. Also, the method table
|
||||
@@ -2523,23 +2503,8 @@ method<Id, ReturnType(Parameters...), Registry>::resolve_multi_next(
|
||||
|
||||
if constexpr (is_virtual<mp_first<MethodArgList>>::value) {
|
||||
vptr_type vtbl = vptr<ArgType>(arg);
|
||||
std::size_t slot, stride;
|
||||
|
||||
if constexpr (has_static_offsets<method>::value) {
|
||||
slot = static_offsets<method>::slots[VirtualArg];
|
||||
stride = static_offsets<method>::strides[VirtualArg - 1];
|
||||
|
||||
if constexpr (Registry::has_runtime_checks) {
|
||||
check_static_offset<static_slot_error>(
|
||||
this->slots_strides[VirtualArg], slot);
|
||||
check_static_offset<static_stride_error>(
|
||||
this->slots_strides[2 * VirtualArg], stride);
|
||||
}
|
||||
} else {
|
||||
slot = this->slots_strides[VirtualArg];
|
||||
stride = this->slots_strides[Arity + VirtualArg - 1];
|
||||
}
|
||||
|
||||
std::size_t slot = this->slots_strides[VirtualArg];
|
||||
std::size_t stride = this->slots_strides[Arity + VirtualArg - 1];
|
||||
dispatch = dispatch + vtbl[slot].i * stride;
|
||||
}
|
||||
|
||||
@@ -2564,10 +2529,8 @@ method<Id, ReturnType(Parameters...), Registry>::has_next() -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
if constexpr (!Registry::has_n2216) {
|
||||
if (next<Fn> == fn_ambiguous) {
|
||||
return false;
|
||||
}
|
||||
if (next<Fn> == fn_ambiguous) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -2581,8 +2544,8 @@ method<Id, ReturnType(Parameters...), Registry>::fn_not_implemented(
|
||||
using namespace policies;
|
||||
|
||||
if constexpr (Registry::has_error_handler) {
|
||||
not_implemented_error error;
|
||||
detail::init_call_error<method, rtti, 0u>::fn(
|
||||
no_overrider error;
|
||||
detail::init_bad_call<method, rtti, 0u>::fn(
|
||||
error,
|
||||
detail::parameter_traits<Parameters, Registry>::peek(args)...);
|
||||
Registry::error_handler::error(error);
|
||||
@@ -2599,8 +2562,8 @@ method<Id, ReturnType(Parameters...), Registry>::fn_ambiguous(
|
||||
using namespace policies;
|
||||
|
||||
if constexpr (Registry::has_error_handler) {
|
||||
ambiguous_error error;
|
||||
detail::init_call_error<method, rtti, 0u>::fn(
|
||||
ambiguous_call error;
|
||||
detail::init_bad_call<method, rtti, 0u>::fn(
|
||||
error,
|
||||
detail::parameter_traits<Parameters, Registry>::peek(args)...);
|
||||
Registry::error_handler::error(error);
|
||||
@@ -2767,7 +2730,7 @@ void method<Id, ReturnType(Parameters...), Registry>::override_impl<
|
||||
this->vp_type_ids);
|
||||
}
|
||||
|
||||
//! Contains aliases for the most frequently used types in the library
|
||||
//! Aliases for the most frequently used types in the library.
|
||||
namespace aliases {
|
||||
|
||||
using boost::openmethod::final_virtual_ptr;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#ifndef BOOST_OPENMETHOD_DEFAULT_REGISTRY_HPP
|
||||
#define BOOST_OPENMETHOD_DEFAULT_REGISTRY_HPP
|
||||
|
||||
#include <boost/openmethod/registry.hpp>
|
||||
#include <boost/openmethod/preamble.hpp>
|
||||
#include <boost/openmethod/policies/std_rtti.hpp>
|
||||
#include <boost/openmethod/policies/vptr_vector.hpp>
|
||||
#include <boost/openmethod/policies/stderr_output.hpp>
|
||||
@@ -15,33 +15,44 @@
|
||||
|
||||
namespace boost::openmethod {
|
||||
|
||||
struct release_registry
|
||||
//! Default registry.
|
||||
//!
|
||||
//! `default_registry` is a predefined @ref registry, and the default value of
|
||||
//! [BOOST_OPENMETHOD_DEFAULT_REGISTRY](../BOOST_OPENMETHOD_DEFAULT_REGISTRY.html).
|
||||
//! It contains the following policies:
|
||||
//! @li @ref policies::std_rtti: Use standard RTTI.
|
||||
//! @li @ref policies::fast_perfect_hash: Use a fast perfect hash function to
|
||||
//! map type ids to indices.
|
||||
//! @li @ref policies::vptr_vector: Store v-table pointers in a `std::vector`.
|
||||
//! @li @ref policies::default_error_handler: Write short diagnostic messages.
|
||||
//! @li @ref policies::stderr_output: Write messages to `stderr`.
|
||||
//!
|
||||
//! If
|
||||
//! [BOOST_OPENMETHOD_ENABLE_RUNTIME_CHECKS](../BOOST_OPENMETHOD_ENABLE_RUNTIME_CHECKS.html)
|
||||
//! is defined, `default_registry` also includes the @ref runtime_checks policy.
|
||||
//!
|
||||
//! @note Use `BOOST_OPENMETHOD_ENABLE_RUNTIME_CHECKS` with caution, as
|
||||
//! inconsistent use of the macro can cause ODR violations. If defined, it must
|
||||
//! be in all the translation units in the program that use `default_registry`,
|
||||
//! including those pulled from libraries.
|
||||
|
||||
struct default_registry
|
||||
: registry<
|
||||
policies::std_rtti, policies::fast_perfect_hash,
|
||||
policies::vptr_vector, policies::default_error_handler,
|
||||
policies::stderr_output> {};
|
||||
|
||||
//! Registry with runtime checks and trace enabled
|
||||
//!
|
||||
//! `debug_registry` uses the same policies as @ref release_registry, with the
|
||||
//! additional policies of @ref policies::runtime_checks and @ref
|
||||
//! policies::trace.
|
||||
//!
|
||||
//! This is the default value of
|
||||
//! [BOOST_OPENMETHOD_DEFAULT_REGISTRY](../BOOST_OPENMETHOD_DEFAULT_REGISTRY.html)
|
||||
//! when NDEBUG is not defined.
|
||||
//!
|
||||
//! `debug_registry` is derived from `release_registry::with<...>`, instead of
|
||||
//! being aliased, to avoid creating long symbol names wherever it is used. Its
|
||||
//! state is entirely distinct from `release_registry`\'s.
|
||||
struct debug_registry
|
||||
: release_registry::with<policies::runtime_checks, policies::trace> {};
|
||||
|
||||
#ifdef NDEBUG
|
||||
using default_registry = release_registry;
|
||||
#else
|
||||
using default_registry = debug_registry;
|
||||
policies::stderr_output
|
||||
#ifdef BOOST_OPENMETHOD_ENABLE_RUNTIME_CHECKS
|
||||
,
|
||||
policies::runtime_checks
|
||||
#endif
|
||||
> {
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
static odr_check<default_registry> default_registry_odr_check_instance;
|
||||
|
||||
}
|
||||
|
||||
} // namespace boost::openmethod
|
||||
|
||||
|
||||
@@ -1,155 +0,0 @@
|
||||
// Copyright (c) 2018-2025 Jean-Louis Leroy
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See accompanying file LICENSE_1_0.txt
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_OPENMETHOD_DETAIL_TRACE_HPP
|
||||
#define BOOST_OPENMETHOD_DETAIL_TRACE_HPP
|
||||
|
||||
#include <boost/openmethod/registry.hpp>
|
||||
|
||||
#include <boost/dynamic_bitset.hpp>
|
||||
|
||||
namespace boost::openmethod {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<typename Iterator>
|
||||
struct range;
|
||||
|
||||
struct rflush {
|
||||
std::size_t width;
|
||||
std::size_t value;
|
||||
explicit rflush(std::size_t width, std::size_t value)
|
||||
: width(width), value(value) {
|
||||
}
|
||||
};
|
||||
|
||||
struct type_name {
|
||||
type_name(type_id type) : type(type) {
|
||||
}
|
||||
type_id type;
|
||||
};
|
||||
|
||||
template<class Registry>
|
||||
struct trace_type {
|
||||
std::size_t indentation_level{0};
|
||||
|
||||
auto operator++() -> trace_type& {
|
||||
if constexpr (Registry::has_trace) {
|
||||
if (Registry::trace::on) {
|
||||
for (std::size_t i = 0; i < indentation_level; ++i) {
|
||||
Registry::output::os << " ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
struct indent {
|
||||
trace_type& trace;
|
||||
int by;
|
||||
|
||||
explicit indent(trace_type& trace, int by = 2) : trace(trace), by(by) {
|
||||
trace.indentation_level += by;
|
||||
}
|
||||
|
||||
~indent() {
|
||||
trace.indentation_level -= by;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
template<class Registry, typename T, typename F>
|
||||
auto write_range(trace_type<Registry>& trace, range<T> range, F fn) -> auto& {
|
||||
if constexpr (Registry::has_trace) {
|
||||
if (Registry::trace::on) {
|
||||
trace << "(";
|
||||
const char* sep = "";
|
||||
for (auto value : range) {
|
||||
trace << sep << fn(value);
|
||||
sep = ", ";
|
||||
}
|
||||
|
||||
trace << ")";
|
||||
}
|
||||
}
|
||||
|
||||
return trace;
|
||||
}
|
||||
|
||||
template<class Registry, typename T>
|
||||
auto operator<<(trace_type<Registry>& trace, const T& value) -> auto& {
|
||||
if constexpr (Registry::has_trace) {
|
||||
if (Registry::trace::on) {
|
||||
Registry::output::os << value;
|
||||
}
|
||||
}
|
||||
return trace;
|
||||
}
|
||||
|
||||
template<class Registry>
|
||||
auto operator<<(trace_type<Registry>& trace, const rflush& rf) -> auto& {
|
||||
if constexpr (Registry::has_trace) {
|
||||
if (Registry::trace::on) {
|
||||
std::size_t digits = 1;
|
||||
auto tmp = rf.value / 10;
|
||||
|
||||
while (tmp) {
|
||||
++digits;
|
||||
tmp /= 10;
|
||||
}
|
||||
|
||||
while (digits < rf.width) {
|
||||
trace << " ";
|
||||
++digits;
|
||||
}
|
||||
|
||||
trace << rf.value;
|
||||
}
|
||||
}
|
||||
|
||||
return trace;
|
||||
}
|
||||
|
||||
template<class Registry>
|
||||
auto operator<<(
|
||||
trace_type<Registry>& trace, const boost::dynamic_bitset<>& bits) -> auto& {
|
||||
if constexpr (Registry::has_trace) {
|
||||
if (Registry::trace::on) {
|
||||
auto i = bits.size();
|
||||
while (i != 0) {
|
||||
--i;
|
||||
Registry::output::os << bits[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return trace;
|
||||
}
|
||||
|
||||
template<class Registry>
|
||||
auto operator<<(trace_type<Registry>& trace, const range<type_id*>& tips)
|
||||
-> auto& {
|
||||
return write_range(trace, tips, [](auto tip) { return type_name(tip); });
|
||||
}
|
||||
|
||||
template<class Registry, typename T>
|
||||
auto operator<<(trace_type<Registry>& trace, const range<T>& range) -> auto& {
|
||||
return write_range(trace, range, [](auto value) { return value; });
|
||||
}
|
||||
|
||||
template<class Registry>
|
||||
auto operator<<(trace_type<Registry>& trace, const type_name& manip) -> auto& {
|
||||
if constexpr (Registry::has_trace) {
|
||||
Registry::rtti::type_name(manip.type, trace);
|
||||
}
|
||||
|
||||
return trace;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace boost::openmethod
|
||||
|
||||
#endif // BOOST_OPENMETHOD_DETAIL_HPP
|
||||
@@ -1,281 +0,0 @@
|
||||
// Copyright (c) 2018-2025 Jean-Louis Leroy
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See accompanying file LICENSE_1_0.txt
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_OPENMETHOD_DETAIL_TYPES_HPP
|
||||
#define BOOST_OPENMETHOD_DETAIL_TYPES_HPP
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <boost/openmethod/detail/static_list.hpp>
|
||||
|
||||
#if BOOST_CXX_VERSION >= 202002L
|
||||
#define BOOST_OPENMETHOD_DETAIL_CXX17(...)
|
||||
#define BOOST_OPENMETHOD_DETAIL_CXX20(...) __VA_ARGS__
|
||||
#else
|
||||
#define BOOST_OPENMETHOD_DETAIL_CXX17(...) __VA_ARGS__
|
||||
#define BOOST_OPENMETHOD_DETAIL_CXX20(...)
|
||||
#endif
|
||||
|
||||
namespace boost::openmethod {
|
||||
|
||||
namespace detail {
|
||||
|
||||
union word {
|
||||
word() {
|
||||
} // undefined
|
||||
word(void (*pf)()) : pf(pf) {
|
||||
}
|
||||
word(word* pw) : pw(pw) {
|
||||
}
|
||||
word(std::size_t i) : i(i) {
|
||||
}
|
||||
|
||||
void (*pf)();
|
||||
std::size_t i;
|
||||
word* pw;
|
||||
};
|
||||
|
||||
#if defined(UINTPTR_MAX)
|
||||
using uintptr = std::uintptr_t;
|
||||
constexpr uintptr uintptr_max = UINTPTR_MAX;
|
||||
#else
|
||||
static_assert(
|
||||
sizeof(std::size_t) == sizeof(void*),
|
||||
"This implementation requires that size_t and void* have the same size.");
|
||||
using uintptr = std::size_t;
|
||||
constexpr uintptr uintptr_max = (std::numeric_limits<std::size_t>::max)();
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
|
||||
using vptr_type = const detail::word*;
|
||||
|
||||
using type_id = const void*;
|
||||
|
||||
template<typename T>
|
||||
struct virtual_;
|
||||
|
||||
template<typename T, class Registry>
|
||||
struct virtual_traits;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Error handling
|
||||
|
||||
struct openmethod_error {};
|
||||
|
||||
//! Registry not initialized
|
||||
struct not_initialized_error : openmethod_error {
|
||||
//! Write a short description to an output stream
|
||||
//! @param os The output stream
|
||||
//! @tparam Registry The registry
|
||||
//! @tparam Stream A @ref LightweightOutputStream
|
||||
template<class Registry, class Stream>
|
||||
auto write(Stream& os) const -> void {
|
||||
os << "not initialized";
|
||||
}
|
||||
};
|
||||
|
||||
//! Unknown class
|
||||
struct unknown_class_error : openmethod_error {
|
||||
//! The type_id of the unknown class.
|
||||
type_id type;
|
||||
|
||||
//! Write a short description to an output stream
|
||||
//! @param os The output stream
|
||||
//! @tparam Registry The registry
|
||||
//! @tparam Stream A @ref LightweightOutputStream
|
||||
template<class Registry, class Stream>
|
||||
auto write(Stream& os) const -> void;
|
||||
};
|
||||
|
||||
//! Cannot find hash factors
|
||||
struct fast_perfect_hash_error : openmethod_error {
|
||||
//! Number of attempts to find hash factors
|
||||
std::size_t attempts;
|
||||
//! Number of buckets used in the last attempt
|
||||
std::size_t buckets;
|
||||
|
||||
//! Write a short description to an output stream
|
||||
//! @param os The output stream
|
||||
//! @tparam Registry The registry
|
||||
//! @tparam Stream A @ref LightweightOutputStream
|
||||
template<class Registry, class Stream>
|
||||
auto write(Stream& os) const -> void;
|
||||
};
|
||||
|
||||
//! No valid overrider
|
||||
struct call_error : openmethod_error {
|
||||
//! The type_id of method that was called
|
||||
type_id method;
|
||||
//! The number of @em virtual arguments in the call
|
||||
std::size_t arity;
|
||||
//! The maximum size of `types`
|
||||
static constexpr std::size_t max_types = 16;
|
||||
//! The type_ids of the arguments.
|
||||
type_id types[max_types];
|
||||
|
||||
protected:
|
||||
template<class Registry, class Stream>
|
||||
auto write_aux(Stream& os, const char* subtype) const -> void;
|
||||
};
|
||||
|
||||
//! No overrider for virtual tuple
|
||||
//!
|
||||
//! @see @ref call_error for data members.
|
||||
struct not_implemented_error : call_error {
|
||||
//! Write a short description to an output stream
|
||||
//! @param os The output stream
|
||||
//! @tparam Registry The registry
|
||||
//! @tparam Stream A @ref LightweightOutputStream
|
||||
template<class Registry, class Stream>
|
||||
auto write(Stream& os) const -> void {
|
||||
write_aux<Registry>(os, "not implemented");
|
||||
}
|
||||
};
|
||||
|
||||
//! Ambiguous call
|
||||
//!
|
||||
//! @see @ref call_error for data members.
|
||||
struct ambiguous_error : call_error {
|
||||
//! Write a short description to an output stream
|
||||
//! @param os The output stream
|
||||
//! @tparam Registry The registry
|
||||
//! @tparam Stream A @ref LightweightOutputStream
|
||||
template<class Registry, class Stream>
|
||||
auto write(Stream& os) const -> void {
|
||||
write_aux<Registry>(os, "ambiguous");
|
||||
}
|
||||
};
|
||||
|
||||
//! Static and dynamic type mismatch in "final" construct
|
||||
//!
|
||||
//! If runtime checks are enabled, the "final" construct checks that the static
|
||||
//! and dynamic types of the object, as reported by the `rtti` policy, are the
|
||||
//! same. If they are not, and if the registry contains an @ref error_handler
|
||||
//! policy, its @ref error function is called with a `final_error` object, then
|
||||
//! the program is terminated with
|
||||
//! @ref abort.
|
||||
struct final_error : openmethod_error {
|
||||
type_id static_type, dynamic_type;
|
||||
|
||||
//! Write a short description to an output stream
|
||||
//! @param os The output stream
|
||||
//! @tparam Registry The registry
|
||||
//! @tparam Stream A @ref LightweightOutputStream
|
||||
template<class Registry, class Stream>
|
||||
auto write(Stream& os) const -> void;
|
||||
};
|
||||
|
||||
//! For future use
|
||||
struct static_offset_error : openmethod_error {
|
||||
type_id method;
|
||||
int actual, expected;
|
||||
|
||||
//! Write a short description to an output stream
|
||||
//! @param os The output stream
|
||||
//! @tparam Registry The registry
|
||||
//! @tparam Stream A @ref LightweightOutputStream
|
||||
template<class Registry, class Stream>
|
||||
auto write(Stream& os) const -> void;
|
||||
};
|
||||
|
||||
//! For future use
|
||||
struct static_slot_error : static_offset_error {};
|
||||
|
||||
//! For future use
|
||||
struct static_stride_error : static_offset_error {};
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct empty {};
|
||||
|
||||
template<typename Iterator>
|
||||
struct range {
|
||||
range(Iterator first, Iterator last) : first(first), last(last) {
|
||||
}
|
||||
|
||||
Iterator first, last;
|
||||
|
||||
auto begin() const -> Iterator {
|
||||
return first;
|
||||
}
|
||||
|
||||
auto end() const -> Iterator {
|
||||
return last;
|
||||
}
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// class info
|
||||
|
||||
struct class_info : static_list<class_info>::static_link {
|
||||
type_id type;
|
||||
vptr_type* static_vptr;
|
||||
type_id *first_base, *last_base;
|
||||
bool is_abstract{false};
|
||||
|
||||
auto vptr() const {
|
||||
return static_vptr;
|
||||
}
|
||||
|
||||
auto type_id_begin() const {
|
||||
return &type;
|
||||
}
|
||||
|
||||
auto type_id_end() const {
|
||||
return &type + 1;
|
||||
}
|
||||
};
|
||||
|
||||
struct deferred_class_info : class_info {
|
||||
virtual void resolve_type_ids() = 0;
|
||||
};
|
||||
|
||||
// -----------
|
||||
// method info
|
||||
|
||||
struct overrider_info;
|
||||
|
||||
struct method_info : static_list<method_info>::static_link {
|
||||
type_id* vp_begin;
|
||||
type_id* vp_end;
|
||||
static_list<overrider_info> specs;
|
||||
void (*not_implemented)();
|
||||
void (*ambiguous)();
|
||||
type_id method_type_id;
|
||||
type_id return_type_id;
|
||||
std::size_t* slots_strides_ptr;
|
||||
|
||||
auto arity() const {
|
||||
return std::distance(vp_begin, vp_end);
|
||||
}
|
||||
};
|
||||
|
||||
struct deferred_method_info : method_info {
|
||||
virtual void resolve_type_ids() = 0;
|
||||
};
|
||||
|
||||
struct overrider_info : static_list<overrider_info>::static_link {
|
||||
~overrider_info() {
|
||||
method->specs.remove(*this);
|
||||
}
|
||||
|
||||
method_info* method; // for the destructor, to remove definition
|
||||
type_id return_type; // for N2216 disambiguation
|
||||
type_id type; // of the function, for trace
|
||||
void (**next)();
|
||||
type_id *vp_begin, *vp_end;
|
||||
void (*pf)();
|
||||
};
|
||||
|
||||
struct deferred_overrider_info : overrider_info {
|
||||
virtual void resolve_type_ids() = 0;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace boost::openmethod
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,18 +21,18 @@ template<class>
|
||||
struct update_vptr_bases;
|
||||
|
||||
template<class To, class Class>
|
||||
void update_vptr(Class* obj);
|
||||
void boost_openmethod_update_vptr(Class* obj);
|
||||
|
||||
template<class... Bases>
|
||||
struct update_vptr_bases<mp11::mp_list<Bases...>> {
|
||||
template<class To, class Class>
|
||||
static void fn(Class* obj) {
|
||||
(update_vptr<To>(static_cast<Bases*>(obj)), ...);
|
||||
(boost_openmethod_update_vptr<To>(static_cast<Bases*>(obj)), ...);
|
||||
}
|
||||
};
|
||||
|
||||
template<class To, class Class>
|
||||
void update_vptr(Class* obj) {
|
||||
void boost_openmethod_update_vptr(Class* obj) {
|
||||
using registry = inplace_vptr_registry<Class>;
|
||||
using bases = decltype(boost_openmethod_bases(obj));
|
||||
|
||||
@@ -47,11 +47,6 @@ void update_vptr(Class* obj) {
|
||||
}
|
||||
}
|
||||
|
||||
struct inplace_vptr_derived {};
|
||||
|
||||
template<class, class, bool>
|
||||
class inplace_vptr_aux;
|
||||
|
||||
#if defined(__GNUC__) && !defined(__clang__)
|
||||
#pragma GCC diagnostic ignored "-Wnon-template-friend"
|
||||
#endif
|
||||
@@ -59,25 +54,87 @@ class inplace_vptr_aux;
|
||||
template<class... Classes>
|
||||
inline use_classes<Classes...> inplace_vptr_use_classes;
|
||||
|
||||
template<class Class, class Registry>
|
||||
class inplace_vptr_aux<Class, Registry, true> {
|
||||
protected:
|
||||
class inplace_vptr_base_tag {};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
//! Embed a v-table pointer in a class.
|
||||
//!
|
||||
//! `inplace_vptr_base` is a [mixin](https://en.wikipedia.org/wiki/Mixin) that
|
||||
//! embeds a v-table pointer at the root of a class hierarchy. It also declares
|
||||
//! a @ref boost_openmethod_vptr free function that returns the v-table pointer
|
||||
//! stored in the object.
|
||||
//!
|
||||
//! `inplace_vptr_base` registers the class in `Registry`. It is not necessary
|
||||
//! to register the class with @ref use_class or
|
||||
//! [BOOST_OPENMETHOD_REGISTER](../BOOST_OPENMETHOD_REGISTER.html)
|
||||
//!
|
||||
//! The v-table pointer is obtained directly from the `Registry`\'s @ref
|
||||
//! static_vptr variable. No hashing is involved. If all the classes in
|
||||
//! `Registry` inherit from `inplace_vptr_base`, the registry needs not have a
|
||||
//! @ref policies::vptr policy, nor any policy it depends on (like @ref
|
||||
//! policies::type_hash).
|
||||
//!
|
||||
//! If `Registry` contains the @ref has_indirect_vptr policy, the v-table
|
||||
//! pointer is stored as a pointer to a pointer, and remains valid after a call
|
||||
//! to @ref initialize.
|
||||
//!
|
||||
//! The default value of `Registry` can be changed by defining
|
||||
//! [BOOST_OPENMETHOD_DEFAULT_REGISTRY](../BOOST_OPENMETHOD_DEFAULT_REGISTRY.html)
|
||||
//!
|
||||
//! @tparam Class The class in which to embed the v-table pointer.
|
||||
//! @tparam Registry The @ref registry in which `Class` and its derived classes
|
||||
//! are registered.
|
||||
//!
|
||||
//! @par Example
|
||||
//! @code
|
||||
//! #include <boost/openmethod.hpp>
|
||||
//! #include <boost/openmethod/inplace_vptr.hpp>
|
||||
//! #include <boost/openmethod/initialize.hpp>
|
||||
//!
|
||||
//! using namespace boost::openmethod;
|
||||
//!
|
||||
//! struct Animal : inplace_vptr_base<Animal> {};
|
||||
//!
|
||||
//! struct Cat : Animal, inplace_vptr_derived<Cat, Animal> {};
|
||||
//!
|
||||
//! struct Dog : Animal, inplace_vptr_derived<Dog, Animal> {};
|
||||
//!
|
||||
//! BOOST_OPENMETHOD(
|
||||
//! poke, (virtual_<Animal&> animal, std::ostream& os), void);
|
||||
//!
|
||||
//! BOOST_OPENMETHOD_OVERRIDE(poke, (Cat&, std::ostream& os), void) {
|
||||
//! os << "hiss\n";
|
||||
//! }
|
||||
//!
|
||||
//! BOOST_OPENMETHOD_OVERRIDE(poke, (Dog&, std::ostream& os), void) {
|
||||
//! os << "bark\n";
|
||||
//! }
|
||||
//!
|
||||
//! int main() {
|
||||
//! initialize();
|
||||
//!
|
||||
//! std::unique_ptr<Animal> a = std::make_unique<Cat>();
|
||||
//! std::unique_ptr<Animal> b = std::make_unique<Dog>();
|
||||
//!
|
||||
//! poke(*a, std::cout); // hiss
|
||||
//! poke(*b, std::cout); // bark
|
||||
//!
|
||||
//! return 0;
|
||||
//! }
|
||||
//! @endcode
|
||||
template<class Class, class Registry = BOOST_OPENMETHOD_DEFAULT_REGISTRY>
|
||||
class inplace_vptr_base : protected detail::inplace_vptr_base_tag {
|
||||
template<class To, class Other>
|
||||
friend void update_vptr(Other*);
|
||||
friend void detail::boost_openmethod_update_vptr(Other*);
|
||||
friend auto boost_openmethod_registry(Class*) -> Registry;
|
||||
friend auto boost_openmethod_bases(Class*) -> mp11::mp_list<>;
|
||||
|
||||
inplace_vptr_aux() {
|
||||
(void)&inplace_vptr_use_classes<Class, Registry>;
|
||||
detail::update_vptr<Class>(static_cast<Class*>(this));
|
||||
}
|
||||
|
||||
~inplace_vptr_aux() {
|
||||
std::conditional_t<Registry::has_indirect_vptr, const vptr_type*, vptr_type>
|
||||
boost_openmethod_vptr = nullptr;
|
||||
}
|
||||
|
||||
friend auto
|
||||
boost_openmethod_vptr(const Class& obj, Registry*) -> vptr_type {
|
||||
boost_openmethod_vptr(const Class& obj, Registry*) noexcept -> vptr_type {
|
||||
if constexpr (Registry::has_indirect_vptr) {
|
||||
return *obj.boost_openmethod_vptr;
|
||||
} else {
|
||||
@@ -85,69 +142,103 @@ class inplace_vptr_aux<Class, Registry, true> {
|
||||
}
|
||||
}
|
||||
|
||||
friend auto boost_openmethod_registry(Class*) -> Registry;
|
||||
|
||||
std::conditional_t<Registry::has_indirect_vptr, const vptr_type*, vptr_type>
|
||||
boost_openmethod_vptr = nullptr;
|
||||
};
|
||||
|
||||
template<class Class, class Base>
|
||||
class inplace_vptr_aux<Class, Base, false> : inplace_vptr_derived {
|
||||
protected:
|
||||
friend void update_vptr(Class*);
|
||||
|
||||
inplace_vptr_aux() {
|
||||
(void)&inplace_vptr_use_classes<
|
||||
Class, Base, inplace_vptr_registry<Class>>;
|
||||
detail::update_vptr<Class>(static_cast<Class*>(this));
|
||||
//! Set the vptr to `Class`\'s v-table.
|
||||
inplace_vptr_base() noexcept {
|
||||
(void)&detail::inplace_vptr_use_classes<Class, Registry>;
|
||||
detail::boost_openmethod_update_vptr<Class>(static_cast<Class*>(this));
|
||||
}
|
||||
|
||||
~inplace_vptr_aux() {
|
||||
detail::update_vptr<Base>(
|
||||
//! Set the vptr to `nullptr`.
|
||||
~inplace_vptr_base() noexcept {
|
||||
boost_openmethod_vptr = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef __MRDOCS__
|
||||
//! Adjust the v-table pointer embedded in a class.
|
||||
//!
|
||||
//! `inplace_vptr_derived` is a [mixin](https://en.wikipedia.org/wiki/Mixin)
|
||||
//! that adjusts the v-table pointer in a @ref inplace_vptr_base. It can be used
|
||||
//! only with classes that have @ref inplace_vptr_base as a direct or indirect
|
||||
//! base class.
|
||||
//!
|
||||
//! `inplace_vptr_derived` registers the class and its bases in `Registry`. It
|
||||
//! is not necessary to register them with @ref use_class or
|
||||
//! [BOOST_OPENMETHOD_REGISTER](../BOOST_OPENMETHOD_REGISTER.html)
|
||||
//!
|
||||
//! The v-table pointer is obtained directly from the `Registry`\'s @ref
|
||||
//! static_vptr variable. No hashing is involved. If all the classes in
|
||||
//! `Registry` inherit from `inplace_vptr_derived`, the registry needs not have a
|
||||
//! @ref policies::vptr policy, nor any policy it depends on (like @ref
|
||||
//! policies::type_hash).
|
||||
//!
|
||||
//! @see @ref inplace_vptr_base for an example.
|
||||
//!
|
||||
//! @tparam Class The class in which to embed the v-table pointer.
|
||||
//! @tparam Base A direct base class of `Class`.
|
||||
//! @tparam MoreBases More direct base classes of `Class`.
|
||||
template<class Class, class Base, class... MoreBases>
|
||||
class inplace_vptr_derived {
|
||||
protected:
|
||||
//! Set the vptr to `Class`\'s v-table.
|
||||
inplace_vptr_derived() noexcept;
|
||||
|
||||
//! Set the vptr in each base class.
|
||||
//!
|
||||
//! For each base, set its vptr to the base's v-table.
|
||||
~inplace_vptr_derived() noexcept;
|
||||
};
|
||||
|
||||
#else
|
||||
template<class Class, class Base, class... MoreBases>
|
||||
class inplace_vptr_derived;
|
||||
#endif
|
||||
|
||||
//! Specialization for a single base class.
|
||||
//!
|
||||
//!
|
||||
//! @see The main template for documentation.
|
||||
template<class Class, class Base>
|
||||
class inplace_vptr_derived<Class, Base> {
|
||||
static_assert(
|
||||
!detail::is_registry<Base>,
|
||||
"registry can be specified only for root classes");
|
||||
|
||||
static_assert(
|
||||
std::is_base_of_v<detail::inplace_vptr_base_tag, Base>,
|
||||
"class must inherit from inplace_vptr_base");
|
||||
|
||||
template<class To, class Other>
|
||||
friend void detail::boost_openmethod_update_vptr(Other*);
|
||||
friend auto boost_openmethod_bases(Class*) -> mp11::mp_list<Base>;
|
||||
|
||||
protected:
|
||||
//! Set the vptr to `Class`\'s v-table.
|
||||
inplace_vptr_derived() noexcept {
|
||||
using namespace detail;
|
||||
(void)&detail::inplace_vptr_use_classes<
|
||||
Class, Base, detail::inplace_vptr_registry<Class>>;
|
||||
boost_openmethod_update_vptr<Class>(static_cast<Class*>(this));
|
||||
}
|
||||
|
||||
//! Set the vptr in base class.
|
||||
~inplace_vptr_derived() noexcept {
|
||||
detail::boost_openmethod_update_vptr<Base>(
|
||||
static_cast<Base*>(static_cast<Class*>(this)));
|
||||
}
|
||||
|
||||
friend auto boost_openmethod_bases(Class*) -> mp11::mp_list<Base>;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename...>
|
||||
struct inplace_vptr;
|
||||
|
||||
template<class Class>
|
||||
struct inplace_vptr<Class>
|
||||
: detail::inplace_vptr_aux<Class, BOOST_OPENMETHOD_DEFAULT_REGISTRY, true> {
|
||||
};
|
||||
|
||||
template<class Class, class Other>
|
||||
struct inplace_vptr<Class, Other>
|
||||
: detail::inplace_vptr_aux<Class, Other, detail::is_registry<Other>> {};
|
||||
|
||||
//! Specialization for multiple base classes.
|
||||
//!
|
||||
//! @see The main template for documentation.
|
||||
template<class Class, class Base1, class Base2, class... MoreBases>
|
||||
struct inplace_vptr<Class, Base1, Base2, MoreBases...>
|
||||
: detail::inplace_vptr_derived {
|
||||
|
||||
class inplace_vptr_derived<Class, Base1, Base2, MoreBases...> {
|
||||
static_assert(
|
||||
!detail::is_registry<Base1> && !detail::is_registry<Base2> &&
|
||||
(!detail::is_registry<MoreBases> && ...),
|
||||
"registry can be specified only for root classes");
|
||||
|
||||
protected:
|
||||
inplace_vptr() {
|
||||
(void)&detail::inplace_vptr_use_classes<
|
||||
Class, Base1, Base2, MoreBases...,
|
||||
detail::inplace_vptr_registry<Base1>>;
|
||||
detail::update_vptr<Class>(static_cast<Class*>(this));
|
||||
}
|
||||
|
||||
~inplace_vptr() {
|
||||
auto obj = static_cast<Class*>(this);
|
||||
detail::update_vptr<Base1>(static_cast<Base1*>(obj));
|
||||
detail::update_vptr<Base2>(static_cast<Base2*>(obj));
|
||||
(detail::update_vptr<MoreBases>(static_cast<Base2*>(obj)), ...);
|
||||
}
|
||||
|
||||
friend auto
|
||||
boost_openmethod_registry(Class*) -> detail::inplace_vptr_registry<Base1>;
|
||||
friend auto
|
||||
@@ -157,8 +248,34 @@ struct inplace_vptr<Class, Base1, Base2, MoreBases...>
|
||||
detail::inplace_vptr_registry<Base1>* registry) -> vptr_type {
|
||||
return boost_openmethod_vptr(static_cast<const Base1&>(obj), registry);
|
||||
}
|
||||
|
||||
protected:
|
||||
//! Set the vptr to `Class`\'s v-table.
|
||||
inplace_vptr_derived() noexcept {
|
||||
(void)&detail::inplace_vptr_use_classes<
|
||||
Class, Base1, Base2, MoreBases...,
|
||||
detail::inplace_vptr_registry<Base1>>;
|
||||
detail::boost_openmethod_update_vptr<Class>(static_cast<Class*>(this));
|
||||
}
|
||||
|
||||
//! Set the vptr in each base class.
|
||||
//!
|
||||
//! For each base, set its vptr to the base's v-table.
|
||||
~inplace_vptr_derived() noexcept {
|
||||
auto obj = static_cast<Class*>(this);
|
||||
detail::boost_openmethod_update_vptr<Base1>(static_cast<Base1*>(obj));
|
||||
detail::boost_openmethod_update_vptr<Base2>(static_cast<Base2*>(obj));
|
||||
(detail::boost_openmethod_update_vptr<MoreBases>(
|
||||
static_cast<MoreBases*>(obj)),
|
||||
...);
|
||||
}
|
||||
};
|
||||
|
||||
namespace aliases {
|
||||
using boost::openmethod::inplace_vptr_base;
|
||||
using boost::openmethod::inplace_vptr_derived;
|
||||
} // namespace aliases
|
||||
|
||||
} // namespace boost::openmethod
|
||||
|
||||
#endif // BOOST_OPENMETHOD_inplace_vptr_HPP
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
// See accompanying file LICENSE_1_0.txt
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_OPENMETHOD_SHARED_PTR_HPP
|
||||
#define BOOST_OPENMETHOD_SHARED_PTR_HPP
|
||||
#ifndef BOOST_OPENMETHOD_INTEROP_SHARED_PTR_HPP
|
||||
#define BOOST_OPENMETHOD_INTEROP_SHARED_PTR_HPP
|
||||
|
||||
#include <boost/openmethod/core.hpp>
|
||||
#include <memory>
|
||||
@@ -3,8 +3,8 @@
|
||||
// See accompanying file LICENSE_1_0.txt
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_OPENMETHOD_UNIQUE_PTR_HPP
|
||||
#define BOOST_OPENMETHOD_UNIQUE_PTR_HPP
|
||||
#ifndef BOOST_OPENMETHOD_INTEROP_UNIQUE_PTR_HPP
|
||||
#define BOOST_OPENMETHOD_INTEROP_UNIQUE_PTR_HPP
|
||||
|
||||
#include <boost/openmethod/core.hpp>
|
||||
|
||||
@@ -119,12 +119,7 @@ struct va_args<ReturnType> {
|
||||
BOOST_ASSERT(has_next()); \
|
||||
return boost_openmethod_detail_locate_method_aux< \
|
||||
void ARGS>::type::next<fn>(std::forward<Args>(args)...); \
|
||||
} \
|
||||
inline BOOST_OPENMETHOD_REGISTER( \
|
||||
BOOST_OPENMETHOD_OVERRIDERS(NAME) < __VA_ARGS__ ARGS > \
|
||||
::boost_openmethod_detail_locate_method_aux<void ARGS>::type:: \
|
||||
override< \
|
||||
BOOST_OPENMETHOD_OVERRIDERS(NAME) < __VA_ARGS__ ARGS>::fn >);
|
||||
}
|
||||
|
||||
#define BOOST_OPENMETHOD_OVERRIDER(NAME, ARGS, ...) \
|
||||
BOOST_OPENMETHOD_OVERRIDERS(NAME)<__VA_ARGS__ ARGS>
|
||||
@@ -135,10 +130,20 @@ struct va_args<ReturnType> {
|
||||
|
||||
#define BOOST_OPENMETHOD_INLINE_OVERRIDE(NAME, ARGS, ...) \
|
||||
BOOST_OPENMETHOD_DECLARE_OVERRIDER(NAME, ARGS, __VA_ARGS__) \
|
||||
inline BOOST_OPENMETHOD_REGISTER( \
|
||||
BOOST_OPENMETHOD_OVERRIDERS(NAME) < __VA_ARGS__ ARGS > \
|
||||
::boost_openmethod_detail_locate_method_aux<void ARGS>::type:: \
|
||||
override< \
|
||||
BOOST_OPENMETHOD_OVERRIDERS(NAME) < __VA_ARGS__ ARGS>::fn >); \
|
||||
inline BOOST_OPENMETHOD_DEFINE_OVERRIDER(NAME, ARGS, __VA_ARGS__)
|
||||
|
||||
#define BOOST_OPENMETHOD_OVERRIDE(NAME, ARGS, ...) \
|
||||
BOOST_OPENMETHOD_DECLARE_OVERRIDER(NAME, ARGS, __VA_ARGS__) \
|
||||
BOOST_OPENMETHOD_REGISTER( \
|
||||
BOOST_OPENMETHOD_OVERRIDERS(NAME) < __VA_ARGS__ ARGS > \
|
||||
::boost_openmethod_detail_locate_method_aux<void ARGS>::type:: \
|
||||
override< \
|
||||
BOOST_OPENMETHOD_OVERRIDERS(NAME) < __VA_ARGS__ ARGS>::fn >); \
|
||||
BOOST_OPENMETHOD_DEFINE_OVERRIDER(NAME, ARGS, __VA_ARGS__)
|
||||
|
||||
#define BOOST_OPENMETHOD_CLASSES(...) \
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#ifndef BOOST_OPENMETHOD_POLICY_VECTORED_ERROR_HPP
|
||||
#define BOOST_OPENMETHOD_POLICY_VECTORED_ERROR_HPP
|
||||
|
||||
#include <boost/openmethod/registry.hpp>
|
||||
#include <boost/openmethod/preamble.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <variant>
|
||||
@@ -32,22 +32,51 @@ namespace boost::openmethod::policies {
|
||||
//! enable exception throwing on a registry basis.
|
||||
|
||||
struct default_error_handler : error_handler {
|
||||
//! A @ref std::variant containing an instance of a subclass of @ref
|
||||
//! openmethod_error.
|
||||
using error_variant = std::variant<
|
||||
not_initialized_error, not_implemented_error, ambiguous_error,
|
||||
unknown_class_error, fast_perfect_hash_error, final_error,
|
||||
static_slot_error, static_stride_error>;
|
||||
|
||||
//! The type of the error handler function object.
|
||||
using function_type = std::function<void(const error_variant& error)>;
|
||||
|
||||
//! A model of @ref error_handler::fn.
|
||||
//!
|
||||
//! @tparam Registry The registry containing this policy.
|
||||
template<class Registry>
|
||||
class fn {
|
||||
template<typename, typename, typename>
|
||||
struct error_variant_aux;
|
||||
|
||||
template<
|
||||
typename T, class... Errors, class Policy, class... MorePolicies>
|
||||
struct error_variant_aux<
|
||||
T, std::variant<Errors...>, mp11::mp_list<Policy, MorePolicies...>>
|
||||
: error_variant_aux<
|
||||
void, std::variant<Errors...>,
|
||||
mp11::mp_list<MorePolicies...>> {};
|
||||
|
||||
template<class... Errors, class Policy, class... MorePolicies>
|
||||
struct error_variant_aux<
|
||||
std::void_t<typename Policy::errors>, std::variant<Errors...>,
|
||||
mp11::mp_list<Policy, MorePolicies...>>
|
||||
: error_variant_aux<
|
||||
void,
|
||||
mp11::mp_append<
|
||||
std::variant<Errors...>, typename Policy::errors>,
|
||||
mp11::mp_list<MorePolicies...>> {};
|
||||
|
||||
template<class... Errors>
|
||||
struct error_variant_aux<
|
||||
void, std::variant<Errors...>, mp11::mp_list<>> {
|
||||
using type = std::variant<Errors...>;
|
||||
};
|
||||
|
||||
public:
|
||||
//! A @ref std::variant containing an instance of a subclass of @ref
|
||||
//! openmethod_error.
|
||||
using error_variant = typename error_variant_aux<
|
||||
void,
|
||||
std::variant<
|
||||
not_initialized, no_overrider, ambiguous_call,
|
||||
missing_class, missing_base, odr_violation, final_error>,
|
||||
typename Registry::policy_list>::type;
|
||||
|
||||
//! The type of the error handler function object.
|
||||
using function_type = std::function<void(const error_variant& error)>;
|
||||
|
||||
//! Calls a function with the error object, wrapped in an @ref
|
||||
//! error_variant.
|
||||
//!
|
||||
@@ -96,7 +125,7 @@ struct default_error_handler : error_handler {
|
||||
};
|
||||
|
||||
template<class Registry>
|
||||
typename default_error_handler::function_type
|
||||
typename default_error_handler::fn<Registry>::function_type
|
||||
default_error_handler::fn<Registry>::handler = default_handler;
|
||||
|
||||
} // namespace boost::openmethod::policies
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#ifndef BOOST_OPENMETHOD_POLICY_FAST_PERFECT_HASH_HPP
|
||||
#define BOOST_OPENMETHOD_POLICY_FAST_PERFECT_HASH_HPP
|
||||
|
||||
#include <boost/openmethod/registry.hpp>
|
||||
#include <boost/openmethod/preamble.hpp>
|
||||
|
||||
#include <limits>
|
||||
#include <random>
|
||||
@@ -19,10 +19,21 @@ namespace boost::openmethod {
|
||||
|
||||
namespace detail {
|
||||
|
||||
#if defined(UINTPTR_MAX)
|
||||
using uintptr = std::uintptr_t;
|
||||
constexpr uintptr uintptr_max = UINTPTR_MAX;
|
||||
#else
|
||||
static_assert(
|
||||
sizeof(std::size_t) == sizeof(void*),
|
||||
"This implementation requires that size_t and void* have the same size.");
|
||||
using uintptr = std::size_t;
|
||||
constexpr uintptr uintptr_max = (std::numeric_limits<std::size_t>::max)();
|
||||
#endif
|
||||
|
||||
template<class Registry>
|
||||
std::vector<type_id> fast_perfect_hash_control;
|
||||
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
namespace policies {
|
||||
|
||||
@@ -39,6 +50,24 @@ namespace policies {
|
||||
//! range of integers. In other words, a lot of space may be wasted in presence
|
||||
//! of large sets of type_ids.
|
||||
struct fast_perfect_hash : type_hash {
|
||||
|
||||
//! Cannot find hash factors
|
||||
struct search_error : openmethod_error {
|
||||
//! Number of attempts to find hash factors
|
||||
std::size_t attempts;
|
||||
//! Number of buckets used in the last attempt
|
||||
std::size_t buckets;
|
||||
|
||||
//! Write a short description to an output stream
|
||||
//! @param os The output stream
|
||||
//! @tparam Registry The registry
|
||||
//! @tparam Stream A @ref LightweightOutputStream
|
||||
template<class Registry, class Stream>
|
||||
auto write(Stream& os) const -> void;
|
||||
};
|
||||
|
||||
using errors = std::variant<search_error>;
|
||||
|
||||
//! A model of @ref type_hash::fn.
|
||||
//!
|
||||
//! @tparam Registry The registry containing this policy
|
||||
@@ -50,7 +79,7 @@ struct fast_perfect_hash : type_hash {
|
||||
inline static std::size_t max_value;
|
||||
inline static void check(std::size_t index, type_id type);
|
||||
|
||||
template<typename ForwardIterator>
|
||||
template<class ForwardIterator, class... Options>
|
||||
static void initialize(
|
||||
ForwardIterator first, ForwardIterator last,
|
||||
std::vector<type_id>& buckets);
|
||||
@@ -69,7 +98,7 @@ struct fast_perfect_hash : type_hash {
|
||||
//! @ref IdsToVptr objects
|
||||
//! @param first Beginning of the range
|
||||
//! @param last End of the range
|
||||
template<typename ForwardIterator>
|
||||
template<class ForwardIterator, class... Options>
|
||||
static auto initialize(ForwardIterator first, ForwardIterator last) {
|
||||
if constexpr (Registry::has_runtime_checks) {
|
||||
initialize(
|
||||
@@ -90,7 +119,7 @@ struct fast_perfect_hash : type_hash {
|
||||
//! the type id is valid, i.e. if it was present in the set passed to
|
||||
//! @ref initialize. Its absence indicates that a class involved in a
|
||||
//! method definition, method overrider, or method call was not
|
||||
//! registered. In this case, signal a @ref unknown_class_error using
|
||||
//! registered. In this case, signal a @ref missing_class using
|
||||
//! the registry's @ref error_handler if present; then calls `abort`.
|
||||
//!
|
||||
//! @param type The type_id to hash
|
||||
@@ -115,7 +144,7 @@ struct fast_perfect_hash : type_hash {
|
||||
};
|
||||
|
||||
template<class Registry>
|
||||
template<typename ForwardIterator>
|
||||
template<class ForwardIterator, class... Options>
|
||||
void fast_perfect_hash::fn<Registry>::initialize(
|
||||
ForwardIterator first, ForwardIterator last,
|
||||
std::vector<type_id>& buckets) {
|
||||
@@ -123,8 +152,10 @@ void fast_perfect_hash::fn<Registry>::initialize(
|
||||
|
||||
const auto N = std::distance(first, last);
|
||||
|
||||
if constexpr (Registry::has_trace && Registry::has_output) {
|
||||
if (Registry::trace::on) {
|
||||
if constexpr (
|
||||
mp11::mp_contains<mp11::mp_list<Options...>, trace>::value &&
|
||||
Registry::has_output) {
|
||||
if (trace::on) {
|
||||
Registry::output::os << "Finding hash factor for " << N
|
||||
<< " types\n";
|
||||
}
|
||||
@@ -146,7 +177,9 @@ void fast_perfect_hash::fn<Registry>::initialize(
|
||||
min_value = (std::numeric_limits<std::size_t>::max)();
|
||||
max_value = (std::numeric_limits<std::size_t>::min)();
|
||||
|
||||
if constexpr (Registry::has_trace && Registry::has_output) {
|
||||
if constexpr (
|
||||
mp11::mp_contains<mp11::mp_list<Options...>, trace>::value &&
|
||||
Registry::has_output) {
|
||||
if (Registry::trace::on) {
|
||||
Registry::output::os << " trying with M = " << M << ", "
|
||||
<< hash_size << " buckets\n";
|
||||
@@ -180,7 +213,9 @@ void fast_perfect_hash::fn<Registry>::initialize(
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (Registry::has_trace && Registry::has_output) {
|
||||
if constexpr (
|
||||
mp11::mp_contains<mp11::mp_list<Options...>, trace>::value &&
|
||||
Registry::has_output) {
|
||||
if (Registry::trace::on) {
|
||||
Registry::output::os
|
||||
<< " found " << mult << " after " << total_attempts
|
||||
@@ -195,7 +230,7 @@ void fast_perfect_hash::fn<Registry>::initialize(
|
||||
}
|
||||
}
|
||||
|
||||
fast_perfect_hash_error error;
|
||||
search_error error;
|
||||
error.attempts = total_attempts;
|
||||
error.buckets = std::size_t(1) << M;
|
||||
|
||||
@@ -212,7 +247,7 @@ void fast_perfect_hash::fn<Registry>::check(std::size_t index, type_id type) {
|
||||
detail::fast_perfect_hash_control<Registry>[index] != type) {
|
||||
|
||||
if constexpr (Registry::has_error_handler) {
|
||||
unknown_class_error error;
|
||||
missing_class error;
|
||||
error.type = type;
|
||||
Registry::error_handler::error(error);
|
||||
}
|
||||
@@ -221,6 +256,12 @@ void fast_perfect_hash::fn<Registry>::check(std::size_t index, type_id type) {
|
||||
}
|
||||
}
|
||||
|
||||
template<class Registry, class Stream>
|
||||
auto fast_perfect_hash::search_error::write(Stream& os) const -> void {
|
||||
os << "could not find hash factors after " << attempts << "s using "
|
||||
<< buckets << " buckets\n";
|
||||
}
|
||||
|
||||
} // namespace policies
|
||||
} // namespace boost::openmethod
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#ifndef BOOST_OPENMETHOD_POLICY_MINIMAL_RTTI_HPP
|
||||
#define BOOST_OPENMETHOD_POLICY_MINIMAL_RTTI_HPP
|
||||
|
||||
#include <boost/openmethod/registry.hpp>
|
||||
#include <boost/openmethod/preamble.hpp>
|
||||
|
||||
namespace boost::openmethod::policies {
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#ifndef BOOST_OPENMETHOD_POLICY_STD_RTTI_HPP
|
||||
#define BOOST_OPENMETHOD_POLICY_STD_RTTI_HPP
|
||||
|
||||
#include <boost/openmethod/registry.hpp>
|
||||
#include <boost/openmethod/preamble.hpp>
|
||||
|
||||
#ifndef BOOST_NO_RTTI
|
||||
#include <typeindex>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#ifndef BOOST_OPENMETHOD_POLICIES_STANDARD_ERROR_OUTPUT_HPP
|
||||
#define BOOST_OPENMETHOD_POLICIES_STANDARD_ERROR_OUTPUT_HPP
|
||||
|
||||
#include <boost/openmethod/registry.hpp>
|
||||
#include <boost/openmethod/preamble.hpp>
|
||||
#include <boost/openmethod/detail/ostdstream.hpp>
|
||||
|
||||
namespace boost::openmethod::policies {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#ifndef BOOST_OPENMETHOD_POLICY_THROW_ERROR_HPP
|
||||
#define BOOST_OPENMETHOD_POLICY_THROW_ERROR_HPP
|
||||
|
||||
#include <boost/openmethod/registry.hpp>
|
||||
#include <boost/openmethod/preamble.hpp>
|
||||
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#ifndef BOOST_OPENMETHOD_POLICY_VECTORED_ERROR_HPP
|
||||
#define BOOST_OPENMETHOD_POLICY_VECTORED_ERROR_HPP
|
||||
|
||||
#include <boost/openmethod/registry.hpp>
|
||||
#include <boost/openmethod/preamble.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <variant>
|
||||
@@ -15,7 +15,7 @@ namespace boost::openmethod::policies {
|
||||
|
||||
struct default_error_handler : error_handler {
|
||||
using error_variant = std::variant<
|
||||
openmethod_error, not_implemented_error, unknown_class_error,
|
||||
openmethod_error, no_overrider, missing_class,
|
||||
fast_perfect_hash_error, final_error, static_slot_error,
|
||||
static_stride_error>;
|
||||
|
||||
@@ -43,7 +43,7 @@ struct default_error_handler : error_handler {
|
||||
if constexpr (Registry::has_output) {
|
||||
auto& os = Registry::template policy<policies::output>::os;
|
||||
|
||||
if (auto error = std::get_if<not_implemented_error>(&error_v)) {
|
||||
if (auto error = std::get_if<no_overrider>(&error_v)) {
|
||||
os << "no applicable overrider for ";
|
||||
Registry::template policy<policies::rtti>::type_name(
|
||||
error->method, os);
|
||||
@@ -60,7 +60,7 @@ struct default_error_handler : error_handler {
|
||||
|
||||
os << ")\n";
|
||||
} else if (
|
||||
auto error = std::get_if<unknown_class_error>(&error_v)) {
|
||||
auto error = std::get_if<missing_class>(&error_v)) {
|
||||
os << "unknown class ";
|
||||
Registry::template policy<policies::rtti>::type_name(
|
||||
error->type, os);
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#ifndef BOOST_OPENMETHOD_POLICY_VPTR_MAP_HPP
|
||||
#define BOOST_OPENMETHOD_POLICY_VPTR_MAP_HPP
|
||||
|
||||
#include <boost/openmethod/registry.hpp>
|
||||
#include <boost/openmethod/preamble.hpp>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
@@ -42,7 +42,7 @@ class vptr_map : public vptr {
|
||||
//! @ref IdsToVptr objects.
|
||||
//! @param first The beginning of the range.
|
||||
//! @param last The end of the range.
|
||||
template<typename ForwardIterator>
|
||||
template<class ForwardIterator>
|
||||
static void initialize(ForwardIterator first, ForwardIterator last) {
|
||||
for (auto iter = first; iter != last; ++iter) {
|
||||
for (auto type_iter = iter->type_id_begin();
|
||||
@@ -65,7 +65,7 @@ class vptr_map : public vptr {
|
||||
//! If the registry contains the @ref runtime_checks policy, checks that
|
||||
//! the map contains the type id. If it does not, and if the registry
|
||||
//! contains a @ref error_handler policy, calls its
|
||||
//! @ref error function with a @ref unknown_class_error value, then
|
||||
//! @ref error function with a @ref missing_class value, then
|
||||
//! terminates the program with @ref abort.
|
||||
//!
|
||||
//! @tparam Class A registered class.
|
||||
@@ -79,7 +79,7 @@ class vptr_map : public vptr {
|
||||
if constexpr (Registry::has_runtime_checks) {
|
||||
if (iter == vptrs.end()) {
|
||||
if constexpr (Registry::has_error_handler) {
|
||||
unknown_class_error error;
|
||||
missing_class error;
|
||||
error.type = type;
|
||||
Registry::error_handler::error(error);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#ifndef BOOST_OPENMETHOD_POLICY_VPTR_VECTOR_HPP
|
||||
#define BOOST_OPENMETHOD_POLICY_VPTR_VECTOR_HPP
|
||||
|
||||
#include <boost/openmethod/registry.hpp>
|
||||
#include <boost/openmethod/preamble.hpp>
|
||||
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
@@ -62,12 +62,14 @@ struct vptr_vector : vptr {
|
||||
//! IdsToVptr objects.
|
||||
//! @param first The beginning of the range.
|
||||
//! @param last The end of the range.
|
||||
template<typename ForwardIterator>
|
||||
template<class ForwardIterator, class... Options>
|
||||
static auto
|
||||
initialize(ForwardIterator first, ForwardIterator last) -> void {
|
||||
std::size_t size;
|
||||
if constexpr (has_type_hash) {
|
||||
auto [_, max_value] = type_hash::initialize(first, last);
|
||||
auto [_, max_value] =
|
||||
type_hash::template initialize<ForwardIterator, Options...>(
|
||||
first, last);
|
||||
size = max_value + 1;
|
||||
} else {
|
||||
size = 0;
|
||||
@@ -121,7 +123,7 @@ struct vptr_vector : vptr {
|
||||
//! If the registry contains the @ref runtime_checks policy, verifies
|
||||
//! that the index falls within the limits of the vector. If it does
|
||||
//! not, and if the registry contains a @ref error_handler policy, calls
|
||||
//! its @ref error function with a @ref unknown_class_error value, then
|
||||
//! its @ref error function with a @ref missing_class value, then
|
||||
//! terminates the program with @ref abort.
|
||||
//!
|
||||
//! @tparam Class A registered class.
|
||||
@@ -148,7 +150,7 @@ struct vptr_vector : vptr {
|
||||
|
||||
if (index >= max_index) {
|
||||
if constexpr (Registry::has_error_handler) {
|
||||
unknown_class_error error;
|
||||
missing_class error;
|
||||
error.type = dynamic_type;
|
||||
Registry::error_handler::error(error);
|
||||
}
|
||||
|
||||
1047
include/boost/openmethod/preamble.hpp
Normal file
1047
include/boost/openmethod/preamble.hpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,786 +0,0 @@
|
||||
#ifndef BOOST_OPENMETHOD_REGISTRY_HPP
|
||||
#define BOOST_OPENMETHOD_REGISTRY_HPP
|
||||
|
||||
#include <boost/openmethod/detail/types.hpp>
|
||||
|
||||
#include <boost/mp11/algorithm.hpp>
|
||||
#include <boost/mp11/bind.hpp>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
#ifdef _MSC_VER
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4702)
|
||||
#endif
|
||||
|
||||
namespace boost::openmethod {
|
||||
|
||||
//! Namespace containing the policy framework.
|
||||
//!
|
||||
//! A registry contains a set of policies that control how certain operations
|
||||
//! are performed. For example, the "rtti" policy provides type information,
|
||||
//! implements dynamic casting, etc. It can be replaced to interface with custom
|
||||
//! RTII systems (like LLVM's).
|
||||
//!
|
||||
//! A policy must derive from one of the policy base classes, also known as
|
||||
//! _policy categories_.
|
||||
//!
|
||||
//! - @ref rtti: type information acquisition and manipulation.
|
||||
//!
|
||||
//! - @ref error_handler: perform operations when errors are detected.
|
||||
//!
|
||||
//! - @ref vptr: v-table pointer acquisition.
|
||||
//!
|
||||
//! - @ref type_hash: hashing of `type_id`s.
|
||||
//!
|
||||
//! - @ref output: output stream for logging and debugging.
|
||||
//!
|
||||
//! - @ref runtime_checks: detect and report common errors.
|
||||
//!
|
||||
//! - @ref trace: report how dispatch tables are built.
|
||||
//!
|
||||
//! - @ref n2216: handle ambiguities according to the N2216 proposal.
|
||||
//!
|
||||
//! Policies are implemented as Boost.MP11 quoted meta-functions. A policy class
|
||||
//! must contain a `template<class Registry> struct fn` that provides a set of
|
||||
//! _static_ members, fulfilling the requirements specified in the policy's
|
||||
//! category. Registries instantiate policies by passing themselves to the
|
||||
//! nested `fn` class templates.
|
||||
//!
|
||||
//! There are two reason for this design.
|
||||
//!
|
||||
//! Some policies are "stateful": they contain static _data_ members. Since
|
||||
//! several registries can co-exist in the same program, each stateful policy
|
||||
//! needs its own, separate set of static data members. For example, @ref
|
||||
//! vptr_vector, a "vptr" policy, contains a static vector of vptrs, which
|
||||
//! cannot be shared with other registries.
|
||||
//!
|
||||
//! Some policies need access to other policies in the same registry. They can
|
||||
//! be accessed via the `Registry` template parameter. For example, @ref
|
||||
//! vptr_vector hashes type_ids before using them as an indexes, if `Registry`
|
||||
//! cotains a `type_hash` policy. It performs out-of-bounds checks if `Registry`
|
||||
//! contains the `runtime_checks` policy. If an error is detected, it invokes
|
||||
//! the @ref error_handler policy if there is one.
|
||||
//!
|
||||
//! The last three policies (runtime_checks, trace and n2216) act like flags,
|
||||
//! and enabling some sections of code. They can be used as-is, without the need
|
||||
//! for subclassing.
|
||||
|
||||
#ifdef __MRDOCS__
|
||||
|
||||
//! Blueprint for a lightweight output stream (exposition only).
|
||||
struct LightweightOutputStream {
|
||||
LightweightOutputStream& operator<<(const char* str);
|
||||
LightweightOutputStream& operator<<(const std::string_view& view);
|
||||
LightweightOutputStream& operator<<(const void* value);
|
||||
LightweightOutputStream& operator<<(std::size_t value);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
namespace policies {
|
||||
|
||||
#ifdef __MRDOCS__
|
||||
|
||||
//! Requirements for policy categories (exposition only)
|
||||
//!
|
||||
struct PolicyCategory {
|
||||
using category = PolicyCategory;
|
||||
};
|
||||
|
||||
//! Requirements for policies (exposition only)
|
||||
//!
|
||||
struct Policy : PolicyCategory {
|
||||
template<class Registry>
|
||||
struct fn;
|
||||
};
|
||||
|
||||
//! Requirements for IdsToVptr (exposition only)
|
||||
//!
|
||||
struct IdsToVptr {
|
||||
//! Returns an iterator to the beginning of a range of `type_id`s for a
|
||||
//! single registered class.
|
||||
auto type_id_begin() const;
|
||||
|
||||
//! Returns an iterator to the end of a range of `type_id`s for a
|
||||
//! single registered class.
|
||||
auto type_id_end() const;
|
||||
|
||||
//! Returns a range of `type_id`s that this assignment applies to.
|
||||
auto vptr() const -> const vptr_type&;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
//! Policy for runtime type information.
|
||||
//!
|
||||
//! A @e rtti policy is responsible for acquiring and manipulating type
|
||||
//! information, dynamic casting, and detecting polymorphic classes.
|
||||
//!
|
||||
//! @par Requirements
|
||||
//!
|
||||
//! A subclass of `rtti` must contain a `fn<Registry>` class template
|
||||
//! that fulfills the requirements of @ref rtti::fn.
|
||||
struct rtti {
|
||||
using category = rtti;
|
||||
|
||||
//! Default implementations of some `rtti` requirements.
|
||||
struct defaults {
|
||||
//! Default implementation for `type_index`.
|
||||
//!
|
||||
//! @param type A `type_id`.
|
||||
//!
|
||||
//! @return `type` itself.
|
||||
static auto type_index(type_id type) -> type_id {
|
||||
return type;
|
||||
}
|
||||
|
||||
//! Default implementation of `type_name`.
|
||||
//!
|
||||
//! Executes `stream << "type_id(" << type << ")"`.
|
||||
//!
|
||||
//! @param type A `type_id`.
|
||||
//! @param stream A stream to write to.
|
||||
template<typename Stream>
|
||||
static void type_name(type_id type, Stream& stream) {
|
||||
stream << "type_id(" << type << ")";
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef __MRDOCS__
|
||||
//! Requirements for `rtti` policies (exposition only).
|
||||
//!
|
||||
//! This class is for _exposition only_. It is the responsibility of
|
||||
//! subclasses to provide a `fn` class template that contains the members
|
||||
//! listed on this page.
|
||||
template<class Registry>
|
||||
struct fn {
|
||||
//! Tests if a class is polymorphic.
|
||||
//!
|
||||
//! @tparam Class A class.
|
||||
template<class Class>
|
||||
static constexpr bool is_polymorphic = std::is_polymorphic_v<Class>;
|
||||
|
||||
//! Returns the static @ref type_id of a type.
|
||||
//!
|
||||
//! @note `Class` is not necessarily a @e registered class. This
|
||||
//! function is also called to acquire the type_id of non-virtual
|
||||
//! parameters, library types, etc, for diagnostic and trace purposes.
|
||||
//!
|
||||
//! @tparam Class A class.
|
||||
//! @return The static type_id of Class.
|
||||
template<class Class>
|
||||
static auto static_type() -> type_id;
|
||||
|
||||
//! Returns the dynamic @ref type_id of an object.
|
||||
//!
|
||||
//! @tparam Class A registered class.
|
||||
//! @param obj A reference to an instance of `Class`.
|
||||
//! @return The type_id of `obj`'s class.
|
||||
template<class Class>
|
||||
static auto dynamic_type(const Class& obj) -> type_id;
|
||||
|
||||
//! Writes a representation of a @ref type_id to a stream.
|
||||
//!
|
||||
//! @tparam Stream A LightweightOutputStream.
|
||||
//! @param type The `type_id` to write.
|
||||
//! @param stream The stream to write to.
|
||||
template<typename Stream>
|
||||
static auto type_name(type_id type, Stream& stream) -> void;
|
||||
|
||||
//! Returns a key that uniquely identifies a class.
|
||||
//!
|
||||
//! @param type A `type_id`.
|
||||
//! @return A unique value that identifies a class with the given
|
||||
//! `type_id`.
|
||||
static auto type_index(type_id type);
|
||||
|
||||
//! Casts an object to a type.
|
||||
//!
|
||||
//! @tparam D A reference to a subclass of `B`.
|
||||
//! @tparam B A registered class.
|
||||
//! @param obj A reference to an instance of `B`.
|
||||
template<typename D, typename B>
|
||||
static auto dynamic_cast_ref(B&& obj) -> D;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef __MRDOCS__
|
||||
struct std_rtti;
|
||||
struct static_rtti;
|
||||
#endif
|
||||
|
||||
//! Policy for deferred type id collection.
|
||||
//!
|
||||
//! Some custom RTTI systems rely on static constructors to assign type ids.
|
||||
//! OpenMethod itself relies on static constructors to register classes, methods
|
||||
//! and overriders. This creates order-of-initialization issues. Deriving a @e
|
||||
//! rtti policy from this class - instead of just `rtti` - causes the collection
|
||||
//! of type ids to be deferred until the first call to @ref update.
|
||||
struct deferred_static_rtti : rtti {};
|
||||
|
||||
//! Policy for error handling.
|
||||
//!
|
||||
//! A @e error_handler policy runs code before the library terminats the program
|
||||
//! due to an error. This can be useful for throwing, logging, cleanup, or other
|
||||
//! actions.
|
||||
//!
|
||||
//! @par Requirements
|
||||
//!
|
||||
//! A subclass of `error_handler` must contain a `fn<Registry>` class template
|
||||
//! that fulfills the requirements of @ref error_handler::fn.
|
||||
|
||||
struct error_handler {
|
||||
using category = error_handler;
|
||||
|
||||
#ifdef __MRDOCS__
|
||||
//! Requirements for `error_handler` policies (exposition only).
|
||||
//!
|
||||
//! This class is for _exposition only_. It is the responsibility of
|
||||
//! subclasses to provide a `fn` class template that contains the members
|
||||
//! listed on this page.
|
||||
template<class Registry>
|
||||
struct fn {
|
||||
//! Called when an error is detected.
|
||||
//!
|
||||
//! `error` is a function, or a set of functions, that can be called
|
||||
//! with an instance of any subclass of `openmethod_error`.
|
||||
static auto error(const auto& error) -> void;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef __MRDOCS__
|
||||
struct default_error_handler;
|
||||
struct throw_error_handler;
|
||||
#endif
|
||||
|
||||
//! Policy for v-table pointer acquisition.
|
||||
//!
|
||||
//! @par Requirements
|
||||
//!
|
||||
//! A subclass of `vptr` must contain a `fn<Registry>` class template
|
||||
//! that fulfills the requirements of @ref vptr::fn.
|
||||
struct vptr {
|
||||
using category = vptr;
|
||||
|
||||
#ifdef __MRDOCS__
|
||||
//! Requirements for `vptr` policies (exposition only)
|
||||
//!
|
||||
//! This class is for _exposition only_. It is the responsibility of
|
||||
//! subclasses to provide a `fn` class template that contains the members
|
||||
//! listed on this page.
|
||||
template<class Registry>
|
||||
struct fn {
|
||||
//! Stores the v-table pointers.
|
||||
//! @tparam ForwardIterator An iterator to a range of const
|
||||
//! @ref `IdsToVptr` objects.
|
||||
//! @param first The beginning of the range.
|
||||
//! @param last The end of the range.
|
||||
template<typename ForwardIterator>
|
||||
static auto initialize(ForwardIterator first, ForwardIterator last);
|
||||
|
||||
//! Returns a *reference* to a v-table pointer for an object.
|
||||
//!
|
||||
//! @tparam Class A registered class.
|
||||
//! @param arg A reference to a const object of type `Class`.
|
||||
//! @return A reference to a the v-table pointer for `Class`.
|
||||
template<class Class>
|
||||
static auto dynamic_vptr(const Class& arg) -> const vptr_type&;
|
||||
|
||||
//! Releases the resources allocated by `initialize`. This function is
|
||||
//! optional.
|
||||
static auto finalize() -> void;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
//! Policy to add an indirection to pointers to v-tables.
|
||||
//!
|
||||
//! If this policy is present, constructs like @ref virtual_ptr, @ref
|
||||
//! inplace_vptr, @ref vptr_vector, etc store pointers to pointers to v-tables.
|
||||
//! These indirect pointers remain valid after a call to @ref initialize, even
|
||||
//! though the v-tables move to different locations. This is useful in presence
|
||||
//! of dynamic loading.
|
||||
//!
|
||||
//! @par Requirements
|
||||
//!
|
||||
//! None. `indirect_vptr` can be added to a registry's policy list as-is.
|
||||
|
||||
struct indirect_vptr final {
|
||||
using category = indirect_vptr;
|
||||
template<class Registry>
|
||||
struct fn {};
|
||||
};
|
||||
|
||||
#ifdef __MRDOCS__
|
||||
class vptr_vector;
|
||||
template<class MapFn>
|
||||
class vptr_map;
|
||||
#endif
|
||||
|
||||
//! Policy for type_id hashing.
|
||||
//!
|
||||
//! A @e type_hash policy calculates an integer hash for a @ref type_id.
|
||||
//!
|
||||
//! @par Requirements
|
||||
//!
|
||||
//! A subclass of `type_hash` must contain a `fn<Registry>` class template
|
||||
//! that fulfills the requirements of @ref type_hash::fn.
|
||||
struct type_hash {
|
||||
using category = type_hash;
|
||||
|
||||
#ifdef __MRDOCS__
|
||||
//! Requirements for `type_hash` policies (exposition only)
|
||||
//! @tparam Registry The registry containing this policy.
|
||||
//!
|
||||
//! This class is for _exposition only_. It is the responsibility of
|
||||
//! subclasses to provide a `fn` class template that contains the members
|
||||
//! listed on this page.
|
||||
template<class Registry>
|
||||
struct fn {
|
||||
//! Initializes the hash table.
|
||||
//! @tparam ForwardIterator An iterator to a range of const
|
||||
//! @ref IdsToVptr objects.
|
||||
//! @param first The beginning of the range.
|
||||
//! @param last The end of the range.
|
||||
//! @return A pair containing the minimum and maximum hash values.
|
||||
template<typename ForwardIterator>
|
||||
static auto initialize(ForwardIterator first, ForwardIterator last)
|
||||
-> std::pair<std::size_t, std::size_t>;
|
||||
|
||||
//! Hashes a `type_id`.
|
||||
//! @param type A @ref type_id.
|
||||
//! @return A hash value for the given `type_id`.
|
||||
static auto hash(type_id type) -> std::size_t;
|
||||
|
||||
//! Releases the resources allocated by `initialize`. This function is
|
||||
//! optional.
|
||||
static auto finalize() -> void;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef __MRDOCS__
|
||||
class fast_perfect_hash;
|
||||
#endif
|
||||
|
||||
//! Policy for writing diagnostics and trace.
|
||||
//!
|
||||
//! If an `output` policy is present, the default error handler uses it to write
|
||||
//! error messages to its output stream. `initialize` can also use it to write
|
||||
//! trace messages.
|
||||
//!
|
||||
//! @par Requirements
|
||||
//!
|
||||
//! A subclass of `output` must contain a `fn<Registry>` class template
|
||||
//! that fulfills the requirements of @ref output::fn.
|
||||
struct output {
|
||||
using category = output;
|
||||
|
||||
#ifdef __MRDOCS__
|
||||
//! Requirements for `output` policies (exposition only)
|
||||
//!
|
||||
//! This class is for _exposition only_. It is the responsibility of
|
||||
//! subclasses to provide a `fn` class template that contains the members
|
||||
//! listed on this page.
|
||||
template<class Registry>
|
||||
struct fn {
|
||||
//! A @ref LightweightOutputStream.
|
||||
inline static LightweightOutputStream os;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef __MRDOCS__
|
||||
struct stderr_output;
|
||||
#endif
|
||||
|
||||
//! Policy for tracing.
|
||||
//!
|
||||
//! If `trace` is present, trace instructions are added to various parts of the
|
||||
//! initialization process (dispatch table construction, hash factors search,
|
||||
//! etc). These instructions are executed only if `trace::fn<Registry>::on` is
|
||||
//! set to `true`. The default value of `on` is `true` if environment variable
|
||||
//! `BOOST_OPENMETHOD_TRACE` is set to the string "1". At the moment, any other
|
||||
//! value disables tracing.
|
||||
//!
|
||||
//! `trace` requires an `output` policy to be present. Trace is written to its
|
||||
//! output stream.
|
||||
//!
|
||||
//! The exact format of the trace output is not specified, and may change at any
|
||||
//! time. The only guarantee is that it is detailed and comprehensive, and makes
|
||||
//! it possible to troubleshoot problems like missing class registrations,
|
||||
//! missing or ambiguous overriders, etc.
|
||||
struct trace final {
|
||||
using category = trace;
|
||||
|
||||
template<class Registry>
|
||||
struct fn {
|
||||
inline static bool on = []() {
|
||||
#ifdef _MSC_VER
|
||||
char* env;
|
||||
std::size_t len;
|
||||
auto result =
|
||||
_dupenv_s(&env, &len, "BOOST_OPENMETHOD_TRACE") == 0 && env &&
|
||||
len == 2 && *env == '1';
|
||||
free(env);
|
||||
return result;
|
||||
#else
|
||||
auto env = getenv("BOOST_OPENMETHOD_TRACE");
|
||||
return env && *env++ == '1' && *env++ == 0;
|
||||
#endif
|
||||
}();
|
||||
};
|
||||
};
|
||||
|
||||
//! Policy for runtime sanity checks.
|
||||
//!
|
||||
//! If this policy is present, various checks are performed at runtime.
|
||||
//! Currently they all attempt to detect missing class registrations.
|
||||
struct runtime_checks final {
|
||||
using category = runtime_checks;
|
||||
template<class Registry>
|
||||
struct fn {};
|
||||
};
|
||||
|
||||
//! Policy for N2216 ambiguity resolution.
|
||||
//!
|
||||
//! If this policy is present, additional steps are taken to select a single
|
||||
//! overrider in presence of ambiguous overriders sets, according to the rules
|
||||
//! defined in the N2216 paper. If the normal resolution procedure fails to
|
||||
//! select a single overrider, the following steps are applied, in order:
|
||||
//!
|
||||
//! - If the return types of the remaining overriders are all polymorphic and
|
||||
//! covariant, and one of the return types is more specialized thjat all the
|
||||
//! others, use it.
|
||||
//!
|
||||
//! - Otherwise, pick one of the overriders. Which one is used is unspecified,
|
||||
//! but remains the same throughtout the program, and across different runs of
|
||||
//! the same program.
|
||||
struct n2216 final {
|
||||
using category = n2216;
|
||||
template<class Registry>
|
||||
struct fn {};
|
||||
};
|
||||
|
||||
} // namespace policies
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct registry_base {};
|
||||
|
||||
template<typename T>
|
||||
constexpr bool is_registry = std::is_base_of_v<registry_base, T>;
|
||||
|
||||
template<typename T>
|
||||
constexpr bool is_not_void = !std::is_same_v<T, void>;
|
||||
|
||||
template<
|
||||
class Registry, class Index,
|
||||
class Size = mp11::mp_size<typename Registry::policy_list>>
|
||||
struct get_policy_aux {
|
||||
using type = typename mp11::mp_at<
|
||||
typename Registry::policy_list, Index>::template fn<Registry>;
|
||||
};
|
||||
|
||||
template<class Registry, class Size>
|
||||
struct get_policy_aux<Registry, Size, Size> {
|
||||
using type = void;
|
||||
};
|
||||
|
||||
using class_catalog = detail::static_list<detail::class_info>;
|
||||
using method_catalog = detail::static_list<detail::method_info>;
|
||||
|
||||
template<class Policies, class...>
|
||||
struct with_aux;
|
||||
|
||||
template<class Policies>
|
||||
struct with_aux<Policies> {
|
||||
using type = Policies;
|
||||
};
|
||||
|
||||
template<class Policies, class Policy, class... MorePolicies>
|
||||
struct with_aux<Policies, Policy, MorePolicies...> {
|
||||
using replace = mp11::mp_replace_if_q<
|
||||
Policies,
|
||||
mp11::mp_bind_front_q<
|
||||
mp11::mp_quote_trait<std::is_base_of>, typename Policy::category>,
|
||||
Policy>;
|
||||
using replace_or_add = std::conditional_t<
|
||||
std::is_same_v<replace, Policies>, mp11::mp_push_back<Policies, Policy>,
|
||||
replace>;
|
||||
using type = typename with_aux<replace_or_add, MorePolicies...>::type;
|
||||
};
|
||||
|
||||
template<class Policies, class...>
|
||||
struct without_aux;
|
||||
|
||||
template<class Policies>
|
||||
struct without_aux<Policies> {
|
||||
using type = Policies;
|
||||
};
|
||||
|
||||
template<class Policies, class Policy, class... MorePolicies>
|
||||
struct without_aux<Policies, Policy, MorePolicies...> {
|
||||
using type = typename without_aux<
|
||||
mp11::mp_remove_if_q<
|
||||
Policies,
|
||||
mp11::mp_bind_front_q<
|
||||
mp11::mp_quote_trait<std::is_base_of>,
|
||||
typename Policy::category>>,
|
||||
MorePolicies...>::type;
|
||||
};
|
||||
|
||||
template<class...>
|
||||
struct use_class_aux;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
//! A collection of methods and their associated dispatch data.
|
||||
//!
|
||||
//! Methods exist in a registry, which also contains descriptions for all the
|
||||
//! classes that can appear in the methods, their overriders, and method calls.
|
||||
//!
|
||||
//! Before calling a method, the @ref initialize function must be called for its
|
||||
//! registry to set up the dispatch tables. This is typically done at the
|
||||
//! beginning of `main`.
|
||||
//!
|
||||
//! Multiple registries can co-exist in the same program. They must be
|
||||
//! initialized independently. Classes referenced by methods in different
|
||||
//! registries must be registered with each registry individually.
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//! @tparam Policies The policies used in the registry.
|
||||
//!
|
||||
//! @par Requirements
|
||||
//!
|
||||
//! `Policies` must be models of @ref policies::Policy. There may be at most one
|
||||
//! policy per category, i.e. `Policies::category...` must all be different.
|
||||
//!
|
||||
//! @see @ref policies
|
||||
template<class... Policies>
|
||||
class registry : detail::registry_base {
|
||||
inline static detail::class_catalog classes;
|
||||
inline static detail::method_catalog methods;
|
||||
|
||||
template<class...>
|
||||
friend struct detail::use_class_aux;
|
||||
template<typename Name, typename ReturnType, class Registry>
|
||||
friend class method;
|
||||
|
||||
struct compiler;
|
||||
|
||||
inline static std::vector<detail::word> dispatch_data;
|
||||
inline static bool initialized;
|
||||
|
||||
public:
|
||||
//! Initializes the registry.
|
||||
//!
|
||||
//! `initialize` must be called, typically at the beginning of `main`,
|
||||
//! before using any of the methods in the registry. It sets up the
|
||||
//! v-tables, multi-method dispatch tables, and any other data required by
|
||||
//! the policies.
|
||||
//!
|
||||
//! @note
|
||||
//! A translation unit that contains a call to `initialize` must include the
|
||||
//! `<boost/openmethod/initialize.hpp>` header.
|
||||
//!
|
||||
//! @par Errors
|
||||
//!
|
||||
//! @li @ref unknown_class_error: A class used in a virtual parameter was
|
||||
//! not registered.
|
||||
//!
|
||||
//! In addition, policies may encounter and report errors.
|
||||
static auto initialize();
|
||||
|
||||
//! Checks if the registry is initialized.
|
||||
//!
|
||||
//! Checks if `initialize` has been called for this registry, and report an
|
||||
//! error if not.
|
||||
//!
|
||||
//! @par Errors
|
||||
//!
|
||||
//! @li @ref not_initialized_error: The registry is not initialized.
|
||||
static void check_initialized();
|
||||
|
||||
//! Releases the resources held by the registry.
|
||||
//!
|
||||
//! `finalize` may be called to release any resources allocated by
|
||||
//! `initialize`.
|
||||
//!
|
||||
//! @note
|
||||
//! A translation unit that contains a call to `finalize` must include the
|
||||
//! `<boost/openmethod/initialize.hpp>` header.
|
||||
static void finalize();
|
||||
|
||||
//! A pointer to the virtual table for a registered class.
|
||||
//!
|
||||
//! `static_vptr` is set by @ref initialize to the address of the class's
|
||||
//! virtual table. It remains valid until the next call to `initialize` or
|
||||
//! `finalize`.
|
||||
//!
|
||||
//! @tparam Class A registered class.
|
||||
template<class Class>
|
||||
inline static vptr_type static_vptr;
|
||||
|
||||
//! The list of policies selected in a registry.
|
||||
//!
|
||||
//! `policy_list` is a Boost.Mp11 list containing the policies passed to the
|
||||
//! @ref registry clas template.
|
||||
//!
|
||||
//! @tparam Class A registered class.
|
||||
using policy_list = mp11::mp_list<Policies...>;
|
||||
|
||||
//! Returns the policy for a policy category.
|
||||
//!
|
||||
//! `policy` searches for a policy that derives from the specified @ref
|
||||
//! PolicyCategory. If none is found, it aliases to `void`. Otherwise, it
|
||||
//! aliases to the policy's `fn` class template, instantiated for this
|
||||
//! registry.
|
||||
//!
|
||||
//! @tparam Category A model of @ref policies::PolicyCategory.
|
||||
template<class Category>
|
||||
using policy = typename detail::get_policy_aux<
|
||||
registry,
|
||||
mp11::mp_find_if_q<
|
||||
policy_list,
|
||||
mp11::mp_bind_front_q<
|
||||
mp11::mp_quote_trait<std::is_base_of>, Category>>>::type;
|
||||
|
||||
//! Returns a copy of this registry, with additional policies.
|
||||
//!
|
||||
//! `with` aliases to a registry containing `NewPolicies`, in addition to
|
||||
//! this registry's policies that are not in the same category as any of the
|
||||
//! `NewPolicies`.
|
||||
//!
|
||||
//! @tparam NewPolicies Models of @ref policies::Policy.
|
||||
template<class... NewPolicies>
|
||||
using with = boost::mp11::mp_apply<
|
||||
registry, typename detail::with_aux<policy_list, NewPolicies...>::type>;
|
||||
|
||||
//! Returns a copy of this registry, with some policies removed.
|
||||
//!
|
||||
//! `without` returns a copy of this registry, without the policies that
|
||||
//! derive from `Categories`.
|
||||
//!
|
||||
//! @tparam Categories Models of @ref policies::PolicyCategory.
|
||||
template<class... Categories>
|
||||
using without = boost::mp11::mp_apply<
|
||||
registry,
|
||||
typename detail::without_aux<policy_list, Categories...>::type>;
|
||||
|
||||
//! The registry's rtti policy.
|
||||
using rtti = policy<policies::rtti>;
|
||||
|
||||
//! The registry's vptr policy if it contains one, or `void`.
|
||||
using vptr = policy<policies::vptr>;
|
||||
|
||||
//! `true` if the registry has a vptr policy.
|
||||
static constexpr auto has_vptr = !std::is_same_v<vptr, void>;
|
||||
|
||||
//! The registry's error_handler policy if it contains one, or `void`.
|
||||
using error_handler = policy<policies::error_handler>;
|
||||
|
||||
//! `true` if the registry has an error_handler policy.
|
||||
static constexpr auto has_error_handler =
|
||||
!std::is_same_v<error_handler, void>;
|
||||
|
||||
//! The registry's output policy if it contains one, or `void`.
|
||||
using output = policy<policies::output>;
|
||||
|
||||
//! `true` if the registry has an output policy.
|
||||
static constexpr auto has_output = !std::is_same_v<output, void>;
|
||||
|
||||
//! The registry's trace policy if it contains one, or `void`.
|
||||
using trace = policy<policies::trace>;
|
||||
|
||||
//! `true` if the registry has a trace policy.
|
||||
static constexpr auto has_trace = !std::is_same_v<trace, void>;
|
||||
|
||||
//! `true` if the registry has a deferred_static_rtti policy.
|
||||
static constexpr auto has_deferred_static_rtti =
|
||||
!std::is_same_v<policy<policies::deferred_static_rtti>, void>;
|
||||
|
||||
//! `true` if the registry has a runtime_checks policy.
|
||||
static constexpr auto has_runtime_checks =
|
||||
!std::is_same_v<policy<policies::runtime_checks>, void>;
|
||||
|
||||
//! `true` if the registry has an indirect_vptr policy.
|
||||
static constexpr auto has_indirect_vptr =
|
||||
!std::is_same_v<policy<policies::indirect_vptr>, void>;
|
||||
|
||||
//! `true` if the registry has a n2216 policy.
|
||||
static constexpr auto has_n2216 =
|
||||
!std::is_same_v<policy<policies::n2216>, void>;
|
||||
};
|
||||
|
||||
template<class... Policies>
|
||||
inline void registry<Policies...>::check_initialized() {
|
||||
if constexpr (registry::has_runtime_checks) {
|
||||
if (!initialized) {
|
||||
if constexpr (registry::has_error_handler) {
|
||||
error_handler::error(not_initialized_error());
|
||||
}
|
||||
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class Registry, class Stream>
|
||||
auto call_error::write_aux(Stream& os, const char* subtype) const -> void {
|
||||
using namespace detail;
|
||||
using namespace policies;
|
||||
|
||||
os << "invalid call to ";
|
||||
Registry::template policy<rtti>::type_name(method, os);
|
||||
os << "(";
|
||||
auto comma = "";
|
||||
|
||||
for (auto ti : range{types, types + arity}) {
|
||||
os << comma;
|
||||
Registry::template policy<rtti>::type_name(ti, os);
|
||||
comma = ", ";
|
||||
}
|
||||
|
||||
os << "): " << subtype;
|
||||
}
|
||||
|
||||
template<class Registry, class Stream>
|
||||
auto unknown_class_error::write(Stream& os) const -> void {
|
||||
os << "unknown class ";
|
||||
Registry::rtti::type_name(type, os);
|
||||
}
|
||||
|
||||
template<class Registry, class Stream>
|
||||
auto final_error::write(Stream& os) const -> void {
|
||||
os << "invalid call to final construct: static type = ";
|
||||
Registry::rtti::type_name(static_type, os);
|
||||
os << ", dynamic type = ";
|
||||
Registry::rtti::type_name(dynamic_type, os);
|
||||
}
|
||||
|
||||
template<class Registry, class Stream>
|
||||
auto fast_perfect_hash_error::write(Stream& os) const -> void {
|
||||
os << "could not find hash factors after " << attempts << "s using "
|
||||
<< buckets << " buckets\n";
|
||||
}
|
||||
|
||||
template<class Registry, class Stream>
|
||||
auto static_offset_error::write(Stream& os) const -> void {
|
||||
os << "static offset error in ";
|
||||
Registry::rtti::type_name(method, os);
|
||||
os << ": expected " << expected << ", got " << actual;
|
||||
}
|
||||
|
||||
} // namespace boost::openmethod
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // BOOST_OPENMETHOD_REGISTRY_HPP
|
||||
@@ -5,13 +5,17 @@
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#
|
||||
# Official repository: https://github.com/boostorg/url
|
||||
# Official repository: https://github.com/boostorg/openmethod
|
||||
#
|
||||
|
||||
message(STATUS "Building tests")
|
||||
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
add_compile_definitions(BOOST_OPENMETHOD_ENABLE_RUNTIME_CHECKS)
|
||||
endif()
|
||||
|
||||
# Custom target used by the boost super-project
|
||||
if(NOT TARGET tests)
|
||||
if (NOT TARGET tests)
|
||||
add_custom_target(tests)
|
||||
set_property(TARGET tests PROPERTY FOLDER Dependencies)
|
||||
endif()
|
||||
@@ -59,3 +63,35 @@ foreach(test_cpp ${test_cpp_files})
|
||||
add_test(NAME ${test} COMMAND ${test})
|
||||
add_dependencies(tests ${test})
|
||||
endforeach()
|
||||
|
||||
add_executable(test_mix_release_debug mix_release_debug/main.cpp mix_release_debug/lib.cpp)
|
||||
target_link_libraries(test_mix_release_debug Boost::openmethod Boost::unit_test_framework)
|
||||
add_test(NAME test_mix_release_debug COMMAND test_mix_release_debug)
|
||||
add_dependencies(tests test_mix_release_debug)
|
||||
|
||||
function(openmethod_compile_fail_test testname fail_regex)
|
||||
add_library("compile-fail-${testname}" STATIC EXCLUDE_FROM_ALL "${testname}.cpp")
|
||||
target_link_libraries("compile-fail-${testname}" PRIVATE Boost::openmethod)
|
||||
add_test(
|
||||
NAME "openmethod-${testname}"
|
||||
COMMAND "${CMAKE_COMMAND}" --build ${CMAKE_BINARY_DIR} --target "compile-fail-${testname}" --config $<CONFIG>)
|
||||
set_property(TEST "openmethod-${testname}" PROPERTY PASS_REGULAR_EXPRESSION "${fail_regex}")
|
||||
endfunction()
|
||||
|
||||
openmethod_compile_fail_test(
|
||||
compile_fail_non_polymorphic_virtual_parameter "parameter is not a polymorphic class")
|
||||
openmethod_compile_fail_test(
|
||||
compile_fail_non_polymorphic_virtual_ptr ".*")
|
||||
openmethod_compile_fail_test(
|
||||
compile_fail_virtual_parameter_to_value "virtual_traits not specialized for type")
|
||||
openmethod_compile_fail_test(
|
||||
compile_fail_virtual_ptr_different_registries "registry mismatch")
|
||||
openmethod_compile_fail_test(
|
||||
compile_fail_virtual_ptr_other
|
||||
"virtual_ptr<> is required in overrider in same position as in method")
|
||||
openmethod_compile_fail_test(
|
||||
compile_fail_virtual_ptr_ref_to_value "different virtual_ptr<> reference categories")
|
||||
openmethod_compile_fail_test(
|
||||
compile_fail_virtual_ptr_shared_not_const "std::shared_ptr cannot be passed by non-const lvalue reference")
|
||||
openmethod_compile_fail_test(
|
||||
compile_fail_virtual_ptr_value_to_ref "different virtual_ptr<> reference categories")
|
||||
|
||||
@@ -35,6 +35,9 @@ for local src in [ glob test_*.cpp ]
|
||||
run $(src) unit_test_framework ;
|
||||
}
|
||||
|
||||
run mix_release_debug/main.cpp mix_release_debug/lib.cpp unit_test_framework ;
|
||||
|
||||
|
||||
for local src in [ glob compile_fail_*.cpp ]
|
||||
{
|
||||
compile-fail $(src) ;
|
||||
|
||||
@@ -12,8 +12,10 @@ struct Cat {
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_OPENMETHOD(
|
||||
poke, (virtual_ptr<Cat, release_registry>), void, debug_registry);
|
||||
struct other_registry : default_registry::without<policies::type_hash>::with<
|
||||
policies::runtime_checks> {};
|
||||
|
||||
BOOST_OPENMETHOD(poke, (virtual_ptr<Cat>), void, other_registry);
|
||||
|
||||
int main() {
|
||||
Cat felix;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/shared_ptr.hpp>
|
||||
#include <boost/openmethod/interop/std_shared_ptr.hpp>
|
||||
|
||||
using namespace boost::openmethod;
|
||||
|
||||
|
||||
22
test/mix_release_debug/lib.cpp
Normal file
22
test/mix_release_debug/lib.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
// 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>
|
||||
|
||||
#ifdef BOOST_OPENMETHOD_ENABLE_RUNTIME_CHECKS
|
||||
#undef BOOST_OPENMETHOD_ENABLE_RUNTIME_CHECKS
|
||||
#else
|
||||
#define BOOST_OPENMETHOD_ENABLE_RUNTIME_CHECKS
|
||||
#endif
|
||||
|
||||
#include "lib.hpp"
|
||||
|
||||
using namespace boost::openmethod;
|
||||
|
||||
BOOST_OPENMETHOD_CLASSES(Animal, Cat);
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(poke, (virtual_ptr<Cat>, std::ostream& os), void) {
|
||||
os << "hiss";
|
||||
}
|
||||
21
test/mix_release_debug/lib.hpp
Normal file
21
test/mix_release_debug/lib.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_OPENMETHOD_TEST_MIX_RELEASE_DEBUG_LIB_HPP
|
||||
#define BOOST_OPENMETHOD_TEST_MIX_RELEASE_DEBUG_LIB_HPP
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
|
||||
struct Animal {
|
||||
virtual ~Animal() {
|
||||
}
|
||||
};
|
||||
|
||||
struct Cat : Animal {};
|
||||
|
||||
BOOST_OPENMETHOD(
|
||||
poke, (boost::openmethod::virtual_ptr<Animal>, std::ostream&), void);
|
||||
|
||||
#endif // BOOST_OPENMETHOD_TEST_MIX_RELEASE_DEBUG_LIB_HPP
|
||||
23
test/mix_release_debug/main.cpp
Normal file
23
test/mix_release_debug/main.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2018-2025 Jean-Louis Leroy
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// See accompanying file LICENSE_1_0.txt
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_TEST_MODULE openmethod
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/initialize.hpp>
|
||||
|
||||
#include "lib.hpp"
|
||||
|
||||
using namespace boost::openmethod;
|
||||
|
||||
BOOST_AUTO_TEST_CASE(mix_release_debug) {
|
||||
default_registry::error_handler::set(
|
||||
[](const default_registry::error_handler::error_variant& error) {
|
||||
std::visit([](auto&& arg) { throw arg; }, error);
|
||||
});
|
||||
|
||||
BOOST_CHECK_THROW(initialize(), odr_violation);
|
||||
}
|
||||
85
test/test_class_registration.cpp
Normal file
85
test/test_class_registration.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
// 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)
|
||||
|
||||
#define BOOST_TEST_MODULE openmethod
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/policies/throw_error_handler.hpp>
|
||||
#include <boost/openmethod/initialize.hpp>
|
||||
|
||||
#include "test_util.hpp"
|
||||
|
||||
using namespace boost::openmethod;
|
||||
|
||||
struct Animal {
|
||||
virtual ~Animal() {
|
||||
}
|
||||
};
|
||||
|
||||
struct Dog : Animal {};
|
||||
struct Bulldog : Dog {};
|
||||
|
||||
namespace TEST_NS {
|
||||
|
||||
struct registry : test_registry_<__COUNTER__>::with<
|
||||
policies::runtime_checks, policies::throw_error_handler> {
|
||||
};
|
||||
|
||||
BOOST_OPENMETHOD(poke, (boost::openmethod::virtual_<Animal&>), void, registry);
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(poke, (Dog&), void) {
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_CLASSES(Animal, registry);
|
||||
|
||||
BOOST_AUTO_TEST_CASE(unknown_class_overrider) {
|
||||
BOOST_CHECK_THROW(initialize<registry>(), missing_class);
|
||||
}
|
||||
|
||||
} // namespace TEST_NS
|
||||
|
||||
|
||||
namespace TEST_NS {
|
||||
|
||||
struct registry : test_registry_<__COUNTER__>::with<
|
||||
policies::runtime_checks, policies::throw_error_handler> {
|
||||
};
|
||||
|
||||
BOOST_OPENMETHOD(poke, (boost::openmethod::virtual_<Animal&>), void, registry);
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(poke, (Dog&), void) {
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_CLASSES(Animal, registry);
|
||||
BOOST_OPENMETHOD_CLASSES(Dog, registry); // missing base class
|
||||
|
||||
BOOST_AUTO_TEST_CASE(missing_base_class) {
|
||||
BOOST_CHECK_THROW(initialize<registry>(), missing_base);
|
||||
}
|
||||
|
||||
} // namespace TEST_NS
|
||||
|
||||
|
||||
namespace TEST_NS {
|
||||
|
||||
struct registry : test_registry_<__COUNTER__>::with<
|
||||
policies::runtime_checks, policies::throw_error_handler> {
|
||||
};
|
||||
|
||||
BOOST_OPENMETHOD(poke, (boost::openmethod::virtual_<Animal&>), void, registry);
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(poke, (Dog&), void) {
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_CLASSES(Animal, Dog, registry);
|
||||
|
||||
BOOST_AUTO_TEST_CASE(unknown_class_call) {
|
||||
initialize<registry>();
|
||||
Bulldog hector;
|
||||
BOOST_CHECK_THROW(poke(hector), missing_class);
|
||||
}
|
||||
|
||||
} // namespace TEST_NS
|
||||
@@ -104,14 +104,14 @@ BOOST_AUTO_TEST_CASE(test_use_classes_linear) {
|
||||
struct D4 : D3 {};
|
||||
struct D5 : D4 {};
|
||||
|
||||
using policy = test_registry_<__COUNTER__>;
|
||||
struct registry : test_registry_<__COUNTER__> {};
|
||||
|
||||
BOOST_OPENMETHOD_CLASSES(Base, D1, D2, D3, policy);
|
||||
BOOST_OPENMETHOD_CLASSES(D2, D3, policy);
|
||||
BOOST_OPENMETHOD_CLASSES(D3, D4, policy);
|
||||
BOOST_OPENMETHOD_CLASSES(D4, D5, D3, policy);
|
||||
BOOST_OPENMETHOD_CLASSES(Base, D1, D2, D3, registry);
|
||||
BOOST_OPENMETHOD_CLASSES(D2, D3, registry);
|
||||
BOOST_OPENMETHOD_CLASSES(D3, D4, registry);
|
||||
BOOST_OPENMETHOD_CLASSES(D4, D5, D3, registry);
|
||||
|
||||
auto comp = policy::initialize();
|
||||
auto comp = initialize<registry>();
|
||||
|
||||
auto base = get_class<Base>(comp);
|
||||
auto d1 = get_class<D1>(comp);
|
||||
@@ -148,7 +148,7 @@ BOOST_AUTO_TEST_CASE(test_use_classes_diamond) {
|
||||
|
||||
std::vector<class_*> actual, expected;
|
||||
|
||||
auto comp = test_registry::initialize();
|
||||
auto comp = initialize<test_registry>();
|
||||
|
||||
auto a = get_class<A>(comp);
|
||||
auto b = get_class<B>(comp);
|
||||
@@ -239,7 +239,7 @@ BOOST_AUTO_TEST_CASE(test_assign_slots_a_b1_c) {
|
||||
BOOST_OPENMETHOD_REGISTER(use_classes<A, C, test_registry>);
|
||||
ADD_METHOD(B);
|
||||
|
||||
auto comp = test_registry::initialize();
|
||||
auto comp = initialize<test_registry>();
|
||||
|
||||
BOOST_TEST_REQUIRE(check(comp[m_B])->slots.size() == 1u);
|
||||
BOOST_TEST(check(comp[m_B])->slots[0] == 0u);
|
||||
@@ -269,7 +269,7 @@ BOOST_AUTO_TEST_CASE(test_assign_slots_a1_b1_c1) {
|
||||
ADD_METHOD(A);
|
||||
ADD_METHOD(B);
|
||||
ADD_METHOD(C);
|
||||
auto comp = test_registry::initialize();
|
||||
auto comp = initialize<test_registry>();
|
||||
|
||||
BOOST_TEST_REQUIRE(check(comp[m_A])->slots.size() == 1u);
|
||||
BOOST_TEST(check(comp[m_A])->slots[0] == 0u);
|
||||
@@ -310,7 +310,7 @@ BOOST_AUTO_TEST_CASE(test_assign_slots_a1_b1_d1_c1_d1) {
|
||||
ADD_METHOD(B);
|
||||
ADD_METHOD(C);
|
||||
ADD_METHOD(D);
|
||||
auto comp = test_registry::initialize();
|
||||
auto comp = initialize<test_registry>();
|
||||
|
||||
BOOST_TEST_REQUIRE(check(comp[m_A])->slots.size() == 1u);
|
||||
BOOST_TEST(check(comp[m_A])->slots[0] == 0u);
|
||||
@@ -361,7 +361,7 @@ BOOST_AUTO_TEST_CASE(test_assign_slots_a1_b1_d1_c1_d1_e2) {
|
||||
ADD_METHOD_N(E, 1);
|
||||
ADD_METHOD_N(E, 2);
|
||||
ADD_METHOD_N(E, 3);
|
||||
auto comp = test_registry::initialize();
|
||||
auto comp = initialize<test_registry>();
|
||||
|
||||
BOOST_TEST_REQUIRE(check(comp[m_A])->slots.size() == 1u);
|
||||
BOOST_TEST(check(comp[m_A])->slots[0] == 0u);
|
||||
@@ -415,7 +415,7 @@ BOOST_AUTO_TEST_CASE(test_assign_slots_a1_c1_b1) {
|
||||
ADD_METHOD(A);
|
||||
ADD_METHOD(B);
|
||||
ADD_METHOD(C);
|
||||
auto comp = test_registry::initialize();
|
||||
auto comp = initialize<test_registry>();
|
||||
|
||||
BOOST_TEST_REQUIRE(check(comp[m_A])->slots.size() == 1u);
|
||||
BOOST_TEST(check(comp[m_A])->slots[0] == 0u);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#define BOOST_TEST_MODULE core
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <boost/openmethod/registry.hpp>
|
||||
#include <boost/openmethod/preamble.hpp>
|
||||
|
||||
using namespace boost::openmethod;
|
||||
using namespace boost::openmethod::detail;
|
||||
@@ -17,7 +17,7 @@ namespace mp11 = boost::mp11;
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/inplace_vptr.hpp>
|
||||
#include <boost/openmethod/shared_ptr.hpp>
|
||||
#include <boost/openmethod/interop/std_shared_ptr.hpp>
|
||||
|
||||
#include "test_util.hpp"
|
||||
|
||||
@@ -269,41 +269,6 @@ static_assert(
|
||||
|
||||
} // namespace test_use_classes
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// static_slots
|
||||
|
||||
namespace test_static_slots {
|
||||
struct Animal;
|
||||
}
|
||||
|
||||
namespace boost::openmethod::detail {
|
||||
|
||||
template<>
|
||||
struct static_offsets<method<
|
||||
void,
|
||||
void(
|
||||
virtual_<test_static_slots::Animal&>,
|
||||
virtual_<test_static_slots::Animal&>)>> {
|
||||
static constexpr std::size_t slots[] = {0, 1};
|
||||
};
|
||||
|
||||
} // namespace boost::openmethod::detail
|
||||
|
||||
namespace test_static_slots {
|
||||
|
||||
struct Animal {
|
||||
virtual ~Animal() {
|
||||
}
|
||||
};
|
||||
|
||||
using poke = method<void, void(virtual_<Animal&>)>;
|
||||
static_assert(!has_static_offsets<poke>::value);
|
||||
|
||||
using meet = method<void, void(virtual_<Animal&>, virtual_<Animal&>)>;
|
||||
static_assert(has_static_offsets<meet>::value);
|
||||
|
||||
} // namespace test_static_slots
|
||||
|
||||
namespace TEST_NS {
|
||||
|
||||
struct Animal {
|
||||
@@ -330,7 +295,7 @@ static_assert(detail::has_vptr_fn<Animal, test_registry>);
|
||||
static_assert(!detail::has_vptr_fn<Animal, default_registry>);
|
||||
|
||||
BOOST_AUTO_TEST_CASE(vptr_from_function) {
|
||||
test_registry::initialize();
|
||||
initialize<test_registry>();
|
||||
BOOST_TEST(detail::acquire_vptr<test_registry>(Animal{}) == &value);
|
||||
}
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ BOOST_OPENMETHOD_OVERRIDE(poke, (Cat & cat, std::ostream& os), void) {
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(custom_rtti_simple_projection) {
|
||||
test_registry::initialize();
|
||||
initialize<test_registry>();
|
||||
|
||||
Animal &&a = Dog("Snoopy"), &&b = Cat("Sylvester");
|
||||
|
||||
@@ -204,7 +204,7 @@ BOOST_AUTO_TEST_CASE(custom_rtti_simple) {
|
||||
BOOST_TEST(Animal::static_type == 0u);
|
||||
BOOST_TEST(Dog::static_type == 1u);
|
||||
BOOST_TEST(Cat::static_type == 2u);
|
||||
test_registry::initialize();
|
||||
initialize<test_registry>();
|
||||
|
||||
Animal &&a = Dog("Snoopy"), &&b = Cat("Sylvester");
|
||||
|
||||
@@ -362,7 +362,7 @@ BOOST_AUTO_TEST_CASE(virtual_base) {
|
||||
BOOST_TEST(Animal::static_type == 0u);
|
||||
BOOST_TEST(Dog::static_type == 1u);
|
||||
BOOST_TEST(Cat::static_type == 2u);
|
||||
test_registry::initialize();
|
||||
initialize<test_registry>();
|
||||
|
||||
Animal &&a = Dog("Snoopy"), &&b = Cat("Sylvester");
|
||||
|
||||
@@ -497,7 +497,7 @@ BOOST_OPENMETHOD_OVERRIDE(meet, (Dog&, Dog&, std::ostream& os), void) {
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(custom_rtti_deferred) {
|
||||
test_registry::initialize();
|
||||
initialize<test_registry>();
|
||||
|
||||
Animal &&a = Dog("Snoopy"), &&b = Cat("Sylvester");
|
||||
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
#include <any>
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/shared_ptr.hpp>
|
||||
#include <boost/openmethod/unique_ptr.hpp>
|
||||
#include <boost/openmethod/interop/std_shared_ptr.hpp>
|
||||
#include <boost/openmethod/interop/std_unique_ptr.hpp>
|
||||
#include <boost/openmethod/initialize.hpp>
|
||||
#include <boost/openmethod/policies/vptr_vector.hpp>
|
||||
#include <boost/openmethod/policies/throw_error_handler.hpp>
|
||||
@@ -75,7 +75,7 @@ BOOST_OPENMETHOD_OVERRIDE(name, (const Dog& dog), std::string) {
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cast_args_lvalue_refs) {
|
||||
test_registry::initialize();
|
||||
initialize<test_registry>();
|
||||
|
||||
Dog spot("Spot");
|
||||
BOOST_TEST(name(spot) == "Bill's dog Spot");
|
||||
@@ -114,7 +114,7 @@ BOOST_OPENMETHOD_OVERRIDE(teleport, (Dog && dog), std::unique_ptr<Animal>) {
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cast_args_rvalue_refs) {
|
||||
test_registry::initialize();
|
||||
initialize<test_registry>();
|
||||
|
||||
{
|
||||
Dog spot("Spot");
|
||||
@@ -153,7 +153,7 @@ BOOST_OPENMETHOD_OVERRIDE(name, (const Dog* dog), std::string) {
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cast_args_pointer) {
|
||||
test_registry::initialize();
|
||||
initialize<test_registry>();
|
||||
|
||||
Dog spot("Spot");
|
||||
BOOST_TEST(name(&spot) == "Bill's dog Spot");
|
||||
@@ -186,7 +186,7 @@ BOOST_OPENMETHOD_OVERRIDE(name, (std::shared_ptr<const Dog> dog), std::string) {
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cast_args_shared_ptr_by_value) {
|
||||
test_registry::initialize();
|
||||
initialize<test_registry>();
|
||||
|
||||
auto spot = std::make_shared<Dog>("Spot");
|
||||
BOOST_TEST(name(spot) == "Bill's dog Spot");
|
||||
@@ -227,7 +227,7 @@ BOOST_OPENMETHOD_OVERRIDE(
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cast_args_shared_ptr_by_ref) {
|
||||
test_registry::initialize();
|
||||
initialize<test_registry>();
|
||||
|
||||
auto spot = std::make_shared<Dog>("Spot");
|
||||
BOOST_TEST(name(spot) == "Bill's dog Spot");
|
||||
@@ -260,7 +260,7 @@ BOOST_OPENMETHOD_OVERRIDE(name, (std::unique_ptr<Dog> dog), std::string) {
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cast_args_unique_ptr) {
|
||||
test_registry::initialize();
|
||||
initialize<test_registry>();
|
||||
|
||||
auto spot = std::make_unique<Dog>("Spot");
|
||||
BOOST_TEST(name(std::move(spot)) == "Bill's dog Spot");
|
||||
@@ -318,7 +318,7 @@ BOOST_OPENMETHOD_OVERRIDE(times, (const matrix&, double), string_pair) {
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(simple) {
|
||||
auto report = test_registry::initialize().report;
|
||||
auto report = initialize<test_registry>().report;
|
||||
BOOST_TEST(report.not_implemented == 0u);
|
||||
BOOST_TEST(report.ambiguous == 0u);
|
||||
|
||||
@@ -339,7 +339,7 @@ BOOST_AUTO_TEST_CASE(simple) {
|
||||
if constexpr (std::is_same_v<test_registry::vptr, policies::vptr_vector>) {
|
||||
BOOST_TEST(
|
||||
!detail::vptr_vector_vptrs<test_registry::registry_type>.empty());
|
||||
finalize<test_registry>();
|
||||
test_registry::finalize();
|
||||
static_assert(detail::has_finalize_aux<
|
||||
test_registry::policy<policies::vptr>>::value);
|
||||
BOOST_TEST(
|
||||
@@ -439,7 +439,7 @@ BOOST_OPENMETHOD_OVERRIDE(foo, (Test&), std::pair<int, int>) {
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(comma_in_return_type) {
|
||||
test_registry::initialize();
|
||||
initialize<test_registry>();
|
||||
|
||||
Test test;
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ struct test_registry : bom::default_registry::without<
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/inplace_vptr.hpp>
|
||||
#include <boost/openmethod/shared_ptr.hpp>
|
||||
#include <boost/openmethod/interop/std_shared_ptr.hpp>
|
||||
#include <boost/openmethod/initialize.hpp>
|
||||
|
||||
#define BOOST_TEST_MODULE intrusive
|
||||
@@ -25,25 +25,25 @@ struct test_registry : bom::default_registry::without<
|
||||
namespace bom = boost::openmethod;
|
||||
using bom::virtual_;
|
||||
|
||||
struct Animal : bom::inplace_vptr<Animal> {
|
||||
struct Animal : bom::inplace_vptr_base<Animal> {
|
||||
explicit Animal(std::ostream& os);
|
||||
~Animal();
|
||||
std::ostream& os;
|
||||
};
|
||||
|
||||
struct Cat : Animal, bom::inplace_vptr<Cat, Animal> {
|
||||
struct Cat : Animal, bom::inplace_vptr_derived<Cat, Animal> {
|
||||
explicit Cat(std::ostream& os);
|
||||
~Cat();
|
||||
};
|
||||
|
||||
struct Pet : bom::inplace_vptr<Pet> {
|
||||
struct Pet : bom::inplace_vptr_base<Pet> {
|
||||
explicit Pet(std::ostream& os);
|
||||
~Pet();
|
||||
std::string name;
|
||||
std::ostream& os;
|
||||
};
|
||||
|
||||
struct DomesticCat : Cat, Pet, bom::inplace_vptr<DomesticCat, Cat, Pet> {
|
||||
struct DomesticCat : Cat, Pet, bom::inplace_vptr_derived<DomesticCat, Cat, Pet> {
|
||||
explicit DomesticCat(std::ostream& os);
|
||||
~DomesticCat();
|
||||
};
|
||||
@@ -181,7 +181,7 @@ BOOST_AUTO_TEST_CASE(intrusive_mode) {
|
||||
|
||||
struct indirect_policy : test_registry::with<bom::policies::indirect_vptr> {};
|
||||
|
||||
struct Indirect : bom::inplace_vptr<Indirect, indirect_policy> {};
|
||||
struct Indirect : bom::inplace_vptr_base<Indirect, indirect_policy> {};
|
||||
|
||||
BOOST_OPENMETHOD(whatever, (virtual_<Indirect&>), void, indirect_policy);
|
||||
|
||||
@@ -189,7 +189,7 @@ BOOST_OPENMETHOD_OVERRIDE(whatever, (Indirect&), void) {
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(core_intrusive_vptr) {
|
||||
indirect_policy::initialize();
|
||||
bom::initialize<indirect_policy>();
|
||||
Indirect i;
|
||||
BOOST_TEST(
|
||||
boost_openmethod_vptr(i, nullptr) ==
|
||||
@@ -10,8 +10,8 @@
|
||||
#include <any>
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/shared_ptr.hpp>
|
||||
#include <boost/openmethod/unique_ptr.hpp>
|
||||
#include <boost/openmethod/interop/std_shared_ptr.hpp>
|
||||
#include <boost/openmethod/interop/std_unique_ptr.hpp>
|
||||
#include <boost/openmethod/initialize.hpp>
|
||||
#include <boost/openmethod/policies/vptr_vector.hpp>
|
||||
|
||||
@@ -26,13 +26,13 @@ namespace TEST_NS {
|
||||
|
||||
using namespace test_matrices;
|
||||
|
||||
struct n2216 : test_registry_<__COUNTER__>::with<policies::n2216> {};
|
||||
struct test_registry : test_registry_<__COUNTER__> {};
|
||||
|
||||
BOOST_OPENMETHOD_CLASSES(matrix, dense_matrix, n2216);
|
||||
BOOST_OPENMETHOD_CLASSES(matrix, dense_matrix, test_registry);
|
||||
|
||||
BOOST_OPENMETHOD(
|
||||
times, (virtual_<const matrix&>, virtual_<const matrix&>),
|
||||
std::unique_ptr<matrix>, n2216);
|
||||
std::unique_ptr<matrix>, test_registry);
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
times, (const dense_matrix&, const matrix&),
|
||||
@@ -46,13 +46,13 @@ BOOST_OPENMETHOD_OVERRIDE(
|
||||
}
|
||||
|
||||
static_assert(std::is_same_v<
|
||||
detail::virtual_type<std::unique_ptr<matrix>, n2216>, matrix>);
|
||||
detail::virtual_type<std::unique_ptr<matrix>, test_registry>, matrix>);
|
||||
|
||||
BOOST_AUTO_TEST_CASE(covariant_return_type) {
|
||||
auto compiler = n2216::initialize();
|
||||
auto compiler = boost::openmethod::initialize<test_registry, n2216>();
|
||||
BOOST_TEST(compiler.report.ambiguous == 0u);
|
||||
|
||||
// N2216: use covariant return types to resolve ambiguity.
|
||||
// test_registry: use covariant return types to resolve ambiguity.
|
||||
dense_matrix left, right;
|
||||
auto result = times(left, right);
|
||||
BOOST_TEST(result->type == DENSE_MATRIX);
|
||||
@@ -64,13 +64,13 @@ namespace TEST_NS {
|
||||
|
||||
using namespace test_matrices;
|
||||
|
||||
struct n2216 : test_registry_<__COUNTER__>::with<policies::n2216> {};
|
||||
struct test_registry : test_registry_<__COUNTER__> {};
|
||||
|
||||
BOOST_OPENMETHOD_CLASSES(matrix, dense_matrix, n2216);
|
||||
BOOST_OPENMETHOD_CLASSES(matrix, dense_matrix, test_registry);
|
||||
|
||||
BOOST_OPENMETHOD(
|
||||
times, (virtual_<const matrix&>, virtual_<const matrix&>), string_pair,
|
||||
n2216);
|
||||
test_registry);
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(times, (const matrix&, const matrix&), string_pair) {
|
||||
return string_pair(MATRIX_MATRIX, NONE);
|
||||
@@ -87,10 +87,10 @@ BOOST_OPENMETHOD_OVERRIDE(
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(pick_any_ambiguous) {
|
||||
auto compiler = n2216::initialize();
|
||||
auto compiler = boost::openmethod::initialize<test_registry, n2216>();
|
||||
BOOST_TEST(compiler.report.ambiguous == 1u);
|
||||
|
||||
// N2216: use covariant return types to resolve ambiguity.
|
||||
// test_registry: use covariant return types to resolve ambiguity.
|
||||
dense_matrix left, right;
|
||||
auto result = times(left, right);
|
||||
BOOST_TEST(result.first == MATRIX_DENSE);
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/registry.hpp>
|
||||
#include <boost/openmethod/preamble.hpp>
|
||||
#include <boost/openmethod/policies/throw_error_handler.hpp>
|
||||
#include <boost/openmethod/initialize.hpp>
|
||||
#include <boost/openmethod/unique_ptr.hpp>
|
||||
#include <boost/openmethod/interop/std_unique_ptr.hpp>
|
||||
|
||||
#include "test_util.hpp"
|
||||
|
||||
@@ -35,7 +35,7 @@ struct errors_ : test_registry_<N, capture_output> {
|
||||
|
||||
capture() {
|
||||
prev = error_handler::set(
|
||||
[this](const policies::default_error_handler::error_variant&
|
||||
[this](const typename errors_::error_handler::error_variant&
|
||||
error) {
|
||||
prev(error);
|
||||
std::visit([](auto&& arg) { throw arg; }, error);
|
||||
@@ -51,13 +51,13 @@ struct errors_ : test_registry_<N, capture_output> {
|
||||
return output::os.str();
|
||||
}
|
||||
|
||||
policies::default_error_handler::function_type prev;
|
||||
typename errors_::error_handler::function_type prev;
|
||||
};
|
||||
};
|
||||
|
||||
namespace TEST_NS {
|
||||
|
||||
using registry = errors_<__COUNTER__>;
|
||||
struct registry : errors_<__COUNTER__> {};
|
||||
|
||||
BOOST_OPENMETHOD(
|
||||
transpose, (virtual_ptr<const matrix, registry>), void, registry);
|
||||
@@ -66,7 +66,7 @@ BOOST_OPENMETHOD_OVERRIDE(
|
||||
transpose, (virtual_ptr<const diagonal_matrix, registry>), void) {
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(not_initialized) {
|
||||
BOOST_AUTO_TEST_CASE(no_initialization) {
|
||||
if constexpr (registry::has_runtime_checks) {
|
||||
// throw during virtual_ptr construction, because of hash table lookup
|
||||
{
|
||||
@@ -74,7 +74,7 @@ BOOST_AUTO_TEST_CASE(not_initialized) {
|
||||
BOOST_CHECK_THROW(
|
||||
(unique_virtual_ptr<matrix, registry>{
|
||||
std::make_unique<diagonal_matrix>()}),
|
||||
not_initialized_error);
|
||||
not_initialized);
|
||||
BOOST_TEST(capture() == "not initialized\n");
|
||||
}
|
||||
|
||||
@@ -83,12 +83,12 @@ BOOST_AUTO_TEST_CASE(not_initialized) {
|
||||
registry::capture capture;
|
||||
BOOST_CHECK_THROW(
|
||||
transpose(make_unique_virtual<diagonal_matrix, registry>()),
|
||||
not_initialized_error);
|
||||
not_initialized);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
registry::check_initialized();
|
||||
} catch (not_initialized_error&) {
|
||||
registry::require_initialized();
|
||||
} catch (not_initialized&) {
|
||||
BOOST_TEST_FAIL("should have not thrown in release variant");
|
||||
}
|
||||
}
|
||||
@@ -112,7 +112,7 @@ BOOST_AUTO_TEST_CASE(initialize_unknown_class) {
|
||||
if constexpr (registry::has_runtime_checks) {
|
||||
{
|
||||
registry::capture capture;
|
||||
BOOST_CHECK_THROW(registry::initialize(), unknown_class_error);
|
||||
BOOST_CHECK_THROW(initialize<registry>(), missing_class);
|
||||
BOOST_TEST(capture().find("unknown class") != std::string::npos);
|
||||
}
|
||||
}
|
||||
@@ -136,10 +136,10 @@ BOOST_OPENMETHOD_OVERRIDE(transpose, (const matrix&), void) {
|
||||
BOOST_AUTO_TEST_CASE(call_unknown_class) {
|
||||
if constexpr (registry::has_runtime_checks) {
|
||||
{
|
||||
registry::initialize();
|
||||
initialize<registry>();
|
||||
|
||||
registry::capture capture;
|
||||
BOOST_CHECK_THROW(transpose(dense_matrix()), unknown_class_error);
|
||||
BOOST_CHECK_THROW(transpose(dense_matrix()), missing_class);
|
||||
BOOST_TEST(capture().find("unknown class") != std::string::npos);
|
||||
}
|
||||
}
|
||||
@@ -165,21 +165,21 @@ BOOST_OPENMETHOD_OVERRIDE(
|
||||
times, (const diagonal_matrix&, const matrix&), void) {
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(call_error) {
|
||||
auto report = registry::initialize().report;
|
||||
BOOST_AUTO_TEST_CASE(bad_call) {
|
||||
auto report = initialize<registry>().report;
|
||||
BOOST_TEST(report.not_implemented == 1u);
|
||||
BOOST_TEST(report.ambiguous == 1u);
|
||||
|
||||
{
|
||||
registry::capture capture;
|
||||
BOOST_CHECK_THROW(times(matrix(), matrix()), not_implemented_error);
|
||||
BOOST_CHECK_THROW(times(matrix(), matrix()), no_overrider);
|
||||
BOOST_TEST(capture().find("not implemented") != std::string::npos);
|
||||
}
|
||||
|
||||
{
|
||||
registry::capture capture;
|
||||
BOOST_CHECK_THROW(
|
||||
times(diagonal_matrix(), diagonal_matrix()), ambiguous_error);
|
||||
times(diagonal_matrix(), diagonal_matrix()), ambiguous_call);
|
||||
BOOST_TEST(capture().find("ambiguous") != std::string::npos);
|
||||
}
|
||||
}
|
||||
@@ -198,7 +198,7 @@ BOOST_OPENMETHOD(
|
||||
times, (virtual_<const matrix&>, virtual_<const matrix&>), void, registry);
|
||||
|
||||
BOOST_AUTO_TEST_CASE(throw_error) {
|
||||
registry::initialize();
|
||||
initialize<registry>();
|
||||
|
||||
try {
|
||||
times(matrix(), matrix());
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// See accompanying file LICENSE_1_0.txt
|
||||
// or q at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/openmethod/shared_ptr.hpp>
|
||||
#include <boost/openmethod/interop/std_shared_ptr.hpp>
|
||||
|
||||
#define BOOST_TEST_MODULE openmethod
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
@@ -15,7 +15,7 @@ struct static_registry
|
||||
#define BOOST_OPENMETHOD_DEFAULT_REGISTRY static_registry
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/unique_ptr.hpp>
|
||||
#include <boost/openmethod/interop/std_unique_ptr.hpp>
|
||||
#include <boost/openmethod/initialize.hpp>
|
||||
|
||||
struct Animal {};
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// See accompanying file LICENSE_1_0.txt
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/openmethod/unique_ptr.hpp>
|
||||
#include <boost/openmethod/interop/std_unique_ptr.hpp>
|
||||
|
||||
#define BOOST_TEST_MODULE openmethod
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/shared_ptr.hpp>
|
||||
#include <boost/openmethod/unique_ptr.hpp>
|
||||
#include <boost/openmethod/interop/std_shared_ptr.hpp>
|
||||
#include <boost/openmethod/interop/std_unique_ptr.hpp>
|
||||
#include <boost/openmethod/initialize.hpp>
|
||||
|
||||
#include <iostream>
|
||||
@@ -220,7 +220,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(
|
||||
BOOST_OPENMETHOD_REGISTER(typename poke::template override<
|
||||
poke_bear<virtual_ptr<Player, Registry>>>);
|
||||
|
||||
Registry::initialize();
|
||||
initialize<Registry>();
|
||||
|
||||
using vptr_player = virtual_ptr<Player, Registry>;
|
||||
static_assert(detail::is_virtual_ptr<vptr_player>);
|
||||
@@ -248,13 +248,6 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(
|
||||
};
|
||||
|
||||
upcast::fn(virtual_bear_ptr);
|
||||
|
||||
// Registry::finalize();
|
||||
// Registry::initialize();
|
||||
|
||||
// BOOST_TEST(
|
||||
// (virtual_bear_ptr.vptr() == Registry::template static_vptr<Bear>) ==
|
||||
// Registry::has_indirect_vptr);
|
||||
}
|
||||
} // namespace BOOST_OPENMETHOD_GENSYM
|
||||
|
||||
@@ -284,7 +277,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(
|
||||
virtual_ptr<Player, Registry>, virtual_ptr<Object, Registry>,
|
||||
virtual_ptr<Player, Registry>>>);
|
||||
|
||||
Registry::initialize();
|
||||
initialize<Registry>();
|
||||
|
||||
Bear bear;
|
||||
BOOST_TEST(poke::fn(virtual_ptr<Player, Registry>(bear)) == "growl");
|
||||
@@ -329,7 +322,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(
|
||||
shared_virtual_ptr<Object, Registry>,
|
||||
shared_virtual_ptr<Player, Registry>>>);
|
||||
|
||||
Registry::initialize();
|
||||
initialize<Registry>();
|
||||
|
||||
auto bear = make_shared_virtual<Bear, Registry>();
|
||||
auto warrior = make_shared_virtual<Warrior, Registry>();
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// or q at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/shared_ptr.hpp>
|
||||
#include <boost/openmethod/interop/std_shared_ptr.hpp>
|
||||
#include <boost/openmethod/initialize.hpp>
|
||||
|
||||
#define BOOST_TEST_MODULE openmethod
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <boost/openmethod.hpp>
|
||||
#include <boost/openmethod/policies/vptr_map.hpp>
|
||||
#include <boost/openmethod/initialize.hpp>
|
||||
#include <boost/openmethod/unique_ptr.hpp>
|
||||
#include <boost/openmethod/interop/std_unique_ptr.hpp>
|
||||
|
||||
#include "test_util.hpp"
|
||||
|
||||
@@ -42,7 +42,7 @@ void init_test() {
|
||||
BOOST_OPENMETHOD_REGISTER(use_classes<Animal, Cat, Dog, Registry>);
|
||||
struct id;
|
||||
(void)&method<id, auto(virtual_ptr<Animal, Registry>)->void, Registry>::fn;
|
||||
Registry::initialize();
|
||||
initialize<Registry>();
|
||||
}
|
||||
|
||||
struct direct_vector : test_registry_<__COUNTER__> {};
|
||||
@@ -73,11 +73,6 @@ struct check_illegal_smart_ops {
|
||||
!std::is_constructible_v<
|
||||
virtual_ptr<smart_ptr<Animal>, Registry>, smart_ptr<const Animal>>);
|
||||
|
||||
// policies must be the same
|
||||
static_assert(!std::is_constructible_v<
|
||||
virtual_ptr<smart_ptr<Animal>, debug_registry>,
|
||||
virtual_ptr<smart_ptr<Animal>, release_registry>>);
|
||||
|
||||
// a smart virtual_ptr cannot be constructed from a plain reference or
|
||||
// pointer
|
||||
static_assert(!std::is_constructible_v<
|
||||
|
||||
Reference in New Issue
Block a user