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