diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 90d578384067..7297b4a53a74 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -1029,6 +1029,7 @@ set(files mdspan memory memory_resource + meta mutex new numbers diff --git a/libcxx/include/experimental/meta b/libcxx/include/experimental/meta index 4ec4393c9e35..895dbb246e87 100644 --- a/libcxx/include/experimental/meta +++ b/libcxx/include/experimental/meta @@ -1,7 +1,7 @@ // -*- C++ -*- //===----------------------------------------------------------------------===// // -// Copyright 2024 Bloomberg Finance L.P. +// Copyright 2025 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. @@ -12,2993 +12,6 @@ #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 -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 constant_of(info) -> info; - -// template queries -consteval auto template_of(info r) -> info; -consteval auto template_arguments_of(info r) -> vector; - -// member queries -consteval auto members_of(info class_type, access_context ctx) -> vector; -consteval auto bases_of(info class_type, access_context ctx) -> vector; -consteval auto static_data_members_of(info class_type, - access_context ctx) -> vector; -consteval auto nonstatic_data_members_of(info class_type, - access_context ctx) -> vector; -consteval auto enumerators_of(info enum_type) -> vector; - -// substitute -template > - consteval auto can_substitute(info templ, R &&args) -> bool; -template > - consteval auto substitute(info templ, R &&args) -> info; - -// reflect expression results -template - consteval auto reflect_constant(const T&) -> info; -template - consteval auto reflect_object(T &) -> info; -template - consteval auto reflect_function(T &) -> info; - -// extract -template - 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_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 is_enumerable_type(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_aggregate -struct data_member_options; -consteval auto data_member_spec(info class_type, - data_member_options = {}) -> info; -template > - consteval auto define_aggregate(info class_type, R &&members) -> info; - -// data layout -struct member_offset { - ptrdiff_t bytes; - ptrdiff_t bits; - - constexpr size_t total_bits() const; - auto operator<=>(member_offset const&) const = default; -}; -consteval auto offset_of(info) -> member_offset; -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 is_void_type(info) -> bool; -consteval auto is_null_pointer_type(info) -> bool; -consteval auto is_integral_type(info) -> bool; -consteval auto is_floating_point_type(info) -> bool; -consteval auto is_array_type(info) -> bool; -consteval auto is_pointer_type(info) -> bool; -consteval auto is_lvalue_reference_type(info) -> bool; -consteval auto is_rvalue_reference_type(info) -> bool; -consteval auto is_member_object_pointer_type(info) -> bool; -consteval auto is_member_function_pointer_type(info) -> bool; -consteval auto is_enum_type(info) -> bool; -consteval auto is_union_type(info) -> bool; -consteval auto is_class_type(info) -> bool; -consteval auto is_function_type(info) -> bool; -consetval auto is_reflection_type(info) -> bool; - -// composite type categories -consteval auto is_reference_type(info) -> bool; -consteval auto is_arithmetic_type(info) -> bool; -consteval auto is_fundamental_type(info) -> bool; -consteval auto is_object_type(info) -> bool; -consteval auto is_scalar_type(info) -> bool; -consteval auto is_compound_type(info) -> bool; -consteval auto is_member_pointer_type(info) -> bool; - -// type properties -consteval auto is_const_type(info) -> bool; -consteval auto is_volatile_type(info) -> bool; -consteval auto is_trivial_type(info) -> bool; -consteval auto is_trivially_copyable_type(info) -> bool; -consteval auto is_standard_layout_type(info) -> bool; -consteval auto is_empty_type(info) -> bool; -consteval auto is_polymorphic_type(info) -> bool; -consteval auto is_abstract_type(info) -> bool; -consteval auto is_final_type(info) -> bool; -consteval auto is_aggregate_type(info) -> bool; -consteval auto is_consteval_only_type(info) -> bool; -consteval auto is_signed_type(info) -> bool; -consteval auto is_unsigned_type(info) -> bool; -consteval auto is_bounded_array_type(info) -> bool; -consteval auto is_unbounded_array_type(info) -> bool; -consteval auto is_scoped_enum_type(info) -> bool; - -template > - consteval auto is_constructible_type(info, R &&args) -> bool; -consteval auto is_default_constructible_type(info) -> bool; -consteval auto is_copy_constructible_type(info) -> bool; -consteval auto is_move_constructible_type(info) -> bool; - -consteval auto is_assignable_type(info dst, info src) -> bool; -consteval auto is_copy_assignable_type(info) -> bool; -consteval auto is_move_assignable_type(info) -> bool; - -consteval auto is_swappable_with_type(info dst, info src) -> bool; -consteval auto is_swappable_type(info) -> bool; - -consteval auto is_destructible_type(info) -> bool; - -template > - consteval auto type_is_trivially_constructible(info, R &&args) -> bool; -consteval auto is_trivially_default_constructible_type(info) -> bool; -consteval auto is_trivially_copy_constructible_type(info) -> bool; -consteval auto is_trivially_move_constructible_type(info) -> bool; - -consteval auto is_trivially_assignable_type(info dst, info src) -> bool; -consteval auto is_trivially_copy_assignable_type(info) -> bool; -consteval auto is_trivially_move_assignable_type(info) -> bool; -consteval auto is_trivially_destructible_type(info) -> bool; - -template > - consteval auto is_nothrow_constructible_type(info, R &&args) -> bool; -consteval auto is_nothrow_default_constructible_type(info) -> bool; -consteval auto is_nothrow_copy_constructible_type(info) -> bool; -consteval auto is_nothrow_move_constructible_type(info) -> bool; - -consteval auto is_nothrow_assignable_type(info dst, info src) -> bool; -consteval auto is_nothrow_copy_assignable_type(info) -> bool; -consteval auto is_nothrow_move_assignable_type(info) -> bool; - -consteval auto is_nothrow_swappable_with_type(info dst, info src) -> bool; -consteval auto is_nothrow_swappable_type(info) -> bool; - -consteval auto is_nothrow_destructible_type(info) -> bool; - -consteval auto is_implicit_lifetime_type(info) -> bool; - -consteval auto has_virtual_destructor(info) -> bool; - -consteval auto has_unique_object_representations(info) -> bool; - -consteval auto reference_constructs_from_temporary(info) -> bool; -consteval auto reference_converts_from_temporary(info) -> bool; - -// type property queries -consteval auto rank(info) -> size_t; -consteval auto extent(info type, unsigned i) -> size_t; - -// type relations -consteval auto is_same_type(info, info) -> bool; -consteval auto is_base_of_type(info, info) -> bool; -consteval auto is_convertible_type(info, info) -> bool; -consteval auto is_nothrow_convertible_type(info, info) -> bool; -consteval auto is_layout_compatible_type(info, info) -> bool; -consteval auto is_pointer_interconvertible_base_of_type(info, info) -> bool; - -template > - consteval auto is_invocable_type(info type, R &&args) -> bool; -template > - consteval auto is_invocable_r_type(info result, info type, - R &&args) -> bool; - -template > - consteval auto is_nothrow_invocable_type(info type, R &&args) -> bool; -template > - consteval auto is_nothrow_invocable_r_type(info result, info type, - R &&args) -> bool; - -// const volatile modifications -consteval auto remove_const(info) -> info; -consteval auto remove_volatile(info) -> info; -consteval auto remove_cv(info) -> info; -consteval auto add_const(info) -> info; -consteval auto add_volatile(info) -> info; -consteval auto add_cv(info) -> info; - -// reference modifications -consteval auto remove_reference(info) -> info; -consteval auto add_lvalue_reference(info) -> info; -consteval auto add_rvalue_reference(info) -> info; - -// sign modifications -consteval auto make_signed(info) -> info; -consteval auto make_unsigned(info) -> info; - -// array modifications -consteval auto remove_extent(info) -> info; -consteval auto remove_all_extents(info) -> info; - -// pointer modifications -consteval auto remove_pointer(info) -> info; -consteval auto add_pointer(info) -> info; - -// other transformations -consteval auto remove_cvref(info) -> info; -consteval auto decay(info) -> info; -template > - consteval auto common_type(R &&args) -> info; -template > - consteval auto common_reference(R &&args) -> info; -consteval auto underlying_type(info) -> info; -template > - consteval auto invoke_result(info type, R &&args) -> info; -consteval auto unwrap_reference(info) -> info; -consteval auto unwrap_ref_decay(info) -> info; - -// tuple and variant queries -consteval auto tuple_size(info) -> size_t; -consteval auto tuple_element(size_t, info) -> info; - -consteval auto variant_size(info) -> size_t; -consteval auto variant_alternative(size_t, info) -> info; - -// entity proxies (PXYZ) -consteval auto is_entity_proxy(info) -> bool; - -// function parameters (P3096) -consteval auto parameters_of(info) -> vector; -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; -consteval auto variable_of(info) -> info; - -// annotations (P3394) -consteval auto annotations_of(info) -> vector; -consteval auto annotations_of(info, info) -> vector; -template - consteval auto annotation_of_type(info) -> optional; -consteval auto is_annotation(info) -> bool; -consteval auto annotate(info) -> info; - -// modeling access control (P3547) -struct access_context { - access_context() = delete; - - consteval auto scope() const -> info; - consteval auto designating_class() const -> info; - - static consteval auto current() noexcept -> access_context; - static consteval auto unprivileged() noexcept -> access_context; - static consteval auto unchecked() noexcept -> access_context; - - consteval auto via(info) const -> access_context; -}; - -consteval auto is_accessible(info r, access_context ctx) -> bool; -consteval auto has_inaccessible_nonstatic_data_members( - info r, - access_context cls) -> vector; -consteval auto has_inaccessible_bases( - info r, - access_context cls) -> vector; - -// other bespoke functions (not proposed at this time) -consteval auto is_access_specified(info) -> bool; - -template > - consteval auto reflect_invoke(info target, R &&args) -> info; -template , - reflection_range R2 = initializer_list> - consteval auto reflect_invoke(info target, - R1 &&tmpl_args, R2 &&args) -> info; - - -} // namespace reflection_v2 -} // namespace meta -} // namespace std - - */ - -#include <__config> -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if __has_feature(reflection) - -_LIBCPP_BEGIN_NAMESPACE_REFLECTION_V2 - -// An opaque handle to a reflected entity. -using info = decltype(^^int); - -template -concept reflection_range = - ranges::input_range && - same_as, info> && - same_as>, 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, - - // P2996 metafunctions - __metafn_identifier_of, - __metafn_has_identifier, - __metafn_operator_of, - __metafn_source_location_of, - __metafn_type_of, - __metafn_parent_of, - __metafn_underlying_entity_of, - __metafn_proxied_entity_of, - __metafn_object_of, - __metafn_constant_of, - __metafn_template_of, - __metafn_substitute, - __metafn_extract, - __metafn_is_public, - __metafn_is_protected, - __metafn_is_private, - __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_entity_proxy, - __metafn_is_complete_type, - __metafn_has_complete_definition, - __metafn_is_enumerable_type, - __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_data_member_spec, - __metafn_define_aggregate, - __metafn_offset_of, - __metafn_size_of, - __metafn_bit_offset_of, - __metafn_bit_size_of, - __metafn_alignment_of, - - // P3096 parameter reflection metafunctions - __metafn_get_ith_parameter_of, - __metafn_has_ellipsis_parameter, - __metafn_has_default_argument, - __metafn_is_explicit_object_parameter, - __metafn_is_function_parameter, - __metafn_return_type_of, - __metafn_variable_of, - - // P3394 annotation metafunctions - __metafn_get_ith_annotation_of, - __metafn_is_annotation, - __metafn_annotate, - - // P3493 accessibility metafunctions - __metafn_access_context, - __metafn_is_accessible, - - // Other bespoke functions (not proposed at this time) - __metafn_is_access_specified, - __metafn_reflect_invoke, -}; - -consteval auto __workaround_expand_compiler_builtins(info type) -> info; - -consteval auto __underlying_entity_of(info r) -> info { - return __metafunction(detail::__metafn_underlying_entity_of, r); -} - -} // namespace detail - -namespace __range_of_infos { - -struct sentinel {}; - -template -class iterator { - static constexpr Front m_front = { }; - static constexpr Next m_next = { }; - - // The reflected entity passed to the underlying range - info m_reflectedEntity{^^sentinel}; - // The current meta::info within the range: e.g. if we are - // doing template_arguments_of(^^vector) - // m_currInfoItr can be either ^^int, ^^double and ^^string - info m_currInfoItr{^^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{^^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 -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 -consteval ptrdiff_t distance(iterator first, - iterator 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, - ^^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, ^^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, ^^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, ^^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, ^^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, ^^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, ^^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, ^^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, ^^sentinel, idx); - } -}; - -struct front_parameter_of_fn { - consteval info operator()(info reflectedEntity) const { - return __metafunction(detail::__metafn_get_ith_parameter_of, - reflectedEntity, ^^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, ^^sentinel, idx); - } -}; - -struct front_annotation_of { - consteval info operator()(info reflectedEntity) const { - return __metafunction(detail::__metafn_get_ith_annotation_of, - reflectedEntity, ^^sentinel, 0); - } -}; - -} // namespace __range_of_infos - -// ----------------------------------------------------------------------------- -// Metafunctions -// ----------------------------------------------------------------------------- - -// Returns a reflection of the canonical type for the reflected type. -#if __has_feature(entity_proxy_reflection) -[[deprecated("renamed to 'underlying_entity_of' in PXYZ")]] -#endif -consteval auto dealias(info r) -> info { - return __metafunction(detail::__metafn_underlying_entity_of, r); -} - -#if __has_feature(entity_proxy_reflection) -consteval auto underlying_entity_of(info r) -> info { - return __metafunction(detail::__metafn_underlying_entity_of, r); -} - -consteval auto proxied_entity_of(info r) -> info { - return __metafunction(detail::__metafn_proxied_entity_of, r); -} -#endif - -// 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) -> string_view { - return __metafunction(detail::__metafn_identifier_of, ^^const char *, r, - /*UTF8=*/false, /*EnforceConsistent=*/true); -} - -consteval auto u8identifier_of(info r) -> u8string_view { - return __metafunction(detail::__metafn_identifier_of, ^^const char8_t *, - r, /*UTF8=*/true, /*EnforceConsistent=*/true); -} - -// Returns an implementation-defined name for the reflected entity. -consteval auto display_string_of(info r) -> string_view; -consteval auto u8display_string_of(info r) -> u8string_view; - -// 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_exclamation, 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_exclamation_equals, - op_less, op_greater, op_less_equals, op_greater_equals, op_spaceship, - 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, -}; -using enum operators; - -// 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 symbol_of(operators op) -> string_view { - static constexpr string_view op_names[45] = { - {}, "new", "delete", "new[]", "delete[]", "coawait", "()", "[]", "->", - "->*", "~", "!", "+", "-", "*", "/", "%", "^", "&", "|", "=", "+=", "-=", - "*=", "/=", "%=", "^", "&=", "|=", "==", "!=", "<", ">", "<=", ">=", - "<=>", "&&", "||", "<<", ">>", "<<=", ">>=", "++", "--", "," - }; - return op_names[int(op)]; -} - -consteval auto u8symbol_of(operators op) -> u8string_view { - static constexpr u8string_view 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 constant_of(info r) -> info { - return __metafunction(detail::__metafn_constant_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) -> vector { - 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; - auto rng = range{r}; - return vector{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); -} - -// Returns whether 'templ' substituted with 'args' forms a valid template-id. -template > -consteval auto can_substitute(info templ, R &&args) -> bool { - info sub; - if constexpr (ranges::contiguous_range) { - sub = __metafunction(detail::__metafn_substitute, templ, - ranges::data(args), ranges::size(args), false); - } else { - vector vargs = args | ranges::to(); - sub = __metafunction(detail::__metafn_substitute, templ, - vargs.data(), vargs.size(), false); - } - return sub != info{}; -} - -// Returns a reflection representing the template instantiation of the entity -// reflected by 'templ' with the entities reflected by 'args'. -template > -consteval auto substitute(info templ, R &&args) -> info { - if constexpr (ranges::contiguous_range) { - return __metafunction(detail::__metafn_substitute, templ, - ranges::data(args), ranges::size(args), true); - } else { - vector vargs = args | ranges::to(); - return __metafunction(detail::__metafn_substitute, templ, vargs.data(), - vargs.size(), true); - } -} - -// Returns the value or object from 'r' if 'r' is a reflection of a value -// or object having type 'T'. -template requires (!is_rvalue_reference_v) -consteval auto extract(info r) -> Ty { - return __metafunction(detail::__metafn_extract, ^^Ty, r); -} - -consteval auto is_class_type(info r) -> bool { - return extract(substitute(^^is_class_v, {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 whether the reflected class data member is an enumerator. -consteval auto is_enumerator(info r) -> bool { - return __metafunction(detail::__metafn_is_enumerator, r); -} - -class access_context { - consteval access_context(info scope, info designating_class) noexcept - : d_scope{scope}, d_designating_class{designating_class} { } - -public: - const info d_scope; - const info d_designating_class; - - consteval access_context() = delete; - - consteval access_context(const access_context &) noexcept = default; - consteval access_context(access_context &&) noexcept = default; - - consteval info scope() const { return d_scope; } - consteval info designating_class() const { return d_designating_class; } - - [[clang::instantiation_dependent]] - static consteval access_context current() noexcept { - return {__metafunction(detail::__metafn_access_context), {}}; - } - - static consteval access_context unprivileged() noexcept { - return access_context{^^::, info{}}; - } - - static consteval access_context unchecked() noexcept { - return access_context{info{}, info{}}; - } - - consteval access_context via(info new_designating_class) const { - if (!is_class_type(new_designating_class)) - throw "designating class must be a reflection of a class type"; - - return access_context{d_scope, new_designating_class}; - } -}; - -consteval auto is_accessible(info r, access_context ctx) -> bool { - // Note: The accessibility of an enumerator may be looked up in a class - // for which it's not a member, since that enumerator could be - if (!is_class_member(r) && !is_base(r) && !is_enumerator(r)) - return true; - - return __metafunction(detail::__metafn_is_accessible, - r, ctx.scope(), ctx.designating_class()); -} - -consteval auto members_of(info r, access_context ctx) -> vector { - 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; - auto rng = range{r}; - - vector v {rng.begin(), rng.end()}; - return vector{ - from_range, - v | views::filter([=](info r) { return is_accessible(r, ctx); }) - }; -} - -// 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, access_context ctx) -> vector { - 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; - auto rng = range{r}; - - vector v {rng.begin(), rng.end()}; - return vector{ - from_range, - v | views::filter([=](info r) { return is_accessible(r, ctx); }) - }; -} - -// 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, - access_context ctx) -> vector { - if (is_namespace(r)) - throw "Namespaces cannot have static data members"; - - return members_of(r, ctx) | - views::filter(is_variable) | - ranges::to(); -} - -consteval auto nonstatic_data_members_of(info r, - access_context ctx) -> vector { - if (is_namespace(r)) - throw "Namespaces cannot have non-static data members"; - - return members_of(r, ctx) | - views::filter(is_nonstatic_data_member) | - ranges::to(); -} - -// Returns true if the reflected entity is an enumerable type. -consteval auto is_enumerable_type(info r) -> bool { - return __metafunction(detail::__metafn_is_enumerable_type, r); -} - -consteval auto enumerators_of(info r) -> vector { - if (!is_enumerable_type(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; - auto rng = range{r}; - return vector{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); -} - -// 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 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 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 a type 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 a namespace alias. -consteval auto is_namespace_alias(info r) -> bool { - return is_namespace(r) && __metafunction(detail::__metafn_is_alias, r); -} - -#if __has_feature(entity_proxy_reflection) -// Returns true if the reflected entity is an entity proxy. -consteval auto is_entity_proxy(info r) -> bool { - return __metafunction(detail::__metafn_is_entity_proxy, r); -} -#endif - -// 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 - requires (!is_reference_v && - __metafunction(detail::__metafn_is_structural_type, ^^T)) -consteval auto reflect_constant(T r) -> info { - return __metafunction(detail::__metafn_reflect_result, ^^T, r); -} - -// Returns a reflection of the object designated by the provided argument. -template requires (!is_function_v>) -consteval auto reflect_object(T &r) -> info { - return __metafunction(detail::__metafn_reflect_result, type_of(^^r), r); -} - -// Returns a reflection of the object designated by the provided argument. -template requires (is_function_v>) -consteval auto reflect_function(T &r) -> info { - return __metafunction(detail::__metafn_reflect_result, type_of(^^r), r); -} - -// Representation of a data member which may be passed to 'data_member_spec'. -struct data_member_options { - struct name_type { - variant impl; - - template requires constructible_from - consteval name_type(T &&in) : impl(in_place_type, in) {} - - template requires constructible_from - consteval name_type(T &&in) : impl(in_place_type, in) {} - - private: -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-private-field" - info unused = ^^::; -#pragma clang diagnostic pop - }; - - optional name = nullopt; - optional alignment = nullopt; - optional 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_aggregate' to define a record type. -consteval auto data_member_spec(info member_type, - data_member_options 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(substitute(^^is_integral_v, {member_type})) && - !extract(substitute(^^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(name)) { - const u8string &s = get(name); - validate(s); - return __metafunction(detail::__metafn_data_member_spec, - member_type, - !s.empty(), s.size(), ^^const char8_t, s.data(), - options.alignment.has_value(), alignment, - options.width.has_value(), width, - no_unique_address); - } else { - const string &s = get(name); - validate(s); - return __metafunction(detail::__metafn_data_member_spec, - member_type, - !s.empty(), s.size(), ^^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 > -consteval auto define_aggregate(info class_type, R &&members) -> info { - if constexpr (ranges::contiguous_range) { - return __metafunction(detail::__metafn_define_aggregate, class_type, - ranges::size(members), ranges::data(members)); - } else { - vector vmembers = members | ranges::to(); - return __metafunction(detail::__metafn_define_aggregate, class_type, - vmembers.size(), vmembers.data()); - } -} - -struct member_offset { - ptrdiff_t bytes; - ptrdiff_t bits; - - constexpr auto total_bits() -> ptrdiff_t { - return bytes * CHAR_BIT + bits; - } - - auto operator<=>(member_offset const&) const = default; -}; - -// Returns the offset of the reflected entity. -consteval auto offset_of(info r) -> member_offset { - return member_offset { - __metafunction(detail::__metafn_offset_of, ^^ptrdiff_t, r), - __metafunction(detail::__metafn_bit_offset_of, ^^ptrdiff_t, 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); -} - -// Type trait wrappers - -consteval auto is_void_type(info r) -> bool { - return extract(substitute(^^is_void_v, {r})); -} - -consteval auto is_null_pointer_type(info r) -> bool { - return extract(substitute(^^is_null_pointer_v, {r})); -} - -consteval auto is_integral_type(info r) -> bool { - return extract(substitute(^^is_integral_v, {r})); -} - -consteval auto is_floating_point_type(info r) -> bool { - return extract(substitute(^^is_floating_point_v, {r})); -} - -consteval auto is_array_type(info r) -> bool { - return extract(substitute(^^is_array_v, {r})); -} - -consteval auto is_pointer_type(info r) -> bool { - return extract(substitute(^^is_pointer_v, {r})); -} - -consteval auto is_lvalue_reference_type(info r) -> bool { - return extract(substitute(^^is_lvalue_reference_v, {r})); -} - -consteval auto is_rvalue_reference_type(info r) -> bool { - return extract(substitute(^^is_rvalue_reference_v, {r})); -} - -consteval auto is_member_object_pointer_type(info r) -> bool { - return extract(substitute(^^is_member_object_pointer_v, {r})); -} - -consteval auto is_member_function_pointer_type(info r) -> bool { - return extract(substitute(^^is_member_function_pointer_v, {r})); -} - -consteval auto is_enum_type(info r) -> bool { - return extract(substitute(^^is_enum_v, {r})); -} - -consteval auto is_union_type(info r) -> bool { - return extract(substitute(^^is_union_v, {r})); -} - -consteval auto is_function_type(info r) -> bool { - return extract(substitute(^^is_function_v, {r})); -} - -consteval auto is_reflection_type(info r) -> bool { - return r == ^^info; -} - -consteval auto is_reference_type(info r) -> bool { - return extract(substitute(^^is_reference_v, {r})); -} - -consteval auto is_arithmetic_type(info r) -> bool { - return extract(substitute(^^is_arithmetic_v, {r})); -} - -consteval auto is_fundamental_type(info r) -> bool { - return extract(substitute(^^is_fundamental_v, {r})); -} - -consteval auto is_object_type(info r) -> bool { - return extract(substitute(^^is_object_v, {r})); -} - -consteval auto is_scalar_type(info r) -> bool { - return extract(substitute(^^is_scalar_v, {r})); -} - -consteval auto is_compound_type(info r) -> bool { - return extract(substitute(^^is_compound_v, {r})); -} - -consteval auto is_member_pointer_type(info r) -> bool { - return extract(substitute(^^is_member_pointer_v, {r})); -} - -consteval auto is_const_type(info r) -> bool { - return extract(substitute(^^is_const_v, {r})); -} - -consteval auto is_volatile_type(info r) -> bool { - return extract(substitute(^^is_volatile_v, {r})); -} - -consteval auto is_trivial_type(info r) -> bool { - return extract(substitute(^^is_trivial_v, {r})); -} - -consteval auto is_trivially_copyable_type(info r) -> bool { - return extract(substitute(^^is_trivially_copyable_v, {r})); -} - -consteval auto is_standard_layout_type(info r) -> bool { - return extract(substitute(^^is_standard_layout_v, {r})); -} - -consteval auto is_empty_type(info r) -> bool { - return extract(substitute(^^is_empty_v, {r})); -} - -consteval auto is_polymorphic_type(info r) -> bool { - return extract(substitute(^^is_polymorphic_v, {r})); -} - -consteval auto is_abstract_type(info r) -> bool { - return extract(substitute(^^is_abstract_v, {r})); -} - -consteval auto is_final_type(info r) -> bool { - return extract(substitute(^^is_final_v, {r})); -} - -consteval auto is_aggregate_type(info r) -> bool { - return extract(substitute(^^is_aggregate_v, {r})); -} - -consteval auto is_consteval_only_type(info r) -> bool { - return extract(substitute(^^is_consteval_only_v, {r})); -} - -consteval auto is_signed_type(info r) -> bool { - return extract(substitute(^^is_signed_v, {r})); -} - -consteval auto is_unsigned_type(info r) -> bool { - return extract(substitute(^^is_unsigned_v, {r})); -} - -consteval auto is_bounded_array_type(info r) -> bool { - return extract(substitute(^^is_bounded_array_v, {r})); -} - -consteval auto is_unbounded_array_type(info r) -> bool { - return extract(substitute(^^is_unbounded_array_v, {r})); -} - -consteval auto is_scoped_enum_type(info r) -> bool { - return extract(substitute(^^is_scoped_enum_v, {r})); -} - -template > -consteval auto is_constructible_type(info type, R &&type_args) { - vector args(from_range, type_args); - args.insert(args.begin(), type); - - return extract(substitute(^^is_constructible_v, args)); -} - -consteval auto is_default_constructible_type(info r) -> bool { - return extract(substitute(^^is_default_constructible_v, {r})); -} - -consteval auto is_copy_constructible_type(info r) -> bool { - return extract(substitute(^^is_copy_constructible_v, {r})); -} - -consteval auto is_move_constructible_type(info r) -> bool { - return extract(substitute(^^is_move_constructible_v, {r})); -} - -consteval auto is_assignable_type(info dst, info src) -> bool { - return extract(substitute(^^is_assignable_v, {dst, src})); -} - -consteval auto is_copy_assignable_type(info r) -> bool { - return extract(substitute(^^is_copy_assignable_v, {r})); -} - -consteval auto is_move_assignable_type(info r) -> bool { - return extract(substitute(^^is_move_assignable_v, {r})); -} - -consteval auto is_swappable_with_type(info dst, info src) -> bool { - return extract(substitute(^^is_swappable_with_v, {dst, src})); -} - -consteval auto is_swappable_type(info r) -> bool { - return extract(substitute(^^is_swappable_v, {r})); -} - -consteval auto is_destructible_type(info r) -> bool { - return extract(substitute(^^is_destructible_v, {r})); -} - -template > -consteval auto is_trivially_constructible_type(info type, R &&type_args) { - vector args(from_range, type_args); - args.insert(args.begin(), type); - - return extract(substitute(^^is_trivially_constructible_v, args)); -} - -consteval auto is_trivially_default_constructible_type(info r) -> bool { - return extract(substitute(^^is_trivially_default_constructible_v, - {r})); -} - -consteval auto is_trivially_copy_constructible_type(info r) -> bool { - return extract(substitute(^^is_trivially_copy_constructible_v, - {r})); -} - -consteval auto is_trivially_move_constructible_type(info r) -> bool { - return extract(substitute(^^is_trivially_move_constructible_v, - {r})); -} - -consteval auto is_trivially_assignable_type(info dst, info src) -> bool { - return extract(substitute(^^is_trivially_assignable_v, {dst, src})); -} - -consteval auto is_trivially_copy_assignable_type(info r) -> bool { - return extract(substitute(^^is_trivially_copy_assignable_v, {r})); -} - -consteval auto is_trivially_move_assignable_type(info r) -> bool { - return extract(substitute(^^is_trivially_move_assignable_v, {r})); -} - -consteval auto is_trivially_destructible_type(info r) -> bool { - return extract(substitute(^^is_trivially_destructible_v, {r})); -} - -template > -consteval auto is_nothrow_constructible_type(info type, R &&type_args) { - vector args(from_range, type_args); - args.insert(args.begin(), type); - - return extract(substitute(^^is_nothrow_constructible_v, args)); -} - -consteval auto is_nothrow_default_constructible_type(info r) -> bool { - return extract(substitute(^^is_nothrow_default_constructible_v, {r})); -} - -consteval auto is_nothrow_copy_constructible_type(info r) -> bool { - return extract(substitute(^^is_nothrow_copy_constructible_v, {r})); -} - -consteval auto is_nothrow_move_constructible_type(info r) -> bool { - return extract(substitute(^^is_nothrow_move_constructible_v, {r})); -} - -consteval auto is_nothrow_assignable_type(info dst, info src) -> bool { - return extract(substitute(^^is_nothrow_assignable_v, {dst, src})); -} - -consteval auto is_nothrow_copy_assignable_type(info r) -> bool { - return extract(substitute(^^is_nothrow_copy_assignable_v, {r})); -} - -consteval auto is_nothrow_move_assignable_type(info r) -> bool { - return extract(substitute(^^is_nothrow_move_assignable_v, {r})); -} - -consteval auto is_nothrow_swappable_with_type(info dst, info src) -> bool { - return extract(substitute(^^is_nothrow_swappable_with_v, {dst, src})); -} - -consteval auto is_nothrow_swappable_type(info r) -> bool { - return extract(substitute(^^is_nothrow_swappable_v, {r})); -} - -consteval auto is_nothrow_destructible_type(info r) -> bool { - return extract(substitute(^^is_nothrow_destructible_v, {r})); -} - -// TODO(P2996): Not yet implemented in libc++. -/*consteval auto is_implicit_lifetime_type(info r) -> bool { - return extract(substitute(^^is_implicit_lifetime_v, {r})); -}*/ - -consteval auto has_virtual_destructor(info r) -> bool { - return extract(substitute(^^has_virtual_destructor_v, {r})); -} - -consteval auto has_unique_object_representations(info r) -> bool { - return extract(substitute(^^has_unique_object_representations_v, {r})); -} - -// TODO(P2996): Not yet implemented in libc++. -/*consteval auto reference_constructs_from_temporary(info r) -> bool { - return extract(substitute(^^reference_constructs_from_temporary_v, - {r})); -}*/ - -// TODO({2996): Not yet implemented in libc++. -/*consteval auto reference_converts_from_temporary(info r) -> bool { - return extract(substitute(^^reference_converts_from_temporary_v, {r})); -}*/ - -consteval auto rank(info r) -> size_t { - return extract(substitute(^^rank_v, {r})); -} - -consteval auto extent(info r, unsigned i = 0) -> size_t { - return extract(substitute(^^extent_v, {r, reflect_constant(i)})); -} - -consteval auto is_same_type(info r, info s) -> bool { - return extract(substitute(^^is_same_v, {r, s})); -} - -consteval auto is_base_of_type(info r, info s) -> bool { - return extract(substitute(^^is_base_of_v, {r, s})); -} - -consteval auto is_convertible_type(info r, info s) -> bool { - return extract(substitute(^^is_convertible_v, {r, s})); -} - -consteval auto is_nothrow_convertible_type(info r, info s) -> bool { - return extract(substitute(^^is_nothrow_convertible_v, {r, s})); -} - -// TODO(P2996): Not yet implemented in libc++. -/*consteval auto is_layout_compatible_type(info r, info s) -> bool { - return extract(substitute(^^is_layout_compatible_v, {r, s})); -}*/ - -// TODO(P2996): Not yet implemented in libc++. -/*consteval auto is_pointer_interconvertible_base_of_type(info r, - info s) -> bool { - return extract(substitute(^^is_pointer_interconvertible_base_of_v, - {r, s})); -}*/ - -template > -consteval auto is_invocable_type(info type, R &&args) { - vector targs(from_range, args); - targs.insert(targs.begin(), type); - - return extract(substitute(^^is_invocable_v, targs)); -} - -template > -consteval auto is_invocable_r_type(info result, info type, R &&args) { - vector targs(from_range, args); - targs.insert(targs.begin(), type); - targs.insert(targs.begin(), result); - - return extract(substitute(^^is_invocable_r_v, targs)); -} - -template > -consteval auto is_nothrow_invocable_type(info type, R &&args) { - vector targs(from_range, args); - targs.insert(targs.begin(), type); - - return extract(substitute(^^is_nothrow_invocable_v, targs)); -} - -template > -consteval auto is_nothrow_invocable_r_type(info result, info type, - R &&args) { - vector targs(from_range, args); - targs.insert(targs.begin(), type); - targs.insert(targs.begin(), result); - - return extract(substitute(^^is_nothrow_invocable_r_v, targs)); -} - -consteval auto remove_const(info type) -> info { - return detail::__workaround_expand_compiler_builtins( - detail::__underlying_entity_of(substitute(^^remove_const_t, {type}))); -} - -consteval auto remove_volatile(info type) -> info { - return detail::__workaround_expand_compiler_builtins( - detail::__underlying_entity_of(substitute(^^remove_volatile_t, {type}))); -} - -consteval auto remove_cv(info type) -> info { - return detail::__workaround_expand_compiler_builtins( - detail::__underlying_entity_of(substitute(^^remove_cv_t, {type}))); -} - -consteval auto add_const(info type) -> info { - return detail::__underlying_entity_of(substitute(^^add_const_t, {type})); -} - -consteval auto add_volatile(info type) -> info { - return detail::__underlying_entity_of(substitute(^^add_volatile_t, {type})); -} - -consteval auto add_cv(info type) -> info { - return detail::__underlying_entity_of(substitute(^^add_cv_t, {type})); -} - -consteval auto remove_reference(info type) -> info { - return detail::__workaround_expand_compiler_builtins( - detail::__underlying_entity_of(substitute(^^remove_reference_t, {type}))); -} - -consteval auto add_lvalue_reference(info type) -> info { - return detail::__workaround_expand_compiler_builtins( - detail::__underlying_entity_of(substitute(^^add_lvalue_reference_t, - {type}))); -} - -consteval auto add_rvalue_reference(info type) -> info { - return detail::__workaround_expand_compiler_builtins( - detail::__underlying_entity_of(substitute(^^add_rvalue_reference_t, - {type}))); -} - -consteval auto make_signed(info type) -> info { - return detail::__workaround_expand_compiler_builtins( - detail::__underlying_entity_of(substitute(^^make_signed_t, {type}))); -} - -consteval auto make_unsigned(info type) -> info { - return detail::__workaround_expand_compiler_builtins( - detail::__underlying_entity_of(substitute(^^make_unsigned_t, {type}))); -} - -consteval auto remove_extent(info type) -> info { - return detail::__workaround_expand_compiler_builtins( - detail::__underlying_entity_of(substitute(^^remove_extent_t, {type}))); -} - -consteval auto remove_all_extents(info type) -> info { - return detail::__workaround_expand_compiler_builtins( - detail::__underlying_entity_of(substitute(^^remove_all_extents_t, - {type}))); -} - -consteval auto remove_pointer(info type) -> info { - return detail::__workaround_expand_compiler_builtins( - detail::__underlying_entity_of(substitute(^^remove_pointer_t, {type}))); -} - -consteval auto add_pointer(info type) -> info { - return detail::__workaround_expand_compiler_builtins( - detail::__underlying_entity_of(substitute(^^add_pointer_t, {type}))); -} - -consteval auto remove_cvref(info type) -> info { - return detail::__workaround_expand_compiler_builtins( - detail::__underlying_entity_of(substitute(^^remove_cvref_t, {type}))); -} - -consteval auto decay(info type) -> info { - return detail::__workaround_expand_compiler_builtins( - detail::__underlying_entity_of(substitute(^^decay_t, {type}))); -} - -template > -consteval auto common_type(R &&args) -> info { - return detail::__workaround_expand_compiler_builtins( - detail::__underlying_entity_of(substitute(^^common_type_t, args))); -} - -template > -consteval auto common_reference(R &&args) -> info { - return detail::__underlying_entity_of(substitute(^^common_reference_t, args)); -} - -consteval auto underlying_type(info type) -> info { - return detail::__workaround_expand_compiler_builtins( - detail::__underlying_entity_of(substitute(^^underlying_type_t, {type}))); -} - -template > -consteval auto invoke_result(info type, R &&args) -> info { - vector targs(from_range, args); - targs.insert(targs.begin(), type); - - return detail::__underlying_entity_of(substitute(^^invoke_result_t, targs)); -} - -consteval auto unwrap_reference(info type) -> info { - return detail::__underlying_entity_of(substitute(^^unwrap_reference_t, - {type})); -} - -consteval auto unwrap_ref_decay(info type) -> info { - return detail::__underlying_entity_of(substitute(^^unwrap_ref_decay_t, - {type})); -} - -consteval auto tuple_size(info type) -> size_t { - return extract(substitute(^^tuple_size_v, {type})); -} - -consteval auto tuple_element(size_t index, info type) -> info { - return detail::__underlying_entity_of(substitute(^^tuple_element_t, - {reflect_constant(index), type})); -} - -consteval auto variant_size(info type) -> size_t { - return extract(substitute(^^variant_size_v, {type})); -} - -consteval auto variant_alternative(size_t index, info type) -> info { - return detail::__underlying_entity_of(substitute(^^variant_alternative_t, - {reflect_constant(index), type})); -} - - -namespace detail { -template struct __wrap_workaround { using type = T; }; -consteval auto __workaround_expand_compiler_builtins(info type) -> info { - auto r = substitute(^^__wrap_workaround, {type}); - r = members_of(r, access_context::unchecked())[0]; - return detail::__underlying_entity_of(r); -} - -} // namespace detail - -#if __has_feature(parameter_reflection) - -consteval auto parameters_of(info r) -> vector { - 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; - auto rng = range{r}; - return vector{rng.begin(), rng.end()}; -} - -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); -} - -consteval auto variable_of(info r) -> info { - return __metafunction(detail::__metafn_variable_of, r); -} - -#endif // __has_feature(parameter_reflection) - -#if __has_feature(annotation_attributes) - -consteval auto annotations_of(info r) -> vector { - 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; - auto rng = range{r}; - return vector{rng.begin(), rng.end()}; -} - -consteval auto annotations_of(info r, info ty) -> vector { - 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(); -} - -template -consteval optional annotation_of_type(info r) { - auto v = annotations_of(r, ^^T); - optional result{}; - for (info a: v) { - if (result.has_value()) { - if (extract(a) != result) { - throw "inconsistent annotations"; - } - } else { - result = extract(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) - -consteval auto has_inaccessible_nonstatic_data_members( - info r, - access_context ctx) -> bool { - return !ranges::all_of( - nonstatic_data_members_of(r, access_context::unchecked()), - [=](info m) { return is_accessible(m, ctx); }); -} - -consteval auto has_inaccessible_bases(info r, access_context ctx) -> bool { - return !ranges::all_of(bases_of(r, access_context::unchecked()), - [=](info b) { return is_accessible(b, ctx); }); -} - - // =================================================== - // Other bespoke functions (not proposed at this time) - // =================================================== - -// 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 a reflection of the constant value obtained from calling -// target(args...) -template > -consteval auto reflect_invoke(info target, R &&args) -> info { - if constexpr (ranges::contiguous_range) { - return __metafunction(detail::__metafn_reflect_invoke, target, - static_cast(nullptr), 0, - ranges::data(args), ranges::size(args)); - } else { - vector vargs = args | ranges::to(); - return __metafunction(detail::__metafn_reflect_invoke, target, - static_cast(nullptr), 0, - vargs.data(), vargs.size()); - } -} - -template , - reflection_range R2 = initializer_list> -consteval auto reflect_invoke(info target, R1 &&targs, R2 &&args) -> info { - if constexpr (ranges::contiguous_range) { - if constexpr (ranges::contiguous_range) { - 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(); - return __metafunction(detail::__metafn_reflect_invoke, target, - ranges::data(targs), ranges::size(targs), - vargs.data(), vargs.size()); - } - } else { - vector vtargs = targs | ranges::to(); - if constexpr (ranges::contiguous_range) { - return __metafunction(detail::__metafn_reflect_invoke, target, - vtargs.data(), vtargs.size(), - ranges::data(args), ranges::size(args)); - } else { - vector vargs = args | ranges::to(); - return __metafunction(detail::__metafn_reflect_invoke, target, - vtargs.data(), vtargs.size(), - vargs.data(), vargs.size()); - } - } -} - - // ========================= - // Deprecated names and APIs - // ========================= - -template -[[deprecated("separated into 'reflect_value', 'reflect_result', and " - "'reflect_function' in P2996R4")]] -consteval auto reflect_result(Ty r) -> info { - constexpr auto DTy = detail::__underlying_entity_of(^^Ty); - constexpr auto RTy = is_class_v || - is_reference_v ? - DTy : ^^remove_cv_t; - - return __metafunction(detail::__metafn_reflect_result, - detail::__underlying_entity_of(RTy), - static_cast(r)); -} - -template -[[deprecated("renamed to 'reflect_constant' in P2996R12")]] -consteval auto reflect_value(const T &r) -> info { - return reflect_constant(r); -} - -[[deprecated("renamed to 'constant_of' in P2996R12")]] -consteval auto value_of(info r) -> info { - return constant_of(r); -} - -template > -[[deprecated("removed 'test_type' and 'test_types' in P2996R4")]] -consteval auto test_types(info templ, R &&args) -> bool { - return extract(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(substitute(templ, args)); -} - -[[deprecated("removed 'test_trait' in P2996R5")]] -consteval auto test_trait(info templ, info type) -> bool { - info args[1] = {type}; - return extract(substitute(templ, args)); -} - -template > -[[deprecated("removed 'test_trait' in P2996R5")]] -consteval auto test_trait(info templ, R &&args) -> bool { - return extract(substitute(templ, args)); -} - -template > -[[deprecated("renamed to 'define_aggregate' in P2996R8")]] -consteval auto define_class(info class_type, R &&members) -> info { - return define_aggregate(class_type, members); -} - -[[deprecated("P3547 requires an 'access_context' argument " - "(compile with '-fno-access-contexts' to disable this warning)")]] -consteval auto members_of(info r) -> vector { - return members_of(r, access_context::unchecked()); -} - -[[deprecated("P3547 requires an 'access_context' argument " - "(compile with '-fno-access-contexts' to disable this warning)")]] -consteval auto bases_of(info r) -> vector { - return bases_of(r, access_context::unchecked()); -} - -[[deprecated("P3547 requires an 'access_context' argument " - "(compile with '-fno-access-contexts' to disable this warning)")]] -consteval auto static_data_members_of(info r) -> vector { - return static_data_members_of(r, access_context::unchecked()); -} - -[[deprecated("P3547 requires an 'access_context' argument " - "(compile with '-fno-access-contexts' to disable this warning)")]] -consteval auto nonstatic_data_members_of(info r) -> vector { - return nonstatic_data_members_of(r, access_context::unchecked()); -} - -[[deprecated("replaced with 'is_enumerable_type' in P2996R11")]] -consteval auto has_complete_definition(info r) -> bool { - return __metafunction(detail::__metafn_has_complete_definition, r); -} - -namespace __define_static { - -template -inline constexpr ValTy FixedArray[sizeof...(Vals)] = {Vals...}; - -} // namespace __define_static - -template - requires (is_constructible_v, - ranges::range_reference_t>) -consteval auto reflect_constant_array(R &&elems) -> info { - using ValTy = ranges::range_value_t; - vector Args = {^^ValTy}; - for (const auto &V : elems) - Args.push_back(reflect_constant(V)); - return substitute(^^__define_static::FixedArray, Args); -} - -_LIBCPP_END_NAMESPACE_REFLECTION_V2 - -_LIBCPP_BEGIN_NAMESPACE_STD - -template - requires (is_constructible_v, - ranges::range_reference_t>) -consteval auto define_static_array(R &&elems) - -> span> { - using ValTy = ranges::range_value_t; - meta::info array = meta::reflect_constant_array(elems); - return span(extract(array), meta::extent(type_of(array))); -} - -// Returns a static string having the provided contents. -consteval auto define_static_string(string_view in) -> const char * { - const char nullterm[1] = {0}; - vector> v = {in, nullterm}; - return define_static_array(views::join(v)).data(); -} - -consteval auto define_static_string(u8string_view in) -> const char8_t * { - const char8_t nullterm[1] = {0}; - vector> v = {in, nullterm}; - return define_static_array(views::join(v)).data(); -} - -_LIBCPP_END_NAMESPACE_STD - -_LIBCPP_BEGIN_NAMESPACE_REFLECTION_V2 - - // ==================================== - // (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 -struct pretty_printer { - static_assert(detail::__underlying_entity_of(^^CharT) == ^^char || - detail::__underlying_entity_of(^^CharT) == ^^char8_t); - static constexpr bool IsUtf8 = is_same_type(^^CharT, ^^char8_t); - - using string_t = basic_string; - - static consteval const CharT *string_constant(string_view contents) { - if constexpr (IsUtf8) { - u8string result(contents.size(), 0); - for (size_t idx = 0; char c : contents) - result[idx++] = char8_t(c); - - return 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 u8symbol_of(Op); - else - return symbol_of(Op); - } - - template - static consteval info type_of_object_from_memptr() { - return [](T C::*) { return ^^C; }(typename [:R:]{}); - }; - - template - static consteval info type_of_member_from_memptr() { - return [](T C::*) { return ^^T; }(typename [:R:]{}); - }; - - template - struct replicator_type { - template - constexpr void operator>>(F body) const { - (body.template operator()(), ...); - } - }; - - template - static constexpr replicator_type replicator = {}; - - template - static consteval auto expand(R range) { - vector args; - for (auto r : range) { - args.push_back(reflect_constant(r)); - } - return substitute(^^replicator, args); - } - - template - requires (has_template_arguments(R)) - static consteval string_t render_template_argument_list_of(); - - template - requires (is_value(R)) - static consteval string_t render_value_as_hex(); - - template - static consteval const CharT *tprint(); - - struct tprint_impl { - template // Null reflection. - requires (R == info{}) - static consteval string_t render() { - return string_constant("(null-reflection)"); - } - - template // Values of fundamental type. - requires (is_value(R) && is_fundamental_type(type_of(R))) - static consteval string_t render(); - - template // Values of aggregate type. - requires (is_value(R) && is_aggregate_type(type_of(R))) - static consteval string_t render(); - - template // Values of pointer type. - requires (is_value(R) && is_pointer_type(type_of(R))) - static consteval string_t render(); - - template // Objects. - requires (is_object(R)) - static consteval string_t render(); - - template // Variables, data members, enumerators. - requires (is_variable(R) || is_nonstatic_data_member(R) || - is_enumerator(R)) - static consteval string_t render(); - - template // Templates. - requires (is_template(R)) - static consteval string_t render(); - - template // Namespaces. - requires (is_namespace(R)) - static consteval string_t render(); - - template // Functions. - requires (is_function(R)) - static consteval string_t render(); - - template // Value types. - requires (is_type(R) && !(is_const(R) || is_volatile(R)) && - !is_pointer_type(R) && !is_array_type(R) && - !is_function_type(R) && !is_reference_type(R) && - !is_member_pointer_type(R)) - static consteval string_t render(); - - template // CV-qualified non-function, non-arry types. - requires (is_type(R) && (is_const(R) || is_volatile(R)) && - !is_array_type(R) && !is_function_type(R)) - static consteval string_t render(); - - template // Reference types. - requires (is_type(R) && !(is_const(R) || is_volatile(R)) && - is_reference_type(R)) - static consteval string_t render(); - - template // Unqualified array types. - requires (is_type(R) && is_array_type(R)) - static consteval string_t render(); - - template // Function types. - requires (is_type(R) && is_function_type(R)) - static consteval string_t render(); - - template // Non-function, non-member pointer types. - requires (is_type(R) && is_pointer_type(R) && - !(is_const(R) || is_volatile(R)) && - !is_function_type(remove_pointer(R))) - static consteval string_t render(); - - template // Function pointer types. - requires (is_type(R) && is_pointer_type(R) && - is_function_type(remove_pointer(R))) - static consteval string_t render(); - - template // Pointer to data member types. - requires (is_type(R) && is_member_pointer_type(R) && - !(is_const(R) || is_volatile(R)) && - !is_member_function_pointer_type(R)) - static consteval string_t render(); - - template // Pointer to member function types. - requires (is_type(R) && is_member_function_pointer_type(R)) - static consteval string_t render(); - - template // Base specifiers. - requires (is_base(R)) - static consteval string_t render(); - - template // Fallback. - static consteval string_t render(); - }; - - static consteval const CharT *print(info R); - - friend consteval auto display_string_of(info) -> string_view; - friend consteval auto u8display_string_of(info) -> u8string_view; - -}; - -template -consteval auto pretty_printer::print(info R) - -> const CharT * { - return extract(reflect_invoke(^^tprint, - {reflect_constant(R)}, {})); -} - -template -template - requires (has_template_arguments(R)) -consteval auto pretty_printer::render_template_argument_list_of() - -> string_t { - string_t result; - - if (template_arguments_of(R).empty()) - return string_constant("<>"); - - size_t Idx = 0; - [:expand(template_arguments_of(R)):] >> [&] { - result += (Idx++ < 1 ? string_constant("<") : string_constant(", ")); - result += tprint_impl::template render(); - }; - return result + string_constant(">"); -} - -template -template - requires (is_value(R)) -consteval auto pretty_printer::render_value_as_hex() -> string_t { - string_t result = string_constant("0x"); - - auto bytes = bit_cast>([: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 -template -consteval auto pretty_printer::tprint() -> const CharT * { - return define_static_string(tprint_impl::template render()); -} - -template -template // Values of fundamental type. - requires(is_value(R) && is_fundamental_type(type_of(R))) -consteval auto pretty_printer::tprint_impl::render() -> string_t { - string_t result; - constexpr info Ty = detail::__underlying_entity_of(type_of(R)); - - if constexpr (Ty == ^^nullptr_t) - result = string_constant("nullptr"); - - if constexpr (is_same_type(Ty, ^^bool)) { - if (extract(R)) - result = string_constant("true"); - else - result = string_constant("false"); - } - - else if constexpr (is_same_type(Ty, ^^char)) { - result = string_constant("'"); - result.append(1, extract(R)); - result += string_constant("'"); - } - - else if constexpr (is_integral_type(Ty) && - detail::__underlying_entity_of(^^CharT) == ^^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 (is_floating_point_type(Ty)) { - result = render_value_as_hex(); - } - - else { - result += string_constant("(value : "); - result += render(); - result += string_constant(")"); - } - - return result; -} - -template -template // Values of aggregate type. - requires(is_value(R) && is_aggregate_type(type_of(R))) -consteval auto pretty_printer::tprint_impl::render() -> string_t { - string_t result = render() + string_constant("{"); - - size_t Idx = 0; - [:expand(nonstatic_data_members_of(type_of(R), - access_context::unchecked())):] >> - [&] { - if (Idx++ > 0) result += string_constant(", "); - result += tprint_impl::render(); - }; - result += string_constant("}"); - - return result; -} - -template -template // Values of pointer type. - requires (is_value(R) && is_pointer_type(type_of(R))) -consteval auto pretty_printer::tprint_impl::render() -> string_t { - return string_constant("(value : ") + render() + - string_constant(")"); -} - -template -template // Objects. - requires (is_object(R)) -consteval auto pretty_printer::tprint_impl::render() -> string_t { - string_t result = string_constant("(object : "); - result += render(); - return result + string_constant(")"); -} - -template -template // Templates. - requires(is_template(R)) -consteval auto pretty_printer::tprint_impl::render() -> string_t { - if constexpr (is_constructor_template(R)) - return render(); - else if (is_operator_function_template(R)) { - operators op = operator_of(R); - - string_t result = "operator"; - switch (op) { - case operators::op_new: - case operators::op_delete: - case operators::op_array_new: - case operators::op_array_delete: - case 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 -template // Namespaces. - requires(is_namespace(R)) -consteval auto pretty_printer::tprint_impl::render() -> string_t { - if (R == ^^::) - return string_constant("(global-namespace)"); - if (!has_identifier(R)) - return string_constant("(anonymous-namespace)"); - - return string_t {identifier_helper(R)}; -} - -template -template // Functions. - requires(is_function(R)) -consteval auto pretty_printer::tprint_impl::render() -> string_t { - string_t result; - - if constexpr (has_template_arguments(R)) { - return render() + render_template_argument_list_of(); - } else if constexpr (is_destructor(R)) { - constexpr info P = parent_of(R); - return string_constant("~") + - render(); - } else if constexpr (is_constructor(R)) { - return render(); - } else if constexpr (is_operator_function(R)) { - operators op = operator_of(R); - - result = "operator"; - switch (op) { - case operators::op_new: - case operators::op_delete: - case operators::op_array_new: - case operators::op_array_delete: - case 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(); -#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 -template // Value types. - requires (is_type(R) && !(is_const(R) || is_volatile(R)) && - !is_pointer_type(R) && !is_array_type(R) && - !is_function_type(R) && !is_reference_type(R) && - !is_member_pointer_type(R)) -consteval auto pretty_printer::tprint_impl::render() -> string_t { - string_t result; - - if constexpr (has_template_arguments(R)) { - return render() + render_template_argument_list_of(); - } else if constexpr (is_fundamental_type(R)) { - if (R == ^^void) return string_constant("void"); - - if (R == ^^decltype(nullptr) || R == ^^nullptr_t) - return string_constant("std::nullptr_t"); - if (R == ^^info || R == detail::__underlying_entity_of(^^info)) - return string_constant("std::meta::info"); - - if (R == ^^bool) return string_constant("bool"); - if (R == ^^signed char) return string_constant("signed char"); - if (R == ^^unsigned char) return string_constant("unsigned char"); - if (R == ^^char) return string_constant("char"); - - if (R == ^^char8_t) return string_constant("char8_t"); - if (R == ^^char16_t) return string_constant("char16_t"); - if (R == ^^char32_t) return string_constant("char32_t"); - - if (R == ^^float) return string_constant("float"); - if (R == ^^double) return string_constant("double"); - if (R == ^^long double) return string_constant("long double"); - - if (is_unsigned_type(R)) result += string_constant("unsigned "); - if constexpr (!is_type_alias(R)) { - auto U = make_signed(R); - if (U == ^^short) return result + string_constant("short"); - if (U == ^^int) return result + string_constant("int"); - if (U == ^^long) return result + string_constant("long"); - if (U == ^^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 -template // CV-qualified non-function, non-array types. - requires (is_type(R) && (is_const(R) || is_volatile(R)) && - !is_array_type(R) && !is_function_type(R)) -consteval auto pretty_printer::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(); -} - -template -template // Reference types. - requires (is_type(R) && !(is_const(R) || is_volatile(R)) && - is_reference_type(R)) -consteval auto pretty_printer::tprint_impl::render() -> string_t { - string_t result = render() + string_constant(" &"); - if (is_rvalue_reference_type(R)) - result += string_constant("&"); - return result; -} - -template -template // Array types. - requires (is_type(R) && is_array_type(R)) -consteval auto pretty_printer::tprint_impl::render() -> string_t { - string_t result = render(); - - for (size_t k = 0; k < rank(R); ++k) { - CharT buffer[32] = {}; - if (!to_chars(begin(buffer), end(buffer), extent(R, k))) - throw "'to_chars' failed to format integeral value"; - - result += "[" + string_t {buffer} + "]"; - } - return result; -} - -template -template // Non-function, non-member pointer types. - requires (is_type(R) && is_pointer_type(R) && - !(is_const(R) || is_volatile(R)) && - !is_function_type(remove_pointer(R))) -consteval auto pretty_printer::tprint_impl::render() -> string_t { - return render() + string_constant(" *"); -} - -template -template // Function pointers. - requires (is_type(R) && is_pointer_type(R) && - is_function_type(remove_pointer(R))) -consteval auto pretty_printer::tprint_impl::render() -> string_t { - -#if __has_feature(parameter_reflection) - constexpr auto FnTy = remove_pointer(R); - string_t result = render() + string_constant("(*)("); - size_t Idx = 0; - [:expand(parameters_of(FnTy)):] >> [&] { - if (Idx++ > 0) result += string_constant(", "); - result += tprint_impl::render(); - }; - result += string_constant(")"); - - if (is_noexcept(FnTy)) - result += string_constant(" noexcept"); -#else - string_t result = string_constant("(function-pointer-type)"); -#endif - - return result; -} - -template -template // Function types. - requires (is_type(R) && is_function_type(R)) -consteval auto pretty_printer::tprint_impl::render() -> string_t { -#if __has_feature(parameter_reflection) - string_t result = render() + string_constant("("); - size_t Idx = 0; - [:expand(parameters_of(R)):] >> [&] { - if (Idx++ > 0) result += string_constant(", "); - result += tprint_impl::render(); - }; - 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 -template // Pointer to data member types. - requires (is_type(R) && is_member_pointer_type(R) && - !(is_const(R) || is_volatile(R)) && - !is_member_function_pointer_type(R)) -consteval auto pretty_printer::tprint_impl::render() -> string_t { - string_t result = render()>() + - string_constant(" "); - result += render()>() + string_constant("::*"); - - return result; -} - -template -template // Pointer to member function types. - requires (is_type(R) && is_member_function_pointer_type(R)) -consteval auto pretty_printer::tprint_impl::render() -> string_t { - constexpr auto FnTy = type_of_member_from_memptr(); - -#if __has_feature(parameter_reflection) - string_t result = render() + string_constant("("); - result += render()>() + - string_constant("::*)("); - - size_t Idx = 0; - [:expand(parameters_of(FnTy)):] >> [&] { - if (Idx++ > 0) result += string_constant(", "); - result += tprint_impl::render(); - }; - 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 -template // Base specifiers. - requires (is_base(R)) -consteval auto pretty_printer::tprint_impl::render() -> string_t { - return string_t {render()}; -} - -template -template // Fallback. -consteval auto pretty_printer::tprint_impl::render() -> string_t { - return string_constant("(unsupported-reflection)"); -} - -template -template // Variables, data members, enumerators. - requires (is_variable(R) || is_nonstatic_data_member(R) || is_enumerator(R)) -consteval auto pretty_printer::tprint_impl::render() -> string_t { - return string_t {identifier_helper(R)}; -} -} // namespace detail - -consteval auto display_string_of(info R) -> string_view { - return detail::pretty_printer::print(R); -} - -consteval auto u8display_string_of(info R) -> u8string_view { - return detail::pretty_printer::print(R); -} - -_LIBCPP_END_NAMESPACE_REFLECTION_V2 - -#endif // __has_feature(reflection) +#include #endif // _LIBCPP_EXPERIMENTAL_META diff --git a/libcxx/include/meta b/libcxx/include/meta new file mode 100644 index 000000000000..06498b5ca46a --- /dev/null +++ b/libcxx/include/meta @@ -0,0 +1,3004 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Copyright 2025 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_META +#define _LIBCPP_META + +/* + meta synopsis + +// C++2c +namespace std +{ +namespace meta +{ +inline namespace reflection_v2 +{ + +// std::meta::info +using info = decltype(^^int); + +// concept reflection_range +template +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 constant_of(info) -> info; + +// template queries +consteval auto template_of(info r) -> info; +consteval auto template_arguments_of(info r) -> vector; + +// member queries +consteval auto members_of(info class_type, access_context ctx) -> vector; +consteval auto bases_of(info class_type, access_context ctx) -> vector; +consteval auto static_data_members_of(info class_type, + access_context ctx) -> vector; +consteval auto nonstatic_data_members_of(info class_type, + access_context ctx) -> vector; +consteval auto enumerators_of(info enum_type) -> vector; + +// substitute +template > + consteval auto can_substitute(info templ, R &&args) -> bool; +template > + consteval auto substitute(info templ, R &&args) -> info; + +// reflect expression results +template + consteval auto reflect_constant(const T&) -> info; +template + consteval auto reflect_object(T &) -> info; +template + consteval auto reflect_function(T &) -> info; + +// extract +template + 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_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 is_enumerable_type(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_aggregate +struct data_member_options; +consteval auto data_member_spec(info class_type, + data_member_options = {}) -> info; +template > + consteval auto define_aggregate(info class_type, R &&members) -> info; + +// data layout +struct member_offset { + ptrdiff_t bytes; + ptrdiff_t bits; + + constexpr size_t total_bits() const; + auto operator<=>(member_offset const&) const = default; +}; +consteval auto offset_of(info) -> member_offset; +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 is_void_type(info) -> bool; +consteval auto is_null_pointer_type(info) -> bool; +consteval auto is_integral_type(info) -> bool; +consteval auto is_floating_point_type(info) -> bool; +consteval auto is_array_type(info) -> bool; +consteval auto is_pointer_type(info) -> bool; +consteval auto is_lvalue_reference_type(info) -> bool; +consteval auto is_rvalue_reference_type(info) -> bool; +consteval auto is_member_object_pointer_type(info) -> bool; +consteval auto is_member_function_pointer_type(info) -> bool; +consteval auto is_enum_type(info) -> bool; +consteval auto is_union_type(info) -> bool; +consteval auto is_class_type(info) -> bool; +consteval auto is_function_type(info) -> bool; +consetval auto is_reflection_type(info) -> bool; + +// composite type categories +consteval auto is_reference_type(info) -> bool; +consteval auto is_arithmetic_type(info) -> bool; +consteval auto is_fundamental_type(info) -> bool; +consteval auto is_object_type(info) -> bool; +consteval auto is_scalar_type(info) -> bool; +consteval auto is_compound_type(info) -> bool; +consteval auto is_member_pointer_type(info) -> bool; + +// type properties +consteval auto is_const_type(info) -> bool; +consteval auto is_volatile_type(info) -> bool; +consteval auto is_trivial_type(info) -> bool; +consteval auto is_trivially_copyable_type(info) -> bool; +consteval auto is_standard_layout_type(info) -> bool; +consteval auto is_empty_type(info) -> bool; +consteval auto is_polymorphic_type(info) -> bool; +consteval auto is_abstract_type(info) -> bool; +consteval auto is_final_type(info) -> bool; +consteval auto is_aggregate_type(info) -> bool; +consteval auto is_consteval_only_type(info) -> bool; +consteval auto is_signed_type(info) -> bool; +consteval auto is_unsigned_type(info) -> bool; +consteval auto is_bounded_array_type(info) -> bool; +consteval auto is_unbounded_array_type(info) -> bool; +consteval auto is_scoped_enum_type(info) -> bool; + +template > + consteval auto is_constructible_type(info, R &&args) -> bool; +consteval auto is_default_constructible_type(info) -> bool; +consteval auto is_copy_constructible_type(info) -> bool; +consteval auto is_move_constructible_type(info) -> bool; + +consteval auto is_assignable_type(info dst, info src) -> bool; +consteval auto is_copy_assignable_type(info) -> bool; +consteval auto is_move_assignable_type(info) -> bool; + +consteval auto is_swappable_with_type(info dst, info src) -> bool; +consteval auto is_swappable_type(info) -> bool; + +consteval auto is_destructible_type(info) -> bool; + +template > + consteval auto type_is_trivially_constructible(info, R &&args) -> bool; +consteval auto is_trivially_default_constructible_type(info) -> bool; +consteval auto is_trivially_copy_constructible_type(info) -> bool; +consteval auto is_trivially_move_constructible_type(info) -> bool; + +consteval auto is_trivially_assignable_type(info dst, info src) -> bool; +consteval auto is_trivially_copy_assignable_type(info) -> bool; +consteval auto is_trivially_move_assignable_type(info) -> bool; +consteval auto is_trivially_destructible_type(info) -> bool; + +template > + consteval auto is_nothrow_constructible_type(info, R &&args) -> bool; +consteval auto is_nothrow_default_constructible_type(info) -> bool; +consteval auto is_nothrow_copy_constructible_type(info) -> bool; +consteval auto is_nothrow_move_constructible_type(info) -> bool; + +consteval auto is_nothrow_assignable_type(info dst, info src) -> bool; +consteval auto is_nothrow_copy_assignable_type(info) -> bool; +consteval auto is_nothrow_move_assignable_type(info) -> bool; + +consteval auto is_nothrow_swappable_with_type(info dst, info src) -> bool; +consteval auto is_nothrow_swappable_type(info) -> bool; + +consteval auto is_nothrow_destructible_type(info) -> bool; + +consteval auto is_implicit_lifetime_type(info) -> bool; + +consteval auto has_virtual_destructor(info) -> bool; + +consteval auto has_unique_object_representations(info) -> bool; + +consteval auto reference_constructs_from_temporary(info) -> bool; +consteval auto reference_converts_from_temporary(info) -> bool; + +// type property queries +consteval auto rank(info) -> size_t; +consteval auto extent(info type, unsigned i) -> size_t; + +// type relations +consteval auto is_same_type(info, info) -> bool; +consteval auto is_base_of_type(info, info) -> bool; +consteval auto is_convertible_type(info, info) -> bool; +consteval auto is_nothrow_convertible_type(info, info) -> bool; +consteval auto is_layout_compatible_type(info, info) -> bool; +consteval auto is_pointer_interconvertible_base_of_type(info, info) -> bool; + +template > + consteval auto is_invocable_type(info type, R &&args) -> bool; +template > + consteval auto is_invocable_r_type(info result, info type, + R &&args) -> bool; + +template > + consteval auto is_nothrow_invocable_type(info type, R &&args) -> bool; +template > + consteval auto is_nothrow_invocable_r_type(info result, info type, + R &&args) -> bool; + +// const volatile modifications +consteval auto remove_const(info) -> info; +consteval auto remove_volatile(info) -> info; +consteval auto remove_cv(info) -> info; +consteval auto add_const(info) -> info; +consteval auto add_volatile(info) -> info; +consteval auto add_cv(info) -> info; + +// reference modifications +consteval auto remove_reference(info) -> info; +consteval auto add_lvalue_reference(info) -> info; +consteval auto add_rvalue_reference(info) -> info; + +// sign modifications +consteval auto make_signed(info) -> info; +consteval auto make_unsigned(info) -> info; + +// array modifications +consteval auto remove_extent(info) -> info; +consteval auto remove_all_extents(info) -> info; + +// pointer modifications +consteval auto remove_pointer(info) -> info; +consteval auto add_pointer(info) -> info; + +// other transformations +consteval auto remove_cvref(info) -> info; +consteval auto decay(info) -> info; +template > + consteval auto common_type(R &&args) -> info; +template > + consteval auto common_reference(R &&args) -> info; +consteval auto underlying_type(info) -> info; +template > + consteval auto invoke_result(info type, R &&args) -> info; +consteval auto unwrap_reference(info) -> info; +consteval auto unwrap_ref_decay(info) -> info; + +// tuple and variant queries +consteval auto tuple_size(info) -> size_t; +consteval auto tuple_element(size_t, info) -> info; + +consteval auto variant_size(info) -> size_t; +consteval auto variant_alternative(size_t, info) -> info; + +// entity proxies (PXYZ) +consteval auto is_entity_proxy(info) -> bool; + +// function parameters (P3096) +consteval auto parameters_of(info) -> vector; +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; +consteval auto variable_of(info) -> info; + +// annotations (P3394) +consteval auto annotations_of(info) -> vector; +consteval auto annotations_of(info, info) -> vector; +template + consteval auto annotation_of_type(info) -> optional; +consteval auto is_annotation(info) -> bool; +consteval auto annotate(info) -> info; + +// modeling access control (P3547) +struct access_context { + access_context() = delete; + + consteval auto scope() const -> info; + consteval auto designating_class() const -> info; + + static consteval auto current() noexcept -> access_context; + static consteval auto unprivileged() noexcept -> access_context; + static consteval auto unchecked() noexcept -> access_context; + + consteval auto via(info) const -> access_context; +}; + +consteval auto is_accessible(info r, access_context ctx) -> bool; +consteval auto has_inaccessible_nonstatic_data_members( + info r, + access_context cls) -> vector; +consteval auto has_inaccessible_bases( + info r, + access_context cls) -> vector; + +// other bespoke functions (not proposed at this time) +consteval auto is_access_specified(info) -> bool; + +template > + consteval auto reflect_invoke(info target, R &&args) -> info; +template , + reflection_range R2 = initializer_list> + consteval auto reflect_invoke(info target, + R1 &&tmpl_args, R2 &&args) -> info; + + +} // namespace reflection_v2 +} // namespace meta +} // namespace std + + */ + +#include <__config> +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if __has_feature(reflection) + +_LIBCPP_BEGIN_NAMESPACE_REFLECTION_V2 + +// An opaque handle to a reflected entity. +using info = decltype(^^int); + +template +concept reflection_range = + ranges::input_range && + same_as, info> && + same_as>, 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, + + // P2996 metafunctions + __metafn_identifier_of, + __metafn_has_identifier, + __metafn_operator_of, + __metafn_source_location_of, + __metafn_type_of, + __metafn_parent_of, + __metafn_underlying_entity_of, + __metafn_proxied_entity_of, + __metafn_object_of, + __metafn_constant_of, + __metafn_template_of, + __metafn_substitute, + __metafn_extract, + __metafn_is_public, + __metafn_is_protected, + __metafn_is_private, + __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_entity_proxy, + __metafn_is_complete_type, + __metafn_has_complete_definition, + __metafn_is_enumerable_type, + __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_data_member_spec, + __metafn_define_aggregate, + __metafn_offset_of, + __metafn_size_of, + __metafn_bit_offset_of, + __metafn_bit_size_of, + __metafn_alignment_of, + + // P3096 parameter reflection metafunctions + __metafn_get_ith_parameter_of, + __metafn_has_ellipsis_parameter, + __metafn_has_default_argument, + __metafn_is_explicit_object_parameter, + __metafn_is_function_parameter, + __metafn_return_type_of, + __metafn_variable_of, + + // P3394 annotation metafunctions + __metafn_get_ith_annotation_of, + __metafn_is_annotation, + __metafn_annotate, + + // P3493 accessibility metafunctions + __metafn_access_context, + __metafn_is_accessible, + + // Other bespoke functions (not proposed at this time) + __metafn_is_access_specified, + __metafn_reflect_invoke, +}; + +consteval auto __workaround_expand_compiler_builtins(info type) -> info; + +consteval auto __underlying_entity_of(info r) -> info { + return __metafunction(detail::__metafn_underlying_entity_of, r); +} + +} // namespace detail + +namespace __range_of_infos { + +struct sentinel {}; + +template +class iterator { + static constexpr Front m_front = { }; + static constexpr Next m_next = { }; + + // The reflected entity passed to the underlying range + info m_reflectedEntity{^^sentinel}; + // The current meta::info within the range: e.g. if we are + // doing template_arguments_of(^^vector) + // m_currInfoItr can be either ^^int, ^^double and ^^string + info m_currInfoItr{^^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{^^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 +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 +consteval ptrdiff_t distance(iterator first, + iterator 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, + ^^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, ^^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, ^^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, ^^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, ^^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, ^^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, ^^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, ^^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, ^^sentinel, idx); + } +}; + +struct front_parameter_of_fn { + consteval info operator()(info reflectedEntity) const { + return __metafunction(detail::__metafn_get_ith_parameter_of, + reflectedEntity, ^^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, ^^sentinel, idx); + } +}; + +struct front_annotation_of { + consteval info operator()(info reflectedEntity) const { + return __metafunction(detail::__metafn_get_ith_annotation_of, + reflectedEntity, ^^sentinel, 0); + } +}; + +} // namespace __range_of_infos + +// ----------------------------------------------------------------------------- +// Metafunctions +// ----------------------------------------------------------------------------- + +// Returns a reflection of the canonical type for the reflected type. +#if __has_feature(entity_proxy_reflection) +[[deprecated("renamed to 'underlying_entity_of' in PXYZ")]] +#endif +consteval auto dealias(info r) -> info { + return __metafunction(detail::__metafn_underlying_entity_of, r); +} + +#if __has_feature(entity_proxy_reflection) +consteval auto underlying_entity_of(info r) -> info { + return __metafunction(detail::__metafn_underlying_entity_of, r); +} + +consteval auto proxied_entity_of(info r) -> info { + return __metafunction(detail::__metafn_proxied_entity_of, r); +} +#endif + +// 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) -> string_view { + return __metafunction(detail::__metafn_identifier_of, ^^const char *, r, + /*UTF8=*/false, /*EnforceConsistent=*/true); +} + +consteval auto u8identifier_of(info r) -> u8string_view { + return __metafunction(detail::__metafn_identifier_of, ^^const char8_t *, + r, /*UTF8=*/true, /*EnforceConsistent=*/true); +} + +// Returns an implementation-defined name for the reflected entity. +consteval auto display_string_of(info r) -> string_view; +consteval auto u8display_string_of(info r) -> u8string_view; + +// 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_exclamation, 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_exclamation_equals, + op_less, op_greater, op_less_equals, op_greater_equals, op_spaceship, + 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, +}; +using enum operators; + +// 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 symbol_of(operators op) -> string_view { + static constexpr string_view op_names[45] = { + {}, "new", "delete", "new[]", "delete[]", "coawait", "()", "[]", "->", + "->*", "~", "!", "+", "-", "*", "/", "%", "^", "&", "|", "=", "+=", "-=", + "*=", "/=", "%=", "^", "&=", "|=", "==", "!=", "<", ">", "<=", ">=", + "<=>", "&&", "||", "<<", ">>", "<<=", ">>=", "++", "--", "," + }; + return op_names[int(op)]; +} + +consteval auto u8symbol_of(operators op) -> u8string_view { + static constexpr u8string_view 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 constant_of(info r) -> info { + return __metafunction(detail::__metafn_constant_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) -> vector { + 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; + auto rng = range{r}; + return vector{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); +} + +// Returns whether 'templ' substituted with 'args' forms a valid template-id. +template > +consteval auto can_substitute(info templ, R &&args) -> bool { + info sub; + if constexpr (ranges::contiguous_range) { + sub = __metafunction(detail::__metafn_substitute, templ, + ranges::data(args), ranges::size(args), false); + } else { + vector vargs = args | ranges::to(); + sub = __metafunction(detail::__metafn_substitute, templ, + vargs.data(), vargs.size(), false); + } + return sub != info{}; +} + +// Returns a reflection representing the template instantiation of the entity +// reflected by 'templ' with the entities reflected by 'args'. +template > +consteval auto substitute(info templ, R &&args) -> info { + if constexpr (ranges::contiguous_range) { + return __metafunction(detail::__metafn_substitute, templ, + ranges::data(args), ranges::size(args), true); + } else { + vector vargs = args | ranges::to(); + return __metafunction(detail::__metafn_substitute, templ, vargs.data(), + vargs.size(), true); + } +} + +// Returns the value or object from 'r' if 'r' is a reflection of a value +// or object having type 'T'. +template requires (!is_rvalue_reference_v) +consteval auto extract(info r) -> Ty { + return __metafunction(detail::__metafn_extract, ^^Ty, r); +} + +consteval auto is_class_type(info r) -> bool { + return extract(substitute(^^is_class_v, {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 whether the reflected class data member is an enumerator. +consteval auto is_enumerator(info r) -> bool { + return __metafunction(detail::__metafn_is_enumerator, r); +} + +class access_context { + consteval access_context(info scope, info designating_class) noexcept + : d_scope{scope}, d_designating_class{designating_class} { } + +public: + const info d_scope; + const info d_designating_class; + + consteval access_context() = delete; + + consteval access_context(const access_context &) noexcept = default; + consteval access_context(access_context &&) noexcept = default; + + consteval info scope() const { return d_scope; } + consteval info designating_class() const { return d_designating_class; } + + [[clang::instantiation_dependent]] + static consteval access_context current() noexcept { + return {__metafunction(detail::__metafn_access_context), {}}; + } + + static consteval access_context unprivileged() noexcept { + return access_context{^^::, info{}}; + } + + static consteval access_context unchecked() noexcept { + return access_context{info{}, info{}}; + } + + consteval access_context via(info new_designating_class) const { + if (!is_class_type(new_designating_class)) + throw "designating class must be a reflection of a class type"; + + return access_context{d_scope, new_designating_class}; + } +}; + +consteval auto is_accessible(info r, access_context ctx) -> bool { + // Note: The accessibility of an enumerator may be looked up in a class + // for which it's not a member, since that enumerator could be + if (!is_class_member(r) && !is_base(r) && !is_enumerator(r)) + return true; + + return __metafunction(detail::__metafn_is_accessible, + r, ctx.scope(), ctx.designating_class()); +} + +consteval auto members_of(info r, access_context ctx) -> vector { + 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; + auto rng = range{r}; + + vector v {rng.begin(), rng.end()}; + return vector{ + from_range, + v | views::filter([=](info r) { return is_accessible(r, ctx); }) + }; +} + +// 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, access_context ctx) -> vector { + 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; + auto rng = range{r}; + + vector v {rng.begin(), rng.end()}; + return vector{ + from_range, + v | views::filter([=](info r) { return is_accessible(r, ctx); }) + }; +} + +// 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, + access_context ctx) -> vector { + if (is_namespace(r)) + throw "Namespaces cannot have static data members"; + + return members_of(r, ctx) | + views::filter(is_variable) | + ranges::to(); +} + +consteval auto nonstatic_data_members_of(info r, + access_context ctx) -> vector { + if (is_namespace(r)) + throw "Namespaces cannot have non-static data members"; + + return members_of(r, ctx) | + views::filter(is_nonstatic_data_member) | + ranges::to(); +} + +// Returns true if the reflected entity is an enumerable type. +consteval auto is_enumerable_type(info r) -> bool { + return __metafunction(detail::__metafn_is_enumerable_type, r); +} + +consteval auto enumerators_of(info r) -> vector { + if (!is_enumerable_type(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; + auto rng = range{r}; + return vector{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); +} + +// 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 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 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 a type 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 a namespace alias. +consteval auto is_namespace_alias(info r) -> bool { + return is_namespace(r) && __metafunction(detail::__metafn_is_alias, r); +} + +#if __has_feature(entity_proxy_reflection) +// Returns true if the reflected entity is an entity proxy. +consteval auto is_entity_proxy(info r) -> bool { + return __metafunction(detail::__metafn_is_entity_proxy, r); +} +#endif + +// 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 + requires (!is_reference_v && + __metafunction(detail::__metafn_is_structural_type, ^^T)) +consteval auto reflect_constant(T r) -> info { + return __metafunction(detail::__metafn_reflect_result, ^^T, r); +} + +// Returns a reflection of the object designated by the provided argument. +template requires (!is_function_v>) +consteval auto reflect_object(T &r) -> info { + return __metafunction(detail::__metafn_reflect_result, type_of(^^r), r); +} + +// Returns a reflection of the object designated by the provided argument. +template requires (is_function_v>) +consteval auto reflect_function(T &r) -> info { + return __metafunction(detail::__metafn_reflect_result, type_of(^^r), r); +} + +// Representation of a data member which may be passed to 'data_member_spec'. +struct data_member_options { + struct name_type { + variant impl; + + template requires constructible_from + consteval name_type(T &&in) : impl(in_place_type, in) {} + + template requires constructible_from + consteval name_type(T &&in) : impl(in_place_type, in) {} + + private: +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-private-field" + info unused = ^^::; +#pragma clang diagnostic pop + }; + + optional name = nullopt; + optional alignment = nullopt; + optional 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_aggregate' to define a record type. +consteval auto data_member_spec(info member_type, + data_member_options 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(substitute(^^is_integral_v, {member_type})) && + !extract(substitute(^^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(name)) { + const u8string &s = get(name); + validate(s); + return __metafunction(detail::__metafn_data_member_spec, + member_type, + !s.empty(), s.size(), ^^const char8_t, s.data(), + options.alignment.has_value(), alignment, + options.width.has_value(), width, + no_unique_address); + } else { + const string &s = get(name); + validate(s); + return __metafunction(detail::__metafn_data_member_spec, + member_type, + !s.empty(), s.size(), ^^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 > +consteval auto define_aggregate(info class_type, R &&members) -> info { + if constexpr (ranges::contiguous_range) { + return __metafunction(detail::__metafn_define_aggregate, class_type, + ranges::size(members), ranges::data(members)); + } else { + vector vmembers = members | ranges::to(); + return __metafunction(detail::__metafn_define_aggregate, class_type, + vmembers.size(), vmembers.data()); + } +} + +struct member_offset { + ptrdiff_t bytes; + ptrdiff_t bits; + + constexpr auto total_bits() -> ptrdiff_t { + return bytes * CHAR_BIT + bits; + } + + auto operator<=>(member_offset const&) const = default; +}; + +// Returns the offset of the reflected entity. +consteval auto offset_of(info r) -> member_offset { + return member_offset { + __metafunction(detail::__metafn_offset_of, ^^ptrdiff_t, r), + __metafunction(detail::__metafn_bit_offset_of, ^^ptrdiff_t, 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); +} + +// Type trait wrappers + +consteval auto is_void_type(info r) -> bool { + return extract(substitute(^^is_void_v, {r})); +} + +consteval auto is_null_pointer_type(info r) -> bool { + return extract(substitute(^^is_null_pointer_v, {r})); +} + +consteval auto is_integral_type(info r) -> bool { + return extract(substitute(^^is_integral_v, {r})); +} + +consteval auto is_floating_point_type(info r) -> bool { + return extract(substitute(^^is_floating_point_v, {r})); +} + +consteval auto is_array_type(info r) -> bool { + return extract(substitute(^^is_array_v, {r})); +} + +consteval auto is_pointer_type(info r) -> bool { + return extract(substitute(^^is_pointer_v, {r})); +} + +consteval auto is_lvalue_reference_type(info r) -> bool { + return extract(substitute(^^is_lvalue_reference_v, {r})); +} + +consteval auto is_rvalue_reference_type(info r) -> bool { + return extract(substitute(^^is_rvalue_reference_v, {r})); +} + +consteval auto is_member_object_pointer_type(info r) -> bool { + return extract(substitute(^^is_member_object_pointer_v, {r})); +} + +consteval auto is_member_function_pointer_type(info r) -> bool { + return extract(substitute(^^is_member_function_pointer_v, {r})); +} + +consteval auto is_enum_type(info r) -> bool { + return extract(substitute(^^is_enum_v, {r})); +} + +consteval auto is_union_type(info r) -> bool { + return extract(substitute(^^is_union_v, {r})); +} + +consteval auto is_function_type(info r) -> bool { + return extract(substitute(^^is_function_v, {r})); +} + +consteval auto is_reflection_type(info r) -> bool { + return r == ^^info; +} + +consteval auto is_reference_type(info r) -> bool { + return extract(substitute(^^is_reference_v, {r})); +} + +consteval auto is_arithmetic_type(info r) -> bool { + return extract(substitute(^^is_arithmetic_v, {r})); +} + +consteval auto is_fundamental_type(info r) -> bool { + return extract(substitute(^^is_fundamental_v, {r})); +} + +consteval auto is_object_type(info r) -> bool { + return extract(substitute(^^is_object_v, {r})); +} + +consteval auto is_scalar_type(info r) -> bool { + return extract(substitute(^^is_scalar_v, {r})); +} + +consteval auto is_compound_type(info r) -> bool { + return extract(substitute(^^is_compound_v, {r})); +} + +consteval auto is_member_pointer_type(info r) -> bool { + return extract(substitute(^^is_member_pointer_v, {r})); +} + +consteval auto is_const_type(info r) -> bool { + return extract(substitute(^^is_const_v, {r})); +} + +consteval auto is_volatile_type(info r) -> bool { + return extract(substitute(^^is_volatile_v, {r})); +} + +consteval auto is_trivial_type(info r) -> bool { + return extract(substitute(^^is_trivial_v, {r})); +} + +consteval auto is_trivially_copyable_type(info r) -> bool { + return extract(substitute(^^is_trivially_copyable_v, {r})); +} + +consteval auto is_standard_layout_type(info r) -> bool { + return extract(substitute(^^is_standard_layout_v, {r})); +} + +consteval auto is_empty_type(info r) -> bool { + return extract(substitute(^^is_empty_v, {r})); +} + +consteval auto is_polymorphic_type(info r) -> bool { + return extract(substitute(^^is_polymorphic_v, {r})); +} + +consteval auto is_abstract_type(info r) -> bool { + return extract(substitute(^^is_abstract_v, {r})); +} + +consteval auto is_final_type(info r) -> bool { + return extract(substitute(^^is_final_v, {r})); +} + +consteval auto is_aggregate_type(info r) -> bool { + return extract(substitute(^^is_aggregate_v, {r})); +} + +consteval auto is_consteval_only_type(info r) -> bool { + return extract(substitute(^^is_consteval_only_v, {r})); +} + +consteval auto is_signed_type(info r) -> bool { + return extract(substitute(^^is_signed_v, {r})); +} + +consteval auto is_unsigned_type(info r) -> bool { + return extract(substitute(^^is_unsigned_v, {r})); +} + +consteval auto is_bounded_array_type(info r) -> bool { + return extract(substitute(^^is_bounded_array_v, {r})); +} + +consteval auto is_unbounded_array_type(info r) -> bool { + return extract(substitute(^^is_unbounded_array_v, {r})); +} + +consteval auto is_scoped_enum_type(info r) -> bool { + return extract(substitute(^^is_scoped_enum_v, {r})); +} + +template > +consteval auto is_constructible_type(info type, R &&type_args) { + vector args(from_range, type_args); + args.insert(args.begin(), type); + + return extract(substitute(^^is_constructible_v, args)); +} + +consteval auto is_default_constructible_type(info r) -> bool { + return extract(substitute(^^is_default_constructible_v, {r})); +} + +consteval auto is_copy_constructible_type(info r) -> bool { + return extract(substitute(^^is_copy_constructible_v, {r})); +} + +consteval auto is_move_constructible_type(info r) -> bool { + return extract(substitute(^^is_move_constructible_v, {r})); +} + +consteval auto is_assignable_type(info dst, info src) -> bool { + return extract(substitute(^^is_assignable_v, {dst, src})); +} + +consteval auto is_copy_assignable_type(info r) -> bool { + return extract(substitute(^^is_copy_assignable_v, {r})); +} + +consteval auto is_move_assignable_type(info r) -> bool { + return extract(substitute(^^is_move_assignable_v, {r})); +} + +consteval auto is_swappable_with_type(info dst, info src) -> bool { + return extract(substitute(^^is_swappable_with_v, {dst, src})); +} + +consteval auto is_swappable_type(info r) -> bool { + return extract(substitute(^^is_swappable_v, {r})); +} + +consteval auto is_destructible_type(info r) -> bool { + return extract(substitute(^^is_destructible_v, {r})); +} + +template > +consteval auto is_trivially_constructible_type(info type, R &&type_args) { + vector args(from_range, type_args); + args.insert(args.begin(), type); + + return extract(substitute(^^is_trivially_constructible_v, args)); +} + +consteval auto is_trivially_default_constructible_type(info r) -> bool { + return extract(substitute(^^is_trivially_default_constructible_v, + {r})); +} + +consteval auto is_trivially_copy_constructible_type(info r) -> bool { + return extract(substitute(^^is_trivially_copy_constructible_v, + {r})); +} + +consteval auto is_trivially_move_constructible_type(info r) -> bool { + return extract(substitute(^^is_trivially_move_constructible_v, + {r})); +} + +consteval auto is_trivially_assignable_type(info dst, info src) -> bool { + return extract(substitute(^^is_trivially_assignable_v, {dst, src})); +} + +consteval auto is_trivially_copy_assignable_type(info r) -> bool { + return extract(substitute(^^is_trivially_copy_assignable_v, {r})); +} + +consteval auto is_trivially_move_assignable_type(info r) -> bool { + return extract(substitute(^^is_trivially_move_assignable_v, {r})); +} + +consteval auto is_trivially_destructible_type(info r) -> bool { + return extract(substitute(^^is_trivially_destructible_v, {r})); +} + +template > +consteval auto is_nothrow_constructible_type(info type, R &&type_args) { + vector args(from_range, type_args); + args.insert(args.begin(), type); + + return extract(substitute(^^is_nothrow_constructible_v, args)); +} + +consteval auto is_nothrow_default_constructible_type(info r) -> bool { + return extract(substitute(^^is_nothrow_default_constructible_v, {r})); +} + +consteval auto is_nothrow_copy_constructible_type(info r) -> bool { + return extract(substitute(^^is_nothrow_copy_constructible_v, {r})); +} + +consteval auto is_nothrow_move_constructible_type(info r) -> bool { + return extract(substitute(^^is_nothrow_move_constructible_v, {r})); +} + +consteval auto is_nothrow_assignable_type(info dst, info src) -> bool { + return extract(substitute(^^is_nothrow_assignable_v, {dst, src})); +} + +consteval auto is_nothrow_copy_assignable_type(info r) -> bool { + return extract(substitute(^^is_nothrow_copy_assignable_v, {r})); +} + +consteval auto is_nothrow_move_assignable_type(info r) -> bool { + return extract(substitute(^^is_nothrow_move_assignable_v, {r})); +} + +consteval auto is_nothrow_swappable_with_type(info dst, info src) -> bool { + return extract(substitute(^^is_nothrow_swappable_with_v, {dst, src})); +} + +consteval auto is_nothrow_swappable_type(info r) -> bool { + return extract(substitute(^^is_nothrow_swappable_v, {r})); +} + +consteval auto is_nothrow_destructible_type(info r) -> bool { + return extract(substitute(^^is_nothrow_destructible_v, {r})); +} + +// TODO(P2996): Not yet implemented in libc++. +/*consteval auto is_implicit_lifetime_type(info r) -> bool { + return extract(substitute(^^is_implicit_lifetime_v, {r})); +}*/ + +consteval auto has_virtual_destructor(info r) -> bool { + return extract(substitute(^^has_virtual_destructor_v, {r})); +} + +consteval auto has_unique_object_representations(info r) -> bool { + return extract(substitute(^^has_unique_object_representations_v, {r})); +} + +// TODO(P2996): Not yet implemented in libc++. +/*consteval auto reference_constructs_from_temporary(info r) -> bool { + return extract(substitute(^^reference_constructs_from_temporary_v, + {r})); +}*/ + +// TODO({2996): Not yet implemented in libc++. +/*consteval auto reference_converts_from_temporary(info r) -> bool { + return extract(substitute(^^reference_converts_from_temporary_v, {r})); +}*/ + +consteval auto rank(info r) -> size_t { + return extract(substitute(^^rank_v, {r})); +} + +consteval auto extent(info r, unsigned i = 0) -> size_t { + return extract(substitute(^^extent_v, {r, reflect_constant(i)})); +} + +consteval auto is_same_type(info r, info s) -> bool { + return extract(substitute(^^is_same_v, {r, s})); +} + +consteval auto is_base_of_type(info r, info s) -> bool { + return extract(substitute(^^is_base_of_v, {r, s})); +} + +consteval auto is_convertible_type(info r, info s) -> bool { + return extract(substitute(^^is_convertible_v, {r, s})); +} + +consteval auto is_nothrow_convertible_type(info r, info s) -> bool { + return extract(substitute(^^is_nothrow_convertible_v, {r, s})); +} + +// TODO(P2996): Not yet implemented in libc++. +/*consteval auto is_layout_compatible_type(info r, info s) -> bool { + return extract(substitute(^^is_layout_compatible_v, {r, s})); +}*/ + +// TODO(P2996): Not yet implemented in libc++. +/*consteval auto is_pointer_interconvertible_base_of_type(info r, + info s) -> bool { + return extract(substitute(^^is_pointer_interconvertible_base_of_v, + {r, s})); +}*/ + +template > +consteval auto is_invocable_type(info type, R &&args) { + vector targs(from_range, args); + targs.insert(targs.begin(), type); + + return extract(substitute(^^is_invocable_v, targs)); +} + +template > +consteval auto is_invocable_r_type(info result, info type, R &&args) { + vector targs(from_range, args); + targs.insert(targs.begin(), type); + targs.insert(targs.begin(), result); + + return extract(substitute(^^is_invocable_r_v, targs)); +} + +template > +consteval auto is_nothrow_invocable_type(info type, R &&args) { + vector targs(from_range, args); + targs.insert(targs.begin(), type); + + return extract(substitute(^^is_nothrow_invocable_v, targs)); +} + +template > +consteval auto is_nothrow_invocable_r_type(info result, info type, + R &&args) { + vector targs(from_range, args); + targs.insert(targs.begin(), type); + targs.insert(targs.begin(), result); + + return extract(substitute(^^is_nothrow_invocable_r_v, targs)); +} + +consteval auto remove_const(info type) -> info { + return detail::__workaround_expand_compiler_builtins( + detail::__underlying_entity_of(substitute(^^remove_const_t, {type}))); +} + +consteval auto remove_volatile(info type) -> info { + return detail::__workaround_expand_compiler_builtins( + detail::__underlying_entity_of(substitute(^^remove_volatile_t, {type}))); +} + +consteval auto remove_cv(info type) -> info { + return detail::__workaround_expand_compiler_builtins( + detail::__underlying_entity_of(substitute(^^remove_cv_t, {type}))); +} + +consteval auto add_const(info type) -> info { + return detail::__underlying_entity_of(substitute(^^add_const_t, {type})); +} + +consteval auto add_volatile(info type) -> info { + return detail::__underlying_entity_of(substitute(^^add_volatile_t, {type})); +} + +consteval auto add_cv(info type) -> info { + return detail::__underlying_entity_of(substitute(^^add_cv_t, {type})); +} + +consteval auto remove_reference(info type) -> info { + return detail::__workaround_expand_compiler_builtins( + detail::__underlying_entity_of(substitute(^^remove_reference_t, {type}))); +} + +consteval auto add_lvalue_reference(info type) -> info { + return detail::__workaround_expand_compiler_builtins( + detail::__underlying_entity_of(substitute(^^add_lvalue_reference_t, + {type}))); +} + +consteval auto add_rvalue_reference(info type) -> info { + return detail::__workaround_expand_compiler_builtins( + detail::__underlying_entity_of(substitute(^^add_rvalue_reference_t, + {type}))); +} + +consteval auto make_signed(info type) -> info { + return detail::__workaround_expand_compiler_builtins( + detail::__underlying_entity_of(substitute(^^make_signed_t, {type}))); +} + +consteval auto make_unsigned(info type) -> info { + return detail::__workaround_expand_compiler_builtins( + detail::__underlying_entity_of(substitute(^^make_unsigned_t, {type}))); +} + +consteval auto remove_extent(info type) -> info { + return detail::__workaround_expand_compiler_builtins( + detail::__underlying_entity_of(substitute(^^remove_extent_t, {type}))); +} + +consteval auto remove_all_extents(info type) -> info { + return detail::__workaround_expand_compiler_builtins( + detail::__underlying_entity_of(substitute(^^remove_all_extents_t, + {type}))); +} + +consteval auto remove_pointer(info type) -> info { + return detail::__workaround_expand_compiler_builtins( + detail::__underlying_entity_of(substitute(^^remove_pointer_t, {type}))); +} + +consteval auto add_pointer(info type) -> info { + return detail::__workaround_expand_compiler_builtins( + detail::__underlying_entity_of(substitute(^^add_pointer_t, {type}))); +} + +consteval auto remove_cvref(info type) -> info { + return detail::__workaround_expand_compiler_builtins( + detail::__underlying_entity_of(substitute(^^remove_cvref_t, {type}))); +} + +consteval auto decay(info type) -> info { + return detail::__workaround_expand_compiler_builtins( + detail::__underlying_entity_of(substitute(^^decay_t, {type}))); +} + +template > +consteval auto common_type(R &&args) -> info { + return detail::__workaround_expand_compiler_builtins( + detail::__underlying_entity_of(substitute(^^common_type_t, args))); +} + +template > +consteval auto common_reference(R &&args) -> info { + return detail::__underlying_entity_of(substitute(^^common_reference_t, args)); +} + +consteval auto underlying_type(info type) -> info { + return detail::__workaround_expand_compiler_builtins( + detail::__underlying_entity_of(substitute(^^underlying_type_t, {type}))); +} + +template > +consteval auto invoke_result(info type, R &&args) -> info { + vector targs(from_range, args); + targs.insert(targs.begin(), type); + + return detail::__underlying_entity_of(substitute(^^invoke_result_t, targs)); +} + +consteval auto unwrap_reference(info type) -> info { + return detail::__underlying_entity_of(substitute(^^unwrap_reference_t, + {type})); +} + +consteval auto unwrap_ref_decay(info type) -> info { + return detail::__underlying_entity_of(substitute(^^unwrap_ref_decay_t, + {type})); +} + +consteval auto tuple_size(info type) -> size_t { + return extract(substitute(^^tuple_size_v, {type})); +} + +consteval auto tuple_element(size_t index, info type) -> info { + return detail::__underlying_entity_of(substitute(^^tuple_element_t, + {reflect_constant(index), type})); +} + +consteval auto variant_size(info type) -> size_t { + return extract(substitute(^^variant_size_v, {type})); +} + +consteval auto variant_alternative(size_t index, info type) -> info { + return detail::__underlying_entity_of(substitute(^^variant_alternative_t, + {reflect_constant(index), type})); +} + + +namespace detail { +template struct __wrap_workaround { using type = T; }; +consteval auto __workaround_expand_compiler_builtins(info type) -> info { + auto r = substitute(^^__wrap_workaround, {type}); + r = members_of(r, access_context::unchecked())[0]; + return detail::__underlying_entity_of(r); +} + +} // namespace detail + +#if __has_feature(parameter_reflection) + +consteval auto parameters_of(info r) -> vector { + 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; + auto rng = range{r}; + return vector{rng.begin(), rng.end()}; +} + +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); +} + +consteval auto variable_of(info r) -> info { + return __metafunction(detail::__metafn_variable_of, r); +} + +#endif // __has_feature(parameter_reflection) + +#if __has_feature(annotation_attributes) + +consteval auto annotations_of(info r) -> vector { + 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; + auto rng = range{r}; + return vector{rng.begin(), rng.end()}; +} + +consteval auto annotations_of(info r, info ty) -> vector { + 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(); +} + +template +consteval optional annotation_of_type(info r) { + auto v = annotations_of(r, ^^T); + optional result{}; + for (info a: v) { + if (result.has_value()) { + if (extract(a) != result) { + throw "inconsistent annotations"; + } + } else { + result = extract(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) + +consteval auto has_inaccessible_nonstatic_data_members( + info r, + access_context ctx) -> bool { + return !ranges::all_of( + nonstatic_data_members_of(r, access_context::unchecked()), + [=](info m) { return is_accessible(m, ctx); }); +} + +consteval auto has_inaccessible_bases(info r, access_context ctx) -> bool { + return !ranges::all_of(bases_of(r, access_context::unchecked()), + [=](info b) { return is_accessible(b, ctx); }); +} + + // =================================================== + // Other bespoke functions (not proposed at this time) + // =================================================== + +// 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 a reflection of the constant value obtained from calling +// target(args...) +template > +consteval auto reflect_invoke(info target, R &&args) -> info { + if constexpr (ranges::contiguous_range) { + return __metafunction(detail::__metafn_reflect_invoke, target, + static_cast(nullptr), 0, + ranges::data(args), ranges::size(args)); + } else { + vector vargs = args | ranges::to(); + return __metafunction(detail::__metafn_reflect_invoke, target, + static_cast(nullptr), 0, + vargs.data(), vargs.size()); + } +} + +template , + reflection_range R2 = initializer_list> +consteval auto reflect_invoke(info target, R1 &&targs, R2 &&args) -> info { + if constexpr (ranges::contiguous_range) { + if constexpr (ranges::contiguous_range) { + 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(); + return __metafunction(detail::__metafn_reflect_invoke, target, + ranges::data(targs), ranges::size(targs), + vargs.data(), vargs.size()); + } + } else { + vector vtargs = targs | ranges::to(); + if constexpr (ranges::contiguous_range) { + return __metafunction(detail::__metafn_reflect_invoke, target, + vtargs.data(), vtargs.size(), + ranges::data(args), ranges::size(args)); + } else { + vector vargs = args | ranges::to(); + return __metafunction(detail::__metafn_reflect_invoke, target, + vtargs.data(), vtargs.size(), + vargs.data(), vargs.size()); + } + } +} + + // ========================= + // Deprecated names and APIs + // ========================= + +template +[[deprecated("separated into 'reflect_value', 'reflect_result', and " + "'reflect_function' in P2996R4")]] +consteval auto reflect_result(Ty r) -> info { + constexpr auto DTy = detail::__underlying_entity_of(^^Ty); + constexpr auto RTy = is_class_v || + is_reference_v ? + DTy : ^^remove_cv_t; + + return __metafunction(detail::__metafn_reflect_result, + detail::__underlying_entity_of(RTy), + static_cast(r)); +} + +template +[[deprecated("renamed to 'reflect_constant' in P2996R12")]] +consteval auto reflect_value(const T &r) -> info { + return reflect_constant(r); +} + +[[deprecated("renamed to 'constant_of' in P2996R12")]] +consteval auto value_of(info r) -> info { + return constant_of(r); +} + +template > +[[deprecated("removed 'test_type' and 'test_types' in P2996R4")]] +consteval auto test_types(info templ, R &&args) -> bool { + return extract(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(substitute(templ, args)); +} + +[[deprecated("removed 'test_trait' in P2996R5")]] +consteval auto test_trait(info templ, info type) -> bool { + info args[1] = {type}; + return extract(substitute(templ, args)); +} + +template > +[[deprecated("removed 'test_trait' in P2996R5")]] +consteval auto test_trait(info templ, R &&args) -> bool { + return extract(substitute(templ, args)); +} + +template > +[[deprecated("renamed to 'define_aggregate' in P2996R8")]] +consteval auto define_class(info class_type, R &&members) -> info { + return define_aggregate(class_type, members); +} + +[[deprecated("P3547 requires an 'access_context' argument " + "(compile with '-fno-access-contexts' to disable this warning)")]] +consteval auto members_of(info r) -> vector { + return members_of(r, access_context::unchecked()); +} + +[[deprecated("P3547 requires an 'access_context' argument " + "(compile with '-fno-access-contexts' to disable this warning)")]] +consteval auto bases_of(info r) -> vector { + return bases_of(r, access_context::unchecked()); +} + +[[deprecated("P3547 requires an 'access_context' argument " + "(compile with '-fno-access-contexts' to disable this warning)")]] +consteval auto static_data_members_of(info r) -> vector { + return static_data_members_of(r, access_context::unchecked()); +} + +[[deprecated("P3547 requires an 'access_context' argument " + "(compile with '-fno-access-contexts' to disable this warning)")]] +consteval auto nonstatic_data_members_of(info r) -> vector { + return nonstatic_data_members_of(r, access_context::unchecked()); +} + +[[deprecated("replaced with 'is_enumerable_type' in P2996R11")]] +consteval auto has_complete_definition(info r) -> bool { + return __metafunction(detail::__metafn_has_complete_definition, r); +} + +namespace __define_static { + +template +inline constexpr ValTy FixedArray[sizeof...(Vals)] = {Vals...}; + +} // namespace __define_static + +template + requires (is_constructible_v, + ranges::range_reference_t>) +consteval auto reflect_constant_array(R &&elems) -> info { + using ValTy = ranges::range_value_t; + vector Args = {^^ValTy}; + for (const auto &V : elems) + Args.push_back(reflect_constant(V)); + return substitute(^^__define_static::FixedArray, Args); +} + +_LIBCPP_END_NAMESPACE_REFLECTION_V2 + +_LIBCPP_BEGIN_NAMESPACE_STD + +template + requires (is_constructible_v, + ranges::range_reference_t>) +consteval auto define_static_array(R &&elems) + -> span> { + using ValTy = ranges::range_value_t; + meta::info array = meta::reflect_constant_array(elems); + return span(extract(array), meta::extent(type_of(array))); +} + +// Returns a static string having the provided contents. +consteval auto define_static_string(string_view in) -> const char * { + const char nullterm[1] = {0}; + vector> v = {in, nullterm}; + return define_static_array(views::join(v)).data(); +} + +consteval auto define_static_string(u8string_view in) -> const char8_t * { + const char8_t nullterm[1] = {0}; + vector> v = {in, nullterm}; + return define_static_array(views::join(v)).data(); +} + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_BEGIN_NAMESPACE_REFLECTION_V2 + + // ==================================== + // (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 +struct pretty_printer { + static_assert(detail::__underlying_entity_of(^^CharT) == ^^char || + detail::__underlying_entity_of(^^CharT) == ^^char8_t); + static constexpr bool IsUtf8 = is_same_type(^^CharT, ^^char8_t); + + using string_t = basic_string; + + static consteval const CharT *string_constant(string_view contents) { + if constexpr (IsUtf8) { + u8string result(contents.size(), 0); + for (size_t idx = 0; char c : contents) + result[idx++] = char8_t(c); + + return 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 u8symbol_of(Op); + else + return symbol_of(Op); + } + + template + static consteval info type_of_object_from_memptr() { + return [](T C::*) { return ^^C; }(typename [:R:]{}); + }; + + template + static consteval info type_of_member_from_memptr() { + return [](T C::*) { return ^^T; }(typename [:R:]{}); + }; + + template + struct replicator_type { + template + constexpr void operator>>(F body) const { + (body.template operator()(), ...); + } + }; + + template + static constexpr replicator_type replicator = {}; + + template + static consteval auto expand(R range) { + vector args; + for (auto r : range) { + args.push_back(reflect_constant(r)); + } + return substitute(^^replicator, args); + } + + template + requires (has_template_arguments(R)) + static consteval string_t render_template_argument_list_of(); + + template + requires (is_value(R)) + static consteval string_t render_value_as_hex(); + + template + static consteval const CharT *tprint(); + + struct tprint_impl { + template // Null reflection. + requires (R == info{}) + static consteval string_t render() { + return string_constant("(null-reflection)"); + } + + template // Values of fundamental type. + requires (is_value(R) && is_fundamental_type(type_of(R))) + static consteval string_t render(); + + template // Values of aggregate type. + requires (is_value(R) && is_aggregate_type(type_of(R))) + static consteval string_t render(); + + template // Values of pointer type. + requires (is_value(R) && is_pointer_type(type_of(R))) + static consteval string_t render(); + + template // Objects. + requires (is_object(R)) + static consteval string_t render(); + + template // Variables, data members, enumerators. + requires (is_variable(R) || is_nonstatic_data_member(R) || + is_enumerator(R)) + static consteval string_t render(); + + template // Templates. + requires (is_template(R)) + static consteval string_t render(); + + template // Namespaces. + requires (is_namespace(R)) + static consteval string_t render(); + + template // Functions. + requires (is_function(R)) + static consteval string_t render(); + + template // Value types. + requires (is_type(R) && !(is_const(R) || is_volatile(R)) && + !is_pointer_type(R) && !is_array_type(R) && + !is_function_type(R) && !is_reference_type(R) && + !is_member_pointer_type(R)) + static consteval string_t render(); + + template // CV-qualified non-function, non-arry types. + requires (is_type(R) && (is_const(R) || is_volatile(R)) && + !is_array_type(R) && !is_function_type(R)) + static consteval string_t render(); + + template // Reference types. + requires (is_type(R) && !(is_const(R) || is_volatile(R)) && + is_reference_type(R)) + static consteval string_t render(); + + template // Unqualified array types. + requires (is_type(R) && is_array_type(R)) + static consteval string_t render(); + + template // Function types. + requires (is_type(R) && is_function_type(R)) + static consteval string_t render(); + + template // Non-function, non-member pointer types. + requires (is_type(R) && is_pointer_type(R) && + !(is_const(R) || is_volatile(R)) && + !is_function_type(remove_pointer(R))) + static consteval string_t render(); + + template // Function pointer types. + requires (is_type(R) && is_pointer_type(R) && + is_function_type(remove_pointer(R))) + static consteval string_t render(); + + template // Pointer to data member types. + requires (is_type(R) && is_member_pointer_type(R) && + !(is_const(R) || is_volatile(R)) && + !is_member_function_pointer_type(R)) + static consteval string_t render(); + + template // Pointer to member function types. + requires (is_type(R) && is_member_function_pointer_type(R)) + static consteval string_t render(); + + template // Base specifiers. + requires (is_base(R)) + static consteval string_t render(); + + template // Fallback. + static consteval string_t render(); + }; + + static consteval const CharT *print(info R); + + friend consteval auto display_string_of(info) -> string_view; + friend consteval auto u8display_string_of(info) -> u8string_view; + +}; + +template +consteval auto pretty_printer::print(info R) + -> const CharT * { + return extract(reflect_invoke(^^tprint, + {reflect_constant(R)}, {})); +} + +template +template + requires (has_template_arguments(R)) +consteval auto pretty_printer::render_template_argument_list_of() + -> string_t { + string_t result; + + if (template_arguments_of(R).empty()) + return string_constant("<>"); + + size_t Idx = 0; + [:expand(template_arguments_of(R)):] >> [&] { + result += (Idx++ < 1 ? string_constant("<") : string_constant(", ")); + result += tprint_impl::template render(); + }; + return result + string_constant(">"); +} + +template +template + requires (is_value(R)) +consteval auto pretty_printer::render_value_as_hex() -> string_t { + string_t result = string_constant("0x"); + + auto bytes = bit_cast>([: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 +template +consteval auto pretty_printer::tprint() -> const CharT * { + return define_static_string(tprint_impl::template render()); +} + +template +template // Values of fundamental type. + requires(is_value(R) && is_fundamental_type(type_of(R))) +consteval auto pretty_printer::tprint_impl::render() -> string_t { + string_t result; + constexpr info Ty = detail::__underlying_entity_of(type_of(R)); + + if constexpr (Ty == ^^nullptr_t) + result = string_constant("nullptr"); + + if constexpr (is_same_type(Ty, ^^bool)) { + if (extract(R)) + result = string_constant("true"); + else + result = string_constant("false"); + } + + else if constexpr (is_same_type(Ty, ^^char)) { + result = string_constant("'"); + result.append(1, extract(R)); + result += string_constant("'"); + } + + else if constexpr (is_integral_type(Ty) && + detail::__underlying_entity_of(^^CharT) == ^^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 (is_floating_point_type(Ty)) { + result = render_value_as_hex(); + } + + else { + result += string_constant("(value : "); + result += render(); + result += string_constant(")"); + } + + return result; +} + +template +template // Values of aggregate type. + requires(is_value(R) && is_aggregate_type(type_of(R))) +consteval auto pretty_printer::tprint_impl::render() -> string_t { + string_t result = render() + string_constant("{"); + + size_t Idx = 0; + [:expand(nonstatic_data_members_of(type_of(R), + access_context::unchecked())):] >> + [&] { + if (Idx++ > 0) result += string_constant(", "); + result += tprint_impl::render(); + }; + result += string_constant("}"); + + return result; +} + +template +template // Values of pointer type. + requires (is_value(R) && is_pointer_type(type_of(R))) +consteval auto pretty_printer::tprint_impl::render() -> string_t { + return string_constant("(value : ") + render() + + string_constant(")"); +} + +template +template // Objects. + requires (is_object(R)) +consteval auto pretty_printer::tprint_impl::render() -> string_t { + string_t result = string_constant("(object : "); + result += render(); + return result + string_constant(")"); +} + +template +template // Templates. + requires(is_template(R)) +consteval auto pretty_printer::tprint_impl::render() -> string_t { + if constexpr (is_constructor_template(R)) + return render(); + else if (is_operator_function_template(R)) { + operators op = operator_of(R); + + string_t result = "operator"; + switch (op) { + case operators::op_new: + case operators::op_delete: + case operators::op_array_new: + case operators::op_array_delete: + case 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 +template // Namespaces. + requires(is_namespace(R)) +consteval auto pretty_printer::tprint_impl::render() -> string_t { + if (R == ^^::) + return string_constant("(global-namespace)"); + if (!has_identifier(R)) + return string_constant("(anonymous-namespace)"); + + return string_t {identifier_helper(R)}; +} + +template +template // Functions. + requires(is_function(R)) +consteval auto pretty_printer::tprint_impl::render() -> string_t { + string_t result; + + if constexpr (has_template_arguments(R)) { + return render() + render_template_argument_list_of(); + } else if constexpr (is_destructor(R)) { + constexpr info P = parent_of(R); + return string_constant("~") + + render(); + } else if constexpr (is_constructor(R)) { + return render(); + } else if constexpr (is_operator_function(R)) { + operators op = operator_of(R); + + result = "operator"; + switch (op) { + case operators::op_new: + case operators::op_delete: + case operators::op_array_new: + case operators::op_array_delete: + case 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(); +#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 +template // Value types. + requires (is_type(R) && !(is_const(R) || is_volatile(R)) && + !is_pointer_type(R) && !is_array_type(R) && + !is_function_type(R) && !is_reference_type(R) && + !is_member_pointer_type(R)) +consteval auto pretty_printer::tprint_impl::render() -> string_t { + string_t result; + + if constexpr (has_template_arguments(R)) { + return render() + render_template_argument_list_of(); + } else if constexpr (is_fundamental_type(R)) { + if (R == ^^void) return string_constant("void"); + + if (R == ^^decltype(nullptr) || R == ^^nullptr_t) + return string_constant("std::nullptr_t"); + if (R == ^^info || R == detail::__underlying_entity_of(^^info)) + return string_constant("std::meta::info"); + + if (R == ^^bool) return string_constant("bool"); + if (R == ^^signed char) return string_constant("signed char"); + if (R == ^^unsigned char) return string_constant("unsigned char"); + if (R == ^^char) return string_constant("char"); + + if (R == ^^char8_t) return string_constant("char8_t"); + if (R == ^^char16_t) return string_constant("char16_t"); + if (R == ^^char32_t) return string_constant("char32_t"); + + if (R == ^^float) return string_constant("float"); + if (R == ^^double) return string_constant("double"); + if (R == ^^long double) return string_constant("long double"); + + if (is_unsigned_type(R)) result += string_constant("unsigned "); + if constexpr (!is_type_alias(R)) { + auto U = make_signed(R); + if (U == ^^short) return result + string_constant("short"); + if (U == ^^int) return result + string_constant("int"); + if (U == ^^long) return result + string_constant("long"); + if (U == ^^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 +template // CV-qualified non-function, non-array types. + requires (is_type(R) && (is_const(R) || is_volatile(R)) && + !is_array_type(R) && !is_function_type(R)) +consteval auto pretty_printer::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(); +} + +template +template // Reference types. + requires (is_type(R) && !(is_const(R) || is_volatile(R)) && + is_reference_type(R)) +consteval auto pretty_printer::tprint_impl::render() -> string_t { + string_t result = render() + string_constant(" &"); + if (is_rvalue_reference_type(R)) + result += string_constant("&"); + return result; +} + +template +template // Array types. + requires (is_type(R) && is_array_type(R)) +consteval auto pretty_printer::tprint_impl::render() -> string_t { + string_t result = render(); + + for (size_t k = 0; k < rank(R); ++k) { + CharT buffer[32] = {}; + if (!to_chars(begin(buffer), end(buffer), extent(R, k))) + throw "'to_chars' failed to format integeral value"; + + result += "[" + string_t {buffer} + "]"; + } + return result; +} + +template +template // Non-function, non-member pointer types. + requires (is_type(R) && is_pointer_type(R) && + !(is_const(R) || is_volatile(R)) && + !is_function_type(remove_pointer(R))) +consteval auto pretty_printer::tprint_impl::render() -> string_t { + return render() + string_constant(" *"); +} + +template +template // Function pointers. + requires (is_type(R) && is_pointer_type(R) && + is_function_type(remove_pointer(R))) +consteval auto pretty_printer::tprint_impl::render() -> string_t { + +#if __has_feature(parameter_reflection) + constexpr auto FnTy = remove_pointer(R); + string_t result = render() + string_constant("(*)("); + size_t Idx = 0; + [:expand(parameters_of(FnTy)):] >> [&] { + if (Idx++ > 0) result += string_constant(", "); + result += tprint_impl::render(); + }; + result += string_constant(")"); + + if (is_noexcept(FnTy)) + result += string_constant(" noexcept"); +#else + string_t result = string_constant("(function-pointer-type)"); +#endif + + return result; +} + +template +template // Function types. + requires (is_type(R) && is_function_type(R)) +consteval auto pretty_printer::tprint_impl::render() -> string_t { +#if __has_feature(parameter_reflection) + string_t result = render() + string_constant("("); + size_t Idx = 0; + [:expand(parameters_of(R)):] >> [&] { + if (Idx++ > 0) result += string_constant(", "); + result += tprint_impl::render(); + }; + 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 +template // Pointer to data member types. + requires (is_type(R) && is_member_pointer_type(R) && + !(is_const(R) || is_volatile(R)) && + !is_member_function_pointer_type(R)) +consteval auto pretty_printer::tprint_impl::render() -> string_t { + string_t result = render()>() + + string_constant(" "); + result += render()>() + string_constant("::*"); + + return result; +} + +template +template // Pointer to member function types. + requires (is_type(R) && is_member_function_pointer_type(R)) +consteval auto pretty_printer::tprint_impl::render() -> string_t { + constexpr auto FnTy = type_of_member_from_memptr(); + +#if __has_feature(parameter_reflection) + string_t result = render() + string_constant("("); + result += render()>() + + string_constant("::*)("); + + size_t Idx = 0; + [:expand(parameters_of(FnTy)):] >> [&] { + if (Idx++ > 0) result += string_constant(", "); + result += tprint_impl::render(); + }; + 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 +template // Base specifiers. + requires (is_base(R)) +consteval auto pretty_printer::tprint_impl::render() -> string_t { + return string_t {render()}; +} + +template +template // Fallback. +consteval auto pretty_printer::tprint_impl::render() -> string_t { + return string_constant("(unsupported-reflection)"); +} + +template +template // Variables, data members, enumerators. + requires (is_variable(R) || is_nonstatic_data_member(R) || is_enumerator(R)) +consteval auto pretty_printer::tprint_impl::render() -> string_t { + return string_t {identifier_helper(R)}; +} +} // namespace detail + +consteval auto display_string_of(info R) -> string_view { + return detail::pretty_printer::print(R); +} + +consteval auto u8display_string_of(info R) -> u8string_view { + return detail::pretty_printer::print(R); +} + +_LIBCPP_END_NAMESPACE_REFLECTION_V2 + +#endif // __has_feature(reflection) + +#endif // _LIBCPP_META diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index db0cb6d3b91c..215e8a29134c 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1683,6 +1683,11 @@ module std [system] { export * } + module meta { + header "meta" + export "*" + } + module mutex { module lock_guard { header "__mutex/lock_guard.h" } module mutex { header "__mutex/mutex.h" }