Back to home page

EIC code displayed by LXR

 
 

    


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

0001 // Copyright (c) 2017-2018 Chris Beck
0002 // Copyright (c) 2019-2025 Antony Polukhin
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 
0007 #ifndef BOOST_PFR_DETAIL_OFFSET_BASED_GETTER_HPP
0008 #define BOOST_PFR_DETAIL_OFFSET_BASED_GETTER_HPP
0009 #pragma once
0010 
0011 #include <boost/pfr/detail/config.hpp>
0012 
0013 #ifdef BOOST_PFR_HAS_STD_MODULE
0014 import std;
0015 #else
0016 #include <type_traits>
0017 #include <utility>
0018 #include <memory>  // std::addressof
0019 #endif
0020 
0021 #include <boost/pfr/detail/sequence_tuple.hpp>
0022 #include <boost/pfr/detail/rvalue_t.hpp>
0023 #include <boost/pfr/detail/size_t_.hpp>
0024 
0025 
0026 namespace boost { namespace pfr { namespace detail {
0027 
0028 // Our own implementation of std::aligned_storage. On godbolt with MSVC, I have compilation errors
0029 // using the standard version, it seems the compiler cannot generate default ctor.
0030 
0031 template<std::size_t s, std::size_t a>
0032 struct internal_aligned_storage {
0033    alignas(a) char storage_[s];
0034 };
0035 
0036 // Metafunction that replaces tuple<T1, T2, T3, ...> with
0037 // tuple<std::aligned_storage_t<sizeof(T1), alignof(T1)>, std::aligned_storage<sizeof(T2), alignof(T2)>, ...>
0038 //
0039 // The point is, the new tuple is "layout compatible" in the sense that members have the same offsets,
0040 // but this tuple is constexpr constructible.
0041 
0042 template <typename T>
0043 struct tuple_of_aligned_storage;
0044 
0045 template <typename... Ts>
0046 struct tuple_of_aligned_storage<sequence_tuple::tuple<Ts...>> {
0047   using type = sequence_tuple::tuple<internal_aligned_storage<sizeof(Ts),
0048 #if defined(__GNUC__) && __GNUC__ < 8 && !defined(__x86_64__) && !defined(__CYGWIN__)
0049       // Before GCC-8 the `alignof` was returning the optimal alignment rather than the minimal one.
0050       // We have to adjust the alignment because otherwise we get the wrong offset.
0051       (alignof(Ts) > 4 ? 4 : alignof(Ts))
0052 #else
0053       alignof(Ts)
0054 #endif
0055   >...>;
0056 };
0057 
0058 // Note: If pfr has a typelist also, could also have an overload for that here
0059 
0060 template <typename T>
0061 using tuple_of_aligned_storage_t = typename tuple_of_aligned_storage<T>::type;
0062 
0063 /***
0064  * Given a structure type and its sequence of members, we want to build a function
0065  * object "getter" that implements a version of `std::get` using offset arithmetic
0066  * and reinterpret_cast.
0067  *
0068  * typename U should be a user-defined struct
0069  * typename S should be a sequence_tuple which is layout compatible with U
0070  */
0071 
0072 template <typename U, typename S>
0073 class offset_based_getter {
0074   using this_t = offset_based_getter<U, S>;
0075 
0076   static_assert(sizeof(U) == sizeof(S), "====================> Boost.PFR: Member sequence does not indicate correct size for struct type! Maybe the user-provided type is not a SimpleAggregate?");
0077   static_assert(alignof(U) == alignof(S), "====================> Boost.PFR: Member sequence does not indicate correct alignment for struct type!");
0078 
0079   static_assert(!std::is_const<U>::value, "====================> Boost.PFR: const should be stripped from user-defined type when using offset_based_getter or overload resolution will be ambiguous later, this indicates an error within pfr");
0080   static_assert(!std::is_reference<U>::value, "====================> Boost.PFR: reference should be stripped from user-defined type when using offset_based_getter or overload resolution will be ambiguous later, this indicates an error within pfr");
0081   static_assert(!std::is_volatile<U>::value, "====================> Boost.PFR: volatile should be stripped from user-defined type when using offset_based_getter or overload resolution will be ambiguous later. this indicates an error within pfr");
0082 
0083   // Get type of idx'th member
0084   template <std::size_t idx>
0085   using index_t = typename sequence_tuple::tuple_element<idx, S>::type;
0086 
0087   // Get offset of idx'th member
0088   // Idea: Layout object has the same offsets as instance of S, so if S and U are layout compatible, then these offset
0089   // calculations are correct.
0090   template <std::size_t idx>
0091   static constexpr std::ptrdiff_t offset() noexcept {
0092     constexpr tuple_of_aligned_storage_t<S> layout{};
0093     return &sequence_tuple::get<idx>(layout).storage_[0] - &sequence_tuple::get<0>(layout).storage_[0];
0094   }
0095 
0096   // Encapsulates offset arithmetic and reinterpret_cast
0097   template <std::size_t idx>
0098   static index_t<idx> * get_pointer(U * u) noexcept {
0099     return reinterpret_cast<index_t<idx> *>(reinterpret_cast<char *>(u) + this_t::offset<idx>());
0100   }
0101 
0102   template <std::size_t idx>
0103   static const index_t<idx> * get_pointer(const U * u) noexcept {
0104     return reinterpret_cast<const index_t<idx> *>(reinterpret_cast<const char *>(u) + this_t::offset<idx>());
0105   }
0106 
0107   template <std::size_t idx>
0108   static volatile index_t<idx> * get_pointer(volatile U * u) noexcept {
0109     return reinterpret_cast<volatile index_t<idx> *>(reinterpret_cast<volatile char *>(u) + this_t::offset<idx>());
0110   }
0111 
0112   template <std::size_t idx>
0113   static const volatile index_t<idx> * get_pointer(const volatile U * u) noexcept {
0114     return reinterpret_cast<const volatile index_t<idx> *>(reinterpret_cast<const volatile char *>(u) + this_t::offset<idx>());
0115   }
0116 
0117 public:
0118   template <std::size_t idx>
0119   index_t<idx> & get(U & u, size_t_<idx>) const noexcept {
0120     return *this_t::get_pointer<idx>(std::addressof(u));
0121   }
0122 
0123   template <std::size_t idx>
0124   index_t<idx> const & get(U const & u, size_t_<idx>) const noexcept {
0125     return *this_t::get_pointer<idx>(std::addressof(u));
0126   }
0127 
0128   template <std::size_t idx>
0129   index_t<idx> volatile & get(U volatile & u, size_t_<idx>) const noexcept {
0130     return *this_t::get_pointer<idx>(std::addressof(u));
0131   }
0132 
0133   template <std::size_t idx>
0134   index_t<idx> const volatile & get(U const volatile & u, size_t_<idx>) const noexcept {
0135     return *this_t::get_pointer<idx>(std::addressof(u));
0136   }
0137 
0138   // rvalues must not be used here, to avoid template instantiation bloats.
0139   template <std::size_t idx>
0140   index_t<idx> && get(rvalue_t<U> u, size_t_<idx>) const = delete;
0141 };
0142 
0143 
0144 }}} // namespace boost::pfr::detail
0145 
0146 #endif // BOOST_PFR_DETAIL_OFFSET_LIST_HPP