1 // Copyright 2019 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "absl/base/config.h"
16 #include "absl/container/fixed_array.h"
17
18 #ifdef ABSL_HAVE_EXCEPTIONS
19
20 #include <initializer_list>
21
22 #include "gtest/gtest.h"
23 #include "absl/base/internal/exception_safety_testing.h"
24
25 namespace absl {
26 ABSL_NAMESPACE_BEGIN
27
28 namespace {
29
30 constexpr size_t kInlined = 25;
31 constexpr size_t kSmallSize = kInlined / 2;
32 constexpr size_t kLargeSize = kInlined * 2;
33
34 constexpr int kInitialValue = 5;
35 constexpr int kUpdatedValue = 10;
36
37 using ::testing::TestThrowingCtor;
38
39 using Thrower = testing::ThrowingValue<testing::TypeSpec::kEverythingThrows>;
40 using ThrowAlloc =
41 testing::ThrowingAllocator<Thrower, testing::AllocSpec::kEverythingThrows>;
42 using MoveThrower = testing::ThrowingValue<testing::TypeSpec::kNoThrowMove>;
43 using MoveThrowAlloc =
44 testing::ThrowingAllocator<MoveThrower,
45 testing::AllocSpec::kEverythingThrows>;
46
47 using FixedArr = absl::FixedArray<Thrower, kInlined>;
48 using FixedArrWithAlloc = absl::FixedArray<Thrower, kInlined, ThrowAlloc>;
49
50 using MoveFixedArr = absl::FixedArray<MoveThrower, kInlined>;
51 using MoveFixedArrWithAlloc =
52 absl::FixedArray<MoveThrower, kInlined, MoveThrowAlloc>;
53
TEST(FixedArrayExceptionSafety,CopyConstructor)54 TEST(FixedArrayExceptionSafety, CopyConstructor) {
55 auto small = FixedArr(kSmallSize);
56 TestThrowingCtor<FixedArr>(small);
57
58 auto large = FixedArr(kLargeSize);
59 TestThrowingCtor<FixedArr>(large);
60 }
61
TEST(FixedArrayExceptionSafety,CopyConstructorWithAlloc)62 TEST(FixedArrayExceptionSafety, CopyConstructorWithAlloc) {
63 auto small = FixedArrWithAlloc(kSmallSize);
64 TestThrowingCtor<FixedArrWithAlloc>(small);
65
66 auto large = FixedArrWithAlloc(kLargeSize);
67 TestThrowingCtor<FixedArrWithAlloc>(large);
68 }
69
TEST(FixedArrayExceptionSafety,MoveConstructor)70 TEST(FixedArrayExceptionSafety, MoveConstructor) {
71 TestThrowingCtor<FixedArr>(FixedArr(kSmallSize));
72 TestThrowingCtor<FixedArr>(FixedArr(kLargeSize));
73
74 // TypeSpec::kNoThrowMove
75 TestThrowingCtor<MoveFixedArr>(MoveFixedArr(kSmallSize));
76 TestThrowingCtor<MoveFixedArr>(MoveFixedArr(kLargeSize));
77 }
78
TEST(FixedArrayExceptionSafety,MoveConstructorWithAlloc)79 TEST(FixedArrayExceptionSafety, MoveConstructorWithAlloc) {
80 TestThrowingCtor<FixedArrWithAlloc>(FixedArrWithAlloc(kSmallSize));
81 TestThrowingCtor<FixedArrWithAlloc>(FixedArrWithAlloc(kLargeSize));
82
83 // TypeSpec::kNoThrowMove
84 TestThrowingCtor<MoveFixedArrWithAlloc>(MoveFixedArrWithAlloc(kSmallSize));
85 TestThrowingCtor<MoveFixedArrWithAlloc>(MoveFixedArrWithAlloc(kLargeSize));
86 }
87
TEST(FixedArrayExceptionSafety,SizeConstructor)88 TEST(FixedArrayExceptionSafety, SizeConstructor) {
89 TestThrowingCtor<FixedArr>(kSmallSize);
90 TestThrowingCtor<FixedArr>(kLargeSize);
91 }
92
TEST(FixedArrayExceptionSafety,SizeConstructorWithAlloc)93 TEST(FixedArrayExceptionSafety, SizeConstructorWithAlloc) {
94 TestThrowingCtor<FixedArrWithAlloc>(kSmallSize);
95 TestThrowingCtor<FixedArrWithAlloc>(kLargeSize);
96 }
97
TEST(FixedArrayExceptionSafety,SizeValueConstructor)98 TEST(FixedArrayExceptionSafety, SizeValueConstructor) {
99 TestThrowingCtor<FixedArr>(kSmallSize, Thrower());
100 TestThrowingCtor<FixedArr>(kLargeSize, Thrower());
101 }
102
TEST(FixedArrayExceptionSafety,SizeValueConstructorWithAlloc)103 TEST(FixedArrayExceptionSafety, SizeValueConstructorWithAlloc) {
104 TestThrowingCtor<FixedArrWithAlloc>(kSmallSize, Thrower());
105 TestThrowingCtor<FixedArrWithAlloc>(kLargeSize, Thrower());
106 }
107
TEST(FixedArrayExceptionSafety,IteratorConstructor)108 TEST(FixedArrayExceptionSafety, IteratorConstructor) {
109 auto small = FixedArr(kSmallSize);
110 TestThrowingCtor<FixedArr>(small.begin(), small.end());
111
112 auto large = FixedArr(kLargeSize);
113 TestThrowingCtor<FixedArr>(large.begin(), large.end());
114 }
115
TEST(FixedArrayExceptionSafety,IteratorConstructorWithAlloc)116 TEST(FixedArrayExceptionSafety, IteratorConstructorWithAlloc) {
117 auto small = FixedArrWithAlloc(kSmallSize);
118 TestThrowingCtor<FixedArrWithAlloc>(small.begin(), small.end());
119
120 auto large = FixedArrWithAlloc(kLargeSize);
121 TestThrowingCtor<FixedArrWithAlloc>(large.begin(), large.end());
122 }
123
TEST(FixedArrayExceptionSafety,InitListConstructor)124 TEST(FixedArrayExceptionSafety, InitListConstructor) {
125 constexpr int small_inlined = 3;
126 using SmallFixedArr = absl::FixedArray<Thrower, small_inlined>;
127
128 TestThrowingCtor<SmallFixedArr>(std::initializer_list<Thrower>{});
129 // Test inlined allocation
130 TestThrowingCtor<SmallFixedArr>(
131 std::initializer_list<Thrower>{Thrower{}, Thrower{}});
132 // Test out of line allocation
133 TestThrowingCtor<SmallFixedArr>(std::initializer_list<Thrower>{
134 Thrower{}, Thrower{}, Thrower{}, Thrower{}, Thrower{}});
135 }
136
TEST(FixedArrayExceptionSafety,InitListConstructorWithAlloc)137 TEST(FixedArrayExceptionSafety, InitListConstructorWithAlloc) {
138 constexpr int small_inlined = 3;
139 using SmallFixedArrWithAlloc =
140 absl::FixedArray<Thrower, small_inlined, ThrowAlloc>;
141
142 TestThrowingCtor<SmallFixedArrWithAlloc>(std::initializer_list<Thrower>{});
143 // Test inlined allocation
144 TestThrowingCtor<SmallFixedArrWithAlloc>(
145 std::initializer_list<Thrower>{Thrower{}, Thrower{}});
146 // Test out of line allocation
147 TestThrowingCtor<SmallFixedArrWithAlloc>(std::initializer_list<Thrower>{
148 Thrower{}, Thrower{}, Thrower{}, Thrower{}, Thrower{}});
149 }
150
151 template <typename FixedArrT>
ReadMemory(FixedArrT * fixed_arr)152 testing::AssertionResult ReadMemory(FixedArrT* fixed_arr) {
153 int sum = 0;
154 for (const auto& thrower : *fixed_arr) {
155 sum += thrower.Get();
156 }
157 return testing::AssertionSuccess() << "Values sum to [" << sum << "]";
158 }
159
TEST(FixedArrayExceptionSafety,Fill)160 TEST(FixedArrayExceptionSafety, Fill) {
161 auto test_fill = testing::MakeExceptionSafetyTester()
162 .WithContracts(ReadMemory<FixedArr>)
163 .WithOperation([&](FixedArr* fixed_arr_ptr) {
164 auto thrower =
165 Thrower(kUpdatedValue, testing::nothrow_ctor);
166 fixed_arr_ptr->fill(thrower);
167 });
168
169 EXPECT_TRUE(
170 test_fill.WithInitialValue(FixedArr(kSmallSize, Thrower(kInitialValue)))
171 .Test());
172 EXPECT_TRUE(
173 test_fill.WithInitialValue(FixedArr(kLargeSize, Thrower(kInitialValue)))
174 .Test());
175 }
176
TEST(FixedArrayExceptionSafety,FillWithAlloc)177 TEST(FixedArrayExceptionSafety, FillWithAlloc) {
178 auto test_fill = testing::MakeExceptionSafetyTester()
179 .WithContracts(ReadMemory<FixedArrWithAlloc>)
180 .WithOperation([&](FixedArrWithAlloc* fixed_arr_ptr) {
181 auto thrower =
182 Thrower(kUpdatedValue, testing::nothrow_ctor);
183 fixed_arr_ptr->fill(thrower);
184 });
185
186 EXPECT_TRUE(test_fill
187 .WithInitialValue(
188 FixedArrWithAlloc(kSmallSize, Thrower(kInitialValue)))
189 .Test());
190 EXPECT_TRUE(test_fill
191 .WithInitialValue(
192 FixedArrWithAlloc(kLargeSize, Thrower(kInitialValue)))
193 .Test());
194 }
195
196 } // namespace
197
198 ABSL_NAMESPACE_END
199 } // namespace absl
200
201 #endif // ABSL_HAVE_EXCEPTIONS
202