Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Field's names functionality #129

Merged
merged 27 commits into from
Sep 17, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
4a1defa
Add methods to extract fields names
denzor200 Jun 25, 2023
e8e077c
fix for cxx14 build
denzor200 Jun 26, 2023
f09357c
fix lint issues
denzor200 Jun 27, 2023
454947d
review
denzor200 Jun 28, 2023
03e1d76
Merge remote-tracking branch 'origin/develop' into feature/get_name
denzor200 Aug 11, 2023
fe5a70b
Merge remote-tracking branch 'origin/develop' into feature/get_name
denzor200 Aug 12, 2023
196aeb6
Fix lint issue about nonascii symbol
denzor200 Aug 12, 2023
50c9d6f
Fix strip_boost_namespace.sh
denzor200 Aug 12, 2023
b15196c
Fix MSVC
denzor200 Aug 13, 2023
6f544ce
Add Clang support
denzor200 Aug 19, 2023
6e23ed5
Fix nonascii fields
denzor200 Aug 19, 2023
a5b9cd5
Add test for big structures
denzor200 Aug 24, 2023
9b6a0de
Refactoring for parser
denzor200 Aug 26, 2023
efd25e9
review
denzor200 Aug 26, 2023
9b2817a
Parsing ala boost type_index
denzor200 Aug 28, 2023
fcfca74
Write docs
denzor200 Sep 2, 2023
dbbfa6e
Parser might be explicitly tagged as backward
denzor200 Sep 2, 2023
2c79ac7
Fix CI
denzor200 Sep 2, 2023
0cb5cf2
Fix strip_boost_namespace.sh
denzor200 Sep 7, 2023
5a7d652
Fix docs
denzor200 Sep 9, 2023
dd8a527
Rename C++20 features detectors
denzor200 Sep 9, 2023
8794056
review
denzor200 Sep 9, 2023
6dcf66c
Fix for old MSVC compiler
denzor200 Sep 10, 2023
3f07e71
relax standard library requirements
apolukhin Sep 17, 2023
41e87fb
Do not require Python to run tests
apolukhin Sep 17, 2023
27b9706
Fix compilation on MSVC
apolukhin Sep 17, 2023
9cc76bc
Suppress non-ASCII warning from boost-inspect
apolukhin Sep 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions doc/pfr.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,10 @@ Boost.PFR adds the following out-of-the-box functionality for aggregate initiali
* hash
* IO streaming
* access to members by index or type
* access to member's names by index
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
* member type retrieval
* methods for cooperation with `std::tuple`
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
* methods for cooperation with `std::array` for member's names
* methods to visit each field of the structure
* trait to detect potential ability to reflect type, and ability to override trait's decision in user-side code

Expand Down Expand Up @@ -485,6 +487,7 @@ By default Boost.PFR [*auto-detects your compiler abilities] and automatically d
[[*BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE*] [Define to `0` if you are hit by the template instantiation depth issues with `std::make_integer_sequence` and wish to use Boost.PFR version of that metafunction. Define to `1` to override Boost.PFR detection logic. ]]
[[*BOOST_PFR_HAS_GUARANTEED_COPY_ELISION*] [Define to `0` if your compiler does not implement C++17 guaranteed copy elision properly and fails to reflect aggregates with non-movable fields. Define to `1` to override Boost.PFR detection logic. ]]
[[*BOOST_PFR_ENABLE_IMPLICIT_REFLECTION*] [Define to `0` if you are hit by lots of non-effective choices made by implicitly reflection. Define to `1` to override Boost.PFR detection logic. ]]
[[*BOOST_PFR_ENABLE_GETTING_NAMES*] [On platforms where field's names extracting is not supported, the 'boost/pfr/config.hpp' header defines the BOOST_PFR_ENABLE_GETTING_NAMES macro equal to 0. Defining this macro as 0 before including the header disables the ability to get a field's name. ]]
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
[[*BOOST_PFR_ENABLED*] [On platforms where Boost.PFR is not supported, the `boost/pfr/config.hpp` header defines the BOOST_PFR_ENABLED macro equal to 0. Defining this macro as 0 before including the header disables the Boost.PFR library. ]]
]

Expand Down
1 change: 1 addition & 0 deletions include/boost/pfr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <boost/pfr/config.hpp>
#include <boost/pfr/core.hpp>
#include <boost/pfr/core_name.hpp>
#include <boost/pfr/functions_for.hpp>
#include <boost/pfr/functors.hpp>
#include <boost/pfr/io.hpp>
Expand Down
8 changes: 8 additions & 0 deletions include/boost/pfr/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,14 @@
# endif
#endif

