17
17
#include < type_traits>
18
18
19
19
#include " googletest/include/gtest/gtest.h"
20
+ #include " subspace/containers/array.h"
20
21
#include " subspace/macros/builtin.h"
21
22
#include " subspace/mem/relocate.h"
23
+ #include " subspace/ops/range_literals.h"
24
+ #include " subspace/prelude.h"
22
25
23
- namespace sus ::mem {
24
26
namespace {
25
27
26
28
TEST (Swap, ConstexprTrivialRelocate) {
27
29
using T = int ;
28
- static_assert (relocate_by_memcpy<T>, " " );
30
+ static_assert (sus::mem:: relocate_by_memcpy<T>, " " );
29
31
30
32
auto i = []() constexpr {
31
33
T i (2 );
32
34
T j (5 );
33
- :: sus::mem::swap (mref(i), mref(j));
35
+ sus::mem::swap (mref (i), mref (j));
34
36
return i;
35
37
};
36
38
auto j = []() constexpr {
37
39
T i (2 );
38
40
T j (5 );
39
- :: sus::mem::swap (mref(i), mref(j));
41
+ sus::mem::swap (mref (i), mref (j));
40
42
return j;
41
43
};
42
44
static_assert (i () == T (5 ), " " );
@@ -55,18 +57,19 @@ TEST(Swap, ConstexprTrivialAbi) {
55
57
// [[sus_trivial_abi]].
56
58
static_assert (!std::is_trivially_move_constructible_v<S>, " " );
57
59
static_assert (
58
- relocate_by_memcpy<S> == __has_extension (trivially_relocatable), " " );
60
+ sus::mem::relocate_by_memcpy<S> == __has_extension (trivially_relocatable),
61
+ " " );
59
62
60
63
auto i = []() constexpr {
61
64
S i (2 );
62
65
S j (5 );
63
- :: sus::mem::swap (mref(i), mref(j));
66
+ sus::mem::swap (mref (i), mref (j));
64
67
return i;
65
68
};
66
69
auto j = []() constexpr {
67
70
S i (2 );
68
71
S j (5 );
69
- :: sus::mem::swap (mref(i), mref(j));
72
+ sus::mem::swap (mref (i), mref (j));
70
73
return j;
71
74
};
72
75
static_assert (i ().num == 5 , " " );
@@ -84,18 +87,18 @@ TEST(Swap, ConstexprNonTrivial) {
84
87
int num;
85
88
int moves = 0 ;
86
89
};
87
- static_assert (!relocate_by_memcpy<S>, " " );
90
+ static_assert (!sus::mem:: relocate_by_memcpy<S>, " " );
88
91
89
92
auto i = []() constexpr {
90
93
S i (2 );
91
94
S j (5 );
92
- :: sus::mem::swap (mref(i), mref(j));
95
+ sus::mem::swap (mref (i), mref (j));
93
96
return i;
94
97
};
95
98
auto j = []() constexpr {
96
99
S i (2 );
97
100
S j (5 );
98
- :: sus::mem::swap (mref(i), mref(j));
101
+ sus::mem::swap (mref (i), mref (j));
99
102
return j;
100
103
};
101
104
static_assert (i ().num == 5 , " " );
@@ -107,11 +110,11 @@ TEST(Swap, ConstexprNonTrivial) {
107
110
108
111
TEST (Swap, TrivialRelocate) {
109
112
using T = int ;
110
- static_assert (relocate_by_memcpy<T>, " " );
113
+ static_assert (sus::mem:: relocate_by_memcpy<T>, " " );
111
114
112
115
T i (2 );
113
116
T j (5 );
114
- :: sus::mem::swap (mref(i), mref(j));
117
+ sus::mem::swap (mref (i), mref (j));
115
118
EXPECT_EQ (i, T (5 ));
116
119
EXPECT_EQ (j, T (2 ));
117
120
}
@@ -131,11 +134,12 @@ TEST(Swap, TrivialAbi) {
131
134
// [[sus_trivial_abi]].
132
135
static_assert (!std::is_trivially_move_constructible_v<S>, " " );
133
136
static_assert (
134
- relocate_by_memcpy<S> == __has_extension (trivially_relocatable), " " );
137
+ sus::mem::relocate_by_memcpy<S> == __has_extension (trivially_relocatable),
138
+ " " );
135
139
136
140
S i (2 );
137
141
S j (5 );
138
- :: sus::mem::swap (mref(i), mref(j));
142
+ sus::mem::swap (mref (i), mref (j));
139
143
EXPECT_EQ (i.num , 5 );
140
144
EXPECT_EQ (j.num , 2 );
141
145
#if __has_extension(trivially_relocatable)
@@ -158,17 +162,92 @@ TEST(Swap, NonTrivial) {
158
162
int num;
159
163
int moves = 0 ;
160
164
};
161
- static_assert (!relocate_by_memcpy<S>, " " );
165
+ static_assert (!sus::mem:: relocate_by_memcpy<S>, " " );
162
166
163
167
S i (2 );
164
168
S j (5 );
165
- :: sus::mem::swap (mref(i), mref(j));
169
+ sus::mem::swap (mref (i), mref (j));
166
170
EXPECT_EQ (i.num , 5 );
167
171
EXPECT_EQ (j.num , 2 );
168
172
// The swap was done by move operations.
169
173
EXPECT_GE (i.moves , 1 );
170
174
EXPECT_GE (j.moves , 1 );
171
175
}
172
176
177
+ struct Trivial {
178
+ explicit Trivial (sus::Array<i32 , 100 > i) : num(sus::move(i)) {}
179
+ Trivial (Trivial&&) { moves += 1u ; }
180
+ Trivial& operator =(Trivial&&) {
181
+ moves += 1u ;
182
+ return *this ;
183
+ }
184
+ sus::Array<i32 , 100 > num;
185
+
186
+ static usize moves;
187
+
188
+ sus_class_trivially_relocatable_unchecked (unsafe_fn);
189
+ };
190
+
191
+ usize Trivial::moves;
192
+
193
+ TEST (Swap, Alias) {
194
+ static usize moves;
195
+ struct S {
196
+ explicit S (i32 i) : num(i) {}
197
+ S (S&&) { moves += 1u ; }
198
+ S& operator =(S&&) {
199
+ moves += 1u ;
200
+ return *this ;
201
+ }
202
+ i32 num;
203
+ };
204
+
205
+ S i (2 );
206
+ sus::mem::swap (mref (i), mref (i));
207
+ EXPECT_EQ (moves, 0u );
208
+
209
+ Trivial::moves = 0u ;
210
+ Trivial t (sus::Array<i32 , 100 >::with_initializer (
211
+ [i = 0_i32]() mutable { return sus::mem::replace (i, i + 1 ); }));
212
+ sus::mem::swap (mref (t), mref (t));
213
+ for (usize j : " 0..100" _r) {
214
+ EXPECT_EQ (t.num [j], i32::from (j));
215
+ }
216
+ EXPECT_EQ (Trivial::moves, 0u );
217
+ }
218
+
219
+ TEST (Swap, NoAliasUnchecked) {
220
+ static usize moves;
221
+ struct S {
222
+ explicit S (i32 i) : num(i) {}
223
+ S (S&&) { moves += 1u ; }
224
+ S& operator =(S&&) {
225
+ moves += 1u ;
226
+ return *this ;
227
+ }
228
+ i32 num;
229
+ };
230
+
231
+ S i (2 );
232
+ sus::mem::swap_no_alias_unchecked (unsafe_fn, mref (i), mref (i));
233
+ // Luckily S doesn't do anything bad when assigned to itself, and we can
234
+ // verify the number of times a move happened.
235
+ EXPECT_EQ (moves, 3u );
236
+
237
+ Trivial::moves = 0u ;
238
+ Trivial t1 (sus::Array<i32 , 100 >::with_initializer (
239
+ [i = 0_i32]() mutable { return sus::mem::replace (i, i + 1 ); }));
240
+ Trivial t2 (sus::Array<i32 , 100 >::with_initializer (
241
+ [i = 10_i32]() mutable { return sus::mem::replace (i, i + 1 ); }));
242
+ sus::mem::swap_no_alias_unchecked (unsafe_fn, mref (t1), mref (t2));
243
+ for (usize j : " 0..100" _r) {
244
+ EXPECT_EQ (t1.num [j], i32::from (j) + 10 );
245
+ EXPECT_EQ (t2.num [j], i32::from (j));
246
+ }
247
+ EXPECT_EQ (Trivial::moves, 0u );
248
+
249
+ sus::mem::swap_no_alias_unchecked (unsafe_fn, mref (t1), mref (t1));
250
+ // As memcpy() was called in an invalid way we can't really check anything
251
+ // here, but we can see we didn't check() anything.
252
+ }
173
253
} // namespace
174
- } // namespace sus::mem
0 commit comments