summaryrefslogtreecommitdiff
path: root/Source/Core/Common
diff options
context:
space:
mode:
authorJosJuice <josjuice@gmail.com>2024-04-13 18:29:52 +0200
committerJosJuice <josjuice@gmail.com>2024-04-20 18:31:08 +0200
commit3cfa233b63dfcd734be2dd0ae4bd0d3e98109df6 (patch)
treef4b111b5d43f9192b15f82250d3123d15585b001 /Source/Core/Common
parent5c9bb80638ec05b32eaa129a8c763ac6bb3a5cb4 (diff)
VideoCommon: Use GetSpanForAddress safely in texture decoding
Now only VertexLoader remains... But that one might be tricky.
Diffstat (limited to 'Source/Core/Common')
-rw-r--r--Source/Core/Common/CMakeLists.txt1
-rw-r--r--Source/Core/Common/SpanUtils.h41
2 files changed, 42 insertions, 0 deletions
diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt
index 7b81cd2c6d..af48ba7e13 100644
--- a/Source/Core/Common/CMakeLists.txt
+++ b/Source/Core/Common/CMakeLists.txt
@@ -126,6 +126,7 @@ add_library(common
SmallVector.h
SocketContext.cpp
SocketContext.h
+ SpanUtils.h
SPSCQueue.h
StringLiteral.h
StringUtil.cpp
diff --git a/Source/Core/Common/SpanUtils.h b/Source/Core/Common/SpanUtils.h
new file mode 100644
index 0000000000..d09193b314
--- /dev/null
+++ b/Source/Core/Common/SpanUtils.h
@@ -0,0 +1,41 @@
+// Copyright 2024 Dolphin Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <algorithm>
+#include <cstddef>
+#include <span>
+#include <utility>
+
+#include "Common/CommonTypes.h"
+
+namespace Common
+{
+
+// Like std::span::subspan, except undefined behavior is replaced with returning a 0-length span.
+template <class T>
+[[nodiscard]] constexpr std::span<T> SafeSubspan(std::span<T> span, size_t offset,
+ size_t count = std::dynamic_extent)
+{
+ if (count == std::dynamic_extent || offset > span.size())
+ return span.subspan(std::min(offset, span.size()));
+ else
+ return span.subspan(offset, std::min(count, span.size() - offset));
+}
+
+// Default-constructs an object of type T, then copies data into it from the specified offset in
+// the specified span. Out-of-bounds reads will be skipped, meaning that specifying a too large
+// offset results in the object partially or entirely remaining default constructed.
+template <class T>
+[[nodiscard]] T SafeSpanRead(std::span<const u8> span, size_t offset)
+{
+ static_assert(std::is_trivially_copyable<T>());
+
+ const std::span<const u8> subspan = SafeSubspan(span, offset);
+ T result{};
+ std::memcpy(&result, subspan.data(), std::min(subspan.size(), sizeof(result)));
+ return result;
+}
+
+} // namespace Common