Commit 948bc7b6 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

Support -fno-exceptions in folly/small_vector.h

Summary: [Folly] Support `-fno-exceptions` in `folly/small_vector.h`.

Reviewed By: ot

Differential Revision: D13499417

fbshipit-source-id: d1b50ff7f028203849888f42a44c9370986a7ac1
parent 94af6423
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#include <folly/FormatTraits.h> #include <folly/FormatTraits.h>
#include <folly/Likely.h> #include <folly/Likely.h>
#include <folly/Portability.h> #include <folly/Portability.h>
#include <folly/ScopeGuard.h>
#include <folly/Traits.h> #include <folly/Traits.h>
#include <folly/lang/Assume.h> #include <folly/lang/Assume.h>
#include <folly/lang/Exception.h> #include <folly/lang/Exception.h>
...@@ -113,17 +114,8 @@ moveObjectsRight(T* first, T* lastConstructed, T* realLast) { ...@@ -113,17 +114,8 @@ moveObjectsRight(T* first, T* lastConstructed, T* realLast) {
T* end = first - 1; // Past the end going backwards. T* end = first - 1; // Past the end going backwards.
T* out = realLast - 1; T* out = realLast - 1;
T* in = lastConstructed - 1; T* in = lastConstructed - 1;
try { {
for (; in != end && out >= lastConstructed; --in, --out) { auto rollback = makeGuard([&] {
new (out) T(std::move(*in));
}
for (; in != end; --in, --out) {
*out = std::move(*in);
}
for (; out >= lastConstructed; --out) {
new (out) T();
}
} catch (...) {
// We want to make sure the same stuff is uninitialized memory // We want to make sure the same stuff is uninitialized memory
// if we exit via an exception (this is to make sure we provide // if we exit via an exception (this is to make sure we provide
// the basic exception safety guarantee for insert functions). // the basic exception safety guarantee for insert functions).
...@@ -133,7 +125,17 @@ moveObjectsRight(T* first, T* lastConstructed, T* realLast) { ...@@ -133,7 +125,17 @@ moveObjectsRight(T* first, T* lastConstructed, T* realLast) {
for (auto it = out + 1; it != realLast; ++it) { for (auto it = out + 1; it != realLast; ++it) {
it->~T(); it->~T();
} }
throw; });
for (; in != end && out >= lastConstructed; --in, --out) {
new (out) T(std::move(*in));
}
for (; in != end; --in, --out) {
*out = std::move(*in);
}
for (; out >= lastConstructed; --out) {
new (out) T();
}
rollback.dismiss();
} }
} }
...@@ -155,16 +157,17 @@ moveObjectsRight(T* first, T* lastConstructed, T* realLast) { ...@@ -155,16 +157,17 @@ moveObjectsRight(T* first, T* lastConstructed, T* realLast) {
template <class T, class Function> template <class T, class Function>
void populateMemForward(T* mem, std::size_t n, Function const& op) { void populateMemForward(T* mem, std::size_t n, Function const& op) {
std::size_t idx = 0; std::size_t idx = 0;
try { {
auto rollback = makeGuard([&] {
for (std::size_t i = 0; i < idx; ++i) {
mem[i].~T();
}
});
for (size_t i = 0; i < n; ++i) { for (size_t i = 0; i < n; ++i) {
op(&mem[idx]); op(&mem[idx]);
++idx; ++idx;
} }
} catch (...) { rollback.dismiss();
for (std::size_t i = 0; i < idx; ++i) {
mem[i].~T();
}
throw;
} }
} }
...@@ -229,11 +232,8 @@ struct IntegralSizePolicy<SizeType, true> ...@@ -229,11 +232,8 @@ struct IntegralSizePolicy<SizeType, true>
typename std::enable_if<!folly::is_trivially_copyable<T>::value>::type typename std::enable_if<!folly::is_trivially_copyable<T>::value>::type
moveToUninitialized(T* first, T* last, T* out) { moveToUninitialized(T* first, T* last, T* out) {
std::size_t idx = 0; std::size_t idx = 0;
try { {
for (; first != last; ++first, ++idx) { auto rollback = makeGuard([&] {
new (&out[idx]) T(std::move(*first));
}
} catch (...) {
// Even for callers trying to give the strong guarantee // Even for callers trying to give the strong guarantee
// (e.g. push_back) it's ok to assume here that we don't have to // (e.g. push_back) it's ok to assume here that we don't have to
// move things back and that it was a copy constructor that // move things back and that it was a copy constructor that
...@@ -242,7 +242,11 @@ struct IntegralSizePolicy<SizeType, true> ...@@ -242,7 +242,11 @@ struct IntegralSizePolicy<SizeType, true>
for (std::size_t i = 0; i < idx; ++i) { for (std::size_t i = 0; i < idx; ++i) {
out[i].~T(); out[i].~T();
} }
throw; });
for (; first != last; ++first, ++idx) {
new (&out[idx]) T(std::move(*first));
}
rollback.dismiss();
} }
} }
...@@ -273,22 +277,24 @@ struct IntegralSizePolicy<SizeType, true> ...@@ -273,22 +277,24 @@ struct IntegralSizePolicy<SizeType, true>
// We have to support the strong exception guarantee for emplace_back(). // We have to support the strong exception guarantee for emplace_back().
emplaceFunc(out + pos); emplaceFunc(out + pos);
// move old elements to the left of the new one // move old elements to the left of the new one
try { {
this->moveToUninitialized(begin, begin + pos, out); auto rollback = makeGuard([&] { //
} catch (...) {
out[pos].~T(); out[pos].~T();
throw; });
this->moveToUninitialized(begin, begin + pos, out);
rollback.dismiss();
} }
// move old elements to the right of the new one // move old elements to the right of the new one
try { {
if (begin + pos < end) { auto rollback = makeGuard([&] {
this->moveToUninitialized(begin + pos, end, out + pos + 1);
}
} catch (...) {
for (SizeType i = 0; i <= pos; ++i) { for (SizeType i = 0; i <= pos; ++i) {
out[i].~T(); out[i].~T();
} }
throw; });
if (begin + pos < end) {
this->moveToUninitialized(begin + pos, end, out + pos + 1);
}
rollback.dismiss();
} }
} }
}; };
...@@ -444,13 +450,14 @@ class small_vector : public detail::small_vector_base< ...@@ -444,13 +450,14 @@ class small_vector : public detail::small_vector_base<
small_vector(small_vector const& o) { small_vector(small_vector const& o) {
auto n = o.size(); auto n = o.size();
makeSize(n); makeSize(n);
try { {
std::uninitialized_copy(o.begin(), o.end(), begin()); auto rollback = makeGuard([&] {
} catch (...) {
if (this->isExtern()) { if (this->isExtern()) {
u.freeHeap(); u.freeHeap();
} }
throw; });
std::uninitialized_copy(o.begin(), o.end(), begin());
rollback.dismiss();
} }
this->setSize(n); this->setSize(n);
} }
...@@ -612,19 +619,20 @@ class small_vector : public detail::small_vector_base< ...@@ -612,19 +619,20 @@ class small_vector : public detail::small_vector_base<
size_type i = oldSmall.size(); size_type i = oldSmall.size();
const size_type ci = i; const size_type ci = i;
try { {
auto rollback = makeGuard([&] {
oldSmall.setSize(i);
for (; i < oldLarge.size(); ++i) { for (; i < oldLarge.size(); ++i) {
auto addr = oldSmall.begin() + i;
new (addr) value_type(std::move(oldLarge[i]));
oldLarge[i].~value_type(); oldLarge[i].~value_type();
} }
} catch (...) { oldLarge.setSize(ci);
oldSmall.setSize(i); });
for (; i < oldLarge.size(); ++i) { for (; i < oldLarge.size(); ++i) {
auto addr = oldSmall.begin() + i;
new (addr) value_type(std::move(oldLarge[i]));
oldLarge[i].~value_type(); oldLarge[i].~value_type();
} }
oldLarge.setSize(ci); rollback.dismiss();
throw;
} }
oldSmall.setSize(i); oldSmall.setSize(i);
oldLarge.setSize(ci); oldLarge.setSize(ci);
...@@ -640,12 +648,8 @@ class small_vector : public detail::small_vector_base< ...@@ -640,12 +648,8 @@ class small_vector : public detail::small_vector_base<
auto buff = oldExtern.u.buffer(); auto buff = oldExtern.u.buffer();
size_type i = 0; size_type i = 0;
try { {
for (; i < oldIntern.size(); ++i) { auto rollback = makeGuard([&] {
new (&buff[i]) value_type(std::move(oldIntern[i]));
oldIntern[i].~value_type();
}
} catch (...) {
for (size_type kill = 0; kill < i; ++kill) { for (size_type kill = 0; kill < i; ++kill) {
buff[kill].~value_type(); buff[kill].~value_type();
} }
...@@ -655,7 +659,12 @@ class small_vector : public detail::small_vector_base< ...@@ -655,7 +659,12 @@ class small_vector : public detail::small_vector_base<
oldIntern.setSize(0); oldIntern.setSize(0);
oldExtern.u.pdata_.heap_ = oldExternHeap; oldExtern.u.pdata_.heap_ = oldExternHeap;
oldExtern.setCapacity(oldExternCapacity); oldExtern.setCapacity(oldExternCapacity);
throw; });
for (; i < oldIntern.size(); ++i) {
new (&buff[i]) value_type(std::move(oldIntern[i]));
oldIntern[i].~value_type();
}
rollback.dismiss();
} }
oldIntern.u.pdata_.heap_ = oldExternHeap; oldIntern.u.pdata_.heap_ = oldExternHeap;
this->swapSizePolicy(o); this->swapSizePolicy(o);
...@@ -955,14 +964,15 @@ class small_vector : public detail::small_vector_base< ...@@ -955,14 +964,15 @@ class small_vector : public detail::small_vector_base<
auto distance = std::distance(first, last); auto distance = std::distance(first, last);
makeSize(distance); makeSize(distance);
this->setSize(distance); this->setSize(distance);
try { {
detail::populateMemForward( auto rollback = makeGuard([&] {
data(), distance, [&](void* p) { new (p) value_type(*first++); });
} catch (...) {
if (this->isExtern()) { if (this->isExtern()) {
u.freeHeap(); u.freeHeap();
} }
throw; });
detail::populateMemForward(
data(), distance, [&](void* p) { new (p) value_type(*first++); });
rollback.dismiss();
} }
} }
...@@ -970,13 +980,14 @@ class small_vector : public detail::small_vector_base< ...@@ -970,13 +980,14 @@ class small_vector : public detail::small_vector_base<
void doConstruct(size_type n, InitFunc&& func) { void doConstruct(size_type n, InitFunc&& func) {
makeSize(n); makeSize(n);
this->setSize(n); this->setSize(n);
try { {
detail::populateMemForward(data(), n, std::forward<InitFunc>(func)); auto rollback = makeGuard([&] {
} catch (...) {
if (this->isExtern()) { if (this->isExtern()) {
u.freeHeap(); u.freeHeap();
} }
throw; });
detail::populateMemForward(data(), n, std::forward<InitFunc>(func));
rollback.dismiss();
} }
} }
...@@ -1021,7 +1032,7 @@ class small_vector : public detail::small_vector_base< ...@@ -1021,7 +1032,7 @@ class small_vector : public detail::small_vector_base<
EmplaceFunc&& emplaceFunc, EmplaceFunc&& emplaceFunc,
size_type pos) { size_type pos) {
if (newSize > max_size()) { if (newSize > max_size()) {
throw std::length_error("max_size exceeded in small_vector"); throw_exception<std::length_error>("max_size exceeded in small_vector");
} }
if (newSize <= capacity()) { if (newSize <= capacity()) {
assert(!insert); assert(!insert);
...@@ -1057,7 +1068,10 @@ class small_vector : public detail::small_vector_base< ...@@ -1057,7 +1068,10 @@ class small_vector : public detail::small_vector_base<
heapifyCapacity ? detail::shiftPointer(newh, kHeapifyCapacitySize) heapifyCapacity ? detail::shiftPointer(newh, kHeapifyCapacitySize)
: newh); : newh);
try { {
auto rollback = makeGuard([&] { //
free(newh);
});
if (insert) { if (insert) {
// move and insert the new element // move and insert the new element
this->moveToUninitializedEmplace( this->moveToUninitializedEmplace(
...@@ -1066,9 +1080,7 @@ class small_vector : public detail::small_vector_base< ...@@ -1066,9 +1080,7 @@ class small_vector : public detail::small_vector_base<
// move without inserting new element // move without inserting new element
this->moveToUninitialized(begin(), end(), newp); this->moveToUninitialized(begin(), end(), newp);
} }
} catch (...) { rollback.dismiss();
free(newh);
throw;
} }
for (auto& val : *this) { for (auto& val : *this) {
val.~value_type(); val.~value_type();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment