TempAllocator.h 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  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. JPH_CRASH; // Out of memory
  51. void *address = mBase + mTop;
  52. mTop = new_top;
  53. return address;
  54. }
  55. }
  56. // See: TempAllocator
  57. virtual void Free(void *inAddress, uint inSize) override
  58. {
  59. if (inAddress == nullptr)
  60. {
  61. JPH_ASSERT(inSize == 0);
  62. }
  63. else
  64. {
  65. mTop -= AlignUp(inSize, JPH_RVECTOR_ALIGNMENT);
  66. if (mBase + mTop != inAddress)
  67. JPH_CRASH; // Freeing in the wrong order
  68. }
  69. }
  70. // Check if no allocations have been made
  71. bool IsEmpty() const
  72. {
  73. return mTop == 0;
  74. }
  75. private:
  76. uint8 * mBase; ///< Base address of the memory block
  77. uint mSize; ///< Size of the memory block
  78. uint mTop = 0; ///< Current top of the stack
  79. };
  80. /// Implementation of the TempAllocator that just falls back to malloc/free
  81. /// Note: This can be quite slow when running in the debugger as large memory blocks need to be initialized with 0xcd
  82. class JPH_EXPORT TempAllocatorMalloc final : public TempAllocator
  83. {
  84. public:
  85. JPH_OVERRIDE_NEW_DELETE
  86. // See: TempAllocator
  87. virtual void * Allocate(uint inSize) override
  88. {
  89. return AlignedAllocate(inSize, JPH_RVECTOR_ALIGNMENT);
  90. }
  91. // See: TempAllocator
  92. virtual void Free(void *inAddress, [[maybe_unused]] uint inSize) override
  93. {
  94. AlignedFree(inAddress);
  95. }
  96. };
  97. JPH_NAMESPACE_END