| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273 |
- // zlib open source license
- //
- // Copyright (c) 2024 David Forsgren Piuva
- //
- // This software is provided 'as-is', without any express or implied
- // warranty. In no event will the authors be held liable for any damages
- // arising from the use of this software.
- //
- // Permission is granted to anyone to use this software for any purpose,
- // including commercial applications, and to alter it and redistribute it
- // freely, subject to the following restrictions:
- //
- // 1. The origin of this software must not be misrepresented; you must not
- // claim that you wrote the original software. If you use this software
- // in a product, an acknowledgment in the product documentation would be
- // appreciated but is not required.
- //
- // 2. Altered source versions must be plainly marked as such, and must not be
- // misrepresented as being the original software.
- //
- // 3. This notice may not be removed or altered from any source
- // distribution.
- #ifndef DFPSR_VIRTUAL_STACK
- #define DFPSR_VIRTUAL_STACK
- #include "SafePointer.h"
- namespace dsr {
- // Allocate memory in the virtual stack owned by the current thread.
- // paddedSize is the number of bytes to allocate including all elements and internal padding.
- // paddedSize must be at least 1, but has no rounding requirements.
- // alignmentMask should only contain zeroes at the bits to round away for alignment.
- // alignmentMask should be the bitwise negation of the alignment minus one, where the alignment is a power of two.
- // ~(alignment - 1)
- UnsafeAllocation virtualStack_push(uint64_t paddedSize, uintptr_t alignmentAndMask);
- // A simpler way to get the correct alignment is to allocate a number of elements with a specific type.
- // TODO: Create another function for manual alignment exceeding the type's alignment using another template argument.
- // TODO: Let the address offset be negated and start with the allocation size going down to zero,
- // so that rounding up addresses can be done by simply masking the least significant bits.
- template <typename T>
- SafePointer<T> virtualStack_push(uint64_t elementCount, const char *name) {
- // Calculate element size and multiply by element count to get the total size.
- uint64_t paddedSize = memory_getPaddedSize<T>() * elementCount;
- // Allocate the data with the amount of alignment requested by the element type T.
- UnsafeAllocation result = virtualStack_push(paddedSize, memory_createAlignmentAndMask((uintptr_t)alignof(T)));
- // Return a safe pointer to the allocated data.
- #ifdef SAFE_POINTER_CHECKS
- return SafePointer<T>(name, (T*)(result.data), (intptr_t)paddedSize, result.header);
- #else
- return SafePointer<T>(name, (T*)(result.data), (intptr_t)paddedSize);
- #endif
- }
- // Free the last allocation from the virtual stack.
- // Must be called from the same thread that pushed, because virtual stacks are local to their threads.
- void virtualStack_pop();
- // Allocate this array on the stack to automatically free the memory when the scope ends.
- // Replaces VLA or alloca.
- template <typename T>
- class VirtualStackAllocation : public SafePointer<T> {
- public:
- VirtualStackAllocation(uint64_t elementCount)
- : SafePointer<T>(virtualStack_push<T>(elementCount, "virtual stack allocation")) {}
- ~VirtualStackAllocation() {
- virtualStack_pop();
- }
- };
- }
- #endif
|