@@ -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
0 commit comments