From 6e88c44d5dd041a75912f000cce631316a6b72fd Mon Sep 17 00:00:00 2001 From: JosJuice Date: Mon, 21 Aug 2023 16:12:49 +0200 Subject: [PATCH] Move SmallVector to Common We had one implementation of this type of data structure in Arm64Emitter and one in VideoCommon. This moves the Arm64Emitter implementation to its own file and adds begin and end functions to it, so that VideoCommon can use it. You may notice that the license header for the new file is CC0. I wrote the Arm64Emitter implementation of SmallVector, so this should be no problem. --- Source/Core/Common/Arm64Emitter.cpp | 34 +++--------------- Source/Core/Common/CMakeLists.txt | 1 + Source/Core/Common/SmallVector.h | 46 +++++++++++++++++++++++++ Source/Core/DolphinLib.props | 1 + Source/Core/VideoCommon/BPFunctions.cpp | 24 ++----------- 5 files changed, 55 insertions(+), 51 deletions(-) create mode 100644 Source/Core/Common/SmallVector.h diff --git a/Source/Core/Common/Arm64Emitter.cpp b/Source/Core/Common/Arm64Emitter.cpp index d59fd13300..296b9976c7 100644 --- a/Source/Core/Common/Arm64Emitter.cpp +++ b/Source/Core/Common/Arm64Emitter.cpp @@ -18,6 +18,7 @@ #include "Common/BitUtils.h" #include "Common/CommonTypes.h" #include "Common/MathUtil.h" +#include "Common/SmallVector.h" #ifdef _WIN32 #include @@ -1794,33 +1795,6 @@ void ARM64XEmitter::ADRP(ARM64Reg Rd, s64 imm) EncodeAddressInst(1, Rd, static_cast(imm >> 12)); } -template -class SmallVector final -{ -public: - SmallVector() = default; - explicit SmallVector(size_t size) : m_size(size) {} - - void push_back(const T& x) { m_array[m_size++] = x; } - void push_back(T&& x) { m_array[m_size++] = std::move(x); } - - template - T& emplace_back(Args&&... args) - { - return m_array[m_size++] = T{std::forward(args)...}; - } - - T& operator[](size_t i) { return m_array[i]; } - const T& operator[](size_t i) const { return m_array[i]; } - - size_t size() const { return m_size; } - bool empty() const { return m_size == 0; } - -private: - std::array m_array{}; - size_t m_size = 0; -}; - template void ARM64XEmitter::MOVI2RImpl(ARM64Reg Rd, T imm) { @@ -1844,17 +1818,17 @@ void ARM64XEmitter::MOVI2RImpl(ARM64Reg Rd, T imm) constexpr size_t max_parts = sizeof(T) / 2; - SmallVector best_parts; + Common::SmallVector best_parts; Approach best_approach; u64 best_base; - const auto instructions_required = [](const SmallVector& parts, + const auto instructions_required = [](const Common::SmallVector& parts, Approach approach) { return parts.size() + (approach > Approach::MOVNBase); }; const auto try_base = [&](T base, Approach approach, bool first_time) { - SmallVector parts; + Common::SmallVector parts; for (size_t i = 0; i < max_parts; ++i) { diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index 5f3194e09d..20f657698d 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -110,6 +110,7 @@ add_library(common SettingsHandler.h SFMLHelper.cpp SFMLHelper.h + SmallVector.h SocketContext.cpp SocketContext.h SPSCQueue.h diff --git a/Source/Core/Common/SmallVector.h b/Source/Core/Common/SmallVector.h new file mode 100644 index 0000000000..09559ed21a --- /dev/null +++ b/Source/Core/Common/SmallVector.h @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: CC0-1.0 + +#pragma once + +#include +#include +#include + +namespace Common +{ + +// An std::vector-like container that uses no heap allocations but is limited to a maximum size. +template +class SmallVector final +{ +public: + SmallVector() = default; + explicit SmallVector(size_t size) : m_size(size) {} + + void push_back(const T& x) { m_array[m_size++] = x; } + void push_back(T&& x) { m_array[m_size++] = std::move(x); } + + template + T& emplace_back(Args&&... args) + { + return m_array[m_size++] = T{std::forward(args)...}; + } + + T& operator[](size_t i) { return m_array[i]; } + const T& operator[](size_t i) const { return m_array[i]; } + + auto begin() { return m_array.begin(); } + auto end() { return m_array.begin() + m_size; } + + auto begin() const { return m_array.begin(); } + auto end() const { return m_array.begin() + m_size; } + + size_t size() const { return m_size; } + bool empty() const { return m_size == 0; } + +private: + std::array m_array{}; + size_t m_size = 0; +}; + +} // namespace Common diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props index 1b44f15ec4..810bff4f26 100644 --- a/Source/Core/DolphinLib.props +++ b/Source/Core/DolphinLib.props @@ -143,6 +143,7 @@ + diff --git a/Source/Core/VideoCommon/BPFunctions.cpp b/Source/Core/VideoCommon/BPFunctions.cpp index ad9898b27e..6f9948a68e 100644 --- a/Source/Core/VideoCommon/BPFunctions.cpp +++ b/Source/Core/VideoCommon/BPFunctions.cpp @@ -10,6 +10,7 @@ #include "Common/Assert.h" #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" +#include "Common/SmallVector.h" #include "VideoCommon/AbstractFramebuffer.h" #include "VideoCommon/AbstractGfx.h" @@ -76,26 +77,7 @@ bool ScissorResult::IsWorse(const ScissorRect& lhs, const ScissorRect& rhs) cons namespace { -// Dynamically sized small array of ScissorRanges (used as an heap-less alternative to std::vector -// to reduce allocation overhead) -struct RangeList -{ - static constexpr u32 MAX_RANGES = 9; - - u32 m_num_ranges = 0; - std::array m_ranges{}; - - void AddRange(int offset, int start, int end) - { - DEBUG_ASSERT(m_num_ranges < MAX_RANGES); - m_ranges[m_num_ranges] = ScissorRange(offset, start, end); - m_num_ranges++; - } - auto begin() const { return m_ranges.begin(); } - auto end() const { return m_ranges.begin() + m_num_ranges; } - - u32 size() { return m_num_ranges; } -}; +using RangeList = Common::SmallVector; static RangeList ComputeScissorRanges(int start, int end, int offset, int efb_dim) { @@ -108,7 +90,7 @@ static RangeList ComputeScissorRanges(int start, int end, int offset, int efb_di int new_end = std::clamp(end - new_off + 1, 0, efb_dim); if (new_start < new_end) { - ranges.AddRange(new_off, new_start, new_end); + ranges.emplace_back(new_off, new_start, new_end); } }