Skip to content

Commit

Permalink
review
Browse files Browse the repository at this point in the history
  • Loading branch information
denzor200 committed Sep 10, 2023
1 parent dd8a527 commit 8794056
Show file tree
Hide file tree
Showing 21 changed files with 192 additions and 55 deletions.
24 changes: 12 additions & 12 deletions doc/pfr.qbk
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,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_GET_NAME_STATIC*] [On platforms where field's names extracting is not supported, the 'boost/pfr/config.hpp' header defines the BOOST_PFR_ENABLE_GET_NAME_STATIC macro equal to 0. Defining this macro as 0 before including the header disables the ability to get a field's name. ]]
[[*BOOST_PFR_CORE_NAME_ENABLED*] [On platforms where field's names extracting is not supported, the 'boost/pfr/config.hpp' header defines the BOOST_PFR_CORE_NAME_ENABLED macro equal to 0. Defining this macro as 0 before including the header disables the ability to get a field's name. ]]
[[*BOOST_PFR_FUNCTION_SIGNATURE*] [On platforms which are unknown by Boost.PFR library, the 'boost/pfr/config.hpp' header defines the BOOST_PFR_FUNCTION_SIGNATURE macro equal to "". Defining this macro before including the header might help the library to work on your specific platform. See details [link boost_pfr.limitations_of_field_names_refle [*here]]. ]]
[[*BOOST_PFR_CORE_NAME_PARSING*] [On platforms which are unknown by Boost.PFR library, the 'boost/pfr/config.hpp' header defines the BOOST_PFR_CORE_NAME_PARSING macro equal to (0,0,false). Defining this macro before including the header might help the library to work on your specific platform. See details [link boost_pfr.limitations_of_field_names_refle [*here]]. ]]
[[*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 Expand Up @@ -556,13 +556,13 @@ Boost.PFRs extraction of field name has been tested and successfully work on man
[section Define the BOOST_PFR_FUNCTION_SIGNATURE macro]

If you get the following error during compilation
``
PFRs extraction of field name could not detect your compiler.
Please make the BOOST_PFR_FUNCTION_SIGNATURE macro use
correct compiler macro for getting the whole function name.
Define BOOST_PFR_CORE_NAME_PARSING to correct value after that.
``
then you are using a compiler that was not tested with this library.
```
error: static_assert failed "====================> Boost.PFR: Extraction of field name could not detect your compiler.
Please make the BOOST_PFR_FUNCTION_SIGNATURE macro use
correct compiler macro for getting the whole function name.
Define BOOST_PFR_CORE_NAME_PARSING to correct value after that."
```
then you are using a compiler that was not tested with this library.

BOOST_PFR_FUNCTION_SIGNATURE must be defined to a compiler specific macro, that outputs the *whole*
function signature including non-type template parameters.
Expand All @@ -574,18 +574,18 @@ function signature including non-type template parameters.

Let's assume the structure `namespace A { struct A { int fn; }; }`

If the output of `boost::pfr::get_name<0, A::A>()`
returns not just `fn` but also a lot of text around the `fn`
If the output of `boost::pfr::get_name<0, A::A>()`
returns not just `fn` but also a lot of text around the `fn`
or does not return name at all
then you are using a compiler that was not tested with this library and you need to setup the
BOOST_PFR_CORE_NAME_PARSING macro.

Here is a short instruction:

# get the output of `boost::pfr::get_name<0, A::A>()`
# define BOOST_PFR_CORE_NAME_PARSING to
# define BOOST_PFR_CORE_NAME_PARSING to
`(skip_at_begin, skip_at_end, false, "")`, where
* `skip_at_begin` is equal to characters count before the first occurrence of `fn` in output
* `skip_at_begin` is equal to characters count before the first occurrence of `fn` in output
* `skip_at_end` is equal to characters count after last occurrence of `fn` in output
# check that `boost::pfr::get_name<0, A::A>()` returns "fn"
# if it does not return `fn`, then define BOOST_PFR_CORE_NAME_PARSING to
Expand Down
4 changes: 2 additions & 2 deletions example/get_name.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

#include <boost/pfr/config.hpp>

#if BOOST_PFR_ENABLE_GET_NAME_STATIC && BOOST_PFR_USE_CPP17
#if BOOST_PFR_CORE_NAME_ENABLED && BOOST_PFR_USE_CPP17
//[pfr_example_get_name
/*`
Since C++20 it's possible to read name of structure fields by index using Boost.PFR library.
Expand All @@ -34,7 +34,7 @@ constexpr auto r2 = boost::pfr::get_name<1, foo>(); // reading name of field wit
#endif

int main() {
#if BOOST_PFR_ENABLE_GET_NAME_STATIC && BOOST_PFR_USE_CPP17
#if BOOST_PFR_CORE_NAME_ENABLED && BOOST_PFR_USE_CPP17
if (r1 != "some_integer") return 1;
if (r2 != "c") return 2;
#endif
Expand Down
14 changes: 9 additions & 5 deletions include/boost/pfr/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,16 @@
# endif
#endif

#ifndef BOOST_PFR_ENABLE_GET_NAME_STATIC
# if (defined(__cpp_nontype_template_args) && __cpp_nontype_template_args >= 201911) \
|| (__cplusplus >= 202002L && defined(__clang_major__) && __clang_major__ >= 12)
# define BOOST_PFR_ENABLE_GET_NAME_STATIC 1
#ifndef BOOST_PFR_CORE_NAME_ENABLED
# if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && (_MSVC_LANG >= 202002L))
# if (defined(__cpp_nontype_template_args) && __cpp_nontype_template_args >= 201911) \
|| (defined(__clang_major__) && __clang_major__ >= 12)
# define BOOST_PFR_CORE_NAME_ENABLED 1
# else
# define BOOST_PFR_CORE_NAME_ENABLED 0
# endif
# else
# define BOOST_PFR_ENABLE_GET_NAME_STATIC 0
# define BOOST_PFR_CORE_NAME_ENABLED 0
# endif
#endif

Expand Down
15 changes: 13 additions & 2 deletions include/boost/pfr/core_name.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
#include <boost/pfr/detail/stdarray.hpp>
#include <boost/pfr/detail/make_integer_sequence.hpp>

#include <cstddef>
#include <cstddef> // for std::size_t
#include <type_traits> // for std::enable_if_t

#include <boost/pfr/tuple_size.hpp>

Expand Down Expand Up @@ -74,13 +75,23 @@ std::array<std::string_view, boost::pfr::tuple_size_v<T>>
#else
auto
#endif
names_as_array() noexcept {
names_as_array(
#ifndef BOOST_PFR_DOXYGEN_INVOKED
std::enable_if_t<!decltype(detail::tie_as_names_tuple<T>())::empty()>* = nullptr
#endif
) noexcept {
return detail::make_stdarray_from_tietuple(
detail::tie_as_names_tuple<T>(),
detail::make_index_sequence< tuple_size_v<T> >()
);
}

#ifndef BOOST_PFR_DOXYGEN_INVOKED
template <class T>
constexpr auto names_as_array(std::enable_if_t<decltype(detail::tie_as_names_tuple<T>())::empty()>* = nullptr) noexcept {
return detail::make_empty_stdarray();
}
#endif

}} // namespace boost::pfr

Expand Down
2 changes: 1 addition & 1 deletion include/boost/pfr/detail/core_name.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
//
// The whole functional of extracting field's names is build on top of those
// two functions.
#if BOOST_PFR_ENABLE_GET_NAME_STATIC
#if BOOST_PFR_CORE_NAME_ENABLED
#include <boost/pfr/detail/core_name20_static.hpp>
#else
#include <boost/pfr/detail/core_name14_disabled.hpp>
Expand Down
29 changes: 14 additions & 15 deletions include/boost/pfr/detail/core_name20_static.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
#include <boost/pfr/detail/make_integer_sequence.hpp>
#include <boost/pfr/detail/fields_count.hpp>
#include <boost/pfr/detail/stdarray.hpp>
#include <boost/pfr/detail/fake_object.hpp>
#include <type_traits>
#include <string_view>
#include <array>
#include <algorithm> // for std::ranges::copy
#include <memory> // for std::addressof

namespace boost { namespace pfr { namespace detail {

Expand Down Expand Up @@ -62,7 +64,7 @@ struct backward {
explicit consteval backward(std::string_view value) noexcept
: value(value)
{}

std::string_view value;
};

Expand Down Expand Up @@ -93,7 +95,7 @@ template <bool Condition>
consteval void assert_compile_time_legths() noexcept {
static_assert(
Condition,
"PFRs extraction of field name is misconfigured for your compiler. "
"====================> Boost.PFR: Extraction of field name is misconfigured for your compiler. "
"Please define BOOST_PFR_CORE_NAME_PARSING to correct values. See section "
"Limitations of field's names reflection' of the documentation for more information."
);
Expand All @@ -103,7 +105,7 @@ template <class T>
consteval void failed_to_get_function_name() noexcept {
static_assert(
sizeof(T) && false,
"PFRs extraction of field name could not detect your compiler. "
"====================> Boost.PFR: Extraction of field name could not detect your compiler. "
"Please make the BOOST_PFR_FUNCTION_SIGNATURE macro use "
"correct compiler macro for getting the whole function name. "
"Define BOOST_PFR_CORE_NAME_PARSING to correct value after that."
Expand All @@ -118,7 +120,7 @@ consteval std::string_view clang_workaround(std::string_view value) noexcept
return value;
}

template <typename MsvcWorkaround, auto ptr>
template <class MsvcWorkaround, auto ptr>
consteval auto name_of_field_impl() noexcept {
constexpr std::string_view sv = detail::clang_workaround<MsvcWorkaround>(BOOST_PFR_FUNCTION_SIGNATURE);
if constexpr (sv.empty()) {
Expand All @@ -141,32 +143,29 @@ consteval auto name_of_field_impl() noexcept {
}
}

template <typename T>
extern const T fake_object;

#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundefined-var-template"

// clang 16 doesn't support address of non-static member as template parameter
// clang 16 and earlier don't support address of non-static member as template parameter
// but fortunately it's possible to use C++20 non-type template parameters in another way
// even in clang 16 and more older clangs
// all we need is to wrap pointer into 'clang_wrapper_t' and then pass it into template
template<class T>
template <class T>
struct clang_wrapper_t {
T v;
};
template<class T>
template <class T>
clang_wrapper_t(T) -> clang_wrapper_t<T>;

template<typename T>
template <class T>
constexpr auto make_clang_wrapper(const T& arg) noexcept {
return clang_wrapper_t{arg};
}

#else

template<typename T>
template <class T>
constexpr const T& make_clang_wrapper(const T& arg) noexcept {
// It's everything OK with address of non-static member as template parameter support on this compiler
// so we don't need a wrapper here, just pass the pointer into template
Expand All @@ -178,9 +177,9 @@ constexpr const T& make_clang_wrapper(const T& arg) noexcept {
// Without passing 'T' into 'name_of_field_impl' different fields from different structures might have the same name!
// See https://developercommunity.visualstudio.com/t/__FUNCSIG__-outputs-wrong-value-with-C/10458554 for details
template <class T, std::size_t I>
constexpr auto stored_name_of_field = name_of_field_impl<T, make_clang_wrapper(&detail::sequence_tuple::get<I>(
constexpr auto stored_name_of_field = detail::name_of_field_impl<T, detail::make_clang_wrapper(std::addressof(detail::sequence_tuple::get<I>(
detail::tie_as_tuple(fake_object<T>)
))>();
)))>();

#ifdef __clang__
#pragma clang diagnostic pop
Expand Down Expand Up @@ -216,7 +215,7 @@ constexpr auto tie_as_names_tuple() noexcept {
"====================> 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>()>{});
return detail::tie_as_names_tuple_impl<T>(detail::make_index_sequence<detail::fields_count<T>()>{});
}

}}} // namespace boost::pfr::detail
Expand Down
25 changes: 25 additions & 0 deletions include/boost/pfr/detail/fake_object.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// 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_FAKE_OBJECT_HPP
#define BOOST_PFR_DETAIL_FAKE_OBJECT_HPP
#pragma once

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

namespace boost { namespace pfr { namespace detail {

template <class T>
extern const T fake_object;

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

#endif // BOOST_PFR_DETAIL_FAKE_OBJECT_HPP

3 changes: 3 additions & 0 deletions include/boost/pfr/detail/sequence_tuple.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ struct tuple: tuple_base<
detail::index_sequence_for<Values...>,
Values...
>::tuple_base;

constexpr static std::size_t size() noexcept { return sizeof...(Values); }
constexpr static bool empty() noexcept { return size() == 0; }
};


Expand Down
7 changes: 6 additions & 1 deletion include/boost/pfr/detail/stdarray.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
#include <boost/pfr/detail/config.hpp>

#include <utility> // metaprogramming stuff
#include <tuple>
#include <array>
#include <type_traits> // for std::common_type_t
#include <cstddef>

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

Expand All @@ -29,6 +30,10 @@ constexpr auto make_stdarray_from_tietuple(const T& t, std::index_sequence<I...>
);
}

constexpr auto make_empty_stdarray() noexcept {
return std::array<std::nullptr_t, 0>{};
}

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

#endif // BOOST_PFR_DETAIL_STDARRAY_HPP
Expand Down
2 changes: 1 addition & 1 deletion test/config/print_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,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_GET_NAME_STATIC == " << BOOST_PFR_ENABLE_GET_NAME_STATIC << '\n'
<< "BOOST_PFR_CORE_NAME_ENABLED == " << BOOST_PFR_CORE_NAME_ENABLED << '\n'
<< "BOOST_PFR_FUNCTION_SIGNATURE == " << BOOST_PP_STRINGIZE(BOOST_PFR_FUNCTION_SIGNATURE) << '\n'
<< "BOOST_PFR_CORE_NAME_PARSING == " << BOOST_PP_STRINGIZE(BOOST_PFR_CORE_NAME_PARSING) << '\n'
<< "BOOST_PFR_ENABLED == " << BOOST_PFR_ENABLED << '\n'
Expand Down
28 changes: 13 additions & 15 deletions test/core_name/Jamfile.v2
Original file line number Diff line number Diff line change
Expand Up @@ -43,35 +43,33 @@ project
[ check-target-builds ../core_name//compiler_supports_cxx20_address_of_non_static_member_tplarg : : [ check-target-builds ../core_name//compiler_supports_cxx20_nontype_tplarg : : <build>no ] ]
;

local ENABLED_ENGINE = <define>BOOST_PFR_ENABLE_GET_NAME_STATIC=1 ;
local DISABLED_ENGINE = <define>BOOST_PFR_ENABLE_GET_NAME_STATIC=0 ;



actions invoke_python_generator
{
python $(>) > $(<)
}

make fields_names_nonascii.cpp : generate_fields_names_nonascii.cpp.py : @invoke_python_generator ;
make fields_names_big.cpp : generate_fields_names_big.cpp.py : @invoke_python_generator ;

test-suite pfr_name_tests
:
[ run fields_names.cpp : : : : ]
[ run fields_names_constexpr.cpp : : : : ]
[ run fields_names_nonascii.cpp : : : <toolset>msvc:<cxxflags>"/utf-8" : ]
[ run fields_names_big.cpp : : : <toolset>msvc:<cxxflags>"/bigobj" : ]
[ run fields_names_correctly_configured_compiler.cpp : : : : ]
[ run fields_names_internal_parser.cpp : : : : ]
[ run print_name.cpp : : : <test-info>always_show_run_output ]
;

for local source_file in [ glob ./run/*.cpp ]
{
pfr_name_tests += [ run $(source_file) : : : : ] ;
}

for local source_file in [ glob ./run/*.py ]
{
local cpp_source_file = $(source_file[1]:B) ;
make $(cpp_source_file) : $(source_file) : @invoke_python_generator ;
pfr_name_tests += [ run $(cpp_source_file) : : : <toolset>msvc:<cxxflags>"/utf-8" <toolset>msvc:<cxxflags>"/bigobj" : ] ;
}

for local source_file in [ glob ./compile-fail/*.cpp ]
{
local target_name = $(source_file[1]:B) ;
pfr_name_tests += [ compile-fail $(source_file) : $(ENABLED_ENGINE) : $(target_name)_on ] ;
pfr_name_tests += [ compile-fail $(source_file) : $(DISABLED_ENGINE) : $(target_name)_off ] ;
pfr_name_tests += [ compile-fail $(source_file) : : ] ;
}


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

#define BOOST_PFR_CORE_NAME_ENABLED 0
#include <boost/pfr/core_name.hpp>

struct A { int field; };

int main() {
(void)boost::pfr::get_name<0, A>(); // Must be a compile time error
}


Loading

0 comments on commit 8794056

Please sign in to comment.