Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
InputStreamFromStdIStream.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
6#include "Stroika/Foundation/Execution/Exceptions.h"
7#include "Stroika/Foundation/Execution/Throw.h"
8
9namespace Stroika::Foundation::Streams::iostream::InputStreamFromStdIStream {
10
11 namespace Private_ {
12 template <typename ELEMENT_TYPE, typename BASIC_ISTREAM_ELEMENT_TYPE, typename BASIC_ISTREAM_TRAITS_TYPE>
13 class Rep_ : public InputStream::IRep<ELEMENT_TYPE> {
14 private:
15 bool fOpen_{true};
16
17 public:
18 Rep_ (basic_istream<BASIC_ISTREAM_ELEMENT_TYPE, BASIC_ISTREAM_TRAITS_TYPE>& originalStream)
19 : Rep_{originalStream, eSeekable}
20 {
21 }
22 Rep_ (basic_istream<BASIC_ISTREAM_ELEMENT_TYPE, BASIC_ISTREAM_TRAITS_TYPE>& originalStream, SeekableFlag seekable)
23 : fOriginalStreamRef_{originalStream}
24 , fSeekable_{seekable}
25 {
26 }
27
28 protected:
29 virtual bool IsSeekable () const override
30 {
31 return fSeekable_ == eSeekable;
32 }
33 virtual void CloseRead () override
34 {
35 fOpen_ = false;
36 Ensure (not IsOpenRead ());
37 }
38 virtual bool IsOpenRead () const override
39 {
40 return fOpen_;
41 }
42 virtual optional<size_t> AvailableToRead () override
43 {
44 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
45 streamsize sz = fOriginalStreamRef_.rdbuf ()->in_avail ();
46 // http://en.cppreference.com/w/cpp/io/basic_streambuf/in_avail
47 if (sz == 0) {
48 return nullopt;
49 }
50 else if (sz == -1) {
51 return 0;
52 }
53 return static_cast<size_t> (sz);
54 }
55 virtual optional<SeekOffsetType> RemainingLength () override
56 {
57 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
58 Require (IsOpenRead ());
60 return nullopt; // pretty easy, but @todo
61 }
62 virtual optional<span<ELEMENT_TYPE>> Read (span<ELEMENT_TYPE> intoBuffer, NoDataAvailableHandling blockFlag) override
63 {
64 Require (not intoBuffer.empty ());
65 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
66 Require (IsOpenRead ());
67 if (fOriginalStreamRef_.eof ()) {
68 return span<ELEMENT_TYPE>{};
69 }
70 if (blockFlag == NoDataAvailableHandling::eDontBlock and AvailableToRead () == nullopt) {
71 return nullopt;
72 }
73 size_t maxToRead = intoBuffer.size ();
74 fOriginalStreamRef_.clear (); // clear any failures before read - it will report if a failure found
75 fOriginalStreamRef_.read (reinterpret_cast<BASIC_ISTREAM_ELEMENT_TYPE*> (intoBuffer.data ()), maxToRead);
76 size_t n = static_cast<size_t> (fOriginalStreamRef_.gcount ()); // cast safe cuz amount asked to read was also size_t
77 Assert (n <= maxToRead);
78 // apparently based on http://www.cplusplus.com/reference/iostream/istream/read/ EOF sets the EOF bit AND the fail bit
79 if (not fOriginalStreamRef_.eof () and fOriginalStreamRef_.fail ()) [[unlikely]] {
80 static const Execution::RuntimeErrorException kException_{"Failed to read from istream"sv};
81 Execution::Throw (kException_);
82 }
83 return intoBuffer.subspan (0, n);
84 }
85 virtual SeekOffsetType GetReadOffset () const override
86 {
87 // instead of tellg () - avoids issue with EOF where fail bit set???
88 Debug::AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
89 Require (IsOpenRead ());
90 return fOriginalStreamRef_.rdbuf ()->pubseekoff (0, ios_base::cur, ios_base::in);
91 }
92 virtual SeekOffsetType SeekRead (Whence whence, SignedSeekOffsetType offset) override
93 {
94 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
95 Require (IsOpenRead ());
96 fOriginalStreamRef_.clear (); // in case we hit eof (causing fail) - eof gets cleared by seeking, but not failbit - it appears...--LGP 2024-02-11
97 switch (whence) {
98 case eFromStart:
99 fOriginalStreamRef_.seekg (offset, ios::beg);
100 break;
101 case eFromCurrent:
102 fOriginalStreamRef_.seekg (offset, ios::cur);
103 break;
104 case eFromEnd:
105 fOriginalStreamRef_.seekg (offset, ios::end);
106 break;
107 }
108 // instead of tellg () - avoids issue with EOF where fail bit set???
109 return fOriginalStreamRef_.rdbuf ()->pubseekoff (0, ios_base::cur, ios_base::in);
110 }
111
112 private:
113 basic_istream<BASIC_ISTREAM_ELEMENT_TYPE, BASIC_ISTREAM_TRAITS_TYPE>& fOriginalStreamRef_;
114 SeekableFlag fSeekable_;
115 [[no_unique_address]] Debug::AssertExternallySynchronizedMutex fThisAssertExternallySynchronized_;
116 };
117 }
118
119 /*
120 ********************************************************************************
121 ***************** InputStreamFromStdIStream<ELEMENT_TYPE>::New *****************
122 ********************************************************************************
123 */
124 template <typename ELEMENT_TYPE, typename BASIC_ISTREAM_ELEMENT_TYPE, typename BASIC_ISTREAM_TRAITS_TYPE>
125 inline auto New (basic_istream<BASIC_ISTREAM_ELEMENT_TYPE, BASIC_ISTREAM_TRAITS_TYPE>& originalStream) -> Ptr<ELEMENT_TYPE>
126 requires ((same_as<ELEMENT_TYPE, byte> and same_as<BASIC_ISTREAM_ELEMENT_TYPE, char>) or
127 (same_as<ELEMENT_TYPE, Characters::Character> and same_as<BASIC_ISTREAM_ELEMENT_TYPE, wchar_t>))
128 {
129 return Ptr<ELEMENT_TYPE>{make_shared<Private_::Rep_<ELEMENT_TYPE, BASIC_ISTREAM_ELEMENT_TYPE, BASIC_ISTREAM_TRAITS_TYPE>> (originalStream)};
130 }
131 template <typename ELEMENT_TYPE, typename BASIC_ISTREAM_ELEMENT_TYPE, typename BASIC_ISTREAM_TRAITS_TYPE>
132 inline auto New (basic_istream<BASIC_ISTREAM_ELEMENT_TYPE, BASIC_ISTREAM_TRAITS_TYPE>& originalStream, SeekableFlag seekable) -> Ptr<ELEMENT_TYPE>
133 requires ((same_as<ELEMENT_TYPE, byte> and same_as<BASIC_ISTREAM_ELEMENT_TYPE, char>) or
134 (same_as<ELEMENT_TYPE, Characters::Character> and same_as<BASIC_ISTREAM_ELEMENT_TYPE, wchar_t>))
135 {
136 return Ptr<ELEMENT_TYPE>{
137 make_shared<Private_::Rep_<ELEMENT_TYPE, BASIC_ISTREAM_ELEMENT_TYPE, BASIC_ISTREAM_TRAITS_TYPE>> (originalStream, seekable)};
138 }
139 template <typename ELEMENT_TYPE, typename BASIC_ISTREAM_ELEMENT_TYPE, typename BASIC_ISTREAM_TRAITS_TYPE>
140 inline auto New (Execution::InternallySynchronized internallySynchronized,
141 basic_istream<BASIC_ISTREAM_ELEMENT_TYPE, BASIC_ISTREAM_TRAITS_TYPE>& originalStream) -> Ptr<ELEMENT_TYPE>
142 requires ((same_as<ELEMENT_TYPE, byte> and same_as<BASIC_ISTREAM_ELEMENT_TYPE, char>) or
143 (same_as<ELEMENT_TYPE, Characters::Character> and same_as<BASIC_ISTREAM_ELEMENT_TYPE, wchar_t>))
144 {
145 switch (internallySynchronized) {
146 case Execution::eInternallySynchronized:
147 return InternallySynchronizedInputStream::New<Private_::Rep_<ELEMENT_TYPE, BASIC_ISTREAM_ELEMENT_TYPE, BASIC_ISTREAM_TRAITS_TYPE>> (
148 {}, originalStream);
149 case Execution::eNotKnownInternallySynchronized:
150 return New<ELEMENT_TYPE> (originalStream);
151 default:
153 return nullptr;
154 }
155 }
156 template <typename ELEMENT_TYPE, typename BASIC_ISTREAM_ELEMENT_TYPE, typename BASIC_ISTREAM_TRAITS_TYPE>
157 inline auto New (Execution::InternallySynchronized internallySynchronized,
158 basic_istream<BASIC_ISTREAM_ELEMENT_TYPE, BASIC_ISTREAM_TRAITS_TYPE>& originalStream, SeekableFlag seekable) -> Ptr<ELEMENT_TYPE>
159 requires ((same_as<ELEMENT_TYPE, byte> and same_as<BASIC_ISTREAM_ELEMENT_TYPE, char>) or
160 (same_as<ELEMENT_TYPE, Characters::Character> and same_as<BASIC_ISTREAM_ELEMENT_TYPE, wchar_t>))
161 {
162 switch (internallySynchronized) {
163 case Execution::eInternallySynchronized:
164 return InternallySynchronizedInputStream::New<Private_::Rep_<ELEMENT_TYPE, BASIC_ISTREAM_ELEMENT_TYPE, BASIC_ISTREAM_TRAITS_TYPE>> (
165 {}, originalStream);
166 case Execution::eNotKnownInternallySynchronized:
167 return New<ELEMENT_TYPE> (originalStream, seekable);
168 default:
170 return nullptr;
171 }
172 }
173
174}
#define AssertNotImplemented()
Definition Assertions.h:401
#define RequireNotReached()
Definition Assertions.h:385
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...
InputStream<>::Ptr is Smart pointer (with abstract Rep) class defining the interface to reading from ...
A Streams::Ptr<ELEMENT_TYPE> is a smart-pointer to a stream of elements of type T.
Definition Stream.h:170
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...
Definition Throw.inl:43