Common: Add UniqueBuffer and SharedBuffer templates.

This commit is contained in:
Jordan Woyak 2025-04-18 22:13:56 -05:00
parent f78fa2e9f1
commit 12dcd6c285
3 changed files with 90 additions and 0 deletions

View File

@ -0,0 +1,88 @@
// Copyright 2025 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <memory>
// UniqueBuffer<T> and SharedBuffer<T> are a lighter alternative to std::vector<T>.
// The main benefit is that elements are not value-initialized like in vector.
// That can be quite a bit of unecessary overhead when allocating a large buffer.
namespace Common
{
namespace detail
{
template <auto MakeFunc>
class BufferBase final
{
public:
using PtrType = decltype(MakeFunc(1));
using value_type = PtrType::element_type;
using size_type = std::size_t;
BufferBase() {}
BufferBase(PtrType ptr, size_type new_size) : m_ptr{std::move(ptr)}, m_size{new_size} {}
explicit BufferBase(size_type new_size) : BufferBase{MakeFunc(new_size), new_size} {}
BufferBase(const BufferBase&) = default;
BufferBase& operator=(const BufferBase&) = default;
BufferBase(BufferBase&& other) { swap(other); }
BufferBase& operator=(BufferBase&& other)
{
reset();
swap(other);
return *this;
}
void assign(PtrType ptr, size_type new_size) { BufferBase{std::move(ptr), new_size}.swap(*this); }
void reset(size_type new_size = 0) { BufferBase{new_size}.swap(*this); }
std::pair<PtrType, size_type> extract()
{
std::pair result = {std::move(m_ptr), m_size};
reset();
return result;
}
void swap(BufferBase& other)
{
std::swap(m_ptr, other.m_ptr);
std::swap(m_size, other.m_size);
}
size_type size() const { return m_size; }
bool empty() const { return m_size == 0; }
value_type* get() { return m_ptr.get(); }
const value_type* get() const { return m_ptr.get(); }
value_type* data() { return m_ptr.get(); }
const value_type* data() const { return m_ptr.get(); }
value_type* begin() { return m_ptr.get(); }
value_type* end() { return m_ptr.get() + m_size; }
const value_type* begin() const { return m_ptr.get(); }
const value_type* end() const { return m_ptr.get() + m_size; }
value_type& operator[](size_type index) { return m_ptr[index]; }
const value_type& operator[](size_type index) const { return m_ptr[index]; }
private:
PtrType m_ptr;
size_type m_size = 0;
};
} // namespace detail
template <typename T>
using UniqueBuffer = detail::BufferBase<std::make_unique_for_overwrite<T[]>>;
// TODO: std::make_shared_for_overwrite requires GCC 12.1+
// template <typename T>
// using SharedBuffer = detail::BufferBase<std::make_shared_for_overwrite<T[]>>;
} // namespace Common

View File

@ -18,6 +18,7 @@ add_library(common
BitSet.h
BitUtils.h
BlockingLoop.h
Buffer.h
ChunkFile.h
CodeBlock.h
ColorUtil.cpp

View File

@ -26,6 +26,7 @@
<ClInclude Include="Common\BitSet.h" />
<ClInclude Include="Common\BitUtils.h" />
<ClInclude Include="Common\BlockingLoop.h" />
<ClInclude Include="Common\Buffer.h" />
<ClInclude Include="Common\ChunkFile.h" />
<ClInclude Include="Common\CodeBlock.h" />
<ClInclude Include="Common\ColorUtil.h" />