Fix the final (I think?) reference invalidation in SmallVector that
we need to fix to align with std::vector. (There is still some left in
the range insert / append / assign, but the standard calls that UB for
std::vector so I think we don't care?)
Avoid reference invalidation during SmallVector::emplace_back when one
of the arguments is an internal reference to storage and the vector has
to grow.
For POD-like types, reimplement emplace_back in terms of push_back.
For other types, split the grow operation in three and construct the new
element in the middle.
Also reimplement SmallVector:assign(size_type, const T&) to avoid
invalidating the argument during clear() when it's an internal
reference.
There is a minor semantic change when not growing. Previously, assign
would start with clear(), and so the old elements were destructed and
all elements of the new vector were copy-constructed. The new
implementation skips destruction and uses copy-assignment for the prefix
of the new vector less than size(). The new semantics match what
libc++ does for std::vector::assign.
Note that the following is another possible implementation:
void assign(size_type NumElts, ValueParamT Elt) { std::fill_n(this->begin(), std::min(NumElts, this->size()), Elt); this->resize(NumElts, Elt); }
The downside of this is that if the vector has to grow there will be
size() redundant copy operations.
I should probably split this patch up into three for committing:
- NFC refactoring to split up grow().
- Fix emplace_back().
- Fix assign().
... but I wanted to start the review all together since the patches
will be interdependent.