rx/refl: add C arrays support & reduce binary size

Use StaticString constant to keep only used part of template string
Use bisect for field count query
This commit is contained in:
DH 2025-10-04 14:29:29 +03:00
parent 593297153a
commit 2df7b3871c

View file

@ -1,5 +1,7 @@
#pragma once
#include "StaticString.hpp"
#include <algorithm>
#include <cstddef>
#include <string_view>
@ -14,24 +16,49 @@
namespace rx {
namespace detail {
struct AnyStructFieldQuery {
template <typename T> constexpr operator T &&();
template <typename T> constexpr operator T();
};
template <typename StructT, std::size_t N = 1, std::size_t LastValidCount = 0>
// clang 21 crashes with concept
template <typename, typename, typename = void>
struct IsValidFieldCountImpl : std::false_type {};
template <typename StructT, std::size_t... I>
struct IsValidFieldCountImpl<
StructT, std::index_sequence<I...>,
std::void_t<decltype(StructT{(I, AnyStructFieldQuery{})...})>>
: std::true_type {};
template <typename StructT, std::size_t I>
static constexpr bool IsValidFieldCount =
IsValidFieldCountImpl<StructT,
decltype(std::make_index_sequence<I>{})>::value;
template <typename StructT, std::size_t Min = 1,
std::size_t Max = std::min<std::size_t>(sizeof(StructT), 128),
std::size_t Mid = (Max - Min) / 2>
struct CalcFieldCount;
template <typename StructT, std::size_t Min, std::size_t Max, std::size_t Mid>
requires(Mid < Max && IsValidFieldCount<StructT, Mid>)
struct CalcFieldCount<StructT, Min, Max, Mid>
: CalcFieldCount<StructT, Mid + 1, Max, (Mid + 1 + Max) / 2> {};
template <typename StructT, std::size_t Min, std::size_t Max, std::size_t Mid>
requires(Mid < Max && !IsValidFieldCount<StructT, Mid>)
struct CalcFieldCount<StructT, Min, Max, Mid>
: CalcFieldCount<StructT, Min, Mid, (Min + Mid) / 2> {};
template <typename StructT, std::size_t Min, std::size_t Max, std::size_t Mid>
requires(Mid >= Max)
struct CalcFieldCount<StructT, Min, Max, Mid> {
static constexpr auto count = Min == 0 ? 0
: IsValidFieldCount<StructT, Min> ? Min
: Min - 1;
};
template <typename StructT>
requires std::is_class_v<StructT>
constexpr auto calcFieldCount() {
auto isValidFieldCount = []<std::size_t... I>(std::index_sequence<I...>) {
return requires { StructT(((I, AnyStructFieldQuery{}))...); };
};
if constexpr (isValidFieldCount(std::make_index_sequence<N>())) {
return calcFieldCount<StructT, N + 1, N>();
} else if constexpr (sizeof(StructT) <= N || LastValidCount > 0) {
return LastValidCount;
} else {
return calcFieldCount<StructT, N + 1, LastValidCount>();
}
return CalcFieldCount<StructT>::count;
}
consteval std::string_view unwrapName(std::string_view prefix,
@ -95,38 +122,45 @@ constexpr bool isField<TypeT(BaseT::*)> = true;
} // namespace detail
template <auto &&V> consteval auto getNameOf() {
std::string_view prefix;
template <auto &&V> constexpr auto getNameOf() {
constexpr std::string_view prefix =
#ifdef _MSC_VER
prefix = "getNameOf<";
"getNameOf<";
#else
prefix = "V = ";
"V = ";
#endif
return detail::unwrapName(prefix, RX_PRETTY_FUNCTION, true);
constexpr auto name = detail::unwrapName(prefix, RX_PRETTY_FUNCTION, true);
static constexpr auto result = rx::StaticString<name.size() + 1>{name};
return std::string_view{result};
}
template <auto V>
requires(detail::isField<decltype(V)> ||
std::is_enum_v<std::remove_cvref_t<decltype(V)>> ||
std::is_pointer_v<std::remove_cvref_t<decltype(V)>>)
consteval auto getNameOf() {
std::string_view prefix;
constexpr auto getNameOf() {
constexpr std::string_view prefix =
#ifdef _MSC_VER
prefix = "getNameOf<";
"getNameOf<";
#else
prefix = "V = ";
"V = ";
#endif
return detail::unwrapName(prefix, RX_PRETTY_FUNCTION, true);
constexpr auto name = detail::unwrapName(prefix, RX_PRETTY_FUNCTION, true);
static constexpr auto result = rx::StaticString<name.size() + 1>{name};
return std::string_view{result};
}
template <typename T> consteval auto getNameOf() {
std::string_view prefix;
template <typename T> constexpr auto getNameOf() {
constexpr std::string_view prefix =
#ifdef _MSC_VER
prefix = "getNameOf<";
"getNameOf<";
#else
prefix = "T = ";
"T = ";
#endif
return detail::unwrapName(prefix, RX_PRETTY_FUNCTION, false);
constexpr auto name = detail::unwrapName(prefix, RX_PRETTY_FUNCTION, false);
static constexpr auto result = rx::StaticString<name.size() + 1>{name};
return std::string_view{result};
}
namespace detail {