diff --git a/docs/PRO_DEF_FREE_AS_MEM_DISPATCH.md b/docs/PRO_DEF_FREE_AS_MEM_DISPATCH.md new file mode 100644 index 0000000..a917e92 --- /dev/null +++ b/docs/PRO_DEF_FREE_AS_MEM_DISPATCH.md @@ -0,0 +1,71 @@ +# Macro `PRO_DEF_FREE_AS_MEM_DISPATCH` + +```cpp +#define PRO_DEF_FREE_AS_MEM_DISPATCH // see below +``` + +Macro `PRO_DEF_FREE_AS_MEM_DISPATCH` defines dispatch types for free function expressions with accessibility via a member function. It supports two syntaxes: + +```cpp +// (1) +PRO_DEF_FREE_AS_MEM_DISPATCH(dispatch_name, func_name); + +// (2) +PRO_DEF_FREE_AS_MEM_DISPATCH(dispatch_name, func_name, accessibility_func_name); +``` + +`(1)` Equivalent to `PRO_DEF_FREE_AS_MEM_DISPATCH(dispatch_name, func_name, func_name);` + +`(2)` Defines a class named `dispatch_name` of free function call expressions of `func_name` with accessibility via a member function. `dispatch_name` meets the [*ProAccessible*](ProAccessible.md) requirements of types `F`, `C`, and `Os...`, where `F` models concept [`facade`](facade.md), `C` is a tuple element type defined in `typename F::convention_types`, and each type `O` (possibly qualified with *cv ref noex*) in `Os...` is a tuple element type defined in `typename C::overload_types`. The member functions provided by `typename dispatch_name::template accessor` are named `accessibility_func_name`. Let `SELF` be `std::forward(*this)`, effectively equivalent to: + +```cpp +struct dispatch_name { + template + decltype(auto) operator()(T&& self, Args&&... args) + noexcept(noexcept(func_name(std::forward(self), std::forward(args)...))) + requires(requires { func_name(std::forward(self), std::forward(args)...); }) { + return func_name(std::forward(self), std::forward(args)...); + } + + template + struct accessor { + accessor() = delete; + }; + template + requires(sizeof...(Os) > 1u && (std::is_trivial_v> && ...)) + struct accessor : accessor... { + using accessor::accessibility_func_name ...; + }; + template + struct accessor { + R accessibility_func_name(Args... args) cv ref noex { + return pro::proxy_invoke(pro::access_proxy(SELF), std::forward(args)...); + } + }; +} +``` + +## Example + +```cpp +#include +#include + +#include "proxy.h" + +PRO_DEF_FREE_AS_MEM_DISPATCH(FreeToString, std::to_string, ToString); + +struct Stringable : pro::facade_builder + ::add_convention + ::build {}; + +int main() { + pro::proxy p = pro::make_proxy(123); + std::cout << p->ToString() << "\n"; // Prints: "123" +} +``` + +## See Also + +- [macro `PRO_DEF_FREE_DISPATCH`](PRO_DEF_FREE_DISPATCH.md) +- [alias template `basic_facade_builder::add_convention`](basic_facade_builder/add_convention.md) diff --git a/docs/PRO_DEF_FREE_DISPATCH.md b/docs/PRO_DEF_FREE_DISPATCH.md index 60d9617..710555e 100644 --- a/docs/PRO_DEF_FREE_DISPATCH.md +++ b/docs/PRO_DEF_FREE_DISPATCH.md @@ -39,7 +39,7 @@ struct dispatch_name { return pro::proxy_invoke(pro::access_proxy(SELF), std::forward(args)...); } }; -}; +} ``` ## Example @@ -65,4 +65,5 @@ int main() { ## See Also - [macro `PRO_DEF_MEM_DISPATCH`](PRO_DEF_MEM_DISPATCH.md) +- [macro `PRO_DEF_FREE_AS_MEM_DISPATCH`](PRO_DEF_FREE_AS_MEM_DISPATCH.md) - [alias template `basic_facade_builder::add_convention`](basic_facade_builder/add_convention.md) diff --git a/docs/PRO_DEF_MEM_DISPATCH.md b/docs/PRO_DEF_MEM_DISPATCH.md index 1857974..8239a84 100644 --- a/docs/PRO_DEF_MEM_DISPATCH.md +++ b/docs/PRO_DEF_MEM_DISPATCH.md @@ -42,7 +42,7 @@ struct dispatch_name { return pro::proxy_invoke(pro::access_proxy(SELF), std::forward(args)...); } }; -}; +} ``` ## Example diff --git a/docs/PRO_DEF_WEAK_DISPATCH.md b/docs/PRO_DEF_WEAK_DISPATCH.md index cc16606..72b03e4 100644 --- a/docs/PRO_DEF_WEAK_DISPATCH.md +++ b/docs/PRO_DEF_WEAK_DISPATCH.md @@ -21,7 +21,7 @@ struct dispatch_name : existing_dispatch { requires(requires { default_func_name(std::forward(args)...); }) { return default_func_name(std::forward(args)...); } -}; +} ``` ## Notes diff --git a/docs/ProBasicReflection.md b/docs/ProBasicReflection.md new file mode 100644 index 0000000..17e785e --- /dev/null +++ b/docs/ProBasicReflection.md @@ -0,0 +1,13 @@ +# Named requirements: *ProBasicReflection* + +A type `R` meets the *ProBasicReflection* requirements if the following expressions are well-formed and have the specified semantics. + +| Expressions | Semantics | +| ---------------------------- | ------------------------------------------------------------ | +| `R::is_direct` | A [core constant expression](https://en.cppreference.com/w/cpp/language/constant_expression) of type `bool`, specifying whether the reflection applies to a pointer type itself (`true`), or the element type of a pointer type (`false`). | +| `typename R::reflector_type` | A [trivial type](https://en.cppreference.com/w/cpp/named_req/TrivialType) that defines the data structure reflected from the type. | + +## See Also + +- [*ProBasicFacade* requirements](ProBasicFacade.md) +- [*ProReflection* requirements](ProReflection.md) diff --git a/docs/ProReflection.md b/docs/ProReflection.md index b8f0af6..dc75fb5 100644 --- a/docs/ProReflection.md +++ b/docs/ProReflection.md @@ -1,10 +1,10 @@ # Named requirements: *ProReflection* -A type `R` meets the *ProReflection* requirements of a type `P` if the following expressions are well-formed and have the specified semantics. +A type `R` meets the *ProReflection* requirements of a type `P` if `R` meets the [*ProBasicReflection* requirements](ProBasicReflection.md), and the following expressions are well-formed and have the specified semantics (let `T` be `P` when `R::is_direct` is `true`, or otherwise `typename std::pointer_traits

