Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:41:00

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