sfizz/sources/Buffer.h

87 lines
3.1 KiB
C
Raw Normal View History

2019-07-29 02:13:03 +02:00
#pragma once
#include "Globals.h"
2019-07-29 02:13:03 +02:00
#include <type_traits>
#include <cstdlib>
#include <memory>
2019-08-04 16:42:44 +02:00
template<class Type, unsigned int Alignment = SIMDConfig::defaultAlignment>
2019-07-29 02:13:03 +02:00
class Buffer
{
public:
2019-08-21 01:00:07 +02:00
using value_type = std::remove_cv_t<Type>;
using pointer = value_type*;
using const_pointer = const value_type*;
using reference = value_type&;
using const_reference = const value_type&;
using iterator = pointer;
using const_iterator = const_pointer;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
using size_type = size_t;
using difference_type = ptrdiff_t;
constexpr Buffer() { }
Buffer(size_t size)
{
resize(size);
}
bool resize(size_t newSize)
2019-07-29 02:13:03 +02:00
{
if (newSize == 0)
{
clear();
return true;
}
2019-07-29 02:13:03 +02:00
2019-07-31 01:45:58 +02:00
auto tempSize = newSize + 2 * AlignmentMask; // To ensure that we have leeway at the beginning and at the end
2019-08-21 01:00:07 +02:00
auto* newData = paddedData != nullptr ? std::realloc(paddedData, tempSize * sizeof(value_type)) : std::malloc(tempSize * sizeof(value_type));
if (newData == nullptr)
return false;
largerSize = tempSize;
alignedSize = newSize;
2019-08-21 01:00:07 +02:00
paddedData = static_cast<pointer>(newData);
normalData = static_cast<pointer>(std::align(Alignment, alignedSize, newData, tempSize));
2019-08-03 18:14:58 +02:00
normalEnd = normalData + alignedSize;
if (auto endMisalignment = (alignedSize & TypeAlignmentMask); endMisalignment != 0)
_alignedEnd = normalEnd + Alignment - endMisalignment;
2019-08-07 23:39:35 +02:00
else
_alignedEnd = normalEnd;
return true;
}
void clear()
{
largerSize = 0;
alignedSize = 0;
2019-08-03 18:14:58 +02:00
std::free(paddedData);
normalData = nullptr;
normalEnd = nullptr;
_alignedEnd = nullptr;
2019-07-29 02:13:03 +02:00
}
~Buffer()
{
2019-08-03 18:14:58 +02:00
std::free(paddedData);
2019-07-29 02:13:03 +02:00
}
2019-08-03 18:14:58 +02:00
Type& operator[](int idx) { return *(normalData + idx); }
2019-08-21 01:00:07 +02:00
constexpr pointer data() const noexcept { return normalData; }
constexpr size_type size() const noexcept { return alignedSize; }
constexpr bool empty() const noexcept { return alignedSize == 0; }
constexpr iterator begin() noexcept { return data(); }
constexpr iterator end() noexcept { return normalEnd; }
constexpr pointer alignedEnd() noexcept { return _alignedEnd; }
2019-07-29 02:13:03 +02:00
private:
2019-08-03 18:14:58 +02:00
static constexpr auto AlignmentMask { Alignment - 1 };
2019-08-21 01:00:07 +02:00
static constexpr auto TypeAlignment { Alignment / sizeof(value_type) };
2019-08-03 18:14:58 +02:00
static constexpr auto TypeAlignmentMask { TypeAlignment - 1 };
2019-08-21 01:00:07 +02:00
static_assert(std::is_arithmetic<value_type>::value, "Type should be arithmetic");
2019-08-03 18:14:58 +02:00
static_assert(Alignment == 0 || Alignment == 4 || Alignment == 8 || Alignment == 16, "Bad alignment value");
2019-08-21 01:00:07 +02:00
static_assert(TypeAlignment * sizeof(value_type) == Alignment, "The alignment does not appear to be divided by the size of the Type");
size_type largerSize { 0 };
size_type alignedSize { 0 };
pointer normalData { nullptr };
pointer paddedData { nullptr };
pointer normalEnd { nullptr };
pointer _alignedEnd { nullptr };
2019-07-29 02:13:03 +02:00
};