#ifndef RFL_INTERNAL_GETFIELDNAMES_HPP_ #define RFL_INTERNAL_GETFIELDNAMES_HPP_ #include #include #if __has_include() #include #endif #include "../Literal.hpp" #include "get_ith_field_from_fake_object.hpp" #include "is_flatten_field.hpp" #include "is_rename.hpp" #include "num_fields.hpp" #if __GNUC__ #ifndef __clang__ #pragma GCC system_header #endif #endif namespace rfl::internal { template struct Wrapper { using Type = T; T v; }; template Wrapper(T) -> Wrapper; // This workaround is necessary for clang. template constexpr auto wrap(const T& arg) noexcept { return Wrapper{arg}; } template consteval auto get_field_name_str_view() { #if __cpp_lib_source_location >= 201907L const auto func_name = std::string_view{std::source_location::current().function_name()}; #elif defined(_MSC_VER) // Officially, we only support MSVC versions that are modern enough to contain // , but inofficially, this might work. const auto func_name = std::string_view{__FUNCSIG__}; #else const auto func_name = std::string_view{__PRETTY_FUNCTION__}; #endif #if defined(__clang__) const auto split = func_name.substr(0, func_name.size() - 2); return split.substr(split.find_last_of(":.") + 1); #elif defined(__GNUC__) const auto split = func_name.substr(0, func_name.size() - 2); return split.substr(split.find_last_of(":") + 1); #elif defined(_MSC_VER) const auto split = func_name.substr(0, func_name.size() - 7); return split.substr(split.rfind("->") + 2); #else static_assert(false, "You are using an unsupported compiler. Please use GCC, Clang " "or MSVC or switch to the rfl::Field-syntax."); #endif } template consteval auto get_field_name_str_lit() { constexpr auto name = get_field_name_str_view(); const auto to_str_lit = [&](std::index_sequence) { return StringLiteral{name[Ns]...}; }; return to_str_lit(std::make_index_sequence{}); } template auto get_field_names(); template auto get_field_name() { #if defined(__clang__) using Type = std::remove_cvref_t::Type>>; #else using Type = std::remove_cvref_t>; #endif if constexpr (is_rename_v) { using Name = typename Type::Name; return Name(); } else if constexpr (is_flatten_field_v) { return get_field_names>(); } else { return rfl::Literal()>(); } } // We don't want the operator+ to apply to normal literals, // so we introduce this wrapper. template struct LiteralWrapper { Literal<_names...> literal_; }; template auto wrap_literal(const Literal<_names...>& _literal) { return LiteralWrapper<_names...>{_literal}; } template auto operator+(const LiteralWrapper<_names1...>&, const LiteralWrapper<_names2...>&) { return LiteralWrapper<_names1..., _names2...>{ rfl::Literal<_names1..., _names2...>::template from_value<0>()}; } template auto concat_literals(const Head& _head, const Tail&... _tail) { return (wrap_literal(_head) + ... + wrap_literal(_tail)).literal_; } // Special case - the struct does not contain rfl::Flatten. template auto concat_literals(const rfl::Literal<_head>&, const rfl::Literal<_tail>&...) { return rfl::Literal<_head, _tail...>::template from_value<0>(); } inline auto concat_literals() { return rfl::Literal<>(); } #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wundefined-var-template" #pragma clang diagnostic ignored "-Wundefined-inline" #endif template #if __GNUC__ #ifndef __clang__ [[gnu::no_sanitize_undefined]] #endif #endif auto get_field_names() { using Type = std::remove_cvref_t; if constexpr (std::is_pointer_v) { return get_field_names>(); } else { #if defined(__clang__) const auto get = [](std::index_sequence<_is...>) { return concat_literals( get_field_name())>()...); }; #else const auto get = [](std::index_sequence<_is...>) { return concat_literals( get_field_name()>()...); }; #endif return get(std::make_index_sequence>()); } } #ifdef __clang__ #pragma clang diagnostic pop #endif } // namespace rfl::internal #endif