[libcxx-commits] [libcxx] [libc++][test] Add exception tests for vector capacity operations (PR #118141)
Peng Liu via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Nov 29 14:48:58 PST 2024
https://github.com/winner245 created https://github.com/llvm/llvm-project/pull/118141
This PR provides comprehensive exceptions tests for capacity-related functions in `std::vector`, including `reserve`, 'resize', and `shrink_to_fit`. The tests are performed under various exception scenarios, validating the strong exception guarantees provided by these functions.
>From dc5cbdb77c178d1cd9c73318a39b123a0538b369 Mon Sep 17 00:00:00 2001
From: Peng Liu <winner245 at hotmail.com>
Date: Fri, 29 Nov 2024 17:38:31 -0500
Subject: [PATCH] Add exception tests for vector capacity operations
---
.../std/containers/sequences/vector/common.h | 46 ++++++
.../reserve_exceptions.pass.cpp | 144 ++++++++++++++++++
.../resize_exceptions.pass.cpp | 46 ++++++
.../shrink_to_fit_exceptions.pass.cpp | 46 ++++++
4 files changed, 282 insertions(+)
create mode 100644 libcxx/test/std/containers/sequences/vector/vector.capacity/reserve_exceptions.pass.cpp
create mode 100644 libcxx/test/std/containers/sequences/vector/vector.capacity/resize_exceptions.pass.cpp
create mode 100644 libcxx/test/std/containers/sequences/vector/vector.capacity/shrink_to_fit_exceptions.pass.cpp
diff --git a/libcxx/test/std/containers/sequences/vector/common.h b/libcxx/test/std/containers/sequences/vector/common.h
index e793ab2a21c1d0..14671a997a6ed7 100644
--- a/libcxx/test/std/containers/sequences/vector/common.h
+++ b/libcxx/test/std/containers/sequences/vector/common.h
@@ -16,6 +16,52 @@
#include "count_new.h"
+template <typename T>
+struct throwing_data {
+ T data_;
+ int* throw_after_n_ = nullptr;
+ throwing_data() { throw 0; }
+
+ throwing_data(const T& data, int& throw_after_n) : data_(data), throw_after_n_(&throw_after_n) {
+ if (throw_after_n == 0)
+ throw 0;
+ --throw_after_n;
+ }
+
+ throwing_data(const throwing_data& rhs) : data_(rhs.data_), throw_after_n_(rhs.throw_after_n_) {
+ if (throw_after_n_ == nullptr || *throw_after_n_ == 0)
+ throw 1;
+ --*throw_after_n_;
+ }
+
+ throwing_data& operator=(const throwing_data& rhs) {
+ data_ = rhs.data_;
+ throw_after_n_ = rhs.throw_after_n_;
+ if (throw_after_n_ == nullptr || *throw_after_n_ == 0)
+ throw 1;
+ --*throw_after_n_;
+ return *this;
+ }
+
+ throwing_data(throwing_data&& rhs) : data_(std::move(rhs.data_)), throw_after_n_(rhs.throw_after_n_) {
+ if (throw_after_n_ == nullptr || *throw_after_n_ == 0)
+ throw 1;
+ --*throw_after_n_;
+ }
+
+ throwing_data& operator=(throwing_data&& rhs) {
+ if (this == &rhs)
+ return *this;
+ data_ = std::move(rhs.data_);
+ throw_after_n_ = rhs.throw_after_n_;
+ rhs.throw_after_n_ = nullptr;
+ if (throw_after_n_ == nullptr || *throw_after_n_ == 0)
+ throw 1;
+ --*throw_after_n_;
+ return *this;
+ }
+};
+
template <class T>
struct throwing_allocator {
using value_type = T;
diff --git a/libcxx/test/std/containers/sequences/vector/vector.capacity/reserve_exceptions.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.capacity/reserve_exceptions.pass.cpp
new file mode 100644
index 00000000000000..be144b0d3fc34c
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/vector/vector.capacity/reserve_exceptions.pass.cpp
@@ -0,0 +1,144 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: no-exceptions
+
+// Check that std::vector::reserve provides strong exception guarantees
+
+#include <cstddef>
+#include <memory>
+#include <stdexcept>
+#include <type_traits>
+#include <vector>
+
+#include "../common.h"
+#include "count_new.h"
+#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_iterators.h"
+
+template <typename T = int, typename Alloc = std::allocator<T>>
+void test_allocation_exception(std::vector<T, Alloc>& v) {
+ std::vector<T, Alloc> old_vector = v;
+ T* old_data = v.data();
+ std::size_t old_size = v.size();
+ std::size_t old_cap = v.capacity();
+ std::size_t new_cap = v.max_size() + 1;
+ try {
+ v.reserve(new_cap);
+ } catch (std::length_error&) {
+ assert(v.size() == old_size);
+ assert(v.capacity() == old_cap);
+ assert(v.data() == old_data);
+ assert(v == old_vector);
+ }
+}
+
+template <typename T = int, typename Alloc = std::allocator<throwing_data<T>>>
+void test_construction_exception(std::vector<throwing_data<T>, Alloc>& v, const std::vector<T>& in) {
+ assert(v.empty() && !in.empty());
+ int throw_after = 2 * in.size() - 1;
+ v.reserve(in.size());
+ for (std::size_t i = 0; i < in.size(); ++i)
+ v.emplace_back(in[i], throw_after);
+
+ throwing_data<T>* old_data = v.data();
+ std::size_t old_size = v.size();
+ std::size_t old_cap = v.capacity();
+ std::size_t new_cap = 2 * old_cap;
+
+ try {
+ v.reserve(new_cap);
+ } catch (int) {
+ assert(v.size() == old_size);
+ assert(v.capacity() == old_cap);
+ assert(v.data() == old_data);
+ for (std::size_t i = 0; i < in.size(); ++i)
+ assert(v[i].data_ == in[i]);
+ }
+}
+
+void test_allocation_exceptions() {
+ {
+ std::vector<int> v;
+ test_allocation_exception(v);
+ }
+ check_new_delete_called();
+
+ {
+ std::vector<int> v(10, 42);
+ test_allocation_exception(v);
+ }
+ check_new_delete_called();
+
+ {
+ std::vector<int, min_allocator<int> > v(10, 42);
+ test_allocation_exception(v);
+ }
+ check_new_delete_called();
+
+ {
+ std::vector<int, safe_allocator<int> > v(10, 42);
+ test_allocation_exception(v);
+ }
+ check_new_delete_called();
+
+ {
+ std::vector<int, test_allocator<int> > v(10, 42);
+ test_allocation_exception(v);
+ }
+ check_new_delete_called();
+
+ {
+ std::vector<int, limited_allocator<int, 100> > v(10, 42);
+ test_allocation_exception(v);
+ }
+ check_new_delete_called();
+}
+
+void test_construction_exceptions() {
+ {
+ std::vector<throwing_data<int>> v;
+ std::vector<int> in = {1, 2, 3, 4, 5};
+ test_construction_exception(v, in);
+ }
+ check_new_delete_called();
+
+ {
+ std::vector<throwing_data<int>, min_allocator<throwing_data<int>>> v;
+ std::vector<int> in = {1, 2, 3, 4, 5};
+ test_construction_exception(v, in);
+ }
+ check_new_delete_called();
+
+ {
+ std::vector<throwing_data<int>, safe_allocator<throwing_data<int>> > v;
+ std::vector<int> in(10, 42);
+ test_construction_exception(v, in);
+ }
+ check_new_delete_called();
+
+ {
+ std::vector<throwing_data<int>, test_allocator<throwing_data<int>> > v;
+ std::vector<int> in(10, 42);
+ test_construction_exception(v, in);
+ }
+ check_new_delete_called();
+
+ {
+ std::vector<throwing_data<int>, limited_allocator<throwing_data<int>, 100> > v;
+ std::vector<int> in(10, 42);
+ test_construction_exception(v, in);
+ }
+ check_new_delete_called();
+}
+
+int main(int, char**) {
+ test_allocation_exceptions();
+ test_construction_exceptions();
+}
diff --git a/libcxx/test/std/containers/sequences/vector/vector.capacity/resize_exceptions.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.capacity/resize_exceptions.pass.cpp
new file mode 100644
index 00000000000000..3e0a624bf71944
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/vector/vector.capacity/resize_exceptions.pass.cpp
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: no-exceptions
+
+// Check that std::vector::resize provides strong exception guarantees
+
+#include <cstddef>
+#include <memory>
+#include <stdexcept>
+#include <type_traits>
+#include <vector>
+
+#include "../common.h"
+#include "count_new.h"
+#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_iterators.h"
+
+template <typename T = int, typename Alloc = std::allocator<T>>
+void test_allocation_exception(std::vector<T, Alloc>& v) {
+
+}
+
+template <typename T = int, typename Alloc = std::allocator<throwing_data<T>>>
+void test_construction_exception(std::vector<throwing_data<T>, Alloc>& v, const std::vector<T>& in) {
+
+}
+
+void test_allocation_exceptions() {
+
+}
+
+void test_construction_exceptions() {
+
+}
+
+int main(int, char**) {
+ test_allocation_exceptions();
+ test_construction_exceptions();
+}
diff --git a/libcxx/test/std/containers/sequences/vector/vector.capacity/shrink_to_fit_exceptions.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.capacity/shrink_to_fit_exceptions.pass.cpp
new file mode 100644
index 00000000000000..3cb1e47acc97f8
--- /dev/null
+++ b/libcxx/test/std/containers/sequences/vector/vector.capacity/shrink_to_fit_exceptions.pass.cpp
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: no-exceptions
+
+// Check that std::vector::shrink_to_fit provides strong exception guarantees
+
+#include <cstddef>
+#include <memory>
+#include <stdexcept>
+#include <type_traits>
+#include <vector>
+
+#include "../common.h"
+#include "count_new.h"
+#include "min_allocator.h"
+#include "test_allocator.h"
+#include "test_iterators.h"
+
+template <typename T = int, typename Alloc = std::allocator<T>>
+void test_allocation_exception(std::vector<T, Alloc>& v) {
+
+}
+
+template <typename T = int, typename Alloc = std::allocator<throwing_data<T>>>
+void test_construction_exception(std::vector<throwing_data<T>, Alloc>& v, const std::vector<T>& in) {
+
+}
+
+void test_allocation_exceptions() {
+
+}
+
+void test_construction_exceptions() {
+
+}
+
+int main(int, char**) {
+ test_allocation_exceptions();
+ test_construction_exceptions();
+}
More information about the libcxx-commits
mailing list