Fix PR#25973 : 'basic_string::assign(InputIt, InputIt) doesn't provide the strong exception safety guarantee'. This turned out to be a pervasive problem in <string>, which required a fair amount of rework. Add in an optimization for when iterators provide noexcept increment/comparison/assignment/dereference (which covers many of the iterators in libc++). Reviewed as http://reviews.llvm.org/D15862

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@257682 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/string b/include/string
index ee5db1a..9150244 100644
--- a/include/string
+++ b/include/string
@@ -1201,6 +1201,30 @@
 #pragma warning( pop )
 #endif // _LIBCPP_MSVC
 
+#ifdef _LIBCPP_NO_EXCEPTIONS
+template <class _Iter>
+struct __libcpp_string_gets_noexcept_iterator_impl : public true_type {};
+#elif defined(_LIBCPP_HAS_NO_NOEXCEPT)
+template <class _Iter>
+struct __libcpp_string_gets_noexcept_iterator_impl : public false_type {};
+#else
+template <class _Iter, bool = __is_forward_iterator<_Iter>::value>
+struct __libcpp_string_gets_noexcept_iterator_impl : public _LIBCPP_BOOL_CONSTANT((
+    noexcept(++(declval<_Iter&>())) && 
+    is_nothrow_assignable<_Iter&, _Iter>::value && 
+    noexcept(declval<_Iter>() == declval<_Iter>()) && 
+    noexcept(*declval<_Iter>())
+)) {};
+
+template <class _Iter> 
+struct __libcpp_string_gets_noexcept_iterator_impl<_Iter, false> : public false_type {};
+#endif
+
+
+template <class _Iter>
+struct __libcpp_string_gets_noexcept_iterator
+    : public _LIBCPP_BOOL_CONSTANT(__libcpp_is_trivial_iterator<_Iter>::value || __libcpp_string_gets_noexcept_iterator_impl<_Iter>::value) {};
+
 #ifdef _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT
 
 template <class _CharT, size_t = sizeof(_CharT)>
@@ -1495,15 +1519,16 @@
     template<class _InputIterator>
         typename enable_if
         <
-             __is_input_iterator  <_InputIterator>::value &&
-            !__is_forward_iterator<_InputIterator>::value,
+            __is_exactly_input_iterator<_InputIterator>::value
+                || !__libcpp_string_gets_noexcept_iterator<_InputIterator>::value,
             basic_string&
         >::type
         append(_InputIterator __first, _InputIterator __last);
     template<class _ForwardIterator>
         typename enable_if
         <
-            __is_forward_iterator<_ForwardIterator>::value,
+            __is_forward_iterator<_ForwardIterator>::value
+                && __libcpp_string_gets_noexcept_iterator<_ForwardIterator>::value,
             basic_string&
         >::type
         append(_ForwardIterator __first, _ForwardIterator __last);
@@ -1535,15 +1560,16 @@
     template<class _InputIterator>
         typename enable_if
         <
-             __is_input_iterator  <_InputIterator>::value &&
-            !__is_forward_iterator<_InputIterator>::value,
+           __is_exactly_input_iterator<_InputIterator>::value
+                || !__libcpp_string_gets_noexcept_iterator<_InputIterator>::value,
             basic_string&
         >::type
         assign(_InputIterator __first, _InputIterator __last);
     template<class _ForwardIterator>
         typename enable_if
         <
-            __is_forward_iterator<_ForwardIterator>::value,
+            __is_forward_iterator<_ForwardIterator>::value
+                 && __libcpp_string_gets_noexcept_iterator<_ForwardIterator>::value,
             basic_string&
         >::type
         assign(_ForwardIterator __first, _ForwardIterator __last);
@@ -1564,15 +1590,16 @@
     template<class _InputIterator>
         typename enable_if
         <
-             __is_input_iterator  <_InputIterator>::value &&
-            !__is_forward_iterator<_InputIterator>::value,
+           __is_exactly_input_iterator<_InputIterator>::value
+                || !__libcpp_string_gets_noexcept_iterator<_InputIterator>::value,
             iterator
         >::type
         insert(const_iterator __pos, _InputIterator __first, _InputIterator __last);
     template<class _ForwardIterator>
         typename enable_if
         <
-            __is_forward_iterator<_ForwardIterator>::value,
+            __is_forward_iterator<_ForwardIterator>::value
+                 && __libcpp_string_gets_noexcept_iterator<_ForwardIterator>::value,
             iterator
         >::type
         insert(const_iterator __pos, _ForwardIterator __first, _ForwardIterator __last);
@@ -1817,8 +1844,7 @@
     template <class _InputIterator>
     typename enable_if
     <
-         __is_input_iterator  <_InputIterator>::value &&
-        !__is_forward_iterator<_InputIterator>::value,
+        __is_exactly_input_iterator<_InputIterator>::value,
         void
     >::type
     __init(_InputIterator __first, _InputIterator __last);
@@ -2195,8 +2221,7 @@
 template <class _InputIterator>
 typename enable_if
 <
-     __is_input_iterator  <_InputIterator>::value &&
-    !__is_forward_iterator<_InputIterator>::value,
+    __is_exactly_input_iterator<_InputIterator>::value,
     void
 >::type
 basic_string<_CharT, _Traits, _Allocator>::__init(_InputIterator __first, _InputIterator __last)