::element_type`). -| Expressions | Semantics | -| -------------------------- | ------------------------------------------------------------ | -| `R{std::in_place_type

}` | A [core constant expression](https://en.cppreference.com/w/cpp/language/constant_expression) that constructs a value of type `R`, reflecting implementation-defined metadata of type `P`. | +| Expressions | Semantics | +| --------------------------------------------------- | ------------------------------------------------------------ | +| `typename R::reflector_type{std::in_place_type}` | A [core constant expression](https://en.cppreference.com/w/cpp/language/constant_expression) that constructs a value of type `typename R::reflector_type`, reflecting implementation-defined metadata of type `T`. | ## See Also diff --git a/docs/basic_facade_builder.md b/docs/basic_facade_builder.md index 5bbd1fd..d080ec9 100644 --- a/docs/basic_facade_builder.md +++ b/docs/basic_facade_builder.md @@ -36,7 +36,7 @@ using facade_builder = basic_facade_builder, std::tuple<>, | Name | Description | | ------------------------------------------------------------ | ------------------------------------------------------------ | | [`add_convention`
`add_indirect_convention`
`add_direct_convention`](basic_facade_builder/add_convention.md) | Adds a convention to the template parameters | -| [`add_reflection`](basic_facade_builder/add_reflection.md) | Adds a reflection to the template parameters | +| [`add_reflection`
`add_indirect_reflection`
`add_direct_reflection`](basic_facade_builder/add_reflection.md) | Adds a reflection to the template parameters | | [`add_facade`](basic_facade_builder/add_facade.md) | Adds a facade to the template parameters | | [`restrict_layout`](basic_facade_builder/restrict_layout.md) | Specifies maximum `max_size` and `max_align` of `C` in the template parameters | | [`support_copy`](basic_facade_builder/support_copy.md) | Specifies minimum `copyability` of `C` in the template parameters | diff --git a/docs/basic_facade_builder/add_convention.md b/docs/basic_facade_builder/add_convention.md index 7e66f8c..afecaa6 100644 --- a/docs/basic_facade_builder/add_convention.md +++ b/docs/basic_facade_builder/add_convention.md @@ -18,12 +18,12 @@ The alias templates `add_convention`, `add_indirect_convention`, and `add_direct - `IC::is_direct` is `false`. - `typename IC::dispatch_type` is `D`. - `typename IC::overload_types` is a [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type of distinct types in `Os`. - - `typename IC::template accessor` is `typename D::template accessor`. + - `typename IC::template accessor` is `typename D::template accessor` if applicable. - `add_direct_convention` merges an implementation-defined convention type `IC` into `Cs`, where: - `IC::is_direct` is `true`. - `typename IC::dispatch_type` is `D`. - `typename IC::overload_types` is a [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type of distinct types in `Os`. - - `typename IC::template accessor` is `typename D::template accessor`. + - `typename IC::template accessor` is `typename D::template accessor` if applicable. When `Cs` already contains a convention type `IC2` where `IC2::is_direct == IC::is_direct && std::is_same_v` is `true`, `Os` merges with `typename IC2::overload_types` and removes duplicates, and `std::tuple_size_v` shall not change. diff --git a/docs/basic_facade_builder/add_reflection.md b/docs/basic_facade_builder/add_reflection.md index 9ac03a5..df2ae0e 100644 --- a/docs/basic_facade_builder/add_reflection.md +++ b/docs/basic_facade_builder/add_reflection.md @@ -2,14 +2,32 @@ ```cpp template -using add_reflection = basic_facade_builder; +using add_reflection = add_indirect_reflection; + +template +using add_indirect_reflection = basic_facade_builder; + +template +using add_direct_reflection = basic_facade_builder; ``` -The alias template `add_reflection` of `basic_facade_builder` incorporates reflection types (see [named requirements: *ProReflection*](../ProReflection.md)) into the template parameters. It merges `R` into `Rs` if `Rs` does not already contain `R`. +The alias templates `add_reflection`, `add_indirect_reflection` and `add_direct_reflection` of `basic_facade_builder` add reflection types to the template parameters. Specifically, + +- `add_reflection` is equivalent to `add_indirect_reflection`. +- `add_indirect_reflection` merges an implementation-defined reflection type `R2` into `Rs`, where: + - `R2::is_direct` is `false`. + - `typename R2::reflector_type` is `R`. + - `typename R2::template accessor` is `typename R2::template accessor` if applicable. +- `add_direct_reflection` merges an implementation-defined reflection type `R2` into `Rs`, where: + - `R2::is_direct` is `true`. + - `typename R2::reflector_type` is `R`. + - `typename R2::template accessor` is `typename R2::template accessor` if applicable. + +When `Rs` already contains `R2`, the template parameters shall not change. ## Notes -Adding duplicate reflection types is well-defined, whether done directly via `add_reflection` or indirectly via [`add_facade`](add_facade.md). This process does not affect the behavior of [`build`](build.md) at either compile-time or runtime. +Adding duplicate reflection types is well-defined, whether done directly via `add_reflection`, `add_indirect_reflection`, `add_direct_reflection`, or indirectly via [`add_facade`](add_facade.md). This process does not affect the behavior of [`build`](build.md) at either compile-time or runtime. ## Example @@ -19,36 +37,33 @@ Adding duplicate reflection types is well-defined, whether done directly via `ad #include "proxy.h" -class DebugReflection { +class RttiReflector { public: - template - constexpr explicit DebugReflection(std::in_place_type_t

) - : pointer_type_(typeid(P)), - element_type_(typeid(typename std::pointer_traits

::element_type)) {} + template + constexpr explicit RttiReflector(std::in_place_type_t) : type_(typeid(T)) {} - void PrintDebugInfo() const { - std::cout << "Pointer type: " << pointer_type_.name() << "\n"; - std::cout << "Element type: " << element_type_.name() << "\n"; - } + template + struct accessor { + const char* GetTypeName() const noexcept { + const RttiReflector& self = pro::proxy_reflect(pro::access_proxy(*this)); + return self.type_.name(); + } + }; private: - const std::type_info& pointer_type_; - const std::type_info& element_type_; + const std::type_info& type_; }; -struct TestFacade : pro::facade_builder - ::add_reflection +struct RttiAware : pro::facade_builder + ::add_direct_reflection + ::add_indirect_reflection ::build {}; int main() { - pro::proxy p1 = std::make_shared(123); - pro::proxy_reflect(p1).PrintDebugInfo(); // Prints: "Pointer type: St10shared_ptrIiE" - // "Element type: i" (assuming GCC) - - double v = 3.14; - pro::proxy p2 = &v; - pro::proxy_reflect(p2).PrintDebugInfo(); // Prints: "Pointer type: Pd" - // "Element type: d" (assuming GCC) + 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) } ``` diff --git a/docs/proxy.md b/docs/proxy.md index 71805ef..5fd85c7 100644 --- a/docs/proxy.md +++ b/docs/proxy.md @@ -7,7 +7,7 @@ class proxy; Class template `proxy` is a general-purpose polymorphic wrapper for C++ objects. Unlike other polymorphic wrappers in the C++ standard (e.g., [`std::function`](https://en.cppreference.com/w/cpp/utility/functional/function), [`std::move_only_function`](https://en.cppreference.com/w/cpp/utility/functional/move_only_function), [`std::any`](https://en.cppreference.com/w/cpp/utility/any), etc.), `proxy` is based on pointer semantics. It supports flexible lifetime management without runtime [garbage collection (GC)](https://en.wikipedia.org/wiki/Garbage_collection_(computer_science)) at runtime, and offers best-in-class code generation quality, extendibility and accessibility. -To instantiate `proxy`, `F` shall model [concept `facade`](facade.md). As per `facade`, `typename F::convention_types` shall be a [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type containing any number of distinct types `Cs`. For each type `C` in `Cs`, if `C` meets the [*ProAccessible* requirements](ProAccessible.md) of `F`, `typename C::template accessor` is inherited by `proxy` when `C::is_direct` is `true`. Otherwise, it is inherited by the return type of [`operator*`](proxy/indirection.md) when `C::is_direct` is `false`. Implementation of accessors can call [`access_proxy`](access_proxy.md) to access the `proxy` object. It is recommended to use [`facade_builder`](basic_facade_builder.md) to define a facade type. +To instantiate `proxy`, `F` shall model [concept `facade`](facade.md). As per `facade`, `typename F::convention_types` shall be a [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type containing any number of distinct types `Cs`, and `typename F::reflection_types` shall be a [tuple-like](https://en.cppreference.com/w/cpp/utility/tuple/tuple-like) type containing any number of distinct types `Rs`. For each type `T` in `Cs` or `Rs`, if `T` meets the [*ProAccessible* requirements](ProAccessible.md) of `F`, `typename T::template accessor` is inherited by `proxy` when `T::is_direct` is `true`. Otherwise, it is inherited by the return type of [`operator*`](proxy/indirection.md) when `T::is_direct` is `false`. Implementation of accessors can call [`access_proxy`](access_proxy.md) to access the `proxy` object. It is recommended to use [`facade_builder`](basic_facade_builder.md) to define a facade type. Any instance of `proxy` at any given point in time either *contains a value* or *does not contain a value*. If a `proxy` *contains a value*, the type of the value shall be a pointer type `P` where [`proxiable`](proxiable.md) is `true`, and the value is guaranteed to be allocated as part of the `proxy` object footprint, i.e. no dynamic memory allocation occurs. However, `P` may allocate during its construction, depending on its implementation. diff --git a/docs/proxy_reflect.md b/docs/proxy_reflect.md index b94a6f5..5e84808 100644 --- a/docs/proxy_reflect.md +++ b/docs/proxy_reflect.md @@ -2,10 +2,10 @@ ```cpp template -const R& proxy_reflect(const proxy& p) noexcept; +/* see below */ proxy_reflect(const proxy& p) noexcept; ``` -Retrieves a value of type `R` constructed from [`std::in_place_type

`](https://en.cppreference.com/w/cpp/utility/in_place), where `P` is the type of the contained value of `p`. `R` is required to be defined in `typename F::reflection_types`. The behavior is undefined if `p` does not contain a value. +Let `P` be the type of the contained value of `p`. Retrieves a value of type `const typename R::reflector_type&` constructed from [`std::in_place_type`](https://en.cppreference.com/w/cpp/utility/in_place), where `T` is `P` when `R::is_direct` is `true`, or otherwise `T` is `typename std::pointer_traits

::element_type` when `R::is_direct` is `false`. `R` is required to be defined in `typename F::reflection_types`. The behavior is undefined if `p` does not contain a value. The reference obtained from `proxy_reflect()` may be invalidated if `p` is subsequently modified. @@ -22,24 +22,34 @@ This function is useful when only metadata deduced from a type is needed. While #include "proxy.h" -struct TraitsRefl { - template - constexpr explicit TraitsRefl(std::in_place_type_t

) - : Copyable(std::is_copy_constructible_v

) {} - - const bool Copyable; +class CopyabilityReflector { + public: + template + constexpr explicit CopyabilityReflector(std::in_place_type_t) + : copyable_(std::is_copy_constructible_v) {} + + template + struct accessor { + bool IsCopyable() const noexcept { + const CopyabilityReflector& self = pro::proxy_reflect(pro::access_proxy(*this)); + return self.copyable_; + } + }; + + private: + bool copyable_; }; -struct TestFacade : pro::facade_builder - ::add_reflection +struct CopyabilityAware : pro::facade_builder + ::add_direct_reflection ::build {}; int main() { - pro::proxy p1 = std::make_unique(); - std::cout << std::boolalpha << pro::proxy_reflect(p1).Copyable << "\n"; // Prints: "false" + pro::proxy p1 = std::make_unique(); + std::cout << std::boolalpha << p1.IsCopyable() << "\n"; // Prints: "false" - pro::proxy p2 = std::make_shared(); - std::cout << pro::proxy_reflect(p2).Copyable << "\n"; // Prints: "true" + pro::proxy p2 = std::make_shared(); + std::cout << p2.IsCopyable() << "\n"; // Prints: "true" } ``` diff --git a/docs/specifications.md b/docs/specifications.md index 4795d8d..8224fa9 100644 --- a/docs/specifications.md +++ b/docs/specifications.md @@ -34,12 +34,13 @@ This document provides the API specifications for the C++ library Proxy (version ## Macros -| Name | Description | -| --------------------------------------------------- | ------------------------------------------------------------ | -| [`PRO_DEF_MEM_DISPATCH`](PRO_DEF_MEM_DISPATCH.md) | Defines a dispatch type for member function call expressions with accessibility | -| [`PRO_DEF_FREE_DISPATCH`](PRO_DEF_FREE_DISPATCH.md) | Defines a dispatch type for free function call expressions with accessibility | -| [`PRO_DEF_WEAK_DISPATCH`](PRO_DEF_WEAK_DISPATCH.md) | Defines a weak dispatch type with a default implementation | -| [`__msft_lib_proxy`](msft_lib_proxy.md) | Feature test macro | +| Name | Description | +| ------------------------------------------------------------ | ------------------------------------------------------------ | +| [`PRO_DEF_MEM_DISPATCH`](PRO_DEF_MEM_DISPATCH.md) | Defines a dispatch type for member function call expressions with accessibility | +| [`PRO_DEF_FREE_DISPATCH`](PRO_DEF_FREE_DISPATCH.md) | Defines a dispatch type for free function call expressions with accessibility | +| [`PRO_DEF_FREE_AS_MEM_DISPATCH`](PRO_DEF_FREE_AS_MEM_DISPATCH.md) | Defines a dispatch type for free function call expressions with accessibility via a member function | +| [`PRO_DEF_WEAK_DISPATCH`](PRO_DEF_WEAK_DISPATCH.md) | Defines a weak dispatch type with a default implementation | +| [`__msft_lib_proxy`](msft_lib_proxy.md) | Feature test macro | ## Named Requirements @@ -47,6 +48,7 @@ This document provides the API specifications for the C++ library Proxy (version | --------------------------------------------- | ------------------------------------------------------------ | | [*ProBasicFacade*](ProBasicFacade.md) | Specifies that a type potentially models a "facade" of `proxy` | | [*ProBasicConvention*](ProBasicConvention.md) | Specifies that a type potentially models a "convention" | +| [*ProBasicReflection*](ProBasicReflection.md) | Specifies that a type potentially models a "reflection" | | [*ProFacade*](ProFacade.md) | Specifies that a type models a "facade" of `proxy` | | [*ProConvention*](ProConvention.md) | Specifies that a type models a "convention" | | [*ProReflection*](ProReflection.md) | Specifies that a type models a "reflection" | diff --git a/proxy.h b/proxy.h index 099c8ad..16ef19c 100644 --- a/proxy.h +++ b/proxy.h @@ -333,10 +333,10 @@ template using composite_meta = recursive_reduction_t, Ms...>; -template -consteval bool is_conv_is_direct_well_formed() { - if constexpr (requires { { C::is_direct } -> std::same_as; }) { - if constexpr (is_consteval([] { return C::is_direct; })) { +template +consteval bool is_is_direct_well_formed() { + if constexpr (requires { { T::is_direct } -> std::same_as; }) { + if constexpr (is_consteval([] { return T::is_direct; })) { return true; } } @@ -363,12 +363,49 @@ template typename C::dispatch_type; typename C::overload_types; } && - is_conv_is_direct_well_formed() && + is_is_direct_well_formed() && std::is_trivial_v && is_tuple_like_well_formed()) struct conv_traits : instantiated_t {}; +template +using ptr_element_t = typename std::pointer_traits

::element_type; +template +struct refl_meta { + template requires(R::is_direct) + constexpr explicit refl_meta(std::in_place_type_t

) + : reflector(std::in_place_type

) {} + template requires(!R::is_direct) + constexpr explicit refl_meta(std::in_place_type_t

) + : reflector(std::in_place_type>) {} + + typename R::reflector_type reflector; +}; + +template +consteval bool is_reflector_well_formed() { + if constexpr (IS_DIRECT) { + if constexpr (std::is_constructible_v>) { + if constexpr (is_consteval([] { return R{std::in_place_type}; })) { + return true; + } + } + } else if constexpr (requires { typename ptr_element_t; }) { + return is_reflector_well_formed, true>(); + } + return false; +} +template struct refl_traits : inapplicable_traits {}; +template + requires(requires { typename R::reflector_type; } && + is_is_direct_well_formed()) +struct refl_traits : applicable_traits { + template + static constexpr bool applicable_ptr = + is_reflector_well_formed(); +}; + template struct copyability_meta_provider { template @@ -423,25 +460,42 @@ class ___PRO_ENFORCE_EBO composite_accessor_impl : public As... { = default; }; -template