virtualStack.h 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. // zlib open source license
  2. //
  3. // Copyright (c) 2024 David Forsgren Piuva
  4. //
  5. // This software is provided 'as-is', without any express or implied
  6. // warranty. In no event will the authors be held liable for any damages
  7. // arising from the use of this software.
  8. //
  9. // Permission is granted to anyone to use this software for any purpose,
  10. // including commercial applications, and to alter it and redistribute it
  11. // freely, subject to the following restrictions:
  12. //
  13. // 1. The origin of this software must not be misrepresented; you must not
  14. // claim that you wrote the original software. If you use this software
  15. // in a product, an acknowledgment in the product documentation would be
  16. // appreciated but is not required.
  17. //
  18. // 2. Altered source versions must be plainly marked as such, and must not be
  19. // misrepresented as being the original software.
  20. //
  21. // 3. This notice may not be removed or altered from any source
  22. // distribution.
  23. #ifndef DFPSR_VIRTUAL_STACK
  24. #define DFPSR_VIRTUAL_STACK
  25. #include "SafePointer.h"
  26. namespace dsr {
  27. // Allocate memory in the virtual stack owned by the current thread.
  28. // paddedSize is the number of bytes to allocate including all elements and internal padding.
  29. // paddedSize must be at least 1, but has no rounding requirements.
  30. // The start of the allocation is aligned according to alignmentAndMask.
  31. // alignmentAndMask should only contain zeroes at the bits to round away for alignment.
  32. // alignmentAndMask should be the bitwise negation of the alignment minus one, where the alignment is a power of two.
  33. // ~(alignment - 1)
  34. UnsafeAllocation virtualStack_push(uint64_t paddedSize, uintptr_t alignmentAndMask, const char *name = "Nameless virtual stack allocation");
  35. // A simpler way to get the correct alignment is to allocate a number of elements with a specific type.
  36. // Pre-condition:
  37. // sizeof(T) % alignof(T) == 0
  38. template <typename T>
  39. SafePointer<T> virtualStack_push(uint64_t elementCount, const char *name = "Nameless virtual stack allocation") {
  40. // Calculate element size and multiply by element count to get the total size.
  41. uint64_t paddedSize = sizeof(T) * elementCount;
  42. // Allocate the data with the amount of alignment requested by the element type T.
  43. UnsafeAllocation result = virtualStack_push(paddedSize, memory_createAlignmentAndMask((uintptr_t)alignof(T)), name);
  44. // Return a safe pointer to the allocated data.
  45. #ifdef SAFE_POINTER_CHECKS
  46. return SafePointer<T>(result.header, result.header->allocationIdentity, name, (T*)(result.data), (intptr_t)paddedSize);
  47. #else
  48. return SafePointer<T>(name, (T*)(result.data), (intptr_t)paddedSize);
  49. #endif
  50. }
  51. // Free the last allocation from the virtual stack.
  52. // Must be called from the same thread that pushed, because virtual stacks are local to their threads.
  53. void virtualStack_pop();
  54. // Allocate this array on the stack to automatically free the memory when the scope ends.
  55. // Replaces Variable Length Arrays (VLA) or alloca.
  56. template <typename T>
  57. class VirtualStackAllocation : public SafePointer<T> {
  58. public:
  59. VirtualStackAllocation(uint64_t elementCount, const char *name = "Nameless virtual stack allocation")
  60. : SafePointer<T>(virtualStack_push<T>(elementCount, name)) {}
  61. ~VirtualStackAllocation() {
  62. virtualStack_pop();
  63. }
  64. };
  65. }
  66. #endif