Coverage Report

Created: 2025-11-11 06:12

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/immer/immer/detail/util.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 <immer/config.hpp>
12
13
#include <cstddef>
14
#include <memory>
15
#include <new>
16
#include <type_traits>
17
18
#include <immer/detail/type_traits.hpp>
19
20
#if defined(_MSC_VER)
21
#include <intrin.h> // for __lzcnt*
22
#endif
23
24
namespace immer {
25
namespace detail {
26
27
template <typename T>
28
const T* as_const(T* x)
29
{
30
    return x;
31
}
32
33
template <typename T>
34
const T& as_const(T& x)
35
{
36
    return x;
37
}
38
39
template <std::size_t Size, std::size_t Align>
40
struct aligned_storage
41
{
42
    struct type
43
    {
44
        alignas(Align) unsigned char data[Size];
45
    };
46
};
47
48
template <std::size_t Size, std::size_t Align>
49
using aligned_storage_t = typename aligned_storage<Size, Align>::type;
50
51
template <typename T>
52
using aligned_storage_for =
53
    typename aligned_storage<sizeof(T), alignof(T)>::type;
54
55
template <typename T>
56
T& auto_const_cast(const T& x)
57
17.9M
{
58
17.9M
    return const_cast<T&>(x);
59
17.9M
}
60
template <typename T>
61
T&& auto_const_cast(const T&& x)
62
{
63
    return const_cast<T&&>(std::move(x));
64
}
65
66
template <class T>
67
inline auto destroy_at(T* p) noexcept
68
    -> std::enable_if_t<std::is_trivially_destructible<T>::value>
69
{
70
    p->~T();
71
}
72
73
template <class T>
74
inline auto destroy_at(T* p) noexcept
75
    -> std::enable_if_t<!std::is_trivially_destructible<T>::value>
76
1.08M
{
77
1.08M
    p->~T();
78
1.08M
}
79
80
template <typename Iter1>
81
constexpr bool can_trivially_detroy = std::is_trivially_destructible<
82
    typename std::iterator_traits<Iter1>::value_type>::value;
83
84
template <class Iter>
85
auto destroy(Iter, Iter last) noexcept
86
    -> std::enable_if_t<can_trivially_detroy<Iter>, Iter>
87
{
88
    return last;
89
}
90
template <class Iter>
91
auto destroy(Iter first, Iter last) noexcept
92
    -> std::enable_if_t<!can_trivially_detroy<Iter>, Iter>
93
0
{
94
0
    for (; first != last; ++first)
95
0
        detail::destroy_at(std::addressof(*first));
96
0
    return first;
97
0
}
98
99
template <class Iter, class Size>
100
auto destroy_n(Iter first, Size n) noexcept
101
    -> std::enable_if_t<can_trivially_detroy<Iter>, Iter>
102
{
103
    return first + n;
104
}
105
template <class Iter, class Size>
106
auto destroy_n(Iter first, Size n) noexcept
107
    -> std::enable_if_t<!can_trivially_detroy<Iter>, Iter>
108
408k
{
109
1.49M
    for (; n > 0; (void) ++first, --n)
110
1.08M
        detail::destroy_at(std::addressof(*first));
111
408k
    return first;
112
408k
}
113
114
template <typename Iter1, typename Iter2>
115
constexpr bool can_trivially_copy =
116
    std::is_same<typename std::iterator_traits<Iter1>::value_type,
117
                 typename std::iterator_traits<Iter2>::value_type>::value &&
118
    std::is_trivially_copyable<
119
        typename std::iterator_traits<Iter1>::value_type>::value;
120
121
template <typename Iter1, typename Iter2>
122
auto uninitialized_move(Iter1 first, Iter1 last, Iter2 out) noexcept
123
    -> std::enable_if_t<can_trivially_copy<Iter1, Iter2>, Iter2>
124
{
125
    return std::copy(first, last, out);
126
}
127
template <typename Iter1, typename Iter2>
128
auto uninitialized_move(Iter1 first, Iter1 last, Iter2 out)
129
    -> std::enable_if_t<!can_trivially_copy<Iter1, Iter2>, Iter2>
130
131
22.2k
{
132
22.2k
    using value_t = typename std::iterator_traits<Iter2>::value_type;
133
22.2k
    auto current  = out;
134
22.2k
    IMMER_TRY {
135
51.4k
        for (; first != last; ++first, (void) ++current) {
136
29.1k
            ::new (const_cast<void*>(static_cast<const volatile void*>(
137
29.1k
                std::addressof(*current)))) value_t(std::move(*first));
138
29.1k
        }
139
22.2k
        return current;
140
22.2k
    }
141
22.2k
    IMMER_CATCH (...) {
142
0
        detail::destroy(out, current);
143
0
        IMMER_RETHROW;
144
0
    }
145
22.2k
}
146
147
template <typename SourceIter, typename Sent, typename SinkIter>
148
auto uninitialized_copy(SourceIter first, Sent last, SinkIter out) noexcept
149
    -> std::enable_if_t<can_trivially_copy<SourceIter, SinkIter>, SinkIter>
150
{
151
    return std::copy(first, last, out);
152
}
153
template <typename SourceIter, typename Sent, typename SinkIter>
154
auto uninitialized_copy(SourceIter first, Sent last, SinkIter out)
155
    -> std::enable_if_t<!can_trivially_copy<SourceIter, SinkIter>, SinkIter>
156
409k
{
157
409k
    using value_t = typename std::iterator_traits<SinkIter>::value_type;
158
409k
    auto current  = out;
159
409k
    IMMER_TRY {
160
1.36M
        for (; first != last; ++first, (void) ++current) {
161
960k
            ::new (const_cast<void*>(static_cast<const volatile void*>(
162
960k
                std::addressof(*current)))) value_t(*first);
163
960k
        }
164
409k
        return current;
165
409k
    }
166
409k
    IMMER_CATCH (...) {
167
0
        detail::destroy(out, current);
168
0
        IMMER_RETHROW;
169
0
    }
170
409k
}
171
172
template <typename Heap, typename T, typename... Args>
173
T* make(Args&&... args)
174
{
175
    auto ptr = Heap::allocate(sizeof(T));
176
    IMMER_TRY {
177
        return new (ptr) T{std::forward<Args>(args)...};
178
    }
179
    IMMER_CATCH (...) {
180
        Heap::deallocate(sizeof(T), ptr);
181
        IMMER_RETHROW;
182
    }
183
}
184
185
struct not_supported_t
186
{};
187
struct empty_t
188
{};
189
190
template <typename T>
191
struct exact_t
192
{
193
    T value;
194
    exact_t(T v)
195
        : value{v} {};
196
};
197
198
template <typename T>
199
inline constexpr auto clz_(T) -> not_supported_t
200
{
201
    IMMER_UNREACHABLE;
202
    return {};
203
}
204
#if defined(_MSC_VER)
205
// inline auto clz_(unsigned short x) { return __lzcnt16(x); }
206
// inline auto clz_(unsigned int x) { return __lzcnt(x); }
207
// inline auto clz_(unsigned __int64 x) { return __lzcnt64(x); }
208
#else
209
0
inline constexpr auto clz_(unsigned int x) { return __builtin_clz(x); }
210
0
inline constexpr auto clz_(unsigned long x) { return __builtin_clzl(x); }
211
0
inline constexpr auto clz_(unsigned long long x) { return __builtin_clzll(x); }
212
#endif
213
214
template <typename T>
215
inline constexpr T log2_aux(T x, T r = 0)
216
{
217
    return x <= 1 ? r : log2_aux(x >> 1, r + 1);
218
}
219
220
template <typename T>
221
inline constexpr auto log2(T x) -> std::
222
    enable_if_t<!std::is_same<decltype(clz_(x)), not_supported_t>::value, T>
223
{
224
    return x == 0 ? 0 : sizeof(std::size_t) * 8 - 1 - clz_(x);
225
}
226
227
template <typename T>
228
inline constexpr auto log2(T x)
229
    -> std::enable_if_t<std::is_same<decltype(clz_(x)), not_supported_t>::value,
230
                        T>
231
{
232
    return log2_aux(x);
233
}
234
235
template <typename T>
236
constexpr T ipow(T num, unsigned int pow)
237
{
238
    return pow == 0 ? 1 : num * ipow(num, pow - 1);
239
}
240
241
template <bool b, typename F>
242
auto static_if(F&& f) -> std::enable_if_t<b>
243
{
244
    std::forward<F>(f)(empty_t{});
245
}
246
template <bool b, typename F>
247
auto static_if(F&& f) -> std::enable_if_t<!b>
248
{
249
}
250
251
template <bool b, typename R = void, typename F1, typename F2>
252
auto static_if(F1&& f1, F2&& f2) -> std::enable_if_t<b, R>
253
{
254
    return std::forward<F1>(f1)(empty_t{});
255
}
256
template <bool b, typename R = void, typename F1, typename F2>
257
auto static_if(F1&& f1, F2&& f2) -> std::enable_if_t<!b, R>
258
{
259
    return std::forward<F2>(f2)(empty_t{});
260
}
261
262
template <typename T, T value>
263
struct constantly
264
{
265
    template <typename... Args>
266
    T operator()(Args&&...) const
267
526k
    {
268
526k
        return value;
269
526k
    }
unsigned long immer::detail::constantly<unsigned long, 1ul>::operator()<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&>(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) const
Line
Count
Source
267
263k
    {
268
263k
        return value;
269
263k
    }
unsigned long immer::detail::constantly<unsigned long, 0ul>::operator()<>() const
Line
Count
Source
267
263k
    {
268
263k
        return value;
269
263k
    }
270
};
271
272
/*!
273
 * An alias to `std::distance`
274
 */
275
template <typename Iterator,
276
          typename Sentinel,
277
          std::enable_if_t<detail::std_distance_supports_v<Iterator, Sentinel>,
278
                           bool> = true>
279
typename std::iterator_traits<Iterator>::difference_type
280
distance(Iterator first, Sentinel last)
281
{
282
    return std::distance(first, last);
283
}
284
285
/*!
286
 * Equivalent of the `std::distance` applied to the sentinel-delimited
287
 * forward range @f$ [first, last) @f$
288
 */
289
template <typename Iterator,
290
          typename Sentinel,
291
          std::enable_if_t<
292
              (!detail::std_distance_supports_v<Iterator, Sentinel>) &&detail::
293
                      is_forward_iterator_v<Iterator> &&
294
                  detail::compatible_sentinel_v<Iterator, Sentinel> &&
295
                  (!detail::is_subtractable_v<Sentinel, Iterator>),
296
              bool> = true>
297
typename std::iterator_traits<Iterator>::difference_type
298
distance(Iterator first, Sentinel last)
299
{
300
    std::size_t result = 0;
301
    while (first != last) {
302
        ++first;
303
        ++result;
304
    }
305
    return result;
306
}
307
308
/*!
309
 * Equivalent of the `std::distance` applied to the sentinel-delimited
310
 * random access range @f$ [first, last) @f$
311
 */
312
template <typename Iterator,
313
          typename Sentinel,
314
          std::enable_if_t<
315
              (!detail::std_distance_supports_v<Iterator, Sentinel>) &&detail::
316
                      is_forward_iterator_v<Iterator> &&
317
                  detail::compatible_sentinel_v<Iterator, Sentinel> &&
318
                  detail::is_subtractable_v<Sentinel, Iterator>,
319
              bool> = true>
320
typename std::iterator_traits<Iterator>::difference_type
321
distance(Iterator first, Sentinel last)
322
{
323
    return last - first;
324
}
325
326
} // namespace detail
327
} // namespace immer