From 97a102f70604ffc75d05569fca86c0ee74ec04d8 Mon Sep 17 00:00:00 2001 From: Barry Revzin Date: Sun, 29 Jun 2025 08:30:19 -0500 Subject: [PATCH] Improve compile time (#164) * 1. Remove variant usage * 2. Remove * 3. Remove most of --- libcxx/include/meta | 302 ++++++++++-------- .../reflection/define-aggregate.pass.cpp | 1 + .../reflection/entity-classification.pass.cpp | 4 +- .../reflection/entity-proxies.pass.cpp | 2 +- .../experimental/reflection/layout.pass.cpp | 1 + .../reflection/member-classification.pass.cpp | 4 +- .../reflection/member-visibility.pass.cpp | 2 +- .../members-and-subobjects.pass.cpp | 1 + .../experimental/reflection/names.pass.cpp | 2 +- .../reflection/p2996-ex-tuple-cat.pass.cpp | 1 + .../reflection/p3096-fn-parameters.pass.cpp | 1 + .../reflection/p3394-annotations.pass.cpp | 2 +- .../reflection/reflect-invoke.pass.cpp | 4 +- .../reflection/substitute.verify.cpp | 1 + .../reflection/template-arguments.pass.cpp | 2 +- 15 files changed, 178 insertions(+), 152 deletions(-) diff --git a/libcxx/include/meta b/libcxx/include/meta index d5342efb5263..616ca61119e8 100644 --- a/libcxx/include/meta +++ b/libcxx/include/meta @@ -395,12 +395,16 @@ template , */ #include <__config> -#include #include #include #include -#include + +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/size.h> + #include +#include #include #include #include @@ -597,7 +601,7 @@ public: } // pre-incr ++itr; - consteval iterator operator++() { + consteval iterator& operator++() { m_currInfoItr = m_next(m_currInfoItr, m_reflectedEntity, m_nextIndex++); return *this; } @@ -639,6 +643,11 @@ public: { return m_last; } + + consteval vector to_vec() const + { + return vector(m_first, m_last); + } }; template @@ -927,7 +936,7 @@ consteval auto can_substitute(info templ, R &&args) -> bool { sub = __metafunction(detail::__metafn_substitute, templ, ranges::data(args), ranges::size(args), false); } else { - vector vargs = args | ranges::to(); + vector vargs(from_range, args); sub = __metafunction(detail::__metafn_substitute, templ, vargs.data(), vargs.size(), false); } @@ -942,7 +951,7 @@ consteval auto substitute(info templ, R &&args) -> info { return __metafunction(detail::__metafn_substitute, templ, ranges::data(args), ranges::size(args), true); } else { - vector vargs = args | ranges::to(); + vector vargs(from_range, args); return __metafunction(detail::__metafn_substitute, templ, vargs.data(), vargs.size(), true); } @@ -1016,19 +1025,20 @@ consteval auto is_accessible(info r, access_context ctx) -> bool { r, ctx.scope(), ctx.designating_class()); } +template +consteval auto __filtered(vector v, P pred) -> vector { + erase_if(v, [=](info i) { return !pred(i); }); + return v; +} + consteval auto members_of(info r, access_context ctx) -> vector { using iterator = __range_of_infos::iterator<__range_of_infos::front_member_of_fn, __range_of_infos::next_member_of_fn, __range_of_infos::map_decl_to_entity_fn>; using range = __range_of_infos::range; - auto rng = range{r}; - vector v {rng.begin(), rng.end()}; - return vector{ - from_range, - v | views::filter([=](info r) { return is_accessible(r, ctx); }) - }; + return __filtered(range(r).to_vec(), [=](info r) { return is_accessible(r, ctx); }); } // Returns whether the reflected entity is a namespace. @@ -1045,13 +1055,8 @@ consteval auto bases_of(info r, access_context ctx) -> vector { __range_of_infos::next_base_of_fn, __range_of_infos::map_identity_fn>; using range = __range_of_infos::range; - auto rng = range{r}; - vector v {rng.begin(), rng.end()}; - return vector{ - from_range, - v | views::filter([=](info r) { return is_accessible(r, ctx); }) - }; + return __filtered(range(r).to_vec(), [=](info r) { return is_accessible(r, ctx); }); } // Returns whether the reflected entity is a variable. @@ -1064,9 +1069,7 @@ consteval auto static_data_members_of(info r, if (is_namespace(r)) throw "Namespaces cannot have static data members"; - return members_of(r, ctx) | - views::filter(is_variable) | - ranges::to(); + return __filtered(members_of(r, ctx), is_variable); } consteval auto nonstatic_data_members_of(info r, @@ -1074,9 +1077,7 @@ consteval auto nonstatic_data_members_of(info r, if (is_namespace(r)) throw "Namespaces cannot have non-static data members"; - return members_of(r, ctx) | - views::filter(is_nonstatic_data_member) | - ranges::to(); + return __filtered(members_of(r, ctx), is_nonstatic_data_member); } // Returns true if the reflected entity is an enumerable type. @@ -1419,106 +1420,6 @@ consteval auto reflect_function(T &r) -> info { return __metafunction(detail::__metafn_reflect_result, type_of(^^r), r); } -// Representation of a data member which may be passed to 'data_member_spec'. -struct data_member_options { - struct name_type { - variant impl; - - template requires constructible_from - consteval name_type(T &&in) : impl(in_place_type, in) {} - - template requires constructible_from - consteval name_type(T &&in) : impl(in_place_type, in) {} - - private: -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-private-field" - info unused = ^^::; -#pragma clang diagnostic pop - }; - - optional name = nullopt; - optional alignment = nullopt; - optional width = nullopt; - bool no_unique_address = false; -}; - -// Returns the alignment of the reflected entity. -consteval auto alignment_of(info r) -> size_t { - return __metafunction(detail::__metafn_alignment_of, r); -} - -// Returns a reflection representing a description of a data member, which may -// be used with 'define_aggregate' to define a record type. -consteval auto data_member_spec(info member_type, - data_member_options options = {}) -> info { - if (!is_type(member_type)) - throw "'member_type' must represent a type"; - - auto name = options.name.value_or(u8"").impl; - int alignment = options.alignment.value_or(0); - int width = options.width.value_or(0); - bool no_unique_address = options.no_unique_address; - - auto validate = [&](auto name_string) { - if (width) { - if (alignment) - throw "Cannot specify both width and alignment for data member"; - if (no_unique_address) - throw "Cannot specify both width and no_unique_address for data member"; - if (width < 0) - throw "Cannot specify a negative width for data member"; - if (!extract(substitute(^^is_integral_v, {member_type})) && - !extract(substitute(^^is_enum_v, {member_type}))) - throw "Bit field must have integral or enumeral type"; - } else { - if (options.width.has_value() && !name_string.empty()) - throw "Bit-fields of zero width must be unnamed"; - } - - if (alignment) { - if (alignment < int(alignment_of(member_type))) - throw "Cannot specify an alignment less than that of the member type"; - if (alignment <= 0 || ((alignment - 1) & alignment)) - throw "Alignment specifier must be a non-negative power of 2"; - } - }; - - if (holds_alternative(name)) { - const u8string &s = get(name); - validate(s); - return __metafunction(detail::__metafn_data_member_spec, - member_type, - !s.empty(), s.size(), ^^const char8_t, s.data(), - options.alignment.has_value(), alignment, - options.width.has_value(), width, - no_unique_address); - } else { - const string &s = get(name); - validate(s); - return __metafunction(detail::__metafn_data_member_spec, - member_type, - !s.empty(), s.size(), ^^const char, s.data(), - options.alignment.has_value(), alignment, - options.width.has_value(), width, - no_unique_address); - } -} - -// Completes the definition of the record type reflected by 'class_type' with -// the members described by the reflections in the provided range. -template > -consteval auto define_aggregate(info class_type, R &&members) -> info { - if constexpr (ranges::contiguous_range) { - return __metafunction(detail::__metafn_define_aggregate, class_type, - ranges::size(members), ranges::data(members)); - } else { - vector vmembers = members | ranges::to(); - return __metafunction(detail::__metafn_define_aggregate, class_type, - vmembers.size(), vmembers.data()); - } -} - struct member_offset { ptrdiff_t bytes; ptrdiff_t bits; @@ -2122,9 +2023,9 @@ consteval auto annotations_of(info r, info ty) -> vector { if (!is_type(ty)) throw "Expected a reflection of a type"; - return annotations_of(r) | views::filter([=](info annot) { - return type_of(annot) == ty; - }) | ranges::to(); + return __filtered(annotations_of(r), [=](info annot) { + return remove_const(type_of(annot)) == remove_const(ty); + }); } template @@ -2153,17 +2054,23 @@ consteval auto annotate(info entity, info val) -> info { #endif // __has_feature(annotation_attributes) +consteval auto __any_inaccessible(vector const& r, access_context ctx) -> bool { + for (info i : r) { + if (!is_accessible(i, ctx)) { + return true; + } + } + return false; +} + consteval auto has_inaccessible_nonstatic_data_members( info r, access_context ctx) -> bool { - return !ranges::all_of( - nonstatic_data_members_of(r, access_context::unchecked()), - [=](info m) { return is_accessible(m, ctx); }); + return __any_inaccessible(nonstatic_data_members_of(r, access_context::unchecked()), ctx); } consteval auto has_inaccessible_bases(info r, access_context ctx) -> bool { - return !ranges::all_of(bases_of(r, access_context::unchecked()), - [=](info b) { return is_accessible(b, ctx); }); + return __any_inaccessible(bases_of(r, access_context::unchecked()), ctx); } // =================================================== @@ -2184,7 +2091,7 @@ consteval auto reflect_invoke(info target, R &&args) -> info { static_cast(nullptr), 0, ranges::data(args), ranges::size(args)); } else { - vector vargs = args | ranges::to(); + vector vargs(from_range, args); return __metafunction(detail::__metafn_reflect_invoke, target, static_cast(nullptr), 0, vargs.data(), vargs.size()); @@ -2200,19 +2107,19 @@ consteval auto reflect_invoke(info target, R1 &&targs, R2 &&args) -> info { ranges::data(targs), ranges::size(targs), ranges::data(args), ranges::size(args)); } else { - vector vargs = args | ranges::to(); + vector vargs(from_range, args); return __metafunction(detail::__metafn_reflect_invoke, target, ranges::data(targs), ranges::size(targs), vargs.data(), vargs.size()); } } else { - vector vtargs = targs | ranges::to(); + vector vtargs(from_range, targs); if constexpr (ranges::contiguous_range) { return __metafunction(detail::__metafn_reflect_invoke, target, vtargs.data(), vtargs.size(), ranges::data(args), ranges::size(args)); } else { - vector vargs = args | ranges::to(); + vector vargs(from_range, args); return __metafunction(detail::__metafn_reflect_invoke, target, vtargs.data(), vtargs.size(), vargs.data(), vargs.size()); @@ -2220,6 +2127,113 @@ consteval auto reflect_invoke(info target, R1 &&targs, R2 &&args) -> info { } } + +// Representation of a data member which may be passed to 'data_member_spec'. +struct data_member_options { + struct name_type { + bool is_u8; + u8string u8; + string s; + + template requires constructible_from + consteval name_type(T &&in) : is_u8(true), u8((T&&)in) {} + + template requires constructible_from + consteval name_type(T &&in) : is_u8(false), s((T&&)in) {} + + private: +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-private-field" + info unused = ^^::; +#pragma clang diagnostic pop + }; + + optional name = nullopt; + optional alignment = nullopt; + optional width = nullopt; + bool no_unique_address = false; +}; + +// Returns the alignment of the reflected entity. +consteval auto alignment_of(info r) -> size_t { + return __metafunction(detail::__metafn_alignment_of, r); +} + +// Returns a reflection representing a description of a data member, which may +// be used with 'define_aggregate' to define a record type. +consteval auto data_member_spec(info member_type, + data_member_options options = {}) -> info { + if (!is_type(member_type)) + throw "'member_type' must represent a type"; + + bool has_name = options.name.has_value(); + int alignment = options.alignment.value_or(0); + int width = options.width.value_or(0); + bool no_unique_address = options.no_unique_address; + + 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 (!is_integral_type(member_type) && !is_enum_type(member_type)) + throw "Bit field must have integral or enumeration type"; + } else { + if (options.width.has_value() && has_name) + 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 (has_name) { + if (options.name->is_u8) { + const u8string &s = options.name->u8; + return __metafunction(detail::__metafn_data_member_spec, + member_type, + !s.empty(), s.size(), ^^const char8_t, s.data(), + options.alignment.has_value(), alignment, + options.width.has_value(), width, + no_unique_address); + } else { + const string &s = options.name->s; + return __metafunction(detail::__metafn_data_member_spec, + member_type, + !s.empty(), s.size(), ^^const char, s.data(), + options.alignment.has_value(), alignment, + options.width.has_value(), width, + no_unique_address); + } + } else { + return __metafunction(detail::__metafn_data_member_spec, + member_type, + false, 0, ^^const char, "", + options.alignment.has_value(), alignment, + options.width.has_value(), width, + no_unique_address); + } +} + +// Completes the definition of the record type reflected by 'class_type' with +// the members described by the reflections in the provided range. +template > +consteval auto define_aggregate(info class_type, R &&members) -> info { + if constexpr (ranges::contiguous_range) { + return __metafunction(detail::__metafn_define_aggregate, class_type, + ranges::size(members), ranges::data(members)); + } else { + vector vmembers(from_range, members); + return __metafunction(detail::__metafn_define_aggregate, class_type, + vmembers.size(), vmembers.data()); + } +} + // ========================= // Deprecated names and APIs // ========================= @@ -2330,6 +2344,14 @@ consteval auto reflect_constant_string(std::string_view In) -> info { return substitute(^^__define_static::FixedArray, Args); } +consteval auto reflect_constant_string(std::u8string_view In) -> info { + vector Args = {^^char8_t}; + for (char8_t C : In) + Args.push_back(reflect_constant(C)); + Args.push_back(reflect_constant(char8_t{})); + return substitute(^^__define_static::FixedArray, Args); +} + _LIBCPP_END_NAMESPACE_REFLECTION_V2 _LIBCPP_BEGIN_NAMESPACE_STD @@ -2346,15 +2368,13 @@ consteval auto define_static_array(R &&elems) // Returns a static string having the provided contents. consteval auto define_static_string(string_view in) -> const char * { - const char nullterm[1] = {0}; - vector> v = {in, nullterm}; - return define_static_array(views::join(v)).data(); + meta::info array = meta::reflect_constant_string(in); + return extract(array); } consteval auto define_static_string(u8string_view in) -> const char8_t * { - const char8_t nullterm[1] = {0}; - vector> v = {in, nullterm}; - return define_static_array(views::join(v)).data(); + meta::info array = meta::reflect_constant_string(in); + return extract(array); } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/test/std/experimental/reflection/define-aggregate.pass.cpp b/libcxx/test/std/experimental/reflection/define-aggregate.pass.cpp index 1a9e8e1f4a30..dc4d96777cad 100644 --- a/libcxx/test/std/experimental/reflection/define-aggregate.pass.cpp +++ b/libcxx/test/std/experimental/reflection/define-aggregate.pass.cpp @@ -22,6 +22,7 @@ #include #include +#include constexpr auto ctx = std::meta::access_context::unchecked(); diff --git a/libcxx/test/std/experimental/reflection/entity-classification.pass.cpp b/libcxx/test/std/experimental/reflection/entity-classification.pass.cpp index 01c6e44e327b..cac6bc6d5d22 100644 --- a/libcxx/test/std/experimental/reflection/entity-classification.pass.cpp +++ b/libcxx/test/std/experimental/reflection/entity-classification.pass.cpp @@ -17,7 +17,7 @@ #include #include - +#include constexpr auto ctx = std::meta::access_context::current(); @@ -586,7 +586,7 @@ static_assert(is_structured_binding(^^z2)); static_assert(!is_variable(^^x2)); static_assert(!is_variable(^^y2)); static_assert(!is_variable(^^z2)); -// "wrapped" type of each element is +// "wrapped" type of each element is // std::tuple_element>::type // where I is index of tuple field diff --git a/libcxx/test/std/experimental/reflection/entity-proxies.pass.cpp b/libcxx/test/std/experimental/reflection/entity-proxies.pass.cpp index 96ec80c454d2..92363b3d5184 100644 --- a/libcxx/test/std/experimental/reflection/entity-proxies.pass.cpp +++ b/libcxx/test/std/experimental/reflection/entity-proxies.pass.cpp @@ -18,7 +18,7 @@ // [reflection] #include - +#include constexpr auto ctx = std::meta::access_context::current(); constexpr auto unchecked = std::meta::access_context::unchecked(); diff --git a/libcxx/test/std/experimental/reflection/layout.pass.cpp b/libcxx/test/std/experimental/reflection/layout.pass.cpp index 3414bcec27b2..c41f8b7d0807 100644 --- a/libcxx/test/std/experimental/reflection/layout.pass.cpp +++ b/libcxx/test/std/experimental/reflection/layout.pass.cpp @@ -16,6 +16,7 @@ // [reflection] #include +#include using int_alias = int; diff --git a/libcxx/test/std/experimental/reflection/member-classification.pass.cpp b/libcxx/test/std/experimental/reflection/member-classification.pass.cpp index ac0b0c4ccbb9..cb3e1181dc52 100644 --- a/libcxx/test/std/experimental/reflection/member-classification.pass.cpp +++ b/libcxx/test/std/experimental/reflection/member-classification.pass.cpp @@ -17,7 +17,7 @@ // [reflection] #include - +#include constexpr auto ctx = std::meta::access_context::unchecked(); @@ -406,7 +406,7 @@ struct S { void noexcept_true_method() noexcept(true); void noexcept_false_method() noexcept(false); void not_noexcept_method(); - + // virtual methods // w/o defining it complains about vtable virtual void noexcept_virtual_method() noexcept {} diff --git a/libcxx/test/std/experimental/reflection/member-visibility.pass.cpp b/libcxx/test/std/experimental/reflection/member-visibility.pass.cpp index 104e735749bf..8f6b56da96c2 100644 --- a/libcxx/test/std/experimental/reflection/member-visibility.pass.cpp +++ b/libcxx/test/std/experimental/reflection/member-visibility.pass.cpp @@ -16,7 +16,7 @@ // [reflection] #include - +#include using std::meta::access_context; diff --git a/libcxx/test/std/experimental/reflection/members-and-subobjects.pass.cpp b/libcxx/test/std/experimental/reflection/members-and-subobjects.pass.cpp index dbaff25219bc..bf9065e1d3d6 100644 --- a/libcxx/test/std/experimental/reflection/members-and-subobjects.pass.cpp +++ b/libcxx/test/std/experimental/reflection/members-and-subobjects.pass.cpp @@ -20,6 +20,7 @@ #include #include +#include #include diff --git a/libcxx/test/std/experimental/reflection/names.pass.cpp b/libcxx/test/std/experimental/reflection/names.pass.cpp index bc121c4af91b..982107471248 100644 --- a/libcxx/test/std/experimental/reflection/names.pass.cpp +++ b/libcxx/test/std/experimental/reflection/names.pass.cpp @@ -17,7 +17,7 @@ // [reflection] #include - +#include constexpr auto ctx = std::meta::access_context::unchecked(); diff --git a/libcxx/test/std/experimental/reflection/p2996-ex-tuple-cat.pass.cpp b/libcxx/test/std/experimental/reflection/p2996-ex-tuple-cat.pass.cpp index 68267e62093e..132aa4fda22c 100644 --- a/libcxx/test/std/experimental/reflection/p2996-ex-tuple-cat.pass.cpp +++ b/libcxx/test/std/experimental/reflection/p2996-ex-tuple-cat.pass.cpp @@ -20,6 +20,7 @@ #include +#include #include #include #include diff --git a/libcxx/test/std/experimental/reflection/p3096-fn-parameters.pass.cpp b/libcxx/test/std/experimental/reflection/p3096-fn-parameters.pass.cpp index 4e0a32d696ff..d340a3548e82 100644 --- a/libcxx/test/std/experimental/reflection/p3096-fn-parameters.pass.cpp +++ b/libcxx/test/std/experimental/reflection/p3096-fn-parameters.pass.cpp @@ -17,6 +17,7 @@ // [reflection] #include +#include constexpr auto ctx = std::meta::access_context::unchecked(); diff --git a/libcxx/test/std/experimental/reflection/p3394-annotations.pass.cpp b/libcxx/test/std/experimental/reflection/p3394-annotations.pass.cpp index da352e1a5ee5..cc5595522e06 100644 --- a/libcxx/test/std/experimental/reflection/p3394-annotations.pass.cpp +++ b/libcxx/test/std/experimental/reflection/p3394-annotations.pass.cpp @@ -17,7 +17,7 @@ // [reflection] #include - +#include // ========== // empty_case diff --git a/libcxx/test/std/experimental/reflection/reflect-invoke.pass.cpp b/libcxx/test/std/experimental/reflection/reflect-invoke.pass.cpp index 1a4f66c47342..71815e5f3e44 100644 --- a/libcxx/test/std/experimental/reflection/reflect-invoke.pass.cpp +++ b/libcxx/test/std/experimental/reflection/reflect-invoke.pass.cpp @@ -19,7 +19,7 @@ #include #include - +#include constexpr auto ctx = std::meta::access_context::unchecked(); @@ -177,7 +177,7 @@ struct Cls { template consteval Cls(T) : value(sizeof(T)) {} }; -constexpr auto ctor = +constexpr auto ctor = (members_of(^^Cls, ctx) | std::views::filter(std::meta::is_constructor) | std::views::filter(std::meta::is_user_provided)).front(); diff --git a/libcxx/test/std/experimental/reflection/substitute.verify.cpp b/libcxx/test/std/experimental/reflection/substitute.verify.cpp index 78b05c1c4500..89e34f5476eb 100644 --- a/libcxx/test/std/experimental/reflection/substitute.verify.cpp +++ b/libcxx/test/std/experimental/reflection/substitute.verify.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include diff --git a/libcxx/test/std/experimental/reflection/template-arguments.pass.cpp b/libcxx/test/std/experimental/reflection/template-arguments.pass.cpp index fa1cc7ab24c1..4cddd48d4668 100644 --- a/libcxx/test/std/experimental/reflection/template-arguments.pass.cpp +++ b/libcxx/test/std/experimental/reflection/template-arguments.pass.cpp @@ -16,7 +16,7 @@ // [reflection] #include - +#include constexpr auto ctx = std::meta::access_context::unchecked();