1
1
#pragma once
2
2
3
- #include " ../algorithm/algorithm.h"
4
3
#include " allocation_traits.h"
5
4
#include " launder_iterator.h"
6
5
6
+ #include < algorithm>
7
+
7
8
namespace stdsharp ::details
8
9
{
9
10
template <typename Allocator, typename T>
@@ -20,21 +21,33 @@ namespace stdsharp::details
20
21
static constexpr auto data = allocation_traits::template data<T>;
21
22
static constexpr auto get = allocation_traits::template get<T>;
22
23
23
- constexpr void size_validate (this const auto & t, const auto & allocation) noexcept
24
+ template <typename >
25
+ struct forward_value ;
26
+
27
+ template <allocation<Allocator> Allocation>
28
+ struct forward_value <Allocation>
24
29
{
25
- Expects (
26
- allocation.size () * sizeof (typename allocation_traits::value_type) >= t.value_size ()
27
- );
28
- }
30
+ using type = T&&;
31
+ };
32
+
33
+ template <callocation<Allocator> Allocation>
34
+ struct forward_value <Allocation>
35
+ {
36
+ using type = const T&;
37
+ };
29
38
30
- constexpr void size_validate (
31
- this const auto & t,
32
- const auto & src_allocation,
33
- const auto & dst_allocation
34
- ) noexcept
39
+ template <typename Allocation>
40
+ using forward_value_t = forward_value<Allocation>::type;
41
+
42
+ constexpr void size_validate (this const auto & t, const auto &... allocations) noexcept
35
43
{
36
- t.size_validate (src_allocation);
37
- t.size_validate (dst_allocation);
44
+ ( //
45
+ Expects (
46
+ allocations.size () * sizeof (typename allocation_traits::value_type) >=
47
+ t.value_size ()
48
+ ),
49
+ ...
50
+ );
38
51
}
39
52
40
53
static constexpr struct default_construct_t
@@ -60,6 +73,9 @@ namespace stdsharp
60
73
using m_base::data;
61
74
using m_base::get;
62
75
76
+ template <typename Allocation>
77
+ using forward_value_t = m_base::template forward_value_t <Allocation>;
78
+
63
79
static constexpr auto always_equal = true ;
64
80
65
81
[[nodiscard]] static constexpr auto value_size () noexcept { return sizeof (T); }
@@ -69,6 +85,14 @@ namespace stdsharp
69
85
private:
70
86
using typename m_base::ctor;
71
87
using typename m_base::dtor;
88
+ using m_base::size_validate;
89
+
90
+ template <typename Allocation>
91
+ [[nodiscard]] constexpr decltype (auto ) forward_value(const Allocation& src_allocation) const noexcept
92
+ {
93
+ size_validate (src_allocation);
94
+ return static_cast <forward_value_t <Allocation>>(get (src_allocation));
95
+ }
72
96
73
97
public:
74
98
constexpr void operator ()(
@@ -78,58 +102,39 @@ namespace stdsharp
78
102
) const noexcept (nothrow_invocable<ctor, allocator_type&, T*>)
79
103
requires std::invocable<ctor, allocator_type&, T*>
80
104
{
81
- this -> size_validate (allocation);
105
+ size_validate (allocation);
82
106
ctor{}(allocator, data (allocation));
83
107
}
84
108
109
+ template <typename SrcAllocation, typename Value = forward_value_t <SrcAllocation>>
110
+ requires std::invocable<ctor, allocator_type&, T*, Value>
85
111
constexpr void operator ()(
86
112
allocator_type& allocator,
87
- const callocation<Allocator> auto & src_allocation,
113
+ const SrcAllocation & src_allocation,
88
114
const allocation<Allocator> auto & dst_allocation
89
- ) const noexcept (nothrow_invocable<ctor, allocator_type&, T*, const T&>)
90
- requires std::invocable<ctor, allocator_type&, T*, const T&>
115
+ ) const noexcept (nothrow_invocable<ctor, allocator_type&, T*, Value>)
91
116
{
92
- this -> size_validate (src_allocation, dst_allocation);
93
- ctor{}(allocator, data (dst_allocation), get (src_allocation));
117
+ size_validate (dst_allocation);
118
+ ctor{}(allocator, data (dst_allocation), forward_value (src_allocation));
94
119
}
95
120
121
+ template <typename Allocation, typename Value = forward_value_t <Allocation>>
96
122
constexpr void operator ()(
97
- allocator_type& allocator,
98
- const allocation<Allocator> auto & src_allocation,
99
- const allocation<Allocator> auto & dst_allocation
100
- ) const noexcept (nothrow_invocable<ctor, allocator_type&, T*, T>)
101
- requires std::invocable<ctor, allocator_type&, T*, T>
102
- {
103
- this ->size_validate (src_allocation, dst_allocation);
104
- ctor{}(allocator, data (dst_allocation), cpp_move (get (src_allocation)));
105
- }
106
-
107
- constexpr void operator ()(
108
- const callocation<Allocator> auto & src_allocation,
123
+ const Allocation& src_allocation,
109
124
const allocation<Allocator> auto & dst_allocation
110
- ) const noexcept (nothrow_copy_assignable<T >)
111
- requires copy_assignable<T >
125
+ ) const noexcept (nothrow_assignable_from<T&, Value >)
126
+ requires std::assignable_from<T&, Value >
112
127
{
113
- this ->size_validate (src_allocation, dst_allocation);
114
- get (dst_allocation) = get (src_allocation);
115
- }
116
-
117
- constexpr void operator ()(
118
- const allocation<Allocator> auto & src_allocation,
119
- const allocation<Allocator> auto & dst_allocation
120
- ) const noexcept (nothrow_move_assignable<T>)
121
- requires move_assignable<T>
122
- {
123
- this ->size_validate (src_allocation, dst_allocation);
124
- get (dst_allocation) = cpp_move (get (src_allocation));
128
+ size_validate (dst_allocation);
129
+ get (dst_allocation) = forward_value (src_allocation);
125
130
}
126
131
127
132
constexpr void operator ()(
128
133
allocator_type& allocator,
129
134
const allocation<Allocator> auto & allocation
130
135
) const noexcept
131
136
{
132
- this -> size_validate (allocation);
137
+ size_validate (allocation);
133
138
dtor{}(allocator, data (allocation));
134
139
}
135
140
};
@@ -154,17 +159,34 @@ namespace stdsharp
154
159
using typename m_base::ctor;
155
160
using typename m_base::dtor;
156
161
using size_t = std::size_t ;
162
+ using m_base::size_validate;
157
163
158
164
size_t size_;
159
165
160
166
[[nodiscard]] constexpr auto launder_begin (const auto & allocation) const noexcept
161
167
{
168
+ size_validate (allocation);
162
169
return launder_iterator{data (allocation)};
163
170
}
164
171
165
- [[nodiscard]] constexpr auto value_rng (const auto & allocation) const noexcept
172
+ [[nodiscard]] constexpr auto
173
+ forward_launder_begin (const callocation<Allocator> auto & allocation) const noexcept
174
+ {
175
+ return launder_begin (allocation);
176
+ }
177
+
178
+ [[nodiscard]] constexpr auto
179
+ forward_launder_begin (const allocation<Allocator> auto & allocation) const noexcept
180
+ {
181
+ return std::move_iterator{launder_begin (allocation)};
182
+ }
183
+
184
+ template <typename Allocation>
185
+ using forward_value_t = m_base::template forward_value_t <Allocation>;
186
+
187
+ [[nodiscard]] constexpr auto forward_rng (const auto & allocation) const noexcept
166
188
{
167
- return std::views::counted (launder_begin (allocation), size ());
189
+ return std::views::counted (forward_launder_begin (allocation), size ());
168
190
}
169
191
170
192
public:
@@ -183,81 +205,49 @@ namespace stdsharp
183
205
) const noexcept (nothrow_invocable<ctor, allocator_type&, T*>)
184
206
requires std::invocable<ctor, allocator_type&, T*>
185
207
{
186
- this ->size_validate (allocation);
187
-
188
- auto && p = data (allocation);
189
- const auto count = size ();
190
- for (size_t i = 0 ; i < count; ++i, ++p) ctor{}(allocator, p);
191
- }
192
-
193
- constexpr void operator ()(
194
- allocator_type& allocator,
195
- const callocation<Allocator> auto & src_allocation,
196
- const allocation<Allocator> auto & dst_allocation
197
- ) const noexcept (nothrow_invocable<ctor, allocator_type&, T*, const T&>)
198
- requires std::invocable<ctor, allocator_type&, T*, const T&>
199
- {
200
- this ->size_validate (src_allocation, dst_allocation);
201
-
202
- auto && dst_begin = data (dst_allocation);
203
- const auto & src_begin = launder_begin (src_allocation);
204
- const auto count = size ();
205
-
206
- for (size_t i = 0 ; i < count; ++i, ++dst_begin)
207
- ctor{}(allocator, dst_begin, src_begin[i]);
208
+ size_validate (allocation);
209
+ auto begin = data (allocation);
210
+ for (const auto end = begin + size (); begin < end; ++begin) ctor{}(allocator, begin);
208
211
}
209
212
213
+ template <typename Allocation, typename Value = forward_value_t <Allocation>>
210
214
constexpr void operator ()(
211
215
allocator_type& allocator,
212
- const allocation<Allocator> auto & src_allocation,
216
+ const Allocation & src_allocation,
213
217
const allocation<Allocator> auto & dst_allocation
214
- ) const noexcept (nothrow_invocable<ctor, allocator_type&, T*, T >)
215
- requires std::invocable<ctor, allocator_type&, T*, T >
218
+ ) const noexcept (nothrow_invocable<ctor, allocator_type&, T*, Value >)
219
+ requires std::invocable<ctor, allocator_type&, T*, Value >
216
220
{
217
- this -> size_validate (src_allocation, dst_allocation);
221
+ size_validate (dst_allocation);
218
222
219
- auto & & dst_begin = data (dst_allocation);
220
- const auto & src_begin = launder_begin (src_allocation);
223
+ const auto & dst_begin = data (dst_allocation);
224
+ const auto & src_begin = forward_launder_begin (src_allocation);
221
225
const auto count = size ();
222
226
223
- for (size_t i = 0 ; i < count; ++i, ++dst_begin)
224
- ctor{}(allocator, dst_begin, cpp_move (src_begin[i]));
227
+ for (size_t i = 0 ; i < count; ++i) ctor{}(allocator, dst_begin[i], src_begin[i]);
225
228
}
226
229
230
+ template <typename Allocation, typename Value = forward_value_t <Allocation>>
227
231
constexpr void operator ()(
228
- const callocation<Allocator> auto & src_allocation,
232
+ const Allocation & src_allocation,
229
233
const allocation<Allocator> auto & dst_allocation
230
- ) const noexcept (nothrow_copy_assignable<T >)
231
- requires copy_assignable<T >
234
+ ) const noexcept (nothrow_assignable_from<T, Value >)
235
+ requires std::assignable_from<T, Value >
232
236
{
233
- this ->size_validate (src_allocation, dst_allocation);
234
- std::ranges::copy_n ( //
237
+ std::ranges::copy_n (
235
238
launder_begin (src_allocation),
236
239
size (),
237
- launder_begin (dst_allocation)
240
+ forward_launder_begin (dst_allocation)
238
241
);
239
242
}
240
243
241
- constexpr void operator ()(
242
- const allocation<Allocator> auto & src_allocation,
243
- const allocation<Allocator> auto & dst_allocation
244
- ) const noexcept (nothrow_move_assignable<T>)
245
- requires move_assignable<T>
246
- {
247
- this ->size_validate (src_allocation, dst_allocation);
248
- move_n (launder_begin (src_allocation), size (), launder_begin (dst_allocation));
249
- }
250
-
251
244
constexpr void operator ()(
252
245
allocator_type& allocator,
253
246
const allocation<Allocator> auto & allocation
254
247
) const noexcept
255
248
{
256
- this ->size_validate (allocation);
257
-
258
- auto && iter = launder_begin (allocation);
259
- const auto count = size ();
260
- for (size_t i = 0 ; i < count; ++i, ++iter) dtor{}(allocator, iter.data ());
249
+ auto && begin = launder_begin (allocation);
250
+ for (const auto & end = begin + size (); begin < end; ++begin) dtor{}(allocator, begin);
261
251
}
262
252
};
263
253
}
0 commit comments