[libcxx-commits] [libcxx] [libc++][test] Fix and refactor exception tests for std::vector (PR #117641)
Peng Liu via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Nov 25 19:16:20 PST 2024
https://github.com/winner245 updated https://github.com/llvm/llvm-project/pull/117641
>From 4e6225241c997532f099c5fc5cb22fedd615719f Mon Sep 17 00:00:00 2001
From: Peng Liu <winner245 at hotmail.com>
Date: Mon, 25 Nov 2024 17:58:06 -0500
Subject: [PATCH] Fix and refactor exception tests for std::vector
---
.../vector/vector.cons/exceptions.pass.cpp | 146 +++++-------------
libcxx/test/support/exception_test_helpers.h | 119 ++++++++++++++
2 files changed, 154 insertions(+), 111 deletions(-)
create mode 100644 libcxx/test/support/exception_test_helpers.h
diff --git a/libcxx/test/std/containers/sequences/vector/vector.cons/exceptions.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/exceptions.pass.cpp
index e2b0d691889c6c..82768947986a27 100644
--- a/libcxx/test/std/containers/sequences/vector/vector.cons/exceptions.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector/vector.cons/exceptions.pass.cpp
@@ -17,94 +17,12 @@
#include <vector>
#include "count_new.h"
+#include "exception_test_helpers.h"
+#include "test_allocator.h"
#include "test_iterators.h"
-template <class T>
-struct Allocator {
- using value_type = T;
- using is_always_equal = std::false_type;
-
- template <class U>
- Allocator(const Allocator<U>&) {}
-
- Allocator(bool should_throw = true) {
- if (should_throw)
- throw 0;
- }
-
- T* allocate(std::size_t n) { return std::allocator<T>().allocate(n); }
- void deallocate(T* ptr, std::size_t n) { std::allocator<T>().deallocate(ptr, n); }
-
- template <class U>
- friend bool operator==(const Allocator&, const Allocator<U>&) { return true; }
-};
-
-struct ThrowingT {
- int* throw_after_n_ = nullptr;
- ThrowingT() { throw 0; }
-
- ThrowingT(int& throw_after_n) : throw_after_n_(&throw_after_n) {
- if (throw_after_n == 0)
- throw 0;
- --throw_after_n;
- }
-
- ThrowingT(const ThrowingT& rhs) : throw_after_n_(rhs.throw_after_n_) {
- if (throw_after_n_ == nullptr || *throw_after_n_ == 0)
- throw 1;
- --*throw_after_n_;
- }
-
- ThrowingT& operator=(const ThrowingT& rhs) {
- throw_after_n_ = rhs.throw_after_n_;
- if (throw_after_n_ == nullptr || *throw_after_n_ == 0)
- throw 1;
- --*throw_after_n_;
- return *this;
- }
-};
-
-template <class IterCat>
-struct Iterator {
- using iterator_category = IterCat;
- using difference_type = std::ptrdiff_t;
- using value_type = int;
- using reference = int&;
- using pointer = int*;
-
- int i_;
- Iterator(int i = 0) : i_(i) {}
- int& operator*() {
- if (i_ == 1)
- throw 1;
- return i_;
- }
-
- friend bool operator==(const Iterator& lhs, const Iterator& rhs) { return lhs.i_ == rhs.i_; }
-
- friend bool operator!=(const Iterator& lhs, const Iterator& rhs) { return lhs.i_ != rhs.i_; }
-
- Iterator& operator++() {
- ++i_;
- return *this;
- }
-
- Iterator operator++(int) {
- auto tmp = *this;
- ++i_;
- return tmp;
- }
-};
-
-void check_new_delete_called() {
- assert(globalMemCounter.new_called == globalMemCounter.delete_called);
- assert(globalMemCounter.new_array_called == globalMemCounter.delete_array_called);
- assert(globalMemCounter.aligned_new_called == globalMemCounter.aligned_delete_called);
- assert(globalMemCounter.aligned_new_array_called == globalMemCounter.aligned_delete_array_called);
-}
-
int main(int, char**) {
- using AllocVec = std::vector<int, Allocator<int> >;
+ using AllocVec = std::vector<int, throwing_allocator<int> >;
try { // vector()
AllocVec vec;
} catch (int) {
@@ -112,7 +30,7 @@ int main(int, char**) {
check_new_delete_called();
try { // Throw in vector(size_type) from type
- std::vector<ThrowingT> get_alloc(1);
+ std::vector<throwing_t> get_alloc(1);
} catch (int) {
}
check_new_delete_called();
@@ -120,42 +38,44 @@ int main(int, char**) {
#if TEST_STD_VER >= 14
try { // Throw in vector(size_type, value_type) from type
int throw_after = 1;
- ThrowingT v(throw_after);
- std::vector<ThrowingT> get_alloc(1, v);
+ throwing_t v(throw_after);
+ std::vector<throwing_t> get_alloc(1, v);
} catch (int) {
}
check_new_delete_called();
- try { // Throw in vector(size_type, const allocator_type&) from allocator
- Allocator<int> alloc(false);
+ try { // Throw in vector(size_type, const allocator_type&) from allocator
+ throwing_allocator<int> alloc(false, true); // throw on copy only
AllocVec get_alloc(0, alloc);
} catch (int) {
}
check_new_delete_called();
try { // Throw in vector(size_type, const allocator_type&) from the type
- std::vector<ThrowingT> vec(1, std::allocator<ThrowingT>());
+ std::vector<throwing_t> vec(1, std::allocator<throwing_t>());
} catch (int) {
}
check_new_delete_called();
-#endif // TEST_STD_VER >= 14
+#endif // TEST_STD_VER >= 14
try { // Throw in vector(size_type, value_type, const allocator_type&) from the type
int throw_after = 1;
- ThrowingT v(throw_after);
- std::vector<ThrowingT> vec(1, v, std::allocator<ThrowingT>());
+ throwing_t v(throw_after);
+ std::vector<throwing_t> vec(1, v, std::allocator<throwing_t>());
} catch (int) {
}
check_new_delete_called();
try { // Throw in vector(InputIterator, InputIterator) from input iterator
- std::vector<int> vec((Iterator<std::input_iterator_tag>()), Iterator<std::input_iterator_tag>(2));
+ std::vector<int> vec(
+ (throwing_iterator<int, std::input_iterator_tag>()), throwing_iterator<int, std::input_iterator_tag>(2));
} catch (int) {
}
check_new_delete_called();
try { // Throw in vector(InputIterator, InputIterator) from forward iterator
- std::vector<int> vec((Iterator<std::forward_iterator_tag>()), Iterator<std::forward_iterator_tag>(2));
+ std::vector<int> vec(
+ (throwing_iterator<int, std::forward_iterator_tag>()), throwing_iterator<int, std::forward_iterator_tag>(2));
} catch (int) {
}
check_new_delete_called();
@@ -169,21 +89,24 @@ int main(int, char**) {
try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from input iterator
std::allocator<int> alloc;
- std::vector<int> vec(Iterator<std::input_iterator_tag>(), Iterator<std::input_iterator_tag>(2), alloc);
+ std::vector<int> vec(
+ throwing_iterator<int, std::input_iterator_tag>(), throwing_iterator<int, std::input_iterator_tag>(2), alloc);
} catch (int) {
}
check_new_delete_called();
try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from forward iterator
std::allocator<int> alloc;
- std::vector<int> vec(Iterator<std::forward_iterator_tag>(), Iterator<std::forward_iterator_tag>(2), alloc);
+ std::vector<int> vec(throwing_iterator<int, std::forward_iterator_tag>(),
+ throwing_iterator<int, std::forward_iterator_tag>(2),
+ alloc);
} catch (int) {
}
check_new_delete_called();
try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from allocator
int a[] = {1, 2};
- Allocator<int> alloc(false);
+ throwing_allocator<int> alloc(false, true); // throw on copy only
AllocVec vec(cpp17_input_iterator<int*>(a), cpp17_input_iterator<int*>(a + 2), alloc);
} catch (int) {
// FIXME: never called.
@@ -192,7 +115,7 @@ int main(int, char**) {
try { // Throw in vector(InputIterator, InputIterator, const allocator_type&) from allocator
int a[] = {1, 2};
- Allocator<int> alloc(false);
+ throwing_allocator<int> alloc(false, true); // throw on copy only
AllocVec vec(forward_iterator<int*>(a), forward_iterator<int*>(a + 2), alloc);
} catch (int) {
// FIXME: never called.
@@ -200,8 +123,8 @@ int main(int, char**) {
check_new_delete_called();
try { // Throw in vector(const vector&) from type
- std::vector<ThrowingT> vec;
- int throw_after = 0;
+ std::vector<throwing_t> vec;
+ int throw_after = 1;
vec.emplace_back(throw_after);
auto vec2 = vec;
} catch (int) {
@@ -209,19 +132,20 @@ int main(int, char**) {
check_new_delete_called();
try { // Throw in vector(const vector&, const allocator_type&) from type
- std::vector<ThrowingT> vec;
+ std::vector<throwing_t> vec;
int throw_after = 1;
vec.emplace_back(throw_after);
- std::vector<ThrowingT> vec2(vec, std::allocator<int>());
+ std::vector<throwing_t> vec2(vec, std::allocator<int>());
} catch (int) {
}
check_new_delete_called();
- try { // Throw in vector(vector&&, const allocator_type&) from type
- std::vector<ThrowingT, Allocator<ThrowingT> > vec(Allocator<ThrowingT>(false));
- int throw_after = 1;
- vec.emplace_back(throw_after);
- std::vector<ThrowingT, Allocator<ThrowingT> > vec2(std::move(vec), Allocator<ThrowingT>(false));
+ try { // Throw in vector(vector&&, const allocator_type&) from type during element-wise move
+ std::vector<throwing_t, test_allocator<throwing_t> > vec(test_allocator<throwing_t>(1));
+ int throw_after = 10;
+ throwing_t v(throw_after);
+ vec.insert(vec.end(), 6, v);
+ std::vector<throwing_t, test_allocator<throwing_t> > vec2(std::move(vec), test_allocator<throwing_t>(2));
} catch (int) {
}
check_new_delete_called();
@@ -229,14 +153,14 @@ int main(int, char**) {
#if TEST_STD_VER >= 11
try { // Throw in vector(initializer_list<value_type>) from type
int throw_after = 1;
- std::vector<ThrowingT> vec({ThrowingT(throw_after)});
+ std::vector<throwing_t> vec({throwing_t(throw_after)});
} catch (int) {
}
check_new_delete_called();
try { // Throw in vector(initializer_list<value_type>, const allocator_type&) constructor from type
int throw_after = 1;
- std::vector<ThrowingT> vec({ThrowingT(throw_after)}, std::allocator<ThrowingT>());
+ std::vector<throwing_t> vec({throwing_t(throw_after)}, std::allocator<throwing_t>());
} catch (int) {
}
check_new_delete_called();
diff --git a/libcxx/test/support/exception_test_helpers.h b/libcxx/test/support/exception_test_helpers.h
new file mode 100644
index 00000000000000..b7c2e49a5f7dba
--- /dev/null
+++ b/libcxx/test/support/exception_test_helpers.h
@@ -0,0 +1,119 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef EXCEPTION_TEST_HELPERS_H
+#define EXCEPTION_TEST_HELPERS_H
+
+#include "count_new.h"
+
+struct throwing_t {
+ int* throw_after_n_ = nullptr;
+ throwing_t() { throw 0; }
+
+ throwing_t(int& throw_after_n) : throw_after_n_(&throw_after_n) {
+ if (throw_after_n == 0)
+ throw 0;
+ --throw_after_n;
+ }
+
+ throwing_t(const throwing_t& rhs) : throw_after_n_(rhs.throw_after_n_) {
+ if (throw_after_n_ == nullptr || *throw_after_n_ == 0)
+ throw 1;
+ --*throw_after_n_;
+ }
+
+ throwing_t& operator=(const throwing_t& rhs) {
+ throw_after_n_ = rhs.throw_after_n_;
+ if (throw_after_n_ == nullptr || *throw_after_n_ == 0)
+ throw 1;
+ --*throw_after_n_;
+ return *this;
+ }
+
+ friend bool operator==(const throwing_t& lhs, const throwing_t& rhs) {
+ return lhs.throw_after_n_ == rhs.throw_after_n_;
+ }
+ friend bool operator!=(const throwing_t& lhs, const throwing_t& rhs) {
+ return lhs.throw_after_n_ != rhs.throw_after_n_;
+ }
+};
+
+template <class T>
+struct throwing_allocator {
+ using value_type = T;
+ using is_always_equal = std::false_type;
+
+ bool throw_on_copy_ = false;
+
+ throwing_allocator(bool throw_on_ctor = true, bool throw_on_copy = false) : throw_on_copy_(throw_on_copy) {
+ if (throw_on_ctor)
+ throw 0;
+ }
+
+ throwing_allocator(const throwing_allocator& rhs) : throw_on_copy_(rhs.throw_on_copy_) {
+ if (throw_on_copy_)
+ throw 0;
+ }
+
+ template <class U>
+ throwing_allocator(const throwing_allocator<U>& rhs) : throw_on_copy_(rhs.throw_on_copy_) {
+ if (throw_on_copy_)
+ throw 0;
+ }
+
+ T* allocate(std::size_t n) { return std::allocator<T>().allocate(n); }
+ void deallocate(T* ptr, std::size_t n) { std::allocator<T>().deallocate(ptr, n); }
+
+ template <class U>
+ friend bool operator==(const throwing_allocator&, const throwing_allocator<U>&) {
+ return true;
+ }
+};
+
+template <class T, class IterCat>
+struct throwing_iterator {
+ using iterator_category = IterCat;
+ using difference_type = std::ptrdiff_t;
+ using value_type = T;
+ using reference = T&;
+ using pointer = T*;
+
+ int i_;
+ T v_;
+
+ throwing_iterator(int i = 0, const T& v = T()) : i_(i), v_(v) {}
+
+ reference operator*() {
+ if (i_ == 1)
+ throw 1;
+ return v_;
+ }
+
+ friend bool operator==(const throwing_iterator& lhs, const throwing_iterator& rhs) { return lhs.i_ == rhs.i_; }
+ friend bool operator!=(const throwing_iterator& lhs, const throwing_iterator& rhs) { return lhs.i_ != rhs.i_; }
+
+ throwing_iterator& operator++() {
+ ++i_;
+ return *this;
+ }
+
+ throwing_iterator operator++(int) {
+ auto tmp = *this;
+ ++i_;
+ return tmp;
+ }
+};
+
+inline void check_new_delete_called() {
+ assert(globalMemCounter.new_called == globalMemCounter.delete_called);
+ assert(globalMemCounter.new_array_called == globalMemCounter.delete_array_called);
+ assert(globalMemCounter.aligned_new_called == globalMemCounter.aligned_delete_called);
+ assert(globalMemCounter.aligned_new_array_called == globalMemCounter.aligned_delete_array_called);
+}
+
+#endif // EXCEPTION_TEST_HELPERS_H
\ No newline at end of file
More information about the libcxx-commits
mailing list