Coverage Report

Created: 2025-12-11 06:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/immer/immer/detail/combine_standard_layout.hpp
Line
Count
Source
1
//
2
// immer: immutable data structures for C++
3
// Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
4
//
5
// This software is distributed under the Boost Software License, Version 1.0.
6
// See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
7
//
8
9
#pragma once
10
11
#include <cstddef>
12
#include <type_traits>
13
14
#if defined(__GNUC__) && __GNUC__ == 7 && __GNUC_MINOR__ == 1
15
#define IMMER_BROKEN_STANDARD_LAYOUT_DETECTION 1
16
#define immer_offsetof(st, m) ((std::size_t) & (((st*) 0)->m))
17
#else
18
#define IMMER_BROKEN_STANDARD_LAYOUT_DETECTION 0
19
4.99M
#define immer_offsetof offsetof
20
#endif
21
22
namespace immer {
23
namespace detail {
24
25
//
26
// Metafunction that returns a standard layout struct that combines
27
// all the standard layout types in `Ts...`, while making sure that
28
// empty base optimizations are used.
29
//
30
// To query a part of the type do `get<my_part>(x)`;
31
//
32
// This is useful when putting together a type that merges various
33
// types coming from different policies.  Some of them might be empty,
34
// so we shall enable empty base optimizations.  But if we just
35
// inherit from all of them, we would break the "standard layout"
36
// rules, preventing us from using `offseof(...)`.  So metafunction
37
// will generate the type by sometimes inheriting, sometimes adding as
38
// member.
39
//
40
// Note that the types are added to the combined type from right to
41
// left!
42
//
43
template <typename... Ts>
44
struct combine_standard_layout;
45
46
template <typename... Ts>
47
using combine_standard_layout_t = typename combine_standard_layout<Ts...>::type;
48
49
namespace csl {
50
51
template <typename T>
52
struct type_t
53
{};
54
55
template <typename U, typename T>
56
U& get(T& x);
57
58
template <typename U, typename T>
59
const U& get(const T& x);
60
61
template <typename T, typename Next = void>
62
struct inherit
63
{
64
    struct type
65
        : T
66
        , Next
67
    {
68
        using Next::get_;
69
70
        template <typename U>
71
        friend decltype(auto) get(type& x)
72
        {
73
            return x.get_(type_t<U>{});
74
        }
75
        template <typename U>
76
        friend decltype(auto) get(const type& x)
77
        {
78
            return x.get_(type_t<U>{});
79
        }
80
81
        T& get_(type_t<T>) { return *this; }
82
        const T& get_(type_t<T>) const { return *this; }
83
    };
84
};
85
86
template <typename T>
87
struct inherit<T, void>
88
{
89
    struct type : T
90
    {
91
        template <typename U>
92
        friend decltype(auto) get(type& x)
93
        {
94
            return x.get_(type_t<U>{});
95
        }
96
        template <typename U>
97
        friend decltype(auto) get(const type& x)
98
        {
99
            return x.get_(type_t<U>{});
100
        }
101
102
63.8k
        T& get_(type_t<T>) { return *this; }
103
8.93k
        const T& get_(type_t<T>) const { return *this; }
104
    };
105
};
106
107
template <typename T, typename Next = void>
108
struct member
109
{
110
    struct type : Next
111
    {
112
        T d;
113
114
        using Next::get_;
115
116
        template <typename U>
117
        friend decltype(auto) get(type& x)
118
        {
119
            return x.get_(type_t<U>{});
120
        }
121
        template <typename U>
122
        friend decltype(auto) get(const type& x)
123
        {
124
            return x.get_(type_t<U>{});
125
        }
126
127
        T& get_(type_t<T>) { return d; }
128
6.65M
        const T& get_(type_t<T>) const { return d; }
129
    };
130
};
131
132
template <typename T>
133
struct member<T, void>
134
{
135
    struct type
136
    {
137
        T d;
138
139
        template <typename U>
140
        friend decltype(auto) get(type& x)
141
        {
142
            return x.get_(type_t<U>{});
143
        }
144
        template <typename U>
145
        friend decltype(auto) get(const type& x)
146
        {
147
            return x.get_(type_t<U>{});
148
        }
149
150
        T& get_(type_t<T>) { return d; }
151
        const T& get_(type_t<T>) const { return d; }
152
    };
153
};
154
155
template <typename T, typename Next>
156
struct member_two
157
{
158
    struct type
159
    {
160
        Next n;
161
        T d;
162
163
        template <typename U>
164
        friend decltype(auto) get(type& x)
165
63.8k
        {
166
63.8k
            return x.get_(type_t<U>{});
167
63.8k
        }
decltype(auto) immer::detail::csl::get<immer::no_transience_policy::apply<immer::free_list_heap_policy<immer::cpp_heap, 1024ul> >::type::ownee>(immer::detail::csl::member_two<immer::detail::hamts::node<unsigned long, colliding_hash_t, std::__1::equal_to<unsigned long>, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true>, 5u>::impl_data_t, immer::detail::csl::member<immer::refcount_policy, immer::detail::csl::inherit<immer::no_transience_policy::apply<immer::free_list_heap_policy<immer::cpp_heap, 1024ul> >::type::ownee, void>::type>::type>::type&)
Line
Count
Source
165
39.4k
        {
166
39.4k
            return x.get_(type_t<U>{});
167
39.4k
        }
decltype(auto) immer::detail::csl::get<immer::no_transience_policy::apply<immer::free_list_heap_policy<immer::cpp_heap, 1024ul> >::type::ownee>(immer::detail::csl::member_two<immer::detail::hamts::node<unsigned long, colliding_hash_t, std::__1::equal_to<unsigned long>, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true>, 5u>::values_data_t, immer::detail::csl::member<immer::refcount_policy, immer::detail::csl::inherit<immer::no_transience_policy::apply<immer::free_list_heap_policy<immer::cpp_heap, 1024ul> >::type::ownee, void>::type>::type>::type&)
Line
Count
Source
165
24.3k
        {
166
24.3k
            return x.get_(type_t<U>{});
167
24.3k
        }
168
        template <typename U>
169
        friend decltype(auto) get(const type& x)
170
6.66M
        {
171
6.66M
            return x.get_(type_t<U>{});
172
6.66M
        }
decltype(auto) immer::detail::csl::get<immer::refcount_policy>(immer::detail::csl::member_two<immer::detail::hamts::node<unsigned long, colliding_hash_t, std::__1::equal_to<unsigned long>, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true>, 5u>::impl_data_t, immer::detail::csl::member<immer::refcount_policy, immer::detail::csl::inherit<immer::no_transience_policy::apply<immer::free_list_heap_policy<immer::cpp_heap, 1024ul> >::type::ownee, void>::type>::type>::type const&)
Line
Count
Source
170
5.62M
        {
171
5.62M
            return x.get_(type_t<U>{});
172
5.62M
        }
decltype(auto) immer::detail::csl::get<immer::refcount_policy>(immer::detail::csl::member_two<immer::detail::hamts::node<unsigned long, colliding_hash_t, std::__1::equal_to<unsigned long>, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true>, 5u>::values_data_t, immer::detail::csl::member<immer::refcount_policy, immer::detail::csl::inherit<immer::no_transience_policy::apply<immer::free_list_heap_policy<immer::cpp_heap, 1024ul> >::type::ownee, void>::type>::type>::type const&)
Line
Count
Source
170
1.02M
        {
171
1.02M
            return x.get_(type_t<U>{});
172
1.02M
        }
decltype(auto) immer::detail::csl::get<immer::no_transience_policy::apply<immer::free_list_heap_policy<immer::cpp_heap, 1024ul> >::type::ownee>(immer::detail::csl::member_two<immer::detail::hamts::node<unsigned long, colliding_hash_t, std::__1::equal_to<unsigned long>, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true>, 5u>::impl_data_t, immer::detail::csl::member<immer::refcount_policy, immer::detail::csl::inherit<immer::no_transience_policy::apply<immer::free_list_heap_policy<immer::cpp_heap, 1024ul> >::type::ownee, void>::type>::type>::type const&)
Line
Count
Source
170
8.93k
        {
171
8.93k
            return x.get_(type_t<U>{});
172
8.93k
        }
173
174
        T& get_(type_t<T>) { return d; }
175
        const T& get_(type_t<T>) const { return d; }
176
177
        template <typename U>
178
        auto get_(type_t<U> t) -> decltype(auto)
179
63.8k
        {
180
63.8k
            return n.get_(t);
181
63.8k
        }
decltype(auto) immer::detail::csl::member_two<immer::detail::hamts::node<unsigned long, colliding_hash_t, std::__1::equal_to<unsigned long>, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true>, 5u>::impl_data_t, immer::detail::csl::member<immer::refcount_policy, immer::detail::csl::inherit<immer::no_transience_policy::apply<immer::free_list_heap_policy<immer::cpp_heap, 1024ul> >::type::ownee, void>::type>::type>::type::get_<immer::no_transience_policy::apply<immer::free_list_heap_policy<immer::cpp_heap, 1024ul> >::type::ownee>(immer::detail::csl::type_t<immer::no_transience_policy::apply<immer::free_list_heap_policy<immer::cpp_heap, 1024ul> >::type::ownee>)
Line
Count
Source
179
39.4k
        {
180
39.4k
            return n.get_(t);
181
39.4k
        }
decltype(auto) immer::detail::csl::member_two<immer::detail::hamts::node<unsigned long, colliding_hash_t, std::__1::equal_to<unsigned long>, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true>, 5u>::values_data_t, immer::detail::csl::member<immer::refcount_policy, immer::detail::csl::inherit<immer::no_transience_policy::apply<immer::free_list_heap_policy<immer::cpp_heap, 1024ul> >::type::ownee, void>::type>::type>::type::get_<immer::no_transience_policy::apply<immer::free_list_heap_policy<immer::cpp_heap, 1024ul> >::type::ownee>(immer::detail::csl::type_t<immer::no_transience_policy::apply<immer::free_list_heap_policy<immer::cpp_heap, 1024ul> >::type::ownee>)
Line
Count
Source
179
24.3k
        {
180
24.3k
            return n.get_(t);
181
24.3k
        }
182
        template <typename U>
183
        auto get_(type_t<U> t) const -> decltype(auto)
184
6.66M
        {
185
6.66M
            return n.get_(t);
186
6.66M
        }
decltype(auto) immer::detail::csl::member_two<immer::detail::hamts::node<unsigned long, colliding_hash_t, std::__1::equal_to<unsigned long>, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true>, 5u>::impl_data_t, immer::detail::csl::member<immer::refcount_policy, immer::detail::csl::inherit<immer::no_transience_policy::apply<immer::free_list_heap_policy<immer::cpp_heap, 1024ul> >::type::ownee, void>::type>::type>::type::get_<immer::refcount_policy>(immer::detail::csl::type_t<immer::refcount_policy>) const
Line
Count
Source
184
5.62M
        {
185
5.62M
            return n.get_(t);
186
5.62M
        }
decltype(auto) immer::detail::csl::member_two<immer::detail::hamts::node<unsigned long, colliding_hash_t, std::__1::equal_to<unsigned long>, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true>, 5u>::values_data_t, immer::detail::csl::member<immer::refcount_policy, immer::detail::csl::inherit<immer::no_transience_policy::apply<immer::free_list_heap_policy<immer::cpp_heap, 1024ul> >::type::ownee, void>::type>::type>::type::get_<immer::refcount_policy>(immer::detail::csl::type_t<immer::refcount_policy>) const
Line
Count
Source
184
1.02M
        {
185
1.02M
            return n.get_(t);
186
1.02M
        }
decltype(auto) immer::detail::csl::member_two<immer::detail::hamts::node<unsigned long, colliding_hash_t, std::__1::equal_to<unsigned long>, immer::memory_policy<immer::free_list_heap_policy<immer::cpp_heap, 1024ul>, immer::refcount_policy, immer::spinlock_policy, immer::no_transience_policy, false, true>, 5u>::impl_data_t, immer::detail::csl::member<immer::refcount_policy, immer::detail::csl::inherit<immer::no_transience_policy::apply<immer::free_list_heap_policy<immer::cpp_heap, 1024ul> >::type::ownee, void>::type>::type>::type::get_<immer::no_transience_policy::apply<immer::free_list_heap_policy<immer::cpp_heap, 1024ul> >::type::ownee>(immer::detail::csl::type_t<immer::no_transience_policy::apply<immer::free_list_heap_policy<immer::cpp_heap, 1024ul> >::type::ownee>) const
Line
Count
Source
184
8.93k
        {
185
8.93k
            return n.get_(t);
186
8.93k
        }
187
    };
188
};
189
190
template <typename... Ts>
191
struct combine_standard_layout_aux;
192
193
template <typename T>
194
struct combine_standard_layout_aux<T>
195
{
196
    static_assert(std::is_standard_layout<T>::value, "");
197
198
    using type = typename std::conditional_t<std::is_empty<T>::value,
199
                                             csl::inherit<T>,
200
                                             csl::member<T>>::type;
201
};
202
203
template <typename T, typename... Ts>
204
struct combine_standard_layout_aux<T, Ts...>
205
{
206
    static_assert(std::is_standard_layout<T>::value, "");
207
208
    using this_t = T;
209
    using next_t = typename combine_standard_layout_aux<Ts...>::type;
210
211
    static constexpr auto empty_this = std::is_empty<this_t>::value;
212
    static constexpr auto empty_next = std::is_empty<next_t>::value;
213
214
    using type = typename std::conditional_t<
215
        empty_this,
216
        inherit<this_t, next_t>,
217
        std::conditional_t<empty_next,
218
                           member<this_t, next_t>,
219
                           member_two<this_t, next_t>>>::type;
220
};
221
222
} // namespace csl
223
224
using csl::get;
225
226
template <typename... Ts>
227
struct combine_standard_layout
228
{
229
    using type = typename csl::combine_standard_layout_aux<Ts...>::type;
230
#if !IMMER_BROKEN_STANDARD_LAYOUT_DETECTION
231
    static_assert(std::is_standard_layout<type>::value, "");
232
#endif
233
};
234
235
} // namespace detail
236
} // namespace immer