Improve the performance of `a = b` on imported C++ types

Swift implements a = b on an imported C++ type as: destroy a, copy-construct it from b (see assignWithCopy). This is slower than calling operator= especially for STL types.

For example, std::vector::operator= does not allocate a new buffer if b fits inside a, see this example:

                                   C++                   Swift
vector: b.size() <= a.capacity()   operator=: 0 allocs   destroy+copy: 1 allocs
vector: b.size() >  a.capacity()   operator=: 1 allocs   destroy+copy: 1 allocs

This is more pronounced in containers like std::map where nodes are reused instead of being deleted, see this example:

                             C++                     Swift
map<int,int> 100 -> 100      operator=:   0 allocs   destroy+copy: 100 allocs
map<int,int>  50 -> 100      operator=:  50 allocs   destroy+copy: 100 allocs

I think the solution for this is to call the copy assignment in assignWithCopy if operator= it's public and not-deleted, otherwise call destroy + copy as today. Maybe the same could be done for move.

As far as I understand, Swift does not promise any specific number of copies, so this acts purely as a performance optimisation with no semantic changes for "well-behaved" types. Well-behaved = same observable behavior between operator= and destroy + copy.

1 Like

We should definitely be using the copy-assignment operator there, and similarly we should be using the move-assignment operator for assignWithTake. CC'ing @egor.zhdan.

1 Like