NSUNI/NSLAR Library a250670
Loading...
Searching...
No Matches
io.hpp
Go to the documentation of this file.
1
16#pragma once
17#include <filesystem>
18#include <fstream>
19#include <type_traits>
20#include <vector>
21
25#include "NNL/utility/math.hpp"
26
27namespace nnl {
28
35
40using Buffer = std::vector<u8>;
41
51class RWBase {
52 public:
57 virtual void Seek(std::size_t offset) = 0;
62 virtual std::size_t Tell() = 0;
67 virtual std::size_t Len() = 0;
68
69 virtual ~RWBase() = default;
70};
71
78class Reader : virtual public RWBase {
79 public:
85 void ReadBuf(void* dst, std::size_t size) { ReadData(dst, size); }
91 template <typename T, typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
92 T ReadLE() {
93 T value;
94 ReadData(&value, sizeof(T));
95 return value;
96 }
97
106 template <typename T>
107 std::vector<T> ReadArrayLE(std::size_t num_elements) {
108 static_assert(std::is_trivially_copyable_v<T>);
109 std::vector<T> result;
110
111 result.resize(num_elements);
112
113 ReadData(result.data(), num_elements * sizeof(T));
114
115 return result;
116 }
117
118 virtual ~Reader() override = default;
119
120 protected:
126 virtual void ReadData(void* dst, std::size_t size) = 0;
127};
128
136class Writer : virtual public RWBase {
137 public:
156 template <typename T>
157 class Offset {
158 public:
159 auto Get() const { return Ref<T>(*this); }
160
161 template <typename M, typename A = T, std::enable_if_t<std::is_class_v<A>, int> = 0>
162 auto Get(M A::*member) const {
163 return this->Get().Get(member);
164 }
165
173 auto operator*() const { return this->Get(); }
174
183 template <typename M, typename A = T, std::enable_if_t<std::is_class_v<A>, int> = 0>
184 auto operator->*(M A::*member) const {
185 return this->Get(member);
186 }
187
198 auto operator[](std::size_t index) const { return *((*this) + index); }
199
205 template <typename Int>
206 explicit operator Int() const noexcept {
207 static_assert(std::is_integral_v<Int>);
208 return static_cast<Int>(offset_);
209 }
210
211 bool operator==(const Offset& rhs) const = delete;
212
213 bool operator!=(const Offset& rhs) const = delete;
214
215 Offset& operator++() {
216 offset_ += sizeof(T);
217 return *this;
218 }
219
220 Offset operator++(int) {
221 Offset prev = *this;
222 ++(*this);
223 return prev;
224 }
225
226 Offset& operator+=(std::size_t value) {
227 offset_ += sizeof(T) * value;
228 return *this;
229 }
230
231 Offset operator+(std::size_t value) const {
232 Offset result = *this;
233 result += value; // Reuse compound assignment
234 return result;
235 }
236
237 Offset& operator--() {
238 offset_ -= sizeof(T);
239 return *this;
240 }
241
242 Offset operator--(int) {
243 Offset prev = *this;
244 --(*this);
245 return prev;
246 }
247
248 Offset& operator-=(std::size_t value) { return *this -= value; }
249
250 Offset operator-(std::size_t value) const {
251 Offset result = *this;
252 result -= value;
253 return result;
254 }
255
256 friend Offset operator+(std::size_t value, const Offset& offset) {
257 return Offset{offset.writer_, offset.offset_ + value};
258 }
259
260 friend Offset operator-(std::size_t value, const Offset& offset) {
261 return Offset{offset.writer_, offset.offset_ - value};
262 }
263
264 private:
265 Offset(Writer& writer, std::size_t offset) : writer_(writer), offset_(offset) {}
266
267 Writer& writer_;
268 std::size_t offset_;
269 friend class Writer;
270 }; // class Offset
271
283 template <typename T>
284 class Ref {
285 public:
286 template <typename A = T>
287 std::enable_if_t<!std::is_array_v<A>, T> Get() const {
288 auto prev_offset = off_.writer_.Tell();
289 off_.writer_.Seek(off_.offset_);
290 auto value = dynamic_cast<Reader&>(off_.writer_).ReadLE<T>();
291 off_.writer_.Seek(prev_offset);
292 return value;
293 }
294
295 void Set(const T& value) {
296 auto prev_offset = off_.writer_.Tell();
297 off_.writer_.Seek(off_.offset_);
298 off_.writer_.WriteData(&value, sizeof(T));
299 off_.writer_.Seek(prev_offset);
300 }
301
302 template <typename M, typename A = T, std::enable_if_t<std::is_class_v<A>, int> = 0>
303 Ref<M> Get(M A::*member) const {
304 std::size_t member_offset = reinterpret_cast<std::size_t>(&(((T*)nullptr)->*member));
305 return Ref<M>({off_.writer_, off_.offset_ + member_offset});
306 }
307
308 template <typename A = T, typename M = std::remove_all_extents_t<A>,
309 std::enable_if_t<std::is_array_v<A> && std::rank_v<A> == 1, int> = 0>
310 Ref<M> Get(std::size_t index) const {
311 return Ref<M>({off_.writer_, off_.offset_ + sizeof(M) * index});
312 }
313
314 template <typename A = T, typename M = std::remove_extent_t<A>,
315 std::enable_if_t<std::is_array_v<A> && std::rank_v<A> != 1, int> = 0>
316 Ref<M> Get(std::size_t index) const {
317 return Ref<M>({off_.writer_, off_.offset_ + sizeof(M) * index});
318 }
319
326 template <typename M, typename A = T, std::enable_if_t<std::is_class_v<A>, int> = 0>
327 Ref<M> operator->*(M A::*member) const {
328 return Get(member);
329 }
330
336 template <typename A = T, typename M = std::remove_all_extents_t<A>,
337 std::enable_if_t<std::is_array_v<A> && std::rank_v<A> == 1, int> = 0>
338 Ref<M> operator[](std::size_t index) const {
339 return Get(index);
340 }
341
348 template <typename A = T, typename M = std::remove_extent_t<A>,
349 std::enable_if_t<std::is_array_v<A> && std::rank_v<A> != 1, int> = 0>
350 Ref<M> operator[](std::size_t index) const {
351 return Get(index);
352 }
353
358 template <typename A = T, std::enable_if_t<!std::is_array_v<A>, int> = 0>
359 operator A() const {
360 static_assert(std::is_convertible_v<T, A>);
361
362 return Get();
363 }
364
369 void operator=(const T& value) { Set(value); }
370
371 bool operator==(const Ref& other) const { return this->Get() == other.Get(); }
372
373 bool operator!=(const Ref& other) const { return !(*this == other); }
374
375 bool operator==(const T& other) const { return this->Get() == other; }
376
377 bool operator!=(const T& other) const { return !(*this == other); }
378
379 private:
380 Ref(Offset<T> offset) : off_(offset) {}
381
382 Offset<T> off_;
383
384 friend class Writer;
385 }; // class Ref
386
392 template <typename T, typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
394 return Offset<T>(*this, Tell());
395 }
396
402 Offset<u8> WriteBuf(const void* src, std::size_t size) {
403 auto pos = Tell();
404 WriteData(src, size);
405 return Offset<u8>(*this, pos);
406 }
407
414 template <typename T, std::enable_if_t<std::is_trivially_copyable_v<T>, int> = 0>
415 Offset<T> WriteLE(const T& value) {
416 auto pos = Tell();
417
418 WriteData(&value, sizeof(T));
419
420 return Offset<T>(*this, pos);
421 }
422
430 template <typename T>
431 Offset<T> WriteArrayLE(const std::vector<T>& container) {
432 static_assert(std::is_trivially_copyable_v<T>);
433
434 auto prev_position = Tell();
435
436 WriteData(container.data(), container.size() * sizeof(T));
437
438 return Offset<T>(*this, prev_position);
439 }
440
446 void AlignData(std::size_t multiple, unsigned char value = 0) {
447 auto cur_pos = Tell();
448 auto num_bytes = utl::math::RoundNum(cur_pos, multiple) - cur_pos;
449 for (std::size_t i = 0; i < num_bytes; i++) WriteLE(value);
450 }
451
452 virtual ~Writer() override = default;
453
454 protected:
460 virtual void WriteData(const void* src, std::size_t size) = 0;
461};
462
467class FileReader final : public Reader {
468 public:
475 FileReader(const std::filesystem::path& path) : path_(path) {
476 file_stream_.open(path, std::ios::ate | std::ios::in | std::ios::binary);
477
478 if (!file_stream_.is_open()) {
479 NNL_THROW(nnl::IOError(NNL_SRCTAG(std::strerror(errno)), utl::filesys::u8string(path)));
480 }
481
482 size_ = file_stream_.tellg();
483 file_stream_.seekg(0);
484 }
485 void Seek(std::size_t offset) override { file_stream_.seekg(offset, std::ios::beg); }
486
487 std::size_t Tell() override { return file_stream_.tellg(); }
488
489 std::size_t Len() override { return size_; }
493 void ClearState() { file_stream_.clear(); }
497 void Close() {
498 file_stream_.close();
499 size_ = 0;
500 }
501
502 protected:
503 void ReadData(void* dst, std::size_t size) override {
504 file_stream_.read(static_cast<char*>(dst), size);
505 if (!file_stream_) {
506 NNL_THROW(nnl::IOError(NNL_SRCTAG("failed to read data"), utl::filesys::u8string(path_)));
507 }
508 }
509
510 private:
511 std::filesystem::path path_;
512 std::ifstream file_stream_;
513 std::size_t size_ = 0;
514};
515
520class FileRW final : public Writer, public Reader {
521 public:
530 FileRW(const std::filesystem::path& path, bool truncate) : path_(path) {
531 auto open_mode = std::ios::binary | std::ios::out | std::ios::in;
532
533 if (truncate) {
534 open_mode |= std::ios::trunc;
535 }
536
537 file_stream_.open(path, open_mode);
538
539 if (!file_stream_.is_open()) {
540 NNL_THROW(nnl::IOError(NNL_SRCTAG(std::strerror(errno)), utl::filesys::u8string(path)));
541 }
542 }
543 void Seek(std::size_t offset) override { file_stream_.seekp(offset, std::ios::beg); }
544
545 std::size_t Tell() override { return file_stream_.tellp(); }
546
547 std::size_t Len() override {
548 auto cur_pos = file_stream_.tellp();
549 file_stream_.seekp(0, std::ios::end);
550 std::size_t size = file_stream_.tellp();
551 file_stream_.seekp(cur_pos);
552 return size;
553 }
554
557 void ClearState() { file_stream_.clear(); }
561 void Close() { file_stream_.close(); }
562
563 protected:
564 void WriteData(const void* src, std::size_t size) override {
565 file_stream_.write(static_cast<const char*>(src), size);
566 if (!file_stream_) {
567 NNL_THROW(nnl::IOError(NNL_SRCTAG("failed to write data"), utl::filesys::u8string(path_)));
568 }
569 }
570
571 void ReadData(void* dst, std::size_t size) override {
572 file_stream_.read(static_cast<char*>(dst), size);
573 if (!file_stream_) {
574 NNL_THROW(nnl::IOError(NNL_SRCTAG("failed to read data"), utl::filesys::u8string(path_)));
575 }
576 }
577
578 private:
579 std::filesystem::path path_;
580 std::fstream file_stream_;
581};
582
598class BufferView final : public Reader {
599 public:
600 using value_type = u8;
601 using iterator = const value_type*;
602 using const_iterator = const value_type*;
603 using reverse_iterator = std::reverse_iterator<iterator>;
604 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
605
606 BufferView() noexcept {}
607
613 BufferView(const void* buffer, std::size_t size) noexcept
614 : buffer_ptr_(reinterpret_cast<const u8*>(buffer)), buffer_size_(size) {
615 NNL_EXPECTS_DBG(buffer != nullptr || size == 0);
616 }
617
623 template <typename TContainer,
624 typename = std::enable_if_t<std::is_trivially_copyable_v<typename TContainer::value_type>>>
625 BufferView(const TContainer& buffer) noexcept
626 : buffer_ptr_(reinterpret_cast<const u8*>(buffer.data())),
627 buffer_size_(buffer.size() * sizeof(typename TContainer::value_type)) {}
628
629 void Seek(std::size_t offset) override { position_ = offset; }
630
631 std::size_t Tell() override { return position_; }
632
633 std::size_t Len() override { return buffer_size_; }
634
641 [[nodiscard]] BufferView SubView(std::size_t offset, std::size_t size) const {
642 NNL_EXPECTS(offset + size <= buffer_size_);
643 return BufferView(buffer_ptr_ + offset, size);
644 }
645
646 Buffer CopyBuf() const {
647 std::vector<u8> copied_buf(buffer_size_);
648
649 if (buffer_ptr_ != nullptr && buffer_size_ != 0) std::memcpy(copied_buf.data(), buffer_ptr_, buffer_size_);
650
651 return copied_buf;
652 }
653
654 const u8& operator[](std::size_t index) const {
655 NNL_EXPECTS_DBG(index < size());
656 return buffer_ptr_[index];
657 }
658
659 friend bool operator==(const BufferView& lhs, const BufferView& rhs) {
660 return (lhs.buffer_size_ == 0 && rhs.buffer_size_ == 0) ||
661 (lhs.buffer_size_ == rhs.buffer_size_ &&
662 std::memcmp(lhs.buffer_ptr_, rhs.buffer_ptr_, lhs.buffer_size_) == 0);
663 }
664
665 friend bool operator!=(const BufferView& lhs, const BufferView& rhs) { return !(lhs == rhs); }
666
667 std::size_t size() const noexcept { return buffer_size_; }
668
669 [[nodiscard]] std::size_t empty() const noexcept { return buffer_size_ == 0; }
670
675 const u8* data() const noexcept { return buffer_ptr_; }
676
677 const u8& at(std::size_t index) const {
678 NNL_EXPECTS(index < buffer_size_);
679 return buffer_ptr_[index];
680 }
681
682 const u8& front() const {
683 NNL_EXPECTS_DBG(buffer_size_ > 0);
684 return *begin();
685 }
686
687 const u8& back() const {
688 NNL_EXPECTS_DBG(buffer_size_ > 0);
689 return *rbegin();
690 }
691
692 const_iterator begin() const noexcept { return buffer_ptr_; }
693
694 const_iterator end() const noexcept { return buffer_ptr_ + buffer_size_; }
695
696 const_reverse_iterator rbegin() const noexcept { return std::make_reverse_iterator(end()); }
697
698 const_reverse_iterator rend() const noexcept { return std::make_reverse_iterator(begin()); }
699
700 protected:
701 void ReadData(void* dst, std::size_t size) override {
702 if (position_ + size > this->buffer_size_) {
703 NNL_THROW(nnl::IOError(NNL_SRCTAG("Read exceeds buffer size")));
704 }
705 std::memcpy(dst, buffer_ptr_ + position_, size);
706 position_ += size;
707 }
708
709 private:
710 const u8* buffer_ptr_ = nullptr;
711 std::size_t buffer_size_ = 0;
712 std::size_t position_ = 0;
713};
714
725class BufferSpan final : public Reader, public Writer {
726 public:
727 using value_type = u8;
728 using iterator = value_type*;
729 using reverse_iterator = std::reverse_iterator<iterator>;
730
731 BufferSpan() noexcept {}
737 BufferSpan(void* buffer, std::size_t size) noexcept : buffer_ptr_(reinterpret_cast<u8*>(buffer)), buffer_size_(size) {
738 NNL_EXPECTS_DBG(buffer != nullptr || size == 0);
739 }
740
746 template <typename TContainer,
747 typename = std::enable_if_t<std::is_trivially_copyable_v<typename TContainer::value_type>>>
748 BufferSpan(TContainer& buffer) noexcept
749 : buffer_ptr_(reinterpret_cast<u8*>(buffer.data())),
750 buffer_size_(buffer.size() * sizeof(typename TContainer::value_type)) {}
751
752 void Seek(std::size_t offset) override { position_ = offset; }
753
754 std::size_t Tell() override { return position_; }
755
756 std::size_t Len() override { return buffer_size_; }
757
762 void Clear(u8 val = 0) {
763 if (buffer_ptr_ != nullptr) std::memset(buffer_ptr_, val, buffer_size_);
764 }
765
772 [[nodiscard]] BufferView SubView(std::size_t offset, std::size_t size) const {
773 NNL_EXPECTS(offset + size <= buffer_size_);
774
775 return BufferView(buffer_ptr_ + offset, size);
776 }
777
785 [[nodiscard]] BufferSpan SubSpan(std::size_t offset, std::size_t size) {
786 NNL_EXPECTS(offset + size <= buffer_size_);
787
788 return BufferSpan(buffer_ptr_ + offset, size);
789 }
790
791 Buffer CopyBuf() const {
792 std::vector<u8> copy(buffer_size_);
793 if (buffer_ptr_ != nullptr && buffer_size_ != 0) std::memcpy(copy.data(), buffer_ptr_, buffer_size_);
794 return copy;
795 }
796
800 operator BufferView() const noexcept { return BufferView(buffer_ptr_, buffer_size_); }
801
802 u8& operator[](std::size_t index) {
803 NNL_EXPECTS_DBG(index < Len());
804 return buffer_ptr_[index];
805 }
806
807 friend bool operator==(const BufferSpan& lhs, const BufferSpan& rhs) {
808 return (lhs.buffer_size_ == 0 && rhs.buffer_size_ == 0) ||
809 (lhs.buffer_size_ == rhs.buffer_size_ &&
810 std::memcmp(lhs.buffer_ptr_, rhs.buffer_ptr_, lhs.buffer_size_) == 0);
811 }
812
813 friend bool operator!=(const BufferSpan& lhs, const BufferSpan& rhs) { return !(lhs == rhs); }
814
815 std::size_t size() const noexcept { return buffer_size_; }
816
817 [[nodiscard]] std::size_t empty() const noexcept { return buffer_size_ == 0; }
822 u8* data() noexcept { return buffer_ptr_; }
823
824 u8& at(std::size_t index) {
825 NNL_EXPECTS(index < buffer_size_);
826 return buffer_ptr_[index];
827 }
828
829 u8& front() {
830 NNL_EXPECTS_DBG(buffer_size_ > 0);
831 return *begin();
832 }
833
834 u8& back() {
835 NNL_EXPECTS_DBG(buffer_size_ > 0);
836 return *rbegin();
837 }
838
839 iterator begin() noexcept { return buffer_ptr_; }
840
841 iterator end() noexcept { return buffer_ptr_ + buffer_size_; }
842
843 reverse_iterator rbegin() noexcept { return std::make_reverse_iterator(end()); }
844
845 reverse_iterator rend() noexcept { return std::make_reverse_iterator(begin()); }
846
847 protected:
848 void ReadData(void* dst, std::size_t size) override {
849 if (position_ + size > this->buffer_size_) {
850 NNL_THROW(nnl::IOError(NNL_SRCTAG("Read exceeds buffer size")));
851 }
852 std::memcpy(dst, buffer_ptr_ + position_, size);
853 position_ += size;
854 }
855
856 void WriteData(const void* src, std::size_t size) override {
857 if (position_ + size > this->buffer_size_) {
858 NNL_THROW(nnl::IOError(NNL_SRCTAG("Write exceeds buffer size")));
859 }
860 std::memcpy(buffer_ptr_ + position_, src, size);
861 position_ += size;
862 }
863
864 private:
865 u8* buffer_ptr_ = nullptr;
866 std::size_t buffer_size_ = 0;
867 std::size_t position_ = 0;
868};
869
878class BufferRW final : public Writer, public Reader {
879 public:
880 BufferRW() {}
881
882 BufferRW(const BufferRW& buf) : buffer_(buf.buffer_), position_(buf.position_) {}
883
884 BufferRW(BufferRW&& buf) noexcept : buffer_(std::move(buf.buffer_)), position_(buf.position_) { buf.position_ = 0; }
885
886 BufferRW(const Buffer& buf) : buffer_(buf) {}
887
888 BufferRW(Buffer&& buf) noexcept : buffer_(std::move(buf)) {}
889
890 BufferRW& operator=(const BufferRW& buf) {
891 if (this != &buf) {
892 buffer_ = buf.buffer_;
893 position_ = buf.position_;
894 }
895 return *this;
896 }
897
898 BufferRW& operator=(BufferRW&& buf) noexcept {
899 if (this != &buf) {
900 buffer_ = std::move(buf.buffer_);
901 position_ = buf.position_;
902 buf.position_ = 0;
903 }
904 return *this;
905 }
906
907 void Seek(std::size_t offset) override { position_ = offset; }
908
909 std::size_t Tell() override { return position_; }
910
911 std::size_t Len() override { return buffer_.size(); }
917 Buffer CopyBuf() const { return buffer_; }
918
924 [[nodiscard]] Buffer ReleaseBuf() noexcept {
925 position_ = 0;
926 return std::move(buffer_);
927 }
928
929 operator Buffer() const { return buffer_; }
930
939 operator Buffer&&() && noexcept {
940 position_ = 0;
941 return std::move(buffer_);
942 }
943
944 protected:
945 void WriteData(const void* src, std::size_t size) override {
946 if (position_ + size > buffer_.size()) buffer_.resize(position_ + size);
947
948 std::memcpy(buffer_.data() + position_, src, size);
949 position_ += size;
950 }
951
952 void ReadData(void* dst, std::size_t size) override {
953 if (position_ + size > this->buffer_.size()) {
954 NNL_THROW(nnl::IOError(NNL_SRCTAG("Read exceeds buffer size")));
955 }
956 std::memcpy(dst, buffer_.data() + position_, size);
957 position_ += size;
958 }
959
960 private:
961 Buffer buffer_;
962 std::size_t position_ = 0;
963};
964
966
967} // namespace nnl
Pointer-like object for storing stream positions.
Definition io.hpp:157
auto operator[](std::size_t index) const
Gets a reference to the element at the index relative to the current offset.
Definition io.hpp:198
auto operator->*(M A::*member) const
Gets a reference to a member of T (->)
Definition io.hpp:184
auto operator*() const
Gets a reference to T.
Definition io.hpp:173
Reference-like object for writing and reading data at memorized stream positions.
Definition io.hpp:284
Ref< M > operator[](std::size_t index) const
Creates an Ref to an element of the referenced C array.
Definition io.hpp:338
Ref< M > operator->*(M A::*member) const
Creates an Ref to a member of the referenced struct.
Definition io.hpp:327
void operator=(const T &value)
Assignment operator for writing the entire object.
Definition io.hpp:369
Defines the library-wide exception hierarchy and error handling macros.
Provides utility functions for filesystem operations.
Contains macros and definitions for fixed-width types.
#define NNL_EXPECTS_DBG(precondition)
Debug-only precondition check.
Definition contract.hpp:59
#define NNL_EXPECTS(precondition)
A precondition check.
Definition contract.hpp:45
Exception thrown for I/O like operations.
Definition exception.hpp:132
#define NNL_THROW(object)
Throws an exception or terminates the program if exceptions are disabled.
Definition exception.hpp:46
std::string u8string(const std::filesystem::path &path)
Converts a filesystem path to a UTF-8 string.
std::uint8_t u8
8-bit unsigned integer
Definition fixed_type.hpp:64
void Seek(std::size_t offset) override
Seeks to a specific offset in the data.
Definition io.hpp:543
void ClearState()
Clears any error flags on the file stream.
Definition io.hpp:493
std::size_t Tell() override
Gets the current position in the data.
Definition io.hpp:631
Offset< T > MakeOffsetLE()
Creates an Offset pointing to the current position.
Definition io.hpp:393
BufferView SubView(std::size_t offset, std::size_t size) const
Creates a read-only view into a subrange.
Definition io.hpp:772
void ReadData(void *dst, std::size_t size) override
Low-level data reading implementation.
Definition io.hpp:848
void WriteData(const void *src, std::size_t size) override
Low-level data writing implementation.
Definition io.hpp:856
std::size_t Tell() override
Gets the current position in the data.
Definition io.hpp:909
const u8 * data() const noexcept
Gets pointer to the underlying buffer.
Definition io.hpp:675
void ReadData(void *dst, std::size_t size) override
Low-level data reading implementation.
Definition io.hpp:952
virtual void WriteData(const void *src, std::size_t size)=0
Low-level data writing implementation.
BufferView SubView(std::size_t offset, std::size_t size) const
Creates a view into a subrange of the buffer.
Definition io.hpp:641
void WriteData(const void *src, std::size_t size) override
Low-level data writing implementation.
Definition io.hpp:564
BufferSpan(void *buffer, std::size_t size) noexcept
Constructs a BufferSpan from a pointer/size pair.
Definition io.hpp:737
void Seek(std::size_t offset) override
Seeks to a specific offset in the data.
Definition io.hpp:752
std::size_t Len() override
Gets the available length of the data.
Definition io.hpp:633
void ReadData(void *dst, std::size_t size) override
Low-level data reading implementation.
Definition io.hpp:503
std::size_t Len() override
Gets the available length of the data.
Definition io.hpp:756
void Clear(u8 val=0)
Clears the buffer with a specific value.
Definition io.hpp:762
std::size_t Len() override
Gets the available length of the data.
Definition io.hpp:489
virtual void ReadData(void *dst, std::size_t size)=0
Low-level data reading implementation.
void Seek(std::size_t offset) override
Seeks to a specific offset in the data.
Definition io.hpp:485
void AlignData(std::size_t multiple, unsigned char value=0)
Aligns the current position to a specified multiple.
Definition io.hpp:446
std::size_t Tell() override
Gets the current position in the data.
Definition io.hpp:487
Buffer ReleaseBuf() noexcept
Transfers the ownership of the internal buffer_.
Definition io.hpp:924
FileRW(const std::filesystem::path &path, bool truncate)
Constructs a FileRW from the specified file.
Definition io.hpp:530
void Seek(std::size_t offset) override
Seeks to a specific offset in the data.
Definition io.hpp:629
u8 * data() noexcept
Gets the pointer to the underlying buffer.
Definition io.hpp:822
virtual void Seek(std::size_t offset)=0
Seeks to a specific offset in the data.
BufferSpan SubSpan(std::size_t offset, std::size_t size)
Creates a mutable span into a subrange.
Definition io.hpp:785
void Close()
Closes the file.
Definition io.hpp:497
T ReadLE()
Reads a trivially copyable object.
Definition io.hpp:92
virtual std::size_t Tell()=0
Gets the current position in the data.
void Seek(std::size_t offset) override
Seeks to a specific offset in the data.
Definition io.hpp:907
std::size_t Tell() override
Gets the current position in the data.
Definition io.hpp:754
void ReadData(void *dst, std::size_t size) override
Low-level data reading implementation.
Definition io.hpp:701
virtual std::size_t Len()=0
Gets the available length of the data.
BufferView(const void *buffer, std::size_t size) noexcept
Constructs a BufferView from a pointer/size pair.
Definition io.hpp:613
BufferView(const TContainer &buffer) noexcept
Constructs a BufferView from a generic contiguous container.
Definition io.hpp:625
std::size_t Len() override
Gets the available length of the data.
Definition io.hpp:911
void ClearState()
Clears any error flags on the file stream.
Definition io.hpp:557
Offset< T > WriteArrayLE(const std::vector< T > &container)
Writes contents of a vector.
Definition io.hpp:431
void ReadBuf(void *dst, std::size_t size)
Reads a block of data into the specified destination.
Definition io.hpp:85
Buffer CopyBuf() const
Makes a copy of the data.
Definition io.hpp:917
void WriteData(const void *src, std::size_t size) override
Low-level data writing implementation.
Definition io.hpp:945
Offset< T > WriteLE(const T &value)
Writes a trivially copyable value.
Definition io.hpp:415
std::size_t Len() override
Gets the available length of the data.
Definition io.hpp:547
BufferSpan(TContainer &buffer) noexcept
Constructs a BufferView from a generic contiguous container.
Definition io.hpp:748
FileReader(const std::filesystem::path &path)
Constructs a FileReader from the specified file.
Definition io.hpp:475
void Close()
Closes the file.
Definition io.hpp:561
Offset< u8 > WriteBuf(const void *src, std::size_t size)
Writes raw binary data.
Definition io.hpp:402
void ReadData(void *dst, std::size_t size) override
Low-level data reading implementation.
Definition io.hpp:571
std::size_t Tell() override
Gets the current position in the data.
Definition io.hpp:545
std::vector< T > ReadArrayLE(std::size_t num_elements)
Reads multiple trivially copyable objects into a vector.
Definition io.hpp:107
Reader implementation for read-only memory buffers.
Definition io.hpp:598
Abstract class for writing data.
Definition io.hpp:136
Abstract class for reading data.
Definition io.hpp:78
Base interface for data reading/writing classes.
Definition io.hpp:51
std::vector< u8 > Buffer
A type alias for std::vector<u8> that denotes a raw, contiguous memory region that may be interpreted...
Definition io.hpp:40
T RoundNum(T number, std::size_t multiple)
Rounds number up to the nearest multiple.
Definition math.hpp:219
Provides various math utility functions.
Definition exception.hpp:56