Skip to content

Commit 77041bd

Browse files
committed
Fixed trivially copyable case.
1 parent c54f381 commit 77041bd

File tree

2 files changed

+61
-6
lines changed

2 files changed

+61
-6
lines changed

include/phtree/common/bpt_fixed_vector.h

+35-4
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,10 @@ class bpt_vector {
200200
auto index = to_index(iter);
201201

202202
pointer dst_ptr = {const_cast<pointer>(&*iter)};
203-
std::memmove(dst_ptr + length, dst_ptr, sizeof(V) * (size_ - index));
203+
move_to_back(dst_ptr + length, dst_ptr, size_ - index);
204204

205205
// TODO Use memmove if the source is also a bpt_vector....
206+
// if constexpr (src_begin.base() is b_vector_iterator) ... move_to_back else loop
206207
auto src = src_begin;
207208
while (src != src_end) {
208209
place(dst_ptr, std::move(*src));
@@ -219,7 +220,7 @@ class bpt_vector {
219220
assert(size_ < SIZE);
220221
auto index = to_index(iter);
221222
pointer dst_ptr{const_cast<pointer>(&*iter)};
222-
memmove(dst_ptr + 1, dst_ptr, sizeof(V) * (size_ - index));
223+
move_to_back(dst_ptr + 1, dst_ptr, size_ - index);
223224
place(dst_ptr, std::forward<Args>(args)...);
224225
++size_;
225226
return iterator{dst_ptr};
@@ -234,7 +235,7 @@ class bpt_vector {
234235
iterator erase(const_iterator iter) noexcept {
235236
iter->~V();
236237
pointer dst{const_cast<pointer>(&*iter)};
237-
memmove(dst, dst + 1, sizeof(V) * (size_ - to_index(iter) - 1));
238+
move_to_front(dst, dst + 1, size_ - to_index(iter) - 1);
238239
--size_;
239240
return iterator{dst};
240241
}
@@ -246,7 +247,7 @@ class bpt_vector {
246247
}
247248
auto length = last - first;
248249
pointer dst{const_cast<pointer>(&*first)};
249-
memmove(dst, dst + length, sizeof(V) * (end_ptr() - &*last));
250+
move_to_front(dst, dst + length, end_ptr() - &*last);
250251
size_ -= length;
251252
return iterator{dst};
252253
}
@@ -262,6 +263,32 @@ class bpt_vector {
262263
void reserve(size_t) noexcept {}
263264

264265
private:
266+
template <class V2 = V, typename std::enable_if_t<std::is_trivially_copyable_v<V2>, int> = 0>
267+
void move_to_back(pointer dst, pointer src, size_t count) noexcept {
268+
memmove(dst, src, count * sizeof(V));
269+
}
270+
271+
template <class V2 = V, typename std::enable_if_t<!std::is_trivially_copyable_v<V2>, int> = 0>
272+
void move_to_back(pointer dst, pointer src, size_t count) noexcept {
273+
dst += count - 1;
274+
src += count - 1;
275+
for (size_t i = 0; i < count; ++i, --dst, --src) {
276+
data(dst) = std::move(data(src));
277+
}
278+
}
279+
280+
template <class V2 = V, typename std::enable_if_t<std::is_trivially_copyable_v<V2>, int> = 0>
281+
void move_to_front(pointer dst, pointer src, size_t count) noexcept {
282+
memmove(dst, src, count * sizeof(V));
283+
}
284+
285+
template <class V2 = V, typename std::enable_if_t<!std::is_trivially_copyable_v<V2>, int> = 0>
286+
void move_to_front(pointer dst, pointer src, size_t count) noexcept {
287+
for (size_t i = 0; i < count; ++i, ++dst, ++src) {
288+
*dst = std::move(*src);
289+
}
290+
}
291+
265292
template <typename... Args>
266293
pointer place(size_t index, Args&&... args) noexcept {
267294
return new (reinterpret_cast<void*>(&data_[index * sizeof(V)]))
@@ -285,6 +312,10 @@ class bpt_vector {
285312
return iterator{&data(index)};
286313
}
287314

315+
reference data(pointer ptr) noexcept {
316+
return *std::launder(ptr);
317+
}
318+
288319
reference data(size_t index) noexcept {
289320
return *std::launder(reinterpret_cast<V*>(&data_[index * sizeof(V)]));
290321
}

test/common/b_vector_test.cc

+26-2
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,20 @@ struct Id {
9191
int i_;
9292
};
9393

94+
struct IdTriviallyCopyable {
95+
IdTriviallyCopyable() : i_{0} {}
96+
97+
explicit IdTriviallyCopyable(const size_t i) : i_{static_cast<int>(i)} {}
98+
99+
explicit IdTriviallyCopyable(const int i) : i_{i} {}
100+
101+
bool operator==(const IdTriviallyCopyable& rhs) const {
102+
return i_ == rhs.i_;
103+
}
104+
105+
int i_;
106+
};
107+
94108
template <typename R, typename K, typename V, typename END>
95109
void CheckMapResult(const R& result, END end, const K& key, const V& val) {
96110
ASSERT_NE(result, end);
@@ -105,7 +119,6 @@ TEST(PhTreeBptFixedVectorTest, SmokeTest0) {
105119

106120
using ValueT = Id;
107121
for (int i = 0; i < 100; i++) {
108-
std::cout << "Round i=" << i << std::endl;
109122
bpt_vector<ValueT, N> test_map{};
110123

111124
// populate 50%
@@ -183,7 +196,8 @@ TEST(PhTreeBptFixedVectorTest, SmokeTest0) {
183196
ASSERT_LE(construct_count_ + copy_construct_count_, destruct_count_);
184197
}
185198

186-
TEST(PhTreeBptFixedVectorTest, SmokeTest) {
199+
template <typename Id>
200+
void SmokeTest() {
187201
const size_t N = 100;
188202
std::default_random_engine random_engine{0};
189203
std::uniform_int_distribution<> cube_distribution(0, N - 1);
@@ -291,11 +305,21 @@ TEST(PhTreeBptFixedVectorTest, SmokeTest) {
291305
ASSERT_EQ(0u, test_map.size());
292306
ASSERT_TRUE(test_map.empty());
293307
}
308+
}
294309

310+
TEST(PhTreeBptFixedVectorTest, SmokeTest) {
311+
static_assert(!std::is_trivially_copyable_v<Id>);
312+
reset_id_counters();
313+
SmokeTest<Id>();
295314
ASSERT_GE(construct_count_ + copy_construct_count_ + move_construct_count_, destruct_count_);
296315
ASSERT_LE(construct_count_ + copy_construct_count_, destruct_count_);
297316
}
298317

318+
TEST(PhTreeBptFixedVectorTest, SmokeTest_TriviallyCopyable) {
319+
static_assert(std::is_trivially_copyable_v<IdTriviallyCopyable>);
320+
SmokeTest<IdTriviallyCopyable>();
321+
}
322+
299323
template <typename TREE>
300324
void test_tree(TREE& tree) {
301325
// test various operations

0 commit comments

Comments
 (0)