|
15 | 15 | #include <type_traits> |
16 | 16 | #include <utility> |
17 | 17 |
|
| 18 | +#ifdef __cpp_rtti |
| 19 | +#ifndef __cpp_exceptions |
| 20 | +#include <cstdlib> // For std::abort() when "throw" is not available |
| 21 | +#endif // __cpp_exceptions |
| 22 | +#include <optional> |
| 23 | +#include <typeinfo> |
| 24 | +#endif // __cpp_rtti |
| 25 | + |
18 | 26 | #if __has_cpp_attribute(msvc::no_unique_address) |
19 | 27 | #define ___PRO_NO_UNIQUE_ADDRESS_ATTRIBUTE msvc::no_unique_address |
20 | 28 | #elif __has_cpp_attribute(no_unique_address) |
@@ -1240,6 +1248,10 @@ using proxy_view = proxy<observer_facade<F>>; |
1240 | 1248 | ___PRO_DEBUG( \ |
1241 | 1249 | accessor() noexcept { ::std::ignore = &accessor::__VA_ARGS__; }) |
1242 | 1250 |
|
| 1251 | +#ifdef __cpp_rtti |
| 1252 | +struct bad_proxy_cast : std::bad_cast {}; |
| 1253 | +#endif // __cpp_rtti |
| 1254 | + |
1243 | 1255 | namespace details { |
1244 | 1256 |
|
1245 | 1257 | template <class F, class C> |
@@ -1537,6 +1549,113 @@ struct sign { |
1537 | 1549 | template <std::size_t N> |
1538 | 1550 | sign(const char (&str)[N]) -> sign<N>; |
1539 | 1551 |
|
| 1552 | +#ifdef __cpp_rtti |
| 1553 | +#ifdef __cpp_exceptions |
| 1554 | +#define ___PRO_THROW(...) throw __VA_ARGS__ |
| 1555 | +#else |
| 1556 | +#define ___PRO_THROW(...) std::abort() |
| 1557 | +#endif // __cpp_exceptions |
| 1558 | + |
| 1559 | +struct proxy_cast_context { |
| 1560 | + const std::type_info* type_ptr; |
| 1561 | + bool is_ref; |
| 1562 | + bool is_const; |
| 1563 | + void* result_ptr; |
| 1564 | +}; |
| 1565 | + |
| 1566 | +template <class F, class C, class O> |
| 1567 | +struct proxy_cast_accessor_impl { |
| 1568 | + using _Self = |
| 1569 | + add_qualifier_t<adl_accessor_arg_t<F, C>, overload_traits<O>::qualifier>; |
| 1570 | + template <class T> |
| 1571 | + friend T proxy_cast(_Self self) { |
| 1572 | + static_assert(!std::is_rvalue_reference_v<T>); |
| 1573 | + if (!access_proxy<F>(self).has_value()) { ___PRO_THROW(bad_proxy_cast{}); } |
| 1574 | + if constexpr (std::is_lvalue_reference_v<T>) { |
| 1575 | + using U = std::remove_reference_t<T>; |
| 1576 | + void* result = nullptr; |
| 1577 | + proxy_cast_context ctx{.type_ptr = &typeid(T), .is_ref = true, |
| 1578 | + .is_const = std::is_const_v<U>, .result_ptr = &result}; |
| 1579 | + proxy_invoke<C, O>(access_proxy<F>(std::forward<_Self>(self)), ctx); |
| 1580 | + if (result == nullptr) { ___PRO_THROW(bad_proxy_cast{}); } |
| 1581 | + return *static_cast<U*>(result); |
| 1582 | + } else { |
| 1583 | + std::optional<std::remove_const_t<T>> result; |
| 1584 | + proxy_cast_context ctx{.type_ptr = &typeid(T), .is_ref = false, |
| 1585 | + .is_const = false, .result_ptr = &result}; |
| 1586 | + proxy_invoke<C, O>(access_proxy<F>(std::forward<_Self>(self)), ctx); |
| 1587 | + if (!result.has_value()) { ___PRO_THROW(bad_proxy_cast{}); } |
| 1588 | + return std::move(*result); |
| 1589 | + } |
| 1590 | + } |
| 1591 | + template <class T> |
| 1592 | + friend T* proxy_cast(std::remove_reference_t<_Self>* self) noexcept |
| 1593 | + requires(std::is_lvalue_reference_v<_Self>) { |
| 1594 | + if (!access_proxy<F>(*self).has_value()) { return nullptr; } |
| 1595 | + void* result = nullptr; |
| 1596 | + proxy_cast_context ctx{.type_ptr = &typeid(T), .is_ref = true, |
| 1597 | + .is_const = std::is_const_v<T>, .result_ptr = &result}; |
| 1598 | + proxy_invoke<C, O>(access_proxy<F>(*self), ctx); |
| 1599 | + return static_cast<T*>(result); |
| 1600 | + } |
| 1601 | +}; |
| 1602 | + |
| 1603 | +#define ___PRO_DEF_PROXY_CAST_ACCESSOR(Q, ...) \ |
| 1604 | + template <class F, class C> \ |
| 1605 | + struct accessor<F, C, void(proxy_cast_context) Q> \ |
| 1606 | + : proxy_cast_accessor_impl<F, C, void(proxy_cast_context) Q> {} |
| 1607 | +struct proxy_cast_dispatch { |
| 1608 | + template <class T> |
| 1609 | + void operator()(T&& self, proxy_cast_context ctx) { |
| 1610 | + if (typeid(T) == *ctx.type_ptr) { |
| 1611 | + if (ctx.is_ref) { |
| 1612 | + if constexpr (std::is_lvalue_reference_v<T>) { |
| 1613 | + if (ctx.is_const || !std::is_const_v<T>) { |
| 1614 | + *static_cast<void**>(ctx.result_ptr) = (void*)&self; |
| 1615 | + } |
| 1616 | + } |
| 1617 | + } else { |
| 1618 | + if constexpr (std::is_constructible_v<std::decay_t<T>, T>) { |
| 1619 | + static_cast<std::optional<std::decay_t<T>>*>(ctx.result_ptr) |
| 1620 | + ->emplace(std::forward<T>(self)); |
| 1621 | + } |
| 1622 | + } |
| 1623 | + } |
| 1624 | + } |
| 1625 | + ___PRO_DEF_FREE_ACCESSOR_TEMPLATE(___PRO_DEF_PROXY_CAST_ACCESSOR) |
| 1626 | +}; |
| 1627 | +#undef ___PRO_DEF_PROXY_CAST_ACCESSOR |
| 1628 | + |
| 1629 | +struct proxy_typeid_reflector { |
| 1630 | + template <class T> |
| 1631 | + constexpr explicit proxy_typeid_reflector(std::in_place_type_t<T>) |
| 1632 | + : info(&typeid(T)) {} |
| 1633 | + constexpr proxy_typeid_reflector(const proxy_typeid_reflector&) = default; |
| 1634 | + |
| 1635 | + template <class F, class R> |
| 1636 | + struct accessor { |
| 1637 | + friend const std::type_info& proxy_typeid( |
| 1638 | + const adl_accessor_arg_t<F, R>& self) noexcept { |
| 1639 | + const proxy<F>& p = access_proxy<F>(self); |
| 1640 | + if (!p.has_value()) { return typeid(void); } |
| 1641 | + const proxy_typeid_reflector& refl = proxy_reflect<R>(p); |
| 1642 | + return *refl.info; |
| 1643 | + } |
| 1644 | +___PRO_DEBUG( |
| 1645 | + accessor() noexcept { std::ignore = &accessor::_symbol_guard; } |
| 1646 | + |
| 1647 | + private: |
| 1648 | + static inline const std::type_info& _symbol_guard( |
| 1649 | + const adl_accessor_arg_t<F, R>& self) noexcept |
| 1650 | + { return proxy_typeid(self); } |
| 1651 | +) |
| 1652 | + }; |
| 1653 | + |
| 1654 | + const std::type_info* info; |
| 1655 | +}; |
| 1656 | +#undef ___PRO_THROW |
| 1657 | +#endif // __cpp_rtti |
| 1658 | + |
1540 | 1659 | } // namespace details |
1541 | 1660 |
|
1542 | 1661 | template <class Cs, class Rs, proxiable_ptr_constraints C> |
@@ -1582,6 +1701,25 @@ struct basic_facade_builder { |
1582 | 1701 | template <constraint_level CL> |
1583 | 1702 | using support_destruction = basic_facade_builder< |
1584 | 1703 | Cs, Rs, details::make_destructible(C, CL)>; |
| 1704 | +#ifdef __cpp_rtti |
| 1705 | + using support_indirect_rtti = |
| 1706 | + basic_facade_builder< |
| 1707 | + details::add_conv_t<Cs, details::conv_impl<false, |
| 1708 | + details::proxy_cast_dispatch, void(details::proxy_cast_context) &, |
| 1709 | + void(details::proxy_cast_context) const&, |
| 1710 | + void(details::proxy_cast_context) &&>>, |
| 1711 | + details::add_tuple_t<Rs, details::refl_impl<false, |
| 1712 | + details::proxy_typeid_reflector>>, C>; |
| 1713 | + using support_direct_rtti = |
| 1714 | + basic_facade_builder< |
| 1715 | + details::add_conv_t<Cs, details::conv_impl<true, |
| 1716 | + details::proxy_cast_dispatch, void(details::proxy_cast_context) &, |
| 1717 | + void(details::proxy_cast_context) const&, |
| 1718 | + void(details::proxy_cast_context) &&>>, |
| 1719 | + details::add_tuple_t<Rs, details::refl_impl<true, |
| 1720 | + details::proxy_typeid_reflector>>, C>; |
| 1721 | + using support_rtti = support_indirect_rtti; |
| 1722 | +#endif // __cpp_rtti |
1585 | 1723 | template <class F> |
1586 | 1724 | using add_view = add_direct_convention< |
1587 | 1725 | details::proxy_view_dispatch, details::proxy_view_overload<F>>; |
|
0 commit comments