2
0
mirror of https://github.com/boostorg/pfr.git synced 2026-01-19 04:22:13 +00:00
This commit is contained in:
denzor200
2023-06-28 12:32:26 +00:00
committed by Antony Polukhin
parent 86911e0247
commit 04aef42dcb
9 changed files with 152 additions and 11 deletions

View File

@@ -98,8 +98,16 @@
# endif
#endif
#ifndef BOOST_PFR_FUNCTION_MACRO_SUPPORTED
# if defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER)
# define BOOST_PFR_FUNCTION_MACRO_SUPPORTED 1
# else
# define BOOST_PFR_FUNCTION_MACRO_SUPPORTED 0
# endif
#endif
#ifndef BOOST_PFR_ENABLE_GETTING_NAMES
# if defined(__cpp_nontype_template_args) && __cpp_nontype_template_args >= 201911
# if defined(__cpp_nontype_template_args) && __cpp_nontype_template_args >= 201911 && BOOST_PFR_FUNCTION_MACRO_SUPPORTED
# define BOOST_PFR_ENABLE_GETTING_NAMES 1
# else
# define BOOST_PFR_ENABLE_GETTING_NAMES 0

View File

@@ -28,7 +28,7 @@ namespace boost { namespace pfr {
template <std::size_t I, class T>
constexpr auto get_name() noexcept {
return detail::sequence_tuple::get<I>( detail::tie_as_names_tuple<T>() );
return detail::get_name<T, I>();
}
// FIXME: implement this

View File

@@ -14,8 +14,8 @@
#include <boost/pfr/detail/config.hpp>
// Each core_name provides `TODO:` and
// `TODO:` functions.
// Each core_name provides `boost::pfr::detail::get_name` and
// `boost::pfr::detail::tie_as_names_tuple` functions.
//
// The whole functional of extracting field's names is build on top of those
// two functions.

View File

@@ -23,12 +23,21 @@ constexpr auto make_sequence_tuple(Args... args) noexcept {
return sequence_tuple::tuple<Args...>{ args... };
}
template <class T, std::size_t I>
constexpr auto get_name() noexcept {
static_assert(
sizeof(T) && false,
"====================> Boost.PFR: Field's names extracting functionality requires C++20 and compiler that supports __PRETTY_FUNCTION__ or __FUNCSIG__ macro (GCC, Clang or MSVC)."
);
return nullptr;
}
template <class T>
constexpr auto tie_as_names_tuple() noexcept {
static_assert(
sizeof(T) && false,
"====================> Boost.PFR: Extraction of field's names is allowed only in C++20"
"====================> Boost.PFR: Field's names extracting functionality requires C++20 and compiler that supports __PRETTY_FUNCTION__ or __FUNCSIG__ macro (GCC, Clang or MSVC)."
);
return detail::make_sequence_tuple();

View File

@@ -20,6 +20,7 @@
#include <type_traits>
#include <string_view>
#include <array>
#include <algorithm> // for std::ranges::copy
namespace boost { namespace pfr { namespace detail {
@@ -30,7 +31,7 @@ constexpr auto make_sequence_tuple(Args... args) noexcept {
}
template <auto& ptr>
constexpr auto name_of_field_impl() noexcept {
consteval auto name_of_field_impl() noexcept {
#ifdef _MSC_VER
constexpr std::string_view sv = __FUNCSIG__;
constexpr auto last = sv.find_last_not_of(" >(", sv.size() - 6);
@@ -38,11 +39,11 @@ constexpr auto name_of_field_impl() noexcept {
constexpr std::string_view sv = __PRETTY_FUNCTION__;
constexpr auto last = sv.find_last_not_of(" ])");
#endif
constexpr auto first = sv.find_last_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789", last);
std::array<char, last - first + 1> res{};
auto it = res.data();
for (auto a = first+1; a <= last; ++a)
*it++ = sv[a];
constexpr auto first = sv.find_last_of(":", last);
auto res = std::array<char, last - first + 1>{};
std::ranges::copy(sv.begin()+first+1,
sv.begin()+last+1,
res.begin());
return res;
}
@@ -59,6 +60,20 @@ constexpr auto tie_as_names_tuple_impl(std::index_sequence<I...>) noexcept {
return detail::make_sequence_tuple(std::string_view{stored_name_of_field<T, I>.data()}...);
}
template <class T, std::size_t I>
constexpr std::string_view get_name() noexcept {
static_assert(
!std::is_union<T>::value,
"====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
);
static_assert(
sizeof(T) && BOOST_PFR_USE_CPP17,
"====================> Boost.PFR: Extraction of field's names is allowed only when the BOOST_PFR_USE_CPP17 macro enabled."
);
return stored_name_of_field<T, I>.data();
}
template <class T>
constexpr auto tie_as_names_tuple() noexcept {
static_assert(

View File

@@ -51,6 +51,8 @@ test-suite pfr_tests
:
[ run fields_names.cpp : : : : ]
[ run fields_names_constexpr.cpp : : : : ]
[ run fields_names_nonascii.cpp : : : : ]
[ run fields_names_unnamed_struct.cpp : : : <cxxflags>"-fpermissive" : ]
;

View File

@@ -58,6 +58,7 @@ void test_names_as_array() {
}
}
} // anonymous namespace

View File

@@ -0,0 +1,50 @@
// Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov.
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Initial implementation by Bela Schaum, https://github.com/schaumb
// The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669
//
#include <boost/pfr/core_name.hpp>
#include <boost/core/lightweight_test.hpp>
namespace testing {
namespace {
struct Aggregate {
int ;
};
void test_get_name() {
BOOST_TEST_EQ( ((boost::pfr::get_name<0, Aggregate>())), "");
}
void test_names_as_array() {
const auto expected = std::array<std::string_view, 1>{
""
};
const auto value = boost::pfr::names_as_array<Aggregate>();
BOOST_TEST_EQ(expected.size(), value.size());
for (std::size_t i=0;i<expected.size();++i) {
BOOST_TEST_EQ(value[i], expected[i]);
}
}
} // anonymous namespace
} // namespace testing
int main() {
testing::test_get_name();
testing::test_names_as_array();
return boost::report_errors();
}

View File

@@ -0,0 +1,56 @@
// Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov.
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Initial implementation by Bela Schaum, https://github.com/schaumb
// The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669
//
#include <boost/pfr/core_name.hpp>
#include <boost/core/lightweight_test.hpp>
namespace testing {
namespace {
struct {
int field_of_unnamed_structure;
} unnamed;
void test_get_name() {
BOOST_TEST_EQ( ((boost::pfr::get_name<0, decltype(unnamed)>())), "field_of_unnamed_structure");
}
void test_names_as_array() {
const auto expected = std::array<std::string_view, 1>{
"field_of_unnamed_structure"
};
const auto value = boost::pfr::names_as_array<decltype(unnamed)>();
BOOST_TEST_EQ(expected.size(), value.size());
for (std::size_t i=0;i<expected.size();++i) {
BOOST_TEST_EQ(value[i], expected[i]);
}
}
void test_get_name_for_local_structure() {
struct A { int a_field_name; };
BOOST_TEST_EQ( ((boost::pfr::get_name<0, A>())), "a_field_name" );
}
} // anonymous namespace
} // namespace testing
int main() {
testing::test_get_name();
testing::test_names_as_array();
testing::test_get_name_for_local_structure();
return boost::report_errors();
}