Added more exception safety to Deque::grow

This commit is contained in:
sfc-gh-tclinkenbeard 2020-07-13 18:29:12 -07:00
parent da28face2c
commit d6b6626a2b
2 changed files with 45 additions and 1 deletions

View File

@ -79,4 +79,41 @@ TEST_CASE("/flow/Deque/max_size") {
return Void();
}
struct RandomlyThrows {
int data = 0;
RandomlyThrows() = default;
explicit RandomlyThrows(int data) : data(data) {}
~RandomlyThrows() = default;
RandomlyThrows(const RandomlyThrows& other) : data(other.data) { randomlyThrow(); }
RandomlyThrows& operator=(const RandomlyThrows& other) {
data = other.data;
randomlyThrow();
return *this;
}
private:
void randomlyThrow() {
if (deterministicRandom()->random01() < 0.1) {
throw success();
}
}
};
TEST_CASE("/flow/Deque/grow_exception_safety") {
Deque<RandomlyThrows> q;
for (int i = 0; i < 100; ++i) {
loop {
try {
q.push_back(RandomlyThrows{ i });
break;
} catch (Error& e) {
}
}
}
for (int i = 0; i < 100; ++i) {
ASSERT(q[i].data == i);
}
return Void();
}
void forceLinkDequeTests() {}

View File

@ -170,8 +170,15 @@ private:
T* newArr = (T*)aligned_alloc(std::max(__alignof(T), sizeof(void*)),
newSize * sizeof(T)); // SOMEDAY: FastAllocator
ASSERT(newArr != nullptr);
try {
for (int i = begin; i != end; i++) {
new (&newArr[i - begin]) T(std::move_if_noexcept(arr[i & mask]));
}
} catch (...) {
aligned_free(newArr);
throw;
}
for (int i = begin; i != end; i++) {
new (&newArr[i - begin]) T(std::move_if_noexcept(arr[i & mask]));
static_assert(std::is_nothrow_destructible_v<T>);
arr[i&mask].~T();
}