@auto_js/utility 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CMakeLists.txt +45 -0
- package/LICENSE +13 -0
- package/_module.cc +14 -0
- package/assertions.cc +32 -0
- package/container/mutable_priority_queue.cc +35 -0
- package/container/sealed_map.cc +121 -0
- package/container/segmented_priority_queue.cc +105 -0
- package/container/tinker_queue.cc +73 -0
- package/functional/bind.cc +151 -0
- package/functional/elide.cc +52 -0
- package/functional/flat_tuple.cc +90 -0
- package/functional/function_constant.cc +58 -0
- package/functional/function_ref.cc +68 -0
- package/functional/functional.cc +107 -0
- package/functional/regular_return.cc +55 -0
- package/include/auto_js/chunk_view.h +363 -0
- package/include/auto_js/no_unique_address.h +8 -0
- package/memory/autorelease_pool.cc +281 -0
- package/memory/comparator.cc +53 -0
- package/memory/memory.cc +64 -0
- package/memory/noinit_allocator.cc +64 -0
- package/meta/algorithm.cc +74 -0
- package/package.json +11 -0
- package/platform/lockable.cc +261 -0
- package/platform/shim/darwin.cc +8 -0
- package/platform/stop_token.cc +107 -0
- package/platform/timer.cc +175 -0
- package/platform/timer.h.cc +36 -0
- package/type_traits/function_traits.cc +173 -0
- package/type_traits/transform.cc +60 -0
- package/type_traits/type_of.cc +72 -0
- package/type_traits/type_pack.cc +116 -0
- package/type_traits/type_traits.cc +5 -0
- package/utility/constant_wrapper.cc +57 -0
- package/utility/covariant_value.cc +33 -0
- package/utility/facade.cc +126 -0
- package/utility/hash.cc +37 -0
- package/utility/ranges.cc +55 -0
- package/utility/string.cc +328 -0
- package/utility/utility.cc +150 -0
- package/utility/variant.cc +26 -0
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
// https://github.com/llvm/llvm-project/pull/85741
|
|
2
|
+
// -*- C++ -*-
|
|
3
|
+
//===----------------------------------------------------------------------===//
|
|
4
|
+
//
|
|
5
|
+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
6
|
+
// See https://llvm.org/LICENSE.txt for license information.
|
|
7
|
+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
8
|
+
//
|
|
9
|
+
//===----------------------------------------------------------------------===//
|
|
10
|
+
#include <version>
|
|
11
|
+
#ifdef _LIBCPP_VERSION
|
|
12
|
+
#ifndef _LIBCPP___RANGES_CHUNK_VIEW_H
|
|
13
|
+
#define _LIBCPP___RANGES_CHUNK_VIEW_H
|
|
14
|
+
|
|
15
|
+
#include <__concepts/constructible.h>
|
|
16
|
+
#include <__concepts/convertible_to.h>
|
|
17
|
+
#include <__functional/bind_back.h>
|
|
18
|
+
#include <__iterator/advance.h>
|
|
19
|
+
#include <__iterator/concepts.h>
|
|
20
|
+
#include <__iterator/default_sentinel.h>
|
|
21
|
+
#include <__iterator/distance.h>
|
|
22
|
+
#include <__iterator/iterator_traits.h>
|
|
23
|
+
#include <__ranges/access.h>
|
|
24
|
+
#include <__ranges/all.h>
|
|
25
|
+
#include <__ranges/concepts.h>
|
|
26
|
+
#include <__ranges/enable_borrowed_range.h>
|
|
27
|
+
#include <__ranges/subrange.h>
|
|
28
|
+
#include <__ranges/take_view.h>
|
|
29
|
+
#include <__ranges/view_interface.h>
|
|
30
|
+
#include <__type_traits/make_unsigned.h>
|
|
31
|
+
#include <__type_traits/maybe_const.h>
|
|
32
|
+
#include <__config>
|
|
33
|
+
|
|
34
|
+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
|
35
|
+
#pragma GCC system_header
|
|
36
|
+
#endif
|
|
37
|
+
|
|
38
|
+
_LIBCPP_PUSH_MACROS
|
|
39
|
+
#include <__undef_macros>
|
|
40
|
+
|
|
41
|
+
_LIBCPP_BEGIN_NAMESPACE_STD
|
|
42
|
+
|
|
43
|
+
#if _LIBCPP_STD_VER >= 23
|
|
44
|
+
|
|
45
|
+
namespace ranges {
|
|
46
|
+
|
|
47
|
+
template <class _Integer>
|
|
48
|
+
constexpr _Integer __div_ceil(_Integer __num, _Integer __denom) {
|
|
49
|
+
_Integer __r = __num / __denom;
|
|
50
|
+
if (__num % __denom) {
|
|
51
|
+
++__r;
|
|
52
|
+
}
|
|
53
|
+
return __r;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
template <view _View>
|
|
57
|
+
requires input_range<_View>
|
|
58
|
+
class chunk_view : public view_interface<chunk_view<_View>> {};
|
|
59
|
+
|
|
60
|
+
template <view _View>
|
|
61
|
+
requires forward_range<_View>
|
|
62
|
+
class chunk_view<_View> : public view_interface<chunk_view<_View>> {
|
|
63
|
+
private:
|
|
64
|
+
_LIBCPP_NO_UNIQUE_ADDRESS _View __base_;
|
|
65
|
+
range_difference_t<_View> __n_;
|
|
66
|
+
|
|
67
|
+
template <bool>
|
|
68
|
+
class __iterator;
|
|
69
|
+
|
|
70
|
+
public:
|
|
71
|
+
constexpr explicit chunk_view(_View __base, range_difference_t<_View> __n) :
|
|
72
|
+
__base_(std::move(__base)), __n_(__n) {
|
|
73
|
+
_LIBCPP_ASSERT_UNCATEGORIZED(__n > 0, "__n must be greater than 0");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
[[nodiscard]] constexpr _View base() const&
|
|
77
|
+
requires copy_constructible<_View>
|
|
78
|
+
{
|
|
79
|
+
return __base_;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
[[nodiscard]] constexpr _View base() && { return std::move(__base_); }
|
|
83
|
+
|
|
84
|
+
[[nodiscard]] constexpr auto begin()
|
|
85
|
+
requires(!__simple_view<_View>)
|
|
86
|
+
{
|
|
87
|
+
return __iterator<false>(this, ranges::begin(__base_));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
[[nodiscard]] constexpr auto begin() const
|
|
91
|
+
requires forward_range<const _View>
|
|
92
|
+
{
|
|
93
|
+
return __iterator<true>(this, ranges::begin(__base_));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
[[nodiscard]] constexpr auto end()
|
|
97
|
+
requires(!__simple_view<_View>)
|
|
98
|
+
{
|
|
99
|
+
if constexpr (common_range<_View> && sized_range<_View>) {
|
|
100
|
+
auto __missing = (__n_ - ranges::distance(__base_) % __n_) % __n_;
|
|
101
|
+
return __iterator<false>(this, ranges::end(__base_), __missing);
|
|
102
|
+
} else if constexpr (common_range<_View> && !bidirectional_range<_View>) {
|
|
103
|
+
return __iterator<false>(this, ranges::end(__base_));
|
|
104
|
+
} else {
|
|
105
|
+
return default_sentinel;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
[[nodiscard]] constexpr auto end() const
|
|
110
|
+
requires forward_range<_View>
|
|
111
|
+
{
|
|
112
|
+
if constexpr (common_range<const _View> && sized_range<const _View>) {
|
|
113
|
+
auto __missing = (__n_ - ranges::distance(__base_) % __n_) % __n_;
|
|
114
|
+
return __iterator<true>(this, ranges::end(__base_), __missing);
|
|
115
|
+
} else if constexpr (common_range<const _View> && !bidirectional_range<const _View>) {
|
|
116
|
+
return __iterator<true>(this, ranges::end(__base_));
|
|
117
|
+
} else {
|
|
118
|
+
return default_sentinel;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
[[nodiscard]] constexpr auto size()
|
|
123
|
+
requires sized_range<_View>
|
|
124
|
+
{
|
|
125
|
+
return std::__to_unsigned_like(__div_ceil(ranges::distance(__base_), __n_));
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
[[nodiscard]] constexpr auto size() const
|
|
129
|
+
requires sized_range<const _View>
|
|
130
|
+
{
|
|
131
|
+
return std::__to_unsigned_like(__div_ceil(ranges::distance(__base_), __n_));
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
template <class _View>
|
|
136
|
+
chunk_view(_View&&, range_difference_t<_View>) -> chunk_view<views::all_t<_View>>;
|
|
137
|
+
|
|
138
|
+
template <class _View>
|
|
139
|
+
constexpr inline bool enable_borrowed_range<chunk_view<_View>> = enable_borrowed_range<_View> && forward_range<_View>;
|
|
140
|
+
|
|
141
|
+
template <view _View>
|
|
142
|
+
requires forward_range<_View>
|
|
143
|
+
template <bool _Const>
|
|
144
|
+
class chunk_view<_View>::__iterator {
|
|
145
|
+
private:
|
|
146
|
+
friend chunk_view;
|
|
147
|
+
|
|
148
|
+
using _Parent = __maybe_const<_Const, chunk_view>;
|
|
149
|
+
using _Base = __maybe_const<_Const, _View>;
|
|
150
|
+
|
|
151
|
+
iterator_t<_Base> __current_ = iterator_t<_Base>();
|
|
152
|
+
sentinel_t<_Base> __end_ = sentinel_t<_Base>();
|
|
153
|
+
range_difference_t<_Base> __n_ = 0;
|
|
154
|
+
range_difference_t<_Base> __missing_ = 0;
|
|
155
|
+
|
|
156
|
+
constexpr __iterator(
|
|
157
|
+
_Parent* __parent,
|
|
158
|
+
iterator_t<_Base> __current,
|
|
159
|
+
range_difference_t<_Base> __missing = 0
|
|
160
|
+
) :
|
|
161
|
+
__current_(std::move(__current)),
|
|
162
|
+
__end_(ranges::end(__parent->__base_)),
|
|
163
|
+
__n_(__parent->__n_),
|
|
164
|
+
__missing_(__missing) {}
|
|
165
|
+
|
|
166
|
+
public:
|
|
167
|
+
using iterator_category = input_iterator_tag;
|
|
168
|
+
using iterator_concept =
|
|
169
|
+
conditional_t<random_access_range<_Base>, random_access_iterator_tag, conditional_t<bidirectional_range<_Base>, bidirectional_iterator_tag, forward_iterator_tag>>;
|
|
170
|
+
using value_type = decltype(views::take(subrange(__current_, __end_), __n_));
|
|
171
|
+
using difference_type = range_difference_t<_Base>;
|
|
172
|
+
|
|
173
|
+
__iterator() = default;
|
|
174
|
+
|
|
175
|
+
constexpr __iterator(__iterator<!_Const> __i)
|
|
176
|
+
requires _Const && convertible_to<iterator_t<_View>, iterator_t<_Base>> &&
|
|
177
|
+
convertible_to<sentinel_t<_View>, sentinel_t<_Base>>
|
|
178
|
+
:
|
|
179
|
+
__current_(std::move(__i.__current_)),
|
|
180
|
+
__end_(std::move(__i.__end_)),
|
|
181
|
+
__n_(__i.__n_),
|
|
182
|
+
__missing_(__i.__missing_) {}
|
|
183
|
+
|
|
184
|
+
[[nodiscard]] constexpr iterator_t<_Base> base() const { return __current_; }
|
|
185
|
+
|
|
186
|
+
[[nodiscard]] constexpr value_type operator*() const {
|
|
187
|
+
_LIBCPP_ASSERT_PEDANTIC(__current_ != __end_, "Dereferencing past-the-end chunk_view iterator");
|
|
188
|
+
return views::take(subrange(__current_, __end_), __n_);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
constexpr __iterator& operator++() {
|
|
192
|
+
_LIBCPP_ASSERT_PEDANTIC(__current_ != __end_, "Incrementing past-the-end chunk_view iterator");
|
|
193
|
+
__missing_ = ranges::advance(__current_, __n_, __end_);
|
|
194
|
+
return *this;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
constexpr __iterator operator++(int) {
|
|
198
|
+
auto __tmp = *this;
|
|
199
|
+
++*this;
|
|
200
|
+
return __tmp;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
constexpr __iterator& operator--()
|
|
204
|
+
requires bidirectional_range<_Base>
|
|
205
|
+
{
|
|
206
|
+
ranges::advance(__current_, __missing_ - __n_);
|
|
207
|
+
__missing_ = 0;
|
|
208
|
+
return *this;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
constexpr __iterator operator--(int)
|
|
212
|
+
requires bidirectional_range<_Base>
|
|
213
|
+
{
|
|
214
|
+
auto __tmp = *this;
|
|
215
|
+
--*this;
|
|
216
|
+
return __tmp;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
constexpr __iterator& operator+=(const difference_type __offset)
|
|
220
|
+
requires random_access_range<_Base>
|
|
221
|
+
{
|
|
222
|
+
if (__offset > 0) {
|
|
223
|
+
ranges::advance(__current_, __n_ * (__offset - 1));
|
|
224
|
+
__missing_ = ranges::advance(__current_, __n_, __end_);
|
|
225
|
+
} else if (__offset < 0) {
|
|
226
|
+
ranges::advance(__current_, __n_ * __offset + __missing_);
|
|
227
|
+
__missing_ = 0;
|
|
228
|
+
}
|
|
229
|
+
return *this;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
constexpr __iterator& operator-=(const difference_type __offset)
|
|
233
|
+
requires random_access_range<_Base>
|
|
234
|
+
{
|
|
235
|
+
return *this += -__offset;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
[[nodiscard]] constexpr value_type operator[](const difference_type __offset) const
|
|
239
|
+
requires random_access_range<_Base>
|
|
240
|
+
{
|
|
241
|
+
return *(*this + __offset);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
[[nodiscard]] constexpr friend bool
|
|
245
|
+
operator==(const __iterator& __x, const __iterator& __y) {
|
|
246
|
+
return __x.__current_ == __y.__current_;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
[[nodiscard]] constexpr friend bool
|
|
250
|
+
operator==(const __iterator& __x, default_sentinel_t) {
|
|
251
|
+
return __x.__current_ == __x.__end_;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
[[nodiscard]] constexpr friend bool
|
|
255
|
+
operator==(const __iterator& __x, const __iterator& __y)
|
|
256
|
+
requires random_access_range<_Base>
|
|
257
|
+
{
|
|
258
|
+
return __x.__current_ < __y.__current_;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
[[nodiscard]] constexpr friend bool
|
|
262
|
+
operator>(const __iterator& __x, const __iterator& __y)
|
|
263
|
+
requires random_access_range<_Base>
|
|
264
|
+
{
|
|
265
|
+
return __y < __x;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
[[nodiscard]] constexpr friend bool
|
|
269
|
+
operator<=(const __iterator& __x, const __iterator& __y)
|
|
270
|
+
requires random_access_range<_Base>
|
|
271
|
+
{
|
|
272
|
+
return !(__y < __x);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
[[nodiscard]] constexpr friend bool
|
|
276
|
+
operator>=(const __iterator& __x, const __iterator& __y)
|
|
277
|
+
requires random_access_range<_Base>
|
|
278
|
+
{
|
|
279
|
+
return !(__x < __y);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
[[nodiscard]] constexpr friend auto
|
|
283
|
+
operator<=>(const __iterator& __x, const __iterator& __y)
|
|
284
|
+
requires random_access_range<_Base> && three_way_comparable<iterator_t<_Base>>
|
|
285
|
+
{
|
|
286
|
+
return __x.__current_ <=> __y.__current_;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
[[nodiscard]] constexpr friend __iterator
|
|
290
|
+
operator+(const __iterator& __x, const difference_type __y)
|
|
291
|
+
requires random_access_range<_Base>
|
|
292
|
+
{
|
|
293
|
+
return __iterator{__x} += __y;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
[[nodiscard]] constexpr friend __iterator
|
|
297
|
+
operator+(const difference_type __x, const __iterator& __y)
|
|
298
|
+
requires random_access_range<_Base>
|
|
299
|
+
{
|
|
300
|
+
return __y + __x;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
[[nodiscard]] constexpr friend __iterator
|
|
304
|
+
operator-(const __iterator& __x, difference_type __y)
|
|
305
|
+
requires random_access_range<_Base>
|
|
306
|
+
{
|
|
307
|
+
return __iterator{__x} -= __y;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
[[nodiscard]] constexpr friend difference_type
|
|
311
|
+
operator-(const __iterator& __x, const __iterator& __y)
|
|
312
|
+
requires sized_sentinel_for<iterator_t<_Base>, iterator_t<_Base>>
|
|
313
|
+
{
|
|
314
|
+
return (__x.__current_ - __y.__current_ + __x.__missing_ - __y.__missing_) / __x.__n_;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
[[nodiscard]] constexpr friend difference_type
|
|
318
|
+
operator-(const default_sentinel_t, const __iterator& __x)
|
|
319
|
+
requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>>
|
|
320
|
+
{
|
|
321
|
+
return __div_ceil(__x.__end_ - __x.__current_, __x.__n_);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
[[nodiscard]] constexpr friend difference_type
|
|
325
|
+
operator-(const __iterator& __x, const default_sentinel_t __y)
|
|
326
|
+
requires sized_sentinel_for<sentinel_t<_Base>, iterator_t<_Base>>
|
|
327
|
+
{
|
|
328
|
+
return -(__y - __x);
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
namespace views {
|
|
333
|
+
namespace __chunk {
|
|
334
|
+
struct __fn {
|
|
335
|
+
template <class _Range, convertible_to<range_difference_t<_Range>> _Np>
|
|
336
|
+
[[nodiscard]] constexpr auto operator()(_Range&& __range, _Np&& __n) const noexcept(noexcept(chunk_view(std::forward<_Range>(__range), std::forward<_Np>(__n))))
|
|
337
|
+
-> decltype(chunk_view(std::forward<_Range>(__range), std::forward<_Np>(__n))) {
|
|
338
|
+
return chunk_view(std::forward<_Range>(__range), std::forward<_Np>(__n));
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
template <class _Np>
|
|
342
|
+
requires constructible_from<decay_t<_Np>, _Np>
|
|
343
|
+
[[nodiscard]] constexpr auto operator()(_Np&& __n) const noexcept(is_nothrow_constructible_v<decay_t<_Np>, _Np>) {
|
|
344
|
+
return __pipeable(std::__bind_back(*this, std::forward<_Np>(__n)));
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
} // namespace __chunk
|
|
348
|
+
|
|
349
|
+
inline namespace __cpo {
|
|
350
|
+
constexpr inline auto chunk = __chunk::__fn{};
|
|
351
|
+
} // namespace __cpo
|
|
352
|
+
} // namespace views
|
|
353
|
+
|
|
354
|
+
} // namespace ranges
|
|
355
|
+
|
|
356
|
+
#endif // _LIBCPP_STD_VER >= 23
|
|
357
|
+
|
|
358
|
+
_LIBCPP_END_NAMESPACE_STD
|
|
359
|
+
|
|
360
|
+
_LIBCPP_POP_MACROS
|
|
361
|
+
|
|
362
|
+
#endif // _LIBCPP___RANGES_CHUNK_VIEW_H
|
|
363
|
+
#endif
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// See: https://devblogs.microsoft.com/cppblog/msvc-cpp20-and-the-std-cpp20-switch/
|
|
2
|
+
// But the main reason this is a macro is because clang-format clobbers the msvc attribute for some
|
|
3
|
+
// reason.
|
|
4
|
+
#if _MSC_VER
|
|
5
|
+
#define NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
|
|
6
|
+
#else
|
|
7
|
+
#define NO_UNIQUE_ADDRESS [[no_unique_address]]
|
|
8
|
+
#endif
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
module;
|
|
2
|
+
#include "auto_js/no_unique_address.h"
|
|
3
|
+
#include <algorithm>
|
|
4
|
+
#include <cassert>
|
|
5
|
+
#include <memory>
|
|
6
|
+
#include <utility>
|
|
7
|
+
#include <vector>
|
|
8
|
+
export module util:memory.autorelease_pool;
|
|
9
|
+
import :memory.comparator;
|
|
10
|
+
import :utility;
|
|
11
|
+
|
|
12
|
+
namespace util {
|
|
13
|
+
|
|
14
|
+
// v8 may not invoke destructors on `External` objects, but we still want to give it owning
|
|
15
|
+
// references to resources. This provides an allocator to manage those resources. If an
|
|
16
|
+
// `autorelease_pool` goes out of scope then all objects allocated/created will be appropriately
|
|
17
|
+
// destroyed and deallocated.
|
|
18
|
+
//
|
|
19
|
+
// - Not thread safe!
|
|
20
|
+
// - Destroying a collected resourced after the group goes out of scope is UB.
|
|
21
|
+
// - Does not work with non-object types.
|
|
22
|
+
// - Does not work with arrays.
|
|
23
|
+
// - Does not work with anything that uses placement-new (`std::shared_ptr`, `std::optional`,
|
|
24
|
+
// `std::vector`, actually probably a lot of things)
|
|
25
|
+
|
|
26
|
+
template <class Type, class Alloc>
|
|
27
|
+
class resource;
|
|
28
|
+
|
|
29
|
+
// Base class of an allocated resource which knows how to destroy itself at any point in the lifecycle.
|
|
30
|
+
template <class Alloc>
|
|
31
|
+
class releasable {
|
|
32
|
+
protected:
|
|
33
|
+
using dtor_type = auto (releasable::*)(Alloc&) -> void;
|
|
34
|
+
|
|
35
|
+
private:
|
|
36
|
+
using allocator_traits = std::allocator_traits<Alloc>;
|
|
37
|
+
|
|
38
|
+
// Deleter for `std::unique_ptr` / `unique_pointer_type`
|
|
39
|
+
class deleter : private Alloc {
|
|
40
|
+
public:
|
|
41
|
+
constexpr explicit deleter(const Alloc& alloc) :
|
|
42
|
+
Alloc(alloc) {}
|
|
43
|
+
|
|
44
|
+
constexpr auto operator()(releasable* pointer) -> void {
|
|
45
|
+
pointer->release(*this);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
public:
|
|
50
|
+
using unique_pointer_type = std::unique_ptr<releasable, deleter>;
|
|
51
|
+
|
|
52
|
+
constexpr explicit releasable(dtor_type dtor) noexcept :
|
|
53
|
+
dtor_{dtor} {}
|
|
54
|
+
|
|
55
|
+
// allocate a new `resource<T>` and construct it as `releasable` (which is a base class)
|
|
56
|
+
template <class Type>
|
|
57
|
+
constexpr static auto allocate(Alloc& alloc) -> unique_pointer_type {
|
|
58
|
+
using resource_type = resource<Type, Alloc>;
|
|
59
|
+
using resource_alloc_type = std::allocator_traits<Alloc>::template rebind_alloc<resource_type>;
|
|
60
|
+
using resource_alloc_traits = std::allocator_traits<resource_alloc_type>;
|
|
61
|
+
resource_alloc_type resource_alloc{alloc};
|
|
62
|
+
// dtor is initialized to destroy<releasable> + dealloc<resource>. `releasable()` ctor won't
|
|
63
|
+
// throw so this is correct.
|
|
64
|
+
releasable* ptr = resource_alloc_traits::allocate(resource_alloc, 1);
|
|
65
|
+
const auto dtor = dtor_type{&releasable::destroy_and_deallocate<Type, releasable>};
|
|
66
|
+
allocator_traits::construct(alloc, ptr, dtor);
|
|
67
|
+
return unique_pointer_type{ptr, deleter{alloc}};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// can also be invoked from `autorelease_pool::allocator`
|
|
71
|
+
template <class Type>
|
|
72
|
+
constexpr auto construct(Alloc& alloc, auto&&... args)
|
|
73
|
+
requires std::constructible_from<Type, decltype(args)...> {
|
|
74
|
+
using resource_type = resource<Type, Alloc>;
|
|
75
|
+
// "destroy" the releasable which should be trivial anyway
|
|
76
|
+
allocator_traits::destroy(alloc, this);
|
|
77
|
+
// construct resource on top of the existing allocated memory
|
|
78
|
+
const auto dtor = dtor_type{&releasable::deallocate<Type>};
|
|
79
|
+
auto* resource_ptr = static_cast<resource_type*>(this);
|
|
80
|
+
// dtor is initialized first, so if `Type` throws then dtor will be deallocate<releasable>
|
|
81
|
+
allocator_traits::construct(alloc, resource_ptr, dtor, std::forward<decltype(args)>(args)...);
|
|
82
|
+
// update destructor *after* successful construction
|
|
83
|
+
resource_ptr->dtor_ = &releasable::destroy_and_deallocate<Type, resource_type>;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// can also be invoked from `autorelease_pool::allocator`
|
|
87
|
+
template <class Type, class ConstructedType>
|
|
88
|
+
constexpr auto destroy(Alloc& alloc) -> void {
|
|
89
|
+
dtor_ = &releasable::deallocate<Type>;
|
|
90
|
+
allocator_traits::destroy(alloc, static_cast<ConstructedType*>(this));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
template <class Type>
|
|
94
|
+
constexpr auto get() -> Type* {
|
|
95
|
+
using resource_type = resource<Type, Alloc>;
|
|
96
|
+
return static_cast<resource_type*>(this)->get();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private:
|
|
100
|
+
// dtor after `construct` is invoked
|
|
101
|
+
template <class Type, class ConstructedType>
|
|
102
|
+
constexpr auto destroy_and_deallocate(Alloc& alloc) -> void {
|
|
103
|
+
destroy<Type, ConstructedType>(alloc);
|
|
104
|
+
deallocate<Type>(alloc);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// dtor after `allocate` but before `construct` is invoked
|
|
108
|
+
template <class Type>
|
|
109
|
+
constexpr auto deallocate(Alloc& alloc) -> void {
|
|
110
|
+
using resource_type = resource<Type, Alloc>;
|
|
111
|
+
using resource_alloc_type = std::allocator_traits<Alloc>::template rebind_alloc<resource_type>;
|
|
112
|
+
using resource_alloc_traits = std::allocator_traits<resource_alloc_type>;
|
|
113
|
+
resource_alloc_type resource_alloc{alloc};
|
|
114
|
+
dtor_ = nullptr;
|
|
115
|
+
resource_alloc_traits::deallocate(resource_alloc, static_cast<resource_type*>(this), 1);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
constexpr auto release(Alloc& alloc) -> void {
|
|
119
|
+
(this->*dtor_)(alloc);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
dtor_type dtor_;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
// Fully initialized object holder. This is constructed on top of a pre-allocated `releasable`.
|
|
126
|
+
template <class Type, class Alloc>
|
|
127
|
+
class resource : public releasable<Alloc>, private Type {
|
|
128
|
+
public:
|
|
129
|
+
constexpr explicit resource(releasable<Alloc>::dtor_type dtor, auto&&... args) :
|
|
130
|
+
releasable<Alloc>{dtor},
|
|
131
|
+
Type(std::forward<decltype(args)>(args)...) {}
|
|
132
|
+
|
|
133
|
+
constexpr auto get() -> Type* { return this; }
|
|
134
|
+
constexpr static auto translate(Type* ptr) -> resource* {
|
|
135
|
+
return static_cast<resource*>(ptr);
|
|
136
|
+
// Making `Type` a member variable allows instantiation of non-object and `final` classes but raises
|
|
137
|
+
// `-Wno-invalid-offsetof`.
|
|
138
|
+
// auto* bytes = reinterpret_cast<std::byte*>(ptr);
|
|
139
|
+
// // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
|
140
|
+
// return reinterpret_cast<resource*>(bytes - offsetof(resource, value_));
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// Container of allocated resources. On destruction of the pool, all resources will be released.
|
|
145
|
+
export class autorelease_pool : util::non_copyable {
|
|
146
|
+
private:
|
|
147
|
+
// Deleter for `std::unique_ptr`. This is different than the `releasable::deleter` in that it
|
|
148
|
+
// simply erases the pointer from the set. That, in turn, invokes the `releasable` destructor.
|
|
149
|
+
template <class Type>
|
|
150
|
+
class deleter {
|
|
151
|
+
public:
|
|
152
|
+
constexpr explicit deleter(autorelease_pool& pool) :
|
|
153
|
+
pool_{&pool} {}
|
|
154
|
+
|
|
155
|
+
auto operator()(Type* pointer) const -> void {
|
|
156
|
+
using resource_type = resource<Type, allocator_type>;
|
|
157
|
+
pool_->erase(resource_type::translate(pointer));
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private:
|
|
161
|
+
autorelease_pool* pool_;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
using allocator_type = std::allocator<void>;
|
|
165
|
+
using releasable_type = releasable<allocator_type>;
|
|
166
|
+
using container_type = std::vector<releasable_type::unique_pointer_type>;
|
|
167
|
+
|
|
168
|
+
public:
|
|
169
|
+
template <class> class allocator;
|
|
170
|
+
template <class Type>
|
|
171
|
+
using unique_ptr = std::unique_ptr<Type, deleter<Type>>;
|
|
172
|
+
|
|
173
|
+
autorelease_pool() = default;
|
|
174
|
+
explicit autorelease_pool(const allocator_type& alloc) :
|
|
175
|
+
allocator_{alloc} {}
|
|
176
|
+
|
|
177
|
+
auto clear() -> void {
|
|
178
|
+
releasables_.clear();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Nope!
|
|
182
|
+
// template <class Type>
|
|
183
|
+
// constexpr auto make_shared(auto&&... args) -> std::shared_ptr<Type>
|
|
184
|
+
// requires std::constructible_from<Type, decltype(args)...> {
|
|
185
|
+
// return std::allocate_shared<Type>(allocator<Type>{*this}, std::forward<decltype(args)>(args)...);
|
|
186
|
+
// }
|
|
187
|
+
|
|
188
|
+
template <class Type>
|
|
189
|
+
auto make_unique(auto&&... args) -> unique_ptr<Type>
|
|
190
|
+
requires std::constructible_from<Type, decltype(args)...> {
|
|
191
|
+
releasable_type* allocation = emplace<Type>();
|
|
192
|
+
allocation->construct<Type>(allocator_, std::forward<decltype(args)>(args)...);
|
|
193
|
+
return reacquire(allocation->get<Type>());
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
constexpr auto resource_alloc() -> allocator_type& {
|
|
197
|
+
return allocator_;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
template <class Type>
|
|
201
|
+
constexpr auto reacquire(Type* pointer) -> unique_ptr<Type> {
|
|
202
|
+
return unique_ptr<Type>{pointer, deleter<Type>{*this}};
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
protected:
|
|
206
|
+
template <class> friend class allocator;
|
|
207
|
+
|
|
208
|
+
template <class Type>
|
|
209
|
+
auto emplace() -> releasable_type* {
|
|
210
|
+
return releasables_.emplace_back(releasable_type::allocate<Type>(allocator_)), releasables_.back().get();
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
auto erase(releasable_type* ptr) -> void {
|
|
214
|
+
util::swap_and_pop(releasables_, find(ptr));
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
auto find(releasable_type* ptr) -> container_type::iterator {
|
|
218
|
+
auto iterator = std::ranges::find(releasables_, ptr, util::pointer_projection<releasable_type>{});
|
|
219
|
+
assert(iterator != releasables_.end());
|
|
220
|
+
return iterator;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
private:
|
|
224
|
+
container_type releasables_;
|
|
225
|
+
NO_UNIQUE_ADDRESS allocator_type allocator_;
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
// Allocator which allocates in the underlying autorelease pool.
|
|
229
|
+
template <class Type>
|
|
230
|
+
class autorelease_pool::allocator {
|
|
231
|
+
private:
|
|
232
|
+
template <class> friend class allocator;
|
|
233
|
+
using resource_type = resource<Type, allocator_type>;
|
|
234
|
+
|
|
235
|
+
public:
|
|
236
|
+
using value_type = Type;
|
|
237
|
+
using pointer = value_type*;
|
|
238
|
+
|
|
239
|
+
// Nope!
|
|
240
|
+
template <class Other>
|
|
241
|
+
struct rebind {
|
|
242
|
+
using other = void;
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
// Initialize from pool
|
|
246
|
+
constexpr explicit allocator(autorelease_pool& pool) :
|
|
247
|
+
pool_{&pool} {}
|
|
248
|
+
|
|
249
|
+
// Copy from other allocator
|
|
250
|
+
template <class T>
|
|
251
|
+
constexpr explicit allocator(const allocator<T>& alloc) :
|
|
252
|
+
pool_{alloc.pool_} {}
|
|
253
|
+
|
|
254
|
+
constexpr auto allocate(std::size_t count) -> pointer {
|
|
255
|
+
if (count != 1) {
|
|
256
|
+
throw std::bad_array_new_length{};
|
|
257
|
+
}
|
|
258
|
+
releasable_type* allocation = pool_->emplace<value_type>();
|
|
259
|
+
return allocation->get<value_type>();
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
constexpr auto construct(pointer ptr, auto&&... args) -> void
|
|
263
|
+
requires std::constructible_from<value_type, decltype(args)...> {
|
|
264
|
+
auto* resource_ptr = resource_type::translate(ptr);
|
|
265
|
+
resource_ptr->template construct<Type>(pool_->resource_alloc(), std::forward<decltype(args)>(args)...);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
constexpr auto deallocate(pointer ptr, std::size_t /*count*/) -> void {
|
|
269
|
+
pool_->erase(resource_type::translate(ptr));
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
constexpr auto destroy(pointer ptr) -> void {
|
|
273
|
+
resource_type* resource = resource_type::translate(ptr);
|
|
274
|
+
resource->template destroy<Type, resource_type>(pool_->resource_alloc());
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
private:
|
|
278
|
+
autorelease_pool* pool_;
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
} // namespace util
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module;
|
|
2
|
+
#include <memory>
|
|
3
|
+
export module util:memory.comparator;
|
|
4
|
+
|
|
5
|
+
namespace util {
|
|
6
|
+
|
|
7
|
+
// Range projection which extract underlying pointer of a type
|
|
8
|
+
export template <class Type>
|
|
9
|
+
struct pointer_projection {
|
|
10
|
+
[[nodiscard]] constexpr auto operator()(const Type* pointer) const -> const Type* {
|
|
11
|
+
return pointer;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
template <class From>
|
|
15
|
+
[[nodiscard]] constexpr auto operator()(const std::shared_ptr<From>& pointer) const -> const Type* {
|
|
16
|
+
return pointer.get();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
template <class From, class Deleter>
|
|
20
|
+
[[nodiscard]] constexpr auto operator()(const std::unique_ptr<From, Deleter>& pointer) const -> const Type* {
|
|
21
|
+
return pointer.get();
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// General pointer binary comparison
|
|
26
|
+
template <class Type, class Compare>
|
|
27
|
+
class pointer_compare : private pointer_projection<Type> {
|
|
28
|
+
private:
|
|
29
|
+
using pointer_projection<Type>::operator();
|
|
30
|
+
|
|
31
|
+
public:
|
|
32
|
+
using is_transparent = void;
|
|
33
|
+
|
|
34
|
+
constexpr explicit pointer_compare(Compare compare = {}) :
|
|
35
|
+
compare_{std::move(compare)} {}
|
|
36
|
+
|
|
37
|
+
template <class Left, class Right>
|
|
38
|
+
constexpr auto operator()(const Left& left, const Right& right) const -> bool {
|
|
39
|
+
return compare_(operator()(left), operator()(right));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private:
|
|
43
|
+
Compare compare_;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// Concrete pointer binary comparators
|
|
47
|
+
export template <class Type>
|
|
48
|
+
using pointer_equal_to = pointer_compare<Type, std::equal_to<>>;
|
|
49
|
+
|
|
50
|
+
export template <class Type>
|
|
51
|
+
using pointer_less = pointer_compare<Type, std::less<>>;
|
|
52
|
+
|
|
53
|
+
} // namespace util
|