18#include <source_location>
26#include <gmp/meta/detail/member_ref.hpp>
47 static constexpr int min = -128;
48 static constexpr int max = 127;
64#define GMP_ENUM_RANGE(Enum, Min, Max) \
66 struct gmp::enum_traits<Enum> { \
67 static constexpr int min = Min; \
68 static constexpr int max = Max; \
81#define GMP_ENUM_VALUES(Enum, ...) \
83 struct gmp::enum_traits<Enum> { \
84 static constexpr auto values = std::to_array({__VA_ARGS__}); \
108concept has_enum_values =
118template<
typename E, fixed_
string P, auto V>
119consteval bool is_valid_enum_value() {
121 if (
name.find(
P.data()) != std::string_view::npos) {
156consteval auto enum_values_scan(std::index_sequence<I...>) {
159 std::array<E, count>
result{};
160 std::size_t index = 0;
162 auto append = [&]<
int V>()
consteval {
164 result[index++] =
static_cast<E>(
V);
168 (append.template
operator()<
Min +
static_cast<int>(
I)>(), ...);
194 static_assert(std::is_enum_v<E>,
"enum_values<E>() requires E to be an enum type");
196 if constexpr (detail::has_enum_values<E>) {
202 static_assert(min <= max,
"enum_traits<E>::min must be <= max");
204 return detail::enum_values_scan<E, P, min>(
205 std::make_index_sequence<
static_cast<std::size_t
>(max - min + 1)>{}
240 static_assert(std::is_enum_v<E>,
"enum_count<E>() requires E to be an enum type");
272template<
auto E, fixed_string
P = fixed_string(
"::")>
274 constexpr auto name = detail::value_name_of<E>();
276 if constexpr (
start != std::string_view::npos) {
277#if GMP_COMPILER_CLANG || GMP_COMPILER_GCC
278 constexpr auto end =
name.find_last_of(
"]");
280 constexpr auto end =
name.find_last_of(
">");
331 constexpr std::size_t size = values.size();
333 if constexpr (size == 0) {
334 return std::array<std::string_view, 0>{};
336 return [&]<std::size_t...
Is>(std::index_sequence<
Is...>) {
337 return std::array<std::string_view, size>{
340 }(std::make_index_sequence<size>{});
358 constexpr std::size_t size = values.size();
360 if constexpr (size == 0) {
361 return std::array<std::pair<E, std::string_view>, 0>{};
363 return [&]<std::size_t...
Is>(std::index_sequence<
Is...>) {
364 return std::array<std::pair<E, std::string_view>, size>{
365 std::pair<E, std::string_view>{ values[
Is],
names[
Is] }...
367 }(std::make_index_sequence<size>{});
382 for (std::size_t
i = 0;
i < values.size(); ++
i) {
383 if (values[
i] == value) {
401 for (
const auto& [value,
n] :
entries) {
413 requires std::is_enum_v<E>
415 return static_cast<std::underlying_type_t<E>
>(value);
422 requires std::is_enum_v<E>
430template<
typename E,
typename U>
431 requires std::is_enum_v<E> && std::is_integral_v<U>
471template<
typename T,
typename...
Args>
472 requires std::is_aggregate_v<std::remove_cvref_t<T>>
478 return static_cast<int>(
sizeof...(Args)) - 1;
497 std::is_class_v<std::remove_cvref_t<T>> &&
498 std::is_aggregate_v<std::remove_cvref_t<T>> &&
554template<std::
size_t I,
typename T>
555 requires std::is_aggregate_v<T> &&
559 constexpr auto name = detail::member_name_of<
567template<std::
size_t I,
typename T>
569 static_assert(std::is_aggregate_v<T>,
"member_name() can only be used with aggregate types.");
635 if constexpr (size == 0) {
636 return std::array<std::string_view, 0>{};
638 return []<std::size_t...
Is>(std::index_sequence<
Is...>) {
639 return (std::array<std::string_view, size> {
642 }(std::make_index_sequence<size>{});
653 for (std::size_t
i = 0;
i <
names.size(); ++
i) {
685template<std::
size_t I,
typename T>
694struct member_type_names_holder {
697 static constexpr auto fixed_names = []<std::size_t...
Is>(std::index_sequence<
Is...>) {
699 }(std::make_index_sequence<N>{});
701 static constexpr auto views = []<std::size_t...
Is>(std::index_sequence<
Is...>) {
702 return std::array<std::string_view, N>{
703 std::get<Is>(fixed_names).to_string_view()...
705 }(std::make_index_sequence<N>{});
744 return detail::member_type_names_holder<T>::views;
759template<std::
size_t I,
typename T,
typename UnqualifiedT = std::remove_cvref_t<T>>
760 requires std::is_aggregate_v<UnqualifiedT>
764 return detail::member_ref<I>(
765 std::forward<T>(value),
771template<std::
size_t I,
typename T,
typename UnqualifiedT = std::remove_cvref_t<T>>
773 static_assert(std::is_aggregate_v<UnqualifiedT>,
"member_ref() can only be used with aggregate types.");
786 return [&]<std::size_t...
Is>(std::index_sequence<
Is...>)
noexcept {
787 return std::forward_as_tuple(
790 }(std::make_index_sequence<size>{});
796template<
typename T,
typename F>
799 noexcept(
noexcept(std::apply(
800 std::forward<F>(
func),
804 std::forward<F>(
func),
811template<
typename T,
typename F, std::size_t...
Is>
812constexpr void for_each_member_impl(T&& value,
F&&
func, std::index_sequence<Is...>)
813 noexcept((std::is_nothrow_invocable_v<
840template<
typename T,
typename F>
843 noexcept(
noexcept(detail::for_each_member_impl(
844 std::forward<T>(value),
845 std::forward<F>(
func),
846 std::make_index_sequence<
member_count_v<std::remove_cvref_t<T>>>{}
848 detail::for_each_member_impl(
849 std::forward<T>(value),
850 std::forward<F>(
func),
851 std::make_index_sequence<
member_count_v<std::remove_cvref_t<T>>>{}
856template<
typename T,
typename F>
859 static_assert(std::is_aggregate_v<value_type>,
860 "for_each_member() can only be used with aggregate types.");
861 if constexpr (std::is_aggregate_v<value_type>) {
862 static_assert(std::is_class_v<value_type>,
863 "for_each_member() does not support arrays or unions.");
865 "for_each_member() does not support this aggregate type.");
876template<
typename T,
typename F>
881 std::forward<T>(value),
886 std::forward<
decltype(member)>(member)
Constraint for aggregate types supported by the reflection helpers.
#define GMP_MAX_SUPPORTED_FIELDS
constexpr constant_arg_t< V > constant_arg
A ready-to-use constant_arg_t<V> object for a compile-time value.
A placeholder type implicitly convertible to any type.
Customize the reflection range or explicit values for an enumeration.
A compile-time string type with fixed length and constexpr operations.
Format a type name for documentation-friendly display.