StormByte C++ Library: Buffer module 1.2.0
StormByte-Buffer is the buffer module of the StormByte C++ suite.
Loading...
Searching...
No Matches
generic.hxx
Go to the documentation of this file.
1/*
2 * Copyright (C) 2024-2026 David C. Manuelda (StormBytePP)
3 *
4 * This file is part of StormByte-Buffer.
5 *
6 * StormByte-Buffer is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License version 3
8 * or later, as published by the Free Software Foundation.
9 *
10 * StormByte-Buffer is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with StormByte-Buffer. If not, see
17 * <https://www.gnu.org/licenses/lgpl-3.0.html>.
18 */
19
20#pragma once
21
23#include <StormByte/type_traits.hxx>
24
25#include <algorithm>
26#include <iterator>
27#include <ranges>
28#include <type_traits>
29#include <string_view>
30#include <utility>
31
36namespace StormByte::Buffer {
49 public:
55 Generic() noexcept = default;
56
58 Generic(const Generic&) noexcept = default;
59
61 Generic(Generic&&) noexcept = default;
62
66 virtual ~Generic() noexcept = 0;
67
69 Generic& operator=(const Generic& other) = default;
70
72 Generic& operator=(Generic&&) noexcept = default;
75 protected:
93 template<Type::ByteInputRange Src>
94 static DataType DataConvert(const Src& src) noexcept {
95 DataType out;
96 if constexpr (requires { std::ranges::size(src); }) {
97 auto s = std::ranges::size(src);
98 if (s > 0) out.reserve(static_cast<typename DataType::size_type>(s));
99 }
100 std::transform(std::ranges::begin(src), std::ranges::end(src), std::back_inserter(out),
101 [] (auto&& e) noexcept { return static_cast<std::byte>(e); });
102 return out;
103 }
104
111 template<Type::ByteInputRange Src>
112 static DataType DataConvert(Src&& src) noexcept {
113 if constexpr (Type::SameAs<Src, DataType>) {
114 return std::move(src);
115 } else {
116 DataType out;
117 if constexpr (requires { std::ranges::size(src); }) {
118 auto s = std::ranges::size(src);
119 if (s > 0) out.reserve(static_cast<typename DataType::size_type>(s));
120 }
121 std::transform(std::ranges::begin(src), std::ranges::end(src), std::back_inserter(out),
122 [] (auto&& e) noexcept { return static_cast<std::byte>(e); });
123 return out;
124 }
125 }
126
132 static DataType DataConvert(std::string_view sv) noexcept {
133 DataType out;
134 if (!sv.empty()) out.reserve(static_cast<typename DataType::size_type>(sv.size()));
135 std::transform(sv.begin(), sv.end(), std::back_inserter(out),
136 [] (char c) noexcept { return static_cast<std::byte>(c); });
137 return out;
138 }
139
145 static DataType DataConvert(const char* s) noexcept {
146 if (!s) return DataType{};
147 return DataConvert(std::string_view(s));
148 }
149
151 };
152
153 class WriteOnly; // Forward declaration
154
165 public:
171 inline ReadOnly() noexcept: Generic() {}
172
174 ReadOnly(const ReadOnly&) noexcept = default;
175
177 ReadOnly(ReadOnly&&) noexcept = default;
178
180 virtual ~ReadOnly() noexcept;
181
183 ReadOnly& operator=(const ReadOnly&) = default;
184
186 ReadOnly& operator=(ReadOnly&&) noexcept = default;
198 virtual std::size_t AvailableBytes() const noexcept = 0;
199
204 virtual const DataType& Data() const noexcept = 0;
205
211 virtual bool Empty() const noexcept = 0;
212
217 virtual bool EoF() const noexcept = 0;
218
223 virtual bool IsReadable() const noexcept = 0;
224
230 virtual std::size_t Size() const noexcept = 0;
231
243 virtual void Clean() noexcept = 0;
244
250 virtual void Clear() noexcept = 0;
251
258 virtual bool Drop(const std::size_t& count) noexcept = 0;
259
267 virtual void Seek(const std::ptrdiff_t& offset, const Position& mode) const noexcept = 0;
268
282 inline virtual bool Extract(const std::size_t& count, DataType& outBuffer) noexcept = 0;
283
289 inline bool Extract(DataType& outBuffer) noexcept {
290 return Extract(0, outBuffer);
291 }
292
299 inline virtual bool Extract(const std::size_t& count, WriteOnly& outBuffer) noexcept = 0;
300
306 inline bool Extract(WriteOnly& outBuffer) noexcept {
307 return Extract(0, outBuffer);
308 }
309
314 virtual void ExtractUntilEoF(DataType& outBuffer) noexcept = 0;
315
320 virtual void ExtractUntilEoF(WriteOnly& outBuffer) noexcept = 0;
321
341 virtual bool Peek(const std::size_t& count, DataType& outBuffer) const noexcept = 0;
342
352 virtual bool Peek(const std::size_t& count, WriteOnly& outBuffer) const noexcept = 0;
353
367 virtual bool Read(const std::size_t& count, DataType& outBuffer) const noexcept = 0;
368
374 inline bool Read(DataType& outBuffer) const noexcept {
375 return Read(0, outBuffer);
376 }
377
384 virtual bool Read(const std::size_t& count, WriteOnly& outBuffer) const noexcept = 0;
385
391 inline bool Read(WriteOnly& outBuffer) const noexcept {
392 return Read(0, outBuffer);
393 }
394
399 virtual void ReadUntilEoF(DataType& outBuffer) const noexcept = 0;
400
405 virtual void ReadUntilEoF(WriteOnly& outBuffer) const noexcept = 0;
406
408 };
409
421 public:
427 inline WriteOnly() noexcept: Generic() {}
428
430 WriteOnly(const WriteOnly&) = default;
431
433 WriteOnly(WriteOnly&&) noexcept = default;
434
436 virtual ~WriteOnly() noexcept;
437
439 WriteOnly& operator=(const WriteOnly&) = default;
440
442 WriteOnly& operator=(WriteOnly&&) noexcept = default;
454 virtual bool IsWritable() const noexcept = 0;
455
461 virtual void Close() noexcept = 0;
462
467 virtual void SetError() noexcept = 0;
468
483 virtual bool Write(const std::size_t& count, const DataType& data) noexcept = 0;
484
492 virtual bool Write(const std::size_t& count, DataType&& data) noexcept = 0;
493
501 virtual bool Write(const std::size_t& count, const ReadOnly& data) noexcept = 0;
502
510 virtual bool Write(const std::size_t& count, ReadOnly&& data) noexcept = 0;
511
524 inline bool Write(const ReadOnly& data) noexcept {
525 return Write(data.AvailableBytes(), data);
526 }
527
533 inline bool Write(ReadOnly&& data) noexcept {
534 return Write(data.AvailableBytes(), std::move(data));
535 }
536
551 bool Write(std::string_view sv) noexcept {
552 DataType tmp;
553 if (!sv.empty()) tmp.reserve(static_cast<typename DataType::size_type>(sv.size()));
554 std::transform(sv.begin(), sv.end(), std::back_inserter(tmp),
555 [] (char e) noexcept { return static_cast<std::byte>(e); });
556 return Write(static_cast<std::size_t>(tmp.size()), std::move(tmp));
557 }
558
564 bool Write(const char* s) noexcept {
565 if (!s) return Write(DataType{});
566 return Write(std::string_view(s));
567 }
568
575 bool Write(const std::size_t& count, std::string_view sv) noexcept {
576 size_t to_write = (count == 0) ? static_cast<size_t>(sv.size())
577 : std::min(count, static_cast<std::size_t>(sv.size()));
578 DataType tmp;
579 if (to_write > 0) tmp.reserve(static_cast<typename DataType::size_type>(to_write));
580 std::transform(sv.begin(), sv.begin() + to_write, std::back_inserter(tmp),
581 [] (char e) noexcept { return static_cast<std::byte>(e); });
582 return Write(static_cast<std::size_t>(to_write), std::move(tmp));
583 }
584
591 bool Write(const std::size_t& count, const char* s) noexcept {
592 if (!s) return Write(count, DataType{});
593 return Write(count, std::string_view(s));
594 }
595
602 template<std::size_t N>
603 bool Write(const char (&s)[N]) noexcept {
604 if (N == 0) return Write(DataType{});
605 return Write(std::string_view(s, (N > 0) ? (N - 1) : 0));
606 }
607
621 template<Type::ByteInputRange R>
622 bool Write(const R& r) noexcept {
623 DataType tmp;
624 if constexpr (requires(DataType& d, typename DataType::size_type n) { d.reserve(n); }) {
625 auto dist = std::ranges::distance(r);
626 if (dist > 0) tmp.reserve(static_cast<typename DataType::size_type>(dist));
627 }
628 std::transform(std::ranges::begin(r), std::ranges::end(r), std::back_inserter(tmp),
629 [] (auto&& e) noexcept { return static_cast<std::byte>(e); });
630 return Write(static_cast<std::size_t>(tmp.size()), std::move(tmp));
631 }
632
640 template<Type::ByteInputRange Rw>
641 bool Write(const std::size_t& count, const Rw& r) noexcept {
642 if (count == 0) return Write(r);
643 DataType tmp;
644 if constexpr (requires(DataType& d, typename DataType::size_type n) { d.reserve(n); }) {
645 auto dist = std::ranges::distance(r);
646 if (dist > 0)
647 tmp.reserve(static_cast<typename DataType::size_type>(
648 std::min(dist, static_cast<decltype(dist)>(count))));
649 }
650 auto it = std::ranges::begin(r);
651 auto end = std::ranges::end(r);
652 std::size_t written = 0;
653 for (; it != end && written < count; ++it, ++written) {
654 tmp.push_back(static_cast<std::byte>(*it));
655 }
656 return Write(static_cast<std::size_t>(written), std::move(tmp));
657 }
658
666 template<Type::ByteInputRange Rrw>
667 bool Write(const std::size_t& count, Rrw&& r) noexcept {
668 if (count == 0) return Write(std::forward<Rrw>(r));
669 if constexpr (Type::SameAs<Rrw, DataType>) {
670 DataType tmp = std::move(r);
671 if (tmp.size() > count) tmp.resize(count);
672 return Write(static_cast<std::size_t>(tmp.size()), std::move(tmp));
673 } else {
674 DataType tmp;
675 if constexpr (requires(DataType& d, typename DataType::size_type n) { d.reserve(n); }) {
676 auto dist = std::ranges::distance(r);
677 if (dist > 0)
678 tmp.reserve(static_cast<typename DataType::size_type>(
679 std::min(dist, static_cast<decltype(dist)>(count))));
680 }
681 auto it = std::ranges::begin(r);
682 auto end = std::ranges::end(r);
683 std::size_t written = 0;
684 for (; it != end && written < count; ++it, ++written) {
685 tmp.push_back(static_cast<std::byte>(*it));
686 }
687 return Write(static_cast<std::size_t>(written), std::move(tmp));
688 }
689 }
690
697 template<Type::ByteInputRange Rr>
698 bool Write(Rr&& r) noexcept {
699 if constexpr (Type::SameAs<Rr, DataType>) {
700 return Write(static_cast<std::size_t>(r.size()), std::move(r));
701 } else {
702 DataType tmp;
703 if constexpr (requires(DataType& d, typename DataType::size_type n) { d.reserve(n); }) {
704 auto dist = std::ranges::distance(r);
705 if (dist > 0) tmp.reserve(static_cast<typename DataType::size_type>(dist));
706 }
707 std::transform(std::ranges::begin(r), std::ranges::end(r), std::back_inserter(tmp),
708 [] (auto&& e) noexcept { return static_cast<std::byte>(e); });
709 return Write(static_cast<std::size_t>(tmp.size()), std::move(tmp));
710 }
711 }
712
721 template<Type::ByteInputIterator I, typename S>
722 requires Type::SentinelFor<S, I>
723 bool Write(I first, S last) noexcept {
724 DataType tmp;
725 std::transform(first, last, std::back_inserter(tmp),
726 [] (auto&& e) noexcept { return static_cast<std::byte>(e); });
727 return Write(static_cast<std::size_t>(tmp.size()), std::move(tmp));
728 }
729
739 template<Type::ByteInputIterator I2, typename S2>
740 requires Type::SentinelFor<S2, I2>
741 bool Write(const std::size_t& count, I2 first, S2 last) noexcept {
742 if (count == 0) return Write(first, last);
743 DataType tmp;
744 std::size_t written = 0;
745 for (; first != last && written < count; ++first, ++written) {
746 tmp.push_back(static_cast<std::byte>(*first));
747 }
748 return Write(static_cast<std::size_t>(written), std::move(tmp));
749 }
750
752 };
753
763 public:
769 inline ReadWrite() noexcept: Generic() {}
770
772 ReadWrite(const ReadWrite& other) noexcept = default;
773
775 ReadWrite(ReadWrite&& other) noexcept = default;
776
778 virtual ~ReadWrite() noexcept;
779
781 ReadWrite& operator=(const ReadWrite& other) = default;
782
784 ReadWrite& operator=(ReadWrite&& other) noexcept = default;
786 };
787}
Pure abstract root of the buffer interface hierarchy.
Definition generic.hxx:48
static DataType DataConvert(Src &&src) noexcept
Convert an rvalue input range to DataType (moves when already DataType).
Definition generic.hxx:112
static DataType DataConvert(const char *s) noexcept
Convert a null-terminated C string to DataType.
Definition generic.hxx:145
Generic() noexcept=default
Default construct.
static DataType DataConvert(std::string_view sv) noexcept
Convert a string view to DataType (no trailing NUL).
Definition generic.hxx:132
Pure interface for a buffer that can be read but not written.
Definition generic.hxx:164
ReadOnly(ReadOnly &&) noexcept=default
Move construct.
virtual void ExtractUntilEoF(WriteOnly &outBuffer) noexcept=0
Extract until EoF into a WriteOnly.
virtual bool Extract(const std::size_t &count, WriteOnly &outBuffer) noexcept=0
Extract bytes into a WriteOnly.
virtual void ExtractUntilEoF(DataType &outBuffer) noexcept=0
Extract until EoF into a DataType.
ReadOnly(const ReadOnly &) noexcept=default
Copy construct.
virtual bool Read(const std::size_t &count, WriteOnly &outBuffer) const noexcept=0
Read into a WriteOnly.
virtual bool Read(const std::size_t &count, DataType &outBuffer) const noexcept=0
Read into a DataType.
bool Read(WriteOnly &outBuffer) const noexcept
Read all available bytes into a WriteOnly.
Definition generic.hxx:391
bool Read(DataType &outBuffer) const noexcept
Read all available bytes into a DataType.
Definition generic.hxx:374
ReadOnly() noexcept
Default construct.
Definition generic.hxx:171
bool Extract(WriteOnly &outBuffer) noexcept
Extract all available bytes into a WriteOnly.
Definition generic.hxx:306
virtual void ReadUntilEoF(DataType &outBuffer) const noexcept=0
Read until EoF into a DataType.
virtual bool Peek(const std::size_t &count, WriteOnly &outBuffer) const noexcept=0
Peek into a WriteOnly without advancing the read position.
virtual bool Peek(const std::size_t &count, DataType &outBuffer) const noexcept=0
Peek into a DataType without advancing the read position.
virtual void ReadUntilEoF(WriteOnly &outBuffer) const noexcept=0
Read until EoF into a WriteOnly.
Pure interface combining ReadOnly and WriteOnly.
Definition generic.hxx:762
ReadWrite() noexcept
Default construct.
Definition generic.hxx:769
ReadWrite(const ReadWrite &other) noexcept=default
Copy construct.
ReadWrite(ReadWrite &&other) noexcept=default
Move construct.
virtual ~ReadWrite() noexcept
Virtual destructor.
Pure interface for a buffer that can be written but not read.
Definition generic.hxx:420
WriteOnly(const WriteOnly &)=default
Copy construct.
bool Write(const std::size_t &count, const char *s) noexcept
Write up to count characters from a C string.
Definition generic.hxx:591
bool Write(const char *s) noexcept
Write a null-terminated C string.
Definition generic.hxx:564
bool Write(const std::size_t &count, std::string_view sv) noexcept
Write up to count characters from a string view.
Definition generic.hxx:575
bool Write(const std::size_t &count, I2 first, S2 last) noexcept
Write up to count elements from an iterator pair.
Definition generic.hxx:741
bool Write(const char(&s)[N]) noexcept
Write a string literal without the trailing NUL.
Definition generic.hxx:603
bool Write(const std::size_t &count, Rrw &&r) noexcept
Write up to count elements from an rvalue range.
Definition generic.hxx:667
bool Write(ReadOnly &&data) noexcept
Append all available bytes from a ReadOnly (move path).
Definition generic.hxx:533
bool Write(Rr &&r) noexcept
Write all elements from an rvalue range.
Definition generic.hxx:698
WriteOnly() noexcept
Default construct.
Definition generic.hxx:427
WriteOnly(WriteOnly &&) noexcept=default
Move construct.
bool Write(std::string_view sv) noexcept
Write a string view (no trailing NUL).
Definition generic.hxx:551
bool Write(const std::size_t &count, const Rw &r) noexcept
Write up to count elements from an input range.
Definition generic.hxx:641
bool Write(const R &r) noexcept
Write all elements from an input range.
Definition generic.hxx:622
bool Write(I first, S last) noexcept
Write all elements from an iterator pair.
Definition generic.hxx:723
Buffer module of the StormByte suite.
std::vector< std::byte > DataType
Primary byte storage type used throughout the buffer API.
Definition typedefs.hxx:62
Position
Forward declaration of the WriteOnly interface.
Definition typedefs.hxx:50
#define STORMBYTE_BUFFER_PUBLIC
Definition visibility.h:28