Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
jll63 committed Jul 15, 2023
1 parent 15ca786 commit 36117f4
Show file tree
Hide file tree
Showing 12 changed files with 406 additions and 157 deletions.
58 changes: 26 additions & 32 deletions include/yorel/yomm2/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,9 @@ struct method<Key, R(A...), Policy> : Policy::method_info_type {
detail::ti_ptr tis[sizeof...(args)];
error.tis = tis;
auto ti_iter = tis;
(..., (*ti_iter++ = detail::get_tip<A>(args)));
(...,
(*ti_iter++ =
detail::get_tip<A>(detail::virtual_traits<A>::ref(args))));
detail::error_handler(error_type(std::move(error)));
abort(); // in case user handler "forgets" to abort
}
Expand All @@ -427,7 +429,9 @@ struct method<Key, R(A...), Policy> : Policy::method_info_type {
detail::ti_ptr tis[sizeof...(args)];
error.tis = tis;
auto ti_iter = tis;
(..., (*ti_iter++ = detail::get_tip<A>(args)));
(...,
(*ti_iter++ =
detail::get_tip<A>(detail::virtual_traits<A>::ref(args))));
detail::error_handler(error_type(std::move(error)));
abort(); // in case user handler "forgets" to abort
}
Expand Down Expand Up @@ -600,63 +604,54 @@ class virtual_ptr_aux {
virtual_ptr_aux(Class& obj, mptr_type mptr) : obj(obj), mptr(mptr) {
}

template<class OtherClass>
static auto final(OtherClass& obj) {
template<class Other>
static auto final(Other& obj) {
using namespace detail;

mptr_type mptr;

if constexpr (Policy::use_indirect_method_pointers) {
mptr = detail::indirect_method_table<
typename detail::virtual_traits<Class&>::polymorphic_type,
typename detail::virtual_traits<Other&>::polymorphic_type,
Policy>;
} else {
mptr = detail::method_table<
typename detail::virtual_traits<Class&>::polymorphic_type,
typename detail::virtual_traits<Other&>::polymorphic_type,
Policy>;
}

if constexpr (debug) {
// check that dynamic type == static type
auto key = virtual_traits<OtherClass&>::key(obj);
auto key = virtual_traits<Other&>::key(obj);
auto final_key =
&typeid(typename virtual_traits<OtherClass&>::polymorphic_type);
&typeid(typename virtual_traits<Other&>::polymorphic_type);

if (key != final_key) {
error_handler(method_table_error{key});
}

// check that OtherClass is registered
if constexpr (Policy::use_indirect_method_pointers) {
check_method_pointer<Policy>(*mptr, key);
} else {
check_method_pointer<Policy>(mptr, key);
}
}

return virtual_ptr<Class, Policy>(obj, mptr);
}

template<class OtherClass>
static auto dynamic_method_table(OtherClass& obj) {
template<class Other>
static auto dynamic_method_table(Other& obj) {
using namespace detail;

mptr_type mptr;

auto key = virtual_traits<OtherClass&>::key(obj);
auto key = virtual_traits<Other&>::key(obj);
auto final_key =
&typeid(typename virtual_traits<OtherClass&>::polymorphic_type);
&typeid(typename virtual_traits<Other&>::polymorphic_type);

if (key == final_key) {
if constexpr (Policy::use_indirect_method_pointers) {
mptr = detail::indirect_method_table<
typename detail::virtual_traits<
OtherClass&>::polymorphic_type,
typename detail::virtual_traits<Other&>::polymorphic_type,
Policy>;
} else {
mptr = detail::method_table<
typename detail::virtual_traits<
OtherClass&>::polymorphic_type,
typename detail::virtual_traits<Other&>::polymorphic_type,
Policy>;
}
} else {
Expand Down Expand Up @@ -704,22 +699,21 @@ class virtual_ptr<Class, Policy, false>
public:
// using virtual_ptr_aux<Class, Policy>::virtual_ptr_aux;

template<class OtherClass>
virtual_ptr(OtherClass& obj) : base(obj, this->dynamic_method_table(obj)) {
template<class Other>
virtual_ptr(Other& obj) : base(obj, this->dynamic_method_table(obj)) {
}

template<typename OtherClass>
virtual_ptr(OtherClass&& obj, typename base::mptr_type mptr)
: base(obj, mptr) {
template<typename Other>
virtual_ptr(Other&& obj, typename base::mptr_type mptr) : base(obj, mptr) {
}

template<class OtherClass>
virtual_ptr(virtual_ptr<OtherClass, Policy>& other)
template<class Other>
virtual_ptr(virtual_ptr<Other, Policy>& other)
: base(other.obj, other.mptr) {
}

template<class OtherClass>
virtual_ptr(const virtual_ptr<OtherClass, Policy>& other)
template<class Other>
virtual_ptr(const virtual_ptr<Other, Policy>& other)
: base(other.obj, other.mptr) {
}

Expand Down
8 changes: 4 additions & 4 deletions include/yorel/yomm2/detail.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -339,12 +339,12 @@ template<class Class, class Policy>
struct virtual_traits<virtual_ptr<Class, Policy>> {
using polymorphic_type = Class;

static auto ref(virtual_ptr<Class, Policy> ptr) {
return ptr;
static Class& ref(virtual_ptr<Class, Policy> ptr) {
return *ptr.get();
}

static auto key(virtual_ptr<Class, Policy> arg) {
return &typeid(*arg);
static auto key(const Class& arg) {
return &typeid(arg);
}

template<typename Derived>
Expand Down
6 changes: 2 additions & 4 deletions reference.in/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Yuriy Solodkyy, and Bjarne Stroustrup.

This implementation diverges from the paper on the following points:
* A "base-method" is called a "method declaration" in YOMM2, and an "overrider"
is called a "method definition". This is because
is called a "method definition". This is because
* YOMM2 has a mechanism (`next`) to call the next most specialised method.
* The paper allows only references for virtual parameters. YOMM2 also allows
pointers and smart pointers.
Expand Down Expand Up @@ -153,12 +153,10 @@ This was the recommended header before version 1.3.0. Includes
| ->define_method | macro | add a definition to a method |
| ->define_method_inline | macro | add an definition to a method in a container, and make it inline |
| ->derived | class template | helper for intrusive modes |
| ->direct | type | tag for direct intrusive mode |
| ->error_handler_type | type | handler function |
| ->error_type | variant | object passed to error handler |
| ->friend_method | macro | make a method in a container, or the entire container, a friend |
| ->hash_search_error | class | failure to find a hash function for registered classes |
| ->indirect | type | tag for indirect intrusive mode |
| ->method | class template | implements a method |
| ->method_call_error | class | information about a failed method call |
| ->method_call_error_handler | type | the type of a function called when a method call fails |
Expand All @@ -175,6 +173,7 @@ This was the recommended header before version 1.3.0. Includes
| ->update_methods | function | set up dispatch tables |
| ->use_classes | class template | register classes and their inheritance relationships |
| ->virtual_ | class template | mark a method parameter as virtual |
| ->virtual_ptr | class template | fat pointer for optimal method dispatch |
| ->YOMM2_CLASS | macro | same as `register_class` (deprecated) |
| ->YOMM2_CLASSES | macro | same as `register_classes` |
| ->YOMM2_DECLARE | macro | same as `declare_method` |
Expand All @@ -200,4 +199,3 @@ This was the recommended header before version 1.3.0. Includes
| ->templates | class template | wrap templates in a `types` list |
| ->types | class template | sequence of types |
| ->use_definitions | class template | add batch of definitions from a generic container to methods |

28 changes: 15 additions & 13 deletions reference.in/declare_method.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,34 @@ headers: yorel/yomm2/cute.hpp, yorel/yomm2/keywords.hpp

---
```
#define declare_method(/*unspecified*/) /*unspecified*/
#define declare_method(return-type, method, (types)) /*unspecified*/
```
### usage
```
declare_method(return-type, name, (function-parameter-list)) {
declare_method(return-type, method, (types)) {
...
}
```
---
Declare a method.

Create an inline function `method` that returns `return-type` and takes a
parameter list consisting of the `types` without the `virtual_` marker. At least
one `types` (but not necessarily all) must be marked with `virtual_`.

When `method` is called, the dynamic types of the arguments marked with
`virtual_` are examined, and the most specific definition compatible with
`unspecified_type...` is called. If no compatible definition exists, or if
several compatible definitions exist but none of them is more specific than all
the others, the call is illegal and an error handler is executed. By default it
writes a diagnostic on `std::cerr ` and terminates the program via `abort`. The
handler can be customized.
parameter list consisting of `types`. At least one of `types` (but not
necessarily all) must be a *virtual parameter*, i.e. in the form
[`virtual_<T>`](virtual_.md), or [`virtual_ptr<T>`](virtual_ptr.md). The
`virtual_` decorator is stripped from `types`.

When `method` is called, the dynamic types of the virtual arguments are
examined, and the most specific definition compatible with `unspecified_type...`
is called. If no compatible definition exists, or if several compatible
definitions exist but none of them is more specific than all the others, the
call is illegal and an error handler is executed. By default it writes a
diagnostic on `std::cerr ` and terminates the program via `abort`. The handler
can be customized.

NOTE:

* The parameter list `type` _must_ be surrounded by parentheses.
* The method parameter list _must_ be surrounded by parentheses.

* The parameters in `types` consist of _just_ a type, e.g. `int` is correct
but `int i` is not.
Expand Down
10 changes: 5 additions & 5 deletions reference.in/define_method.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#ifdef YOMM2_MD

hrefs: YOMM2_DEFINE
hrefs: YOMM2_DEFINE

<sub>/ ->home / ->reference </sub>

Expand All @@ -15,23 +15,23 @@ headers: yorel/yomm2/cute.hpp, yorel/yomm2/keywords.hpp></sub

### usage
```
define_method(return-type, name, (function-parameter-list)) {
define_method(return-type, name, (method-parameter-list)) {
...
}

define_method(container, return-type, name, (function-parameter-list)) {
define_method(container, return-type, name, (method-parameter-list)) {
...
}
```
---
Add a definition to a method.

Locate a method with the same name, with a signature compatible with
`function-parameter-list`, and add the definition to the method's list of
`method-parameter-list`, and add the definition to the method's list of
definitions. The method must exist and must be unique. `return-type` must be
covariant with the method's return type. `return-type` may be `auto`.

The types of the arguments are _not_ marked with `virtual_`.
The types of the arguments must _not_ be decorated with `virtual_`.

Inside the block, a function pointer named `next` points to the next most
specific definition, if one exists, and it is unique. Otherwise, `next` points
Expand Down
Loading

0 comments on commit 36117f4

Please sign in to comment.