#ifndef RFL_INTERNAL_GETFIELDNAMES_HPP_ #define RFL_INTERNAL_GETFIELDNAMES_HPP_ #include #include #include #include #include #include #include #include #include "../Literal.hpp" #include "bind_fake_object_to_tuple.hpp" #include "get_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() { // Unfortunately, we cannot avoid the use of a compiler-specific macro for // Clang on Windows. For all other compilers, function_name works as // intended. #if defined(__clang__) && defined(_MSC_VER) const auto func_name = std::string_view {__PRETTY_FUNCTION__}; #else const auto func_name = std::string_view {std::source_location::current().function_name()}; #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()>(); } } template auto concat_two_literals(const rfl::Literal<_names1...>& _lit1, const rfl::Literal<_names2...>& _lit2) { return rfl::Literal<_names1..., _names2...>::template from_value<0>(); } template auto concat_literals(const Head& _head, const Tail&... _tail) { if constexpr (sizeof...(_tail) == 0) { return _head; } else { return concat_two_literals(_head, concat_literals(_tail...)); } } 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) { return concat_literals( get_field_name( bind_fake_object_to_tuple()))>()...); }; #else const auto get = [](std::index_sequence) { return concat_literals( get_field_name(bind_fake_object_to_tuple())>()...); }; #endif return get(std::make_index_sequence>()); } } #ifdef __clang__ #pragma clang diagnostic pop #endif } // namespace rfl::internal #endif