4#include "Stroika/Foundation/Containers/Support/ReserveTweaks.h"
9namespace Stroika::Foundation::Streams::MemoryStream {
12 template <
typename ELEMENT_TYPE>
13 class Rep_ :
public InputOutputStream::IRep<ELEMENT_TYPE> {
15 using ElementType = ELEMENT_TYPE;
18 bool fOpenRead_{
true};
19 bool fOpenWrite_{
true};
23 : fReadCursor_{fData_.begin ()}
24 , fWriteCursor_{fData_.begin ()}
27 Rep_ (
const Rep_&) =
delete;
28 nonvirtual Rep_& operator= (
const Rep_&) =
delete;
30 virtual bool IsSeekable ()
const override
34 virtual void CloseWrite ()
override
38 Ensure (not IsOpenWrite ());
40 virtual bool IsOpenWrite ()
const override
44 virtual void CloseRead ()
override
48 Ensure (not IsOpenRead ());
50 virtual bool IsOpenRead ()
const override
54 virtual optional<size_t> AvailableToRead ()
override
56 Ensure (fData_.end () >= fReadCursor_);
57 return static_cast<size_t> (fData_.end () - fReadCursor_);
59 virtual optional<SeekOffsetType> RemainingLength ()
override
61 Ensure (fData_.end () >= fReadCursor_);
62 return static_cast<size_t> (fData_.end () - fReadCursor_);
64 virtual optional<span<ELEMENT_TYPE>> Read (span<ELEMENT_TYPE> intoBuffer, [[maybe_unused]] NoDataAvailableHandling blockFlag)
override
66 Require (IsOpenRead ());
67 Require (not intoBuffer.empty ());
68 size_t nRequested = intoBuffer.size ();
70 Assert ((fData_.begin () <= fReadCursor_) and (fReadCursor_ <= fData_.end ()));
71 size_t nAvail = fData_.end () - fReadCursor_;
72 size_t nCopied = min (nAvail, nRequested);
74 copy (fReadCursor_, fReadCursor_ + nCopied, intoBuffer.data ());
75 fReadCursor_ = fReadCursor_ + nCopied;
77 return intoBuffer.subspan (0, nCopied);
79 virtual void Write (span<const ELEMENT_TYPE> elts)
override
81 Require (not elts.empty ());
82 Require (IsOpenWrite ());
85 size_t roomLeft = fData_.end () - fWriteCursor_;
86 size_t roomRequired = elts.size ();
87 if (roomLeft < roomRequired) {
88 size_t curReadOffset = fReadCursor_ - fData_.begin ();
89 size_t curWriteOffset = fWriteCursor_ - fData_.begin ();
90 const size_t kChunkSize_ = 128;
91 Containers::Support::ReserveTweaks::Reserve4AddN (fData_, roomRequired - roomLeft, kChunkSize_);
92 fData_.resize (curWriteOffset + roomRequired);
93 fReadCursor_ = fData_.begin () + curReadOffset;
94 fWriteCursor_ = fData_.begin () + curWriteOffset;
95 Assert (fWriteCursor_ < fData_.end ());
97 copy (elts.data (), elts.data () + roomRequired, fWriteCursor_);
98 fWriteCursor_ += roomRequired;
99 Assert (fReadCursor_ < fData_.end ());
100 Assert (fWriteCursor_ <= fData_.end ());
102 virtual void Flush ()
override
104 Require (IsOpenWrite ());
110 Require (IsOpenRead ());
111 return fReadCursor_ - fData_.begin ();
113 virtual SeekOffsetType SeekRead (Whence whence, SignedSeekOffsetType offset)
override
116 Require (IsOpenRead ());
119 if (offset < 0) [[unlikely]] {
123 if (uOffset > fData_.size ()) [[unlikely]] {
126 fReadCursor_ = fData_.begin () +
static_cast<size_t> (uOffset);
129 Streams::SeekOffsetType curOffset = fReadCursor_ - fData_.begin ();
130 Streams::SignedSeekOffsetType newOffset = curOffset + offset;
131 if (newOffset < 0) [[unlikely]] {
135 if (uNewOffset > fData_.size ()) [[unlikely]] {
138 fReadCursor_ = fData_.begin () +
static_cast<size_t> (uNewOffset);
141 Streams::SignedSeekOffsetType newOffset = fData_.size () + offset;
142 if (newOffset < 0) [[unlikely]] {
146 if (uNewOffset > fData_.size ()) [[unlikely]] {
149 fReadCursor_ = fData_.begin () +
static_cast<size_t> (uNewOffset);
152 Ensure ((fData_.begin () <= fReadCursor_) and (fReadCursor_ <= fData_.end ()));
153 return fReadCursor_ - fData_.begin ();
158 Require (IsOpenWrite ());
159 return fWriteCursor_ - fData_.begin ();
161 virtual SeekOffsetType SeekWrite (Whence whence, SignedSeekOffsetType offset)
override
164 Require (IsOpenWrite ());
167 if (offset < 0) [[unlikely]] {
170 if (
static_cast<SeekOffsetType> (offset) > fData_.size ()) [[unlikely]] {
173 fWriteCursor_ = fData_.begin () +
static_cast<size_t> (offset);
176 Streams::SeekOffsetType curOffset = fWriteCursor_ - fData_.begin ();
177 Streams::SignedSeekOffsetType newOffset = curOffset + offset;
178 if (newOffset < 0) [[unlikely]] {
181 if (
static_cast<size_t> (newOffset) > fData_.size ()) [[unlikely]] {
184 fWriteCursor_ = fData_.begin () +
static_cast<size_t> (newOffset);
187 Streams::SignedSeekOffsetType newOffset = fData_.size () + offset;
188 if (newOffset < 0) [[unlikely]] {
191 if (
static_cast<size_t> (newOffset) > fData_.size ()) [[unlikely]] {
194 fWriteCursor_ = fData_.begin () +
static_cast<size_t> (newOffset);
197 Ensure ((fData_.begin () <= fWriteCursor_) and (fWriteCursor_ <= fData_.end ()));
198 return fWriteCursor_ - fData_.begin ();
200 vector<ElementType> AsVector ()
const
205 string AsString ()
const
218 static inline const auto kSeekException_ = range_error{
"seek"};
219 vector<ElementType> fData_;
220 typename vector<ElementType>::iterator fReadCursor_;
221 typename vector<ElementType>::iterator fWriteCursor_;
222 [[no_unique_address]] Debug::AssertExternallySynchronizedMutex fThisAssertExternallySynchronized_;
226 String MemStream2StringHelper_ (
const span<const byte>& s);
234 template <
typename ELEMENT_TYPE>
235 inline auto New () -> Ptr<ELEMENT_TYPE>
237 using MemoryStream::Private_::Rep_;
238 return Memory::MakeSharedPtr<Rep_<ELEMENT_TYPE>> ();
240 template <
typename ELEMENT_TYPE,
size_t EXTENT>
241 inline auto New (span<const ELEMENT_TYPE, EXTENT> copyFrom) -> Ptr<ELEMENT_TYPE>
243 using MemoryStream::Private_::Rep_;
244 Ptr r = Memory::MakeSharedPtr<Rep_<ELEMENT_TYPE>> ();
248 template <
typename ELEMENT_TYPE>
249 inline auto New (
const Memory::BLOB& copyFrom) -> Ptr<ELEMENT_TYPE>
250 requires (same_as<ELEMENT_TYPE, byte>)
252 using MemoryStream::Private_::Rep_;
253 Ptr r = Memory::MakeSharedPtr<Rep_<ELEMENT_TYPE>> ();
263 template <
typename ELEMENT_TYPE>
268 template <
typename ELEMENT_TYPE>
269 inline Ptr<ELEMENT_TYPE>::Ptr (
const shared_ptr<Private_::Rep_<ELEMENT_TYPE>>& from)
273 template <
typename ELEMENT_TYPE>
274 inline auto Ptr<ELEMENT_TYPE>::GetRepConstRef_ () const -> const Private_::Rep_<ELEMENT_TYPE>&
276 using Rep_ =
typename MemoryStream::Private_::Rep_<ELEMENT_TYPE>;
277 return *Debug::UncheckedDynamicCast<const Rep_*> (&inherited::GetRepConstRef ());
279 template <
typename ELEMENT_TYPE>
280 inline auto Ptr<ELEMENT_TYPE>::GetRepRWRef_ () const -> Private_::Rep_<ELEMENT_TYPE>&
282 using Rep_ =
typename MemoryStream::Private_::Rep_<ELEMENT_TYPE>;
283 return *Debug::UncheckedDynamicCast<Rep_*> (&inherited::GetRepRWRef ());
285 template <
typename ELEMENT_TYPE>
286 template <
typename T>
287 inline T Ptr<ELEMENT_TYPE>::As () const
288 requires (same_as<T, vector<ELEMENT_TYPE>> or (same_as<ELEMENT_TYPE,
byte> and (same_as<T, BLOB> or same_as<T,
string>)) or
289 (same_as<ELEMENT_TYPE, Character> and (same_as<T, String>)))
291 if constexpr (same_as<T, vector<ELEMENT_TYPE>>) {
292 return GetRepConstRef_ ().AsVector ();
294 else if constexpr (same_as<T, Memory::BLOB>) {
295 return GetRepConstRef_ ().AsVector ();
297 else if constexpr (same_as<T, string>) {
298 return GetRepConstRef_ ().AsString ();
300 else if constexpr (same_as<T, String>) {
301 auto tmp = GetRepConstRef_ ().AsVector ();
302 return String{span{tmp}};
305 template <
typename ELEMENT_TYPE>
308 return Private_::MemStream2StringHelper_ (GetRepConstRef_ ().AsVector ());
311 template <
typename ELEMENT_TYPE>
312 [[deprecated (
"Since Stroika v3.0d5 use span interface")]]
static Ptr<ELEMENT_TYPE> New (
const ELEMENT_TYPE* start,
const ELEMENT_TYPE* end)
314 return Memory::MakeSharedPtr<Private_::Rep_<ELEMENT_TYPE>> (start, end);
String is like std::u32string, except it is much easier to use, often much more space efficient,...
shared_lock< const AssertExternallySynchronizedMutex > ReadContext
Instantiate AssertExternallySynchronizedMutex::ReadContext to designate an area of code where protect...
unique_lock< AssertExternallySynchronizedMutex > WriteContext
Instantiate AssertExternallySynchronizedMutex::WriteContext to designate an area of code where protec...
CONTAINER::value_type * End(CONTAINER &c)
For a contiguous container (such as a vector or basic_string) - find the pointer to the end of the co...
CONTAINER::value_type * Start(CONTAINER &c)
For a contiguous container (such as a vector or basic_string) - find the pointer to the start of the ...
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...