@@ -2494,15 +2519,14 @@
 template<class _InputIterator>
 typename enable_if
 <
-     __is_input_iterator  <_InputIterator>::value &&
-    !__is_forward_iterator<_InputIterator>::value,
+     __is_exactly_input_iterator <_InputIterator>::value
+          || !__libcpp_string_gets_noexcept_iterator<_InputIterator>::value,
     basic_string<_CharT, _Traits, _Allocator>&
 >::type
 basic_string<_CharT, _Traits, _Allocator>::assign(_InputIterator __first, _InputIterator __last)
 {
-    clear();
-    for (; __first != __last; ++__first)
-        push_back(*__first);
+    basic_string __temp(__first, __last, __alloc());
+    assign(__temp.data(), __temp.size());
     return *this;
 }
 
@@ -2510,7 +2534,8 @@
 template<class _ForwardIterator>
 typename enable_if
 <
-    __is_forward_iterator<_ForwardIterator>::value,
+    __is_forward_iterator<_ForwardIterator>::value
+         && __libcpp_string_gets_noexcept_iterator<_ForwardIterator>::value,
     basic_string<_CharT, _Traits, _Allocator>&
 >::type
 basic_string<_CharT, _Traits, _Allocator>::assign(_ForwardIterator __first, _ForwardIterator __last)
@@ -2643,14 +2668,14 @@
 template<class _InputIterator>
 typename enable_if
 <
-     __is_input_iterator  <_InputIterator>::value &&
-    !__is_forward_iterator<_InputIterator>::value,
+    __is_exactly_input_iterator<_InputIterator>::value
+             || !__libcpp_string_gets_noexcept_iterator<_InputIterator>::value,
     basic_string<_CharT, _Traits, _Allocator>&
 >::type
 basic_string<_CharT, _Traits, _Allocator>::append(_InputIterator __first, _InputIterator __last)
 {
-    for (; __first != __last; ++__first)
-        push_back(*__first);
+	basic_string __temp (__first, __last, __alloc());
+	append(__temp.data(), __temp.size());
     return *this;
 }
 
@@ -2658,7 +2683,8 @@
 template<class _ForwardIterator>
 typename enable_if
 <
-    __is_forward_iterator<_ForwardIterator>::value,
+    __is_forward_iterator<_ForwardIterator>::value
+          && __libcpp_string_gets_noexcept_iterator<_ForwardIterator>::value,
     basic_string<_CharT, _Traits, _Allocator>&
 >::type
 basic_string<_CharT, _Traits, _Allocator>::append(_ForwardIterator __first, _ForwardIterator __last)
@@ -2774,9 +2800,9 @@
 template<class _InputIterator>
 typename enable_if
 <
-     __is_input_iterator  <_InputIterator>::value &&
-    !__is_forward_iterator<_InputIterator>::value,
-    typename basic_string<_CharT, _Traits, _Allocator>::iterator
+   __is_exactly_input_iterator<_InputIterator>::value
+        || !__libcpp_string_gets_noexcept_iterator<_InputIterator>::value,
+   typename basic_string<_CharT, _Traits, _Allocator>::iterator
 >::type
 basic_string<_CharT, _Traits, _Allocator>::insert(const_iterator __pos, _InputIterator __first, _InputIterator __last)
 {
@@ -2785,24 +2811,16 @@
         "string::insert(iterator, range) called with an iterator not"
         " referring to this string");
 #endif
-    size_type __old_sz = size();
-    difference_type __ip = __pos - begin();
-    for (; __first != __last; ++__first)
-        push_back(*__first);
-    pointer __p = __get_pointer();
-    _VSTD::rotate(__p + __ip, __p + __old_sz, __p + size());
-#if _LIBCPP_DEBUG_LEVEL >= 2
-    return iterator(this, __p + __ip);
-#else
-    return iterator(__p + __ip);
-#endif
+    basic_string __temp(__first, __last, __alloc());
+    return insert(__pos, __temp.data(), __temp.data() + __temp.size());
 }
 
 template <class _CharT, class _Traits, class _Allocator>
 template<class _ForwardIterator>
 typename enable_if
 <
-    __is_forward_iterator<_ForwardIterator>::value,
+    __is_forward_iterator<_ForwardIterator>::value
+        && __libcpp_string_gets_noexcept_iterator<_ForwardIterator>::value,
     typename basic_string<_CharT, _Traits, _Allocator>::iterator
 >::type
 basic_string<_CharT, _Traits, _Allocator>::insert(const_iterator __pos, _ForwardIterator __first, _ForwardIterator __last)
@@ -3005,22 +3023,8 @@
 basic_string<_CharT, _Traits, _Allocator>::replace(const_iterator __i1, const_iterator __i2,
                                                    _InputIterator __j1, _InputIterator __j2)
 {
-    for (; true; ++__i1, ++__j1)
-    {
-        if (__i1 == __i2)
-        {
-            if (__j1 != __j2)
-                insert(__i1, __j1, __j2);
-            break;
-        }
-        if (__j1 == __j2)
-        {
-            erase(__i1, __i2);
-            break;
-        }
-        traits_type::assign(const_cast<value_type&>(*__i1), *__j1);
-    }
-    return *this;
+    basic_string __temp(__j1, __j2, __alloc());
+    return this->replace(__i1, __i2, __temp);
 }
 
 template <class _CharT, class _Traits, class _Allocator>