memory_ref.h
1 // Copyright 2020 Citra Emulator Project 2 // Licensed under GPLv2 or any later version 3 // Refer to the license.txt file included. 4 5 #pragma once 6 7 #include <memory> 8 #include <span> 9 #include <vector> 10 #include <boost/serialization/export.hpp> 11 #include <boost/serialization/shared_ptr.hpp> 12 #include <boost/serialization/vector.hpp> 13 #include "common/assert.h" 14 #include "common/common_types.h" 15 16 /// Abstract host-side memory - for example a static buffer, or local vector 17 class BackingMem { 18 public: 19 virtual ~BackingMem() = default; 20 virtual u8* GetPtr() = 0; 21 virtual const u8* GetPtr() const = 0; 22 virtual std::size_t GetSize() const = 0; 23 24 private: 25 template <class Archive> 26 void serialize(Archive&, const unsigned int) {} 27 friend class boost::serialization::access; 28 }; 29 30 /// Backing memory implemented by a local buffer 31 class BufferMem : public BackingMem { 32 public: 33 BufferMem() = default; 34 explicit BufferMem(std::size_t size) : data(size) {} 35 36 u8* GetPtr() override { 37 return data.data(); 38 } 39 40 const u8* GetPtr() const override { 41 return data.data(); 42 } 43 44 std::size_t GetSize() const override { 45 return data.size(); 46 } 47 48 std::vector<u8>& Vector() { 49 return data; 50 } 51 52 const std::vector<u8>& Vector() const { 53 return data; 54 } 55 56 private: 57 std::vector<u8> data; 58 59 template <class Archive> 60 void serialize(Archive& ar, const unsigned int) { 61 ar& boost::serialization::base_object<BackingMem>(*this); 62 ar& data; 63 } 64 friend class boost::serialization::access; 65 }; 66 67 BOOST_CLASS_EXPORT_KEY(BufferMem); 68 69 /** 70 * A managed reference to host-side memory. 71 * Fast enough to be used everywhere instead of u8* 72 * Supports serialization. 73 */ 74 class MemoryRef { 75 public: 76 MemoryRef() = default; 77 MemoryRef(std::nullptr_t) {} 78 79 MemoryRef(std::shared_ptr<BackingMem> backing_mem_) 80 : backing_mem(std::move(backing_mem_)), offset(0) { 81 Init(); 82 } 83 MemoryRef(std::shared_ptr<BackingMem> backing_mem_, u64 offset_) 84 : backing_mem(std::move(backing_mem_)), offset(offset_) { 85 ASSERT(offset <= backing_mem->GetSize()); 86 Init(); 87 } 88 89 explicit operator bool() const { 90 return cptr != nullptr; 91 } 92 93 operator u8*() { 94 return cptr; 95 } 96 97 u8* GetPtr() { 98 return cptr; 99 } 100 101 operator const u8*() const { 102 return cptr; 103 } 104 105 const u8* GetPtr() const { 106 return cptr; 107 } 108 109 std::span<u8> GetWriteBytes(std::size_t size) { 110 return std::span{cptr, std::min(size, csize)}; 111 } 112 113 template <typename T> 114 std::span<const T> GetReadBytes(std::size_t size) const { 115 const auto* cptr_t = reinterpret_cast<T*>(cptr); 116 return std::span{cptr_t, std::min(size, csize) / sizeof(T)}; 117 } 118 119 std::size_t GetSize() const { 120 return csize; 121 } 122 123 MemoryRef& operator+=(u32 offset_by) { 124 ASSERT(offset_by < csize); 125 offset += offset_by; 126 Init(); 127 return *this; 128 } 129 130 MemoryRef operator+(u32 offset_by) const { 131 ASSERT(offset_by < csize); 132 return MemoryRef(backing_mem, offset + offset_by); 133 } 134 135 private: 136 std::shared_ptr<BackingMem> backing_mem{}; 137 u64 offset{}; 138 // Cached values for speed 139 u8* cptr{}; 140 std::size_t csize{}; 141 142 void Init() { 143 if (backing_mem) { 144 cptr = backing_mem->GetPtr() + offset; 145 csize = static_cast<std::size_t>(backing_mem->GetSize() - offset); 146 } else { 147 cptr = nullptr; 148 csize = 0; 149 } 150 } 151 152 template <class Archive> 153 void serialize(Archive& ar, const unsigned int) { 154 ar& backing_mem; 155 ar& offset; 156 Init(); 157 } 158 friend class boost::serialization::access; 159 };