]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/pfr/detail/offset_based_getter.hpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / boost / pfr / detail / offset_based_getter.hpp
CommitLineData
20effc67 1// Copyright (c) 2017-2018 Chris Beck
1e59de90 2// Copyright (c) 2019-2022 Antony Polukhin
20effc67
TL
3//
4// Distributed under the Boost Software License, Version 1.0. (See accompanying
5// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6
7#ifndef BOOST_PFR_DETAIL_OFFSET_BASED_GETTER_HPP
8#define BOOST_PFR_DETAIL_OFFSET_BASED_GETTER_HPP
9#pragma once
10
11#include <boost/pfr/detail/config.hpp>
12
13#include <type_traits>
14#include <utility>
1e59de90 15#include <memory> // std::addressof
20effc67
TL
16#include <boost/pfr/detail/sequence_tuple.hpp>
17#include <boost/pfr/detail/rvalue_t.hpp>
18#include <boost/pfr/detail/size_t_.hpp>
19
20
21namespace boost { namespace pfr { namespace detail {
22
23// Our own implementation of std::aligned_storage. On godbolt with MSVC, I have compilation errors
24// using the standard version, it seems the compiler cannot generate default ctor.
25
26template<std::size_t s, std::size_t a>
27struct internal_aligned_storage {
28 alignas(a) char storage_[s];
29};
30
31// Metafunction that replaces tuple<T1, T2, T3, ...> with
32// tuple<std::aligned_storage_t<sizeof(T1), alignof(T1)>, std::aligned_storage<sizeof(T2), alignof(T2)>, ...>
33//
34// The point is, the new tuple is "layout compatible" in the sense that members have the same offsets,
35// but this tuple is constexpr constructible.
36
37template <typename T>
38struct tuple_of_aligned_storage;
39
40template <typename... Ts>
41struct tuple_of_aligned_storage<sequence_tuple::tuple<Ts...>> {
42 using type = sequence_tuple::tuple<internal_aligned_storage<sizeof(Ts),
43#if defined(__GNUC__) && __GNUC__ < 8 && !defined(__x86_64__) && !defined(__CYGWIN__)
44 // Before GCC-8 the `alignof` was returning the optimal alignment rather than the minimal one.
45 // We have to adjust the alignemnt because otherwise we get the wrong offset.
46 (alignof(Ts) > 4 ? 4 : alignof(Ts))
47#else
48 alignof(Ts)
49#endif
50 >...>;
51};
52
53// Note: If pfr has a typelist also, could also have an overload for that here
54
55template <typename T>
56using tuple_of_aligned_storage_t = typename tuple_of_aligned_storage<T>::type;
57
58/***
59 * Given a structure type and its sequence of members, we want to build a function
60 * object "getter" that implements a version of `std::get` using offset arithmetic
61 * and reinterpret_cast.
62 *
63 * typename U should be a user-defined struct
64 * typename S should be a sequence_tuple which is layout compatible with U
65 */
66
67template <typename U, typename S>
68class offset_based_getter {
69 using this_t = offset_based_getter<U, S>;
70
71 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?");
72 static_assert(alignof(U) == alignof(S), "====================> Boost.PFR: Member sequence does not indicate correct alignment for struct type!");
73
74 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");
75 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");
76 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");
77
78 // Get type of idx'th member
79 template <std::size_t idx>
80 using index_t = typename sequence_tuple::tuple_element<idx, S>::type;
81
82 // Get offset of idx'th member
83 // Idea: Layout object has the same offsets as instance of S, so if S and U are layout compatible, then these offset
84 // calculations are correct.
85 template <std::size_t idx>
86 static constexpr std::ptrdiff_t offset() noexcept {
87 constexpr tuple_of_aligned_storage_t<S> layout{};
88 return &sequence_tuple::get<idx>(layout).storage_[0] - &sequence_tuple::get<0>(layout).storage_[0];
89 }
90
91 // Encapsulates offset arithmetic and reinterpret_cast
92 template <std::size_t idx>
93 static index_t<idx> * get_pointer(U * u) noexcept {
94 return reinterpret_cast<index_t<idx> *>(reinterpret_cast<char *>(u) + this_t::offset<idx>());
95 }
96
97 template <std::size_t idx>
98 static const index_t<idx> * get_pointer(const U * u) noexcept {
99 return reinterpret_cast<const index_t<idx> *>(reinterpret_cast<const char *>(u) + this_t::offset<idx>());
100 }
101
102 template <std::size_t idx>
103 static volatile index_t<idx> * get_pointer(volatile U * u) noexcept {
104 return reinterpret_cast<volatile index_t<idx> *>(reinterpret_cast<volatile char *>(u) + this_t::offset<idx>());
105 }
106
107 template <std::size_t idx>
108 static const volatile index_t<idx> * get_pointer(const volatile U * u) noexcept {
109 return reinterpret_cast<const volatile index_t<idx> *>(reinterpret_cast<const volatile char *>(u) + this_t::offset<idx>());
110 }
111
112public:
113 template <std::size_t idx>
114 index_t<idx> & get(U & u, size_t_<idx>) const noexcept {
115 return *this_t::get_pointer<idx>(std::addressof(u));
116 }
117
118 template <std::size_t idx>
119 index_t<idx> const & get(U const & u, size_t_<idx>) const noexcept {
120 return *this_t::get_pointer<idx>(std::addressof(u));
121 }
122
123 template <std::size_t idx>
124 index_t<idx> volatile & get(U volatile & u, size_t_<idx>) const noexcept {
125 return *this_t::get_pointer<idx>(std::addressof(u));
126 }
127
128 template <std::size_t idx>
129 index_t<idx> const volatile & get(U const volatile & u, size_t_<idx>) const noexcept {
130 return *this_t::get_pointer<idx>(std::addressof(u));
131 }
132
133 // rvalues must not be used here, to avoid template instantiation bloats.
134 template <std::size_t idx>
135 index_t<idx> && get(rvalue_t<U> u, size_t_<idx>) const = delete;
136};
137
138
139}}} // namespace boost::pfr::detail
140
141#endif // BOOST_PFR_DETAIL_OFFSET_LIST_HPP