Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:43:37

0001 // Copyright (c) 2023 Bela Schaum, X-Ryl669, Denis Mikhailov.
0002 //
0003 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0004 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0005 
0006 
0007 // Initial implementation by Bela Schaum, https://github.com/schaumb
0008 // The way to make it union and UB free by X-Ryl669, https://github.com/X-Ryl669
0009 //
0010 
0011 #ifndef BOOST_PFR_DETAIL_CORE_NAME20_STATIC_HPP
0012 #define BOOST_PFR_DETAIL_CORE_NAME20_STATIC_HPP
0013 #pragma once
0014 
0015 #include <boost/pfr/detail/config.hpp>
0016 #include <boost/pfr/detail/core.hpp>
0017 #include <boost/pfr/detail/sequence_tuple.hpp>
0018 #include <boost/pfr/detail/make_integer_sequence.hpp>
0019 #include <boost/pfr/detail/fields_count.hpp>
0020 #include <boost/pfr/detail/stdarray.hpp>
0021 #include <boost/pfr/detail/fake_object.hpp>
0022 #include <type_traits>
0023 #include <string_view>
0024 #include <array>
0025 #include <memory> // for std::addressof
0026 
0027 namespace boost { namespace pfr { namespace detail {
0028 
0029 struct core_name_skip {
0030     std::size_t size_at_begin;
0031     std::size_t size_at_end;
0032     bool is_backward;
0033     std::string_view until_runtime;
0034 
0035     consteval std::string_view apply(std::string_view sv) const noexcept {
0036         // We use std::min here to make the compiler diagnostic shorter and
0037         // cleaner in case of misconfigured BOOST_PFR_CORE_NAME_PARSING
0038         sv.remove_prefix((std::min)(size_at_begin, sv.size()));
0039         sv.remove_suffix((std::min)(size_at_end, sv.size()));
0040         if (until_runtime.empty()) {
0041             return sv;
0042         }
0043 
0044         const auto found = is_backward ? sv.rfind(until_runtime)
0045                                        : sv.find(until_runtime);
0046 
0047         const auto cut_until = found + until_runtime.size();
0048         const auto safe_cut_until = (std::min)(cut_until, sv.size());
0049         return sv.substr(safe_cut_until);
0050     }
0051 };
0052 
0053 struct backward {
0054     explicit consteval backward(std::string_view value) noexcept
0055         : value(value)
0056     {}
0057 
0058     std::string_view value;
0059 };
0060 
0061 consteval core_name_skip make_core_name_skip(std::size_t size_at_begin,
0062                                              std::size_t size_at_end,
0063                                              std::string_view until_runtime) noexcept
0064 {
0065     return core_name_skip{size_at_begin, size_at_end, false, until_runtime};
0066 }
0067 
0068 consteval core_name_skip make_core_name_skip(std::size_t size_at_begin,
0069                                              std::size_t size_at_end,
0070                                              backward until_runtime) noexcept
0071 {
0072     return core_name_skip{size_at_begin, size_at_end, true, until_runtime.value};
0073 }
0074 
0075 // it might be compilation failed without this workaround sometimes
0076 // See https://github.com/llvm/llvm-project/issues/41751 for details
0077 template <class>
0078 consteval std::string_view clang_workaround(std::string_view value) noexcept
0079 {
0080     return value;
0081 }
0082 
0083 template <class MsvcWorkaround, auto ptr>
0084 consteval auto name_of_field_impl() noexcept {
0085     // Some of the following compiler specific macro may be defined only
0086     // inside the function body:
0087 
0088 #ifndef BOOST_PFR_FUNCTION_SIGNATURE
0089 #   if defined(__FUNCSIG__)
0090 #       define BOOST_PFR_FUNCTION_SIGNATURE __FUNCSIG__
0091 #   elif defined(__PRETTY_FUNCTION__) || defined(__GNUC__) || defined(__clang__)
0092 #       define BOOST_PFR_FUNCTION_SIGNATURE __PRETTY_FUNCTION__
0093 #   else
0094 #       define BOOST_PFR_FUNCTION_SIGNATURE ""
0095 #   endif
0096 #endif
0097 
0098     constexpr std::string_view sv = detail::clang_workaround<MsvcWorkaround>(BOOST_PFR_FUNCTION_SIGNATURE);
0099     static_assert(!sv.empty(),
0100         "====================> Boost.PFR: Field reflection parser configured in a wrong way. "
0101         "Please define the BOOST_PFR_FUNCTION_SIGNATURE to a compiler specific macro, "
0102         "that outputs the whole function signature including non-type template parameters."  
0103     );
0104 
0105     constexpr auto skip = detail::make_core_name_skip BOOST_PFR_CORE_NAME_PARSING;
0106     static_assert(skip.size_at_begin + skip.size_at_end + skip.until_runtime.size() < sv.size(),
0107         "====================> Boost.PFR: Field reflection parser configured in a wrong way. "
0108         "It attempts to skip more chars than available. "
0109         "Please define BOOST_PFR_CORE_NAME_PARSING to correct values. See documentation section "
0110         "'Limitations and Configuration' for more information."
0111     );
0112     constexpr auto fn = skip.apply(sv);
0113     static_assert(
0114         !fn.empty(),
0115         "====================> Boost.PFR: Extraction of field name is misconfigured for your compiler. "
0116         "It skipped all the input, leaving the field name empty. "
0117         "Please define BOOST_PFR_CORE_NAME_PARSING to correct values. See documentation section "
0118         "'Limitations and Configuration' for more information."
0119     );
0120     auto res = std::array<char, fn.size()+1>{};
0121 
0122     auto* out = res.data();
0123     for (auto x: fn) {
0124         *out = x;
0125         ++out;
0126     }
0127 
0128     return res;
0129 }
0130 
0131 #ifdef __clang__
0132 #pragma clang diagnostic push
0133 #pragma clang diagnostic ignored "-Wundefined-var-template"
0134 
0135 // clang 16 and earlier don't support address of non-static member as template parameter
0136 // but fortunately it's possible to use C++20 non-type template parameters in another way
0137 // even in clang 16 and more older clangs
0138 // all we need is to wrap pointer into 'clang_wrapper_t' and then pass it into template
0139 template <class T>
0140 struct clang_wrapper_t {
0141     T v;
0142 };
0143 template <class T>
0144 clang_wrapper_t(T) -> clang_wrapper_t<T>;
0145 
0146 template <class T>
0147 constexpr auto make_clang_wrapper(const T& arg) noexcept {
0148     return clang_wrapper_t{arg};
0149 }
0150 
0151 #else
0152 
0153 template <class T>
0154 constexpr const T& make_clang_wrapper(const T& arg) noexcept {
0155     // It's everything OK with address of non-static member as template parameter support on this compiler
0156     // so we don't need a wrapper here, just pass the pointer into template
0157     return arg;
0158 }
0159 
0160 #endif
0161 
0162 template <class MsvcWorkaround, auto ptr>
0163 consteval auto name_of_field() noexcept {
0164     // Sanity check: known field name must match the deduced one
0165     static_assert(
0166         sizeof(MsvcWorkaround)  // do not trigger if `name_of_field()` is not used
0167         && std::string_view{
0168             detail::name_of_field_impl<
0169                 core_name_skip, detail::make_clang_wrapper(std::addressof(
0170                     detail::fake_object<core_name_skip>().size_at_begin
0171                 ))
0172             >().data()
0173         } == "size_at_begin",
0174         "====================> Boost.PFR: Extraction of field name is misconfigured for your compiler. "
0175         "It does not return the proper field name. "
0176         "Please define BOOST_PFR_CORE_NAME_PARSING to correct values. See documentation section "
0177         "'Limitations and Configuration' for more information."
0178     );
0179 
0180     return detail::name_of_field_impl<MsvcWorkaround, ptr>();
0181 }
0182 
0183 // Storing part of a string literal into an array minimizes the binary size.
0184 //
0185 // Without passing 'T' into 'name_of_field' different fields from different structures might have the same name!
0186 // See https://developercommunity.visualstudio.com/t/__FUNCSIG__-outputs-wrong-value-with-C/10458554 for details
0187 template <class T, std::size_t I>
0188 inline constexpr auto stored_name_of_field = detail::name_of_field<T,
0189     detail::make_clang_wrapper(std::addressof(detail::sequence_tuple::get<I>(
0190         detail::tie_as_tuple(detail::fake_object<T>())
0191     )))
0192 >();
0193 
0194 #ifdef __clang__
0195 #pragma clang diagnostic pop
0196 #endif
0197 
0198 template <class T, std::size_t... I>
0199 constexpr auto tie_as_names_tuple_impl(std::index_sequence<I...>) noexcept {
0200     return detail::sequence_tuple::make_sequence_tuple(std::string_view{stored_name_of_field<T, I>.data()}...);
0201 }
0202 
0203 template <class T, std::size_t I>
0204 constexpr std::string_view get_name() noexcept {
0205     static_assert(
0206         !std::is_union<T>::value,
0207         "====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
0208     );
0209     static_assert(
0210         !std::is_array<T>::value,
0211         "====================> Boost.PFR: It is impossible to extract name from old C array since it doesn't have named members"
0212     );
0213     static_assert(
0214         sizeof(T) && BOOST_PFR_USE_CPP17,
0215         "====================> Boost.PFR: Extraction of field's names is allowed only when the BOOST_PFR_USE_CPP17 macro enabled."
0216    );
0217 
0218    return stored_name_of_field<T, I>.data();
0219 }
0220 
0221 template <class T>
0222 constexpr auto tie_as_names_tuple() noexcept {
0223     static_assert(
0224         !std::is_union<T>::value,
0225         "====================> Boost.PFR: For safety reasons it is forbidden to reflect unions. See `Reflection of unions` section in the docs for more info."
0226     );
0227     static_assert(
0228         !std::is_array<T>::value,
0229         "====================> Boost.PFR: It is impossible to extract name from old C array since it doesn't have named members"
0230     );
0231     static_assert(
0232         sizeof(T) && BOOST_PFR_USE_CPP17,
0233         "====================> Boost.PFR: Extraction of field's names is allowed only when the BOOST_PFR_USE_CPP17 macro enabled."
0234     );
0235 
0236     return detail::tie_as_names_tuple_impl<T>(detail::make_index_sequence<detail::fields_count<T>()>{});
0237 }
0238 
0239 }}} // namespace boost::pfr::detail
0240 
0241 #endif // BOOST_PFR_DETAIL_CORE_NAME20_STATIC_HPP
0242