Merge pull request #3489 from sfc-gh-tclinkenbeard/dont-throw-deque-relocate
Add exception-safety to Deque::grow
This commit is contained in:
commit
18e53caf6e
|
@ -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() {}
|
||||
|
|
21
flow/Deque.h
21
flow/Deque.h
|
@ -168,10 +168,18 @@ private:
|
|||
if (newSize > max_size()) throw std::bad_alloc();
|
||||
//printf("Growing to %lld (%u-%u mask %u)\n", (long long)newSize, begin, end, mask);
|
||||
T* newArr = (T*)aligned_alloc(std::max(__alignof(T), sizeof(void*)),
|
||||
newSize * sizeof(T)); // SOMEDAY: FastAllocator, exception safety
|
||||
newSize * sizeof(T)); // SOMEDAY: FastAllocator
|
||||
ASSERT(newArr != nullptr);
|
||||
for (int i = begin; i != end; i++) {
|
||||
new (&newArr[i - begin]) T(std::move(arr[i&mask]));
|
||||
try {
|
||||
new (&newArr[i - begin]) T(std::move_if_noexcept(arr[i & mask]));
|
||||
} catch (...) {
|
||||
cleanup(newArr, i-begin);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
for (int i = begin; i != end; i++) {
|
||||
static_assert(std::is_nothrow_destructible_v<T>);
|
||||
arr[i&mask].~T();
|
||||
}
|
||||
aligned_free(arr);
|
||||
|
@ -181,7 +189,14 @@ private:
|
|||
mask = uint32_t(newSize - 1);
|
||||
}
|
||||
|
||||
void cleanup() {
|
||||
static void cleanup(T *data, size_t size) noexcept {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
data[i].~T();
|
||||
}
|
||||
aligned_free(data);
|
||||
}
|
||||
|
||||
void cleanup() noexcept {
|
||||
for (int i = begin; i != end; i++)
|
||||
arr[i&mask].~T();
|
||||
if(arr)
|
||||
|
|
Loading…
Reference in New Issue