// <meta> -*- C++ -*-

// Copyright (C) 2025-2026 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library.  This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.

// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.

// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
// <http://www.gnu.org/licenses/>.

/** @file include/meta
 *  This is a Standard C++ Library header.
 */

#ifndef _GLIBCXX_META
#define _GLIBCXX_META 1

#ifdef _GLIBCXX_SYSHDR
#pragma GCC system_header
#endif

#define __glibcxx_want_reflection
#define __glibcxx_want_define_static
#include <bits/version.h>

#if __glibcxx_reflection >= 202603L // C++ >= 26 && __cpp_impl_reflection

#include <array>
#include <initializer_list>
#include <optional>
#include <source_location>
#include <span>
#include <string>
#include <string_view>
#include <vector>

namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION

#if __has_builtin(__builtin_is_string_literal)
  // [meta.string.literal], checking string literals
  consteval bool is_string_literal(const char* __p)
  {
    return __builtin_is_string_literal(__p);
  }

  consteval bool is_string_literal(const wchar_t* __p)
  {
    return __builtin_is_string_literal(__p);
  }

#ifdef _GLIBCXX_USE_CHAR8_T
  consteval bool is_string_literal(const char8_t* __p)
  {
    return __builtin_is_string_literal(__p);
  }
#endif

  consteval bool is_string_literal(const char16_t* __p)
  {
    return __builtin_is_string_literal(__p);
  }

  consteval bool is_string_literal(const char32_t* __p)
  {
    return __builtin_is_string_literal(__p);
  }
