mirror of
https://github.com/boostorg/openmethod.git
synced 2026-01-19 04:22:12 +00:00
after boost review
This commit is contained in:
10
dev/local-flat.sh
Executable file
10
dev/local-flat.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
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/compiler.hpp
|
||||
python3 dev/flatten.py \
|
||||
flat/boost/openmethod/policies.hpp \
|
||||
include/boost/openmethod/policies.hpp
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
### Synopsis
|
||||
|
||||
Defined in <boost/openmethod/policies/basic_policy.hpp>.
|
||||
|
||||
```c++
|
||||
namespace boost::openmethod {
|
||||
|
||||
@@ -18,14 +16,11 @@ struct basic_policy : abstract_policy, domain<Policy>, Facets... {
|
||||
template<class NewPolicy>
|
||||
using fork = /*unspecified*/;
|
||||
|
||||
template<class... MoreFacets>
|
||||
using add = /*unspecified*/;
|
||||
template<class... Facets>
|
||||
using with = /*unspecified*/;
|
||||
|
||||
template<class Base, class Facet>
|
||||
using replace = /*unspecified*/;
|
||||
|
||||
template<class Base>
|
||||
using remove = /*unspecified*/;
|
||||
template<class... Facets>
|
||||
using without = /*unspecified*/;
|
||||
};
|
||||
|
||||
struct release : basic_policy<release, ...> {};
|
||||
@@ -43,6 +38,11 @@ using default_policy = policies::debug;
|
||||
} // boost::openmethod
|
||||
```
|
||||
|
||||
### Headers
|
||||
|
||||
Defined in <boost/openmethod/policies/basic_policy.hpp>. Also available via
|
||||
`<boost/openmethod/core.hpp>` and `<boost/openmethod.hpp>`.
|
||||
|
||||
### Description
|
||||
|
||||
`basic_policy` implements a policy, which consists of a a collection of methods,
|
||||
@@ -50,10 +50,8 @@ classes, dispatch data, and facets, which specify how to obtain a pointer to a
|
||||
v-table from an object, how to report errors, whether to perform runtime sanity
|
||||
checks, etc.
|
||||
|
||||
Some of these functionalities require static variables local to the policy.
|
||||
Forthis reason, `basic_policy` uses the CRTP pattern to provide ensure that two
|
||||
different policies - and the facets they contain - get their own copies of the
|
||||
static state.
|
||||
`basic_policy` has state. It uses the Curiously Recurring Template Pattern to
|
||||
allow distinct policies to have distinct sets of static variables.
|
||||
|
||||
### Members
|
||||
|
||||
@@ -73,46 +71,56 @@ template<class NewPolicy>
|
||||
using fork;
|
||||
```
|
||||
|
||||
Creates a new policy from an existing one. _NewPolicy_, and the facets it
|
||||
contains, do not share static variables with the original _Policy_. The new
|
||||
policy does not retain any knowledge of the classes and methods registered in
|
||||
the original.
|
||||
Creates a new policy from an existing one. _NewPolicy_ does not share static
|
||||
variables with the original _Policy_. The new policy does not retain any
|
||||
knowledge of the classes and methods registered in the original.
|
||||
|
||||
#### add
|
||||
`fork` forks the facets in the policy as well: any facet instantiated from a
|
||||
class template is assumed to take a policy as its first template argument. The
|
||||
template is re-instantiated with the new policy as the first arguments, while
|
||||
the other arguments remain the same.
|
||||
|
||||
#### with
|
||||
|
||||
```c++
|
||||
template<class... MoreFacets>
|
||||
using add;
|
||||
template<class... Facets>
|
||||
using with;
|
||||
```
|
||||
|
||||
Creates a new policy by adding _MoreFacets_ to the original policy's collection
|
||||
of facets. The original policy and the new one share static variables.
|
||||
Requires:: _Facets_ is a list of classes that derive from `facet`.
|
||||
|
||||
#### replace
|
||||
Returns:: A new policy containing _Facets_, and the facets from the original
|
||||
that do not have the same category as _Facets_.
|
||||
|
||||
Examples::
|
||||
* `struct dyn_load : default_policy::fork<dyn_load>::with<indirect_vptr> {};` +
|
||||
Creates a policy just like `default_policy`, with an extra indirection added
|
||||
to the v-table pointers. This policy is suitable for use with dynamic loading.
|
||||
* `struct release_with_diags : release::fork<release_with_diags>::with<basic_error_output<release_with_diags>> {};` +
|
||||
Creates a policy just like `release`, except that it prints a diagnostic
|
||||
message before terminating with `abort()`.
|
||||
* `struct default_throw : default_policy::fork<default_throw>::with<throw_error_handler> {};` +
|
||||
Creates a policy just like `default_policy`, except that it reports errors by
|
||||
throwing exceptions, instead of calling a `std::function` like the default
|
||||
error handler does.
|
||||
|
||||
#### without
|
||||
|
||||
```c++
|
||||
template<class Base, class NewFacet>
|
||||
using replace;
|
||||
template<class... Facets>
|
||||
using without;
|
||||
```
|
||||
|
||||
Creates a new policy by replacing the facet in _Policy_ that derives from _Base_
|
||||
with _NewFacet_. It is not an error if _policy_ does not contain such a facet;
|
||||
in that case, the new policy contains the same facet as the original one.
|
||||
Requires:: _Facets_ is a list of facet categories.
|
||||
|
||||
The original policy and the new one share static variables.
|
||||
Returns:: A new policy containing the facets from the original that do not have
|
||||
the same category as _Facets_.
|
||||
|
||||
#### remove
|
||||
|
||||
```c++
|
||||
template<class Base>
|
||||
using remove;
|
||||
```
|
||||
|
||||
Creates a new policy by removing the facet in _Policy_ that derives from _Base_.
|
||||
It is not an error if _policy_ does not contain such a facet; in that case, the
|
||||
new policy contains the same facet as the original one.
|
||||
|
||||
The original policy and the new one share static variables.
|
||||
Examples::
|
||||
* `struct use_map : default_policy::fork<use_map>::with<vptr_map<use_map>>::without<type_hash> {};` +
|
||||
Creates a policy just like `default_policy`, except that it stores pointers to
|
||||
v-table in a `std::unordered_map`. Also removes the hash function, since it
|
||||
will not be used.
|
||||
|
||||
### Non-members
|
||||
|
||||
@@ -122,8 +130,8 @@ The original policy and the new one share static variables.
|
||||
struct release;
|
||||
```
|
||||
|
||||
A policy that contains facet implementations `std_rtti`, `fast_perfect_hash`,
|
||||
`vptr_vector` and `vectored_error_handler`.
|
||||
A policy that contains facets `std_rtti`, `fast_perfect_hash`, `vptr_vector` and
|
||||
`vectored_error_handler`.
|
||||
|
||||
#### debug
|
||||
|
||||
|
||||
@@ -27,10 +27,9 @@ include::{examplesdir}/dl.hpp[tag=header]
|
||||
NOTE: The policy must be passed to the method as well as the
|
||||
`virtual_ptr`{empty}s.
|
||||
|
||||
The `indirect_vptr` facet tells `virtual_ptr` to use a _reference_ to the vptr,
|
||||
instead of its value. Even tough the value of the vptr changes when `initialize`
|
||||
is called, the vptrs are stored in the same place (the policy's
|
||||
`static_vptr<Class>` variables).
|
||||
The `indirect_vptr` facet tells `virtual_ptr` to use a pointer to the vptr. Even
|
||||
tough the value of the vptr changes when `initialize` is called, the vptrs are
|
||||
stored in the same place (the policy's `static_vptr<Class>` variables).
|
||||
|
||||
We can now register the classes and and provide an overrider:
|
||||
|
||||
@@ -39,10 +38,6 @@ We can now register the classes and and provide an overrider:
|
||||
include::{examplesdir}/dl_main.cpp[tag=main]
|
||||
----
|
||||
|
||||
It is not necessary to pass the policy to `BOOST_OPENMETHOD_CLASSES`, because
|
||||
`indirect_vptr` does not have any state. As for `BOOST_OPENMETHOD_OVERRIDE`, it
|
||||
deduces the policy from the method.
|
||||
|
||||
At this point we only have one overrider. Animals of all species ignore one
|
||||
another:
|
||||
|
||||
|
||||
@@ -6,17 +6,14 @@
|
||||
Defined in <boost/openmethod/policies/basic_policy.hpp>.
|
||||
|
||||
```c++
|
||||
namespace boost::openmethod::policies {
|
||||
|
||||
namespace boost::openmethod {
|
||||
|
||||
namespace policies {
|
||||
|
||||
struct error_handler;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Defined in <boost/openmethod/types.hpp>.
|
||||
|
||||
```c++
|
||||
namespace boost::openmethod {
|
||||
|
||||
struct openmethod_error {};
|
||||
|
||||
@@ -40,7 +37,7 @@ struct type_mismatch_error : openmethod_error {
|
||||
type_id type;
|
||||
};
|
||||
|
||||
} // boost::openmethod::policies
|
||||
}
|
||||
```
|
||||
|
||||
### Description
|
||||
|
||||
@@ -23,7 +23,7 @@ include::{examplesdir}/friendship.cpp[tag=friend_all]
|
||||
Be aware, though, that the overriders of _any_ method called `poke` - with any
|
||||
signature - are granted friendship.
|
||||
|
||||
We can also befriendto individual overriders:
|
||||
We can also befriend individual overriders:
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
## Headers and Namespaces
|
||||
|
||||
Most real-life programs will be organized in multiple files and multiple
|
||||
namespaces. OpenMethod interacts with headers and namespaces very naturally,
|
||||
unless using-directives are avoided. In that case, there are a few things to be
|
||||
aware of.
|
||||
namespaces. OpenMethod interacts with headers and namespaces naturally, if
|
||||
using-directives are avoided. In that case, there are a few things to be aware
|
||||
of.
|
||||
|
||||
Let's break the Animals example into headers and namespaces. First we put
|
||||
`Animal` in its own header and namespace:
|
||||
@@ -27,7 +27,7 @@ it is "called" only in a non-evaluated context.
|
||||
* It defines an inline function with the same name and signature as the
|
||||
method (with the `virtual_` decorators stripped).
|
||||
|
||||
Next, let's implement the `Cat` class, and a derived class, `Chhetah`, in the
|
||||
Next, let's implement the `Cat` class, and a derived class, `Cheetah`, in the
|
||||
`felines` namespace:
|
||||
|
||||
[source,c++]
|
||||
@@ -51,7 +51,7 @@ in scope, or with qualified names.
|
||||
as the overrider itself. It "calls" the guide function in a non-evaluated
|
||||
context, passing it a `std::ostream&` and a `virtual_ptr<Cat>`. The return type
|
||||
of the guide function is the method to add the overrider to. Exactly one guide
|
||||
function must match. The normal rules of overload resolution apply. In this
|
||||
function must match. The normal rules of overload resolution apply. In that
|
||||
case, the guide function is found via argument dependant lookup (ADL).
|
||||
|
||||
The macro adds several constructs to the current namespace:
|
||||
@@ -140,7 +140,7 @@ BOOST_OPENMETHOD_OVERRIDE(
|
||||
|
||||
...will fail to compile, with an error like "reference to
|
||||
'poke_boost_openmethod_overriders' is ambiguous". That is because the overrider
|
||||
containers exist in both the canides and felides namespaces, with the same name.
|
||||
containers exist in both the canines and felines namespaces, with the same name.
|
||||
|
||||
Finally, the names passed as first arguments to the BOOST_OPENMETHOD and
|
||||
BOOST_OPENMETHOD_OVERRIDE macros must be identifiers. Qualified names are not
|
||||
|
||||
@@ -96,8 +96,3 @@ reference, because `virtual_ptr` has a conversion constructor for that:
|
||||
----
|
||||
include::{examplesdir}/hello_world.cpp[tag=call]
|
||||
----
|
||||
|
||||
NOTE: `virtual_ptr` is more like a reference than a pointer: it cannot be null,
|
||||
and it cannot be re-assigned. The only reason why it is not called `virtual_ref`
|
||||
is to save the name in case it becomes possible to overload the dot operator in
|
||||
future versions of C++.
|
||||
|
||||
6348
doc/html/index.html
Normal file
6348
doc/html/index.html
Normal file
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@ Defined in `<boost/openmethod/compiler.hpp>`.
|
||||
namespace boost::openmethod {
|
||||
|
||||
template<class Policy = BOOST_OPENMETHOD_DEFAULT_POLICY>
|
||||
auto compiler<Policy>::initialize() -> /*unspecified*/;
|
||||
auto initialize() -> /*unspecified*/;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
@@ -10,26 +10,27 @@ Class templates `use_classes`, `method`, `virtual_ptr`, and macros
|
||||
argument, a policy class, which defaults to `policies::debug` in debug builds,
|
||||
and `policies::release` in release builds.
|
||||
|
||||
A policy has a collection of _facets_. Facets control how type information is
|
||||
obtained, how vptrs are fetched, how errors are handled and printed, etc. Some
|
||||
are used in `initialize` and method dispatch; some are used by other facets in
|
||||
the same policy as part of their implementation. See the reference for a list of
|
||||
facets and stock implementations. Policies and facets are placed in the
|
||||
`boost::openmethod::policies` namespace. Two policies are provided by the
|
||||
A policy has a collection of _facets_. Each facet belongs to a facet category. A
|
||||
policy may contain at most one facet of a given category. Facets control how
|
||||
type information is obtained, how vptrs are fetched, how errors are handled and
|
||||
printed, etc. Some are used in `initialize` and method dispatch; some are used
|
||||
by other facets in the same policy as part of their implementation. See the
|
||||
reference for the list of facets. Policies and facets are placed in the
|
||||
`boost::openmethod::policies` namespace. Two stock policies are provided by the
|
||||
library: `release` and `debug`.
|
||||
|
||||
`release` contains the following facets:
|
||||
The `release` policy contains the following facets:
|
||||
|
||||
[cols="1,1,1"]
|
||||
|===
|
||||
|facet |implementations |role
|
||||
|facet category |facet |role
|
||||
|
||||
| rtti
|
||||
| std_rtti, minimal_rtti
|
||||
| std_rtti
|
||||
| provides type information for classes and objects
|
||||
|
||||
| extern_vptr
|
||||
| vptr_vector, vptr_map
|
||||
| vptr_vector
|
||||
| stores vptrs in an indexed collection
|
||||
|
||||
| type_hash
|
||||
@@ -37,16 +38,16 @@ library: `release` and `debug`.
|
||||
| hash type id to an index in a vector
|
||||
|
||||
| error_handler
|
||||
| vectored_error_handler, throw_error_handler
|
||||
| vectored_error_handler
|
||||
| handles errors
|
||||
|
||||
|===
|
||||
|
||||
`policies::debug` contains the same facets as `release`, plus a few more:
|
||||
The `debug` policy contains the same facets as `release`, plus a few more:
|
||||
|
||||
[cols="1,1,1"]
|
||||
|===
|
||||
|facet |implementation |role
|
||||
|facet category |facet |role
|
||||
|
||||
| runtime_checks
|
||||
| (itself)
|
||||
@@ -65,16 +66,18 @@ library: `release` and `debug`.
|
||||
Policies, and some facets, have static variables. When it is the case, they are
|
||||
implemented as CRTP classes.
|
||||
|
||||
Policies can be created from scratch, using the `basic_policy` template, or by
|
||||
adding or removing facets from existing policies. For example, `policies::debug`
|
||||
is a tweak of `policies::release`:
|
||||
Policies can be created from scratch, using the `basic_policy` template, or
|
||||
constructed from existing policies by adding and removing facets. For example,
|
||||
`policies::debug` is a tweak of `policies::release`:
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
namespace boost::openmethod::policies {
|
||||
|
||||
struct debug : release::add<
|
||||
runtime_checks, basic_error_output<debug>, basic_trace_output<debug>> {};
|
||||
struct debug : release::fork<debug>::with<
|
||||
runtime_checks, basic_error_output<debug>,
|
||||
basic_trace_output<debug>> {};
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
@@ -85,4 +88,4 @@ be overriden by defining the macroprocessor symbol
|
||||
`<boost/openmethod/core.hpp>`. The value of the symbol is used as a default
|
||||
template parameter for `use_classes`, `method`, `virtual_ptr`, and others. Once
|
||||
the `core` header has been included, changing `BOOST_OPENMETHOD_DEFAULT_POLICY`
|
||||
has no effect. See below for examples.
|
||||
has no effect.
|
||||
|
||||
@@ -8,8 +8,8 @@ namespace boost::openmethod::policies {
|
||||
|
||||
### Synopsis
|
||||
|
||||
template<class Policy, class Facet = void, class Map = /* unspecified */>
|
||||
class vptr_map : extern_vptr, Facet /* if not void */ {
|
||||
template<class Policy, class MapAdaptor = mp11::mp_quote<std::unordered_map>>
|
||||
class vptr_map : public extern_vptr {
|
||||
public:
|
||||
template<typename ForwardIterator>
|
||||
static auto register_vptrs(ForwardIterator first, ForwardIterator last) -> void;
|
||||
@@ -24,16 +24,12 @@ class vptr_map : extern_vptr, Facet /* if not void */ {
|
||||
### Description
|
||||
|
||||
`vptr_map` is an implementation of `external_vptr that stores the pointers to
|
||||
the v-tables in a map.
|
||||
the v-tables in a map. If `Policy` contains `indirect_vptr`, a level of
|
||||
indirection is added, making the policy usable in presence of dynamic loading.
|
||||
|
||||
`Policy` is the policy containing the facet.
|
||||
|
||||
If `Facet` is specified, it must be either `void` or `indirect_vptr`. `void`
|
||||
indicates that straight pointers to v-tables should be stored.
|
||||
|
||||
`Map` is an `AssociativeContainer` that maps `type_id`{empty}s to
|
||||
`vptr_type`{empty}s if `Facet` is `void`, or pointers `vptr_type`{empty}s if
|
||||
`Facet` is `indirect_vptr`.
|
||||
`MapAdaptor` is a Boost.Mp11 quoted metafunction that returns a map type.
|
||||
|
||||
### Members
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ Defined in <boost/openmethod/policies/vptr_vector.hpp>.
|
||||
```c++
|
||||
namespace boost::openmethod::policies {
|
||||
|
||||
template<class Policy, typename Facet = void>
|
||||
template<class Policy>
|
||||
class vptr_vector : Base {
|
||||
public:
|
||||
template<typename ForwardIterator>
|
||||
@@ -23,12 +23,10 @@ class vptr_vector : Base {
|
||||
|
||||
### Description
|
||||
|
||||
`vptr_vector` is an implementation or `external_vptr` that keeps the pointers
|
||||
to the v-tables in a `std::vector`. If `UseIndirectVptrs` is `indirect_vptr`,
|
||||
stores pointers to pointers to the v-tables.
|
||||
|
||||
If `Facet` is specified, it must be either `void` or `indirect_vptr`. `void`
|
||||
indicates that straight pointers to v-tables should be stored.
|
||||
`vptr_vector` is an implementation or `external_vptr` that keeps the pointers to
|
||||
the v-tables in a `std::vector`. If `Policy` contains `indirect_vptr`, a level
|
||||
of indirection is added, making the policy usable in presence of dynamic
|
||||
loading.
|
||||
|
||||
`Policy` is the policy containing the facet.
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
### Synopsis
|
||||
|
||||
Defined in <boost/openmethod/core.hpp>.
|
||||
Defined in <boost/openmethod/with_vptr.hpp>.
|
||||
|
||||
```c++
|
||||
namespace boost::openmethod {
|
||||
|
||||
@@ -78,6 +78,9 @@ struct Dog : virtual Animal {
|
||||
namespace bom = boost::openmethod;
|
||||
|
||||
struct custom_rtti : bom::policies::rtti {
|
||||
template<class T>
|
||||
static constexpr bool is_polymorphic = std::is_base_of_v<Animal, T>;
|
||||
|
||||
template<typename T>
|
||||
static auto static_type() -> bom::type_id {
|
||||
if constexpr (std::is_base_of_v<Animal, T>) {
|
||||
|
||||
@@ -27,10 +27,9 @@ struct Cow : Herbivore {};
|
||||
struct Wolf : Carnivore {};
|
||||
|
||||
struct dynamic_policy
|
||||
: boost::openmethod::default_policy::fork<dynamic_policy>::replace<
|
||||
boost::openmethod::policies::extern_vptr,
|
||||
boost::openmethod::policies::vptr_vector<
|
||||
dynamic_policy, boost::openmethod::policies::indirect_vptr>> {};
|
||||
: boost::openmethod::default_policy::fork<dynamic_policy>::with<
|
||||
boost::openmethod::policies::indirect_vptr> {};
|
||||
|
||||
template<class Class>
|
||||
using dyn_vptr = boost::openmethod::virtual_ptr<Class, dynamic_policy>;
|
||||
|
||||
|
||||
@@ -26,9 +26,8 @@ struct throw_if_not_implemented : bom::policies::error_handler {
|
||||
}
|
||||
};
|
||||
|
||||
struct throwing_policy
|
||||
: bom::default_policy::fork<throwing_policy>::replace<
|
||||
bom::policies::error_handler, throw_if_not_implemented> {};
|
||||
struct throwing_policy : bom::default_policy::fork<throwing_policy>::with<
|
||||
throw_if_not_implemented> {};
|
||||
|
||||
#define BOOST_OPENMETHOD_DEFAULT_POLICY throwing_policy
|
||||
|
||||
|
||||
4365
flat/boost/openmethod.hpp
Normal file
4365
flat/boost/openmethod.hpp
Normal file
File diff suppressed because it is too large
Load Diff
1144
flat/boost/openmethod/policies.hpp
Normal file
1144
flat/boost/openmethod/policies.hpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -262,15 +262,6 @@ struct compiler : detail::generic_compiler {
|
||||
-> bool;
|
||||
static auto is_base(const overrider* a, const overrider* b) -> bool;
|
||||
|
||||
static auto static_type(type_id type) -> type_id {
|
||||
if constexpr (std::is_base_of_v<
|
||||
policies::deferred_static_rtti, policies::rtti>) {
|
||||
return reinterpret_cast<type_id (*)()>(type)();
|
||||
} else {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
mutable detail::trace_type<Policy> trace;
|
||||
static constexpr bool trace_enabled =
|
||||
Policy::template has_facet<policies::trace_output>;
|
||||
@@ -342,7 +333,6 @@ void compiler<Policy>::resolve_static_type_ids() {
|
||||
for (auto& ti : range{method.vp_begin, method.vp_end}) {
|
||||
if (*method.vp_end == 0) {
|
||||
resolve(&ti);
|
||||
*method.vp_end = 1;
|
||||
}
|
||||
|
||||
for (auto& overrider : method.specs) {
|
||||
@@ -356,6 +346,8 @@ void compiler<Policy>::resolve_static_type_ids() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*method.vp_end = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -693,7 +685,7 @@ void compiler<Policy>::assign_slots() {
|
||||
|
||||
auto first_slot = cls.used_slots.find_first();
|
||||
cls.first_slot =
|
||||
first_slot == boost::dynamic_bitset<>::npos ? 0 : first_slot;
|
||||
first_slot == boost::dynamic_bitset<>::npos ? 0u : first_slot;
|
||||
cls.vtbl.resize(cls.used_slots.size() - cls.first_slot);
|
||||
++trace << cls << " vtbl: " << cls.first_slot << "-"
|
||||
<< cls.used_slots.size() << " slots " << cls.used_slots
|
||||
|
||||
@@ -351,7 +351,9 @@ class virtual_ptr_impl {
|
||||
|
||||
template<
|
||||
class Other,
|
||||
typename = std::enable_if_t<std::is_constructible_v<Class*, Other*>>>
|
||||
typename = std::enable_if_t<
|
||||
std::is_constructible_v<Class*, Other*> &&
|
||||
Policy::template is_polymorphic<Class>>>
|
||||
virtual_ptr_impl(Other& other)
|
||||
: vp(box_vptr<use_indirect_vptrs>(Policy::dynamic_vptr(other))),
|
||||
obj(&other) {
|
||||
@@ -359,9 +361,11 @@ class virtual_ptr_impl {
|
||||
|
||||
template<
|
||||
class Other,
|
||||
typename = std::enable_if_t<std::is_constructible_v<
|
||||
Class*,
|
||||
decltype(std::declval<virtual_ptr<Other, Policy>>().get())>>>
|
||||
typename = std::enable_if_t<
|
||||
std::is_constructible_v<
|
||||
Class*,
|
||||
decltype(std::declval<virtual_ptr<Other, Policy>>().get())> &&
|
||||
Policy::template is_polymorphic<Class>>>
|
||||
virtual_ptr_impl(Other* other)
|
||||
: vp(box_vptr<use_indirect_vptrs>(Policy::dynamic_vptr(*other))),
|
||||
obj(other) {
|
||||
@@ -381,7 +385,7 @@ class virtual_ptr_impl {
|
||||
typename = std::enable_if_t<std::is_constructible_v<
|
||||
Class*,
|
||||
decltype(std::declval<virtual_ptr<Other, Policy>>().get())>>>
|
||||
virtual_ptr_impl(virtual_ptr<Other, Policy>& other)
|
||||
virtual_ptr_impl(virtual_ptr_impl<Other, Policy>& other)
|
||||
: vp(other.vp), obj(other.get()) {
|
||||
// Why is this needed? Consider this conversion conversion from
|
||||
// smart to dumb pointer:
|
||||
@@ -402,7 +406,9 @@ class virtual_ptr_impl {
|
||||
|
||||
template<
|
||||
class Other,
|
||||
typename = std::enable_if_t<std::is_assignable_v<Class*, Other*>>>
|
||||
typename = std::enable_if_t<
|
||||
std::is_assignable_v<Class*, Other*> &&
|
||||
Policy::template is_polymorphic<Class>>>
|
||||
virtual_ptr_impl& operator=(Other& other) {
|
||||
obj = &other;
|
||||
vp = box_vptr<use_indirect_vptrs>(Policy::dynamic_vptr(other));
|
||||
@@ -411,7 +417,9 @@ class virtual_ptr_impl {
|
||||
|
||||
template<
|
||||
class Other,
|
||||
typename = std::enable_if_t<std::is_assignable_v<Class*, Other*>>>
|
||||
typename = std::enable_if_t<
|
||||
std::is_assignable_v<Class*, Other*> &&
|
||||
Policy::template is_polymorphic<Class>>>
|
||||
virtual_ptr_impl& operator=(Other* other) {
|
||||
obj = other;
|
||||
vp = box_vptr<use_indirect_vptrs>(Policy::dynamic_vptr(*other));
|
||||
@@ -524,7 +532,8 @@ class virtual_ptr_impl<
|
||||
class Other,
|
||||
typename = std::enable_if_t<
|
||||
same_smart_ptr<Class, Other, Policy> &&
|
||||
std::is_constructible_v<Class, const Other&>>>
|
||||
std::is_constructible_v<Class, const Other&> &&
|
||||
Policy::template is_polymorphic<element_type>>>
|
||||
virtual_ptr_impl(const Other& other)
|
||||
: vp(box_vptr<use_indirect_vptrs>(
|
||||
other ? Policy::dynamic_vptr(*other) : null_vptr)),
|
||||
@@ -535,18 +544,20 @@ class virtual_ptr_impl<
|
||||
class Other,
|
||||
typename = std::enable_if_t<
|
||||
same_smart_ptr<Class, Other, Policy> &&
|
||||
std::is_constructible_v<Class, Other&>>>
|
||||
std::is_constructible_v<Class, Other&> &&
|
||||
Policy::template is_polymorphic<element_type>>>
|
||||
virtual_ptr_impl(Other& other)
|
||||
: vp(box_vptr<use_indirect_vptrs>(
|
||||
other ? Policy::dynamic_vptr(*other) : null_vptr)),
|
||||
obj(other) {
|
||||
other ? Policy::dynamic_vptr(*other) : null_vptr)),
|
||||
obj(other) {
|
||||
}
|
||||
|
||||
template<
|
||||
class Other,
|
||||
typename = std::enable_if_t<
|
||||
same_smart_ptr<Class, Other, Policy> &&
|
||||
std::is_constructible_v<Class, Other&&>>>
|
||||
std::is_constructible_v<Class, Other&&> &&
|
||||
Policy::template is_polymorphic<element_type>>>
|
||||
virtual_ptr_impl(Other&& other)
|
||||
: vp(box_vptr<use_indirect_vptrs>(
|
||||
other ? Policy::dynamic_vptr(*other) : null_vptr)),
|
||||
@@ -558,7 +569,7 @@ class virtual_ptr_impl<
|
||||
typename = std::enable_if_t<
|
||||
same_smart_ptr<Class, Other, Policy> &&
|
||||
std::is_constructible_v<Class, const Other&>>>
|
||||
virtual_ptr_impl(const virtual_ptr<Other, Policy>& other)
|
||||
virtual_ptr_impl(const virtual_ptr_impl<Other, Policy>& other)
|
||||
: vp(other.vp), obj(other.obj) {
|
||||
}
|
||||
|
||||
@@ -567,7 +578,7 @@ class virtual_ptr_impl<
|
||||
typename = std::enable_if_t<
|
||||
same_smart_ptr<Class, Other, Policy> &&
|
||||
std::is_constructible_v<Class, Other&>>>
|
||||
virtual_ptr_impl(virtual_ptr<Other, Policy>& other)
|
||||
virtual_ptr_impl(virtual_ptr_impl<Other, Policy>& other)
|
||||
: vp(other.vp), obj(other.obj) {
|
||||
}
|
||||
|
||||
@@ -581,7 +592,7 @@ class virtual_ptr_impl<
|
||||
typename = std::enable_if_t<
|
||||
same_smart_ptr<Class, Other, Policy> &&
|
||||
std::is_constructible_v<Class, Other&&>>>
|
||||
virtual_ptr_impl(virtual_ptr<Other, Policy>&& other)
|
||||
virtual_ptr_impl(virtual_ptr_impl<Other, Policy>&& other)
|
||||
: vp(other.vp), obj(std::move(other.obj)) {
|
||||
other.vp = box_vptr<use_indirect_vptrs>(null_vptr);
|
||||
}
|
||||
@@ -596,7 +607,8 @@ class virtual_ptr_impl<
|
||||
class Other,
|
||||
typename = std::enable_if_t<
|
||||
same_smart_ptr<Class, Other, Policy> &&
|
||||
std::is_assignable_v<Class, const Other&>>>
|
||||
std::is_assignable_v<Class, const Other&> &&
|
||||
Policy::template is_polymorphic<element_type>>>
|
||||
virtual_ptr_impl& operator=(const Other& other) {
|
||||
obj = other;
|
||||
vp = box_vptr<use_indirect_vptrs>(Policy::dynamic_vptr(*other));
|
||||
@@ -607,7 +619,8 @@ class virtual_ptr_impl<
|
||||
class Other,
|
||||
typename = std::enable_if_t<
|
||||
same_smart_ptr<Class, Other, Policy> &&
|
||||
std::is_assignable_v<Class, Other&&>>>
|
||||
std::is_assignable_v<Class, Other&&> &&
|
||||
Policy::template is_polymorphic<element_type>>>
|
||||
virtual_ptr_impl& operator=(Other&& other) {
|
||||
vp = box_vptr<use_indirect_vptrs>(
|
||||
other ? Policy::dynamic_vptr(*other) : null_vptr);
|
||||
@@ -620,12 +633,14 @@ class virtual_ptr_impl<
|
||||
typename = std::enable_if_t<
|
||||
same_smart_ptr<Class, Other, Policy> &&
|
||||
std::is_assignable_v<Class, Other&>>>
|
||||
virtual_ptr_impl& operator=(virtual_ptr<Other, Policy>& other) {
|
||||
virtual_ptr_impl& operator=(virtual_ptr_impl<Other, Policy>& other) {
|
||||
obj = other.obj;
|
||||
vp = other.vp;
|
||||
return *this;
|
||||
}
|
||||
|
||||
virtual_ptr_impl& operator=(const virtual_ptr_impl& other) = default;
|
||||
|
||||
template<
|
||||
class Other,
|
||||
typename = std::enable_if_t<
|
||||
@@ -1042,6 +1057,21 @@ class method<Name(Parameters...), ReturnType, Policy>
|
||||
};
|
||||
};
|
||||
|
||||
// Following cannot be `inline static` becaused of MSVC (19.43) bug causing a
|
||||
// "no appropriate default constructor available". Try this in CE:
|
||||
//
|
||||
// template<typename>
|
||||
// class method {
|
||||
// method();
|
||||
// method(const method&) = delete;
|
||||
// method(method&&) = delete;
|
||||
// ~method();
|
||||
// public:
|
||||
// static inline method instance;
|
||||
// };
|
||||
// template method<void>;
|
||||
// https://godbolt.org/z/GzEn486P7
|
||||
|
||||
template<
|
||||
typename Name, typename... Parameters, typename ReturnType, class Policy>
|
||||
method<Name(Parameters...), ReturnType, Policy>
|
||||
@@ -1168,13 +1198,7 @@ method<Name(Parameters...), ReturnType, Policy>::resolve_uni(
|
||||
using namespace boost::mp11;
|
||||
|
||||
if constexpr (is_virtual<mp_first<MethodArgList>>::value) {
|
||||
vptr_type vtbl;
|
||||
|
||||
if constexpr (is_virtual_ptr<ArgType>) {
|
||||
vtbl = arg.vptr();
|
||||
} else {
|
||||
vtbl = vptr<ArgType>(arg);
|
||||
}
|
||||
vptr_type vtbl = vptr<ArgType>(arg);
|
||||
|
||||
if constexpr (has_static_offsets<method>::value) {
|
||||
if constexpr (Policy::template has_facet<
|
||||
@@ -1203,14 +1227,7 @@ method<Name(Parameters...), ReturnType, Policy>::resolve_multi_first(
|
||||
using namespace boost::mp11;
|
||||
|
||||
if constexpr (is_virtual<mp_first<MethodArgList>>::value) {
|
||||
vptr_type vtbl;
|
||||
|
||||
if constexpr (is_virtual_ptr<ArgType>) {
|
||||
vtbl = arg.vptr();
|
||||
} else {
|
||||
vtbl = vptr<ArgType>(arg);
|
||||
}
|
||||
|
||||
vptr_type vtbl = vptr<ArgType>(arg);
|
||||
std::size_t slot;
|
||||
|
||||
if constexpr (has_static_offsets<method>::value) {
|
||||
@@ -1251,14 +1268,7 @@ method<Name(Parameters...), ReturnType, Policy>::resolve_multi_next(
|
||||
using namespace boost::mp11;
|
||||
|
||||
if constexpr (is_virtual<mp_first<MethodArgList>>::value) {
|
||||
vptr_type vtbl;
|
||||
|
||||
if constexpr (is_virtual_ptr<ArgType>) {
|
||||
vtbl = arg.vptr();
|
||||
} else {
|
||||
vtbl = vptr<ArgType>(arg);
|
||||
}
|
||||
|
||||
vptr_type vtbl = vptr<ArgType>(arg);
|
||||
std::size_t slot, stride;
|
||||
|
||||
if constexpr (has_static_offsets<method>::value) {
|
||||
|
||||
@@ -22,10 +22,9 @@ struct release : basic_policy<
|
||||
release, std_rtti, fast_perfect_hash<release>,
|
||||
vptr_vector<release>, vectored_error_handler<release>> {};
|
||||
|
||||
struct debug : release::add<
|
||||
struct debug : release::fork<debug>::with<
|
||||
runtime_checks, basic_error_output<debug>,
|
||||
basic_trace_output<debug>>::
|
||||
replace<error_handler, vectored_error_handler<debug>> {};
|
||||
basic_trace_output<debug>> {};
|
||||
|
||||
} // namespace policies
|
||||
|
||||
|
||||
@@ -12,13 +12,10 @@
|
||||
namespace boost::openmethod::policies {
|
||||
|
||||
template<class Policy, typename Stream = detail::ostderr>
|
||||
struct basic_error_output : virtual error_output {
|
||||
static Stream error_stream;
|
||||
struct basic_error_output : error_output {
|
||||
inline static Stream error_stream;
|
||||
};
|
||||
|
||||
template<class Policy, typename Stream>
|
||||
Stream basic_error_output<Policy, Stream>::error_stream;
|
||||
|
||||
} // namespace boost::openmethod::policies
|
||||
|
||||
#endif
|
||||
|
||||
@@ -16,11 +16,25 @@
|
||||
|
||||
namespace boost::openmethod {
|
||||
|
||||
namespace policies {
|
||||
|
||||
struct facet {
|
||||
static auto finalize() -> void {
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace policies
|
||||
|
||||
namespace detail {
|
||||
|
||||
using class_catalog = detail::static_list<detail::class_info>;
|
||||
using method_catalog = detail::static_list<detail::method_info>;
|
||||
|
||||
template<class Facet>
|
||||
struct basic_facet : policies::facet {
|
||||
using facet_type = Facet;
|
||||
};
|
||||
|
||||
template<typename Policy, class Facet>
|
||||
struct fork_facet {
|
||||
using type = Facet;
|
||||
@@ -33,6 +47,46 @@ struct fork_facet<NewPolicy, GenericFacet<OldPolicy, Args...>> {
|
||||
using type = GenericFacet<NewPolicy, Args...>;
|
||||
};
|
||||
|
||||
template<class Facets, class...>
|
||||
struct with_aux;
|
||||
|
||||
template<class Facets>
|
||||
struct with_aux<Facets> {
|
||||
using type = Facets;
|
||||
};
|
||||
|
||||
template<class Facets, class Facet, class... MoreFacets>
|
||||
struct with_aux<Facets, Facet, MoreFacets...> {
|
||||
using replace = mp11::mp_replace_if_q<
|
||||
Facets,
|
||||
mp11::mp_bind_front_q<
|
||||
mp11::mp_quote_trait<std::is_base_of>, typename Facet::facet_type>,
|
||||
Facet>;
|
||||
using replace_or_add = std::conditional_t<
|
||||
std::is_same_v<replace, Facets>, mp11::mp_push_back<Facets, Facet>,
|
||||
replace>;
|
||||
using type = typename with_aux<replace_or_add, MoreFacets...>::type;
|
||||
};
|
||||
|
||||
template<class Facets, class...>
|
||||
struct without_aux;
|
||||
|
||||
template<class Facets>
|
||||
struct without_aux<Facets> {
|
||||
using type = Facets;
|
||||
};
|
||||
|
||||
template<class Facets, class Facet, class... MoreFacets>
|
||||
struct without_aux<Facets, Facet, MoreFacets...> {
|
||||
using type = typename without_aux<
|
||||
mp11::mp_remove_if_q<
|
||||
Facets,
|
||||
mp11::mp_bind_front_q<
|
||||
mp11::mp_quote_trait<std::is_base_of>,
|
||||
typename Facet::facet_type>>,
|
||||
MoreFacets...>::type;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
namespace policies {
|
||||
@@ -42,12 +96,7 @@ struct abstract_policy {};
|
||||
// -----------------------------------------------------------------------------
|
||||
// Facets
|
||||
|
||||
struct facet {
|
||||
static auto finalize() -> void {
|
||||
}
|
||||
};
|
||||
|
||||
struct rtti : facet {
|
||||
struct rtti : detail::basic_facet<rtti> {
|
||||
static auto type_index(type_id type) -> type_id {
|
||||
return type;
|
||||
}
|
||||
@@ -59,39 +108,26 @@ struct rtti : facet {
|
||||
};
|
||||
|
||||
struct deferred_static_rtti : rtti {};
|
||||
struct error_handler : facet {};
|
||||
struct type_hash : facet {};
|
||||
struct extern_vptr : facet {};
|
||||
struct indirect_vptr : facet {};
|
||||
struct error_output : facet {};
|
||||
struct trace_output : facet {};
|
||||
struct runtime_checks : facet {};
|
||||
struct error_handler : detail::basic_facet<error_handler> {};
|
||||
struct type_hash : detail::basic_facet<type_hash> {};
|
||||
struct extern_vptr : detail::basic_facet<extern_vptr> {};
|
||||
struct indirect_vptr : detail::basic_facet<indirect_vptr> {};
|
||||
struct error_output : detail::basic_facet<error_output> {};
|
||||
struct trace_output : detail::basic_facet<trace_output> {};
|
||||
struct runtime_checks : detail::basic_facet<runtime_checks> {};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// domain
|
||||
|
||||
template<class Policy>
|
||||
struct domain {
|
||||
static detail::class_catalog classes;
|
||||
static detail::method_catalog methods;
|
||||
inline static detail::class_catalog classes;
|
||||
inline static detail::method_catalog methods;
|
||||
template<class Class>
|
||||
static vptr_type static_vptr;
|
||||
static std::vector<std::uintptr_t> dispatch_data;
|
||||
inline static vptr_type static_vptr;
|
||||
inline static std::vector<std::uintptr_t> dispatch_data;
|
||||
};
|
||||
|
||||
template<class Policy>
|
||||
detail::class_catalog domain<Policy>::classes;
|
||||
|
||||
template<class Policy>
|
||||
detail::method_catalog domain<Policy>::methods;
|
||||
|
||||
template<class Policy>
|
||||
template<class Class>
|
||||
vptr_type domain<Policy>::static_vptr;
|
||||
|
||||
template<class Policy>
|
||||
std::vector<std::uintptr_t> domain<Policy>::dispatch_data;
|
||||
|
||||
template<class Policy, class... Facets>
|
||||
struct basic_policy : abstract_policy, domain<Policy>, Facets... {
|
||||
using facets = mp11::mp_list<Facets...>;
|
||||
@@ -103,28 +139,17 @@ struct basic_policy : abstract_policy, domain<Policy>, Facets... {
|
||||
using fork = basic_policy<
|
||||
NewPolicy, typename detail::fork_facet<NewPolicy, Facets>::type...>;
|
||||
|
||||
template<class... MoreFacets>
|
||||
using add = basic_policy<Policy, Facets..., MoreFacets...>;
|
||||
|
||||
template<class Base, class Facet>
|
||||
using replace = boost::mp11::mp_apply<
|
||||
template<class... NewFacets>
|
||||
using with = boost::mp11::mp_apply<
|
||||
basic_policy,
|
||||
boost::mp11::mp_push_front<
|
||||
boost::mp11::mp_replace_if_q<
|
||||
facets,
|
||||
boost::mp11::mp_bind_front_q<
|
||||
boost::mp11::mp_quote_trait<std::is_base_of>, Base>,
|
||||
Facet>,
|
||||
Policy>>;
|
||||
typename detail::with_aux<facets, NewFacets...>::type, Policy>>;
|
||||
|
||||
template<class Base>
|
||||
using remove = boost::mp11::mp_apply<
|
||||
template<class... RemoveFacets>
|
||||
using without = boost::mp11::mp_apply<
|
||||
basic_policy,
|
||||
boost::mp11::mp_push_front<
|
||||
boost::mp11::mp_remove_if_q<
|
||||
facets,
|
||||
boost::mp11::mp_bind_front_q<
|
||||
boost::mp11::mp_quote_trait<std::is_base_of>, Base>>,
|
||||
typename detail::without_aux<facets, RemoveFacets...>::type,
|
||||
Policy>>;
|
||||
};
|
||||
|
||||
|
||||
@@ -19,19 +19,13 @@ namespace boost::openmethod::policies {
|
||||
|
||||
template<class Policy, typename Stream = detail::ostderr>
|
||||
struct basic_trace_output : virtual trace_output {
|
||||
static bool trace_enabled;
|
||||
static Stream trace_stream;
|
||||
inline static bool trace_enabled = []() {
|
||||
auto env = getenv("BOOST_OPENMETHOD_TRACE");
|
||||
return env && *env++ == '1' && *env++ == 0;
|
||||
}();
|
||||
inline static Stream trace_stream;
|
||||
};
|
||||
|
||||
template<class Policy, typename Stream>
|
||||
Stream basic_trace_output<Policy, Stream>::trace_stream;
|
||||
|
||||
template<class Policy, typename Stream>
|
||||
bool basic_trace_output<Policy, Stream>::trace_enabled([]() {
|
||||
auto env = getenv("BOOST_OPENMETHOD_TRACE");
|
||||
return env && *env++ == '1' && *env++ == 0;
|
||||
}());
|
||||
|
||||
} // namespace boost::openmethod::policies
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <boost/openmethod/policies/basic_policy.hpp>
|
||||
|
||||
#include <limits>
|
||||
#include <random>
|
||||
|
||||
namespace boost::openmethod {
|
||||
@@ -24,12 +25,11 @@ namespace policies {
|
||||
template<class Policy>
|
||||
class fast_perfect_hash : public type_hash {
|
||||
|
||||
static type_id hash_mult;
|
||||
static std::size_t hash_shift;
|
||||
static std::size_t hash_min;
|
||||
static std::size_t hash_max;
|
||||
|
||||
static void check(std::size_t index, type_id type);
|
||||
inline static type_id hash_mult;
|
||||
inline static std::size_t hash_shift;
|
||||
inline static std::size_t hash_min;
|
||||
inline static std::size_t hash_max;
|
||||
inline static void check(std::size_t index, type_id type);
|
||||
|
||||
public:
|
||||
struct report {
|
||||
@@ -100,6 +100,8 @@ void fast_perfect_hash<Policy>::hash_initialize(
|
||||
for (std::size_t pass = 0; pass < 4; ++pass, ++M) {
|
||||
hash_shift = 8 * sizeof(type_id) - M;
|
||||
auto hash_size = 1 << M;
|
||||
hash_min = (std::numeric_limits<std::size_t>::max)();
|
||||
hash_max = (std::numeric_limits<std::size_t>::min)();
|
||||
|
||||
if constexpr (trace_enabled) {
|
||||
if (Policy::trace_enabled) {
|
||||
@@ -108,15 +110,13 @@ void fast_perfect_hash<Policy>::hash_initialize(
|
||||
}
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
std::size_t attempts = 0;
|
||||
buckets.resize(hash_size);
|
||||
|
||||
while (!found && attempts < 100000) {
|
||||
while (attempts < 100000) {
|
||||
std::fill(buckets.begin(), buckets.end(), static_cast<type_id>(-1));
|
||||
++attempts;
|
||||
++total_attempts;
|
||||
found = true;
|
||||
hash_mult = uniform_dist(rnd) | 1;
|
||||
|
||||
for (auto iter = first; iter != last; ++iter) {
|
||||
@@ -128,16 +128,13 @@ void fast_perfect_hash<Policy>::hash_initialize(
|
||||
hash_max = (std::max)(hash_max, index);
|
||||
|
||||
if (buckets[index] != static_cast<type_id>(-1)) {
|
||||
found = false;
|
||||
break;
|
||||
goto collision;
|
||||
}
|
||||
|
||||
buckets[index] = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
if constexpr (trace_enabled) {
|
||||
if (Policy::trace_enabled) {
|
||||
Policy::trace_stream << " found " << hash_mult << " after "
|
||||
@@ -148,6 +145,8 @@ void fast_perfect_hash<Policy>::hash_initialize(
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
collision: {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,15 +175,6 @@ void fast_perfect_hash<Policy>::check(std::size_t index, type_id type) {
|
||||
}
|
||||
}
|
||||
|
||||
template<class Policy>
|
||||
type_id fast_perfect_hash<Policy>::hash_mult;
|
||||
template<class Policy>
|
||||
std::size_t fast_perfect_hash<Policy>::hash_shift;
|
||||
template<class Policy>
|
||||
std::size_t fast_perfect_hash<Policy>::hash_min;
|
||||
template<class Policy>
|
||||
std::size_t fast_perfect_hash<Policy>::hash_max;
|
||||
|
||||
} // namespace policies
|
||||
} // namespace boost::openmethod
|
||||
|
||||
|
||||
@@ -36,8 +36,6 @@ class vectored_error_handler : public error_handler {
|
||||
}
|
||||
|
||||
private:
|
||||
static function_type fn;
|
||||
|
||||
static auto default_handler(const error_variant& error_v) {
|
||||
using namespace detail;
|
||||
using namespace policies;
|
||||
@@ -74,12 +72,13 @@ class vectored_error_handler : public error_handler {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static function_type fn; // Cannot be inline static because it confuses MSVC
|
||||
};
|
||||
|
||||
template<class Policy>
|
||||
typename vectored_error_handler<Policy>::function_type
|
||||
vectored_error_handler<Policy>::fn =
|
||||
vectored_error_handler<Policy>::default_handler;
|
||||
vectored_error_handler<Policy>::fn = default_handler;
|
||||
|
||||
} // namespace boost::openmethod::policies
|
||||
|
||||
|
||||
@@ -10,30 +10,19 @@
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace boost::openmethod::policies {
|
||||
namespace boost::openmethod {
|
||||
|
||||
template<
|
||||
class Policy, class Facet = void,
|
||||
class Map = std::unordered_map<
|
||||
type_id,
|
||||
std::conditional_t<
|
||||
std::is_same_v<Facet, indirect_vptr>, const vptr_type*, vptr_type>>>
|
||||
class vptr_map : public extern_vptr,
|
||||
public std::conditional_t<
|
||||
std::is_same_v<Facet, void>, detail::empty, Facet> {
|
||||
static_assert(
|
||||
std::is_same_v<Facet, void> || std::is_same_v<Facet, indirect_vptr>);
|
||||
static constexpr bool use_indirect_vptrs =
|
||||
std::is_same_v<Facet, indirect_vptr>;
|
||||
static_assert(
|
||||
std::is_same_v<typename Map::mapped_type, vptr_type> ||
|
||||
std::is_same_v<typename Map::mapped_type, const vptr_type*>);
|
||||
static_assert(
|
||||
std::is_same_v<typename Map::mapped_type, const vptr_type*> ==
|
||||
use_indirect_vptrs);
|
||||
namespace detail {
|
||||
|
||||
static Map vptrs;
|
||||
template<class Policy, class MapAdaptor, typename Key, typename Value>
|
||||
inline typename MapAdaptor::template fn<Key, Value> vptr_map_vptrs;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
namespace policies {
|
||||
|
||||
template<class Policy, class MapAdaptor = mp11::mp_quote<std::unordered_map>>
|
||||
class vptr_map : public extern_vptr {
|
||||
public:
|
||||
template<typename ForwardIterator>
|
||||
static void register_vptrs(ForwardIterator first, ForwardIterator last) {
|
||||
@@ -41,10 +30,14 @@ class vptr_map : public extern_vptr,
|
||||
for (auto type_iter = iter->type_id_begin();
|
||||
type_iter != iter->type_id_end(); ++type_iter) {
|
||||
|
||||
if constexpr (use_indirect_vptrs) {
|
||||
vptrs[*type_iter] = &iter->vptr();
|
||||
if constexpr (Policy::template has_facet<indirect_vptr>) {
|
||||
detail::vptr_map_vptrs<Policy,
|
||||
MapAdaptor, type_id,
|
||||
const vptr_type*>.emplace(*type_iter, &iter->vptr());
|
||||
} else {
|
||||
vptrs[*type_iter] = iter->vptr();
|
||||
detail::vptr_map_vptrs<
|
||||
Policy, MapAdaptor, type_id, vptr_type
|
||||
>.emplace(*type_iter, iter->vptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,10 +46,16 @@ class vptr_map : public extern_vptr,
|
||||
template<class Class>
|
||||
static auto dynamic_vptr(const Class& arg) -> const vptr_type& {
|
||||
auto type = Policy::dynamic_type(arg);
|
||||
auto iter = vptrs.find(type);
|
||||
bool constexpr use_indirect_vptrs =
|
||||
Policy::template has_facet<indirect_vptr>;
|
||||
const auto& map = detail::vptr_map_vptrs<
|
||||
Policy, MapAdaptor, type_id,
|
||||
std::conditional_t<
|
||||
use_indirect_vptrs, const vptr_type*, vptr_type>>;
|
||||
auto iter = map.find(type);
|
||||
|
||||
if constexpr (Policy::template has_facet<runtime_checks>) {
|
||||
if (iter == vptrs.end()) {
|
||||
if (iter == map.end()) {
|
||||
if constexpr (Policy::template has_facet<error_handler>) {
|
||||
unknown_class_error error;
|
||||
error.type = type;
|
||||
@@ -75,13 +74,14 @@ class vptr_map : public extern_vptr,
|
||||
}
|
||||
|
||||
static auto finalize() -> void {
|
||||
vptrs.clear();
|
||||
detail::vptr_map_vptrs<
|
||||
Policy, MapAdaptor, type_id, std::conditional_t<
|
||||
Policy::template has_facet<indirect_vptr>,
|
||||
const vptr_type*, vptr_type>>.clear();
|
||||
}
|
||||
};
|
||||
|
||||
template<class Policy, typename UseIndirectVptrs, class Map>
|
||||
Map vptr_map<Policy, UseIndirectVptrs, Map>::vptrs;
|
||||
|
||||
} // namespace boost::openmethod::policies
|
||||
} // namespace policies
|
||||
} // namespace boost::openmethod
|
||||
|
||||
#endif
|
||||
|
||||
@@ -11,20 +11,22 @@
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
namespace boost::openmethod::policies {
|
||||
namespace boost::openmethod {
|
||||
|
||||
template<class Policy, typename Facet = void>
|
||||
class vptr_vector : public extern_vptr,
|
||||
public std::conditional_t<
|
||||
std::is_same_v<Facet, void>, detail::empty, Facet> {
|
||||
static_assert(
|
||||
std::is_same_v<Facet, void> || std::is_same_v<Facet, indirect_vptr>);
|
||||
static constexpr bool use_indirect_vptrs =
|
||||
std::is_same_v<Facet, indirect_vptr>;
|
||||
using element_type =
|
||||
std::conditional_t<use_indirect_vptrs, const vptr_type*, vptr_type>;
|
||||
static std::vector<element_type> vptrs;
|
||||
namespace detail {
|
||||
|
||||
template<class Policy>
|
||||
inline std::vector<vptr_type> vptr_vector_vptrs;
|
||||
|
||||
template<class Policy>
|
||||
inline std::vector<const vptr_type*> vptr_vector_indirect_vptrs;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
namespace policies {
|
||||
|
||||
template<class Policy>
|
||||
class vptr_vector : public extern_vptr {
|
||||
public:
|
||||
template<typename ForwardIterator>
|
||||
static auto register_vptrs(ForwardIterator first, ForwardIterator last)
|
||||
@@ -49,7 +51,11 @@ class vptr_vector : public extern_vptr,
|
||||
++size;
|
||||
}
|
||||
|
||||
vptrs.resize(size);
|
||||
if constexpr (Policy::template has_facet<indirect_vptr>) {
|
||||
detail::vptr_vector_indirect_vptrs<Policy>.resize(size);
|
||||
} else {
|
||||
detail::vptr_vector_vptrs<Policy>.resize(size);
|
||||
}
|
||||
|
||||
for (auto iter = first; iter != last; ++iter) {
|
||||
for (auto type_iter = iter->type_id_begin();
|
||||
@@ -60,10 +66,11 @@ class vptr_vector : public extern_vptr,
|
||||
index = Policy::hash_type_id(index);
|
||||
}
|
||||
|
||||
if constexpr (use_indirect_vptrs) {
|
||||
vptrs[index] = &iter->vptr();
|
||||
if constexpr (Policy::template has_facet<indirect_vptr>) {
|
||||
detail::vptr_vector_indirect_vptrs<Policy>[index] =
|
||||
&iter->vptr();
|
||||
} else {
|
||||
vptrs[index] = iter->vptr();
|
||||
detail::vptr_vector_vptrs<Policy>[index] = iter->vptr();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,22 +84,23 @@ class vptr_vector : public extern_vptr,
|
||||
index = Policy::hash_type_id(index);
|
||||
}
|
||||
|
||||
if constexpr (use_indirect_vptrs) {
|
||||
return *vptrs[index];
|
||||
if constexpr (Policy::template has_facet<indirect_vptr>) {
|
||||
return *detail::vptr_vector_indirect_vptrs<Policy>[index];
|
||||
} else {
|
||||
return vptrs[index];
|
||||
return detail::vptr_vector_vptrs<Policy>[index];
|
||||
}
|
||||
}
|
||||
|
||||
static auto finalize() -> void {
|
||||
vptrs.clear();
|
||||
if constexpr (Policy::template has_facet<indirect_vptr>) {
|
||||
detail::vptr_vector_indirect_vptrs<Policy>.clear();
|
||||
} else {
|
||||
detail::vptr_vector_vptrs<Policy>.clear();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<class Policy, typename UseIndirectVptrs>
|
||||
std::vector<typename vptr_vector<Policy, UseIndirectVptrs>::element_type>
|
||||
vptr_vector<Policy, UseIndirectVptrs>::vptrs;
|
||||
|
||||
} // namespace boost::openmethod::policies
|
||||
} // namespace policies
|
||||
} // namespace boost::openmethod
|
||||
|
||||
#endif
|
||||
|
||||
@@ -389,7 +389,6 @@ BOOST_OPENMETHOD_OVERRIDE(
|
||||
return Types(DIAGONAL_MATRIX, next(a, b).first);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ambiguity) {
|
||||
auto compiler = initialize<policy>();
|
||||
BOOST_TEST(compiler.report.ambiguous == 1u);
|
||||
|
||||
@@ -159,7 +159,7 @@ BOOST_AUTO_TEST_CASE(test_policy) {
|
||||
|
||||
{
|
||||
// check that adding a facet keeps static data from original
|
||||
struct policy : default_policy::add<policies::indirect_vptr> {};
|
||||
struct policy : default_policy::with<policies::indirect_vptr> {};
|
||||
BOOST_TEST(&policy::methods == &default_policy::methods);
|
||||
BOOST_TEST(&policy::classes == &default_policy::classes);
|
||||
BOOST_TEST(
|
||||
@@ -301,18 +301,63 @@ using namespace policies;
|
||||
|
||||
struct key1;
|
||||
struct key2;
|
||||
struct alt_rtti {};
|
||||
struct foo : detail::basic_facet<foo> {};
|
||||
struct foo1 : foo {};
|
||||
struct foo2 : foo {};
|
||||
struct bar : detail::basic_facet<bar> {};
|
||||
struct bar1 : bar {};
|
||||
struct bar2 : bar {};
|
||||
|
||||
static_assert(
|
||||
std::is_same_v<fork_facet<key2, domain<key1>>::type, domain<key2>>);
|
||||
|
||||
struct policy1 : basic_policy<policy1, std_rtti> {};
|
||||
struct policy2 : policy1::fork<policy2> {};
|
||||
struct policy3 : policy1::fork<policy3>::replace<std_rtti, alt_rtti> {};
|
||||
static_assert(std::is_base_of_v<foo1::facet_type, foo>);
|
||||
static_assert(std::is_base_of_v<bar1::facet_type, bar>);
|
||||
|
||||
static_assert(std::is_same_v<policy2::facets, mp11::mp_list<std_rtti>>);
|
||||
static_assert(
|
||||
std::is_same_v<
|
||||
detail::with_aux<mp11::mp_list<>, foo1>::type, mp11::mp_list<foo1>>);
|
||||
|
||||
static_assert(std::is_same_v<policy3::facets, mp11::mp_list<alt_rtti>>);
|
||||
static_assert(std::is_same_v<
|
||||
detail::with_aux<mp11::mp_list<foo1>, foo2>::type,
|
||||
mp11::mp_list<foo2>>);
|
||||
|
||||
static_assert(std::is_same_v<
|
||||
detail::with_aux<mp11::mp_list<foo1, bar1>, foo2, bar2>::type,
|
||||
mp11::mp_list<foo2, bar2>>);
|
||||
|
||||
static_assert(
|
||||
std::is_same_v<basic_policy<key1>::with<foo1>, basic_policy<key1, foo1>>);
|
||||
|
||||
static_assert(std::is_same_v<
|
||||
basic_policy<key1, foo1>::with<foo2>, basic_policy<key1, foo2>>);
|
||||
|
||||
template<class Policy, class... Facets>
|
||||
constexpr bool has_facets = (... && Policy::template has_facet<Facets>) &&
|
||||
mp11::mp_size<typename Policy::facets>::value == sizeof...(Facets);
|
||||
|
||||
static_assert(std::is_same_v<
|
||||
basic_policy<key1, foo1, bar1>::with<foo2>::facets,
|
||||
mp11::mp_list<foo2, bar1>>);
|
||||
|
||||
static_assert(std::is_same_v<
|
||||
basic_policy<key1, foo1, bar1>::with<bar2>::facets,
|
||||
mp11::mp_list<foo1, bar2>>);
|
||||
|
||||
static_assert(std::is_same_v<
|
||||
basic_policy<key1, foo1, bar1>::with<foo2, bar2>::facets,
|
||||
mp11::mp_list<foo2, bar2>>);
|
||||
|
||||
static_assert(
|
||||
std::is_same_v<basic_policy<key1>::without<foo>::facets, mp11::mp_list<>>);
|
||||
|
||||
static_assert(std::is_same_v<
|
||||
basic_policy<key1, foo1, bar1>::without<foo>::facets,
|
||||
mp11::mp_list<bar1>>);
|
||||
|
||||
static_assert(std::is_same_v<
|
||||
basic_policy<key1, foo1, bar1>::without<bar>::facets,
|
||||
mp11::mp_list<foo1>>);
|
||||
|
||||
} // namespace facets
|
||||
|
||||
|
||||
@@ -71,9 +71,7 @@ struct custom_rtti : policies::rtti {
|
||||
}
|
||||
};
|
||||
|
||||
struct test_policy
|
||||
: default_policy::fork<test_policy>::replace<policies::rtti, custom_rtti> {
|
||||
};
|
||||
struct test_policy : default_policy::fork<test_policy>::with<custom_rtti> {};
|
||||
|
||||
BOOST_OPENMETHOD_CLASSES(Animal, Dog, Cat, test_policy);
|
||||
|
||||
@@ -164,9 +162,8 @@ struct custom_rtti : policies::rtti {
|
||||
}
|
||||
};
|
||||
|
||||
struct test_policy
|
||||
: default_policy::fork<test_policy>::replace<
|
||||
policies::rtti, custom_rtti>::remove<policies::type_hash> {};
|
||||
struct test_policy : default_policy::fork<test_policy>::with<
|
||||
custom_rtti>::without<policies::type_hash> {};
|
||||
|
||||
BOOST_OPENMETHOD_CLASSES(Animal, Dog, Cat, test_policy);
|
||||
|
||||
@@ -320,9 +317,8 @@ struct custom_rtti : policies::rtti {
|
||||
}
|
||||
};
|
||||
|
||||
struct test_policy
|
||||
: default_policy::fork<test_policy>::replace<
|
||||
policies::rtti, custom_rtti>::remove<policies::type_hash> {};
|
||||
struct test_policy : default_policy::fork<test_policy>::with<
|
||||
custom_rtti>::without<policies::type_hash> {};
|
||||
|
||||
BOOST_OPENMETHOD_CLASSES(Animal, Dog, Cat, test_policy);
|
||||
|
||||
@@ -460,9 +456,8 @@ struct custom_rtti : policies::deferred_static_rtti {
|
||||
}
|
||||
};
|
||||
|
||||
struct test_policy
|
||||
: default_policy::fork<test_policy>::replace<
|
||||
policies::rtti, custom_rtti>::remove<policies::type_hash> {};
|
||||
struct test_policy : default_policy::fork<test_policy>::with<
|
||||
custom_rtti>::without<policies::type_hash> {};
|
||||
|
||||
BOOST_OPENMETHOD_CLASSES(Animal, Dog, Cat, test_policy);
|
||||
|
||||
@@ -476,6 +471,14 @@ BOOST_OPENMETHOD_OVERRIDE(poke, (Cat & cat, std::ostream& os), void) {
|
||||
os << cat.name << " hisses.";
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD(
|
||||
meet, (virtual_<Animal&>, virtual_<Animal&>, std::ostream&), void,
|
||||
test_policy);
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(meet, (Dog&, Dog&, std::ostream& os), void) {
|
||||
os << "Both wag tails.";
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(custom_rtti_deferred) {
|
||||
initialize<test_policy>();
|
||||
|
||||
@@ -486,11 +489,18 @@ BOOST_AUTO_TEST_CASE(custom_rtti_deferred) {
|
||||
poke(a, os);
|
||||
BOOST_TEST(os.str() == "Snoopy barks.");
|
||||
}
|
||||
|
||||
{
|
||||
std::stringstream os;
|
||||
poke(b, os);
|
||||
BOOST_TEST(os.str() == "Sylvester hisses.");
|
||||
}
|
||||
|
||||
{
|
||||
std::stringstream os;
|
||||
meet(a, a, os);
|
||||
BOOST_TEST(os.str() == "Both wag tails.");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace defered_type_id
|
||||
|
||||
@@ -9,7 +9,10 @@
|
||||
#include <boost/openmethod/policies.hpp>
|
||||
|
||||
namespace bom = boost::openmethod;
|
||||
struct test_policy : bom::default_policy::remove<bom::policies::extern_vptr> {};
|
||||
struct test_policy : bom::default_policy::without<
|
||||
bom::policies::extern_vptr, bom::policies::type_hash> {
|
||||
};
|
||||
|
||||
#define BOOST_OPENMETHOD_DEFAULT_POLICY test_policy
|
||||
|
||||
#include <boost/openmethod.hpp>
|
||||
@@ -84,8 +87,7 @@ DomesticCat::~DomesticCat() {
|
||||
describe(*this, std::cout);
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
speak, (const Animal&, std::ostream& os), void) {
|
||||
BOOST_OPENMETHOD_OVERRIDE(speak, (const Animal&, std::ostream& os), void) {
|
||||
os << "???\n";
|
||||
}
|
||||
|
||||
@@ -168,7 +170,7 @@ BOOST_AUTO_TEST_CASE(intrusive_mode) {
|
||||
}
|
||||
}
|
||||
|
||||
struct indirect_policy : test_policy::add<bom::policies::indirect_vptr> {};
|
||||
struct indirect_policy : test_policy::with<bom::policies::indirect_vptr> {};
|
||||
|
||||
struct Indirect : bom::with_vptr<Indirect, indirect_policy> {
|
||||
using bom::with_vptr<Indirect, indirect_policy>::boost_openmethod_vptr;
|
||||
|
||||
@@ -40,7 +40,7 @@ BOOST_OPENMETHOD(poke, (virtual_<interfaces::Animal&>), std::string);
|
||||
|
||||
namespace canis {
|
||||
// implement 'poke' for dogs
|
||||
BOOST_OPENMETHOD_OVERRIDE(poke, (Dog &), std::string) {
|
||||
BOOST_OPENMETHOD_OVERRIDE(poke, (Dog&), std::string) {
|
||||
return "bark";
|
||||
}
|
||||
|
||||
@@ -61,18 +61,15 @@ BOOST_OPENMETHOD_OVERRIDE(
|
||||
return "ignore";
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
meet, (canis::Dog &, canis::Dog&), std::string) {
|
||||
BOOST_OPENMETHOD_OVERRIDE(meet, (canis::Dog&, canis::Dog&), std::string) {
|
||||
return "wag tail";
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
meet, (canis::Dog &, felis::Cat&), std::string) {
|
||||
BOOST_OPENMETHOD_OVERRIDE(meet, (canis::Dog&, felis::Cat&), std::string) {
|
||||
return "chase";
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
meet, (felis::Cat &, canis::Dog&), std::string) {
|
||||
BOOST_OPENMETHOD_OVERRIDE(meet, (felis::Cat&, canis::Dog&), std::string) {
|
||||
return "run";
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ BOOST_OPENMETHOD_CLASSES(Animal, Dog, Animal);
|
||||
|
||||
BOOST_OPENMETHOD(poke, (virtual_<Animal&>), std::string);
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(poke, (Dog &), std::string) {
|
||||
BOOST_OPENMETHOD_OVERRIDE(poke, (Dog&), std::string) {
|
||||
return "bark";
|
||||
}
|
||||
|
||||
|
||||
@@ -50,29 +50,25 @@ BOOST_OPENMETHOD_OVERRIDE(pay, (virtual_ptr<Manager> exec), double) {
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
approve,
|
||||
(virtual_ptr<const Role>, virtual_ptr<const Expense>, double),
|
||||
approve, (virtual_ptr<const Role>, virtual_ptr<const Expense>, double),
|
||||
bool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
approve,
|
||||
(virtual_ptr<const Employee>, virtual_ptr<const Public>, double),
|
||||
approve, (virtual_ptr<const Employee>, virtual_ptr<const Public>, double),
|
||||
bool) {
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
approve,
|
||||
(virtual_ptr<const Manager>, virtual_ptr<const Taxi>, double),
|
||||
approve, (virtual_ptr<const Manager>, virtual_ptr<const Taxi>, double),
|
||||
bool) {
|
||||
return true;
|
||||
}
|
||||
|
||||
BOOST_OPENMETHOD_OVERRIDE(
|
||||
approve,
|
||||
(virtual_ptr<const Founder>, virtual_ptr<const Expense>, double),
|
||||
approve, (virtual_ptr<const Founder>, virtual_ptr<const Expense>, double),
|
||||
bool) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -269,3 +269,25 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(shared_virtual_ptr_value, Policy, test_policies) {
|
||||
|
||||
template struct check_illegal_smart_ops<
|
||||
std::shared_ptr, std::unique_ptr, direct_vector_policy>;
|
||||
|
||||
// Cannot construct or assign a virtual_ptr from a non-polymorphic object.
|
||||
static_assert(!construct_assign_ok<
|
||||
virtual_ptr<std::shared_ptr<NonPolymorphic>>,
|
||||
const std::shared_ptr<NonPolymorphic>&>);
|
||||
static_assert(!construct_assign_ok<
|
||||
virtual_ptr<std::shared_ptr<NonPolymorphic>>,
|
||||
std::shared_ptr<NonPolymorphic>&>);
|
||||
static_assert(!construct_assign_ok<
|
||||
virtual_ptr<std::shared_ptr<NonPolymorphic>>,
|
||||
std::shared_ptr<NonPolymorphic>&&>);
|
||||
// OK from another virtual_ptr though, because it can be constructed using
|
||||
// 'final'.
|
||||
static_assert(std::is_assignable_v<
|
||||
virtual_ptr<std::shared_ptr<NonPolymorphic>>,
|
||||
const virtual_ptr<std::shared_ptr<NonPolymorphic>>&>);
|
||||
static_assert(construct_assign_ok<
|
||||
virtual_ptr<std::shared_ptr<NonPolymorphic>>,
|
||||
virtual_ptr<std::shared_ptr<NonPolymorphic>>&>);
|
||||
static_assert(construct_assign_ok<
|
||||
virtual_ptr<std::shared_ptr<NonPolymorphic>>,
|
||||
virtual_ptr<std::shared_ptr<NonPolymorphic>>&&>);
|
||||
|
||||
@@ -254,3 +254,19 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(unique_virtual_ptr_value, Policy, test_policies) {
|
||||
|
||||
template struct check_illegal_smart_ops<
|
||||
std::unique_ptr, std::shared_ptr, direct_vector_policy>;
|
||||
|
||||
// Cannot construct or assign a virtual_ptr from a non-polymorphic object.
|
||||
static_assert(!construct_assign_ok<
|
||||
virtual_ptr<std::unique_ptr<NonPolymorphic>>,
|
||||
const std::unique_ptr<NonPolymorphic>&>);
|
||||
static_assert(!construct_assign_ok<
|
||||
virtual_ptr<std::unique_ptr<NonPolymorphic>>,
|
||||
std::unique_ptr<NonPolymorphic>&>);
|
||||
static_assert(!construct_assign_ok<
|
||||
virtual_ptr<std::unique_ptr<NonPolymorphic>>,
|
||||
std::unique_ptr<NonPolymorphic>&&>);
|
||||
// OK to move from another virtual_ptr though, because it can be constructed
|
||||
// using 'final'.
|
||||
static_assert(construct_assign_ok<
|
||||
virtual_ptr<std::unique_ptr<NonPolymorphic>>,
|
||||
virtual_ptr<std::unique_ptr<NonPolymorphic>>&&>);
|
||||
|
||||
@@ -314,3 +314,19 @@ BOOST_AUTO_TEST_CASE(virtual_ptr_final_error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cannot construct or assign a virtual_ptr from a non-polymorphic object.
|
||||
static_assert(
|
||||
!construct_assign_ok<virtual_ptr<NonPolymorphic>, const NonPolymorphic&>);
|
||||
static_assert(
|
||||
!construct_assign_ok<virtual_ptr<NonPolymorphic>, NonPolymorphic&>);
|
||||
static_assert(
|
||||
!construct_assign_ok<virtual_ptr<NonPolymorphic>, NonPolymorphic&&>);
|
||||
static_assert(
|
||||
!construct_assign_ok<virtual_ptr<NonPolymorphic>, const NonPolymorphic*>);
|
||||
static_assert(
|
||||
!construct_assign_ok<virtual_ptr<NonPolymorphic>, NonPolymorphic*>);
|
||||
// OK from another virtual_ptr though, because it can be constructed using
|
||||
// 'final'.
|
||||
static_assert(construct_assign_ok<
|
||||
virtual_ptr<NonPolymorphic>, virtual_ptr<NonPolymorphic>>);
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include <boost/openmethod/compiler.hpp>
|
||||
#include <boost/openmethod/unique_ptr.hpp>
|
||||
|
||||
#include <utility>
|
||||
|
||||
using namespace boost::openmethod;
|
||||
using namespace boost::openmethod::policies;
|
||||
|
||||
@@ -26,6 +28,12 @@ struct Cat : virtual Animal {};
|
||||
|
||||
struct Dog : Animal {};
|
||||
|
||||
template<class Left, class Right>
|
||||
constexpr bool construct_assign_ok =
|
||||
std::is_constructible_v<Left, Right> && std::is_assignable_v<Left, Right>;
|
||||
|
||||
struct NonPolymorphic {};
|
||||
|
||||
template<class Policy>
|
||||
void init_test() {
|
||||
BOOST_OPENMETHOD_REGISTER(use_classes<Animal, Cat, Dog, Policy>);
|
||||
@@ -37,15 +45,13 @@ void init_test() {
|
||||
struct direct_vector_policy : default_policy::fork<direct_vector_policy> {};
|
||||
|
||||
struct indirect_vector_policy
|
||||
: default_policy::fork<indirect_vector_policy>::replace<
|
||||
extern_vptr, vptr_vector<indirect_vector_policy, indirect_vptr>> {};
|
||||
: default_policy::fork<indirect_vector_policy>::with<indirect_vptr> {};
|
||||
|
||||
struct direct_map_policy : default_policy::fork<direct_map_policy>::replace<
|
||||
extern_vptr, vptr_map<direct_map_policy>> {};
|
||||
struct direct_map_policy : default_policy::fork<direct_map_policy>::with<
|
||||
vptr_map<direct_map_policy>> {};
|
||||
|
||||
struct indirect_map_policy
|
||||
: default_policy::fork<indirect_map_policy>::replace<
|
||||
extern_vptr, vptr_map<indirect_map_policy, indirect_vptr>> {};
|
||||
: default_policy::fork<indirect_map_policy>::with<indirect_vptr> {};
|
||||
|
||||
using test_policies = boost::mp11::mp_list<
|
||||
direct_vector_policy, indirect_vector_policy, direct_map_policy,
|
||||
@@ -118,8 +124,4 @@ struct check_illegal_smart_ops {
|
||||
Animal&>);
|
||||
};
|
||||
|
||||
template<class Left, class Right>
|
||||
constexpr bool construct_assign_ok =
|
||||
std::is_constructible_v<Left, Right> && std::is_assignable_v<Left, Right>;
|
||||
|
||||
#endif // TEST_VIRTUAL_PTR_VALUE_SEMANTICS_HPP
|
||||
|
||||
Reference in New Issue
Block a user