Skip to content

Instantly share code, notes, and snippets.

@foonathan

foonathan/meta Secret

Created October 14, 2024 10:12
Show Gist options
  • Save foonathan/457bd0073cfde568e446eb4d42ec87fe to your computer and use it in GitHub Desktop.
Save foonathan/457bd0073cfde568e446eb4d42ec87fe to your computer and use it in GitHub Desktop.
// -*- C++ -*-
//===----------------------------------------------------------------------===//
//
// Copyright 2024 Bloomberg Finance L.P.
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef _LIBCPP_EXPERIMENTAL_META
#define _LIBCPP_EXPERIMENTAL_META
/*
experimental/meta synopsis
// C++2c
namespace std
{
namespace meta
{
inline namespace reflection_v2
{
// std::meta::info
using info = decltype(^int);
// concept reflection_range
template <typename R>
concept reflection_range = see below;
// name and location
consteval auto identifier_of(info) -> string_view;
consteval auto display_string_of(info) -> string_view;
consteval auto u8identifier_of(info) -> u8string_view;
consteval auto u8display_string_of(info) -> u8string_view;
consteval auto has_identifier(info) -> bool;
enum operators;
consteval auto operator_of(info) -> operators;
consteval auto source_location_of(info r) -> source_location;
// type queries
consteval auto type_of(info) -> info;
consteval auto parent_of(info) -> info;
consteval auto dealias(info) -> info;
// object and value queries
consteval auto object_of(info) -> info;
consteval auto value_of(info) -> info;
// template queries
consteval auto template_of(info r) -> info;
consteval auto template_arguments_of(info r) -> vector<info>;
// member queries
consteval auto members_of(info class_type) -> vector<info>;
consteval auto bases_of(info class_type) -> vector<info>;
consteval auto static_data_members_of(info class_type) -> vector<info>;
consteval auto nonstatic_data_members_of(info class_type) -> vector<info>;
consteval auto subobjects_of(info class_type) -> vector<info>;
consteval auto enumerators_of(info enum_type) -> vector<info>;
// public member queries
consteval auto get_public_members(info) -> vector<info>;
consteval auto get_public_bases(info) -> vector<info>;
consteval auto get_static_data_members(info) -> vector<info>;
consteval auto get_nonstatic_data_members(info) -> vector<info>;
// member access queries
struct access_context {
consteval access_context();
consteval access_context(const access_context &) = default;
consteval access_context(access_context &&) = default;
static consteval auto current() -> access_context;
};
consteval auto is_accessible(
info r,
access_context from = access_context::current()) -> bool;
consteval auto accessible_members_of(
info target,
access_context from = access_context::current()) -> vector<info>;
consteval auto accessible_nonstatic_data_members_of(
info target,
access_context from = access_context::current()) -> vector<info>;
consteval auto accessible_static_data_members_of(
info target,
access_context from = access_context::current()) -> vector<info>;
consteval auto accessible_bases_of(
info target,
access_context from = access_context::current()) -> vector<info>;
consteval auto accessible_subobjects_of(
info target,
access_context from = access_context::current()) -> vector<info>;
// substitute
template <reflection_range R = initializer_list<info>>
consteval auto can_substitute(info templ, R &&args) -> bool;
template <reflection_range R = initializer_list<info>>
consteval auto substitute(info templ, R &&args) -> info;
// reflect_invoke
template <reflection_range R = initializer_list<info>>
consteval auto reflect_invoke(info target, R &&args) -> info;
template <reflection_range R1 = initializer_list<info>,
reflection_range R2 = initializer_list<info>>
consteval auto reflect_invoke(info target,
R1 &&tmpl_args, R2 &&args) -> info;
// reflect expression results
template <typename T>
consteval auto reflect_value(T) -> info;
template <typename T>
consteval auto reflect_object(T &) -> info;
template <typename T>
consteval auto reflect_function(T &) -> info;
// extract<T>
template <typename Ty>
consteval auto extract(info) -> T;
// other type predicates
consteval auto is_public(info) -> bool;
consteval auto is_protected(info) -> bool;
consteval auto is_private(info) -> bool;
consteval auto is_access_specified(info) -> bool;
consteval auto is_virtual(info) -> bool;
consteval auto is_pure_virtual(info) -> bool;
consteval auto is_override(info) -> bool;
consteval auto is_deleted(info) -> bool;
consteval auto is_defaulted(info) -> bool;
consteval auto is_explicit(info) -> bool;
consteval bool is_noexcept(info) -> bool;
consteval auto is_bit_field(info) -> bool;
consteval auto is_enumerator(info) -> bool;
consteval auto is_const(info) -> bool;
consteval auto is_volatile(info) -> bool;
consteval auto is_mutable_member(info) -> bool;
consteval auto is_lvalue_reference_qualified(info) -> bool;
consteval auto is_rvalue_reference_qualified(info) -> bool;
consteval auto has_static_storage_duration(info) -> bool;
consteval auto has_thread_storage_duration(info r) -> bool;
consteval auto has_automatic_storage_duration(info r) -> bool;
consteval auto has_internal_linkage(info) -> bool;
consteval auto has_module_linkage(info) -> bool;
consteval auto has_external_linkage(info) -> bool;
consteval auto has_linkage(info) -> bool;
consteval auto is_class_member(info) -> bool;
consteval auto is_namespace_member(info) -> bool;
consteval auto is_nonstatic_data_member(info) -> bool;
consteval auto is_static_member(info) -> bool;
consteval auto is_base(info) -> bool;
consteval auto is_data_member_spec(info) -> bool;
consteval auto is_namespace(info) -> bool;
consteval auto is_function(info) -> bool;
consteval auto is_variable(info) -> bool;
consteval auto is_type(info) -> bool;
consteval auto is_type_alias(info) -> bool;
consteval auto is_namespace_alias(info) -> bool;
consteval auto is_complete_type(info) -> bool;
consteval auto has_complete_definition(info) -> bool;
consteval auto is_template(info) -> bool;
consteval auto is_function_template(info) -> bool;
consteval auto is_variable_template(info) -> bool;
consteval auto is_class_template(bool) -> bool;
consteval auto is_alias_template(bool) -> bool;
consteval auto is_conversion_function_template(bool) -> bool;
consteval auto is_operator_function_template(bool) -> bool;
consteval auto is_literal_operator_template(bool) -> bool;
consteval auto is_constructor_template(bool) -> bool;
consteval auto is_concept(info) -> bool;
consteval auto is_structured_binding(info) -> bool;
consteval auto has_template_arguments(info) -> bool;
consteval auto has_default_member_initializer(info) -> bool;
consteval auto is_conversion_function(info) -> bool;
consteval auto is_operator_function(info) -> bool;
consteval auto is_literal_operator(info) -> bool;
consteval auto is_constructor(info) -> bool;
consteval auto is_default_constructor(info) -> bool;
consteval auto is_copy_constructor(info) -> bool;
consteval auto is_move_constructor(info) -> bool;
consteval auto is_assignment(info) -> bool;
consteval auto is_copy_assignment(info) -> bool;
consteval auto is_move_assignment(info) -> bool;
consteval auto is_destructor(info) -> bool;
consteval auto is_special_member_function(info) -> bool;
consteval auto is_user_provided(info) -> bool;
consteval auto is_user_declared(info) -> bool;
// define_class
struct data_member_options_t;
consteval auto data_member_spec(info class_type,
data_member_options = {}) -> info;
template <reflection_range R = initializer_list<info>>
consteval auto define_class(info class_type, R &&members) -> info;
// data layout
struct member_offsets {
size_t bytes;
size_t bits;
constexpr size_t total_bits() const;
auto operator<=>(member_offsets const&) const = default;
};
consteval auto offset_of(info) -> member_offsets;
consteval auto size_of(info) -> size_t;
consteval auto alignment_of(info) -> size_t;
consteval auto bit_size_of(info) -> size_t;
// primary type categories
consteval auto type_is_void(info) -> bool;
consteval auto type_is_null_pointer(info) -> bool;
consteval auto type_is_integral(info) -> bool;
consteval auto type_is_floating_point(info) -> bool;
consteval auto type_is_array(info) -> bool;
consteval auto type_is_pointer(info) -> bool;
consteval auto type_is_lvalue_reference(info) -> bool;
consteval auto type_is_rvalue_reference(info) -> bool;
consteval auto type_is_member_object_pointer(info) -> bool;
consteval auto type_is_member_function_pointer(info) -> bool;
consteval auto type_is_enum(info) -> bool;
consteval auto type_is_union(info) -> bool;
consteval auto type_is_class(info) -> bool;
consteval auto type_is_function(info) -> bool;
// composite type categories
consteval auto type_is_reference(info) -> bool;
consteval auto type_is_arithmetic(info) -> bool;
consteval auto type_is_fundamental(info) -> bool;
consteval auto type_is_object(info) -> bool;
consteval auto type_is_scalar(info) -> bool;
consteval auto type_is_compound(info) -> bool;
consteval auto type_is_member_pointer(info) -> bool;
// type properties
consteval auto type_is_const(info) -> bool;
consteval auto type_is_volatile(info) -> bool;
consteval auto type_is_trivial(info) -> bool;
consteval auto type_is_trivially_copyable(info) -> bool;
consteval auto type_is_standard_layout(info) -> bool;
consteval auto type_is_empty(info) -> bool;
consteval auto type_is_polymorphic(info) -> bool;
consteval auto type_is_abstract(info) -> bool;
consteval auto type_is_final(info) -> bool;
consteval auto type_is_aggregate(info) -> bool;
consteval auto type_is_signed(info) -> bool;
consteval auto type_is_unsigned(info) -> bool;
consteval auto type_is_bounded_array(info) -> bool;
consteval auto type_is_unbounded_array(info) -> bool;
consteval auto type_is_scoped_enum(info) -> bool;
template <reflection_range R = initializer_list<info>>
consteval auto type_is_constructible(info, R &&type_args) -> bool;
consteval auto type_is_default_constructible(info) -> bool;
consteval auto type_is_copy_constructible(info) -> bool;
consteval auto type_is_move_constructible(info) -> bool;
consteval auto type_is_assignable(info dst, info src) -> bool;
consteval auto type_is_copy_assignable(info) -> bool;
consteval auto type_is_move_assignable(info) -> bool;
consteval auto type_is_swappable_with(info dst, info src) -> bool;
consteval auto type_is_swappable(info) -> bool;
consteval auto type_is_destructible(info) -> bool;
template <reflection_range R = initializer_list<info>>
consteval auto type_is_trivially_constructible(info, R &&type_args) -> bool;
consteval auto type_is_trivially_default_constructible(info) -> bool;
consteval auto type_is_trivially_copy_constructible(info) -> bool;
consteval auto type_is_trivially_move_constructible(info) -> bool;
consteval auto type_is_trivially_assignable(info dst, info src) -> bool;
consteval auto type_is_trivially_copy_assignable(info) -> bool;
consteval auto type_is_trivially_move_assignable(info) -> bool;
consteval auto type_is_trivially_destructible(info) -> bool;
template <reflection_range R = initializer_list<info>>
consteval auto type_is_nothrow_constructible(info, R &&type_args) -> bool;
consteval auto type_is_nothrow_default_constructible(info) -> bool;
consteval auto type_is_nothrow_copy_constructible(info) -> bool;
consteval auto type_is_nothrow_move_constructible(info) -> bool;
consteval auto type_is_nothrow_assignable(info dst, info src) -> bool;
consteval auto type_is_nothrow_copy_assignable(info) -> bool;
consteval auto type_is_nothrow_move_assignable(info) -> bool;
consteval auto type_is_nothrow_swappable_with(info dst, info src) -> bool;
consteval auto type_is_nothrow_swappable(info) -> bool;
consteval auto type_is_nothrow_destructible(info) -> bool;
consteval auto type_is_implicit_lifetime(info) -> bool;
consteval auto type_has_virtual_destructor(info) -> bool;
consteval auto type_has_unique_object_representations(info) -> bool;
consteval auto type_reference_constructs_from_temporary(info) -> bool;
consteval auto type_reference_converts_from_temporary(info) -> bool;
// type property queries
consteval auto type_alignment_of(info) -> size_t;
consteval auto type_rank(info) -> size_t;
consteval auto type_extent(info type, unsigned i) -> size_t;
// type relations
consteval auto type_is_same(info, info) -> bool;
consteval auto type_is_base_of(info, info) -> bool;
consteval auto type_is_convertible(info, info) -> bool;
consteval auto type_is_nothrow_convertible(info, info) -> bool;
consteval auto type_is_layout_compatible(info, info) -> bool;
consteval auto type_is_pointer_interconvertible_base_of(info, info) -> bool;
template <reflection_range R = initializer_list<info>>
consteval auto type_is_invocable(info type, R &&args) -> bool;
template <reflection_range R = initializer_list<info>>
consteval auto type_is_invocable_r(info type_result, info type,
R &&args) -> bool;
template <reflection_range R = initializer_list<info>>
consteval auto type_is_nothrow_invocable(info type, R &&args) -> bool;
template <reflection_range R = initializer_list<info>>
consteval auto type_is_nothrow_invocable_r(info type_result, info type,
R &&args) -> bool;
// const volatile modifications
consteval auto type_remove_const(info) -> info;
consteval auto type_remove_volatile(info) -> info;
consteval auto type_remove_cv(info) -> info;
consteval auto type_add_const(info) -> info;
consteval auto type_add_volatile(info) -> info;
consteval auto type_add_cv(info) -> info;
// reference modifications
consteval auto type_remove_reference(info) -> info;
consteval auto type_add_lvalue_reference(info) -> info;
consteval auto type_add_rvalue_reference(info) -> info;
// sign modifications
consteval auto make_signed(info) -> info;
consteval auto make_unsigned(info) -> info;
// array modifications
consteval auto type_remove_extent(info) -> info;
consteval auto type_remove_all_extents(info) -> info;
// pointer modifications
consteval auto type_remove_pointer(info) -> info;
consteval auto type_add_pointer(info) -> info;
// other transformations
consteval auto type_remove_cvref(info) -> info;
consteval auto type_decay(info) -> info;
template <reflection_range R = initializer_list<info>>
consteval auto type_common_type(R &&type_args) -> info;
template <reflection_range R = initializer_list<info>>
consteval auto type_common_reference(R &&type_args) -> info;
consteval auto type_underlying_type(info) -> info;
template <reflection_range R = initializer_list<info>>
consteval auto type_invoke_result(info type, R &&type_args) -> info;
consteval auto type_unwrap_reference(info) -> info;
consteval auto type_unwrap_ref_decay(info) -> info;
// tuple and variant queries
consteval auto type_tuple_size(info) -> size_t;
consteval auto type_tuple_element(size_t, info) -> info;
consteval auto type_variant_size(info) -> size_t;
consteval auto type_variant_alternative(size_t, info) -> info;
// function parameters (P3096)
consteval auto parameters_of(info) -> vector<info>;
consteval auto has_consistent_identifier(info) -> bool;
consteval auto any_identifier_of(info) -> string_view;
consteval auto u8any_identifier_of(info) -> u8string_view;
consteval auto has_ellipsis_parameter(info) -> bool;
consteval auto has_default_argument(info) -> bool;
consteval auto is_explicit_object_parameter(info) -> bool;
consteval auto is_function_parameter(info) -> bool;
consteval auto return_type_of(info) -> info;
// annotations (P3XYZ)
consteval auto annotations_of(info) -> vector<info>;
consteval auto annotations_of(info, info) -> vector<info>;
template <typename T>
consteval auto annotation_of_type(info) -> optional<info>;
consteval auto is_annotation(info) -> bool;
consteval auto annotate(info) -> info;
} // namespace reflection_v2
} // namespace meta
} // namespace std
*/
#include <__config>
#include <algorithm>
#include <bit>
#include <initializer_list>
#include <optional>
#include <ranges>
#include <source_location>
#include <string>
#include <string_view>
#include <type_traits>
#include <variant>
#include <vector>
#if __has_feature(reflection)
#if __has_feature(reflection_new_syntax)
#define LIFT(x) ^^x
#else
#define LIFT(x) ^x
#endif
_LIBCPP_BEGIN_NAMESPACE_REFLECTION_V2
// An opaque handle to a reflected entity.
using info = decltype(LIFT(int));
class info_array {
public:
using value_type = info;
using pointer = const info*;
using const_pointer = pointer;
using reference = const info&;
using const_reference = reference;
using size_type = size_t;
using difference_type = ptrdiff_t;
using iterator = pointer;
info_array() = delete;
constexpr info_array(vector<info>&& impl) : _impl(std::move(impl)) {} // implementation detail
constexpr void swap(info_array& other) noexcept { _impl.swap(other._impl); }
constexpr iterator begin() const noexcept { return _impl.data(); }
constexpr iterator end() const noexcept { return _impl.data() + _impl.size(); }
constexpr iterator cbegin() const noexcept { return begin(); }
constexpr iterator cend() const noexcept { return end(); }
constexpr bool empty() const noexcept { return begin() == end(); }
constexpr size_type size() const noexcept { return end() - begin(); }
constexpr reference operator[](size_type i) const noexcept { return begin()[i]; }
constexpr reference front() const noexcept { return begin()[0]; }
constexpr reference back() const noexcept { return end()[-1]; }
constexpr pointer data() const noexcept { return begin(); }
private:
vector<info> _impl;
};
template <typename R>
concept reflection_range =
ranges::input_range<R> &&
same_as<ranges::range_value_t<R>, info> &&
same_as<remove_cvref_t<ranges::range_reference_t<R>>, info>;
namespace detail {
enum : unsigned {
// non-exposed metafunctions
__metafn_get_begin_enumerator_decl_of,
__metafn_get_get_next_enumerator_decl_of,
__metafn_get_ith_base_of,
__metafn_get_ith_template_argument_of,
__metafn_get_begin_member_decl_of,
__metafn_get_next_member_decl_of,
__metafn_is_structural_type,
__metafn_map_decl_to_entity,
// exposed metafunctions
__metafn_identifier_of,
__metafn_has_identifier,
__metafn_operator_of,
__metafn_source_location_of,
__metafn_type_of,
__metafn_parent_of,
__metafn_dealias,
__metafn_object_of,
__metafn_value_of,
__metafn_template_of,
__metafn_can_substitute,
__metafn_substitute,
__metafn_extract,
__metafn_is_public,
__metafn_is_protected,
__metafn_is_private,
__metafn_is_access_specified,
__metafn_access_context,
__metafn_is_accessible,
__metafn_is_virtual,
__metafn_is_pure_virtual,
__metafn_is_override,
__metafn_is_deleted,
__metafn_is_defaulted,
__metafn_is_explicit,
__metafn_is_noexcept,
__metafn_is_bit_field,
__metafn_is_enumerator,
__metafn_is_const,
__metafn_is_volatile,
__metafn_is_mutable_member,
__metafn_is_lvalue_reference_qualified,
__metafn_is_rvalue_reference_qualified,
__metafn_has_static_storage_duration,
__metafn_has_thread_storage_duration,
__metafn_has_automatic_storage_duration,
__metafn_has_internal_linkage,
__metafn_has_module_linkage,
__metafn_has_external_linkage,
__metafn_has_linkage,
__metafn_is_class_member,
__metafn_is_namespace_member,
__metafn_is_nonstatic_data_member,
__metafn_is_static_member,
__metafn_is_base,
__metafn_is_data_member_spec,
__metafn_is_namespace,
__metafn_is_function,
__metafn_is_variable,
__metafn_is_type,
__metafn_is_alias,
__metafn_is_complete_type,
__metafn_has_complete_definition,
__metafn_is_template,
__metafn_is_function_template,
__metafn_is_variable_template,
__metafn_is_class_template,
__metafn_is_alias_template,
__metafn_is_conversion_function_template,
__metafn_is_operator_function_template,
__metafn_is_literal_operator_template,
__metafn_is_constructor_template,
__metafn_is_concept,
__metafn_is_structured_binding,
__metafn_is_value,
__metafn_is_object,
__metafn_has_template_arguments,
__metafn_has_default_member_initializer,
__metafn_is_conversion_function,
__metafn_is_operator_function,
__metafn_is_literal_operator,
__metafn_is_constructor,
__metafn_is_default_constructor,
__metafn_is_copy_constructor,
__metafn_is_move_constructor,
__metafn_is_assignment,
__metafn_is_copy_assignment,
__metafn_is_move_assignment,
__metafn_is_destructor,
__metafn_is_special_member_function,
__metafn_is_user_provided,
__metafn_is_user_declared,
__metafn_reflect_result,
__metafn_reflect_invoke,
__metafn_data_member_spec,
__metafn_define_class,
__metafn_offset_of,
__metafn_size_of,
__metafn_bit_offset_of,
__metafn_bit_size_of,
__metafn_alignment_of,
__metafn_define_static_string,
__metafn_define_static_array,
// P3096 metafunctions
__metafn_get_ith_parameter_of,
__metafn_has_consistent_identifier,
__metafn_has_ellipsis_parameter,
__metafn_has_default_argument,
__metafn_is_explicit_object_parameter,
__metafn_is_function_parameter,
__metafn_return_type_of,
// P3XYZ annotation metafunctions
__metafn_get_ith_annotation_of,
__metafn_is_annotation,
__metafn_annotate,
};
consteval auto __workaround_expand_compiler_builtins(info type) -> info;
} // namespace detail
namespace __range_of_infos {
struct sentinel {};
template <typename Front, typename Next, typename Map>
class iterator {
static constexpr Front m_front = { };
static constexpr Next m_next = { };
// The reflected entity passed to the underlying range
info m_reflectedEntity{LIFT(sentinel)};
// The current meta::info within the range: e.g. if we are
// doing template_arguments_of(^^vector<int, double, string>)
// m_currInfoItr can be either ^^int, ^^double and ^^string
info m_currInfoItr{LIFT(sentinel)};
Map m_mapFn;
size_t m_nextIndex {0};
public:
using value_type = info;
using reference = info;
using pointer = info;
using difference_type = ptrdiff_t;
using iterator_category = forward_iterator_tag;
consteval iterator()
: m_currInfoItr{LIFT(sentinel)}
, m_mapFn{}
{ }
consteval iterator(meta::info reflectedEntity)
: m_reflectedEntity{reflectedEntity}
, m_currInfoItr{m_front(reflectedEntity)}
, m_nextIndex{1} // after we fetch the front, next index is 1
{ }
consteval info operator*() const {
return m_mapFn(m_currInfoItr);
}
// pre-incr ++itr;
consteval iterator operator++() {
m_currInfoItr = m_next(m_currInfoItr, m_reflectedEntity, m_nextIndex++);
return *this;
}
// post-incr itr++;
consteval iterator operator++(int) {
iterator tmp = *this;
operator++();
return tmp;
}
consteval friend bool operator==(iterator a, iterator b) {
return a.m_currInfoItr == b.m_currInfoItr;
}
consteval friend bool operator!=(iterator a, iterator b) {
return a.m_currInfoItr != b.m_currInfoItr;
}
};
template <typename Iter>
class range {
Iter m_first;
Iter m_last;
public:
using iterator = Iter;
consteval range(info reflection)
: m_first(reflection), m_last()
{ }
consteval iterator begin() const
{
return m_first;
}
consteval iterator end() const
{
return m_last;
}
};
template <typename Front, typename Next, typename Map>
consteval ptrdiff_t distance(iterator<Front, Next, Map> first,
iterator<Front, Next, Map> last) {
ptrdiff_t n = 0;
for (; first != last; ++first)
++n;
return n;
}
constexpr struct next_member_of_fn {
consteval info operator()(info currItrInfo, auto /* reflectedEntity */,
auto /* idx */) const {
return __metafunction(detail::__metafn_get_next_member_decl_of, currItrInfo,
LIFT(sentinel));
}
} next_member;
constexpr struct front_member_of_fn {
consteval info operator()(info reflectedEntity) const {
return __metafunction(detail::__metafn_get_begin_member_decl_of,
reflectedEntity, LIFT(sentinel));
}
} front_member;
constexpr struct map_decl_to_entity_fn {
consteval info operator()(info reflectedDecl) const {
return __metafunction(detail::__metafn_map_decl_to_entity, reflectedDecl);
}
} map_decl_to_entity;
constexpr struct map_identity_fn {
consteval info operator()(info reflectedDecl) const {
return reflectedDecl;
}
} map_identity;
constexpr struct next_targ_fn {
consteval info operator()(auto /* currItrInfo */, info reflectedEntity,
size_t idx) const {
return __metafunction(detail::__metafn_get_ith_template_argument_of,
reflectedEntity, LIFT(sentinel), idx);
}
} next_targ;
constexpr struct front_targ_fn {
consteval info operator()(info reflectedEntity) const {
return __metafunction(detail::__metafn_get_ith_template_argument_of,
reflectedEntity, LIFT(sentinel), 0);
}
} front_targ;
constexpr struct next_base_of_fn {
consteval info operator()(auto /* currItrInfo */, info reflectedEntity,
size_t idx) const {
return __metafunction(detail::__metafn_get_ith_base_of,
reflectedEntity, LIFT(sentinel), idx);
}
} next_base;
constexpr struct front_base_of_fn {
consteval info operator()(info reflectedEntity) const {
return __metafunction(detail::__metafn_get_ith_base_of,
reflectedEntity, LIFT(sentinel), 0);
}
} front_base;
constexpr struct next_enumerator_of_fn {
consteval info operator()(info currItrInfo, auto /* reflectedEntity */,
auto /* idx */ ) const {
return __metafunction(detail::__metafn_get_get_next_enumerator_decl_of,
currItrInfo, LIFT(sentinel));
}
} next_enumerator;
constexpr struct front_enumerator_of_fn {
consteval info operator()(info reflectedEntity) const {
return __metafunction(detail::__metafn_get_begin_enumerator_decl_of,
reflectedEntity, LIFT(sentinel));
}
} front_enumerator;
#if __has_feature(parameter_reflection)
struct next_parameter_of_fn {
consteval info operator()(auto /* currItrInfo */, info reflectedEntity,
size_t idx) const {
return __metafunction(detail::__metafn_get_ith_parameter_of,
reflectedEntity, LIFT(sentinel), idx);
}
};
struct front_parameter_of_fn {
consteval info operator()(info reflectedEntity) const {
return __metafunction(detail::__metafn_get_ith_parameter_of,
reflectedEntity, LIFT(sentinel), 0);
}
};
#endif // __has_feature(parameter_reflection)
// TODO(P2996): Guard on feature flag.
struct next_annotation_of {
consteval info operator()(auto /*currItrInfo */, info reflectedEntity,
size_t idx) const {
return __metafunction(detail::__metafn_get_ith_annotation_of,
reflectedEntity, LIFT(sentinel), idx);
}
};
struct front_annotation_of {
consteval info operator()(info reflectedEntity) const {
return __metafunction(detail::__metafn_get_ith_annotation_of,
reflectedEntity, LIFT(sentinel), 0);
}
};
} // namespace __range_of_infos
// -----------------------------------------------------------------------------
// Metafunctions
// -----------------------------------------------------------------------------
// Returns a reflection of the canonical type for the reflected type.
consteval auto dealias(info r) -> info {
return __metafunction(detail::__metafn_dealias, r);
}
// Returns the identifier for the represented entity. If the entity is a
// literal operator or literal operator template, then this is the identifier
// suffix for the literal operator.
consteval auto identifier_of(info r) -> const char* {
return __metafunction(detail::__metafn_identifier_of, LIFT(const char *), r,
/*UTF8=*/false, /*EnforceConsistent=*/true);
}
consteval auto u8identifier_of(info r) -> const char8_t* {
return __metafunction(detail::__metafn_identifier_of, LIFT(const char8_t *),
r, /*UTF8=*/true, /*EnforceConsistent=*/true);
}
// Returns an implementation-defined name for the reflected entity.
consteval auto display_string_of(info r) -> const char*;
consteval auto u8display_string_of(info r) -> const char8_t*;
// Enumeration of all overloadable operators.
enum class operators {
op_new = 1, op_delete, op_array_new, op_array_delete, op_co_await,
op_parentheses, op_square_brackets, op_arrow, op_arrow_star, op_tilde,
op_exclaim, op_plus, op_minus, op_star, op_slash, op_percent, op_caret,
op_ampersand, op_pipe, op_equals, op_plus_equals, op_minus_equals,
op_star_equals, op_slash_equals, op_percent_equals, op_caret_equals,
op_ampersand_equals, op_pipe_equals, op_equals_equals, op_exclaim_equals,
op_less, op_greater, op_less_equals, op_greater_equals, op_three_way_compare,
op_ampersand_ampersand, op_pipe_pipe, op_less_less, op_greater_greater,
op_less_less_equals, op_greater_greater_equals, op_plus_plus, op_minus_minus,
op_comma,
};
// Returns the operator overloaded by the represented operator function or
// operator function template.
consteval auto operator_of(info r) -> operators {
return operators(__metafunction(detail::__metafn_operator_of, r));
}
// Returns whether the reflected entity has an associated identifier.
consteval auto has_identifier(info r) -> bool {
return __metafunction(detail::__metafn_has_identifier, r);
}
// Returns the string representation of the operator.
consteval auto operator_symbol_of(operators op) -> const char* {
static constexpr const char* op_names[45] = {
{}, "new", "delete", "new[]", "delete[]", "coawait", "()", "[]", "->",
"->*", "~", "!", "+", "-", "*", "/", "%", "^", "&", "|", "=", "+=", "-=",
"*=", "/=", "%=", "^", "&=", "|=", "==", "!=", "<", ">", "<=", ">=",
"<=>", "&&", "||", "<<", ">>", "<<=", ">>=", "++", "--", ","
};
return op_names[int(op)];
}
consteval auto u8operator_symbol_of(operators op) -> const char8_t* {
static constexpr const char8_t* op_names[45] = {
{}, u8"new", u8"delete", u8"new[]", u8"delete[]", u8"coawait", u8"()",
u8"[]", u8"->", u8"->*", u8"~", u8"!", u8"+", u8"-", u8"*", u8"/", u8"%",
u8"^", u8"&", u8"|", u8"=", u8"+=", u8"-=", u8"*=", u8"/=", u8"%=",
u8"^", u8"&=", u8"|=", u8"==", u8"!=", u8"<", u8">", u8"<=", u8">=",
u8"<=>", u8"&&", u8"||", u8"<<", u8">>", u8"<<=", u8">>=", u8"++",
u8"--", u8","
};
return op_names[int(op)];
}
// Returns the source location of the reflected entity.
consteval auto source_location_of(info r) -> source_location {
auto ptr = __metafunction(detail::__metafn_source_location_of, r);
return source_location::current(ptr);
}
// Returns the type of the provided reflection of an expression.
consteval auto type_of(info r) -> info {
return __metafunction(detail::__metafn_type_of, r);
}
// Returns the containing class or namespace of a class or namespace member.
consteval auto parent_of(info r) -> info {
return __metafunction(detail::__metafn_parent_of, r);
}
// Returns a reflection of the object designated by the reflected entity.
consteval auto object_of(info r) -> info {
return __metafunction(detail::__metafn_object_of, r);
}
// Returns a reflection of the value evaluated from the reflected entity.
consteval auto value_of(info r) -> info {
return __metafunction(detail::__metafn_value_of, r);
}
// Returns a reflection of the template from which the reflected entity was
// instantiated.
consteval auto template_of(info r) -> info {
return __metafunction(detail::__metafn_template_of, r);
}
consteval auto template_arguments_of(info r) -> info_array {
using iterator =
__range_of_infos::iterator<__range_of_infos::front_targ_fn,
__range_of_infos::next_targ_fn,
__range_of_infos::map_identity_fn>;
using range = __range_of_infos::range<iterator>;
auto rng = range{r};
return vector<info>{rng.begin(), rng.end()};
}
// Returns whether the reflected entity is a member of a class.
consteval auto is_class_member(info r) -> bool {
return __metafunction(detail::__metafn_is_class_member, r);
}
// Returns whether the reflected entity is a non-static data member.
consteval auto is_nonstatic_data_member(info r) -> bool {
return is_class_member(r) &&
__metafunction(detail::__metafn_is_nonstatic_data_member, r);
}
// Returns whether the reflected entity is a static member.
consteval auto is_static_member(info r) -> bool {
return is_class_member(r) &&
__metafunction(detail::__metafn_is_static_member, r);
}
// Returns whether the reflected entity is a base class specifier.
consteval auto is_base(info r) -> bool {
return __metafunction(detail::__metafn_is_base, r);
}
// Returns whether the reflected entity is a description of a data member.
consteval auto is_data_member_spec(info r) -> bool {
return __metafunction(detail::__metafn_is_data_member_spec, r);
}
consteval auto members_of(info r) -> info_array {
using iterator =
__range_of_infos::iterator<__range_of_infos::front_member_of_fn,
__range_of_infos::next_member_of_fn,
__range_of_infos::map_decl_to_entity_fn>;
using range = __range_of_infos::range<iterator>;
auto rng = range{r};
return vector<info>{rng.begin(), rng.end()};
}
// Returns whether the reflected entity is a namespace.
consteval auto is_namespace(info r) -> bool {
return __metafunction(detail::__metafn_is_namespace, r);
}
consteval auto bases_of(info r) -> info_array {
if (is_namespace(r))
throw "Namespaces cannot have base classes";
using iterator =
__range_of_infos::iterator<__range_of_infos::front_base_of_fn,
__range_of_infos::next_base_of_fn,
__range_of_infos::map_identity_fn>;
using range = __range_of_infos::range<iterator>;
auto rng = range{r};
return vector<info>{rng.begin(), rng.end()};
}
// Returns whether the reflected entity is a variable.
consteval auto is_variable(info r) -> bool {
return __metafunction(detail::__metafn_is_variable, r);
}
consteval auto static_data_members_of(info r) -> info_array {
if (is_namespace(r))
throw "Namespaces cannot have static data members";
return members_of(r) | views::filter(is_variable) |
ranges::to<vector>();
}
consteval auto nonstatic_data_members_of(info r) -> info_array {
if (is_namespace(r))
throw "Namespaces cannot have non-static data members";
return members_of(r) | views::filter(is_nonstatic_data_member) |
ranges::to<vector>();
}
consteval auto subobjects_of(info r) -> info_array {
if (is_namespace(r))
throw "Namespaces cannot have subobjects";
auto subobjects = bases_of(r) | ranges::to<vector>();
subobjects.append_range(nonstatic_data_members_of(r));
return subobjects;
}
// Returns true if the reflected entity has a complete definition.
consteval auto has_complete_definition(info r) -> bool {
return __metafunction(detail::__metafn_has_complete_definition, r);
}
consteval auto enumerators_of(info r) -> info_array {
if (!has_complete_definition(r))
throw "Reflection must represent an enumeration with a definition";
using iterator =
__range_of_infos::iterator<__range_of_infos::front_enumerator_of_fn,
__range_of_infos::next_enumerator_of_fn,
__range_of_infos::map_identity_fn>;
using range = __range_of_infos::range<iterator>;
auto rng = range{r};
return vector<info>{rng.begin(), rng.end()};
}
// Returns whether the reflected entity is a public class member.
consteval auto is_public(info r) -> bool {
return __metafunction(detail::__metafn_is_public, r);
}
consteval auto get_public_members(info r) -> info_array {
return members_of(r) | views::filter(is_public) | ranges::to<vector>();
}
consteval auto get_public_bases(info r) -> info_array {
return bases_of(r) | views::filter(is_public) | ranges::to<vector>();
}
consteval auto get_public_static_data_members(info r) -> info_array {
return static_data_members_of(r) | views::filter(is_public) |
ranges::to<vector>();
}
consteval auto get_public_nonstatic_data_members(info r) -> info_array {
return nonstatic_data_members_of(r) | views::filter(is_public) |
ranges::to<vector>();
}
class access_context {
const info repr;
consteval access_context(info repr) : repr(repr) { }
public:
consteval access_context() noexcept : repr(LIFT(::)) { };
consteval access_context(const access_context &) noexcept = default;
consteval access_context(access_context &&) noexcept = default;
static consteval access_context current() noexcept {
return access_context(__metafunction(detail::__metafn_access_context));
}
};
consteval auto is_accessible(
info target,
access_context from = access_context::current()) -> bool {
info Repr = from.[:nonstatic_data_members_of(LIFT(access_context))[0]:];
return __metafunction(detail::__metafn_is_accessible, target, Repr);
}
consteval auto accessible_members_of(
info target,
access_context from = access_context::current())
-> info_array {
if (is_namespace(target))
throw "Cannot query the accessible members of a namespace";
return members_of(target) |
views::filter([&](info r) { return is_accessible(r, from); }) |
ranges::to<vector>();
}
consteval auto accessible_bases_of(
info target,
access_context from = access_context::current())
-> info_array {
if (is_namespace(target))
throw "Namespaces cannot have base classes";
return bases_of(target) |
views::filter([&](info r) { return is_accessible(r, from); }) |
ranges::to<vector>();
}
consteval auto accessible_nonstatic_data_members_of(
info target,
access_context from = access_context::current()) -> info_array {
if (is_namespace(target))
throw "Namespaces cannot have nonstatic members";
return accessible_members_of(target, from) |
views::filter([&](info r) { return is_nonstatic_data_member(r); }) |
ranges::to<vector>();
}
consteval auto accessible_static_members_of(
info target,
access_context from = access_context::current()) -> info_array {
if (is_namespace(target))
throw "Namespaces cannot have static members";
return accessible_members_of(target, from) |
views::filter([&](info r) { return is_variable(r); }) |
ranges::to<vector>();
}
consteval auto accessible_subobjects_of(
info target,
access_context from = access_context::current()) -> info_array {
if (is_namespace(target))
throw "Namespaces cannot have subobjects";
auto subobjects = accessible_bases_of(target, from) | ranges::to<vector>();
subobjects.append_range(accessible_nonstatic_data_members_of(target, from));
return subobjects;
}
// Returns whether 'templ' substituted with 'args' forms a valid template-id.
template <reflection_range R = initializer_list<info>>
consteval auto can_substitute(info templ, R &&args) -> bool {
if constexpr (ranges::contiguous_range<R>) {
return __metafunction(detail::__metafn_can_substitute, templ,
ranges::data(args), ranges::size(args));
} else {
vector vargs = args | ranges::to<vector>();
return __metafunction(detail::__metafn_can_substitute, templ,
vargs.data(), vargs.size());
}
}
// Returns a reflection representing the template instantiation of the entity
// reflected by 'templ' with the entities reflected by 'args'.
template <reflection_range R = initializer_list<info>>
consteval auto substitute(info templ, R &&args) -> info {
if constexpr (ranges::contiguous_range<R>) {
return __metafunction(detail::__metafn_substitute, templ,
ranges::data(args), ranges::size(args));
} else {
vector vargs = args | ranges::to<vector>();
return __metafunction(detail::__metafn_substitute, templ, vargs.data(),
vargs.size());
}
}
// Returns the value or object from 'r' if 'r' is a reflection of a value
// or object having type 'T'.
template <typename Ty> requires (!is_rvalue_reference_v<Ty>)
consteval auto extract(info r) -> Ty {
return __metafunction(detail::__metafn_extract, LIFT(Ty), r);
}
// Returns whether the reflected entity is a protected class member.
consteval auto is_protected(info r) -> bool {
return __metafunction(detail::__metafn_is_protected, r);
}
// Returns whether the reflected entity is a private class member.
consteval auto is_private(info r) -> bool {
return __metafunction(detail::__metafn_is_private, r);
}
// Returns whether the visibility of the reflected entity was specified.
consteval auto is_access_specified(info r) -> bool {
return __metafunction(detail::__metafn_is_access_specified, r);
}
// Returns whether the reflected entity is a virtual member function or a
// virtual base class.
consteval auto is_virtual(info r) -> bool {
return __metafunction(detail::__metafn_is_virtual, r);
}
// Returns whether the reflected class member function is pure virtual.
consteval auto is_pure_virtual(info r) -> bool {
return __metafunction(detail::__metafn_is_pure_virtual, r);
}
// Returns whether the reflected class member function overrides a virtual
// member function from a base class.
consteval auto is_override(info r) -> bool {
return __metafunction(detail::__metafn_is_override, r);
}
// Returns whether the reflected class member function is deleted.
consteval auto is_deleted(info r) -> bool {
return __metafunction(detail::__metafn_is_deleted, r);
}
// Returns whether the reflected class member function is defaulted.
consteval auto is_defaulted(info r) -> bool {
return __metafunction(detail::__metafn_is_defaulted, r);
}
// Returns whether the reflected class member function is explicit.
consteval auto is_explicit(info r) -> bool {
return __metafunction(detail::__metafn_is_explicit, r);
}
// Returns whether the reflected function type, function or member function
// is noexcept.
consteval auto is_noexcept(info r) -> bool {
return __metafunction(detail::__metafn_is_noexcept, r);
}
// Returns whether the reflected class data member is a bit field.
consteval auto is_bit_field(info r) -> bool {
return __metafunction(detail::__metafn_is_bit_field, r);
}
// Returns whether the reflected class data member is an enumerator.
consteval auto is_enumerator(info r) -> bool {
return __metafunction(detail::__metafn_is_enumerator, r);
}
// Returns whether the reflected type is const-qualified, or if the reflected
// entity is of such a type.
consteval auto is_const(info r) -> bool {
return __metafunction(detail::__metafn_is_const, r);
}
// Returns whether the reflected type is volatile-qualified, or if the reflected
// entity is of such a type.
consteval auto is_volatile(info r) -> bool {
return __metafunction(detail::__metafn_is_volatile, r);
}
// Returns whether the reflected entity is a mutable class member.
consteval auto is_mutable_member(info r) -> bool {
return __metafunction(detail::__metafn_is_mutable_member, r);
}
// Returns whether the reflected member function or function type is
// lvalue-reference qualified.
consteval auto is_lvalue_reference_qualified(info r) -> bool {
return __metafunction(detail::__metafn_is_lvalue_reference_qualified, r);
}
// Returns whether the reflected member function or function type is
// rvalue-reference qualified.
consteval auto is_rvalue_reference_qualified(info r) -> bool {
return __metafunction(detail::__metafn_is_rvalue_reference_qualified, r);
}
// Returns whether the reflected entity is a variable having static storage
// duration.
consteval auto has_static_storage_duration(info r) -> bool {
return __metafunction(detail::__metafn_has_static_storage_duration, r);
}
// Returns whether the reflected entity is a variable having thread storage
// duration.
consteval auto has_thread_storage_duration(info r) -> bool {
return __metafunction(detail::__metafn_has_thread_storage_duration, r);
}
// Returns whether the reflected entity is a variable having automatic storage
// duration.
consteval auto has_automatic_storage_duration(info r) -> bool {
return __metafunction(detail::__metafn_has_automatic_storage_duration, r);
}
// Returns whether the reflected entity has internal linkage.
consteval auto has_internal_linkage(info r) -> bool {
return __metafunction(detail::__metafn_has_internal_linkage, r);
}
// Returns whether the reflected entity has module linkage.
consteval auto has_module_linkage(info r) -> bool {
return __metafunction(detail::__metafn_has_module_linkage, r);
}
// Returns whether the reflected entity has external linkage.
consteval auto has_external_linkage(info r) -> bool {
return __metafunction(detail::__metafn_has_external_linkage, r);
}
// Returns whether the reflected entity has linkage.
consteval auto has_linkage(info r) -> bool {
return __metafunction(detail::__metafn_has_linkage, r);
}
// Returns whether the reflected entity is a member of a namespace.
consteval auto is_namespace_member(info r) -> bool {
return __metafunction(detail::__metafn_is_namespace_member, r);
}
// Returns whether the reflected entity is a function.
consteval auto is_function(info r) -> bool {
return __metafunction(detail::__metafn_is_function, r);
}
// Returns whether the reflected entity is a type.
consteval auto is_type(info r) -> bool {
return __metafunction(detail::__metafn_is_type, r);
}
// Returns true if the reflected entity is an alias.
consteval auto is_type_alias(info r) -> bool {
return is_type(r) && __metafunction(detail::__metafn_is_alias, r);
}
// Returns true if the reflected entity is an alias.
consteval auto is_namespace_alias(info r) -> bool {
return is_namespace(r) && __metafunction(detail::__metafn_is_alias, r);
}
// Returns true if the reflected entity is a complete type.
consteval auto is_complete_type(info r) -> bool {
return __metafunction(detail::__metafn_is_complete_type, r);
}
// Returns true if the reflected entity is a template.
consteval auto is_template(info r) -> bool {
return __metafunction(detail::__metafn_is_template, r);
}
// Returns true if the reflected entity is a function template.
consteval auto is_function_template(info r) -> bool {
return __metafunction(detail::__metafn_is_function_template, r);
}
// Returns true if the reflected entity is a variable template.
consteval auto is_variable_template(info r) -> bool {
return __metafunction(detail::__metafn_is_variable_template, r);
}
// Returns true if the reflected entity is a class template.
consteval auto is_class_template(info r) -> bool {
return __metafunction(detail::__metafn_is_class_template, r);
}
// Returns true if the reflected entity is an alias template.
consteval auto is_alias_template(info r) -> bool {
return __metafunction(detail::__metafn_is_alias_template, r);
}
// Returns true if 'r' represents a conversion function template.
consteval auto is_conversion_function_template(info r) -> bool {
return __metafunction(detail::__metafn_is_conversion_function_template, r);
}
// Returns true if 'r' represents an operator function template.
consteval auto is_operator_function_template(info r) -> bool {
return __metafunction(detail::__metafn_is_operator_function_template, r);
}
// Returns true if 'r' represents a literal operator template.
consteval auto is_literal_operator_template(info r) -> bool {
return __metafunction(detail::__metafn_is_literal_operator_template, r);
}
// Returns true if the reflected entity is a constructor template.
consteval auto is_constructor_template(info r) -> bool {
return __metafunction(detail::__metafn_is_constructor_template, r);
}
// Returns true if the reflected entity is a concept.
consteval auto is_concept(info r) -> bool {
return __metafunction(detail::__metafn_is_concept, r);
}
// Returns whether the reflected entity is a structured binding.
consteval auto is_structured_binding(info r) -> bool {
return __metafunction(detail::__metafn_is_structured_binding, r);
}
// Returns true if the reflected entity is a value.
consteval auto is_value(info r) -> bool {
return __metafunction(detail::__metafn_is_value, r);
}
// Returns true if the reflected entity is an object.
consteval auto is_object(info r) -> bool {
return __metafunction(detail::__metafn_is_object, r);
}
// Returns if the reflected entity has template arguments
consteval auto has_template_arguments(info r) -> bool {
return __metafunction(detail::__metafn_has_template_arguments, r);
}
// Returns if the reflected non-static data member has a default initializer.
consteval auto has_default_member_initializer(info r) -> bool {
return __metafunction(detail::__metafn_has_default_member_initializer, r);
}
// Returns whether 'r' represents a conversion function.
consteval auto is_conversion_function(info r) -> bool {
return __metafunction(detail::__metafn_is_conversion_function, r);
}
// Returns whether 'r' represents an operator function.
consteval auto is_operator_function(info r) -> bool {
return __metafunction(detail::__metafn_is_operator_function, r);
}
// Returns whether 'r' represents a literal operator.
consteval auto is_literal_operator(info r) -> bool {
return __metafunction(detail::__metafn_is_literal_operator, r);
}
// Returns whether the reflected entity is a constructor.
consteval auto is_constructor(info r) -> bool {
return __metafunction(detail::__metafn_is_constructor, r);
}
// Returns whether the reflected entity is a default constructor.
consteval auto is_default_constructor(info r) -> bool {
return __metafunction(detail::__metafn_is_default_constructor, r);
}
// Returns whether the reflected entity is a copy constructor.
consteval auto is_copy_constructor(info r) -> bool {
return __metafunction(detail::__metafn_is_copy_constructor, r);
}
// Returns whether the reflected entity is a move constructor.
consteval auto is_move_constructor(info r) -> bool {
return __metafunction(detail::__metafn_is_move_constructor, r);
}
// Returns whether the reflected entity is an assignment operator.
consteval auto is_assignment(info r) -> bool {
return __metafunction(detail::__metafn_is_assignment, r);
}
// Returns whether the reflected entity is a copy assignment operator.
consteval auto is_copy_assignment(info r) -> bool {
return __metafunction(detail::__metafn_is_copy_assignment, r);
}
// Returns whether the reflected entity is a move assignment operator.
consteval auto is_move_assignment(info r) -> bool {
return __metafunction(detail::__metafn_is_move_assignment, r);
}
// Returns whether the reflected entity is a destructor.
consteval auto is_destructor(info r) -> bool {
return __metafunction(detail::__metafn_is_destructor, r);
}
// Returns whether the reflected entity is a special member function.
consteval auto is_special_member_function(info r) -> bool {
return __metafunction(detail::__metafn_is_special_member_function, r);
}
// Returns whether the reflected entity is a user-provided function.
consteval auto is_user_provided(info r) -> bool {
return __metafunction(detail::__metafn_is_user_provided, r);
}
// Returns whether the reflected entity is a user-declared function.
consteval auto is_user_declared(info r) -> bool {
return __metafunction(detail::__metafn_is_user_declared, r);
}
// Returns a reflection of the value held by the provided argument.
template <typename T>
requires (!is_reference_v<T> &&
__metafunction(detail::__metafn_is_structural_type, LIFT(T)))
consteval auto reflect_value(T r) -> info {
constexpr info Ty = type_of(LIFT(r));
return __metafunction(detail::__metafn_reflect_result, Ty,
static_cast<typename [:Ty:]>(r));
}
// Returns a reflection of the object designated by the provided argument.
template <typename T> requires (!is_function_v<remove_reference_t<T>>)
consteval auto reflect_object(T &r) -> info {
return __metafunction(detail::__metafn_reflect_result, type_of(LIFT(r)), r);
}
// Returns a reflection of the object designated by the provided argument.
template <typename T> requires (is_function_v<remove_reference_t<T>>)
consteval auto reflect_function(T &r) -> info {
return __metafunction(detail::__metafn_reflect_result, type_of(LIFT(r)), r);
}
// Returns a reflection of the constant value obtained from calling
// target(args...)
template <reflection_range R = initializer_list<info>>
consteval auto reflect_invoke(info target, R &&args) -> info {
if constexpr (ranges::contiguous_range<R>) {
return __metafunction(detail::__metafn_reflect_invoke, target,
static_cast<info *>(nullptr), 0,
ranges::data(args), ranges::size(args));
} else {
vector vargs = args | ranges::to<vector>();
return __metafunction(detail::__metafn_reflect_invoke, target,
static_cast<info *>(nullptr), 0,
vargs.data(), vargs.size());
}
}
template <reflection_range R1 = initializer_list<info>,
reflection_range R2 = initializer_list<info>>
consteval auto reflect_invoke(info target, R1 &&targs, R2 &&args) -> info {
if constexpr (ranges::contiguous_range<R1>) {
if constexpr (ranges::contiguous_range<R2>) {
return __metafunction(detail::__metafn_reflect_invoke, target,
ranges::data(targs), ranges::size(targs),
ranges::data(args), ranges::size(args));
} else {
vector vargs = args | ranges::to<vector>();
return __metafunction(detail::__metafn_reflect_invoke, target,
ranges::data(targs), ranges::size(targs),
vargs.data(), vargs.size());
}
} else {
vector vtargs = targs | ranges::to<vector>();
if constexpr (ranges::contiguous_range<R2>) {
return __metafunction(detail::__metafn_reflect_invoke, target,
vtargs.data(), vtargs.size(),
ranges::data(args), ranges::size(args));
} else {
vector vargs = args | ranges::to<vector>();
return __metafunction(detail::__metafn_reflect_invoke, target,
vtargs.data(), vtargs.size(),
vargs.data(), vargs.size());
}
}
}
// Representation of a data member which may be passed to 'data_member_spec'.
struct data_member_options_t {
struct name_type {
variant<u8string, string> impl;
template <typename T> requires constructible_from<u8string, T>
consteval name_type(T &&in) : impl(in_place_type<u8string>, in) {}
template <typename T> requires constructible_from<string, T>
consteval name_type(T &&in) : impl(in_place_type<string>, in) {}
};
optional<name_type> name = nullopt;
optional<int> alignment = nullopt;
optional<int> width = nullopt;
bool no_unique_address = false;
};
// Returns the alignment of the reflected entity.
consteval auto alignment_of(info r) -> size_t {
return __metafunction(detail::__metafn_alignment_of, r);
}
// Returns a reflection representing a description of a data member, which may
// be used with 'define_class' to define a record type.
consteval auto data_member_spec(info member_type,
data_member_options_t options = {}) -> info {
if (!is_type(member_type))
throw "'member_type' must represent a type";
auto name = options.name.value_or(u8"").impl;
int alignment = options.alignment.value_or(0);
int width = options.width.value_or(0);
bool no_unique_address = options.no_unique_address;
auto validate = [&](auto name_string) {
if (width) {
if (alignment)
throw "Cannot specify both width and alignment for data member";
if (no_unique_address)
throw "Cannot specify both width and no_unique_address for data member";
if (width < 0)
throw "Cannot specify a negative width for data member";
if (!extract<bool>(substitute(LIFT(is_integral_v), {member_type})) &&
!extract<bool>(substitute(LIFT(is_enum_v), {member_type})))
throw "Bit field must have integral or enumeral type";
} else {
if (options.width.has_value() && !name_string.empty())
throw "Bit-fields of zero width must be unnamed";
}
if (alignment) {
if (alignment < int(alignment_of(member_type)))
throw "Cannot specify an alignment less than that of the member type";
if (alignment <= 0 || ((alignment - 1) & alignment))
throw "Alignment specifier must be a non-negative power of 2";
}
};
if (holds_alternative<u8string>(name)) {
const u8string &s = get<u8string>(name);
validate(s);
return __metafunction(detail::__metafn_data_member_spec,
member_type,
!s.empty(), s.size(), LIFT(const char8_t), s.data(),
options.alignment.has_value(), alignment,
options.width.has_value(), width,
no_unique_address);
} else {
const string &s = get<string>(name);
validate(s);
return __metafunction(detail::__metafn_data_member_spec,
member_type,
!s.empty(), s.size(), LIFT(const char), s.data(),
options.alignment.has_value(), alignment,
options.width.has_value(), width,
no_unique_address);
}
}
// Completes the definition of the record type reflected by 'class_type' with
// the members described by the reflections in the provided range.
template <reflection_range R = initializer_list<info>>
consteval auto define_class(info class_type, R &&members) -> info {
if constexpr (ranges::contiguous_range<R>) {
return __metafunction(detail::__metafn_define_class, class_type,
ranges::size(members), ranges::data(members));
} else {
vector vmembers = members | ranges::to<vector>();
return __metafunction(detail::__metafn_define_class, class_type,
vmembers.size(), vmembers.data());
}
}
struct member_offsets {
size_t bytes;
size_t bits;
constexpr auto total_bits() -> size_t {
return bytes * CHAR_BIT + bits;
}
auto operator<=>(member_offsets const&) const = default;
};
// Returns the offset of the reflected entity.
consteval auto offset_of(info r) -> member_offsets {
return member_offsets {
__metafunction(detail::__metafn_offset_of, r),
__metafunction(detail::__metafn_bit_offset_of, r)
};
}
// Returns the size of the reflected entity.
consteval auto size_of(info r) -> size_t {
return __metafunction(detail::__metafn_size_of, r);
}
// Returns the size of the reflected entity in bits.
consteval auto bit_size_of(info r) -> size_t {
return __metafunction(detail::__metafn_bit_size_of, r);
}
// Returns a static string having the provided contents.
consteval auto define_static_string(string_view in) -> const char * {
return __metafunction(detail::__metafn_define_static_string,
LIFT(const char *), LIFT(char), in.size(), in.data(),
/*IsUtf8=*/false);
}
consteval auto define_static_string(u8string_view in) -> const char8_t * {
return __metafunction(detail::__metafn_define_static_string,
LIFT(const char8_t *), LIFT(char8_t),
in.size(), in.data(), /*IsUtf8=*/true);
}
template <ranges::input_range R>
requires (is_constructible_v<ranges::range_value_t<R>,
ranges::range_reference_t<R>>)
consteval auto define_static_array(R &&elems)
-> span<const ranges::range_value_t<R>> {
vector vec(from_range, elems);
using value_t = ranges::range_value_t<R>;
const value_t *arr = __metafunction(detail::__metafn_define_static_array,
LIFT(const value_t *), LIFT(value_t),
vec.size(), vec.data());
return span<const ranges::range_value_t<R>>(arr, vec.size());
}
// Type trait wrappers
consteval auto type_is_void(info r) -> bool {
return extract<bool>(substitute(LIFT(is_void_v), {r}));
}
consteval auto type_is_null_pointer(info r) -> bool {
return extract<bool>(substitute(LIFT(is_null_pointer_v), {r}));
}
consteval auto type_is_integral(info r) -> bool {
return extract<bool>(substitute(LIFT(is_integral_v), {r}));
}
consteval auto type_is_floating_point(info r) -> bool {
return extract<bool>(substitute(LIFT(is_floating_point_v), {r}));
}
consteval auto type_is_array(info r) -> bool {
return extract<bool>(substitute(LIFT(is_array_v), {r}));
}
consteval auto type_is_pointer(info r) -> bool {
return extract<bool>(substitute(LIFT(is_pointer_v), {r}));
}
consteval auto type_is_lvalue_reference(info r) -> bool {
return extract<bool>(substitute(LIFT(is_lvalue_reference_v), {r}));
}
consteval auto type_is_rvalue_reference(info r) -> bool {
return extract<bool>(substitute(LIFT(is_rvalue_reference_v), {r}));
}
consteval auto type_is_member_object_pointer(info r) -> bool {
return extract<bool>(substitute(LIFT(is_member_object_pointer_v), {r}));
}
consteval auto type_is_member_function_pointer(info r) -> bool {
return extract<bool>(substitute(LIFT(is_member_function_pointer_v), {r}));
}
consteval auto type_is_enum(info r) -> bool {
return extract<bool>(substitute(LIFT(is_enum_v), {r}));
}
consteval auto type_is_union(info r) -> bool {
return extract<bool>(substitute(LIFT(is_union_v), {r}));
}
consteval auto type_is_class(info r) -> bool {
return extract<bool>(substitute(LIFT(is_class_v), {r}));
}
consteval auto type_is_function(info r) -> bool {
return extract<bool>(substitute(LIFT(is_function_v), {r}));
}
consteval auto type_is_reference(info r) -> bool {
return extract<bool>(substitute(LIFT(is_reference_v), {r}));
}
consteval auto type_is_arithmetic(info r) -> bool {
return extract<bool>(substitute(LIFT(is_arithmetic_v), {r}));
}
consteval auto type_is_fundamental(info r) -> bool {
return extract<bool>(substitute(LIFT(is_fundamental_v), {r}));
}
consteval auto type_is_object(info r) -> bool {
return extract<bool>(substitute(LIFT(is_object_v), {r}));
}
consteval auto type_is_scalar(info r) -> bool {
return extract<bool>(substitute(LIFT(is_scalar_v), {r}));
}
consteval auto type_is_compound(info r) -> bool {
return extract<bool>(substitute(LIFT(is_compound_v), {r}));
}
consteval auto type_is_member_pointer(info r) -> bool {
return extract<bool>(substitute(LIFT(is_member_pointer_v), {r}));
}
consteval auto type_is_const(info r) -> bool {
return extract<bool>(substitute(LIFT(is_const_v), {r}));
}
consteval auto type_is_volatile(info r) -> bool {
return extract<bool>(substitute(LIFT(is_volatile_v), {r}));
}
consteval auto type_is_trivial(info r) -> bool {
return extract<bool>(substitute(LIFT(is_trivial_v), {r}));
}
consteval auto type_is_trivially_copyable(info r) -> bool {
return extract<bool>(substitute(LIFT(is_trivially_copyable_v), {r}));
}
consteval auto type_is_standard_layout(info r) -> bool {
return extract<bool>(substitute(LIFT(is_standard_layout_v), {r}));
}
consteval auto type_is_empty(info r) -> bool {
return extract<bool>(substitute(LIFT(is_empty_v), {r}));
}
consteval auto type_is_polymorphic(info r) -> bool {
return extract<bool>(substitute(LIFT(is_polymorphic_v), {r}));
}
consteval auto type_is_abstract(info r) -> bool {
return extract<bool>(substitute(LIFT(is_abstract_v), {r}));
}
consteval auto type_is_final(info r) -> bool {
return extract<bool>(substitute(LIFT(is_final_v), {r}));
}
consteval auto type_is_aggregate(info r) -> bool {
return extract<bool>(substitute(LIFT(is_aggregate_v), {r}));
}
consteval auto type_is_signed(info r) -> bool {
return extract<bool>(substitute(LIFT(is_signed_v), {r}));
}
consteval auto type_is_unsigned(info r) -> bool {
return extract<bool>(substitute(LIFT(is_unsigned_v), {r}));
}
consteval auto type_is_bounded_array(info r) -> bool {
return extract<bool>(substitute(LIFT(is_bounded_array_v), {r}));
}
consteval auto type_is_unbounded_array(info r) -> bool {
return extract<bool>(substitute(LIFT(is_unbounded_array_v), {r}));
}
consteval auto type_is_scoped_enum(info r) -> bool {
return extract<bool>(substitute(LIFT(is_scoped_enum_v), {r}));
}
template <reflection_range R = initializer_list<info>>
consteval auto type_is_constructible(info type, R &&type_args) {
vector<info> args(from_range, type_args);
args.insert(args.begin(), type);
return extract<bool>(substitute(LIFT(is_constructible_v), args));
}
consteval auto type_is_default_constructible(info r) -> bool {
return extract<bool>(substitute(LIFT(is_default_constructible_v), {r}));
}
consteval auto type_is_copy_constructible(info r) -> bool {
return extract<bool>(substitute(LIFT(is_copy_constructible_v), {r}));
}
consteval auto type_is_move_constructible(info r) -> bool {
return extract<bool>(substitute(LIFT(is_move_constructible_v), {r}));
}
consteval auto type_is_assignable(info dst, info src) -> bool {
return extract<bool>(substitute(LIFT(is_assignable_v), {dst, src}));
}
consteval auto type_is_copy_assignable(info r) -> bool {
return extract<bool>(substitute(LIFT(is_copy_assignable_v), {r}));
}
consteval auto type_is_move_assignable(info r) -> bool {
return extract<bool>(substitute(LIFT(is_move_assignable_v), {r}));
}
consteval auto type_is_swappable_with(info dst, info src) -> bool {
return extract<bool>(substitute(LIFT(is_swappable_with_v), {dst, src}));
}
consteval auto type_is_swappable(info r) -> bool {
return extract<bool>(substitute(LIFT(is_swappable_v), {r}));
}
consteval auto type_is_destructible(info r) -> bool {
return extract<bool>(substitute(LIFT(is_destructible_v), {r}));
}
template <reflection_range R = initializer_list<info>>
consteval auto type_is_trivially_constructible(info type, R &&type_args) {
vector<info> args(from_range, type_args);
args.insert(args.begin(), type);
return extract<bool>(substitute(LIFT(is_trivially_constructible_v), args));
}
consteval auto type_is_trivially_default_constructible(info r) -> bool {
return extract<bool>(substitute(LIFT(is_trivially_default_constructible_v),
{r}));
}
consteval auto type_is_trivially_copy_constructible(info r) -> bool {
return extract<bool>(substitute(LIFT(is_trivially_copy_constructible_v),
{r}));
}
consteval auto type_is_trivially_move_constructible(info r) -> bool {
return extract<bool>(substitute(LIFT(is_trivially_move_constructible_v),
{r}));
}
consteval auto type_is_trivially_assignable(info dst, info src) -> bool {
return extract<bool>(substitute(LIFT(is_trivially_assignable_v), {dst, src}));
}
consteval auto type_is_trivially_copy_assignable(info r) -> bool {
return extract<bool>(substitute(LIFT(is_trivially_copy_assignable_v), {r}));
}
consteval auto type_is_trivially_move_assignable(info r) -> bool {
return extract<bool>(substitute(LIFT(is_trivially_move_assignable_v), {r}));
}
consteval auto type_is_trivially_destructible(info r) -> bool {
return extract<bool>(substitute(LIFT(is_trivially_destructible_v), {r}));
}
template <reflection_range R = initializer_list<info>>
consteval auto type_is_nothrow_constructible(info type, R &&type_args) {
vector<info> args(from_range, type_args);
args.insert(args.begin(), type);
return extract<bool>(substitute(LIFT(is_nothrow_constructible_v), args));
}
consteval auto type_is_nothrow_default_constructible(info r) -> bool {
return extract<bool>(substitute(LIFT(is_nothrow_default_constructible_v),
{r}));
}
consteval auto type_is_nothrow_copy_constructible(info r) -> bool {
return extract<bool>(substitute(LIFT(is_nothrow_copy_constructible_v), {r}));
}
consteval auto type_is_nothrow_move_constructible(info r) -> bool {
return extract<bool>(substitute(LIFT(is_nothrow_move_constructible_v), {r}));
}
consteval auto type_is_nothrow_assignable(info dst, info src) -> bool {
return extract<bool>(substitute(LIFT(is_nothrow_assignable_v), {dst, src}));
}
consteval auto type_is_nothrow_copy_assignable(info r) -> bool {
return extract<bool>(substitute(LIFT(is_nothrow_copy_assignable_v), {r}));
}
consteval auto type_is_nothrow_move_assignable(info r) -> bool {
return extract<bool>(substitute(LIFT(is_nothrow_move_assignable_v), {r}));
}
consteval auto type_is_nothrow_swappable_with(info dst, info src) -> bool {
return extract<bool>(substitute(LIFT(is_nothrow_swappable_with_v),
{dst, src}));
}
consteval auto type_is_nothrow_swappable(info r) -> bool {
return extract<bool>(substitute(LIFT(is_nothrow_swappable_v), {r}));
}
consteval auto type_is_nothrow_destructible(info r) -> bool {
return extract<bool>(substitute(LIFT(is_nothrow_destructible_v), {r}));
}
// TODO(P2996): Not yet implemented in libc++.
/*consteval auto type_is_implicit_lifetime(info r) -> bool {
return extract<bool>(substitute(LIFT(is_implicit_lifetime_v), {r}));
}*/
consteval auto type_has_virtual_destructor(info r) -> bool {
return extract<bool>(substitute(LIFT(has_virtual_destructor_v), {r}));
}
consteval auto type_has_unique_object_representations(info r) -> bool {
return extract<bool>(substitute(LIFT(has_unique_object_representations_v),
{r}));
}
// TODO(P2996): Not yet implemented in libc++.
/*consteval auto type_reference_constructs_from_temporary(info r) -> bool {
return extract<bool>(substitute(LIFT(reference_constructs_from_temporary_v),
{r}));
}*/
// TODO({2996): Not yet implemented in libc++.
/*consteval auto type_reference_converts_from_temporary(info r) -> bool {
return extract<bool>(substitute(LIFT(reference_converts_from_temporary_v),
{r}));
}*/
consteval auto type_alignment_of(info r) -> size_t {
return extract<size_t>(substitute(LIFT(alignment_of_v), {r}));
}
consteval auto type_rank(info r) -> size_t {
return extract<size_t>(substitute(LIFT(rank_v), {r}));
}
consteval auto type_extent(info r, unsigned i = 0) -> size_t {
return extract<size_t>(substitute(LIFT(extent_v), {r, reflect_value(i)}));
}
consteval auto type_is_same(info r, info s) -> bool {
return extract<bool>(substitute(LIFT(is_same_v), {r, s}));
}
consteval auto type_is_base_of(info r, info s) -> bool {
return extract<bool>(substitute(LIFT(is_base_of_v), {r, s}));
}
consteval auto type_is_convertible(info r, info s) -> bool {
return extract<bool>(substitute(LIFT(is_convertible_v), {r, s}));
}
consteval auto type_is_nothrow_convertible(info r, info s) -> bool {
return extract<bool>(substitute(LIFT(is_nothrow_convertible_v), {r, s}));
}
// TODO(P2996): Not yet implemented in libc++.
/*consteval auto type_is_layout_compatible(info r, info s) -> bool {
return extract<bool>(substitute(LIFT(is_layout_compatible_v), {r, s}));
}*/
// TODO(P2996): Not yet implemented in libc++.
/*consteval auto type_is_pointer_interconvertible_base_of(info r,
info s) -> bool {
return extract<bool>(substitute(LIFT(is_pointer_interconvertible_base_of_v),
{r, s}));
}*/
template <reflection_range R = initializer_list<info>>
consteval auto type_is_invocable(info type, R &&args) {
vector<info> targs(from_range, args);
targs.insert(targs.begin(), type);
return extract<bool>(substitute(LIFT(is_invocable_v), targs));
}
template <reflection_range R = initializer_list<info>>
consteval auto type_is_invocable_r(info type_result, info type, R &&args) {
vector<info> targs(from_range, args);
targs.insert(targs.begin(), type);
targs.insert(targs.begin(), type_result);
return extract<bool>(substitute(LIFT(is_invocable_r_v), targs));
}
template <reflection_range R = initializer_list<info>>
consteval auto type_is_nothrow_invocable(info type, R &&args) {
vector<info> targs(from_range, args);
targs.insert(targs.begin(), type);
return extract<bool>(substitute(LIFT(is_nothrow_invocable_v), targs));
}
template <reflection_range R = initializer_list<info>>
consteval auto type_is_nothrow_invocable_r(info type_result, info type,
R &&args) {
vector<info> targs(from_range, args);
targs.insert(targs.begin(), type);
targs.insert(targs.begin(), type_result);
return extract<bool>(substitute(LIFT(is_nothrow_invocable_r_v), targs));
}
consteval auto type_remove_const(info type) -> info {
return detail::__workaround_expand_compiler_builtins(
dealias(substitute(LIFT(remove_const_t), {type})));
}
consteval auto type_remove_volatile(info type) -> info {
return detail::__workaround_expand_compiler_builtins(
dealias(substitute(LIFT(remove_volatile_t), {type})));
}
consteval auto type_remove_cv(info type) -> info {
return detail::__workaround_expand_compiler_builtins(
dealias(substitute(LIFT(remove_cv_t), {type})));
}
consteval auto type_add_const(info type) -> info {
return dealias(substitute(LIFT(add_const_t), {type}));
}
consteval auto type_add_volatile(info type) -> info {
return dealias(substitute(LIFT(add_volatile_t), {type}));
}
consteval auto type_add_cv(info type) -> info {
return dealias(substitute(LIFT(add_cv_t), {type}));
}
consteval auto type_remove_reference(info type) -> info {
return detail::__workaround_expand_compiler_builtins(
dealias(substitute(LIFT(remove_reference_t), {type})));
}
consteval auto type_add_lvalue_reference(info type) -> info {
return detail::__workaround_expand_compiler_builtins(
dealias(substitute(LIFT(add_lvalue_reference_t), {type})));
}
consteval auto type_add_rvalue_reference(info type) -> info {
return detail::__workaround_expand_compiler_builtins(
dealias(substitute(LIFT(add_rvalue_reference_t), {type})));
}
consteval auto type_make_signed(info type) -> info {
return detail::__workaround_expand_compiler_builtins(
dealias(substitute(LIFT(make_signed_t), {type})));
}
consteval auto type_make_unsigned(info type) -> info {
return detail::__workaround_expand_compiler_builtins(
dealias(substitute(LIFT(make_unsigned_t), {type})));
}
consteval auto type_remove_extent(info type) -> info {
return detail::__workaround_expand_compiler_builtins(
dealias(substitute(LIFT(remove_extent_t), {type})));
}
consteval auto type_remove_all_extents(info type) -> info {
return detail::__workaround_expand_compiler_builtins(
dealias(substitute(LIFT(remove_all_extents_t), {type})));
}
consteval auto type_remove_pointer(info type) -> info {
return detail::__workaround_expand_compiler_builtins(
dealias(substitute(LIFT(remove_pointer_t), {type})));
}
consteval auto type_add_pointer(info type) -> info {
return detail::__workaround_expand_compiler_builtins(
dealias(substitute(LIFT(add_pointer_t), {type})));
}
consteval auto type_remove_cvref(info type) -> info {
return detail::__workaround_expand_compiler_builtins(
dealias(substitute(LIFT(remove_cvref_t), {type})));
}
consteval auto type_decay(info type) -> info {
return detail::__workaround_expand_compiler_builtins(
dealias(substitute(LIFT(decay_t), {type})));
}
template <reflection_range R = initializer_list<info>>
consteval auto type_common_type(R &&type_args) -> info {
return detail::__workaround_expand_compiler_builtins(
dealias(substitute(LIFT(common_type_t), type_args)));
}
template <reflection_range R = initializer_list<info>>
consteval auto type_common_reference(R &&type_args) -> info {
return dealias(substitute(LIFT(common_reference_t), type_args));
}
consteval auto type_underlying_type(info type) -> info {
return detail::__workaround_expand_compiler_builtins(
dealias(substitute(LIFT(underlying_type_t), {type})));
}
template <reflection_range R = initializer_list<info>>
consteval auto type_invoke_result(info type, R &&type_args) -> info {
vector<info> targs(from_range, type_args);
targs.insert(targs.begin(), type);
return dealias(substitute(LIFT(invoke_result_t), targs));
}
consteval auto type_unwrap_reference(info type) -> info {
return dealias(substitute(LIFT(unwrap_reference_t), {type}));
}
consteval auto type_unwrap_ref_decay(info type) -> info {
return dealias(substitute(LIFT(unwrap_ref_decay_t), {type}));
}
consteval auto type_tuple_size(info type) -> size_t {
return extract<size_t>(substitute(LIFT(tuple_size_v), {type}));
}
consteval auto type_tuple_element(size_t index, info type) -> info {
return dealias(substitute(LIFT(tuple_element_t),
{std::meta::reflect_value(index), type}));
}
consteval auto type_variant_size(info type) -> size_t {
return extract<size_t>(substitute(LIFT(variant_size_v), {type}));
}
consteval auto type_variant_alternative(size_t index, info type) -> info {
return dealias(substitute(LIFT(variant_alternative_t),
{std::meta::reflect_value(index), type}));
}
namespace detail {
template <class T> struct __wrap_workaround { using type = T; };
consteval auto __workaround_expand_compiler_builtins(info type) -> info {
return dealias(members_of(substitute(LIFT(__wrap_workaround), {type}))[0]);
}
} // namespace detail
#if __has_feature(parameter_reflection)
consteval auto parameters_of(info r) -> info_array {
using iterator =
__range_of_infos::iterator<__range_of_infos::front_parameter_of_fn,
__range_of_infos::next_parameter_of_fn,
__range_of_infos::map_identity_fn>;
using range = __range_of_infos::range<iterator>;
auto rng = range{r};
return vector<info>{rng.begin(), rng.end()};
}
consteval auto has_consistent_identifier(info r) -> bool {
return __metafunction(detail::__metafn_has_consistent_identifier, r);
}
consteval auto any_identifier_of(info r) -> const char* {
return __metafunction(detail::__metafn_identifier_of, LIFT(const char *), r,
/*UTF8=*/false, /*EnforceConsistent=*/false);
}
consteval auto u8any_identifier_of(info r) -> const char8_t* {
return __metafunction(detail::__metafn_identifier_of, LIFT(const char8_t *),
r, /*UTF8=*/true, /*EnforceConsistent=*/false);
}
consteval auto has_ellipsis_parameter(info r) -> bool {
return __metafunction(detail::__metafn_has_ellipsis_parameter, r);
}
consteval auto has_default_argument(info r) -> bool {
return __metafunction(detail::__metafn_has_default_argument, r);
}
consteval auto is_explicit_object_parameter(info r) -> bool {
return __metafunction(detail::__metafn_is_explicit_object_parameter, r);
}
consteval auto is_function_parameter(info r) -> bool {
return __metafunction(detail::__metafn_is_function_parameter, r);
}
consteval auto return_type_of(info r) -> info {
return __metafunction(detail::__metafn_return_type_of, r);
}
#endif // __has_feature(parameter_reflection)
#if __has_feature(annotation_attributes)
consteval auto annotations_of(info r) -> info_array {
using iterator =
__range_of_infos::iterator<__range_of_infos::front_annotation_of,
__range_of_infos::next_annotation_of,
__range_of_infos::map_identity_fn>;
using range = __range_of_infos::range<iterator>;
auto rng = range{r};
return vector<info>{rng.begin(), rng.end()};
}
consteval auto annotations_of(info r, info ty) -> info_array {
if (!is_type(ty))
throw "Expected a reflection of a type";
return annotations_of(r) | views::filter([=](info annot) {
return type_of(annot) == ty;
}) | ranges::to<vector>();
}
template<typename T>
consteval optional<T> annotation_of_type(info r) {
auto v = annotations_of(r, ^^T);
optional<T> result{};
for (info a: v) {
if (result.has_value()) {
if (extract<T>(a) != result) {
throw "inconsistent annotations";
}
} else {
result = extract<T>(a);
}
}
return result;
}
consteval auto is_annotation(info r) -> bool {
return __metafunction(detail::__metafn_is_annotation, r);
}
consteval auto annotate(info entity, info val) -> info {
return __metafunction(detail::__metafn_annotate, entity, val);
}
#endif // __has_feature(annotation_attributes)
template <typename Ty>
[[deprecated("separated into 'reflect_value', 'reflect_result', and "
"'reflect_function' in P2996R4")]]
consteval auto reflect_result(Ty r) -> info {
constexpr auto DTy = dealias(LIFT(Ty));
constexpr auto RTy = is_class_v<[:DTy:]> || is_reference_v<[:DTy:]> ?
DTy : LIFT(remove_cv_t<[:DTy:]>);
return __metafunction(detail::__metafn_reflect_result, dealias(RTy),
static_cast<typename [:DTy:]>(r));
}
template <reflection_range R = initializer_list<info>>
[[deprecated("removed 'test_type' and 'test_types' in P2996R4")]]
consteval auto test_types(info templ, R &&args) -> bool {
return extract<bool>(substitute(templ, args));
}
[[deprecated("removed 'test_type' and 'test_types' in P2996R4")]]
consteval auto test_type(info templ, info type) -> bool {
info args[1] = {type};
return extract<bool>(substitute(templ, args));
}
[[deprecated("removed 'test_trait' in P2996R5")]]
consteval auto test_trait(info templ, info type) -> bool {
info args[1] = {type};
return extract<bool>(substitute(templ, args));
}
template <reflection_range R = initializer_list<info>>
[[deprecated("removed 'test_trait' in P2996R5")]]
consteval auto test_trait(info templ, R &&args) -> bool {
return extract<bool>(substitute(templ, args));
}
// ====================================
// (u8)display_string_of implementation
// ====================================
// For the sake of compile-times, this probably would be better off being
// implemented as an intrinsic - but it ought to be possible to use P2996 to
// implement something like it, and the exercise of implementing it as a
// library has revealed both gaps in the paper and bugs in the implementation.
//
// For now, seeing as Clang/P2996 is still first and foremost a prototype, the
// implementation stands as both a "test" of the power of the APIs proposed by
// the paper, and a demonstratation of some reflection techniques.
namespace detail {
template <typename CharT>
struct pretty_printer {
static_assert(dealias(LIFT(CharT)) == LIFT(char) ||
dealias(LIFT(CharT)) == LIFT(char8_t));
static constexpr bool IsUtf8 = type_is_same(LIFT(CharT), LIFT(char8_t));
using string_t = basic_string<CharT>;
static consteval const CharT *string_constant(std::string_view contents) {
if constexpr (IsUtf8) {
std::u8string result(contents.size(), 0);
for (size_t idx = 0; char c : contents)
result[idx++] = char8_t(c);
return std::meta::define_static_string(result);
} else {
return contents.data();
}
}
static consteval auto identifier_helper(info R) {
if constexpr (IsUtf8)
return u8identifier_of(R);
else
return identifier_of(R);
}
static consteval auto operator_symbol_helper(operators Op) {
if constexpr (IsUtf8)
return u8operator_symbol_of(Op);
else
return operator_symbol_of(Op);
}
template <info R>
static consteval info type_of_object_from_memptr() {
return []<typename T,
typename C>(T C::*) { return LIFT(C); }(typename [:R:]{});
};
template <info R>
static consteval info type_of_member_from_memptr() {
return []<typename T,
typename C>(T C::*) { return LIFT(T); }(typename [:R:]{});
};
template<auto... vals>
struct replicator_type {
template<typename F>
constexpr void operator>>(F body) const {
(body.template operator()<vals>(), ...);
}
};
template<auto... vals>
static constexpr replicator_type<vals...> replicator = {};
template<typename R>
static consteval auto expand(R range) {
vector<info> args;
for (auto r : range) {
args.push_back(reflect_value(r));
}
return substitute(LIFT(replicator), args);
}
template <info R>
requires (has_template_arguments(R))
static consteval string_t render_template_argument_list_of();
template <info R>
requires (is_value(R))
static consteval string_t render_value_as_hex();
template <info R>
static consteval const CharT *tprint();
struct tprint_impl {
template <info R> // Null reflection.
requires (R == info{})
static consteval string_t render() {
return string_constant("(null-reflection)");
}
template <info R> // Values of fundamental type.
requires (is_value(R) && type_is_fundamental(type_of(R)))
static consteval string_t render();
template <info R> // Values of aggregate type.
requires (is_value(R) && type_is_aggregate(type_of(R)))
static consteval string_t render();
template <info R> // Values of pointer type.
requires (is_value(R) && type_is_pointer(type_of(R)))
static consteval string_t render();
template <info R> // Objects.
requires (is_object(R))
static consteval string_t render();
template <info R> // Variables, data members, enumerators.
requires (is_variable(R) || is_nonstatic_data_member(R) ||
is_enumerator(R))
static consteval string_t render();
template <info R> // Templates.
requires (is_template(R))
static consteval string_t render();
template <info R> // Namespaces.
requires (is_namespace(R))
static consteval string_t render();
template <info R> // Functions.
requires (is_function(R))
static consteval string_t render();
template <info R> // Value types.
requires (is_type(R) && !(is_const(R) || is_volatile(R)) &&
!type_is_pointer(R) && !type_is_array(R) &&
!type_is_function(R) && !type_is_reference(R) &&
!type_is_member_pointer(R))
static consteval string_t render();
template <info R> // CV-qualified non-function, non-arry types.
requires (is_type(R) && (is_const(R) || is_volatile(R)) &&
!type_is_array(R) && !type_is_function(R))
static consteval string_t render();
template <info R> // Reference types.
requires (is_type(R) && !(is_const(R) || is_volatile(R)) &&
type_is_reference(R))
static consteval string_t render();
template <info R> // Unqualified array types.
requires (is_type(R) && type_is_array(R))
static consteval string_t render();
template <info R> // Function types.
requires (is_type(R) && type_is_function(R))
static consteval string_t render();
template <info R> // Non-function, non-member pointer types.
requires (is_type(R) && type_is_pointer(R) &&
!(is_const(R) || is_volatile(R)) &&
!type_is_function(type_remove_pointer(R)))
static consteval string_t render();
template <info R> // Function pointer types.
requires (is_type(R) && type_is_pointer(R) &&
type_is_function(type_remove_pointer(R)))
static consteval string_t render();
template <info R> // Pointer to data member types.
requires (is_type(R) && type_is_member_pointer(R) &&
!(is_const(R) || is_volatile(R)) &&
!type_is_member_function_pointer(R))
static consteval string_t render();
template <info R> // Pointer to member function types.
requires (is_type(R) && type_is_member_function_pointer(R))
static consteval string_t render();
template <info R> // Base specifiers.
requires (is_base(R))
static consteval string_t render();
template <info R> // Fallback.
static consteval string_t render();
};
static consteval const CharT *print(info R);
friend consteval auto display_string_of(info) -> const char*;
friend consteval auto u8display_string_of(info) -> const char8_t*;
};
template <typename CharT>
consteval auto pretty_printer<CharT>::print(info R)
-> const CharT * {
return extract<const CharT *>(reflect_invoke(LIFT(tprint),
{reflect_value(R)}, {}));
}
template <typename CharT>
template <info R>
requires (has_template_arguments(R))
consteval auto pretty_printer<CharT>::render_template_argument_list_of()
-> string_t {
string_t result;
size_t Idx = 0;
[:expand(template_arguments_of(R)):] >> [&]<auto TArg> {
result += (Idx++ < 1 ? string_constant("<") : string_constant(", "));
result += tprint_impl::template render<TArg>();
};
return result + string_constant(">");
}
template <typename CharT>
template <info R>
requires (is_value(R))
consteval auto pretty_printer<CharT>::render_value_as_hex() -> string_t {
string_t result = string_constant("0x");
auto bytes = bit_cast<array<unsigned char, size_of(type_of(R))>>([:R:]);
if (endian::native == endian::little)
reverse(begin(bytes), end(bytes));
for (auto b : bytes) {
static constexpr char lookup[] = "0123456789ABCDEF";
result += lookup[(b & CharT(0xF0)) >> 4];
result += lookup[b & CharT(0x0F)];
}
return result;
}
template <typename CharT>
template <info R>
consteval auto pretty_printer<CharT>::tprint() -> const CharT * {
return define_static_string(tprint_impl::template render<R>());
}
template <typename CharT>
template <info R> // Values of fundamental type.
requires(is_value(R) && type_is_fundamental(type_of(R)))
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
string_t result;
constexpr info Ty = dealias(type_of(R));
if constexpr (Ty == LIFT(nullptr_t))
result = string_constant("nullptr");
if constexpr (type_is_same(Ty, LIFT(bool))) {
if (extract<bool>(R))
result = string_constant("true");
else
result = string_constant("false");
}
else if constexpr (type_is_same(Ty, LIFT(char))) {
result = string_constant("'");
result.append(1, extract<char>(R));
result += string_constant("'");
}
else if constexpr (type_is_integral(Ty) &&
dealias(LIFT(CharT)) == LIFT(char)) {
CharT buffer[32] = {};
if (!to_chars(begin(buffer), end(buffer), [:R:]))
throw "'to_chars' failed to format integeral value";
result = buffer;
}
else if constexpr (type_is_floating_point(Ty)) {
result = render_value_as_hex<R>();
}
else {
result += string_constant("(value : ");
result += render<Ty>();
result += string_constant(")");
}
return result;
}
template <typename CharT>
template <info R> // Values of aggregate type.
requires(is_value(R) && type_is_aggregate(type_of(R)))
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
string_t result = render<type_of(R)>() + string_constant("{");
size_t Idx = 0;
[:expand(nonstatic_data_members_of(type_of(R))):] >> [&]<auto Mem> {
if (Idx++ > 0) result += string_constant(", ");
result += tprint_impl::render<reflect_value([:R:].[:Mem:])>();
};
result += string_constant("}");
return result;
}
template <typename CharT>
template <info R> // Values of pointer type.
requires (is_value(R) && type_is_pointer(type_of(R)))
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
return string_constant("(value : ") + render<type_of(R)>() +
string_constant(")");
}
template <typename CharT>
template <info R> // Objects.
requires (is_object(R))
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
string_t result = string_constant("(object : ");
result += render<type_of(R)>();
return result + string_constant(")");
}
template <typename CharT>
template <info R> // Templates.
requires(is_template(R))
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
if constexpr (is_constructor_template(R))
return render<parent_of(R)>();
else if (is_operator_function_template(R)) {
std::meta::operators op = operator_of(R);
string_t result = "operator";
switch (op) {
case std::meta::operators::op_new:
case std::meta::operators::op_delete:
case std::meta::operators::op_array_new:
case std::meta::operators::op_array_delete:
case std::meta::operators::op_co_await:
result += " ";
[[fallthrough]];
default:
return result + operator_symbol_helper(op);
}
} else if (is_conversion_function_template(R))
return string_constant("(conversion-function-template)");
else if (is_literal_operator_template(R))
return string_constant(R"(operator"")") + string_t {identifier_helper(R) };
return string_t {identifier_helper(R)};
}
template <typename CharT>
template <info R> // Namespaces.
requires(is_namespace(R))
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
if (R == LIFT(::))
return string_constant("(global-namespace)");
if (!has_identifier(R))
return string_constant("(anonymous-namespace)");
return string_t {identifier_helper(R)};
}
template <typename CharT>
template <info R> // Functions.
requires(is_function(R))
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
string_t result;
if constexpr (has_template_arguments(R)) {
return render<template_of(R)>() + render_template_argument_list_of<R>();
} else if constexpr (is_destructor(R)) {
constexpr info P = parent_of(R);
return string_constant("~") +
render<has_template_arguments(P) ? template_of(P) : P>();
} else if constexpr (is_constructor(R)) {
return render<parent_of(R)>();
} else if constexpr (is_operator_function(R)) {
std::meta::operators op = operator_of(R);
result = "operator";
switch (op) {
case std::meta::operators::op_new:
case std::meta::operators::op_delete:
case std::meta::operators::op_array_new:
case std::meta::operators::op_array_delete:
case std::meta::operators::op_co_await:
result += " ";
[[fallthrough]];
default:
return result + operator_symbol_helper(op);
}
} else if constexpr (is_conversion_function(R)) {
#if __has_feature(parameter_reflection)
return string_constant("operator ") + render<return_type_of(R)>();
#else
return string_constant("conversion-function");
#endif
} else if constexpr (is_literal_operator(R)) {
return string_constant(R"(operator"")") + string_t {identifier_helper(R) };
}
return string_t {identifier_helper(R)};
}
template <typename CharT>
template <info R> // Value types.
requires (is_type(R) && !(is_const(R) || is_volatile(R)) &&
!type_is_pointer(R) && !type_is_array(R) &&
!type_is_function(R) && !type_is_reference(R) &&
!type_is_member_pointer(R))
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
string_t result;
if constexpr (has_template_arguments(R)) {
return render<template_of(R)>() + render_template_argument_list_of<R>();
} else if constexpr (type_is_fundamental(R)) {
if (R == LIFT(void)) return string_constant("void");
if (R == LIFT(decltype(nullptr)) || R == LIFT(nullptr_t))
return string_constant("std::nullptr_t");
if (R == LIFT(info) || R == dealias(LIFT(info)))
return string_constant("std::meta::info");
if (R == LIFT(bool)) return string_constant("bool");
if (R == LIFT(signed char)) return string_constant("signed char");
if (R == LIFT(unsigned char)) return string_constant("unsigned char");
if (R == LIFT(char)) return string_constant("char");
if (R == LIFT(char8_t)) return string_constant("char8_t");
if (R == LIFT(char16_t)) return string_constant("char16_t");
if (R == LIFT(char32_t)) return string_constant("char32_t");
if (R == LIFT(float)) return string_constant("float");
if (R == LIFT(double)) return string_constant("double");
if (R == LIFT(long double)) return string_constant("long double");
if (type_is_unsigned(R)) result += string_constant("unsigned ");
if constexpr (!is_type_alias(R)) {
auto U = type_make_signed(R);
if (U == LIFT(short)) return result + string_constant("short");
if (U == LIFT(int)) return result + string_constant("int");
if (U == LIFT(long)) return result + string_constant("long");
if (U == LIFT(long long)) return result + string_constant("long long");
}
}
if (has_identifier(R)) {
return string_t {identifier_helper(R)};
} else {
return string_constant("(anonymous type)");
}
}
template <typename CharT>
template <info R> // CV-qualified non-function, non-array types.
requires (is_type(R) && (is_const(R) || is_volatile(R)) &&
!type_is_array(R) && !type_is_function(R))
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
string_t result;
if (is_const(R))
result += string_constant("const ");
if (is_volatile(R))
result += string_constant("volatile ");
return result + render<type_remove_cv(R)>();
}
template <typename CharT>
template <info R> // Reference types.
requires (is_type(R) && !(is_const(R) || is_volatile(R)) &&
type_is_reference(R))
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
string_t result = render<type_remove_reference(R)>() + string_constant(" &");
if (type_is_rvalue_reference(R))
result += string_constant("&");
return result;
}
template <typename CharT>
template <info R> // Array types.
requires (is_type(R) && type_is_array(R))
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
string_t result = render<type_remove_all_extents(R)>();
for (size_t k = 0; k < type_rank(R); ++k) {
CharT buffer[32] = {};
if (!to_chars(begin(buffer), end(buffer), type_extent(R, k)))
throw "'to_chars' failed to format integeral value";
result += "[" + string_t {buffer} + "]";
}
return result;
}
template <typename CharT>
template <info R> // Non-function, non-member pointer types.
requires (is_type(R) && type_is_pointer(R) &&
!(is_const(R) || is_volatile(R)) &&
!type_is_function(type_remove_pointer(R)))
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
return render<type_remove_pointer(R)>() + string_constant(" *");
}
template <typename CharT>
template <info R> // Function pointers.
requires (is_type(R) && type_is_pointer(R) &&
type_is_function(type_remove_pointer(R)))
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
#if __has_feature(parameter_reflection)
constexpr auto FnTy = type_remove_pointer(R);
string_t result = render<return_type_of(FnTy)>() + string_constant("(*)(");
size_t Idx = 0;
[:expand(parameters_of(FnTy)):] >> [&]<auto Param> {
if (Idx++ > 0) result += string_constant(", ");
result += tprint_impl::render<Param>();
};
result += string_constant(")");
if (is_noexcept(FnTy))
result += string_constant(" noexcept");
#else
string_t result = string_constant("(function-pointer-type)");
#endif
return result;
}
template <typename CharT>
template <info R> // Function types.
requires (is_type(R) && type_is_function(R))
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
#if __has_feature(parameter_reflection)
string_t result = render<return_type_of(R)>() + string_constant("(");
size_t Idx = 0;
[:expand(parameters_of(R)):] >> [&]<auto Param> {
if (Idx++ > 0) result += string_constant(", ");
result += tprint_impl::render<Param>();
};
result += string_constant(")");
if (is_const(R))
result += string_constant(" const");
if (is_volatile(R))
result += string_constant(" volatile");
if (is_lvalue_reference_qualified(R))
result += string_constant(" &");
else if (is_rvalue_reference_qualified(R))
result += string_constant(" &&");
if (is_noexcept(R))
result += string_constant(" noexcept");
#else
string_t result = string_constant("(function-type)");
#endif
return result;
}
template <typename CharT>
template <info R> // Pointer to data member types.
requires (is_type(R) && type_is_member_pointer(R) &&
!(is_const(R) || is_volatile(R)) &&
!type_is_member_function_pointer(R))
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
string_t result = render<type_of_member_from_memptr<R>()>() +
string_constant(" ");
result += render<type_of_object_from_memptr<R>()>() + string_constant("::*");
return result;
}
template <typename CharT>
template <info R> // Pointer to member function types.
requires (is_type(R) && type_is_member_function_pointer(R))
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
constexpr auto FnTy = type_of_member_from_memptr<R>();
#if __has_feature(parameter_reflection)
string_t result = render<return_type_of(FnTy)>() + string_constant("(");
result += render<type_of_object_from_memptr<R>()>() +
string_constant("::*)(");
size_t Idx = 0;
[:expand(parameters_of(FnTy)):] >> [&]<auto Param> {
if (Idx++ > 0) result += string_constant(", ");
result += tprint_impl::render<Param>();
};
result += string_constant(")");
if (is_const(FnTy))
result += string_constant(" const");
if (is_volatile(FnTy))
result += string_constant(" volatile");
if (is_lvalue_reference_qualified(FnTy))
result += string_constant(" &");
else if (is_rvalue_reference_qualified(FnTy))
result += string_constant(" &&");
if (is_noexcept(FnTy))
result += string_constant(" noexcept");
#else
string_t result = string_constant("(member-function-pointer-type)");
#endif
return result;
}
template <typename CharT>
template <info R> // Base specifiers.
requires (is_base(R))
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
return string_t {render<type_of(R)>()};
}
template <typename CharT>
template <info R> // Fallback.
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
return string_constant("(unsupported-reflection)");
}
template <typename CharT>
template <info R> // Variables, data members, enumerators.
requires (is_variable(R) || is_nonstatic_data_member(R) || is_enumerator(R))
consteval auto pretty_printer<CharT>::tprint_impl::render() -> string_t {
return string_t {identifier_helper(R)};
}
} // namespace detail
consteval auto display_string_of(info R) -> const char* {
return detail::pretty_printer<char>::print(R);
}
consteval auto u8display_string_of(info R) -> const char8_t* {
return detail::pretty_printer<char8_t>::print(R);
}
_LIBCPP_END_NAMESPACE_REFLECTION_V2
#endif // __has_feature(reflection)
#endif // _LIBCPP_EXPERIMENTAL_META
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment