diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj index 2337cd7c5..b01ef1987 100644 --- a/src/common/common.vcxproj +++ b/src/common/common.vcxproj @@ -43,6 +43,7 @@ + diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters index 385089087..d1e2b8784 100644 --- a/src/common/common.vcxproj.filters +++ b/src/common/common.vcxproj.filters @@ -19,6 +19,7 @@ + diff --git a/src/common/fifo_queue.h b/src/common/fifo_queue.h new file mode 100644 index 000000000..77fd64924 --- /dev/null +++ b/src/common/fifo_queue.h @@ -0,0 +1,181 @@ +#pragma once +#include "YBaseLib/Assert.h" +#include "types.h" +#include +#include + +#ifdef _MSC_VER +#include // _aligned_malloc +#else +#include +#endif + +template +class FIFOQueue +{ +public: + const T* GetDataPointer() const { return m_ptr; } + T* GetDataPointer() { return m_ptr; } + const T* GetFrontPointer() const { return m_ptr[m_head]; } + T* GetFrontPointer() { return m_ptr[m_head]; } + constexpr u32 GetCapacity() const { return CAPACITY; } + u32 GetSize() const { return m_size; } + bool IsEmpty() const { return m_size > 0; } + bool IsFull() const { return m_size == CAPACITY; } + + void Clear() + { + m_head = 0; + m_tail = 0; + m_size = 0; + } + + template + T& Emplace(Args&&... args) + { + T& ref = PushAndGetReference(); + new (&ref) T(std::forward(args...)); + return ref; + } + + template, int> = 0> + T& Push(const T& value) + { + T& ref = PushAndGetReference(); + std::memcpy(&ref, &value, sizeof(T)); + return ref; + } + + template, int> = 0> + T& Push(const T& value) + { + T& ref = PushAndGetReference(); + new (&ref) T(value); + return ref; + } + + // faster version of push_back_range for POD types which can be memcpy()ed + template, int> = 0> + void PushRange(const T* data, u32 size) + { + Assert((m_size + size) <= CAPACITY); + const u32 space_before_end = CAPACITY - m_tail; + const u32 size_before_end = (size > space_before_end) ? space_before_end : size; + const u32 size_after_end = size - size_before_end; + + std::memcpy(&m_ptr[m_tail], data, sizeof(T) * size_before_end); + m_tail = (m_tail + size_before_end) % CAPACITY; + + if (size_after_end > 0) + { + std::memcpy(&m_ptr[m_tail], data + size_before_end, sizeof(T) * size_after_end); + m_tail = (m_tail + size_after_end) % CAPACITY; + } + + m_size += size; + } + + template, int> = 0> + void PushRange(const T* data, u32 size) + { + Assert((m_size + size) <= CAPACITY); + while (size > 0) + { + T& ref = PushAndGetReference(); + new (&ref) T(*data); + data++; + size--; + } + } + + const T& Peek() const { return m_ptr[m_head]; } + const T& Peek(u32 offset) { return m_ptr[(m_head + offset) % CAPACITY]; } + + void RemoveOne() + { + Assert(m_size > 0); + m_ptr[m_head].~T(); + m_head = (m_head + 1) % CAPACITY; + m_size--; + } + + // removes and returns moved value + T Pop() + { + Assert(m_size > 0); + T val = std::move(m_ptr[m_head]); + m_ptr[m_head].~T(); + m_head = (m_head + 1) % CAPACITY; + m_size--; + return val; + } + +protected: + FIFOQueue() = default; + + T& PushAndGetReference() + { + Assert(m_size < CAPACITY); + T& ref = m_ptr[m_tail]; + m_tail = (m_tail + 1) % CAPACITY; + m_size++; + return ref; + } + + T* m_ptr = nullptr; + u32 m_head = 0; + u32 m_tail = 0; + u32 m_size = 0; +}; + +template +class InlineFIFOQueue : public FIFOQueue +{ +public: + InlineFIFOQueue() : FIFOQueue() { m_ptr = m_inline_data; } + +private: + T m_inline_data[CAPACITY] = {}; +}; + +template +class HeapFIFOQueue : public FIFOQueue +{ +public: + HeapFIFOQueue() : FIFOQueue() + { + if constexpr (ALIGNMENT > 0) + { +#ifdef _MSC_VER + m_ptr = static_cast(_aligned_malloc(sizeof(T) * CAPACITY, ALIGNMENT)); +#else + m_ptr = static_cast(memalign(ALIGNMENT, sizeof(T) * CAPACITY)); +#endif + } + else + { + m_ptr = static_cast(std::malloc(sizeof(T) * CAPACITY)); + } + + if (!m_ptr) + Panic("Heap allocation failed"); + + std::memset(m_ptr, 0, sizeof(T) * CAPACITY); + } + + ~HeapFIFOQueue() + { + if constexpr (ALIGNMENT > 0) + { +#ifdef _MSC_VER + _aligned_free(m_ptr); +#else + free(m_ptr); +#endif + } + else + { + free(m_ptr); + } + } +}; diff --git a/src/common/state_wrapper.h b/src/common/state_wrapper.h index 35aa39a3f..d0a3cb4b7 100644 --- a/src/common/state_wrapper.h +++ b/src/common/state_wrapper.h @@ -1,5 +1,6 @@ #pragma once #include "YBaseLib/ByteStream.h" +#include "fifo_queue.h" #include "types.h" #include #include @@ -134,6 +135,29 @@ public: } } + template + void Do(FIFOQueue* data) + { + u32 size = data->GetSize(); + Do(&size); + + if (m_mode == Mode::Read) + { + T* temp = new T[size]; + DoArray(temp, size); + data->PushRange(temp, size); + delete[] temp; + } + else + { + for (u32 i = 0; i < size; i++) + { + T temp(data->Peek(i)); + Do(&temp); + } + } + } + bool DoMarker(const char* marker); private: