summaryrefslogtreecommitdiffstats
path: root/libcxx/test/support/test_iterators.h
diff options
context:
space:
mode:
authorMarshall Clow <mclow.lists@gmail.com>2016-01-13 21:54:34 +0000
committerMarshall Clow <mclow.lists@gmail.com>2016-01-13 21:54:34 +0000
commit76b4afc04051298081c2f46056138b4013c2f49d (patch)
treed527130e26d84a126910890f17fb96cf750046ee /libcxx/test/support/test_iterators.h
parent183ebbe0eeab823594685eb57ebbbd5ee32eb2e1 (diff)
downloadbcm5719-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.h199
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
OpenPOWER on IntegriCloud