diff options
author | Marshall Clow <mclow.lists@gmail.com> | 2016-01-13 21:54:34 +0000 |
---|---|---|
committer | Marshall Clow <mclow.lists@gmail.com> | 2016-01-13 21:54:34 +0000 |
commit | 76b4afc04051298081c2f46056138b4013c2f49d (patch) | |
tree | d527130e26d84a126910890f17fb96cf750046ee /libcxx/test/support/test_iterators.h | |
parent | 183ebbe0eeab823594685eb57ebbbd5ee32eb2e1 (diff) | |
download | bcm5719-llvm-76b4afc04051298081c2f46056138b4013c2f49d.tar.gz bcm5719-llvm-76b4afc04051298081c2f46056138b4013c2f49d.zip |
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
llvm-svn: 257682
Diffstat (limited to 'libcxx/test/support/test_iterators.h')
-rw-r--r-- | libcxx/test/support/test_iterators.h | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h index e09fd834d21..d814879fa27 100644 --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/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 @@ inline Iter base(random_access_iterator<Iter> i) { return i.base(); } 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 |