Skip to content

Commit 53919ed

Browse files
committed
Fix copy for vector<bool> with small storage types
1 parent 4fde8c3 commit 53919ed

File tree

5 files changed

+278
-12
lines changed

5 files changed

+278
-12
lines changed

libcxx/include/__algorithm/copy.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> _
5353
unsigned __clz = __bits_per_word - __first.__ctz_;
5454
difference_type __dn = std::min(static_cast<difference_type>(__clz), __n);
5555
__n -= __dn;
56-
__storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz - __dn));
56+
__storage_type __m = std::__middle_mask<__storage_type>(__clz - __dn, __first.__ctz_);
5757
__storage_type __b = *__first.__seg_ & __m;
5858
*__result.__seg_ &= ~__m;
5959
*__result.__seg_ |= __b;
@@ -73,7 +73,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> _
7373
// do last word
7474
if (__n > 0) {
7575
__first.__seg_ += __nw;
76-
__storage_type __m = ~__storage_type(0) >> (__bits_per_word - __n);
76+
__storage_type __m = std::__trailing_mask<__storage_type>(__bits_per_word - __n);
7777
__storage_type __b = *__first.__seg_ & __m;
7878
*__result.__seg_ &= ~__m;
7979
*__result.__seg_ |= __b;
@@ -98,11 +98,11 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> _
9898
unsigned __clz_f = __bits_per_word - __first.__ctz_;
9999
difference_type __dn = std::min(static_cast<difference_type>(__clz_f), __n);
100100
__n -= __dn;
101-
__storage_type __m = (~__storage_type(0) << __first.__ctz_) & (~__storage_type(0) >> (__clz_f - __dn));
101+
__storage_type __m = std::__middle_mask<__storage_type>(__clz_f - __dn, __first.__ctz_);
102102
__storage_type __b = *__first.__seg_ & __m;
103103
unsigned __clz_r = __bits_per_word - __result.__ctz_;
104104
__storage_type __ddn = std::min<__storage_type>(__dn, __clz_r);
105-
__m = (~__storage_type(0) << __result.__ctz_) & (~__storage_type(0) >> (__clz_r - __ddn));
105+
__m = std::__middle_mask<__storage_type>(__clz_r - __ddn, __result.__ctz_);
106106
*__result.__seg_ &= ~__m;
107107
if (__result.__ctz_ > __first.__ctz_)
108108
*__result.__seg_ |= __b << (__result.__ctz_ - __first.__ctz_);
@@ -112,7 +112,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> _
112112
__result.__ctz_ = static_cast<unsigned>((__ddn + __result.__ctz_) % __bits_per_word);
113113
__dn -= __ddn;
114114
if (__dn > 0) {
115-
__m = ~__storage_type(0) >> (__bits_per_word - __dn);
115+
__m = std::__trailing_mask<__storage_type>(__bits_per_word - __dn);
116116
*__result.__seg_ &= ~__m;
117117
*__result.__seg_ |= __b >> (__first.__ctz_ + __ddn);
118118
__result.__ctz_ = static_cast<unsigned>(__dn);
@@ -123,7 +123,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> _
123123
// __first.__ctz_ == 0;
124124
// do middle words
125125
unsigned __clz_r = __bits_per_word - __result.__ctz_;
126-
__storage_type __m = ~__storage_type(0) << __result.__ctz_;
126+
__storage_type __m = std::__leading_mask<__storage_type>(__result.__ctz_);
127127
for (; __n >= __bits_per_word; __n -= __bits_per_word, ++__first.__seg_) {
128128
__storage_type __b = *__first.__seg_;
129129
*__result.__seg_ &= ~__m;
@@ -134,17 +134,17 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __bit_iterator<_Cp, false> _
134134
}
135135
// do last word
136136
if (__n > 0) {
137-
__m = ~__storage_type(0) >> (__bits_per_word - __n);
137+
__m = std::__trailing_mask<__storage_type>(__bits_per_word - __n);
138138
__storage_type __b = *__first.__seg_ & __m;
139139
__storage_type __dn = std::min(__n, static_cast<difference_type>(__clz_r));
140-
__m = (~__storage_type(0) << __result.__ctz_) & (~__storage_type(0) >> (__clz_r - __dn));
140+
__m = std::__middle_mask<__storage_type>(__clz_r - __dn, __result.__ctz_);
141141
*__result.__seg_ &= ~__m;
142142
*__result.__seg_ |= __b << __result.__ctz_;
143143
__result.__seg_ += (__dn + __result.__ctz_) / __bits_per_word;
144144
__result.__ctz_ = static_cast<unsigned>((__dn + __result.__ctz_) % __bits_per_word);
145145
__n -= __dn;
146146
if (__n > 0) {
147-
__m = ~__storage_type(0) >> (__bits_per_word - __n);
147+
__m = std::__trailing_mask<__storage_type>(__bits_per_word - __n);
148148
*__result.__seg_ &= ~__m;
149149
*__result.__seg_ |= __b >> __dn;
150150
__result.__ctz_ = static_cast<unsigned>(__n);

libcxx/include/__bit_reference

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,20 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __trailing_mask
8282
return static_cast<_StorageType>(~static_cast<_StorageType>(0)) >> __clz;
8383
}
8484

85+
// Creates a mask of type `_StorageType` with a specified number of trailing zeros (__ctz) and sets all remaining
86+
// bits to one.
87+
template <class _StorageType>
88+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __leading_mask(unsigned __ctz) {
89+
static_assert(is_unsigned<_StorageType>::value, "__leading_mask only works with unsigned types");
90+
return static_cast<_StorageType>(~static_cast<_StorageType>(0)) << __ctz;
91+
}
92+
8593
// Creates a mask of type `_StorageType` with a specified number of leading zeros (__clz), a specified number of
8694
// trailing zeros (__ctz), and sets all bits in between to one.
8795
template <class _StorageType>
8896
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __middle_mask(unsigned __clz, unsigned __ctz) {
8997
static_assert(is_unsigned<_StorageType>::value, "__middle_mask only works with unsigned types");
90-
return (static_cast<_StorageType>(~static_cast<_StorageType>(0)) << __ctz) &
91-
std::__trailing_mask<_StorageType>(__clz);
98+
return std::__leading_mask<_StorageType>(__ctz) & std::__trailing_mask<_StorageType>(__clz);
9299
}
93100

94101
// This function is designed to operate correctly even for smaller integral types like `uint8_t`, `uint16_t`,

libcxx/include/__fwd/bit_reference.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,14 @@ struct __size_difference_type_traits;
2828

2929
template <class _StoragePointer>
3030
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void
31-
__fill_masked_range(_StoragePointer __word, unsigned __ctz, unsigned __clz, bool __fill_val);
31+
__fill_masked_range(_StoragePointer __word, unsigned __clz, unsigned __ctz, bool __fill_val);
3232

3333
template <class _StorageType>
3434
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __trailing_mask(unsigned __clz);
3535

36+
template <class _StorageType>
37+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __leading_mask(unsigned __ctz);
38+
3639
template <class _StorageType>
3740
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _StorageType __middle_mask(unsigned __clz, unsigned __ctz);
3841

libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy.pass.cpp

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <cassert>
1717
#include <vector>
1818

19+
#include "sized_allocator.h"
1920
#include "test_macros.h"
2021
#include "test_iterators.h"
2122
#include "type_algorithms.h"
@@ -109,6 +110,133 @@ TEST_CONSTEXPR_CXX20 bool test() {
109110
assert(test_vector_bool(256));
110111
}
111112

113+
// Make sure std::copy behaves properly with std::vector<bool> iterators with custom size types.
114+
{
115+
//// Tests for std::copy with aligned bits
116+
117+
{ // Test the first (partial) word for uint8_t
118+
using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
119+
std::vector<bool, Alloc> in(6, true, Alloc(1));
120+
std::vector<bool, Alloc> out(8, false, Alloc(1));
121+
std::copy(in.begin() + 4, in.end(), out.begin() + 4);
122+
// assert(std::equal(in.begin() + 4, in.end(), out.begin() + 4));
123+
for (std::size_t i = 4; i < in.size(); ++i)
124+
assert(in[i] == out[i]);
125+
}
126+
{ // Test the last word for uint8_t
127+
using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
128+
std::vector<bool, Alloc> in(12, true, Alloc(1));
129+
std::vector<bool, Alloc> out(16, false, Alloc(1));
130+
std::copy(in.begin(), in.end(), out.begin());
131+
// assert(std::equal(in.begin(), in.end(), out.begin()));
132+
for (std::size_t i = 0; i < in.size(); ++i)
133+
assert(in[i] == out[i]);
134+
}
135+
{ // Test middle words for uint8_t
136+
using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
137+
std::vector<bool, Alloc> in(24, true, Alloc(1));
138+
for (std::size_t i = 0; i < in.size(); i += 2)
139+
in[i] = false;
140+
std::vector<bool, Alloc> out(29, false, Alloc(1));
141+
std::copy(in.begin(), in.end(), out.begin());
142+
// assert(std::equal(in.begin(), in.end(), out.begin()));
143+
for (std::size_t i = 0; i < in.size(); ++i)
144+
assert(in[i] == out[i]);
145+
}
146+
147+
{ // Test the first (partial) word for uint16_t
148+
using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>;
149+
std::vector<bool, Alloc> in(12, true, Alloc(1));
150+
std::vector<bool, Alloc> out(16, false, Alloc(1));
151+
std::copy(in.begin() + 4, in.end(), out.begin() + 4);
152+
// assert(std::equal(in.begin() + 4, in.end(), out.begin() + 4));
153+
for (std::size_t i = 4; i < in.size(); ++i)
154+
assert(in[i] == out[i]);
155+
}
156+
{ // Test the last word for uint16_t
157+
using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>;
158+
std::vector<bool, Alloc> in(24, true, Alloc(1));
159+
std::vector<bool, Alloc> out(32, false, Alloc(1));
160+
std::copy(in.begin(), in.end(), out.begin());
161+
// assert(std::equal(in.begin(), in.end(), out.begin()));
162+
for (std::size_t i = 0; i < in.size(); ++i)
163+
assert(in[i] == out[i]);
164+
}
165+
{ // Test middle words for uint16_t
166+
using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>;
167+
std::vector<bool, Alloc> in(48, true, Alloc(1));
168+
for (std::size_t i = 0; i < in.size(); i += 2)
169+
in[i] = false;
170+
std::vector<bool, Alloc> out(55, false, Alloc(1));
171+
std::copy(in.begin(), in.end(), out.begin());
172+
// assert(std::equal(in.begin(), in.end(), out.begin()));
173+
for (std::size_t i = 0; i < in.size(); ++i)
174+
assert(in[i] == out[i]);
175+
}
176+
177+
//// Tests for std::copy with unaligned bits
178+
179+
{ // Test the first (partial) word for uint8_t
180+
using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
181+
std::vector<bool, Alloc> in(6, true, Alloc(1));
182+
std::vector<bool, Alloc> out(8, false, Alloc(1));
183+
std::copy(in.begin() + 4, in.end(), out.begin());
184+
// assert(std::equal(in.begin() + 4, in.end(), out.begin()));
185+
for (std::size_t i = 4; i < in.size(); ++i)
186+
assert(in[i] == out[i - 4]);
187+
}
188+
{ // Test the last word for uint8_t
189+
using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
190+
std::vector<bool, Alloc> in(4, true, Alloc(1));
191+
std::vector<bool, Alloc> out(8, false, Alloc(1));
192+
std::copy(in.begin(), in.end(), out.begin() + 3);
193+
// assert(std::equal(in.begin(), in.end(), out.begin() + 3));
194+
for (std::size_t i = 0; i < in.size(); ++i)
195+
assert(in[i] == out[i + 3]);
196+
}
197+
{ // Test middle words for uint8_t
198+
using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
199+
std::vector<bool, Alloc> in(16, true, Alloc(1));
200+
for (std::size_t i = 0; i < in.size(); i += 2)
201+
in[i] = false;
202+
std::vector<bool, Alloc> out(24, false, Alloc(1));
203+
std::copy(in.begin(), in.end(), out.begin() + 4);
204+
// assert(std::equal(in.begin(), in.end(), out.begin() + 4));
205+
for (std::size_t i = 0; i < in.size(); ++i)
206+
assert(in[i] == out[i + 4]);
207+
}
208+
209+
{ // Test the first (partial) word for uint16_t
210+
using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>;
211+
std::vector<bool, Alloc> in(12, true, Alloc(1));
212+
std::vector<bool, Alloc> out(16, false, Alloc(1));
213+
std::copy(in.begin() + 4, in.end(), out.begin() + 4);
214+
// assert(std::equal(in.begin() + 4, in.end(), out.begin() + 4));
215+
for (std::size_t i = 4; i < in.size(); ++i)
216+
assert(in[i] == out[i]);
217+
}
218+
{ // Test the last word for uint16_t
219+
using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>;
220+
std::vector<bool, Alloc> in(12, true, Alloc(1));
221+
std::vector<bool, Alloc> out(16, false, Alloc(1));
222+
std::copy(in.begin(), in.end(), out.begin() + 3);
223+
// assert(std::equal(in.begin(), in.end(), out.begin() + 3));
224+
for (std::size_t i = 0; i < in.size(); ++i)
225+
assert(in[i] == out[i + 3]);
226+
}
227+
{ // Test the middle words for uint16_t
228+
using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>;
229+
std::vector<bool, Alloc> in(32, true, Alloc(1));
230+
for (std::size_t i = 0; i < in.size(); i += 2)
231+
in[i] = false;
232+
std::vector<bool, Alloc> out(64, false, Alloc(1));
233+
std::copy(in.begin(), in.end(), out.begin() + 4);
234+
// assert(std::equal(in.begin(), in.end(), out.begin() + 4));
235+
for (std::size_t i = 0; i < in.size(); ++i)
236+
assert(in[i] == out[i + 4]);
237+
}
238+
}
239+
112240
return true;
113241
}
114242

libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.pass.cpp

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <vector>
2626

2727
#include "almost_satisfies_types.h"
28+
#include "sized_allocator.h"
2829
#include "test_iterators.h"
2930
#include "test_macros.h"
3031
#include "type_algorithms.h"
@@ -237,6 +238,133 @@ constexpr bool test() {
237238
assert(test_vector_bool(199));
238239
assert(test_vector_bool(256));
239240
}
241+
242+
// Make sure std::ranges::copy behaves properly with std::vector<bool> iterators with custom size types.
243+
{
244+
//// Tests for std::ranges::copy with aligned bits
245+
246+
{ // Test the first (partial) word for uint8_t
247+
using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
248+
std::vector<bool, Alloc> in(6, true, Alloc(1));
249+
std::vector<bool, Alloc> out(8, false, Alloc(1));
250+
std::ranges::copy(std::ranges::subrange(in.begin() + 4, in.end()), out.begin() + 4);
251+
// assert(std::ranges::equal(in.begin() + 4, in.end(), out.begin() + 4, out.begin() + 6));
252+
for (std::size_t i = 4; i < in.size(); ++i)
253+
assert(in[i] == out[i]);
254+
}
255+
{ // Test the last word for uint8_t
256+
using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
257+
std::vector<bool, Alloc> in(12, true, Alloc(1));
258+
std::vector<bool, Alloc> out(16, false, Alloc(1));
259+
std::ranges::copy(in, out.begin());
260+
// assert(std::ranges::equal(in, std::ranges::subrange(out.begin(), out.begin() + in.size())));
261+
for (std::size_t i = 0; i < in.size(); ++i)
262+
assert(in[i] == out[i]);
263+
}
264+
{ // Test middle words for uint8_t
265+
using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
266+
std::vector<bool, Alloc> in(24, true, Alloc(1));
267+
for (std::size_t i = 0; i < in.size(); i += 2)
268+
in[i] = false;
269+
std::vector<bool, Alloc> out(29, false, Alloc(1));
270+
std::ranges::copy(in, out.begin());
271+
// assert(std::ranges::equal(in, std::ranges::subrange(out.begin(), out.begin() + in.size())));
272+
for (std::size_t i = 0; i < in.size(); ++i)
273+
assert(in[i] == out[i]);
274+
}
275+
276+
{ // Test the first (partial) word for uint16_t
277+
using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>;
278+
std::vector<bool, Alloc> in(12, true, Alloc(1));
279+
std::vector<bool, Alloc> out(16, false, Alloc(1));
280+
std::ranges::copy(std::ranges::subrange(in.begin() + 4, in.end()), out.begin() + 4);
281+
// assert(std::ranges::equal(in.begin() + 4, in.end(), out.begin() + 4, out.begin() + 12));
282+
for (std::size_t i = 4; i < in.size(); ++i)
283+
assert(in[i] == out[i]);
284+
}
285+
{ // Test the last word for uint16_t
286+
using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>;
287+
std::vector<bool, Alloc> in(24, true, Alloc(1));
288+
std::vector<bool, Alloc> out(32, false, Alloc(1));
289+
std::ranges::copy(in, out.begin());
290+
// assert(std::ranges::equal(in, std::ranges::subrange(out.begin(), out.begin() + in.size())));
291+
for (std::size_t i = 0; i < in.size(); ++i)
292+
assert(in[i] == out[i]);
293+
}
294+
{ // Test middle words for uint16_t
295+
using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>;
296+
std::vector<bool, Alloc> in(48, true, Alloc(1));
297+
for (std::size_t i = 0; i < in.size(); i += 2)
298+
in[i] = false;
299+
std::vector<bool, Alloc> out(55, false, Alloc(1));
300+
std::ranges::copy(in, out.begin());
301+
// assert(std::ranges::equal(in, std::ranges::subrange(out.begin(), out.begin() + in.size())));
302+
for (std::size_t i = 0; i < in.size(); ++i)
303+
assert(in[i] == out[i]);
304+
}
305+
306+
//// Tests for std::ranges::copy with unaligned bits
307+
308+
{ // Test the first (partial) word for uint8_t
309+
using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
310+
std::vector<bool, Alloc> in(6, true, Alloc(1));
311+
std::vector<bool, Alloc> out(8, false, Alloc(1));
312+
std::ranges::copy(std::ranges::subrange(in.begin() + 4, in.end()), out.begin());
313+
// assert(std::ranges::equal(in.begin() + 4, in.end(), out.begin(), out.begin() + 2));
314+
for (std::size_t i = 4; i < in.size(); ++i)
315+
assert(in[i] == out[i - 4]);
316+
}
317+
{ // Test the last word for uint8_t
318+
using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
319+
std::vector<bool, Alloc> in(4, true, Alloc(1));
320+
std::vector<bool, Alloc> out(8, false, Alloc(1));
321+
std::ranges::copy(in, out.begin() + 3);
322+
// assert(std::ranges::equal(in.begin(), in.end(), out.begin() + 3, out.begin() + 3 + in.size()));
323+
for (std::size_t i = 0; i < in.size(); ++i)
324+
assert(in[i] == out[i + 3]);
325+
}
326+
{ // Test middle words for uint8_t
327+
using Alloc = sized_allocator<bool, std::uint8_t, std::int8_t>;
328+
std::vector<bool, Alloc> in(16, true, Alloc(1));
329+
for (std::size_t i = 0; i < in.size(); i += 2)
330+
in[i] = false;
331+
std::vector<bool, Alloc> out(24, false, Alloc(1));
332+
std::ranges::copy(in, out.begin() + 4);
333+
// assert(std::ranges::equal(in.begin(), in.end(), out.begin() + 4, out.begin() + 4 + in.size()));
334+
for (std::size_t i = 0; i < in.size(); ++i)
335+
assert(in[i] == out[i + 4]);
336+
}
337+
338+
{ // Test the first (partial) word for uint16_t
339+
using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>;
340+
std::vector<bool, Alloc> in(12, true, Alloc(1));
341+
std::vector<bool, Alloc> out(16, false, Alloc(1));
342+
std::ranges::copy(std::ranges::subrange(in.begin() + 4, in.end()), out.begin());
343+
// assert(std::ranges::equal(in.begin() + 4, in.end(), out.begin(), out.begin() + 8));
344+
for (std::size_t i = 4; i < in.size(); ++i)
345+
assert(in[i] == out[i - 4]);
346+
}
347+
{ // Test the last word for uint16_t
348+
using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>;
349+
std::vector<bool, Alloc> in(12, true, Alloc(1));
350+
std::vector<bool, Alloc> out(16, false, Alloc(1));
351+
std::ranges::copy(in, out.begin() + 3);
352+
// assert(std::ranges::equal(in.begin(), in.end(), out.begin() + 3, out.begin() + 3 + in.size()));
353+
for (std::size_t i = 0; i < in.size(); ++i)
354+
assert(in[i] == out[i + 3]);
355+
}
356+
{ // Test the middle words for uint16_t
357+
using Alloc = sized_allocator<bool, std::uint16_t, std::int16_t>;
358+
std::vector<bool, Alloc> in(32, true, Alloc(1));
359+
for (std::size_t i = 0; i < in.size(); i += 2)
360+
in[i] = false;
361+
std::vector<bool, Alloc> out(64, false, Alloc(1));
362+
std::ranges::copy(in, out.begin() + 4);
363+
// assert(std::ranges::equal(in.begin(), in.end(), out.begin() + 4, out.begin() + 4 + in.size()));
364+
for (std::size_t i = 0; i < in.size(); ++i)
365+
assert(in[i] == out[i + 4]);
366+
}
367+
}
240368
#endif
241369

242370
return true;

0 commit comments

Comments
 (0)