[SmallVector] Move error handling out of line

This reduces duplication and avoids emitting ice cold code into every
instance of grow().
This commit is contained in:
Benjamin Kramer 2020-09-06 18:05:24 +02:00
parent ecac5c2808
commit 8c386c9474
2 changed files with 43 additions and 44 deletions

View File

@ -32,9 +32,6 @@
#include <new> #include <new>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#ifdef LLVM_ENABLE_EXCEPTIONS
#include <stdexcept>
#endif
namespace llvm { namespace llvm {
@ -65,6 +62,13 @@ protected:
/// This function will report a fatal error if it cannot increase capacity. /// This function will report a fatal error if it cannot increase capacity.
void grow_pod(void *FirstEl, size_t MinSize, size_t TSize); void grow_pod(void *FirstEl, size_t MinSize, size_t TSize);
/// Report that MinSize doesn't fit into this vector's size type. Throws
/// std::length_error or calls report_fatal_error.
LLVM_ATTRIBUTE_NORETURN static void report_size_overflow(size_t MinSize);
/// Report that this vector is already at maximum capacity. Throws
/// std::length_error or calls report_fatal_error.
LLVM_ATTRIBUTE_NORETURN static void report_at_maximum_capacity();
public: public:
size_t size() const { return Size; } size_t size() const { return Size; }
size_t capacity() const { return Capacity; } size_t capacity() const { return Capacity; }
@ -271,32 +275,16 @@ template <typename T, bool TriviallyCopyable>
void SmallVectorTemplateBase<T, TriviallyCopyable>::grow(size_t MinSize) { void SmallVectorTemplateBase<T, TriviallyCopyable>::grow(size_t MinSize) {
// Ensure we can fit the new capacity. // Ensure we can fit the new capacity.
// This is only going to be applicable when the capacity is 32 bit. // This is only going to be applicable when the capacity is 32 bit.
if (MinSize > this->SizeTypeMax()) { if (MinSize > this->SizeTypeMax())
std::string Reason = "SmallVector unable to grow. Requested capacity (" + this->report_size_overflow(MinSize);
std::to_string(MinSize) +
") is larger than maximum value for size type (" +
std::to_string(this->SizeTypeMax()) + ")";
#ifdef LLVM_ENABLE_EXCEPTIONS
throw std::length_error(Reason);
#else
report_fatal_error(Reason);
#endif
}
// Ensure we can meet the guarantee of space for at least one more element. // Ensure we can meet the guarantee of space for at least one more element.
// The above check alone will not catch the case where grow is called with a // The above check alone will not catch the case where grow is called with a
// default MinSize of 0, but the current capacity cannot be increased. // default MinSize of 0, but the current capacity cannot be increased.
// This is only going to be applicable when the capacity is 32 bit. // This is only going to be applicable when the capacity is 32 bit.
if (this->capacity() == this->SizeTypeMax()) { if (this->capacity() == this->SizeTypeMax())
std::string Reason = this->report_at_maximum_capacity();
"SmallVector capacity unable to grow. Already at maximum size " +
std::to_string(this->SizeTypeMax());
#ifdef LLVM_ENABLE_EXCEPTIONS
throw std::length_error(Reason);
#else
report_fatal_error(Reason);
#endif
}
// Always grow, even from zero. // Always grow, even from zero.
size_t NewCapacity = size_t(NextPowerOf2(this->capacity() + 2)); size_t NewCapacity = size_t(NextPowerOf2(this->capacity() + 2));
NewCapacity = std::min(std::max(NewCapacity, MinSize), this->SizeTypeMax()); NewCapacity = std::min(std::max(NewCapacity, MinSize), this->SizeTypeMax());

View File

@ -12,6 +12,9 @@
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallVector.h"
#include <cstdint> #include <cstdint>
#ifdef LLVM_ENABLE_EXCEPTIONS
#include <stdexcept>
#endif
using namespace llvm; using namespace llvm;
// Check that no bytes are wasted and everything is well-aligned. // Check that no bytes are wasted and everything is well-aligned.
@ -42,37 +45,45 @@ static_assert(sizeof(SmallVector<char, 0>) ==
sizeof(void *) * 2 + sizeof(void *), sizeof(void *) * 2 + sizeof(void *),
"1 byte elements have word-sized type for size and capacity"); "1 byte elements have word-sized type for size and capacity");
template <class Size_T>
void SmallVectorBase<Size_T>::report_size_overflow(size_t MinSize) {
std::string Reason = "SmallVector unable to grow. Requested capacity (" +
std::to_string(MinSize) +
") is larger than maximum value for size type (" +
std::to_string(SizeTypeMax()) + ")";
#ifdef LLVM_ENABLE_EXCEPTIONS
throw std::length_error(Reason);
#else
report_fatal_error(Reason);
#endif
}
template <class Size_T> void SmallVectorBase<Size_T>::report_at_maximum_capacity() {
std::string Reason =
"SmallVector capacity unable to grow. Already at maximum size " +
std::to_string(SizeTypeMax());
#ifdef LLVM_ENABLE_EXCEPTIONS
throw std::length_error(Reason);
#else
report_fatal_error(Reason);
#endif
}
// Note: Moving this function into the header may cause performance regression. // Note: Moving this function into the header may cause performance regression.
template <class Size_T> template <class Size_T>
void SmallVectorBase<Size_T>::grow_pod(void *FirstEl, size_t MinSize, void SmallVectorBase<Size_T>::grow_pod(void *FirstEl, size_t MinSize,
size_t TSize) { size_t TSize) {
// Ensure we can fit the new capacity. // Ensure we can fit the new capacity.
// This is only going to be applicable when the capacity is 32 bit. // This is only going to be applicable when the capacity is 32 bit.
if (MinSize > SizeTypeMax()) { if (MinSize > SizeTypeMax())
std::string Reason = "SmallVector unable to grow. Requested capacity (" + report_size_overflow(MinSize);
std::to_string(MinSize) +
") is larger than maximum value for size type (" +
std::to_string(SizeTypeMax()) + ")";
#ifdef LLVM_ENABLE_EXCEPTIONS
throw std::length_error(Reason);
#else
report_fatal_error(Reason);
#endif
}
// Ensure we can meet the guarantee of space for at least one more element. // Ensure we can meet the guarantee of space for at least one more element.
// The above check alone will not catch the case where grow is called with a // The above check alone will not catch the case where grow is called with a
// default MinSize of 0, but the current capacity cannot be increased. // default MinSize of 0, but the current capacity cannot be increased.
// This is only going to be applicable when the capacity is 32 bit. // This is only going to be applicable when the capacity is 32 bit.
if (capacity() == SizeTypeMax()) { if (capacity() == SizeTypeMax())
std::string Reason = report_at_maximum_capacity();
"SmallVector capacity unable to grow. Already at maximum size " +
std::to_string(SizeTypeMax());
#ifdef LLVM_ENABLE_EXCEPTIONS
throw std::length_error(Reason);
#endif
report_fatal_error(Reason);
}
// In theory 2*capacity can overflow if the capacity is 64 bit, but the // In theory 2*capacity can overflow if the capacity is 64 bit, but the
// original capacity would never be large enough for this to be a problem. // original capacity would never be large enough for this to be a problem.