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 8 commits
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
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
fail-fast: false
matrix:
include:
- toolset: gcc-12
- toolset: gcc-12 # Do not remove! It is the only toolset that tests misc/strip_boost_namespace.sh
cxxstd: "03,11,14,17,2a"
os: ubuntu-22.04
cxxflags: "cxxflags=--coverage -fsanitize=address,leak,undefined -fno-sanitize-recover=undefined"
Expand Down Expand Up @@ -94,7 +94,7 @@ jobs:
dist/bin/inspect libs/$LIBRARY

- name: Test boost namespace stripping
if: ${{matrix.toolset == 'gcc-9'}}
if: ${{matrix.toolset == 'gcc-12'}}
run: ../boost-root/libs/$LIBRARY/misc/strip_boost_namespace.sh

- name: Prepare coverage data
Expand Down
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
16 changes: 16 additions & 0 deletions include/boost/pfr/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,22 @@
# endif
#endif

#ifndef BOOST_PFR_FUNCTION_MACRO_SUPPORTED
# if defined(__clang__) || defined(__GNUC__) || defined(_MSC_VER)
# define BOOST_PFR_FUNCTION_MACRO_SUPPORTED 1
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
# else
# define BOOST_PFR_FUNCTION_MACRO_SUPPORTED 0
# 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 && BOOST_PFR_FUNCTION_MACRO_SUPPORTED
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
# 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
52 changes: 52 additions & 0 deletions include/boost/pfr/core_name.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// 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 <boost/pfr/tuple_size.hpp>

namespace boost { namespace pfr {

template <std::size_t I, class T>
constexpr auto get_name() noexcept {
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
return detail::get_name<T, I>();
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
}

// FIXME: implement this
// template<class U, class T>
// constexpr auto get_name() noexcept {
// 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
return detail::make_stdarray_from_tietuple(
detail::tie_as_names_tuple<T>(),
detail::make_index_sequence< tuple_size_v<T> >()
);
}


}} // namespace boost::pfr

#endif // BOOST_PFR_CORE_NAME_HPP

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

// 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.
#if BOOST_PFR_ENABLE_GETTING_NAMES
#include <boost/pfr/detail/core_name20_static.hpp>
#else
#include <boost/pfr/detail/core_name14_disabled.hpp>
#endif

#endif // BOOST_PFR_DETAIL_CORE_NAME_HPP

49 changes: 49 additions & 0 deletions include/boost/pfr/detail/core_name14_disabled.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// 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_NAME14_DISABLED_HPP
#define BOOST_PFR_DETAIL_CORE_NAME14_DISABLED_HPP
#pragma once

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

namespace boost { namespace pfr { namespace detail {

// TODO: move it outside
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
template <class... Args>
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)."
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
);

return nullptr;
}

template <class T>
constexpr auto tie_as_names_tuple() 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)."
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
);

return detail::make_sequence_tuple();
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
}

}}} // namespace boost::pfr::detail

#endif // BOOST_PFR_DETAIL_CORE_NAME14_DISABLED_HPP

94 changes: 94 additions & 0 deletions include/boost/pfr/detail/core_name20_static.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// 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_NAME20_STATIC_HPP
#define BOOST_PFR_DETAIL_CORE_NAME20_STATIC_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>
#include <algorithm> // for std::ranges::copy

namespace boost { namespace pfr { namespace detail {

// TODO: move it outside
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
template <class... Args>
constexpr auto make_sequence_tuple(Args... args) noexcept {
return sequence_tuple::tuple<Args...>{ args... };
}

template <auto& ptr>
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);
#else
constexpr std::string_view sv = __PRETTY_FUNCTION__;
constexpr auto last = sv.find_last_not_of(" ])");
#endif
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;
}

template <typename T>
extern const T fake_object;
denzor200 marked this conversation as resolved.
Show resolved Hide resolved

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, 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(
!std::is_union<T>::value,
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
"====================> 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>()>{});
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
}

}}} // namespace boost::pfr::detail

#endif // BOOST_PFR_DETAIL_CORE_NAME20_STATIC_HPP

35 changes: 35 additions & 0 deletions include/boost/pfr/detail/stdarray.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// 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 <type_traits> // for std::common_type_t

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

namespace boost { namespace pfr { namespace detail {

template <class... Types>
constexpr auto make_stdarray(const Types&... t) noexcept {
return std::array<std::common_type_t<Types...>, sizeof...(Types)>{t...};
}

template <class T, std::size_t... I>
constexpr auto make_stdarray_from_tietuple(const T& t, std::index_sequence<I...>) noexcept {
return make_stdarray(
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
boost::pfr::detail::sequence_tuple::get<I>(t)...
);
}

}}} // namespace boost::pfr::detail

#endif // BOOST_PFR_DETAIL_STDARRAY_HPP

12 changes: 9 additions & 3 deletions misc/strip_boost_namespace.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,20 +39,26 @@ find ${TARGET_PATH}/doc -type f | xargs sed -i 's|Boost.PFR|PFR|g'
sed -i 's|# \[Boost.PFR\](https://boost.org/libs/pfr)|# [PFR](https://apolukhin.github.io/pfr_non_boost/)|g' ${TARGET_PATH}/README.md

echo -n "***** Testing: "
if g++-9 -std=c++17 -DPFR_USE_LOOPHOLE=0 -DPFR_USE_CPP17=1 -I ${TARGET_PATH}/include/ ${TARGET_PATH}/example/motivating_example0.cpp && ./a.out > /dev/null; then
if g++-12 -std=c++2a -DPFR_USE_LOOPHOLE=0 -DPFR_USE_CPP17=1 -DPFR_ENABLE_GETTING_NAMES=1 -I ${TARGET_PATH}/include/ ${TARGET_PATH}/example/motivating_example0.cpp && ./a.out > /dev/null; then
denzor200 marked this conversation as resolved.
Show resolved Hide resolved
echo -n "OK"
else
echo -n "FAIL"
exit 2
fi
if g++-9 -std=c++17 -DPFR_USE_LOOPHOLE=1 -DPFR_USE_CPP17=0 -I ${TARGET_PATH}/include/ ${TARGET_PATH}/example/motivating_example0.cpp && ./a.out > /dev/null; then
if g++-12 -std=c++2a -DPFR_USE_LOOPHOLE=0 -DPFR_USE_CPP17=1 -DPFR_ENABLE_GETTING_NAMES=0 -I ${TARGET_PATH}/include/ ${TARGET_PATH}/example/motivating_example0.cpp && ./a.out > /dev/null; then
echo -n "OK"
else
echo -n "FAIL"
exit 2
fi
if g++-12 -std=c++2a -DPFR_USE_LOOPHOLE=1 -DPFR_USE_CPP17=0 -I ${TARGET_PATH}/include/ ${TARGET_PATH}/example/motivating_example0.cpp && ./a.out > /dev/null; then
echo -n ", OK"
else
echo -n ", FAIL"
exit 3
fi

if g++-9 -std=c++17 -DPFR_USE_LOOPHOLE=0 -DPFR_USE_CPP17=0 -I ${TARGET_PATH}/include/ ${TARGET_PATH}/example/get.cpp && ./a.out > /dev/null; then
if g++-12 -std=c++2a -DPFR_USE_LOOPHOLE=0 -DPFR_USE_CPP17=0 -I ${TARGET_PATH}/include/ ${TARGET_PATH}/example/get.cpp && ./a.out > /dev/null; then
echo -e ", OK"
else
echo -e ", FAIL"
Expand Down
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
Loading