Date: Wed, 2 Feb 2022 14:13:25 +0100
Hi SG7,
On Tue, Feb 1, 2022 at 5:53 PM Matus Chochlik <chochlik_at_[hidden]> wrote:
>
> template <typename T>
> concept metaobject = __unspecified__
>
> consteval bool some_predicate(metaobject auto mo);
> consteval auto some_operation(metaobject auto mo);
>
> and later when the consteval arguments are available just say:
>
> template <typename T>
> concept metaobject = is_same_v<T, meta::info>;
>
> I started writing a paper with details, but it won't be ready for
> tomorrow's SG7 telco.
>
> This morning I made some changes to the clang compiler and the `mirror`
library implementation and determined that it is possible to do some
additional optimization with the template-wrapped metaobject id (like
meta::info):
assume that:
- __metaobject_id is basically the same thing as meta::info
- mirror(expr) is like ^T but doesn't "return" __metaobject_id directly,
instead it returns a publicly unspecified type that is implemented as:
```
template <__metaobject_id M>
struct wrapped_metaobject {
consteval operator __metaobject_id() const { return M; }
};
```
Then all the metaobject operations like get_name, is_static, etc. etc.
which do not require instantiation context,
and do not return other metaobjects (there are dozens and there may be
potentially hundreds such functions)
can be internally implemented as:
```
consteval auto is_static(__metaobject_id) -> bool;
consteval auto get_name(__metaobject_id) -> string_view;
```
the functions that require instantiation contexts or return other
metaobjects are implemented as:
```
template <__metaobject_id M>
consteval auto get_scope(wrapped_metaobject<M>) -> wrapped_metaobject<...>;
```
All the other algorithms like `for_each`, `filter`, `fold`, etc. etc. that
mostly require instantiation contexts (because they can take
predicate/transform/etc lambdas that do splicing) keep working after this
change.
Formally all those functions could be defined as
```
template <typename T>
concept metaobject = ...;
consteval auto is_static(metaobject auto) -> bool;
consteval auto get_name(metaobject auto) -> string_view;
consteval auto get_scope(metaobject auto);
```
...without specifying the meta::info or wrapped_metaobject types.
The API is always used as:
foo(bar(baz(mirror(int)));
and *not* like:
foo<bar<baz<^T>()>()>();
There is one notable consequence: span<meta::info> cannot be used right
now. But there are alternatives. In the TS there are the
_metaobject-sequences_ that are expanded, iterated, filtered, etc. lazily
(and I think we should keep them even in this new API, there are use cases
where the contained metaobjects are not required only their count for
example), `template for` could be implemented for such metaobject-sequences
pretty easily as well.
I haven't converted everything, only a small part of potential candidates,
but initial measurements indicate that the compilation times for the
extreme cases where almost all reflection operations are invoked now
compile ~10% faster than previously.
--Matus
On Tue, Feb 1, 2022 at 5:53 PM Matus Chochlik <chochlik_at_[hidden]> wrote:
>
> template <typename T>
> concept metaobject = __unspecified__
>
> consteval bool some_predicate(metaobject auto mo);
> consteval auto some_operation(metaobject auto mo);
>
> and later when the consteval arguments are available just say:
>
> template <typename T>
> concept metaobject = is_same_v<T, meta::info>;
>
> I started writing a paper with details, but it won't be ready for
> tomorrow's SG7 telco.
>
> This morning I made some changes to the clang compiler and the `mirror`
library implementation and determined that it is possible to do some
additional optimization with the template-wrapped metaobject id (like
meta::info):
assume that:
- __metaobject_id is basically the same thing as meta::info
- mirror(expr) is like ^T but doesn't "return" __metaobject_id directly,
instead it returns a publicly unspecified type that is implemented as:
```
template <__metaobject_id M>
struct wrapped_metaobject {
consteval operator __metaobject_id() const { return M; }
};
```
Then all the metaobject operations like get_name, is_static, etc. etc.
which do not require instantiation context,
and do not return other metaobjects (there are dozens and there may be
potentially hundreds such functions)
can be internally implemented as:
```
consteval auto is_static(__metaobject_id) -> bool;
consteval auto get_name(__metaobject_id) -> string_view;
```
the functions that require instantiation contexts or return other
metaobjects are implemented as:
```
template <__metaobject_id M>
consteval auto get_scope(wrapped_metaobject<M>) -> wrapped_metaobject<...>;
```
All the other algorithms like `for_each`, `filter`, `fold`, etc. etc. that
mostly require instantiation contexts (because they can take
predicate/transform/etc lambdas that do splicing) keep working after this
change.
Formally all those functions could be defined as
```
template <typename T>
concept metaobject = ...;
consteval auto is_static(metaobject auto) -> bool;
consteval auto get_name(metaobject auto) -> string_view;
consteval auto get_scope(metaobject auto);
```
...without specifying the meta::info or wrapped_metaobject types.
The API is always used as:
foo(bar(baz(mirror(int)));
and *not* like:
foo<bar<baz<^T>()>()>();
There is one notable consequence: span<meta::info> cannot be used right
now. But there are alternatives. In the TS there are the
_metaobject-sequences_ that are expanded, iterated, filtered, etc. lazily
(and I think we should keep them even in this new API, there are use cases
where the contained metaobjects are not required only their count for
example), `template for` could be implemented for such metaobject-sequences
pretty easily as well.
I haven't converted everything, only a small part of potential candidates,
but initial measurements indicate that the compilation times for the
extreme cases where almost all reflection operations are invoked now
compile ~10% faster than previously.
--Matus
Received on 2022-02-02 13:13:37