Skip to content

Commit 5c6b7be

Browse files
committed
inter-operate with 'any'
1 parent 72b8703 commit 5c6b7be

File tree

5 files changed

+356
-6
lines changed

5 files changed

+356
-6
lines changed

include/boost/openmethod/core.hpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -525,12 +525,19 @@ constexpr bool has_vptr_fn = std::is_same_v<
525525
std::declval<const Class&>(), std::declval<Registry*>())),
526526
vptr_type>;
527527

528+
BOOST_OPENMETHOD_DETAIL_HAS_STATIC_FN(dynamic_vptr);
529+
528530
template<class Registry, class ArgType>
529531
decltype(auto) acquire_vptr(const ArgType& arg) {
530532
Registry::require_initialized();
531533

532-
if constexpr (detail::has_vptr_fn<ArgType, Registry>) {
534+
if constexpr (has_vptr_fn<ArgType, Registry>) {
533535
return boost_openmethod_vptr(arg, static_cast<Registry*>(nullptr));
536+
} else if constexpr (has_dynamic_vptr<
537+
virtual_traits<const ArgType&, Registry>,
538+
type_id>) {
539+
return virtual_traits<const ArgType&, Registry>::dynamic_vptr(
540+
arg);
534541
} else {
535542
return Registry::template policy<policies::vptr>::dynamic_vptr(arg);
536543
}
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
// Copyright (c) 2018-2026 Jean-Louis Leroy
2+
// Distributed under the Boost Software License, Version 1.0.
3+
// See accompanying file LICENSE_1_0.txt
4+
// or copy at http://www.boost.org/LICENSE_1_0.txt)
5+
6+
#ifndef BOOST_OPENMETHOD_INTEROP_STD_ANY_HPP
7+
#define BOOST_OPENMETHOD_INTEROP_STD_ANY_HPP
8+
9+
#include <any>
10+
#include <boost/openmethod/core.hpp>
11+
12+
namespace boost::openmethod {
13+
14+
namespace detail {
15+
template<class Registry>
16+
struct validate_method_parameter<virtual_<std::any>, Registry, void>
17+
: std::true_type {};
18+
19+
template<class Registry>
20+
struct validate_method_parameter<virtual_<const std::any&>, Registry, void>
21+
: std::true_type {};
22+
23+
template<class Registry>
24+
struct validate_method_parameter<virtual_<std::any&>, Registry, void>
25+
: std::true_type {};
26+
27+
template<class Registry>
28+
struct validate_method_parameter<virtual_<std::any&&>, Registry, void>
29+
: std::true_type {};
30+
31+
} // namespace detail
32+
33+
//! Specialize virtual_traits for std::any by value.
34+
//!
35+
//! Dispatch is based on the runtime type of the value stored in the `any`,
36+
//! obtained via `std::any::type()`. Requires the registry to use a @ref
37+
//! rtti policy that provides `dynamic_type` (e.g. @ref std_rtti).
38+
//!
39+
//! @tparam Registry A @ref registry.
40+
template<class Registry>
41+
struct virtual_traits<std::any, Registry> {
42+
//! The type used for dispatch.
43+
using virtual_type = std::any;
44+
45+
//! Returns a const reference to the `any` argument.
46+
//! @param arg A reference to a `std::any`.
47+
//! @return A const reference to `arg`.
48+
static auto peek(const std::any& arg) -> const std::any& {
49+
return arg;
50+
}
51+
52+
//! Returns a *reference* to a v-table pointer for an object.
53+
//!
54+
//! Acquires the dynamic @ref type_id of `arg`, using the registry's
55+
//! @ref rtti policy.
56+
//!
57+
//! If the registry has a @ref type_hash policy, uses it to convert the
58+
//! type id to an index; otherwise, uses the type_id as the index.
59+
//!
60+
//! If the registry contains the @ref runtime_checks policy, verifies
61+
//! that the index falls within the limits of the vector. If it does
62+
//! not, and if the registry contains a @ref error_handler policy, calls
63+
//! its @ref error function with a @ref missing_class value, then
64+
//! terminates the program with @ref abort.
65+
//!
66+
//! @param arg A reference to a const `any`.
67+
//! @return A reference to a the v-table pointer for `Class`.
68+
static auto dynamic_vptr(const std::any& arg) -> const vptr_type& {
69+
return Registry::rtti::type_vptr(arg.type());
70+
};
71+
72+
//! Cast to a type.
73+
//!
74+
//! Extracts the stored value using `std::any_cast`.
75+
//!
76+
//! @tparam U The target type (e.g. `Dog&`, `const Dog&`, `Dog`).
77+
//! @param arg An rvalue reference to the `std::any` method argument.
78+
//! @return The value stored in `arg`, cast to `U`.
79+
template<typename U>
80+
static auto cast(std::any&& arg) -> decltype(auto) {
81+
return std::any_cast<U>(arg);
82+
}
83+
};
84+
85+
//! Specialize virtual_traits for `std::any&` (mutable reference).
86+
//!
87+
//! @tparam Registry A @ref registry.
88+
template<class Registry>
89+
struct virtual_traits<const std::any&, Registry> {
90+
//! The type used for dispatch.
91+
using virtual_type = std::any;
92+
93+
//! Returns a const reference to the `any` argument.
94+
//! @param arg A reference to a `std::any`.
95+
//! @return A const reference to `arg`.
96+
static auto peek(const std::any& arg) -> const std::any& {
97+
return arg;
98+
}
99+
100+
//! Returns a *reference* to a v-table pointer for an object.
101+
//!
102+
//! Acquires the dynamic @ref type_id of `arg`, using the registry's
103+
//! @ref rtti policy.
104+
//!
105+
//! If the registry has a @ref type_hash policy, uses it to convert the
106+
//! type id to an index; otherwise, uses the type_id as the index.
107+
//!
108+
//! If the registry contains the @ref runtime_checks policy, verifies
109+
//! that the index falls within the limits of the vector. If it does
110+
//! not, and if the registry contains a @ref error_handler policy, calls
111+
//! its @ref error function with a @ref missing_class value, then
112+
//! terminates the program with @ref abort.
113+
//!
114+
//! @param arg A reference to a const `any`.
115+
//! @return A reference to a the v-table pointer for `Class`.
116+
static auto dynamic_vptr(const std::any& arg) -> const vptr_type& {
117+
return Registry::vptr::type_vptr(&arg.type());
118+
};
119+
120+
//! Cast to a type.
121+
//!
122+
//! Extracts the stored value using `std::any_cast`. Supports mutable
123+
//! references (e.g. `Dog&`) because the `any` argument is non-const.
124+
//!
125+
//! @tparam U The target type (e.g. `Dog&`, `const Dog&`, `Dog`).
126+
//! @param arg A mutable reference to the `std::any` method argument.
127+
//! @return The value stored in `arg`, cast to `U`.
128+
template<typename U>
129+
static auto cast(const std::any& arg) -> decltype(auto) {
130+
return std::any_cast<U>(arg);
131+
}
132+
};
133+
134+
//! Specialize virtual_traits for std::any by value.
135+
//!
136+
//! Dispatch is based on the runtime type of the value stored in the `any`,
137+
//! obtained via `std::any::type()`. Requires the registry to use a @ref
138+
//! rtti policy that provides `dynamic_type` (e.g. @ref std_rtti).
139+
//!
140+
//! @tparam Registry A @ref registry.
141+
template<class Registry>
142+
struct virtual_traits<std::any&&, Registry> {
143+
//! The type used for dispatch.
144+
using virtual_type = std::any;
145+
146+
//! Returns a const reference to the `any` argument.
147+
//! @param arg A reference to a `std::any`.
148+
//! @return A const reference to `arg`.
149+
static auto peek(const std::any& arg) -> const std::any& {
150+
return arg;
151+
}
152+
153+
//! Returns a *reference* to a v-table pointer for an object.
154+
//!
155+
//! Acquires the dynamic @ref type_id of `arg`, using the registry's
156+
//! @ref rtti policy.
157+
//!
158+
//! If the registry has a @ref type_hash policy, uses it to convert the
159+
//! type id to an index; otherwise, uses the type_id as the index.
160+
//!
161+
//! If the registry contains the @ref runtime_checks policy, verifies
162+
//! that the index falls within the limits of the vector. If it does
163+
//! not, and if the registry contains a @ref error_handler policy, calls
164+
//! its @ref error function with a @ref missing_class value, then
165+
//! terminates the program with @ref abort.
166+
//!
167+
//! @param arg A reference to a const `any`.
168+
//! @return A reference to a the v-table pointer for `Class`.
169+
static auto dynamic_vptr(const std::any& arg) -> const vptr_type& {
170+
return Registry::rtti::type_vptr(arg.type());
171+
};
172+
173+
//! Cast to a type.
174+
//!
175+
//! Extracts the stored value using `std::any_cast`.
176+
//!
177+
//! @tparam U The target type (e.g. `Dog&`, `const Dog&`, `Dog`).
178+
//! @param arg An rvalue reference to the `std::any` method argument.
179+
//! @return The value stored in `arg`, cast to `U`.
180+
template<typename U>
181+
static auto cast(std::any&& arg) -> decltype(auto) {
182+
return std::any_cast<U>(arg);
183+
}
184+
};
185+
186+
template<typename... T>
187+
struct use_any_types : detail::use_class_aux<
188+
typename detail::extract_registry<T...>::registry,
189+
mp11::mp_list<std::any, std::any>>,
190+
detail::use_class_aux<
191+
typename detail::extract_registry<T...>::registry,
192+
mp11::mp_list<T, std::any>>... {};
193+
194+
} // namespace boost::openmethod
195+
196+
#endif

include/boost/openmethod/policies/vptr_map.hpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,20 @@ class vptr_map : public vptr {
7979
//! @return A reference to a the v-table pointer for `Class`.
8080
template<class Class>
8181
static auto dynamic_vptr(const Class& arg) -> const vptr_type& {
82-
auto type = Registry::rtti::dynamic_type(arg);
82+
return type_vptr(Registry::rtti::dynamic_type(arg));
83+
}
84+
85+
//! Returns a *reference* to a v-table pointer for a type.
86+
//!
87+
//! If the registry contains the @ref runtime_checks policy, checks that
88+
//! the map contains the type id. If it does not, and if the registry
89+
//! contains a @ref error_handler policy, calls its
90+
//! @ref error function with a @ref missing_class value, then
91+
//! terminates the program with @ref abort.
92+
//!
93+
//! @param type A `type_id`.
94+
//! @return A reference to a the v-table pointer for `type`.
95+
static auto type_vptr(type_id type) -> const vptr_type& {
8396
auto iter = vptrs.find(type);
8497

8598
if constexpr (Registry::has_runtime_checks) {

include/boost/openmethod/policies/vptr_vector.hpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,28 @@ struct vptr_vector : vptr {
133133
//! @return A reference to a the v-table pointer for `Class`.
134134
template<class Class>
135135
static auto dynamic_vptr(const Class& arg) -> const vptr_type& {
136-
auto dynamic_type = Registry::rtti::dynamic_type(arg);
136+
return type_vptr(Registry::rtti::dynamic_type(arg));
137+
};
138+
139+
//! Returns a *reference* to a v-table pointer for a type.
140+
//!
141+
//! If the registry has a @ref type_hash policy, uses it to convert the
142+
//! type id to an index; otherwise, uses the type_id as the index.
143+
//!
144+
//! If the registry contains the @ref runtime_checks policy, verifies
145+
//! that the index falls within the limits of the vector. If it does
146+
//! not, and if the registry contains a @ref error_handler policy, calls
147+
//! its @ref error function with a @ref missing_class value, then
148+
//! terminates the program with @ref abort.
149+
//!
150+
//! @param type A `type_id`.
151+
//! @return A reference to a the v-table pointer for `type`.
152+
static auto type_vptr(type_id type) -> const vptr_type& {
137153
std::size_t index;
138154
if constexpr (has_type_hash) {
139-
index = type_hash::hash(dynamic_type);
155+
index = type_hash::hash(type);
140156
} else {
141-
index = std::size_t(dynamic_type);
157+
index = std::size_t(type);
142158

143159
if constexpr (Registry::has_runtime_checks) {
144160
std::size_t max_index = 0;
@@ -153,7 +169,7 @@ struct vptr_vector : vptr {
153169
if (index >= max_index) {
154170
if constexpr (Registry::has_error_handler) {
155171
missing_class error;
156-
error.type = dynamic_type;
172+
error.type = type;
157173
Registry::error_handler::error(error);
158174
}
159175

0 commit comments

Comments
 (0)