42 lines
1.3 KiB
C++
42 lines
1.3 KiB
C++
// 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
|