sandbox
Loading...
Searching...
No Matches
memory_file.hpp
1// SPDX-License-Identifier: MIT
2#ifndef LIBSBX_FILESYSTEM_MEMORY_FILE_HPP_
3#define LIBSBX_FILESYSTEM_MEMORY_FILE_HPP_
4
5#include <cstring>
6#include <mutex>
7#include <algorithm>
8
9#include <libsbx/utility/lockable.hpp>
10
11#include <libsbx/filesystem/file_base.hpp>
12#include <libsbx/filesystem/file_info.hpp>
13
14namespace sbx::filesystem {
15
16namespace detail {
17
18template<utility::lockable Lockable>
20
21public:
22
23 using lockable_type = Lockable;
24
26 : _data{std::make_shared<std::vector<std::uint8_t>>()} {}
27
29 _copy_from(other);
30 }
31
32 auto operator=(const memory_file_object& other) -> memory_file_object& {
33 if (this != &other) {
34 _copy_from(other);
35 }
36
37 return *this;
38 }
39
40 [[nodiscard]] auto data() const -> std::shared_ptr<std::vector<std::uint8_t>> {
41 auto lock = std::scoped_lock{_mutex};
42
43 return _data;
44 }
45
46 [[nodiscard]] auto writable_data() -> std::shared_ptr<std::vector<std::uint8_t>> {
47 auto lock = std::scoped_lock{_mutex};
48
49 if (!_data || _data.use_count() == 1) {
50 return _data;
51 }
52
53 _data = std::make_shared<std::vector<std::uint8_t>>(*_data);
54
55 return _data;
56 }
57
58 auto reset() -> void {
59 auto lock = std::scoped_lock{_mutex};
60
61 _data = std::make_shared<std::vector<std::uint8_t>>();
62 }
63
64private:
65
66 auto _copy_from(const memory_file_object& other) -> void {
67 auto other_data = other.data();
68
69 auto lock = std::scoped_lock{_mutex};
70
71 if (!other_data) {
72 _data = std::make_shared<std::vector<std::uint8_t>>();
73 } else {
74 _data = std::make_shared<std::vector<std::uint8_t>>(*other_data);
75 }
76 }
77
78private:
79
80 mutable lockable_type _mutex;
81 std::shared_ptr<std::vector<std::uint8_t>> _data;
82
83}; // memory_file_object
84
85template<utility::lockable Lockable>
86using memory_file_object_ptr = std::shared_ptr<memory_file_object<Lockable>>;
87
88} // namespace detail
89
90template<utility::lockable Lockable>
91class basic_memory_file final : public file_base {
92
93public:
94
95 using lockable_type = Lockable;
96
97 basic_memory_file(file_info&& info, detail::memory_file_object_ptr<lockable_type>&& object)
98 : _info(std::move(info)),
99 _object(std::move(object)) {
100 if (!_object) {
101 _object = std::make_shared<detail::memory_file_object<lockable_type>>();
102 }
103 }
104
105 ~basic_memory_file() override {
106 _is_open = false;
107 _position = 0;
108 _mode = mode::read;
109 }
110
111 [[nodiscard]] auto info() const -> const file_info& override {
112 auto lock = std::scoped_lock{_mutex};
113
114 return _info;
115 }
116
117 [[nodiscard]] auto size() const -> std::uint64_t override {
118 auto lock = std::scoped_lock{_mutex};
119
120 if (!_is_open) {
121 return 0;
122 }
123
124 auto data = _object->data();
125
126 return data ? data->size() : 0;
127 }
128
129 [[nodiscard]] auto is_read_only() const -> bool override {
130 auto lock = std::scoped_lock{_mutex};
131
132 return !mode_has_flag(_mode, mode::write);
133 }
134
135 [[nodiscard]] auto open(const mode mode) -> bool override {
136 auto lock = std::scoped_lock{_mutex};
137
138 if (!is_mode_valid(mode)) {
139 return false;
140 }
141
142 if (_is_open && _mode == mode) {
143 _position = 0;
144
145 return true;
146 }
147
148 _mode = mode;
149 _position = 0;
150
151 if (mode_has_flag(mode, mode::append)) {
152 auto data = _object->data();
153
154 _position = data ? data->size() : 0;
155 }
156
157 if (mode_has_flag(mode, mode::truncate)) {
158 _object->reset();
159 }
160
161 _is_open = true;
162
163 return true;
164 }
165
166 auto close() -> void override {
167 auto lock = std::scoped_lock{_mutex};
168
169 _is_open = false;
170 _position = 0;
171 _mode = mode::read;
172 }
173
174 [[nodiscard]] auto is_open() const -> bool override {
175 auto lock = std::scoped_lock{_mutex};
176
177 return _is_open;
178 }
179
180 auto seek(std::uint64_t offset, origin origin) -> std::uint64_t override {
181 auto lock = std::scoped_lock{_mutex};
182
183 if (!_is_open) {
184 return 0;
185 }
186
187 auto data = _object->data();
188
189 const auto size = data ? data->size() : 0;
190
191 switch (origin) {
192 case origin::begin: {
193 _position = offset;
194 break;
195 }
196 case origin::end: {
197 _position = (offset < size) ? size - offset : 0;
198 break;
199 }
200 case origin::set: {
201 _position += offset;
202 break;
203 }
204 }
205
206 _position = std::min(_position, size);
207
208 return _position;
209 }
210
211 [[nodiscard]] auto tell() const -> std::uint64_t override {
212 auto lock = std::scoped_lock{_mutex};
213
214 return _position;
215 }
216
217 auto read(std::span<std::uint8_t> buffer) -> std::uint64_t override {
218 auto lock = std::scoped_lock{_mutex};
219
220 if (!_is_open || !mode_has_flag(_mode, mode::read)) {
221 return 0;
222 }
223
224 auto data = _object->data();
225
226 if (!data) {
227 return 0;
228 }
229
230 if (_position >= data->size()) {
231 return 0;
232 }
233
234 const auto to_read = std::min<std::uint64_t>(buffer.size(), data->size() - _position);
235
236 if (to_read == 0) {
237 return 0;
238 }
239
240 std::memcpy(buffer.data(), data->data() + _position, to_read);
241 _position += to_read;
242
243 return to_read;
244 }
245
246 auto read(std::vector<std::uint8_t>& buffer, std::uint64_t size) -> std::uint64_t override {
247 buffer.resize(size);
248
249 return read(std::span<std::uint8_t>(buffer));
250 }
251
252 auto write(std::span<const std::uint8_t> buffer) -> std::uint64_t override {
253 auto lock = std::scoped_lock{_mutex};
254
255 if (!_is_open || !mode_has_flag(_mode, mode::write)) {
256 return 0;
257 }
258
259 auto data = _object->writable_data();
260
261 if (!data) {
262 return 0;
263 }
264
265 const auto write_size = buffer.size();
266
267 if (write_size == 0) {
268 return 0;
269 }
270
271 if (_position + write_size > data->size()) {
272 data->resize(_position + write_size);
273 }
274
275 std::memcpy(data->data() + _position, buffer.data(), write_size);
276
277 _position += write_size;
278
279 return write_size;
280 }
281
282 auto write(const std::vector<std::uint8_t>& buffer) -> std::uint64_t override {
283 return write(std::span<const std::uint8_t>(buffer));
284 }
285
286private:
287
288 mutable lockable_type _mutex;
289
290 file_info _info;
291 detail::memory_file_object_ptr<lockable_type> _object;
292
293 bool _is_open{false};
294 std::uint64_t _position{0};
295 mode _mode{mode::read};
296
297}; // class basic_memory_file
298
301
303
304} // namespace sbx::filesystem
305
306#endif // LIBSBX_FILESYSTEM_MEMORY_FILE_HPP_
Definition: memory_file.hpp:91
Definition: memory_file.hpp:19
Definition: file_base.hpp:15
Definition: file_info.hpp:10