blob: 724b90b49bd137ff6da049dbf23328d08c55b911 [file] [log] [blame]
/*
* 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