mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-22 13:55:38 +00:00
common: Add a FIFOQueue helper class
This commit is contained in:
parent
2128a2984b
commit
a0e7dff37c
|
@ -43,6 +43,7 @@
|
|||
<ClInclude Include="display_renderer_gl.h" />
|
||||
<ClInclude Include="display_timing.h" />
|
||||
<ClInclude Include="fastjmp.h" />
|
||||
<ClInclude Include="fifo_queue.h" />
|
||||
<ClInclude Include="gl_program.h" />
|
||||
<ClInclude Include="gl_texture.h" />
|
||||
<ClInclude Include="hdd_image.h" />
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
<ClInclude Include="state_wrapper.h" />
|
||||
<ClInclude Include="gl_program.h" />
|
||||
<ClInclude Include="gl_texture.h" />
|
||||
<ClInclude Include="fifo_queue.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="hdd_image.cpp" />
|
||||
|
|
181
src/common/fifo_queue.h
Normal file
181
src/common/fifo_queue.h
Normal file
|
@ -0,0 +1,181 @@
|
|||
#pragma once
|
||||
#include "YBaseLib/Assert.h"
|
||||
#include "types.h"
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <malloc.h> // _aligned_malloc
|
||||
#else
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
|
||||
template<typename T, u32 CAPACITY>
|
||||
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<class... Args>
|
||||
T& Emplace(Args&&... args)
|
||||
{
|
||||
T& ref = PushAndGetReference();
|
||||
new (&ref) T(std::forward<Args>(args...));
|
||||
return ref;
|
||||
}
|
||||
|
||||
template<class Y = T, std::enable_if_t<std::is_pod_v<Y>, int> = 0>
|
||||
T& Push(const T& value)
|
||||
{
|
||||
T& ref = PushAndGetReference();
|
||||
std::memcpy(&ref, &value, sizeof(T));
|
||||
return ref;
|
||||
}
|
||||
|
||||
template<class Y = T, std::enable_if_t<!std::is_pod_v<Y>, 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<class Y = T, std::enable_if_t<std::is_pod_v<Y>, 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<class Y = T, std::enable_if_t<!std::is_pod_v<Y>, 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<typename T, u32 CAPACITY>
|
||||
class InlineFIFOQueue : public FIFOQueue<T, CAPACITY>
|
||||
{
|
||||
public:
|
||||
InlineFIFOQueue() : FIFOQueue<T, CAPACITY>() { m_ptr = m_inline_data; }
|
||||
|
||||
private:
|
||||
T m_inline_data[CAPACITY] = {};
|
||||
};
|
||||
|
||||
template<typename T, u32 CAPACITY, u32 ALIGNMENT = 0>
|
||||
class HeapFIFOQueue : public FIFOQueue<T, CAPACITY>
|
||||
{
|
||||
public:
|
||||
HeapFIFOQueue() : FIFOQueue<T, CAPACITY>()
|
||||
{
|
||||
if constexpr (ALIGNMENT > 0)
|
||||
{
|
||||
#ifdef _MSC_VER
|
||||
m_ptr = static_cast<T*>(_aligned_malloc(sizeof(T) * CAPACITY, ALIGNMENT));
|
||||
#else
|
||||
m_ptr = static_cast<T*>(memalign(ALIGNMENT, sizeof(T) * CAPACITY));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ptr = static_cast<T*>(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);
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include "YBaseLib/ByteStream.h"
|
||||
#include "fifo_queue.h"
|
||||
#include "types.h"
|
||||
#include <cstring>
|
||||
#include <deque>
|
||||
|
@ -134,6 +135,29 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
template<typename T, u32 CAPACITY>
|
||||
void Do(FIFOQueue<T, CAPACITY>* 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:
|
||||
|
|
Loading…
Reference in a new issue