diff --git a/README.md b/README.md index f9591207..65f401e1 100644 --- a/README.md +++ b/README.md @@ -208,7 +208,7 @@ The "Proxy" library is a self-contained solution for runtime polymorphism in C++ - **Allocator awareness**: [function template `allocate_proxy`](https://microsoft.github.io/proxy/docs/allocate_proxy.html) is able to create a `proxy` from a value with any custom allocator. In C++11, [`std::function`](https://en.cppreference.com/w/cpp/utility/functional/function) and [`std::packaged_task`](https://en.cppreference.com/w/cpp/thread/packaged_task) had constructors that accepted custom allocators for performance tuning, but these were [removed in C++17](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0302r1.html) because "the semantics are unclear, and there are technical issues with storing an allocator in a type-erased context and then recovering that allocator later for any allocations needed during copy assignment". These issues do not apply to `allocate_proxy`. - **Configurable constraints**: [`facade_builder`](https://microsoft.github.io/proxy/docs/basic_facade_builder.html) provides full support for constraints configuration, including memory layout (by [`restrict_layout`](https://microsoft.github.io/proxy/docs/basic_facade_builder/restrict_layout.html)), copyability (by [`support_copy`](https://microsoft.github.io/proxy/docs/basic_facade_builder/support_copy.html)), relocatability (by [`support_relocation`](https://microsoft.github.io/proxy/docs/basic_facade_builder/support_relocation.html)), and destructibility (by [`support_destruction`](https://microsoft.github.io/proxy/docs/basic_facade_builder/support_destruction.html)). - **Reflection**: `proxy` supports type-based compile-time reflection for runtime queries. Please refer to [`facade_builder::add_reflection`](https://microsoft.github.io/proxy/docs/basic_facade_builder/add_reflection.html) and [function template `proxy_reflect`](https://microsoft.github.io/proxy/docs/proxy_reflect.html) for more details. -- **Non-owning proxy**: Although `proxy` can manage the lifetime of an object effectively, similar to a smart pointer, we sometimes want to dereference it before passing to a non-owning context. This has been implemented as an extension since 3.2. Please refer to [class template `observer_facade`, alias template `proxy_view`](https://microsoft.github.io/proxy/docs/observer_facade.html) and [`facade_builder::add_view`](https://microsoft.github.io/proxy/docs/basic_facade_builder/add_view.html) for more details. +- **Non-owning proxy**: Although `proxy` can manage the lifetime of an object effectively, similar to a smart pointer, we sometimes want to dereference it before passing to a non-owning context. This has been implemented as an extension since 3.2. Please refer to [alias template `proxy_view`, class template `observer_facade`](https://microsoft.github.io/proxy/docs/proxy_view.html) and [`facade_builder::add_view`](https://microsoft.github.io/proxy/docs/basic_facade_builder/add_view.html) for more details. - **RTTI**: [RTTI (run-time type information)](https://en.wikipedia.org/wiki/Run-time_type_information) provides "weak" reflection capability in C++ since the last century. Although it is not as powerful as reflection in some other languages (like `Object.GetType()` in C# or `Object.getClass()` in Java), it offers the basic infrastructure for type-safe casting at runtime. Since 3.2, "RTTI for `proxy`" has been implemented as an extension and allows users to opt-in for each facade definition. Please refer to [`facade_builder::support_rtti`](https://microsoft.github.io/proxy/docs/basic_facade_builder/support_rtti.html) for more details. - **Weak dispatch**: When an object does not implement a convention, and we do not want it to trigger a hard compile error, it is allowed to specify a [`weak_dispatch`](https://microsoft.github.io/proxy/docs/weak_dispatch.html) that throws when invoked. diff --git a/docs/access_proxy.md b/docs/access_proxy.md index 98b6b0c9..97acc66d 100644 --- a/docs/access_proxy.md +++ b/docs/access_proxy.md @@ -24,7 +24,7 @@ A reference to the `proxy` that has instantiated `a`. Similar to [`proxy_invoke`](proxy_invoke.md), this function can be used to implement the accessibility of `proxy`. If the facade type `F` is defined with the recommended facilities, it has full accessibility support. Specifically, when: -- the underlying dispatch type `typename C::dispatch_type` is defined via [macro `PRO_DEF_MEM_DISPATCH`](PRO_DEF_MEM_DISPATCH.md), [macro `PRO_DEF_FREE_DISPATCH`](PRO_DEF_FREE_DISPATCH.md), or is a specialization of either [`operator_dispatch`](operator_dispatch.md) or [`conversion_dispatch`](conversion_dispatch.md), and +- the underlying dispatch type `typename C::dispatch_type` is defined via [macro `PRO_DEF_MEM_DISPATCH`](PRO_DEF_MEM_DISPATCH.md), [macro `PRO_DEF_FREE_DISPATCH`](PRO_DEF_FREE_DISPATCH.md), or is a specialization of either [`operator_dispatch`](operator_dispatch.md) or [`conversion_dispatch`](explicit_conversion_dispatch.md), and - the convention is defined via [`facade_builder`](basic_facade_builder.md). ## Example diff --git a/docs/basic_facade_builder/add_convention.md b/docs/basic_facade_builder/add_convention.md index 03bfa494..03dc3fa6 100644 --- a/docs/basic_facade_builder/add_convention.md +++ b/docs/basic_facade_builder/add_convention.md @@ -68,5 +68,5 @@ int main() { - [macro `PRO_DEF_MEM_DISPATCH`](../PRO_DEF_MEM_DISPATCH.md) - [macro `PRO_DEF_FREE_DISPATCH`](../PRO_DEF_FREE_DISPATCH.md) - [class template `operator_dispatch`](../operator_dispatch.md) -- [class template `conversion_dispatch`](../conversion_dispatch.md) +- [class `conversion_dispatch`](../explicit_conversion_dispatch.md) - [macro `PRO_DEF_WEAK_DISPATCH`](../PRO_DEF_WEAK_DISPATCH.md) diff --git a/docs/basic_facade_builder/add_reflection.md b/docs/basic_facade_builder/add_reflection.md index a31e7c3f..4edc03a8 100644 --- a/docs/basic_facade_builder/add_reflection.md +++ b/docs/basic_facade_builder/add_reflection.md @@ -32,38 +32,59 @@ Adding duplicate reflection types is well-defined, whether done directly via `ad ## Example ```cpp +#include #include -#include #include "proxy.h" -class RttiReflector { +struct LayoutReflector { public: template - constexpr explicit RttiReflector(std::in_place_type_t) : type_(typeid(T)) {} + constexpr explicit LayoutReflector(std::in_place_type_t) + : Size(sizeof(T)), Align(alignof(T)) {} template struct accessor { - const char* GetTypeName() const noexcept { - const RttiReflector& self = pro::proxy_reflect(pro::access_proxy(*this)); - return self.type_.name(); + friend std::size_t SizeOf(const std::conditional_t, + pro::proxy_indirect_accessor>& self) noexcept { + const LayoutReflector& refl = pro::proxy_reflect(pro::access_proxy(self)); + return refl.Size; + } + + friend std::size_t AlignOf(const std::conditional_t, + pro::proxy_indirect_accessor>& self) noexcept { + const LayoutReflector& refl = pro::proxy_reflect(pro::access_proxy(self)); + return refl.Align; } }; - private: - const std::type_info& type_; + std::size_t Size, Align; }; -struct RttiAware : pro::facade_builder - ::add_direct_reflection - ::add_indirect_reflection +struct LayoutAware : pro::facade_builder + ::add_direct_reflection + ::add_indirect_reflection ::build {}; int main() { int a = 123; - pro::proxy p = &a; - std::cout << p.GetTypeName() << "\n"; // Prints "Pi" (assuming GCC) - std::cout << p->GetTypeName() << "\n"; // Prints "i" (assuming GCC) + pro::proxy p = &a; + std::cout << SizeOf(p) << "\n"; // Prints sizeof(raw pointer) + std::cout << AlignOf(p) << "\n"; // Prints alignof(raw pointer) + std::cout << SizeOf(*p) << "\n"; // Prints sizeof(int) + std::cout << AlignOf(*p) << "\n"; // Prints alignof(int) + + p = pro::make_proxy(123); // SBO enabled + std::cout << SizeOf(p) << "\n"; // Prints sizeof(int) + std::cout << AlignOf(p) << "\n"; // Prints alignof(int) + std::cout << SizeOf(*p) << "\n"; // Prints sizeof(int) + std::cout << AlignOf(*p) << "\n"; // Prints alignof(int) + + p = pro::make_proxy>(); // SBO disabled + std::cout << SizeOf(p) << "\n"; // Prints sizeof(raw pointer) + std::cout << AlignOf(p) << "\n"; // Prints alignof(raw pointer) + std::cout << SizeOf(*p) << "\n"; // Prints "100" + std::cout << AlignOf(*p) << "\n"; // Prints "1" } ``` diff --git a/docs/basic_facade_builder/add_view.md b/docs/basic_facade_builder/add_view.md index 8664745d..819b4f63 100644 --- a/docs/basic_facade_builder/add_view.md +++ b/docs/basic_facade_builder/add_view.md @@ -19,9 +19,7 @@ Let `p` be a value of type `proxy`, `ptr` be the contained value of `p` (if a ## Example ```cpp -#include #include -#include #include "proxy.h" diff --git a/docs/basic_facade_builder/support_rtti/proxy_cast.md b/docs/basic_facade_builder/support_rtti/proxy_cast.md index 66f17802..8922cb57 100644 --- a/docs/basic_facade_builder/support_rtti/proxy_cast.md +++ b/docs/basic_facade_builder/support_rtti/proxy_cast.md @@ -85,8 +85,8 @@ int main() { std::cout << e.what() << "\n"; // Prints an explanatory string } int* ptr1 = proxy_cast(&*p); - std::cout << std::boolalpha << ptr1 << "\n"; // Prints an address - std::cout << std::boolalpha << &v << "\n"; // Prints the same address as above + std::cout << ptr1 << "\n"; // Prints an address + std::cout << &v << "\n"; // Prints the same address as above double* ptr2 = proxy_cast(&*p); std::cout << ptr2 << "\n"; // Prints "0" } diff --git a/docs/proxy_invoke.md b/docs/proxy_invoke.md index 88c027dc..0ab968bf 100644 --- a/docs/proxy_invoke.md +++ b/docs/proxy_invoke.md @@ -32,7 +32,7 @@ The behavior is undefined if `p` does not contain a value. It is generally not recommended to call `proxy_invoke` directly. Using an [`accessor`](ProAccessible.md) is usually a better option with easier and more descriptive syntax. If the facade type `F` is defined with the recommended facilities, it has full accessibility support. Specifically, when -- `D` is defined via [macro `PRO_DEF_MEM_DISPATCH`](PRO_DEF_MEM_DISPATCH.md), [macro `PRO_DEF_FREE_DISPATCH`](PRO_DEF_FREE_DISPATCH.md), or is a specialization of either [`operator_dispatch`](operator_dispatch.md) or [`conversion_dispatch`](conversion_dispatch.md), and +- `D` is defined via [macro `PRO_DEF_MEM_DISPATCH`](PRO_DEF_MEM_DISPATCH.md), [macro `PRO_DEF_FREE_DISPATCH`](PRO_DEF_FREE_DISPATCH.md), or is a specialization of either [`operator_dispatch`](operator_dispatch.md) or [`conversion_dispatch`](explicit_conversion_dispatch.md), and - the convention type `Conv` is defined via [`facade_builder`](basic_facade_builder.md). ## Example diff --git a/samples/basic_facade_builder/add_reflection.cpp b/samples/basic_facade_builder/add_reflection.cpp index 4df8a5d6..e0b91e54 100644 --- a/samples/basic_facade_builder/add_reflection.cpp +++ b/samples/basic_facade_builder/add_reflection.cpp @@ -2,36 +2,57 @@ // Licensed under the MIT License. // This file contains example code from add_reflection.md. +#include #include -#include #include "proxy.h" -class RttiReflector { +struct LayoutReflector { public: template - constexpr explicit RttiReflector(std::in_place_type_t) : type_(typeid(T)) {} + constexpr explicit LayoutReflector(std::in_place_type_t) + : Size(sizeof(T)), Align(alignof(T)) {} template struct accessor { - const char* GetTypeName() const noexcept { - const RttiReflector& self = pro::proxy_reflect(pro::access_proxy(*this)); - return self.type_.name(); + friend std::size_t SizeOf(const std::conditional_t, + pro::proxy_indirect_accessor>& self) noexcept { + const LayoutReflector& refl = pro::proxy_reflect(pro::access_proxy(self)); + return refl.Size; + } + + friend std::size_t AlignOf(const std::conditional_t, + pro::proxy_indirect_accessor>& self) noexcept { + const LayoutReflector& refl = pro::proxy_reflect(pro::access_proxy(self)); + return refl.Align; } }; - private: - const std::type_info& type_; + std::size_t Size, Align; }; -struct RttiAware : pro::facade_builder - ::add_direct_reflection - ::add_indirect_reflection +struct LayoutAware : pro::facade_builder + ::add_direct_reflection + ::add_indirect_reflection ::build {}; int main() { int a = 123; - pro::proxy p = &a; - std::cout << p.GetTypeName() << "\n"; // Prints "Pi" (assuming GCC) - std::cout << p->GetTypeName() << "\n"; // Prints "i" (assuming GCC) + pro::proxy p = &a; + std::cout << SizeOf(p) << "\n"; // Prints sizeof(raw pointer) + std::cout << AlignOf(p) << "\n"; // Prints alignof(raw pointer) + std::cout << SizeOf(*p) << "\n"; // Prints sizeof(int) + std::cout << AlignOf(*p) << "\n"; // Prints alignof(int) + + p = pro::make_proxy(123); // SBO enabled + std::cout << SizeOf(p) << "\n"; // Prints sizeof(int) + std::cout << AlignOf(p) << "\n"; // Prints alignof(int) + std::cout << SizeOf(*p) << "\n"; // Prints sizeof(int) + std::cout << AlignOf(*p) << "\n"; // Prints alignof(int) + + p = pro::make_proxy>(); // SBO disabled + std::cout << SizeOf(p) << "\n"; // Prints sizeof(raw pointer) + std::cout << AlignOf(p) << "\n"; // Prints alignof(raw pointer) + std::cout << SizeOf(*p) << "\n"; // Prints "100" + std::cout << AlignOf(*p) << "\n"; // Prints "1" } diff --git a/samples/basic_facade_builder/add_view.cpp b/samples/basic_facade_builder/add_view.cpp index 81834295..7f18fde4 100644 --- a/samples/basic_facade_builder/add_view.cpp +++ b/samples/basic_facade_builder/add_view.cpp @@ -2,9 +2,7 @@ // Licensed under the MIT License. // This file contains example code from add_view.md. -#include #include -#include #include "proxy.h" diff --git a/samples/basic_facade_builder/support_rtti/proxy_cast.cpp b/samples/basic_facade_builder/support_rtti/proxy_cast.cpp index 1b84407a..25ab381c 100644 --- a/samples/basic_facade_builder/support_rtti/proxy_cast.cpp +++ b/samples/basic_facade_builder/support_rtti/proxy_cast.cpp @@ -28,8 +28,8 @@ int main() { std::cout << e.what() << "\n"; // Prints an explanatory string } int* ptr1 = proxy_cast(&*p); - std::cout << std::boolalpha << ptr1 << "\n"; // Prints an address - std::cout << std::boolalpha << &v << "\n"; // Prints the same address as above + std::cout << ptr1 << "\n"; // Prints an address + std::cout << &v << "\n"; // Prints the same address as above double* ptr2 = proxy_cast(&*p); std::cout << ptr2 << "\n"; // Prints "0" }