| /* | |
| * Copyright 2022 Rive | |
| */ | |
| #pragma once | |
| #include "rive/rive_types.hpp" | |
| #ifdef __clang__ | |
| #include <mm_malloc.h> | |
| #else | |
| #include <cstdlib> | |
| #endif | |
| namespace rive::pls | |
| { | |
| // Wraps a memory allocation whose address is aligned at a multiple of | |
| // "AlignmentInElements * sizeof(T)" bytes. | |
| // This allows for optimal SSE/NEON loads. | |
| template <size_t AlignmentInElements, typename T> class AlignedBuffer | |
| { | |
| public: | |
| size_t capacity() const { return m_capacity; } | |
| RIVE_ALWAYS_INLINE T& operator[](size_t idx) { return m_buffer[idx]; } | |
| RIVE_ALWAYS_INLINE T* get() { return m_buffer; } | |
| template <typename U> U* cast() { return reinterpret_cast<U*>(m_buffer); } | |
| void resize(size_t capacity) | |
| { | |
| if (m_capacity != capacity) | |
| { | |
| freeBuffer(); | |
| // Round "capacity" up to a multiple of "AlignmentInElements". | |
| capacity = | |
| ((capacity + AlignmentInElements - 1) / AlignmentInElements) * AlignmentInElements; | |
| #if defined(__clang__) | |
| m_buffer = reinterpret_cast<T*>( | |
| _mm_malloc(capacity * sizeof(T), AlignmentInElements * sizeof(T))); | |
| #elif defined(_WIN32) | |
| m_buffer = reinterpret_cast<T*>( | |
| _aligned_malloc(capacity * sizeof(T), AlignmentInElements * sizeof(T))); | |
| #else | |
| m_buffer = reinterpret_cast<T*>( | |
| std::aligned_alloc(AlignmentInElements * sizeof(T), capacity * sizeof(T))); | |
| #endif | |
| m_capacity = capacity; | |
| } | |
| } | |
| ~AlignedBuffer() { freeBuffer(); } | |
| private: | |
| void freeBuffer() | |
| { | |
| #if defined(__clang__) | |
| _mm_free(m_buffer); | |
| #elif defined(_WIN32) | |
| _aligned_free(m_buffer); | |
| #else | |
| std::free(m_buffer); | |
| #endif | |
| } | |
| size_t m_capacity = 0; | |
| T* m_buffer = nullptr; | |
| }; | |
| } // namespace rive::pls |