duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

SmallVector.cpp (8411B)


      1 //===- llvm/ADT/SmallVector.cpp - 'Normally small' vectors ----------------===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 //
      9 // This file implements the SmallVector class.
     10 //
     11 //===----------------------------------------------------------------------===//
     12 
     13 #include "common/thirdparty/SmallVector.h"
     14 //#include "llvm/ADT/Twine.h"
     15 //#include "llvm/Support/MemAlloc.h"
     16 #include <cstdint>
     17 #include <string>
     18 #ifdef LLVM_ENABLE_EXCEPTIONS
     19 #include <stdexcept>
     20 #endif
     21 using namespace llvm;
     22 
     23 namespace llvm
     24 {
     25 /*LLVM_ATTRIBUTE_RETURNS_NONNULL*/ inline void *safe_malloc(size_t Sz) {
     26   void *Result = std::malloc(Sz);
     27   if (Result == nullptr) {
     28     // It is implementation-defined whether allocation occurs if the space
     29     // requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting
     30     // non-zero, if the space requested was zero.
     31     if (Sz == 0)
     32       return safe_malloc(1);
     33     //report_bad_alloc_error("Allocation failed");
     34     fputs("Allocation failed\n", stderr);
     35     abort();
     36   }
     37   return Result;
     38 }
     39 
     40 /*LLVM_ATTRIBUTE_RETURNS_NONNULL*/ inline void *safe_realloc(void *Ptr, size_t Sz) {
     41   void *Result = std::realloc(Ptr, Sz);
     42   if (Result == nullptr) {
     43     // It is implementation-defined whether allocation occurs if the space
     44     // requested is zero (ISO/IEC 9899:2018 7.22.3). Retry, requesting
     45     // non-zero, if the space requested was zero.
     46     if (Sz == 0)
     47       return safe_malloc(1);
     48     //report_bad_alloc_error("Allocation failed");
     49     fputs("Allocation failed\n", stderr);
     50     abort();
     51   }
     52   return Result;
     53 }
     54 }
     55 
     56 // Check that no bytes are wasted and everything is well-aligned.
     57 namespace {
     58 // These structures may cause binary compat warnings on AIX. Suppress the
     59 // warning since we are only using these types for the static assertions below.
     60 #if defined(_AIX)
     61 #pragma GCC diagnostic push
     62 #pragma GCC diagnostic ignored "-Waix-compat"
     63 #endif
     64 struct Struct16B {
     65   alignas(16) void *X;
     66 };
     67 struct Struct32B {
     68   alignas(32) void *X;
     69 };
     70 #if defined(_AIX)
     71 #pragma GCC diagnostic pop
     72 #endif
     73 }
     74 static_assert(sizeof(SmallVector<void *, 0>) ==
     75                   sizeof(unsigned) * 2 + sizeof(void *),
     76               "wasted space in SmallVector size 0");
     77 static_assert(alignof(SmallVector<Struct16B, 0>) >= alignof(Struct16B),
     78               "wrong alignment for 16-byte aligned T");
     79 static_assert(alignof(SmallVector<Struct32B, 0>) >= alignof(Struct32B),
     80               "wrong alignment for 32-byte aligned T");
     81 static_assert(sizeof(SmallVector<Struct16B, 0>) >= alignof(Struct16B),
     82               "missing padding for 16-byte aligned T");
     83 static_assert(sizeof(SmallVector<Struct32B, 0>) >= alignof(Struct32B),
     84               "missing padding for 32-byte aligned T");
     85 static_assert(sizeof(SmallVector<void *, 1>) ==
     86                   sizeof(unsigned) * 2 + sizeof(void *) * 2,
     87               "wasted space in SmallVector size 1");
     88 
     89 static_assert(sizeof(SmallVector<char, 0>) ==
     90                   sizeof(void *) * 2 + sizeof(void *),
     91               "1 byte elements have word-sized type for size and capacity");
     92 
     93 /// Report that MinSize doesn't fit into this vector's size type. Throws
     94 /// std::length_error or calls report_fatal_error.
     95 [[noreturn]] static void report_size_overflow(size_t MinSize, size_t MaxSize);
     96 static void report_size_overflow(size_t MinSize, size_t MaxSize) {
     97   std::string Reason = "SmallVector unable to grow. Requested capacity (" +
     98                        std::to_string(MinSize) +
     99                        ") is larger than maximum value for size type (" +
    100                        std::to_string(MaxSize) + ")\n";
    101 #ifdef LLVM_ENABLE_EXCEPTIONS
    102   throw std::length_error(Reason);
    103 #else
    104   //report_fatal_error(Twine(Reason));
    105   fputs(Reason.c_str(), stderr);
    106   abort();
    107 #endif
    108 }
    109 
    110 /// Report that this vector is already at maximum capacity. Throws
    111 /// std::length_error or calls report_fatal_error.
    112 [[noreturn]] static void report_at_maximum_capacity(size_t MaxSize);
    113 static void report_at_maximum_capacity(size_t MaxSize) {
    114   std::string Reason =
    115       "SmallVector capacity unable to grow. Already at maximum size " +
    116       std::to_string(MaxSize);
    117 #ifdef LLVM_ENABLE_EXCEPTIONS
    118   throw std::length_error(Reason);
    119 #else
    120   //report_fatal_error(Twine(Reason));
    121   fputs(Reason.c_str(), stderr);
    122   abort();
    123 #endif
    124 }
    125 
    126 // Note: Moving this function into the header may cause performance regression.
    127 template <class Size_T>
    128 static size_t getNewCapacity(size_t MinSize, size_t TSize, size_t OldCapacity) {
    129   constexpr size_t MaxSize = std::numeric_limits<Size_T>::max();
    130 
    131   // Ensure we can fit the new capacity.
    132   // This is only going to be applicable when the capacity is 32 bit.
    133   if (MinSize > MaxSize)
    134     report_size_overflow(MinSize, MaxSize);
    135 
    136   // Ensure we can meet the guarantee of space for at least one more element.
    137   // The above check alone will not catch the case where grow is called with a
    138   // default MinSize of 0, but the current capacity cannot be increased.
    139   // This is only going to be applicable when the capacity is 32 bit.
    140   if (OldCapacity == MaxSize)
    141     report_at_maximum_capacity(MaxSize);
    142 
    143   // In theory 2*capacity can overflow if the capacity is 64 bit, but the
    144   // original capacity would never be large enough for this to be a problem.
    145   size_t NewCapacity = 2 * OldCapacity + 1; // Always grow.
    146   return std::clamp(NewCapacity, MinSize, MaxSize);
    147 }
    148 
    149 template <class Size_T>
    150 void *SmallVectorBase<Size_T>::replaceAllocation(void *NewElts, size_t TSize,
    151                                                  size_t NewCapacity,
    152                                                  size_t VSize) {
    153   void *NewEltsReplace = llvm::safe_malloc(NewCapacity * TSize);
    154   if (VSize)
    155     memcpy(NewEltsReplace, NewElts, VSize * TSize);
    156   free(NewElts);
    157   return NewEltsReplace;
    158 }
    159 
    160 // Note: Moving this function into the header may cause performance regression.
    161 template <class Size_T>
    162 void *SmallVectorBase<Size_T>::mallocForGrow(void *FirstEl, size_t MinSize,
    163                                              size_t TSize,
    164                                              size_t &NewCapacity) {
    165   NewCapacity = getNewCapacity<Size_T>(MinSize, TSize, this->capacity());
    166   // Even if capacity is not 0 now, if the vector was originally created with
    167   // capacity 0, it's possible for the malloc to return FirstEl.
    168   //void *NewElts = llvm::safe_malloc(NewCapacity * TSize);
    169   void* NewElts = llvm::safe_malloc(NewCapacity * TSize);
    170   if (NewElts == FirstEl)
    171     NewElts = replaceAllocation(NewElts, TSize, NewCapacity);
    172   return NewElts;
    173 }
    174 
    175 // Note: Moving this function into the header may cause performance regression.
    176 template <class Size_T>
    177 void SmallVectorBase<Size_T>::grow_pod(void *FirstEl, size_t MinSize,
    178                                        size_t TSize) {
    179   size_t NewCapacity = getNewCapacity<Size_T>(MinSize, TSize, this->capacity());
    180   void *NewElts;
    181   if (BeginX == FirstEl) {
    182     NewElts = llvm::safe_malloc(NewCapacity * TSize);
    183     if (NewElts == FirstEl)
    184       NewElts = replaceAllocation(NewElts, TSize, NewCapacity);
    185 
    186     // Copy the elements over.  No need to run dtors on PODs.
    187     memcpy(NewElts, this->BeginX, size() * TSize);
    188   } else {
    189     // If this wasn't grown from the inline copy, grow the allocated space.
    190     NewElts = llvm::safe_realloc(this->BeginX, NewCapacity * TSize);
    191     if (NewElts == FirstEl)
    192       NewElts = replaceAllocation(NewElts, TSize, NewCapacity, size());
    193   }
    194 
    195   this->BeginX = NewElts;
    196   this->Capacity = NewCapacity;
    197 }
    198 
    199 template class llvm::SmallVectorBase<uint32_t>;
    200 
    201 // Disable the uint64_t instantiation for 32-bit builds.
    202 // Both uint32_t and uint64_t instantiations are needed for 64-bit builds.
    203 // This instantiation will never be used in 32-bit builds, and will cause
    204 // warnings when sizeof(Size_T) > sizeof(size_t).
    205 #if SIZE_MAX > UINT32_MAX
    206 template class llvm::SmallVectorBase<uint64_t>;
    207 
    208 // Assertions to ensure this #if stays in sync with SmallVectorSizeType.
    209 static_assert(sizeof(SmallVectorSizeType<char>) == sizeof(uint64_t),
    210               "Expected SmallVectorBase<uint64_t> variant to be in use.");
    211 #else
    212 static_assert(sizeof(SmallVectorSizeType<char>) == sizeof(uint32_t),
    213               "Expected SmallVectorBase<uint32_t> variant to be in use.");
    214 #endif