StormByte C++ Library: Buffer module 0.0.9999
StormByte-Buffer is a StormByte library module for handling buffers
Loading...
Searching...
No Matches
generic.hxx
1#pragma once
2
3#include <StormByte/buffer/typedefs.hxx>
4
5#include <algorithm>
6#include <iterator>
7#include <ranges>
8#include <type_traits>
9#include <string_view>
10#include <utility>
11
19namespace StormByte::Buffer {
28 class STORMBYTE_BUFFER_PUBLIC Generic {
29 public:
33 Generic() noexcept = default;
34
39 inline Generic(const DataType& data) noexcept: m_buffer(data) {}
40
45 inline Generic(DataType&& data) noexcept: m_buffer(std::move(data)) {}
46
50 Generic(const Generic&) noexcept = default;
51
55 Generic(Generic&&) noexcept = default;
56
60 virtual ~Generic() noexcept = 0;
61
65 Generic& operator=(const Generic& other) = default;
66
70 Generic& operator=(Generic&&) noexcept = default;
71
72 protected:
73 DataType m_buffer;
74
83 template<std::ranges::input_range Src>
84 requires (!std::is_class_v<std::remove_cv_t<std::ranges::range_value_t<Src>>>) &&
85 requires(std::ranges::range_value_t<Src> v) { static_cast<std::byte>(v); }
86 static DataType DataConvert(const Src& src) noexcept {
87 DataType out;
88 if constexpr (requires { std::ranges::size(src); }) {
89 auto s = std::ranges::size(src);
90 if (s > 0) out.reserve(static_cast<typename DataType::size_type>(s));
91 }
92 std::transform(std::ranges::begin(src), std::ranges::end(src), std::back_inserter(out),
93 [] (auto&& e) noexcept { return static_cast<std::byte>(e); });
94 return out;
95 }
96
97 template<std::ranges::input_range Src>
98 requires (!std::is_class_v<std::remove_cv_t<std::ranges::range_value_t<Src>>>) &&
99 requires(std::ranges::range_value_t<Src> v) { static_cast<std::byte>(v); }
100 static DataType DataConvert(Src&& src) noexcept {
101 using Dec = std::remove_cvref_t<Src>;
102 if constexpr (std::same_as<Dec, DataType>) {
103 return std::move(src);
104 } else {
105 DataType out;
106 if constexpr (requires { std::ranges::size(src); }) {
107 auto s = std::ranges::size(src);
108 if (s > 0) out.reserve(static_cast<typename DataType::size_type>(s));
109 }
110 std::transform(std::ranges::begin(src), std::ranges::end(src), std::back_inserter(out),
111 [] (auto&& e) noexcept { return static_cast<std::byte>(e); });
112 return out;
113 }
114 }
115
119 static DataType DataConvert(std::string_view sv) noexcept {
120 DataType out;
121 if (!sv.empty()) out.reserve(static_cast<typename DataType::size_type>(sv.size()));
122 std::transform(sv.begin(), sv.end(), std::back_inserter(out), [] (char c) noexcept { return static_cast<std::byte>(c); });
123 return out;
124 }
125
129 static DataType DataConvert(const char* s) noexcept {
130 if (!s) return DataType{};
131 return DataConvert(std::string_view(s));
132 }
133 };
134
135 class WriteOnly; // Forward declaration
136
146 class STORMBYTE_BUFFER_PUBLIC ReadOnly: virtual public Generic {
147 public:
151 inline ReadOnly() noexcept: Generic() {};
152
157 inline ReadOnly(const DataType& data) noexcept: Generic(data) {}
158
163 inline ReadOnly(DataType&& data) noexcept: Generic(std::move(data)) {}
164
168 ReadOnly(const ReadOnly&) noexcept = default;
169
173 ReadOnly(ReadOnly&&) noexcept = default;
174
178 virtual ~ReadOnly() noexcept = default;
179
183 ReadOnly& operator=(const ReadOnly&) = default;
184
188 ReadOnly& operator=(ReadOnly&&) noexcept = default;
189
194 virtual std::size_t AvailableBytes() const noexcept = 0;
195
200 virtual void Clean() noexcept = 0;
201
208 virtual void Clear() noexcept = 0;
209
214 virtual const DataType& Data() const noexcept {
215 return m_buffer;
216 }
217
223 virtual bool Drop(const std::size_t& count) noexcept = 0;
224
230 virtual bool Empty() const noexcept = 0;
231
238 virtual bool EoF() const noexcept = 0;
239
247 inline virtual bool Extract(const std::size_t& count, DataType& outBuffer) noexcept = 0;
248
255 inline bool Extract(DataType& outBuffer) noexcept {
256 return Extract(0, outBuffer);
257 }
258
265 inline virtual bool Extract(const std::size_t& count, WriteOnly& outBuffer) noexcept = 0;
266
272 inline bool Extract(WriteOnly& outBuffer) noexcept {
273 return Extract(0, outBuffer);
274 }
275
280 virtual void ExtractUntilEoF(DataType& outBuffer) noexcept = 0;
281
287 virtual void ExtractUntilEoF(WriteOnly& outBuffer) noexcept = 0;
288
293 virtual bool IsReadable() const noexcept = 0;
294
312 virtual bool Peek(const std::size_t& count, DataType& outBuffer) const noexcept = 0;
313
331 virtual bool Peek(const std::size_t& count, WriteOnly& outBuffer) const noexcept = 0;
332
339 virtual bool Read(const std::size_t& count, DataType& outBuffer) const noexcept = 0;
340
346 inline bool Read(DataType& outBuffer) const noexcept {
347 return Read(0, outBuffer);
348 }
349
356 virtual bool Read(const std::size_t& count, WriteOnly& outBuffer) const noexcept = 0;
357
363 inline bool Read(WriteOnly& outBuffer) const noexcept {
364 return Read(0, outBuffer);
365 }
366
371 virtual void ReadUntilEoF(DataType& outBuffer) const noexcept = 0;
372
378 virtual void ReadUntilEoF(WriteOnly& outBuffer) const noexcept = 0;
379
389 virtual void Seek(const std::ptrdiff_t& offset, const Position& mode) const noexcept = 0;
390
396 virtual std::size_t Size() const noexcept = 0;
397 };
398
408 class STORMBYTE_BUFFER_PUBLIC WriteOnly: virtual public Generic {
409 public:
413 inline WriteOnly() noexcept: Generic() {};
414
419 inline WriteOnly(const DataType& data) noexcept: Generic(data) {}
420
425 inline WriteOnly(DataType&& data) noexcept: Generic(std::move(data)) {}
426
430 WriteOnly(const WriteOnly&) = default;
431
435 WriteOnly(WriteOnly&&) noexcept = default;
436
440 virtual ~WriteOnly() noexcept = default;
441
445 WriteOnly& operator=(const WriteOnly&) = default;
446
450 WriteOnly& operator=(WriteOnly&&) noexcept = default;
451
456 virtual bool IsWritable() const noexcept = 0;
457
467 virtual bool Write(const std::size_t& count, const DataType& data) noexcept = 0;
468
485 bool Write(std::string_view sv) noexcept {
486 DataType tmp;
487 if (!sv.empty()) tmp.reserve(static_cast<typename DataType::size_type>(sv.size()));
488 std::transform(sv.begin(), sv.end(), std::back_inserter(tmp), [] (char e) noexcept { return static_cast<std::byte>(e); });
489 return Write(static_cast<std::size_t>(tmp.size()), std::move(tmp));
490 }
491
495 bool Write(const char* s) noexcept {
496 if (!s) return Write(DataType{});
497 return Write(std::string_view(s));
498 }
499
503 bool Write(const std::size_t& count, std::string_view sv) noexcept {
504 size_t to_write = (count == 0) ? static_cast<size_t>(sv.size()) : std::min(count, static_cast<std::size_t>(sv.size()));
505 DataType tmp;
506 if (to_write > 0) tmp.reserve(static_cast<typename DataType::size_type>(to_write));
507 std::transform(sv.begin(), sv.begin() + to_write, std::back_inserter(tmp), [] (char e) noexcept { return static_cast<std::byte>(e); });
508 return Write(static_cast<std::size_t>(to_write), std::move(tmp));
509 }
510
514 bool Write(const std::size_t& count, const char* s) noexcept {
515 if (!s) return Write(count, DataType{});
516 return Write(count, std::string_view(s));
517 }
518
522 template<std::size_t N>
523 bool Write(const char (&s)[N]) noexcept {
524 // N includes the terminating NUL for string literals, so exclude it
525 if (N == 0) return Write(DataType{});
526 return Write(std::string_view(s, (N > 0) ? (N - 1) : 0));
527 }
528
539 template<std::ranges::input_range R>
540 requires (!std::is_class_v<std::remove_cv_t<std::ranges::range_value_t<R>>>) &&
541 requires(std::ranges::range_value_t<R> v) { static_cast<std::byte>(v); }
542 bool Write(const R& r) noexcept {
543 DataType tmp;
544 if constexpr (requires(DataType& d, typename DataType::size_type n) { d.reserve(n); }) {
545 auto dist = std::ranges::distance(r);
546 if (dist > 0) tmp.reserve(static_cast<typename DataType::size_type>(dist));
547 }
548 std::transform(std::ranges::begin(r), std::ranges::end(r), std::back_inserter(tmp),
549 [] (auto&& e) noexcept { return static_cast<std::byte>(e); });
550 return Write(static_cast<std::size_t>(tmp.size()), std::move(tmp));
551 }
552
564 template<std::ranges::input_range Rw>
565 requires (!std::is_class_v<std::remove_cv_t<std::ranges::range_value_t<Rw>>>) &&
566 requires(std::ranges::range_value_t<Rw> v) { static_cast<std::byte>(v); }
567 bool Write(const std::size_t& count, const Rw& r) noexcept {
568 if (count == 0) return Write(r);
569 DataType tmp;
570 if constexpr (requires(DataType& d, typename DataType::size_type n) { d.reserve(n); }) {
571 auto dist = std::ranges::distance(r);
572 if (dist > 0) tmp.reserve(static_cast<typename DataType::size_type>(std::min(dist, static_cast<decltype(dist)>(count))));
573 }
574 auto it = std::ranges::begin(r);
575 auto end = std::ranges::end(r);
576 std::size_t written = 0;
577 for (; it != end && written < count; ++it, ++written) {
578 tmp.push_back(static_cast<std::byte>(*it));
579 }
580 return Write(static_cast<std::size_t>(written), std::move(tmp));
581 }
582
594 template<std::ranges::input_range Rrw>
595 requires (!std::is_class_v<std::remove_cv_t<std::ranges::range_value_t<Rrw>>>) &&
596 requires(std::ranges::range_value_t<Rrw> v) { static_cast<std::byte>(v); }
597 bool Write(const std::size_t& count, Rrw&& r) noexcept {
598 using Dec = std::remove_cvref_t<Rrw>;
599 if (count == 0) return Write(std::forward<Rrw>(r));
600 if constexpr (std::same_as<Dec, DataType>) {
601 // r is DataType; we can move and resize if needed
602 DataType tmp = std::move(r);
603 if (tmp.size() > count) tmp.resize(count);
604 return Write(static_cast<std::size_t>(tmp.size()), std::move(tmp));
605 } else {
606 DataType tmp;
607 if constexpr (requires(DataType& d, typename DataType::size_type n) { d.reserve(n); }) {
608 auto dist = std::ranges::distance(r);
609 if (dist > 0) tmp.reserve(static_cast<typename DataType::size_type>(std::min(dist, static_cast<decltype(dist)>(count))));
610 }
611 auto it = std::ranges::begin(r);
612 auto end = std::ranges::end(r);
613 std::size_t written = 0;
614 for (; it != end && written < count; ++it, ++written) {
615 tmp.push_back(static_cast<std::byte>(*it));
616 }
617 return Write(static_cast<std::size_t>(written), std::move(tmp));
618 }
619 }
620
630 template<std::ranges::input_range Rr>
631 requires (!std::is_class_v<std::remove_cv_t<std::ranges::range_value_t<Rr>>>) &&
632 requires(std::ranges::range_value_t<Rr> v) { static_cast<std::byte>(v); }
633 bool Write(Rr&& r) noexcept {
634 using Dec = std::remove_cvref_t<Rr>;
635 if constexpr (std::same_as<Dec, DataType>) {
636 // r is already the library DataType (std::vector<std::byte>), forward to move overload
637 return Write(static_cast<std::size_t>(r.size()), std::move(r));
638 } else {
639 DataType tmp;
640 if constexpr (requires(DataType& d, typename DataType::size_type n) { d.reserve(n); }) {
641 auto dist = std::ranges::distance(r);
642 if (dist > 0) tmp.reserve(static_cast<typename DataType::size_type>(dist));
643 }
644 std::transform(std::ranges::begin(r), std::ranges::end(r), std::back_inserter(tmp),
645 [] (auto&& e) noexcept { return static_cast<std::byte>(e); });
646 return Write(static_cast<std::size_t>(tmp.size()), std::move(tmp));
647 }
648 }
649
664 template<std::input_iterator I, std::sentinel_for<I> S>
665 requires (!std::is_class_v<std::remove_cv_t<std::iter_value_t<I>>>) &&
666 requires(std::iter_value_t<I> v) { static_cast<std::byte>(v); }
667 bool Write(I first, S last) noexcept {
668 DataType tmp;
669 std::transform(first, last, std::back_inserter(tmp), [] (auto&& e) noexcept { return static_cast<std::byte>(e); });
670 return Write(static_cast<std::size_t>(tmp.size()), std::move(tmp));
671 }
672
686 template<std::input_iterator I2, std::sentinel_for<I2> S2>
687 requires (!std::is_class_v<std::remove_cv_t<std::iter_value_t<I2>>>) &&
688 requires(std::iter_value_t<I2> v) { static_cast<std::byte>(v); }
689 bool Write(const std::size_t& count, I2 first, S2 last) noexcept {
690 if (count == 0) return Write(first, last);
691 DataType tmp;
692 std::size_t written = 0;
693 for (; first != last && written < count; ++first, ++written) {
694 tmp.push_back(static_cast<std::byte>(*first));
695 }
696 return Write(static_cast<std::size_t>(written), std::move(tmp));
697 }
698
708 virtual bool Write(const std::size_t& count, DataType&& data) noexcept = 0;
709
719 virtual bool Write(const std::size_t& count, const ReadOnly& data) noexcept = 0;
720
729 inline bool Write(const ReadOnly& data) noexcept {
730 return Write(data.AvailableBytes(), data);
731 }
732
742 virtual bool Write(const std::size_t& count, ReadOnly&& data) noexcept = 0;
743
752 inline bool Write(ReadOnly&& data) noexcept {
753 return Write(data.AvailableBytes(), std::move(data));
754 }
755 };
756
765 class STORMBYTE_BUFFER_PUBLIC ReadWrite: public ReadOnly, public WriteOnly {
766 public:
770 inline ReadWrite() noexcept: Generic() {};
771
776 inline ReadWrite(const DataType& data) noexcept: Generic(data) {}
777
782 inline ReadWrite(DataType&& data) noexcept: Generic(std::move(data)) {}
783
787 ReadWrite(const ReadWrite& other) noexcept = default;
788
792 ReadWrite(ReadWrite&& other) noexcept = default;
793
797 virtual ~ReadWrite() noexcept = default;
798
802 ReadWrite& operator=(const ReadWrite& other) = default;
803
807 ReadWrite& operator=(ReadWrite&& other) noexcept = default;
808 };
809}
Generic class to maintain common API guarantees across buffer types.
Definition generic.hxx:28
Generic(DataType &&data) noexcept
Construct Generic with initial data using move semantics.
Definition generic.hxx:45
Generic(const Generic &) noexcept=default
Copy construct deleted.
static DataType DataConvert(const Src &src) noexcept
Convert various source types into the library DataType.
Definition generic.hxx:86
Generic(Generic &&) noexcept=default
Move construct deleted.
static DataType DataConvert(const char *s) noexcept
Convert a null-terminated C string to DataType.
Definition generic.hxx:129
Generic() noexcept=default
Construct Generic.
static DataType DataConvert(std::string_view sv) noexcept
Convert a std::string_view to DataType.
Definition generic.hxx:119
Generic class providing a buffer that can be read but not written to.
Definition generic.hxx:146
ReadOnly(ReadOnly &&) noexcept=default
Move construct deleted.
virtual bool IsReadable() const noexcept=0
Check if the buffer is readable.
virtual void ExtractUntilEoF(WriteOnly &outBuffer) noexcept=0
Read all bytes until end-of-file into a WriteOnly buffer.
virtual bool Extract(const std::size_t &count, WriteOnly &outBuffer) noexcept=0
Destructive read that removes data from the buffer into a FIFO.
ReadOnly(const DataType &data) noexcept
Construct ReadOnly.
Definition generic.hxx:157
virtual bool Empty() const noexcept=0
Check if the buffer is empty.
virtual void ExtractUntilEoF(DataType &outBuffer) noexcept=0
Read all bytes until end-of-file into an existing buffer.
ReadOnly(const ReadOnly &) noexcept=default
Copy construct deleted.
virtual bool Read(const std::size_t &count, WriteOnly &outBuffer) const noexcept=0
Read bytes into a WriteOnly buffer.
virtual bool Drop(const std::size_t &count) noexcept=0
Drop bytes in the buffer.
virtual std::size_t Size() const noexcept=0
Get the current number of bytes stored in the buffer.
bool Read(WriteOnly &outBuffer) const noexcept
Read bytes into a WriteOnly buffer.
Definition generic.hxx:363
virtual void Seek(const std::ptrdiff_t &offset, const Position &mode) const noexcept=0
Move the read position for non-destructive reads.
ReadOnly() noexcept
Construct ReadOnly.
Definition generic.hxx:151
bool Extract(WriteOnly &outBuffer) noexcept
Destructive read that removes all data from the buffer into a FIFO.
Definition generic.hxx:272
virtual void ReadUntilEoF(DataType &outBuffer) const noexcept=0
Read all bytes until end-of-file into an existing buffer.
ReadOnly(DataType &&data) noexcept
Construct ReadOnly with initial data using move semantics.
Definition generic.hxx:163
virtual void ReadUntilEoF(WriteOnly &outBuffer) const noexcept=0
Read all bytes until end-of-file into a WriteOnly buffer.
Generic class providing a buffer that can be both read from and written to.
Definition generic.hxx:765
ReadWrite() noexcept
Construct ReadWrite.
Definition generic.hxx:770
ReadWrite(DataType &&data) noexcept
Construct ReadWrite with initial data using move semantics.
Definition generic.hxx:782
ReadWrite(const ReadWrite &other) noexcept=default
Copy construct deleted.
ReadWrite(ReadWrite &&other) noexcept=default
Move construct deleted.
ReadWrite(const DataType &data) noexcept
Construct ReadWrite.
Definition generic.hxx:776
virtual ~ReadWrite() noexcept=default
Virtual destructor.
Generic class providing a buffer that can be written to but not read from.
Definition generic.hxx:408
WriteOnly(const WriteOnly &)=default
Copy construct deleted.
bool Write(const R &r) noexcept
Write all elements from an input range to the buffer.
Definition generic.hxx:542
bool Write(const std::size_t &count, I2 first, S2 last) noexcept
Write up-to count bytes from an iterator pair (0 => all available).
Definition generic.hxx:689
bool Write(const std::size_t &count, const char *s) noexcept
Write up-to count bytes from a C string pointer (null-terminated).
Definition generic.hxx:514
bool Write(const char *s) noexcept
Write from a C string pointer (null-terminated). Uses std::string_view.
Definition generic.hxx:495
bool Write(I first, S last) noexcept
Write from iterator pair whose value_type is convertible to std::byte.
Definition generic.hxx:667
WriteOnly(DataType &&data) noexcept
Construct WriteOnly with initial data using move semantics.
Definition generic.hxx:425
WriteOnly(const DataType &data) noexcept
Construct WriteOnly.
Definition generic.hxx:419
bool Write(const std::size_t &count, std::string_view sv) noexcept
Write up-to count bytes from a string view (0 => all available).
Definition generic.hxx:503
virtual bool Write(const std::size_t &count, ReadOnly &&data) noexcept=0
Move bytes from a vector to the buffer.
bool Write(const char(&s)[N]) noexcept
Write from a string literal (array) and avoid copying the trailing NUL.
Definition generic.hxx:523
virtual bool Write(const std::size_t &count, DataType &&data) noexcept=0
Move bytes from a vector to the buffer.
bool Write(ReadOnly &&data) noexcept
Move bytes from a vector to the buffer.
Definition generic.hxx:752
virtual bool Write(const std::size_t &count, const ReadOnly &data) noexcept=0
Write bytes from a vector to the buffer.
bool Write(const ReadOnly &data) noexcept
Write bytes from a vector to the buffer.
Definition generic.hxx:729
WriteOnly() noexcept
Construct WriteOnly.
Definition generic.hxx:413
bool Write(const std::size_t &count, const Rw &r) noexcept
Write up-to count elements from an input range.
Definition generic.hxx:567
WriteOnly(WriteOnly &&) noexcept=default
Move construct deleted.
bool Write(Rr &&r) noexcept
Write from an rvalue input range.
Definition generic.hxx:633
bool Write(const std::size_t &count, Rrw &&r) noexcept
Write up-to count elements from an rvalue range.
Definition generic.hxx:597