#ifndef BOOST_PFR_ENABLE_GETTING_NAMES
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
# if defined(__cpp_nontype_template_args) && __cpp_nontype_template_args >= 201911
# define BOOST_PFR_ENABLE_GETTING_NAMES 1
# else
# define BOOST_PFR_ENABLE_GETTING_NAMES 0
# endif
#endif

#if defined(__has_cpp_attribute)
# if __has_cpp_attribute(maybe_unused)
# define BOOST_PFR_MAYBE_UNUSED [[maybe_unused]]
Expand Down
56 changes: 56 additions & 0 deletions include/boost/pfr/core_name.hpp
Original file line number Diff line number Diff line change
@@ -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
//

#ifndef BOOST_PFR_CORE_NAME_HPP
#define BOOST_PFR_CORE_NAME_HPP
#pragma once

#include <boost/pfr/detail/config.hpp>

#include <boost/pfr/detail/core_name.hpp>

#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/stdarray.hpp>
#include <boost/pfr/detail/make_integer_sequence.hpp>

#include <cstddef>
#include <string_view>

#include <boost/pfr/tuple_size.hpp>

namespace boost { namespace pfr {

template <std::size_t I, class T>
constexpr std::string_view get_name() noexcept {
static_assert(sizeof(T) && BOOST_PFR_ENABLE_GETTING_NAMES, "====================> Boost.PFR: Calling boost::pfr::get_name is allowed only in C++20");
return detail::sequence_tuple::get<I>( detail::tie_as_names_tuple<T>() );
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
}

// FIXME: implement this
// template<class U, class T>
// constexpr std::string_view get_name() noexcept {
// static_assert(sizeof(T) && BOOST_PFR_ENABLE_GETTING_NAMES, "====================> Boost.PFR: Calling boost::pfr::get_name is allowed only in C++20");
// return detail::sequence_tuple::get_by_type_impl<U>( detail::tie_as_names_tuple<T>() );
// }

template <class T>
constexpr auto names_as_array() noexcept {
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
static_assert(sizeof(T) && BOOST_PFR_ENABLE_GETTING_NAMES, "====================> Boost.PFR: Calling boost::pfr::names_as_array is allowed only in C++20");
return detail::make_stdarray_from_tietuple(
detail::tie_as_names_tuple<T>(),
detail::make_index_sequence< tuple_size_v<T> >()
);
}


}}

#endif // BOOST_PFR_CORE_NAME_HPP

79 changes: 79 additions & 0 deletions include/boost/pfr/detail/core_name.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// 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
//

#ifndef BOOST_PFR_DETAIL_CORE_NAME_HPP
#define BOOST_PFR_DETAIL_CORE_NAME_HPP
#pragma once

#include <boost/pfr/detail/config.hpp>
#include <boost/pfr/detail/core.hpp>
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/make_integer_sequence.hpp>
#include <boost/pfr/detail/fields_count.hpp>
#include <type_traits>
#include <string_view>
#include <array>

namespace boost { namespace pfr { namespace detail {

// TODO: move it outside
template <class... Args>
constexpr auto make_sequence_tuple(Args... args) noexcept {
return sequence_tuple::tuple<Args...>{ args... };
}

template <auto& ptr>
constexpr auto name_of_field_impl() noexcept {
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
#ifdef _MSC_VER
constexpr std::string_view sv = __FUNCSIG__;
constexpr auto last = sv.find_last_not_of(" >(", sv.size() - 6);
#else
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)
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
*it++ = sv[a];
return res;
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
}

template <typename T>
extern const T fake_object;

template <class T, std::size_t I>
constexpr auto stored_name_of_field = name_of_field_impl<detail::sequence_tuple::get<I>(
detail::tie_as_tuple(fake_object<T>)
)>();

template <class T, std::size_t... I>
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>
constexpr auto tie_as_names_tuple() 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 tie_as_names_tuple_impl<T>(detail::make_index_sequence<detail::fields_count<T>()>{});
}

}}}

#endif // BOOST_PFR_DETAIL_CORE_NAME_HPP

30 changes: 30 additions & 0 deletions include/boost/pfr/detail/stdarray.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@

// Copyright (c) 2023 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)

#ifndef BOOST_PFR_DETAIL_STDARRAY_HPP
#define BOOST_PFR_DETAIL_STDARRAY_HPP
#pragma once

#include <boost/pfr/detail/config.hpp>

#include <utility> // metaprogramming stuff
#include <tuple>
denzor200 marked this conversation as resolved.
Show resolved Hide resolved

#include <boost/pfr/detail/sequence_tuple.hpp>

