TempAllocator.h 3.0 KB

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