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/algorithm b/include/algorithm
index 9c05119..71e5df3 100644
--- a/include/algorithm
+++ b/include/algorithm
@@ -1687,25 +1687,6 @@
}
// copy
-
-template <class _Iter>
-struct __libcpp_is_trivial_iterator
-{
- static const bool value = is_pointer<_Iter>::value;
-};
-
-template <class _Iter>
-struct __libcpp_is_trivial_iterator<move_iterator<_Iter> >
-{
- static const bool value = is_pointer<_Iter>::value;
-};
-
-template <class _Iter>
-struct __libcpp_is_trivial_iterator<__wrap_iter<_Iter> >
-{
- static const bool value = is_pointer<_Iter>::value;
-};
-
template <class _Iter>
inline _LIBCPP_INLINE_VISIBILITY
_Iter
diff --git a/include/iterator b/include/iterator
index 8dd6bd5..8d9b311 100644
--- a/include/iterator
+++ b/include/iterator
@@ -437,6 +437,12 @@
template <class _Tp>
struct __is_random_access_iterator : public __has_iterator_category_convertible_to<_Tp, random_access_iterator_tag> {};
+template <class _Tp>
+struct __is_exactly_input_iterator
+ : public integral_constant<bool,
+ __has_iterator_category_convertible_to<_Tp, input_iterator_tag>::value &&
+ !__has_iterator_category_convertible_to<_Tp, forward_iterator_tag>::value> {};
+
template<class _Category, class _Tp, class _Distance = ptrdiff_t,
class _Pointer = _Tp*, class _Reference = _Tp&>
struct _LIBCPP_TYPE_VIS_ONLY iterator
@@ -1404,6 +1410,23 @@
return __x;
}
+template <class _Iter>
+struct __libcpp_is_trivial_iterator
+ : public _LIBCPP_BOOL_CONSTANT(is_pointer<_Iter>::value) {};
+
+template <class _Iter>
+struct __libcpp_is_trivial_iterator<move_iterator<_Iter> >
+ : public _LIBCPP_BOOL_CONSTANT(__libcpp_is_trivial_iterator<_Iter>::value) {};
+
+template <class _Iter>
+struct __libcpp_is_trivial_iterator<reverse_iterator<_Iter> >
+ : public _LIBCPP_BOOL_CONSTANT(__libcpp_is_trivial_iterator<_Iter>::value) {};
+
+template <class _Iter>
+struct __libcpp_is_trivial_iterator<__wrap_iter<_Iter> >
+ : public _LIBCPP_BOOL_CONSTANT(__libcpp_is_trivial_iterator<_Iter>::value) {};
+
+
template <class _Tp, size_t _Np>
inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
_Tp*
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>
diff --git a/test/libcxx/iterators/trivial_iterators.pass.cpp b/test/libcxx/iterators/trivial_iterators.pass.cpp
new file mode 100644
index 0000000..0b7a473
--- /dev/null
+++ b/test/libcxx/iterators/trivial_iterators.pass.cpp
@@ -0,0 +1,187 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+
+// <iterator>
+
+// __libcpp_is_trivial_iterator<Tp>
+
+// __libcpp_is_trivial_iterator determines if an iterator is a "trivial" one,
+// that can be used w/o worrying about its operations throwing exceptions.
+// Pointers are trivial iterators. Libc++ has three "iterator wrappers":
+// reverse_iterator, move_iterator, and __wrap_iter. If the underlying iterator
+// is trivial, then those are as well.
+//
+
+#include <iterator>
+#include <cassert>
+#include <string>
+#include <vector>
+#include <initializer_list>
+
+#include "test_iterators.h"
+
+#ifndef _LIBCPP_HAS_NO_DELETED_FUNCTIONS
+#define DELETE_FUNCTION = delete
+#else
+#define DELETE_FUNCTION
+#endif
+
+class T; // incomplete
+
+class my_input_iterator_tag : public std::input_iterator_tag {};
+
+template <class It>
+class my_input_iterator
+{
+ It it_;
+
+ template <class U> friend class input_iterator;
+public:
+ typedef my_input_iterator_tag iterator_category;
+ typedef typename std::iterator_traits<It>::value_type value_type;
+ typedef typename std::iterator_traits<It>::difference_type difference_type;
+ typedef It pointer;
+ typedef typename std::iterator_traits<It>::reference reference;
+
+ It base() const {return it_;}
+
+ my_input_iterator() : it_() {}
+ explicit my_input_iterator(It it) : it_(it) {}
+ template <class U>
+ my_input_iterator(const input_iterator<U>& u) :it_(u.it_) {}
+
+ reference operator*() const {return *it_;}
+ pointer operator->() const {return it_;}
+
+ my_input_iterator& operator++() {++it_; return *this;}
+ my_input_iterator operator++(int)
+ {my_input_iterator tmp(*this); ++(*this); return tmp;}
+
+ friend bool operator==(const my_input_iterator& x, const my_input_iterator& y)
+ {return x.it_ == y.it_;}
+ friend bool operator!=(const my_input_iterator& x, const my_input_iterator& y)
+ {return !(x == y);}
+
+ template <class T>
+ void operator,(T const &) DELETE_FUNCTION;
+};
+
+template <class T, class U>
+inline
+bool
+operator==(const my_input_iterator<T>& x, const my_input_iterator<U>& y)
+{
+ return x.base() == y.base();
+}
+
+template <class T, class U>
+inline
+bool
+operator!=(const my_input_iterator<T>& x, const my_input_iterator<U>& y)
+{
+ return !(x == y);
+}
+
+
+int main()
+{
+// basic tests
+ static_assert(( std::__libcpp_is_trivial_iterator<char *>::value), "");
+ static_assert(( std::__libcpp_is_trivial_iterator<const char *>::value), "");
+ static_assert(( std::__libcpp_is_trivial_iterator<int *>::value), "");
+ static_assert(( std::__libcpp_is_trivial_iterator<T *>::value), "");
+
+ static_assert(( std::__libcpp_is_trivial_iterator<std::move_iterator<char *> > ::value), "");
+ static_assert(( std::__libcpp_is_trivial_iterator<std::move_iterator<const char *> >::value), "");
+ static_assert(( std::__libcpp_is_trivial_iterator<std::move_iterator<int *> > ::value), "");
+ static_assert(( std::__libcpp_is_trivial_iterator<std::move_iterator<T *> > ::value), "");
+
+ static_assert(( std::__libcpp_is_trivial_iterator<std::reverse_iterator<char *> > ::value), "");
+ static_assert(( std::__libcpp_is_trivial_iterator<std::reverse_iterator<const char *> >::value), "");
+ static_assert(( std::__libcpp_is_trivial_iterator<std::reverse_iterator<int *> > ::value), "");
+ static_assert(( std::__libcpp_is_trivial_iterator<std::reverse_iterator<T *> > ::value), "");
+
+ static_assert(( std::__libcpp_is_trivial_iterator<std::__wrap_iter<char *> > ::value), "");
+ static_assert(( std::__libcpp_is_trivial_iterator<std::__wrap_iter<const char *> >::value), "");
+ static_assert(( std::__libcpp_is_trivial_iterator<std::__wrap_iter<int *> > ::value), "");
+ static_assert(( std::__libcpp_is_trivial_iterator<std::__wrap_iter<T *> > ::value), "");
+
+ static_assert(( std::__libcpp_is_trivial_iterator<std::reverse_iterator<std::__wrap_iter<char *> > > ::value), "");
+
+// iterators in the libc++ test suite
+ static_assert((!std::__libcpp_is_trivial_iterator<output_iterator <char *> >::value), "");
+ static_assert((!std::__libcpp_is_trivial_iterator<input_iterator <char *> >::value), "");
+ static_assert((!std::__libcpp_is_trivial_iterator<forward_iterator <char *> >::value), "");
+ static_assert((!std::__libcpp_is_trivial_iterator<bidirectional_iterator<char *> >::value), "");
+ static_assert((!std::__libcpp_is_trivial_iterator<random_access_iterator<char *> >::value), "");
+ static_assert((!std::__libcpp_is_trivial_iterator<ThrowingIterator <char *> >::value), "");
+ static_assert((!std::__libcpp_is_trivial_iterator<NonThrowingIterator <char *> >::value), "");
+
+
+// Iterator classification
+ static_assert(( std::__is_input_iterator <char *>::value), "" );
+ static_assert(( std::__is_forward_iterator <char *>::value), "" );
+ static_assert(( std::__is_bidirectional_iterator<char *>::value), "" );
+ static_assert(( std::__is_random_access_iterator<char *>::value), "" );
+ static_assert((!std::__is_exactly_input_iterator<char *>::value), "" );
+
+ static_assert(( std::__is_input_iterator <input_iterator<char *> >::value), "" );
+ static_assert((!std::__is_forward_iterator <input_iterator<char *> >::value), "" );
+ static_assert((!std::__is_bidirectional_iterator<input_iterator<char *> >::value), "" );
+ static_assert((!std::__is_random_access_iterator<input_iterator<char *> >::value), "" );
+ static_assert(( std::__is_exactly_input_iterator<input_iterator<char *> >::value), "" );
+
+ static_assert(( std::__is_input_iterator <forward_iterator<char *> >::value), "" );
+ static_assert(( std::__is_forward_iterator <forward_iterator<char *> >::value), "" );
+ static_assert((!std::__is_bidirectional_iterator<forward_iterator<char *> >::value), "" );
+ static_assert((!std::__is_random_access_iterator<forward_iterator<char *> >::value), "" );
+ static_assert((!std::__is_exactly_input_iterator<forward_iterator<char *> >::value), "" );
+
+ static_assert(( std::__is_input_iterator <bidirectional_iterator<char *> >::value), "" );
+ static_assert(( std::__is_forward_iterator <bidirectional_iterator<char *> >::value), "" );
+ static_assert(( std::__is_bidirectional_iterator<bidirectional_iterator<char *> >::value), "" );
+ static_assert((!std::__is_random_access_iterator<bidirectional_iterator<char *> >::value), "" );
+ static_assert((!std::__is_exactly_input_iterator<bidirectional_iterator<char *> >::value), "" );
+
+ static_assert(( std::__is_input_iterator <random_access_iterator<char *> >::value), "" );
+ static_assert(( std::__is_forward_iterator <random_access_iterator<char *> >::value), "" );
+ static_assert(( std::__is_bidirectional_iterator<random_access_iterator<char *> >::value), "" );
+ static_assert(( std::__is_random_access_iterator<random_access_iterator<char *> >::value), "" );
+ static_assert((!std::__is_exactly_input_iterator<random_access_iterator<char *> >::value), "" );
+
+ static_assert(( std::__is_input_iterator <my_input_iterator<char *> >::value), "" );
+ static_assert((!std::__is_forward_iterator <my_input_iterator<char *> >::value), "" );
+ static_assert((!std::__is_bidirectional_iterator<my_input_iterator<char *> >::value), "" );
+ static_assert((!std::__is_random_access_iterator<my_input_iterator<char *> >::value), "" );
+ static_assert(( std::__is_exactly_input_iterator<my_input_iterator<char *> >::value), "" );
+
+//
+// iterators from libc++'s containers
+//
+
+// string
+ static_assert(( std::__libcpp_is_trivial_iterator<std::vector<char>::iterator> ::value), "");
+ static_assert(( std::__libcpp_is_trivial_iterator<std::vector<char>::const_iterator> ::value), "");
+ static_assert(( std::__libcpp_is_trivial_iterator<std::vector<char>::reverse_iterator> ::value), "");
+ static_assert(( std::__libcpp_is_trivial_iterator<std::vector<char>::const_reverse_iterator>::value), "");
+
+// vector
+ static_assert(( std::__libcpp_is_trivial_iterator<std::basic_string<char>::iterator> ::value), "");
+ static_assert(( std::__libcpp_is_trivial_iterator<std::basic_string<char>::const_iterator> ::value), "");
+ static_assert(( std::__libcpp_is_trivial_iterator<std::basic_string<char>::reverse_iterator> ::value), "");
+ static_assert(( std::__libcpp_is_trivial_iterator<std::basic_string<char>::const_reverse_iterator>::value), "");
+
+#ifndef _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS
+// Initializer list (which has no reverse iterators)
+ static_assert(( std::__libcpp_is_trivial_iterator<std::initializer_list<char>::iterator> ::value), "");
+ static_assert(( std::__libcpp_is_trivial_iterator<std::initializer_list<char>::const_iterator> ::value), "");
+#endif
+
+}
diff --git a/test/libcxx/strings/iterators.exceptions.pass.cpp b/test/libcxx/strings/iterators.exceptions.pass.cpp
new file mode 100644
index 0000000..cc542f8
--- /dev/null
+++ b/test/libcxx/strings/iterators.exceptions.pass.cpp
@@ -0,0 +1,75 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+
+// <iterator>
+
+// __libcpp_is_trivial_iterator<Tp>
+
+// __libcpp_string_gets_noexcept_iterator determines if an iterator can be used
+// w/o worrying about whether or not certain operations can throw.
+// This gives us a "fast path for string operations"
+//
+
+#include <iterator>
+#include <cassert>
+#include <string>
+#include <vector>
+#include <initializer_list>
+
+#include "test_iterators.h"
+
+int main()
+{
+// basic tests
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<char *>::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<const char *>::value), "");
+
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::move_iterator<char *> > ::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::move_iterator<const char *> >::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::reverse_iterator<char *> > ::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::reverse_iterator<const char *> >::value), "");
+
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::__wrap_iter<char *> > ::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::__wrap_iter<const char *> >::value), "");
+
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::reverse_iterator<std::__wrap_iter<char *> > > ::value), "");
+
+// iterators in the libc++ test suite
+ static_assert((!std::__libcpp_string_gets_noexcept_iterator<output_iterator <char *> >::value), "");
+ static_assert((!std::__libcpp_string_gets_noexcept_iterator<input_iterator <char *> >::value), "");
+ static_assert((!std::__libcpp_string_gets_noexcept_iterator<forward_iterator <char *> >::value), "");
+ static_assert((!std::__libcpp_string_gets_noexcept_iterator<bidirectional_iterator<char *> >::value), "");
+ static_assert((!std::__libcpp_string_gets_noexcept_iterator<random_access_iterator<char *> >::value), "");
+ static_assert((!std::__libcpp_string_gets_noexcept_iterator<ThrowingIterator <char *> >::value), "");
+
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<NonThrowingIterator <char *> >::value), "");
+
+//
+// iterators from libc++'s containers
+//
+
+// string
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::vector<char>::iterator> ::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::vector<char>::const_iterator> ::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::vector<char>::reverse_iterator> ::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::vector<char>::const_reverse_iterator>::value), "");
+
+// vector
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::basic_string<char>::iterator> ::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::basic_string<char>::const_iterator> ::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::basic_string<char>::reverse_iterator> ::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::basic_string<char>::const_reverse_iterator>::value), "");
+
+#ifndef _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS
+// Initializer list (which has no reverse iterators)
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::initializer_list<char>::iterator> ::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::initializer_list<char>::const_iterator> ::value), "");
+#endif
+}
diff --git a/test/libcxx/strings/iterators.noexcept.pass.cpp b/test/libcxx/strings/iterators.noexcept.pass.cpp
new file mode 100644
index 0000000..4c543b2
--- /dev/null
+++ b/test/libcxx/strings/iterators.noexcept.pass.cpp
@@ -0,0 +1,78 @@
+//===----------------------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is dual licensed under the MIT and the University of Illinois Open
+// Source Licenses. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+
+// <iterator>
+
+// __libcpp_is_trivial_iterator<Tp>
+
+// __libcpp_string_gets_noexcept_iterator determines if an iterator can be used
+// w/o worrying about whether or not certain operations can throw.
+// This gives us a "fast path for string operations"
+//
+
+#define _LIBCPP_NO_EXCEPTIONS
+
+#include <iterator>
+#include <cassert>
+#include <string>
+#include <vector>
+#include <initializer_list>
+
+#include "test_iterators.h"
+
+int main()
+{
+// basic tests
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<char *>::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<const char *>::value), "");
+
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::move_iterator<char *> > ::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::move_iterator<const char *> >::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::reverse_iterator<char *> > ::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::reverse_iterator<const char *> >::value), "");
+
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::__wrap_iter<char *> > ::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::__wrap_iter<const char *> >::value), "");
+
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::reverse_iterator<std::__wrap_iter<char *> > > ::value), "");
+
+// iterators in the libc++ test suite
+// Since we have turned off exceptions, they're all noexcept
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<output_iterator <char *> >::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<input_iterator <char *> >::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<forward_iterator <char *> >::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<bidirectional_iterator<char *> >::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<random_access_iterator<char *> >::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<ThrowingIterator <char *> >::value), "");
+
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<NonThrowingIterator <char *> >::value), "");
+
+//
+// iterators from libc++'s containers
+//
+
+// string
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::vector<char>::iterator> ::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::vector<char>::const_iterator> ::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::vector<char>::reverse_iterator> ::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::vector<char>::const_reverse_iterator>::value), "");
+
+// vector
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::basic_string<char>::iterator> ::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::basic_string<char>::const_iterator> ::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::basic_string<char>::reverse_iterator> ::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::basic_string<char>::const_reverse_iterator>::value), "");
+
+#ifndef _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS
+// Initializer list (which has no reverse iterators)
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::initializer_list<char>::iterator> ::value), "");
+ static_assert(( std::__libcpp_string_gets_noexcept_iterator<std::initializer_list<char>::const_iterator> ::value), "");
+#endif
+}
diff --git a/test/std/strings/basic.string/string.modifiers/string_append/initializer_list.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_append/initializer_list.pass.cpp
index fb28e49..2abfbf0 100644
--- a/test/std/strings/basic.string/string.modifiers/string_append/initializer_list.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_append/initializer_list.pass.cpp
@@ -24,7 +24,7 @@
s.append({'a', 'b', 'c'});
assert(s == "123abc");
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
S s("123");
diff --git a/test/std/strings/basic.string/string.modifiers/string_append/iterator.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_append/iterator.pass.cpp
index 3bf2afa..82e6fb5 100644
--- a/test/std/strings/basic.string/string.modifiers/string_append/iterator.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_append/iterator.pass.cpp
@@ -15,7 +15,7 @@
#include <string>
#include <cassert>
-#include "../../input_iterator.h"
+#include "test_iterators.h"
#include "min_allocator.h"
template <class S, class It>
@@ -27,6 +27,20 @@
assert(s == expected);
}
+template <class S, class It>
+void
+test_exceptions(S s, It first, It last)
+{
+ S aCopy = s;
+ try {
+ s.append(first, last);
+ assert(false);
+ }
+ catch (...) {}
+ assert(s.__invariants());
+ assert(s == aCopy);
+}
+
int main()
{
{
@@ -87,7 +101,7 @@
test(S("12345678901234567890"), input_iterator<const char*>(s), input_iterator<const char*>(s+52),
S("12345678901234567890""ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"));
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
const char* s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
@@ -147,4 +161,17 @@
S("12345678901234567890""ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"));
}
#endif
+ { // test iterator operations that throw
+ typedef std::string S;
+ typedef ThrowingIterator<char> TIter;
+ typedef input_iterator<TIter> IIter;
+ const char* s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ test_exceptions(S(), IIter(TIter(s, s+10, 4, TIter::TAIncrement)), IIter());
+ test_exceptions(S(), IIter(TIter(s, s+10, 5, TIter::TADereference)), IIter());
+ test_exceptions(S(), IIter(TIter(s, s+10, 6, TIter::TAComparison)), IIter());
+
+ test_exceptions(S(), TIter(s, s+10, 4, TIter::TAIncrement), TIter());
+ test_exceptions(S(), TIter(s, s+10, 5, TIter::TADereference), TIter());
+ test_exceptions(S(), TIter(s, s+10, 6, TIter::TAComparison), TIter());
+ }
}
diff --git a/test/std/strings/basic.string/string.modifiers/string_append/pointer.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_append/pointer.pass.cpp
index 5ae15f0..c0413d6 100644
--- a/test/std/strings/basic.string/string.modifiers/string_append/pointer.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_append/pointer.pass.cpp
@@ -43,7 +43,7 @@
test(S("12345678901234567890"), "12345678901234567890",
S("1234567890123456789012345678901234567890"));
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test(S(), "", S());
diff --git a/test/std/strings/basic.string/string.modifiers/string_append/pointer_size.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_append/pointer_size.pass.cpp
index 5a9e8e2..f3ea3b0 100644
--- a/test/std/strings/basic.string/string.modifiers/string_append/pointer_size.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_append/pointer_size.pass.cpp
@@ -48,7 +48,7 @@
test(S("12345678901234567890"), "12345678901234567890", 20,
S("1234567890123456789012345678901234567890"));
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test(S(), "", 0, S());
diff --git a/test/std/strings/basic.string/string.modifiers/string_append/push_back.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_append/push_back.pass.cpp
index b0a2eb5..d6116d3 100644
--- a/test/std/strings/basic.string/string.modifiers/string_append/push_back.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_append/push_back.pass.cpp
@@ -33,7 +33,7 @@
test(S("12345"), 'a', S("12345a"));
test(S("12345678901234567890"), 'a', S("12345678901234567890a"));
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test(S(), 'a', S(1, 'a'));
diff --git a/test/std/strings/basic.string/string.modifiers/string_append/size_char.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_append/size_char.pass.cpp
index 00e6ae3..a049e61 100644
--- a/test/std/strings/basic.string/string.modifiers/string_append/size_char.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_append/size_char.pass.cpp
@@ -43,7 +43,7 @@
test(S("12345678901234567890"), 1, 'a', S("12345678901234567890a"));
test(S("12345678901234567890"), 10, 'a', S("12345678901234567890aaaaaaaaaa"));
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test(S(), 0, 'a', S());
diff --git a/test/std/strings/basic.string/string.modifiers/string_append/string.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_append/string.pass.cpp
index 31f174b..e25627f 100644
--- a/test/std/strings/basic.string/string.modifiers/string_append/string.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_append/string.pass.cpp
@@ -51,7 +51,7 @@
test(S("12345678901234567890"), S("12345678901234567890"),
S("1234567890123456789012345678901234567890"));
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test(S(), S(), S());
diff --git a/test/std/strings/basic.string/string.modifiers/string_append/string_size_size.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_append/string_size_size.pass.cpp
index 1d409b0..d67b030 100644
--- a/test/std/strings/basic.string/string.modifiers/string_append/string_size_size.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_append/string_size_size.pass.cpp
@@ -80,7 +80,7 @@
test(S("12345678901234567890"), S("12345678901234567890"), 5, 10,
S("123456789012345678906789012345"));
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test(S(), S(), 0, 0, S());
diff --git a/test/std/strings/basic.string/string.modifiers/string_assign/initializer_list.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_assign/initializer_list.pass.cpp
index 2dae107..003af0e 100644
--- a/test/std/strings/basic.string/string.modifiers/string_assign/initializer_list.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_assign/initializer_list.pass.cpp
@@ -24,7 +24,7 @@
s.assign({'a', 'b', 'c'});
assert(s == "abc");
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
S s("123");
diff --git a/test/std/strings/basic.string/string.modifiers/string_assign/iterator.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_assign/iterator.pass.cpp
index 83b5dd1..690aebd 100644
--- a/test/std/strings/basic.string/string.modifiers/string_assign/iterator.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_assign/iterator.pass.cpp
@@ -15,7 +15,7 @@
#include <string>
#include <cassert>
-#include "../../input_iterator.h"
+#include "test_iterators.h"
#include "min_allocator.h"
template <class S, class It>
@@ -27,6 +27,20 @@
assert(s == expected);
}
+template <class S, class It>
+void
+test_exceptions(S s, It first, It last)
+{
+ S aCopy = s;
+ try {
+ s.assign(first, last);
+ assert(false);
+ }
+ catch (...) {}
+ assert(s.__invariants());
+ assert(s == aCopy);
+}
+
int main()
{
{
@@ -147,4 +161,17 @@
S("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"));
}
#endif
+ { // test iterator operations that throw
+ typedef std::string S;
+ typedef ThrowingIterator<char> TIter;
+ typedef input_iterator<TIter> IIter;
+ const char* s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ test_exceptions(S(), IIter(TIter(s, s+10, 4, TIter::TAIncrement)), IIter());
+ test_exceptions(S(), IIter(TIter(s, s+10, 5, TIter::TADereference)), IIter());
+ test_exceptions(S(), IIter(TIter(s, s+10, 6, TIter::TAComparison)), IIter());
+
+ test_exceptions(S(), TIter(s, s+10, 4, TIter::TAIncrement), TIter());
+ test_exceptions(S(), TIter(s, s+10, 5, TIter::TADereference), TIter());
+ test_exceptions(S(), TIter(s, s+10, 6, TIter::TAComparison), TIter());
+ }
}
diff --git a/test/std/strings/basic.string/string.modifiers/string_assign/pointer.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_assign/pointer.pass.cpp
index adf24ac..07dbcea 100644
--- a/test/std/strings/basic.string/string.modifiers/string_assign/pointer.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_assign/pointer.pass.cpp
@@ -43,7 +43,7 @@
test(S("12345678901234567890"), "12345678901234567890",
S("12345678901234567890"));
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test(S(), "", S());
diff --git a/test/std/strings/basic.string/string.modifiers/string_assign/pointer_size.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_assign/pointer_size.pass.cpp
index 476fe96..a9c71ce 100644
--- a/test/std/strings/basic.string/string.modifiers/string_assign/pointer_size.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_assign/pointer_size.pass.cpp
@@ -48,7 +48,7 @@
test(S("12345678901234567890"), "12345678901234567890", 20,
S("12345678901234567890"));
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test(S(), "", 0, S());
diff --git a/test/std/strings/basic.string/string.modifiers/string_assign/rv_string.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_assign/rv_string.pass.cpp
index 4273860..b3d225a 100644
--- a/test/std/strings/basic.string/string.modifiers/string_assign/rv_string.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_assign/rv_string.pass.cpp
@@ -52,7 +52,7 @@
test(S("12345678901234567890"), S("12345678901234567890"),
S("12345678901234567890"));
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test(S(), S(), S());
diff --git a/test/std/strings/basic.string/string.modifiers/string_assign/size_char.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_assign/size_char.pass.cpp
index a8f7470..9dd19d8 100644
--- a/test/std/strings/basic.string/string.modifiers/string_assign/size_char.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_assign/size_char.pass.cpp
@@ -43,7 +43,7 @@
test(S("12345678901234567890"), 1, 'a', S(1, 'a'));
test(S("12345678901234567890"), 10, 'a', S(10, 'a'));
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test(S(), 0, 'a', S());
diff --git a/test/std/strings/basic.string/string.modifiers/string_assign/string.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_assign/string.pass.cpp
index 99b5315..2bc5dd2 100644
--- a/test/std/strings/basic.string/string.modifiers/string_assign/string.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_assign/string.pass.cpp
@@ -51,7 +51,7 @@
test(S("12345678901234567890"), S("12345678901234567890"),
S("12345678901234567890"));
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test(S(), S(), S());
diff --git a/test/std/strings/basic.string/string.modifiers/string_assign/string_size_size.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_assign/string_size_size.pass.cpp
index db9e9a3..275d249 100644
--- a/test/std/strings/basic.string/string.modifiers/string_assign/string_size_size.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_assign/string_size_size.pass.cpp
@@ -80,7 +80,7 @@
test(S("12345678901234567890"), S("12345678901234567890"), 5, 10,
S("6789012345"));
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test(S(), S(), 0, 0, S());
diff --git a/test/std/strings/basic.string/string.modifiers/string_insert/iter_char.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_insert/iter_char.pass.cpp
index b9e5fa8..6b0a3aa 100644
--- a/test/std/strings/basic.string/string.modifiers/string_insert/iter_char.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_insert/iter_char.pass.cpp
@@ -56,7 +56,7 @@
test(s, s.begin()+5, 'B', S("a567AB1432dcb"));
test(s, s.begin()+6, 'C', S("a567ABC1432dcb"));
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
S s;
diff --git a/test/std/strings/basic.string/string.modifiers/string_insert/iter_initializer_list.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_insert/iter_initializer_list.pass.cpp
index e091662..2adf846 100644
--- a/test/std/strings/basic.string/string.modifiers/string_insert/iter_initializer_list.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_insert/iter_initializer_list.pass.cpp
@@ -29,7 +29,7 @@
assert(i - s.begin() == 3);
assert(s == "123abc456");
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
S s("123456");
diff --git a/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.pass.cpp
index 38353dd..4c29ab4 100644
--- a/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_insert/iter_iter_iter.pass.cpp
@@ -19,7 +19,7 @@
#include <string>
#include <cassert>
-#include "../../input_iterator.h"
+#include "test_iterators.h"
#include "min_allocator.h"
template <class S, class It>
@@ -33,6 +33,21 @@
assert(s == expected);
}
+template <class S, class It>
+void
+test_exceptions(S s, typename S::difference_type pos, It first, It last)
+{
+ typename S::const_iterator p = s.cbegin() + pos;
+ S aCopy = s;
+ try {
+ s.insert(p, first, last);
+ assert(false);
+ }
+ catch (...) {}
+ assert(s.__invariants());
+ assert(s == aCopy);
+}
+
int main()
{
{
@@ -80,7 +95,7 @@
test(S("12345678901234567890"), 20, input_iterator<const char*>(s), input_iterator<const char*>(s+52),
S("12345678901234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"));
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
const char* s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
@@ -127,6 +142,19 @@
S("12345678901234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"));
}
#endif
+ { // test iterator operations that throw
+ typedef std::string S;
+ typedef ThrowingIterator<char> TIter;
+ typedef input_iterator<TIter> IIter;
+ const char* s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ test_exceptions(S(), 0, IIter(TIter(s, s+10, 4, TIter::TAIncrement)), IIter());
+ test_exceptions(S(), 0, IIter(TIter(s, s+10, 5, TIter::TADereference)), IIter());
+ test_exceptions(S(), 0, IIter(TIter(s, s+10, 6, TIter::TAComparison)), IIter());
+
+ test_exceptions(S(), 0, TIter(s, s+10, 4, TIter::TAIncrement), TIter());
+ test_exceptions(S(), 0, TIter(s, s+10, 5, TIter::TADereference), TIter());
+ test_exceptions(S(), 0, TIter(s, s+10, 6, TIter::TAComparison), TIter());
+ }
#if _LIBCPP_DEBUG >= 1
{
std::string v;
diff --git a/test/std/strings/basic.string/string.modifiers/string_insert/iter_size_char.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_insert/iter_size_char.pass.cpp
index 739c894..e6d1db6 100644
--- a/test/std/strings/basic.string/string.modifiers/string_insert/iter_size_char.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_insert/iter_size_char.pass.cpp
@@ -101,7 +101,7 @@
test(S("abcdefghijklmnopqrst"), 20, 10, '1', S("abcdefghijklmnopqrst1111111111"));
test(S("abcdefghijklmnopqrst"), 20, 20, '1', S("abcdefghijklmnopqrst11111111111111111111"));
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test(S(""), 0, 0, '1', S(""));
diff --git a/test/std/strings/basic.string/string.modifiers/string_insert/size_pointer.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_insert/size_pointer.pass.cpp
index 8277f88..247b330 100644
--- a/test/std/strings/basic.string/string.modifiers/string_insert/size_pointer.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_insert/size_pointer.pass.cpp
@@ -124,7 +124,7 @@
test(S("abcdefghijklmnopqrst"), 21, "1234567890", S("can't happen"));
test(S("abcdefghijklmnopqrst"), 21, "12345678901234567890", S("can't happen"));
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test(S(""), 0, "", S(""));
diff --git a/test/std/strings/basic.string/string.modifiers/string_insert/size_pointer_size.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_insert/size_pointer_size.pass.cpp
index 4df5a14..41b8123 100644
--- a/test/std/strings/basic.string/string.modifiers/string_insert/size_pointer_size.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_insert/size_pointer_size.pass.cpp
@@ -365,7 +365,7 @@
test(S("abcdefghijklmnopqrst"), 21, "12345678901234567890", 19, S("can't happen"));
test(S("abcdefghijklmnopqrst"), 21, "12345678901234567890", 20, S("can't happen"));
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test(S(""), 0, "", 0, S(""));
diff --git a/test/std/strings/basic.string/string.modifiers/string_insert/size_size_char.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_insert/size_size_char.pass.cpp
index 20e0302..945ec48 100644
--- a/test/std/strings/basic.string/string.modifiers/string_insert/size_size_char.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_insert/size_size_char.pass.cpp
@@ -125,7 +125,7 @@
test(S("abcdefghijklmnopqrst"), 21, 10, '1', S("can't happen"));
test(S("abcdefghijklmnopqrst"), 21, 20, '1', S("can't happen"));
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test(S(""), 0, 0, '1', S(""));
diff --git a/test/std/strings/basic.string/string.modifiers/string_insert/size_string.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_insert/size_string.pass.cpp
index 016dcaf..04b47ec 100644
--- a/test/std/strings/basic.string/string.modifiers/string_insert/size_string.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_insert/size_string.pass.cpp
@@ -124,7 +124,7 @@
test(S("abcdefghijklmnopqrst"), 21, S("1234567890"), S("can't happen"));
test(S("abcdefghijklmnopqrst"), 21, S("12345678901234567890"), S("can't happen"));
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test(S(""), 0, S(""), S(""));
diff --git a/test/std/strings/basic.string/string.modifiers/string_insert/size_string_size_size.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_insert/size_string_size_size.pass.cpp
index 3c4c818..c3745c3 100644
--- a/test/std/strings/basic.string/string.modifiers/string_insert/size_string_size_size.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_insert/size_string_size_size.pass.cpp
@@ -1746,7 +1746,7 @@
test29<S>();
test30<S>();
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test0<S>();
diff --git a/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_initializer_list.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_initializer_list.pass.cpp
index 20455b2..b60a58c 100644
--- a/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_initializer_list.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_initializer_list.pass.cpp
@@ -24,7 +24,7 @@
s.replace(s.cbegin() + 3, s.cbegin() + 6, {'a', 'b', 'c'});
assert(s == "123abc456");
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
S s("123def456");
diff --git a/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_iter_iter.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_iter_iter.pass.cpp
index 9295c5b..0579641 100644
--- a/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_iter_iter.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_iter_iter.pass.cpp
@@ -18,6 +18,7 @@
#include <cassert>
#include "min_allocator.h"
+#include "test_iterators.h"
template <class S, class It>
void
@@ -34,6 +35,22 @@
assert(s.size() == old_size - xlen + rlen);
}
+template <class S, class It>
+void
+test_exceptions(S s, typename S::size_type pos1, typename S::size_type n1, It f, It l)
+{
+ typename S::const_iterator first = s.begin() + pos1;
+ typename S::const_iterator last = s.begin() + pos1 + n1;
+ S aCopy = s;
+ try {
+ s.replace(first, last, f, l);
+ assert(false);
+ }
+ catch (...) {}
+ assert(s.__invariants());
+ assert(s == aCopy);
+}
+
const char* str = "12345678901234567890";
template <class S>
@@ -959,7 +976,7 @@
test7<S>();
test8<S>();
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test0<S>();
@@ -973,4 +990,17 @@
test8<S>();
}
#endif
+ { // test iterator operations that throw
+ typedef std::string S;
+ typedef ThrowingIterator<char> TIter;
+ typedef input_iterator<TIter> IIter;
+ const char* s = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+ test_exceptions(S("abcdefghijklmnopqrst"), 10, 5, IIter(TIter(s, s+10, 4, TIter::TAIncrement)), IIter());
+ test_exceptions(S("abcdefghijklmnopqrst"), 10, 5, IIter(TIter(s, s+10, 5, TIter::TADereference)), IIter());
+ test_exceptions(S("abcdefghijklmnopqrst"), 10, 5, IIter(TIter(s, s+10, 6, TIter::TAComparison)), IIter());
+
+ test_exceptions(S("abcdefghijklmnopqrst"), 10, 5, TIter(s, s+10, 4, TIter::TAIncrement), TIter());
+ test_exceptions(S("abcdefghijklmnopqrst"), 10, 5, TIter(s, s+10, 5, TIter::TADereference), TIter());
+ test_exceptions(S("abcdefghijklmnopqrst"), 10, 5, TIter(s, s+10, 6, TIter::TAComparison), TIter());
+ }
}
diff --git a/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_pointer.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_pointer.pass.cpp
index cb4ce61..c7551b9 100644
--- a/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_pointer.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_pointer.pass.cpp
@@ -274,7 +274,7 @@
test1<S>();
test2<S>();
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test0<S>();
diff --git a/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_pointer_size.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_pointer_size.pass.cpp
index b1d6ab1..087df78 100644
--- a/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_pointer_size.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_pointer_size.pass.cpp
@@ -959,7 +959,7 @@
test7<S>();
test8<S>();
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test0<S>();
diff --git a/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_size_char.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_size_char.pass.cpp
index b0e2234..8be8b52 100644
--- a/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_size_char.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_size_char.pass.cpp
@@ -275,7 +275,7 @@
test1<S>();
test2<S>();
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test0<S>();
diff --git a/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_string.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_string.pass.cpp
index 0f95492..b85a106 100644
--- a/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_string.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_string.pass.cpp
@@ -274,7 +274,7 @@
test1<S>();
test2<S>();
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test0<S>();
diff --git a/test/std/strings/basic.string/string.modifiers/string_replace/size_size_pointer.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_replace/size_size_pointer.pass.cpp
index 18f32bf..eb0e982 100644
--- a/test/std/strings/basic.string/string.modifiers/string_replace/size_size_pointer.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_replace/size_size_pointer.pass.cpp
@@ -365,7 +365,7 @@
test1<S>();
test2<S>();
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test0<S>();
diff --git a/test/std/strings/basic.string/string.modifiers/string_replace/size_size_pointer_size.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_replace/size_size_pointer_size.pass.cpp
index fc7ee98..898ab2a 100644
--- a/test/std/strings/basic.string/string.modifiers/string_replace/size_size_pointer_size.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_replace/size_size_pointer_size.pass.cpp
@@ -1308,7 +1308,7 @@
test10<S>();
test11<S>();
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test0<S>();
diff --git a/test/std/strings/basic.string/string.modifiers/string_replace/size_size_size_char.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_replace/size_size_size_char.pass.cpp
index cda4112..e616ecc 100644
--- a/test/std/strings/basic.string/string.modifiers/string_replace/size_size_size_char.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_replace/size_size_size_char.pass.cpp
@@ -364,7 +364,7 @@
test1<S>();
test2<S>();
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test0<S>();
diff --git a/test/std/strings/basic.string/string.modifiers/string_replace/size_size_string.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_replace/size_size_string.pass.cpp
index 59e4d5c..ea311dd 100644
--- a/test/std/strings/basic.string/string.modifiers/string_replace/size_size_string.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_replace/size_size_string.pass.cpp
@@ -362,7 +362,7 @@
test1<S>();
test2<S>();
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test0<S>();
diff --git a/test/std/strings/basic.string/string.modifiers/string_replace/size_size_string_size_size.pass.cpp b/test/std/strings/basic.string/string.modifiers/string_replace/size_size_string_size_size.pass.cpp
index f5ac2e8..01f4a1f 100644
--- a/test/std/strings/basic.string/string.modifiers/string_replace/size_size_string_size_size.pass.cpp
+++ b/test/std/strings/basic.string/string.modifiers/string_replace/size_size_string_size_size.pass.cpp
@@ -5903,7 +5903,7 @@
test54<S>();
test55<S>();
}
-#if __cplusplus >= 201103L
+#if TEST_STD_VER >= 11
{
typedef std::basic_string<char, std::char_traits<char>, min_allocator<char>> S;
test0<S>();
diff --git a/test/support/test_iterators.h b/test/support/test_iterators.h
index e09fd83..d814879 100644
--- a/test/support/test_iterators.h
+++ b/test/support/test_iterators.h
@@ -11,8 +11,11 @@
#define ITERATORS_H
#include <iterator>
+#include <stdexcept>
#include <cassert>
+#include "test_macros.h"
+
#ifndef _LIBCPP_HAS_NO_DELETED_FUNCTIONS
#define DELETE_FUNCTION = delete
#else
@@ -324,6 +327,202 @@
template <class Iter> // everything else
inline Iter base(Iter i) { return i; }
+template <typename T>
+struct ThrowingIterator {
+ typedef std::bidirectional_iterator_tag iterator_category;
+ typedef ptrdiff_t difference_type;
+ typedef const T value_type;
+ typedef const T * pointer;
+ typedef const T & reference;
+
+ enum ThrowingAction { TAIncrement, TADecrement, TADereference, TAAssignment, TAComparison };
+
+// Constructors
+ ThrowingIterator ()
+ : begin_(nullptr), end_(nullptr), current_(nullptr), action_(TADereference), index_(0) {}
+ ThrowingIterator (const T *first, const T *last, size_t index = 0, ThrowingAction action = TADereference)
+ : begin_(first), end_(last), current_(first), action_(action), index_(index) {}
+ ThrowingIterator (const ThrowingIterator &rhs)
+ : begin_(rhs.begin_), end_(rhs.end_), current_(rhs.current_), action_(rhs.action_), index_(rhs.index_) {}
+ ThrowingIterator & operator= (const ThrowingIterator &rhs)
+ {
+ if (action_ == TAAssignment)
+ {
+ if (index_ == 0)
+ throw std::runtime_error ("throw from iterator assignment");
+ else
+ --index_;
+ }
+ begin_ = rhs.begin_;
+ end_ = rhs.end_;
+ current_ = rhs.current_;
+ action_ = rhs.action_;
+ index_ = rhs.index_;
+ return *this;
+ }
+
+// iterator operations
+ reference operator*() const
+ {
+ if (action_ == TADereference)
+ {
+ if (index_ == 0)
+ throw std::runtime_error ("throw from iterator dereference");
+ else
+ --index_;
+ }
+ return *current_;
+ }
+
+ ThrowingIterator & operator++()
+ {
+ if (action_ == TAIncrement)
+ {
+ if (index_ == 0)
+ throw std::runtime_error ("throw from iterator increment");
+ else
+ --index_;
+ }
+ ++current_;
+ return *this;
+ }
+
+ ThrowingIterator operator++(int)
+ {
+ ThrowingIterator temp = *this;
+ ++(*this);
+ return temp;
+ }
+
+ ThrowingIterator & operator--()
+ {
+ if (action_ == TADecrement)
+ {
+ if (index_ == 0)
+ throw std::runtime_error ("throw from iterator decrement");
+ else
+ --index_;
+ }
+ --current_;
+ return *this;
+ }
+
+ ThrowingIterator operator--(int) {
+ ThrowingIterator temp = *this;
+ --(*this);
+ return temp;
+ }
+
+ bool operator== (const ThrowingIterator &rhs) const
+ {
+ if (action_ == TAComparison)
+ {
+ if (index_ == 0)
+ throw std::runtime_error ("throw from iterator comparison");
+ else
+ --index_;
+ }
+ bool atEndL = current_ == end_;
+ bool atEndR = rhs.current_ == rhs.end_;
+ if (atEndL != atEndR) return false; // one is at the end (or empty), the other is not.
+ if (atEndL) return true; // both are at the end (or empty)
+ return current_ == rhs.current_;
+ }
+
+private:
+ const T* begin_;
+ const T* end_;
+ const T* current_;
+ ThrowingAction action_;
+ mutable size_t index_;
+};
+
+template <typename T>
+bool operator== (const ThrowingIterator<T>& a, const ThrowingIterator<T>& b)
+{ return a.operator==(b); }
+
+template <typename T>
+bool operator!= (const ThrowingIterator<T>& a, const ThrowingIterator<T>& b)
+{ return !a.operator==(b); }
+
+template <typename T>
+struct NonThrowingIterator {
+ typedef std::bidirectional_iterator_tag iterator_category;
+ typedef ptrdiff_t difference_type;
+ typedef const T value_type;
+ typedef const T * pointer;
+ typedef const T & reference;
+
+// Constructors
+ NonThrowingIterator ()
+ : begin_(nullptr), end_(nullptr), current_(nullptr) {}
+ NonThrowingIterator (const T *first, const T* last)
+ : begin_(first), end_(last), current_(first) {}
+ NonThrowingIterator (const NonThrowingIterator &rhs)
+ : begin_(rhs.begin_), end_(rhs.end_), current_(rhs.current_) {}
+ NonThrowingIterator & operator= (const NonThrowingIterator &rhs) TEST_NOEXCEPT
+ {
+ begin_ = rhs.begin_;
+ end_ = rhs.end_;
+ current_ = rhs.current_;
+ return *this;
+ }
+
+// iterator operations
+ reference operator*() const TEST_NOEXCEPT
+ {
+ return *current_;
+ }
+
+ NonThrowingIterator & operator++() TEST_NOEXCEPT
+ {
+ ++current_;
+ return *this;
+ }
+
+ NonThrowingIterator operator++(int) TEST_NOEXCEPT
+ {
+ NonThrowingIterator temp = *this;
+ ++(*this);
+ return temp;
+ }
+
+ NonThrowingIterator & operator--() TEST_NOEXCEPT
+ {
+ --current_;
+ return *this;
+ }
+
+ NonThrowingIterator operator--(int) TEST_NOEXCEPT
+ {
+ NonThrowingIterator temp = *this;
+ --(*this);
+ return temp;
+ }
+
+ bool operator== (const NonThrowingIterator &rhs) const TEST_NOEXCEPT
+ {
+ bool atEndL = current_ == end_;
+ bool atEndR = rhs.current_ == rhs.end_;
+ if (atEndL != atEndR) return false; // one is at the end (or empty), the other is not.
+ if (atEndL) return true; // both are at the end (or empty)
+ return current_ == rhs.current_;
+ }
+
+private:
+ const T* begin_;
+ const T* end_;
+ const T* current_;
+};
+
+template <typename T>
+bool operator== (const NonThrowingIterator<T>& a, const NonThrowingIterator<T>& b) TEST_NOEXCEPT
+{ return a.operator==(b); }
+
+template <typename T>
+bool operator!= (const NonThrowingIterator<T>& a, const NonThrowingIterator<T>& b) TEST_NOEXCEPT
+{ return !a.operator==(b); }
+
#undef DELETE_FUNCTION
#endif // ITERATORS_H