TempAllocator.h 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #pragma once
  4. #include <Jolt/Core/NonCopyable.h>
  5. JPH_NAMESPACE_BEGIN
  6. /// Allocator for temporary allocations.
  7. /// This allocator works as a stack: The blocks must always be freed in the reverse order as they are allocated.
  8. /// Note that allocations and frees can take place from different threads, but the order is guaranteed though
  9. /// job dependencies, so it is not needed to use any form of locking.
  10. class TempAllocator : public NonCopyable
  11. {
  12. public:
  13. JPH_OVERRIDE_NEW_DELETE
  14. /// Destructor
  15. virtual ~TempAllocator() = default;
  16. /// Allocates inSize bytes of memory, returned memory address must be 16 byte aligned
  17. virtual void * Allocate(uint inSize) = 0;
  18. /// Frees inSize bytes of memory located at inAddress
  19. virtual void Free(void *inAddress, uint inSize) = 0;
  20. };
  21. /// Default implementation of the temp allocator that allocates a large block through malloc upfront
  22. class TempAllocatorImpl final : public TempAllocator
  23. {
  24. public:
  25. JPH_OVERRIDE_NEW_DELETE
  26. /// Constructs the allocator with a maximum allocatable size of inSize
  27. explicit TempAllocatorImpl(uint inSize) :
  28. mBase(static_cast<uint8 *>(JPH::Allocate(inSize))),
  29. mSize(inSize)
  30. {
  31. }
  32. /// Destructor, frees the block
  33. virtual ~TempAllocatorImpl() override
  34. {
  35. JPH_ASSERT(mTop == 0);
  36. JPH::Free(mBase);
  37. }
  38. // See: TempAllocator
  39. virtual void * Allocate(uint inSize) override
  40. {
  41. if (inSize == 0)
  42. {
  43. return nullptr;
  44. }
  45. else
  46. {
  47. uint new_top = mTop + AlignUp(inSize, 16);
  48. if (new_top > mSize)
  49. JPH_CRASH; // Out of memory
  50. void *address = mBase + mTop;
  51. mTop = new_top;
  52. return address;
  53. }
  54. }
  55. // See: TempAllocator
  56. virtual void Free(void *inAddress, uint inSize) override
  57. {
  58. if (inAddress == nullptr)
  59. {
  60. JPH_ASSERT(inSize == 0);
  61. }
  62. else
  63. {
  64. mTop -= AlignUp(inSize, 16);
  65. if (mBase + mTop != inAddress)
  66. JPH_CRASH; // Freeing in the wrong order
  67. }
  68. }
  69. // Check if no allocations have been made
  70. bool IsEmpty() const
  71. {
  72. return mTop == 0;
  73. }
  74. private:
  75. uint8 * mBase; ///< Base address of the memory block
  76. uint mSize; ///< Size of the memory block
  77. uint mTop = 0; ///< Current top of the stack
  78. };
  79. /// Implementation of the TempAllocator that just falls back to malloc/free
  80. /// Note: This can be quite slow when running in the debugger as large memory blocks need to be initialized with 0xcd
  81. class TempAllocatorMalloc final : public TempAllocator
  82. {
  83. public:
  84. JPH_OVERRIDE_NEW_DELETE
  85. // See: TempAllocator
  86. virtual void * Allocate(uint inSize) override
  87. {
  88. return AlignedAllocate(inSize, 16);
  89. }
  90. // See: TempAllocator
  91. virtual void Free(void *inAddress, uint inSize) override
  92. {
  93. AlignedFree(inAddress);
  94. }
  95. };
  96. JPH_NAMESPACE_END