memory.h 3.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  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_MEMORY
  24. #define DFPSR_MEMORY
  25. // Safe pointer checks are removed in release mode for speed after having tested the program in debug mode for safety.
  26. #ifndef NDEBUG
  27. #define SAFE_POINTER_CHECKS
  28. #endif
  29. #include <cstdint>
  30. namespace dsr {
  31. // A header that is placed next to memory allocations.
  32. struct AllocationHeader {
  33. uintptr_t totalSize; // Size of both header and payload.
  34. #ifdef SAFE_POINTER_CHECKS
  35. uint64_t threadHash; // Hash of the owning thread identity for thread local memory, 0 for shared memory.
  36. uint64_t allocationIdentity; // Rotating identity of the allocation, to know if the memory has been freed and reused within a memory allocator.
  37. #endif
  38. // Header for freed memory.
  39. AllocationHeader();
  40. // Header for allocated memory.
  41. // threadLocal should be true iff the memory may not be accessed from other threads, such as virtual stack memory.
  42. AllocationHeader(uintptr_t totalSize, bool threadLocal);
  43. };
  44. // A structure used to allocate memory before placing the content in SafePointer.
  45. struct UnsafeAllocation {
  46. uint8_t *data;
  47. #ifdef SAFE_POINTER_CHECKS
  48. AllocationHeader *header;
  49. UnsafeAllocation(uint8_t *data, AllocationHeader *header)
  50. : data(data), header(header) {}
  51. #else
  52. UnsafeAllocation(uint8_t *data, AllocationHeader *header)
  53. : data(data) {}
  54. #endif
  55. };
  56. // Post-condition: Returns size rounded up by alignment.
  57. constexpr uint64_t memory_getPaddedSize(uint64_t size, uint64_t alignment) {
  58. // Round up with unsigned integers.
  59. return size + (alignment - 1) - ((size - 1) % alignment);
  60. }
  61. // Post-condition: Returns the size of T rounded up by T's own alignment, which becomes the stride between elements in a memory aligned array.
  62. template <typename T>
  63. constexpr uint64_t memory_getPaddedSize() {
  64. return memory_getPaddedSize((uint64_t)sizeof(T), (uint64_t)alignof(T));
  65. }
  66. // Create a mask for aligning memory in descending address space.
  67. // The bitwise and operation "&" between a pointer and this function's result becomes an address rounded down by alignment.
  68. // myAlignedPointer = (uintptr_t)myPointer & memory_createAlignmentAndMask(alignment)
  69. // By allocating memory from back to front, rounding down can be used for memory alignment.
  70. // Pre-condition:
  71. // alignment is a power of two (1, 2, 4, 8, 16, 32, 64...)
  72. // Post-condition:
  73. // Returns a bit mask for rounding an integer down to the closest multiple of alignment.
  74. constexpr uintptr_t memory_createAlignmentAndMask(uintptr_t alignment) {
  75. // alignment = ...00001000...
  76. // Subtracting one from a power of two gives a mask with ones for the remainder bits.
  77. // remainder = ...00000111...
  78. // Then we simply negate the mask to get the alignment mask for rounding down.
  79. // mask = ...11111000...
  80. return ~(alignment - 1);
  81. }
  82. }
  83. #endif