libc++'s basic_string class assumes that iterator operations on the iterators that are passed to it don't throw. This is wrong, and means that we don't meet the strong exception guarantees in the standard.
A general solution is to do all the work in a temporary string, and then merge/swap the result into the destination in the end.
However, this is wasteful (extra allocations and copying) when the iterator operations can't throw.
Here I introduce some scaffolding to support detecting these iterators.
I took an old name from <algorithm> that was no longer used: __libcpp_is_trivial_iterator as the basis.
A trivial iterator is a pointer, or one of libc++'s wrapper around another iterator: move_iterator, reverse_iterator and __wrap_iterator (when the wrapped iterator is trivial). These are assumed to never throw on indirection, next/prev, comparison and assignment.
Then I add a string-specific type trait: __libcpp_string_gets_noexcept_iterator, which is either a trivial iterator or something that has noexcept increment, dereference and comparison. When I get a non-input iterator where __libcpp_string_gets_noexcept_iterator<Iter>::value is true, I do the algorithm in-place.
Note that this diff is just for assign; there are several other cases to deal with in <string>.
I'm looking for feedback on the general direction.