#endif

  namespace meta
  {
    using info = decltype(^^int);

    // [meta.reflection.exception], class exception
    class exception : public std::exception {
    private:
      string _M_what;
      u8string _M_u8what;
      info _M_from;
      source_location _M_where;

    public:
      consteval
      exception(u8string_view __what, info __from,
		source_location __where = source_location::current()) noexcept
	: _M_what{_S_exception_cvt_from_utf8(__what)}, _M_u8what{__what},
	  _M_from{__from}, _M_where{__where} {}

      consteval
      exception(string_view __what, info __from,
		source_location __where = source_location::current()) noexcept
	: _M_what{__what}, _M_u8what{_S_exception_cvt_to_utf8(__what)},
	  _M_from{__from}, _M_where{__where} {}

      consteval exception(const exception&) = default;
      consteval exception(exception&&) = default;

      consteval exception& operator=(const exception&) = default;
      consteval exception& operator=(exception&&) = default;

      consteval const char*
      what() const noexcept override
      {
	// If u8string is not empty and string is empty, conversion
	// from UTF-8 to ordinary literal encoding failed.
	// In that case what() should be non-constant.
	if (_M_what.size() == 0 && _M_u8what.size() != 0)
#if __has_builtin(__builtin_constexpr_diag)
	  __builtin_constexpr_diag (2, "",
				    "std::meta::exception message could not "
				    "be successfully transcoded from UTF-8 to "
				    "ordinary literal encoding");
#else
	  __asm__("");
#endif
	return _M_what.c_str();
      }
      consteval u8string_view u8what() const noexcept { return _M_u8what; }
      consteval info from() const noexcept { return _M_from; }
      consteval source_location where() const noexcept { return _M_where; }
    private:
      // Helper special template metafunctions to convert from UTF-8 to
      // ordinary literal encoding and vice versa.  On conversion failure
      // they just return an empty {,u8}string_view.
      template<ranges::input_range _Rg>
	static consteval u8string_view _S_exception_cvt_to_utf8(_Rg&&);
      template<ranges::input_range _Rg>
	static consteval string_view _S_exception_cvt_from_utf8(_Rg&&);
    };

    // [meta.reflection.operators], operator representations
    enum class operators {
      op_new = 1,
      op_delete,
      op_array_new,
      op_array_delete,
      op_co_await,
      op_parentheses,
      op_square_brackets,
      op_arrow,
      op_arrow_star,
      op_tilde,
      op_exclamation,
      op_plus,
      op_minus,
      op_star,
      op_slash,
      op_percent,
      op_caret,
      op_ampersand,
      op_equals,
      op_pipe,
      op_plus_equals,
      op_minus_equals,
      op_star_equals,
      op_slash_equals,
      op_percent_equals,
      op_caret_equals,
      op_ampersand_equals,
      op_pipe_equals,
      op_equals_equals,
      op_exclamation_equals,
      op_less,
      op_greater,
      op_less_equals,
      op_greater_equals,
      op_spaceship,
      op_ampersand_ampersand,
      op_pipe_pipe,
      op_less_less,
      op_greater_greater,
      op_less_less_equals,
      op_greater_greater_equals,
      op_plus_plus,
      op_minus_minus,
      op_comma
    };
    using enum operators;
    consteval operators operator_of(info);
    consteval string_view symbol_of(operators);
    consteval u8string_view u8symbol_of(operators);

    // [meta.reflection.names], reflection names and locations
    consteval bool has_identifier(info);

    consteval string_view identifier_of(info);
    consteval u8string_view u8identifier_of(info);

    consteval string_view display_string_of(info);
    consteval u8string_view u8display_string_of(info);

    consteval source_location source_location_of(info);

    // [meta.reflection.queries], reflection queries
    consteval info type_of(info);
    consteval info object_of(info);
    consteval info constant_of(info);

    consteval bool is_public(info);
    consteval bool is_protected(info);
    consteval bool is_private(info);

    consteval bool is_virtual(info);
    consteval bool is_pure_virtual(info);
    consteval bool is_override(info);
    consteval bool is_final(info);

    consteval bool is_deleted(info);
    consteval bool is_defaulted(info);
    consteval bool is_user_provided(info);
    consteval bool is_user_declared(info);
    consteval bool is_explicit(info);
    consteval bool is_noexcept(info);

    consteval bool is_bit_field(info);
    consteval bool is_enumerator(info);
    consteval bool is_annotation(info);

    consteval bool is_const(info);
    consteval bool is_volatile(info);
    consteval bool is_mutable_member(info);
    consteval bool is_lvalue_reference_qualified(info);
    consteval bool is_rvalue_reference_qualified(info);

    consteval bool has_static_storage_duration(info);
    consteval bool has_thread_storage_duration(info);
    consteval bool has_automatic_storage_duration(info);

    consteval bool has_internal_linkage(info);
    consteval bool has_module_linkage(info);
    consteval bool has_external_linkage(info);
    consteval bool has_c_language_linkage(info);
    consteval bool has_linkage(info);

    consteval bool is_complete_type(info);
    consteval bool is_enumerable_type(info);

    consteval bool is_variable(info);
    consteval bool is_type(info);
    consteval bool is_namespace(info);
    consteval bool is_type_alias(info);
    consteval bool is_namespace_alias(info);

    consteval bool is_function(info);
    consteval bool is_conversion_function(info);
    consteval bool is_operator_function(info);
    consteval bool is_literal_operator(info);
    consteval bool is_special_member_function(info);
    consteval bool is_constructor(info);
    consteval bool is_default_constructor(info);
    consteval bool is_copy_constructor(info);
    consteval bool is_move_constructor(info);
    consteval bool is_assignment(info);
    consteval bool is_copy_assignment(info);
    consteval bool is_move_assignment(info);
    consteval bool is_destructor(info);

    consteval bool is_function_parameter(info);
    consteval bool is_explicit_object_parameter(info);
    consteval bool has_default_argument(info);
    consteval bool is_vararg_function(info);

    consteval bool is_template(info);
    consteval bool is_function_template(info);
    consteval bool is_variable_template(info);
    consteval bool is_class_template(info);
    consteval bool is_alias_template(info);
    consteval bool is_conversion_function_template(info);
    consteval bool is_operator_function_template(info);
    consteval bool is_literal_operator_template(info);
    consteval bool is_constructor_template(info);
    consteval bool is_concept(info);

    consteval bool is_value(info);
    consteval bool is_object(info);

    consteval bool is_structured_binding(info);

    consteval bool is_class_member(info);
    consteval bool is_namespace_member(info);
    consteval bool is_nonstatic_data_member(info);
    consteval bool is_static_member(info);
    consteval bool is_base(info);

    consteval bool has_default_member_initializer(info);

    consteval bool has_parent(info);
    consteval info parent_of(info);

    consteval info dealias(info);

    consteval bool has_template_arguments(info);
    consteval info template_of(info);
    consteval vector<info> template_arguments_of(info);
    consteval vector<info> parameters_of(info);
    consteval info variable_of(info);
    consteval info return_type_of(info);

    // [meta.reflection.access.context], access control context
    struct access_context {
    private:
      consteval access_context(info __scope, info __designating_class) noexcept
	: _M_scope{__scope}, _M_designating_class{__designating_class} { }
    public:
      access_context() = delete;
      consteval access_context(const access_context &) = default;
      consteval access_context(access_context &&) = default;

      consteval info scope() const { return _M_scope; }
      consteval info designating_class() const { return _M_designating_class; }

      static consteval access_context current() noexcept;
      static consteval access_context unprivileged() noexcept
      { return access_context { ^^::, info {} }; }
      static consteval access_context unchecked() noexcept
      { return access_context { info {}, info {} }; }
      consteval access_context via(info) const;

      info _M_scope;
      info _M_designating_class;
    };

    // [meta.reflection.access.queries], member accessibility queries
    consteval bool is_accessible(info, access_context);
    consteval bool has_inaccessible_nonstatic_data_members(info,
							   access_context);
    consteval bool has_inaccessible_bases(info, access_context);
    consteval bool has_inaccessible_subobjects(info, access_context);

    // [meta.reflection.scope], scope identification
    consteval info current_function();
    consteval info current_class();
    consteval info current_namespace();

    // [meta.reflection.member.queries], reflection member queries
    consteval vector<info> members_of(info, access_context);
    consteval vector<info> bases_of(info, access_context);
    consteval vector<info> static_data_members_of(info, access_context);
    consteval vector<info> nonstatic_data_members_of(info, access_context);
    consteval vector<info> subobjects_of(info, access_context);
    consteval vector<info> enumerators_of(info);

    // [meta.reflection.layout], reflection layout queries
    struct member_offset {
      ptrdiff_t bytes;
      ptrdiff_t bits;

      constexpr ptrdiff_t
      total_bits() const
      { return bytes * __CHAR_BIT__ + bits; }

      auto operator<=>(const member_offset&) const = default;
    };

    consteval member_offset offset_of(info);
    consteval size_t size_of(info);
    consteval size_t alignment_of(info);
    consteval size_t bit_size_of(info);

    // [meta.reflection.extract], value extraction
    template<class _Tp>
      consteval _Tp extract(info);

    // [meta.reflection.substitute], reflection substitution
    template<class _Rg>
      concept reflection_range = ranges::input_range<_Rg>
	&& same_as<ranges::range_value_t<_Rg>, info>
	&& same_as<remove_cvref_t<ranges::range_reference_t<_Rg>>, info>;

    template<reflection_range _Rg = initializer_list<info>>
      consteval bool can_substitute(info, _Rg&&);
    template<reflection_range _Rg = initializer_list<info>>
      consteval info substitute(info, _Rg&&);

    // [meta.reflection.result], expression result reflection
    template<typename _Tp>
      requires (is_copy_constructible_v<_Tp>)
      consteval info reflect_constant(_Tp);
    template<typename _Tp>
      requires (!is_function_v<remove_reference_t<_Tp>>)
      consteval info reflect_object(_Tp&);
    template<typename _Tp>
      requires (is_function_v<remove_reference_t<_Tp>>)
      consteval info reflect_function(_Tp&);

    // [meta.reflection.array], promoting to static storage arrays
    template<ranges::input_range _Rg>
      consteval info reflect_constant_string(_Rg&&);

    template<ranges::input_range _Rg>
      consteval info reflect_constant_array(_Rg&&);

    // [meta.reflection.define.aggregate], class definition generation
    struct data_member_options {
      struct _Name {
	template<class _Tp>
	  requires constructible_from<u8string, _Tp>
	  consteval _Name(_Tp&& __n) : _M_is_u8(true), _M_u8s((_Tp&&) __n) {}

	template<class _Tp>
	  requires constructible_from<string, _Tp>
	  consteval _Name(_Tp&& __n) : _M_is_u8(false), _M_s((_Tp&&) __n) {}

      private:
	bool _M_is_u8;
	u8string _M_u8s;
	string _M_s;
	info _M_unused = {};
      };

      optional<_Name> name;
      optional<int> alignment = {};
      optional<int> bit_width = {};
      bool no_unique_address = false;
      vector<info> annotations = {};
    };
    consteval info data_member_spec(info, data_member_options);
    consteval bool is_data_member_spec(info);
    template<reflection_range _Rg = initializer_list<info>>
      consteval info define_aggregate(info, _Rg&&);

    // associated with [meta.unary.cat], primary type categories
    consteval bool is_void_type(info);
    consteval bool is_null_pointer_type(info);
    consteval bool is_integral_type(info);
    consteval bool is_floating_point_type(info);
    consteval bool is_array_type(info);
    consteval bool is_pointer_type(info);
    consteval bool is_lvalue_reference_type(info);
    consteval bool is_rvalue_reference_type(info);
    consteval bool is_member_object_pointer_type(info);
    consteval bool is_member_function_pointer_type(info);
    consteval bool is_enum_type(info);
    consteval bool is_union_type(info);
    consteval bool is_class_type(info);
    consteval bool is_function_type(info);
    consteval bool is_reflection_type(info);

    // associated with [meta.unary.comp], composite type categories
    consteval bool is_reference_type(info);
    consteval bool is_arithmetic_type(info);
    consteval bool is_fundamental_type(info);
    consteval bool is_object_type(info);
    consteval bool is_scalar_type(info);
    consteval bool is_compound_type(info);
    consteval bool is_member_pointer_type(info);

    // associated with [meta.unary.prop], type properties
    consteval bool is_const_type(info);
    consteval bool is_volatile_type(info);
    consteval bool is_trivially_copyable_type(info);
    consteval bool is_standard_layout_type(info);
    consteval bool is_empty_type(info);
    consteval bool is_polymorphic_type(info);
    consteval bool is_abstract_type(info);
    consteval bool is_final_type(info);
    consteval bool is_aggregate_type(info);
#if __glibcxx_is_structural >= 202603L
    consteval bool is_structural_type(info);
#endif
    consteval bool is_signed_type(info);
    consteval bool is_unsigned_type(info);
    consteval bool is_bounded_array_type(info);
    consteval bool is_unbounded_array_type(info);
    consteval bool is_scoped_enum_type(info);

    template<reflection_range _Rg = initializer_list<info>>
      consteval bool is_constructible_type(info, _Rg&&);
    consteval bool is_default_constructible_type(info);
    consteval bool is_copy_constructible_type(info);
    consteval bool is_move_constructible_type(info);

    consteval bool is_assignable_type(info, info);
    consteval bool is_copy_assignable_type(info);
    consteval bool is_move_assignable_type(info);

    consteval bool is_swappable_with_type(info, info);
    consteval bool is_swappable_type(info);

    consteval bool is_destructible_type(info);

    template<reflection_range _Rg = initializer_list<info>>
      consteval bool is_trivially_constructible_type(info, _Rg&&);
    consteval bool is_trivially_default_constructible_type(info);
    consteval bool is_trivially_copy_constructible_type(info);
    consteval bool is_trivially_move_constructible_type(info);

    consteval bool is_trivially_assignable_type(info, info);
    consteval bool is_trivially_copy_assignable_type(info);
    consteval bool is_trivially_move_assignable_type(info);
    consteval bool is_trivially_destructible_type(info);

    template<reflection_range _Rg = initializer_list<info>>
      consteval bool is_nothrow_constructible_type(info, _Rg&&);
    consteval bool is_nothrow_default_constructible_type(info);
    consteval bool is_nothrow_copy_constructible_type(info);
    consteval bool is_nothrow_move_constructible_type(info);

    consteval bool is_nothrow_assignable_type(info, info);
    consteval bool is_nothrow_copy_assignable_type(info);
    consteval bool is_nothrow_move_assignable_type(info);

    consteval bool is_nothrow_swappable_with_type(info, info);
    consteval bool is_nothrow_swappable_type(info);

    consteval bool is_nothrow_destructible_type(info);

    consteval bool is_implicit_lifetime_type(info);

    consteval bool has_virtual_destructor(info);

    consteval bool has_unique_object_representations(info);

    consteval bool reference_constructs_from_temporary(info, info);
    consteval bool reference_converts_from_temporary(info, info);

    // associated with [meta.unary.prop.query], type property queries
    consteval size_t rank(info);
    consteval size_t extent(info, unsigned = 0);

    // associated with [meta.rel], type relations
    consteval bool is_same_type(info, info);
    consteval bool is_base_of_type(info, info);
    consteval bool is_virtual_base_of_type(info, info);
    consteval bool is_convertible_type(info, info);
    consteval bool is_nothrow_convertible_type(info, info);
    consteval bool is_layout_compatible_type(info, info);
    consteval bool is_pointer_interconvertible_base_of_type(info, info);

    template<reflection_range _Rg = initializer_list<info>>
      consteval bool is_invocable_type(info, _Rg&&);
    template<reflection_range _Rg = initializer_list<info>>
      consteval bool is_invocable_r_type(info, info, _Rg&&);

    template<reflection_range _Rg = initializer_list<info>>
      consteval bool is_nothrow_invocable_type(info, _Rg&&);
    template<reflection_range _Rg = initializer_list<info>>
      consteval bool is_nothrow_invocable_r_type(info, info, _Rg&&);

    // associated with [meta.trans.cv], const-volatile modifications
    consteval info remove_const(info);
    consteval info remove_volatile(info);
    consteval info remove_cv(info);
    consteval info add_const(info);
    consteval info add_volatile(info);
    consteval info add_cv(info);

    // associated with [meta.trans.ref], reference modifications
    consteval info remove_reference(info);
    consteval info add_lvalue_reference(info);
    consteval info add_rvalue_reference(info);

    // associated with [meta.trans.sign], sign modifications
    consteval info make_signed(info);
    consteval info make_unsigned(info);

    // associated with [meta.trans.arr], array modifications
    consteval info remove_extent(info);
    consteval info remove_all_extents(info);

    // associated with [meta.trans.ptr], pointer modifications
    consteval info remove_pointer(info);
    consteval info add_pointer(info);

    // associated with [meta.trans.other], other transformations
    consteval info remove_cvref(info);
    consteval info decay(info);
    template<reflection_range _Rg = initializer_list<info>>
      consteval info common_type(_Rg&&);
    template<reflection_range _Rg = initializer_list<info>>
      consteval info common_reference(_Rg&&);
    consteval info underlying_type(info);
    template<reflection_range _Rg = initializer_list<info>>
      consteval info invoke_result(info, _Rg&&);
    consteval info unwrap_reference(info);
    consteval info unwrap_ref_decay(info);

    consteval size_t tuple_size(info);
    consteval info tuple_element(size_t, info);

    consteval size_t variant_size(info);
    consteval info variant_alternative(size_t, info);

    consteval strong_ordering type_order(info, info);

    // [meta.reflection.annotation], annotation reflection
    consteval vector<info> annotations_of(info);
    consteval vector<info> annotations_of_with_type(info, info);

    consteval access_context
    access_context::via(info __cls) const
    {
      if (__cls != info {}
	  && (!std::meta::is_type(__cls)
	      || !std::meta::is_class_type(__cls)
	      || !std::meta::is_complete_type(__cls)))
	{
#if __cpp_exceptions
	  throw std::meta::exception(u8"via argument other than null "
				       "or complete class type reflection",
				     ^^access_context::via);
#else
#if __has_builtin(__builtin_constexpr_diag)
	  __builtin_constexpr_diag (2, "",
				    "std::meta::access_context::via argument "
				    "other than null or complete class type "
				    "reflection");
#else
	  __asm__("");
#endif
	  return *this;
#endif
	}
      return access_context { _M_scope, __cls };
    }

  } // namespace meta

  // [meta.define.static], promoting to static storage strings
  template<ranges::input_range _Rg>
    consteval const ranges::range_value_t<_Rg>*
    define_static_string(_Rg&& __r)
    {
      auto __str = meta::reflect_constant_string(__r);
      return meta::extract<const ranges::range_value_t<_Rg>*>(__str);
    }

  namespace __detail
  {
    template<typename _Rg>
    concept __statically_sized
      = requires(_Rg&& __r) {
	static_cast<char(*)[static_cast<size_t>(ranges::size(__r))
			    >= 0]>(nullptr);
      };
  } // namespace __detail

  template<ranges::input_range _Rg>
    consteval auto
    define_static_array(_Rg&& __r)
    {
      using _Tp = ranges::range_value_t<_Rg>;
      auto __array = meta::reflect_constant_array(__r);
      auto __type = meta::type_of(__array);
      if constexpr (__detail::__statically_sized<_Rg>)
	{
	  constexpr size_t __extent = static_cast<size_t>(ranges::size(__r));
	  if constexpr (__extent)
	    return span<const _Tp,
			__extent>(meta::extract<const _Tp*>(__array),
				  meta::extent(__type, 0U));
	  else
	    return span<const _Tp, 0>();
	}
      else
	{
	  if (meta::is_array_type(__type))
	    return span<const _Tp>(meta::extract<const _Tp*>(__array),
				   meta::extent(__type, 0U));
	  else
	    return span<const _Tp>();
	}
    }

  template<class _Tp>
    consteval const remove_cvref_t<_Tp>*
    define_static_object(_Tp&& __t)
    {
      using _Up = remove_cvref_t<_Tp>;
      if constexpr (meta::is_class_type(^^_Up) || meta::is_union_type(^^_Up))
	{
	  auto __cst = meta::reflect_constant(std::forward<_Tp>(__t));
	  return std::addressof(meta::extract<const _Up&>(__cst));
	}
      else if constexpr (meta::is_array_type(^^_Up))
	{
	  auto __cst = meta::reflect_constant_array(std::forward<_Tp>(__t));
	  return std::addressof(meta::extract<const _Up&>(__cst));
	}
      else
	return std::define_static_array(span(std::addressof(__t), 1)).data();
    }

_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std

#endif // C++26

#endif // _GLIBCXX_META