namespace boost { namespace pfr { namespace detail {

template <class T, std::size_t... I>
constexpr auto make_stdarray_from_tietuple(const T& t, std::index_sequence<I...>) noexcept {
return std::array{
boost::pfr::detail::sequence_tuple::get<I>(t)...
};
}

}}}

#endif // BOOST_PFR_DETAIL_STDARRAY_HPP

3 changes: 2 additions & 1 deletion test/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
#

build-project config ;
build-project core ;
build-project core ;
build-project core_name ;
1 change: 1 addition & 0 deletions test/config/print_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ int main() {
<< "BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE == " << BOOST_PFR_USE_STD_MAKE_INTEGRAL_SEQUENCE << '\n'
<< "BOOST_PFR_HAS_GUARANTEED_COPY_ELISION == " << BOOST_PFR_HAS_GUARANTEED_COPY_ELISION << '\n'
<< "BOOST_PFR_ENABLE_IMPLICIT_REFLECTION == " << BOOST_PFR_ENABLE_IMPLICIT_REFLECTION << '\n'
<< "BOOST_PFR_ENABLE_GETTING_NAMES == " << BOOST_PFR_ENABLE_GETTING_NAMES << '\n'
<< "BOOST_PFR_ENABLED == " << BOOST_PFR_ENABLED << '\n'
<< "__cplusplus == " << __cplusplus << '\n'
#ifdef __cpp_structured_bindings
Expand Down
56 changes: 56 additions & 0 deletions test/core_name/Jamfile.v2
Original file line number Diff line number Diff line change
@@ -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
#

import python ;
import testing ;
import ../../config/checks/config : requires ;

########## BEGIN of helpers to detect C++20 non-type template args support

actions mp_simple_run_action
{
$(>) > $(<)
}

rule mp-run-simple ( sources + : args * : input-files * : requirements * : target-name )
{
exe $(target-name)_exe : $(sources) : $(requirements) ;
explicit $(target-name)_exe ;
make $(target-name).output : $(target-name)_exe : @mp_simple_run_action ;
explicit $(target-name).output ;
alias $(target-name) : $(target-name).output ;
}

mp-run-simple cxx20_nontype_template_args_detection.cpp : : : : compiler_supports_cxx20_nontype_template_args ;
explicit compiler_supports_cxx20_nontype_template_args ;

########## END of helpers to detect C++20 non-type template args support


local REQUIRE_CXX20_NONTYPE_TEMPLATE_ARGS =
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
[ check-target-builds ../core_name//compiler_supports_cxx20_nontype_template_args : : <build>no ]
;

project
: source-location .
: requirements
<define>BOOST_PFR_DETAIL_STRICT_RVALUE_TESTING=1
[ check-target-builds ../core_name//compiler_supports_cxx20_nontype_template_args : : <build>no ]
;



test-suite pfr_tests
:
[ run fields_names.cpp : : : : ]
[ run fields_names_constexpr.cpp : : : : ]
;


23 changes: 23 additions & 0 deletions test/core_name/cxx20_nontype_template_args_detection.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// 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
//

template <int* p>
class X {};

struct S
{
int m;
} s;

X<&s.m> x4;

int main() {}


74 changes: 74 additions & 0 deletions test/core_name/fields_names.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// 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>
#include <functional> // for std::reference_wrapper
#include <string>

namespace testing {

namespace {

struct nonconstexpr {
nonconstexpr() {};
};

struct Aggregate {
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
int member1;
nonconstexpr this_is_a_name;
std::reference_wrapper<char> c;
std::string Forth;
};

void test_get_name_by_id() {
BOOST_TEST_EQ( ((boost::pfr::get_name<0, Aggregate>())), "member1");
BOOST_TEST_EQ( ((boost::pfr::get_name<1, Aggregate>())), "this_is_a_name");
BOOST_TEST_EQ( ((boost::pfr::get_name<2, Aggregate>())), "c");
BOOST_TEST_EQ( ((boost::pfr::get_name<3, Aggregate>())), "Forth");
}

void test_get_name_by_type() {
// FIXME: implement this
// using char_ref = std::reference_wrapper<char>;
// BOOST_TEST_EQ( ((boost::pfr::get_name<int, Aggregate>())), "member1");
// BOOST_TEST_EQ( ((boost::pfr::get_name<nonconstexpr, Aggregate>())), "this_is_a_name");
// BOOST_TEST_EQ( ((boost::pfr::get_name<char_ref, Aggregate>())), "c");
}

void test_names_as_array() {
const auto expected = std::array<std::string_view, 4>{
"member1",
"this_is_a_name",
"c",
"Forth"
};
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_by_id();
testing::test_get_name_by_type();
testing::test_names_as_array();

return boost::report_errors();
}


Loading