4#include "Stroika/Foundation/Containers/Support/ReserveTweaks.h"
8namespace Stroika::Foundation::Streams::MemoryStream {
11 template <
typename ELEMENT_TYPE>
12 class Rep_ :
public InputOutputStream::IRep<ELEMENT_TYPE> {
14 using ElementType = ELEMENT_TYPE;
17 bool fOpenRead_{
true};
18 bool fOpenWrite_{
true};
22 : fReadCursor_{fData_.begin ()}
23 , fWriteCursor_{fData_.begin ()}
26 Rep_ (
const Rep_&) =
delete;
27 nonvirtual Rep_& operator= (
const Rep_&) =
delete;
29 virtual bool IsSeekable ()
const override
33 virtual void CloseWrite ()
override
37 Ensure (not IsOpenWrite ());
39 virtual bool IsOpenWrite ()
const override
43 virtual void CloseRead ()
override
47 Ensure (not IsOpenRead ());
49 virtual bool IsOpenRead ()
const override
53 virtual optional<size_t> AvailableToRead ()
override
55 Ensure (fData_.end () >= fReadCursor_);
56 return static_cast<size_t> (fData_.end () - fReadCursor_);
58 virtual optional<SeekOffsetType> RemainingLength ()
override
60 Ensure (fData_.end () >= fReadCursor_);
61 return static_cast<size_t> (fData_.end () - fReadCursor_);
63 virtual optional<span<ELEMENT_TYPE>> Read (span<ELEMENT_TYPE> intoBuffer, [[maybe_unused]] NoDataAvailableHandling blockFlag)
override
65 Require (IsOpenRead ());
66 Require (not intoBuffer.empty ());
67 size_t nRequested = intoBuffer.size ();
69 Assert ((fData_.begin () <= fReadCursor_) and (fReadCursor_ <= fData_.end ()));
70 size_t nAvail = fData_.end () - fReadCursor_;
71 size_t nCopied = min (nAvail, nRequested);
73 copy (fReadCursor_, fReadCursor_ + nCopied, intoBuffer.data ());
74 fReadCursor_ = fReadCursor_ + nCopied;
76 return intoBuffer.subspan (0, nCopied);
78 virtual void Write (span<const ELEMENT_TYPE> elts)
override
80 Require (not elts.empty ());
81 Require (IsOpenWrite ());
84 size_t roomLeft = fData_.end () - fWriteCursor_;
85 size_t roomRequired = elts.size ();
86 if (roomLeft < roomRequired) {
87 size_t curReadOffset = fReadCursor_ - fData_.begin ();
88 size_t curWriteOffset = fWriteCursor_ - fData_.begin ();
89 const size_t kChunkSize_ = 128;
90 Containers::Support::ReserveTweaks::Reserve4AddN (fData_, roomRequired - roomLeft, kChunkSize_);
91 fData_.resize (curWriteOffset + roomRequired);
92 fReadCursor_ = fData_.begin () + curReadOffset;
93 fWriteCursor_ = fData_.begin () + curWriteOffset;
94 Assert (fWriteCursor_ < fData_.end ());
96 copy (elts.data (), elts.data () + roomRequired, fWriteCursor_);
97 fWriteCursor_ += roomRequired;
98 Assert (fReadCursor_ < fData_.end ());
99 Assert (fWriteCursor_ <= fData_.end ());
101 virtual void Flush ()
override
103 Require (IsOpenWrite ());
109 Require (IsOpenRead ());
110 return fReadCursor_ - fData_.begin ();
112 virtual SeekOffsetType SeekRead (Whence whence, SignedSeekOffsetType offset)
override
115 Require (IsOpenRead ());
118 if (offset < 0) [[unlikely]] {
122 if (uOffset > fData_.size ()) [[unlikely]] {
125 fReadCursor_ = fData_.begin () +
static_cast<size_t> (uOffset);
128 Streams::SeekOffsetType curOffset = fReadCursor_ - fData_.begin ();
129 Streams::SignedSeekOffsetType newOffset = curOffset + offset;
130 if (newOffset < 0) [[unlikely]] {
134 if (uNewOffset > fData_.size ()) [[unlikely]] {
137 fReadCursor_ = fData_.begin () +
static_cast<size_t> (uNewOffset);
140 Streams::SignedSeekOffsetType newOffset = fData_.size () + offset;
141 if (newOffset < 0) [[unlikely]] {
145 if (uNewOffset > fData_.size ()) [[unlikely]] {
148 fReadCursor_ = fData_.begin () +
static_cast<size_t> (uNewOffset);
151 Ensure ((fData_.begin () <= fReadCursor_) and (fReadCursor_ <= fData_.end ()));
152 return fReadCursor_ - fData_.begin ();
157 Require (IsOpenWrite ());
158 return fWriteCursor_ - fData_.begin ();
160 virtual SeekOffsetType SeekWrite (Whence whence, SignedSeekOffsetType offset)
override
163 Require (IsOpenWrite ());
166 if (offset < 0) [[unlikely]] {
169 if (
static_cast<SeekOffsetType> (offset) > fData_.size ()) [[unlikely]] {
172 fWriteCursor_ = fData_.begin () +
static_cast<size_t> (offset);
175 Streams::SeekOffsetType curOffset = fWriteCursor_ - fData_.begin ();
176 Streams::SignedSeekOffsetType newOffset = curOffset + offset;
177 if (newOffset < 0) [[unlikely]] {
180 if (
static_cast<size_t> (newOffset) > fData_.size ()) [[unlikely]] {
183 fWriteCursor_ = fData_.begin () +
static_cast<size_t> (newOffset);
186 Streams::SignedSeekOffsetType newOffset = fData_.size () + offset;
187 if (newOffset < 0) [[unlikely]] {
190 if (
static_cast<size_t> (newOffset) > fData_.size ()) [[unlikely]] {
193 fWriteCursor_ = fData_.begin () +
static_cast<size_t> (newOffset);
196 Ensure ((fData_.begin () <= fWriteCursor_) and (fWriteCursor_ <= fData_.end ()));
197 return fWriteCursor_ - fData_.begin ();
199 vector<ElementType> AsVector ()
const
204 string AsString ()
const
217 static inline const auto kSeekException_ = range_error{
"seek"};
218 vector<ElementType> fData_;
219 typename vector<ElementType>::iterator fReadCursor_;
220 typename vector<ElementType>::iterator fWriteCursor_;
221 [[no_unique_address]] Debug::AssertExternallySynchronizedMutex fThisAssertExternallySynchronized_;
225 String MemStream2StringHelper_ (
const span<const byte>& s);
233 template <
typename ELEMENT_TYPE>
234 inline auto New () -> Ptr<ELEMENT_TYPE>
236 using MemoryStream::Private_::Rep_;
237 return make_shared<Rep_<ELEMENT_TYPE>> ();
239 template <
typename ELEMENT_TYPE,
size_t EXTENT>
240 inline auto New (span<const ELEMENT_TYPE, EXTENT> copyFrom) -> Ptr<ELEMENT_TYPE>
242 using MemoryStream::Private_::Rep_;
243 Ptr r = make_shared<Rep_<ELEMENT_TYPE>> ();
247 template <
typename ELEMENT_TYPE>
248 inline auto New (
const Memory::BLOB& copyFrom) -> Ptr<ELEMENT_TYPE>
249 requires (same_as<ELEMENT_TYPE, byte>)
251 using MemoryStream::Private_::Rep_;
252 Ptr r = make_shared<Rep_<ELEMENT_TYPE>> ();
262 template <
typename ELEMENT_TYPE>
267 template <
typename ELEMENT_TYPE>
268 inline Ptr<ELEMENT_TYPE>::Ptr (
const shared_ptr<Private_::Rep_<ELEMENT_TYPE>>& from)
272 template <
typename ELEMENT_TYPE>
273 inline auto Ptr<ELEMENT_TYPE>::GetRepConstRef_ () const -> const Private_::Rep_<ELEMENT_TYPE>&
275 using Rep_ =
typename MemoryStream::Private_::Rep_<ELEMENT_TYPE>;
276 return *Debug::UncheckedDynamicCast<const Rep_*> (&inherited::GetRepConstRef ());
278 template <
typename ELEMENT_TYPE>
279 inline auto Ptr<ELEMENT_TYPE>::GetRepRWRef_ () const -> Private_::Rep_<ELEMENT_TYPE>&
281 using Rep_ =
typename MemoryStream::Private_::Rep_<ELEMENT_TYPE>;
282 return *Debug::UncheckedDynamicCast<Rep_*> (&inherited::GetRepRWRef ());
284 template <
typename ELEMENT_TYPE>
285 template <
typename T>
286 inline T Ptr<ELEMENT_TYPE>::As () const
287 requires (same_as<T, vector<ELEMENT_TYPE>> or (same_as<ELEMENT_TYPE,
byte> and (same_as<T, BLOB> or same_as<T,
string>)) or
288 (same_as<ELEMENT_TYPE, Character> and (same_as<T, String>)))
290 if constexpr (same_as<T, vector<ELEMENT_TYPE>>) {
291 return GetRepConstRef_ ().AsVector ();
293 else if constexpr (same_as<T, Memory::BLOB>) {
294 return GetRepConstRef_ ().AsVector ();
296 else if constexpr (same_as<T, string>) {
297 return GetRepConstRef_ ().AsString ();
299 else if constexpr (same_as<T, String>) {
300 auto tmp = GetRepConstRef_ ().AsVector ();
301 return String{span{tmp}};
304 template <
typename ELEMENT_TYPE>
307 return Private_::MemStream2StringHelper_ (GetRepConstRef_ ().AsVector ());
310 template <
typename ELEMENT_TYPE>
311 [[deprecated (
"Since Stroika v3.0d5 use span interface")]]
static Ptr<ELEMENT_TYPE> New (
const ELEMENT_TYPE* start,
const ELEMENT_TYPE* end)
313 return make_shared<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...