Skip to content

Commit 427bf80

Browse files
committed
Optimize array::insert
1 parent 5739b4a commit 427bf80

3 files changed

Lines changed: 59 additions & 35 deletions

File tree

include/foonathan/array/array.hpp

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -269,8 +269,8 @@ namespace foonathan
269269
template <typename... Args>
270270
iterator emplace(const_iterator pos, Args&&... args)
271271
{
272-
// note: we emplace at a given position by creating the objects at the back,
273-
// then rotating it to the correct position
272+
// note: we emplace at a given position by moving elements to create the space
273+
// then assigning it at the position
274274
//
275275
// when the capacity is sufficient, this is almost as efficient as possible,
276276
// just one extra swap or so
@@ -279,9 +279,23 @@ namespace foonathan
279279
// however this would vastly complicate the interface and just isn't worth it,
280280
// as it is the slow path anyway
281281

282-
auto index = pos - begin();
283-
emplace_back(std::forward<Args>(args)...);
284-
std::rotate(begin() + index, std::prev(end()), end());
282+
auto index = size_type(pos - cbegin());
283+
if (index == size())
284+
// just do an emplace back
285+
emplace_back(std::forward<Args>(args)...);
286+
else
287+
{
288+
// reserve for one more element
289+
reserve(size() + 1u);
290+
auto ptr = view().data() + index;
291+
292+
// move all elements following it one over
293+
move_range(ptr, view().data_end(), ptr + 1);
294+
295+
// create the element at the now empty position
296+
emplace_impl(ptr, std::forward<Args>(args)...);
297+
}
298+
285299
return begin() + index;
286300
}
287301

@@ -403,6 +417,36 @@ namespace foonathan
403417
return array_view<T>(to_pointer<T>(storage_.block().begin()), to_pointer<T>(end_));
404418
}
405419

420+
void move_range(T* from_begin, T* from_end, T* to)
421+
{
422+
// [from_begin, assign_end) can be assigned to [from_begin + assign_range_size, cur_end)
423+
// [assign_end, from_end) must be constructed at the back
424+
auto cur_end = to_pointer<T>(end_);
425+
auto assign_range_size = cur_end - to;
426+
auto assign_end = from_begin + assign_range_size;
427+
428+
// do the construction
429+
for (auto cur = assign_end; cur != from_end; ++cur)
430+
{
431+
construct_object<T>(end_, std::move(*cur));
432+
end_ += sizeof(T);
433+
}
434+
435+
// do the assignment
436+
std::move_backward(from_begin, assign_end, cur_end);
437+
}
438+
439+
template <typename Arg>
440+
static auto emplace_impl(T* ptr, Arg&& arg) -> decltype(*ptr = std::forward<Arg>(arg))
441+
{
442+
return *ptr = std::forward<Arg>(arg);
443+
}
444+
template <typename... Args>
445+
static void emplace_impl(T* ptr, Args&&... args)
446+
{
447+
*ptr = T(std::forward<Args>(args)...);
448+
}
449+
406450
template <typename InputIt>
407451
iterator append_range_impl(std::input_iterator_tag, InputIt begin, InputIt end)
408452
{
@@ -448,7 +492,7 @@ namespace foonathan
448492
{
449493
auto index = pos - this->begin();
450494

451-
// again, like with insert, do an append, plus rotate
495+
// just do an append plus rotate
452496
auto new_begin = append_range(begin, end);
453497
std::rotate(this->begin() + index, new_begin, this->end());
454498

include/foonathan/array/flat_map.hpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -887,16 +887,17 @@ namespace foonathan
887887
return size_type(key - iterator_to_pointer(keys_.begin()));
888888
}
889889

890+
template <typename Arg>
891+
auto assign_value(value_iterator iter, Arg&& arg) noexcept
892+
-> decltype(*iter = std::forward<Arg>(arg))
893+
{
894+
return *iter = std::forward<Arg>(arg);
895+
}
890896
template <typename... Args>
891897
void assign_value(value_iterator iter, Args&&... args) const
892898
{
893899
*iter = Value(std::forward<Args>(args)...);
894900
}
895-
template <typename Arg>
896-
void assign_value(value_iterator iter, Arg&& arg) noexcept
897-
{
898-
*iter = std::forward<Arg>(arg);
899-
}
900901

901902
template <typename InputIt>
902903
static size_type range_size(std::input_iterator_tag, InputIt, InputIt)

main.cpp

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include <algorithm>
66
#include <iostream>
7+
#include <vector>
78

89
#include <foonathan/array/bag.hpp>
910
#include <foonathan/array/block_storage_new.hpp>
@@ -12,28 +13,6 @@ namespace array = foonathan::array;
1213

1314
int main()
1415
{
15-
using bag = array::bag<int, array::block_storage_new<int, array::default_growth>>;
16-
17-
bag b;
18-
b.insert(1);
19-
b.insert(2);
20-
b.insert(3);
21-
b.insert(4);
22-
23-
for (auto el : b)
24-
std::cout << el << ' ';
25-
std::cout << '\n';
26-
27-
auto iter = std::find(b.begin(), b.end(), 2);
28-
b.erase(iter);
29-
30-
for (auto el : b)
31-
std::cout << el << ' ';
32-
std::cout << '\n';
33-
34-
b.insert(5);
35-
36-
for (auto el : b)
37-
std::cout << el << ' ';
38-
std::cout << '\n';
16+
std::vector<int> vec(7);
17+
std::cout << vec.size() << ' ' << vec.capacity() << '\n';
3918
}

0 commit comments

Comments
 (0)