7#include "Stroika/Foundation/Execution/Exceptions.h"
8#include "Stroika/Foundation/Execution/Throw.h"
13namespace Stroika::Foundation::Streams::iostream::InputStreamFromStdIStream {
16 template <
typename ELEMENT_TYPE,
typename BASIC_ISTREAM_ELEMENT_TYPE,
typename BASIC_ISTREAM_TRAITS_TYPE>
17 class Rep_ :
public InputStream::IRep<ELEMENT_TYPE> {
23 static constexpr bool kTranscodes =
sizeof (ELEMENT_TYPE) !=
sizeof (BASIC_ISTREAM_ELEMENT_TYPE);
29 Rep_ (basic_istream<BASIC_ISTREAM_ELEMENT_TYPE, BASIC_ISTREAM_TRAITS_TYPE>& originalStream)
30 : Rep_{originalStream, kTranscodes ? eNotSeekable : eSeekable}
33 Rep_ (basic_istream<BASIC_ISTREAM_ELEMENT_TYPE, BASIC_ISTREAM_TRAITS_TYPE>& originalStream, SeekableFlag seekable)
34 : fOriginalStreamRef_{originalStream}
35 , fSeekable_{seekable}
37 Require (not kTranscodes or seekable == eNotSeekable);
41 virtual bool IsSeekable ()
const override
43 return fSeekable_ == eSeekable;
45 virtual void CloseRead ()
override
48 Ensure (not IsOpenRead ());
50 virtual bool IsOpenRead ()
const override
54 virtual optional<size_t> AvailableToRead ()
override
57 streamsize sz = fOriginalStreamRef_.rdbuf ()->in_avail ();
65 if constexpr (kTranscodes) {
67 return sz == 1 ? nullopt : optional<size_t>{
static_cast<size_t> (sz) / 2};
69 return static_cast<size_t> (sz);
71 virtual optional<SeekOffsetType> RemainingLength ()
override
74 Require (IsOpenRead ());
75 if constexpr (kTranscodes) {
81 virtual optional<span<ELEMENT_TYPE>> Read (span<ELEMENT_TYPE> intoBuffer, NoDataAvailableHandling blockFlag)
override
83 Require (not intoBuffer.empty ());
85 Require (IsOpenRead ());
86 if (fOriginalStreamRef_.eof ()) {
87 return span<ELEMENT_TYPE>{};
89 if (blockFlag == NoDataAvailableHandling::eDontBlock and AvailableToRead () == nullopt) {
92 if constexpr (kTranscodes) {
95 Memory::StackBuffer<BASIC_ISTREAM_ELEMENT_TYPE> units{Memory::eUninitialized, intoBuffer.size () + 1};
96 size_t n = ReadElements_ (span{units}.subspan (0, intoBuffer.size ()));
97 if (n != 0 and Characters::Character::IsSurrogatePair_Hi (
static_cast<char16_t> (units[n - 1]))) {
98 n += ReadElements_ (span{units}.subspan (n, 1));
100 Memory::StackBuffer<ELEMENT_TYPE> characters{
101 Memory::eUninitialized, Characters::UTFConvert::ComputeTargetBufferSize<ELEMENT_TYPE, BASIC_ISTREAM_ELEMENT_TYPE> (n)};
102 span<ELEMENT_TYPE> converted =
104 Assert (converted.size () <= intoBuffer.size ());
105 std::copy (converted.begin (), converted.end (), intoBuffer.begin ());
106 fOffset_ += converted.size ();
107 return intoBuffer.subspan (0, converted.size ());
110 return intoBuffer.subspan (
111 0, ReadElements_ (span{
reinterpret_cast<BASIC_ISTREAM_ELEMENT_TYPE*
> (intoBuffer.data ()), intoBuffer.size ()}));
117 Require (IsOpenRead ());
118 if constexpr (kTranscodes) {
123 return fOriginalStreamRef_.rdbuf ()->pubseekoff (0, ios_base::cur, ios_base::in);
126 virtual SeekOffsetType SeekRead (Whence whence, SignedSeekOffsetType offset)
override
129 Require (IsOpenRead ());
130 Require (IsSeekable ());
131 fOriginalStreamRef_.clear ();
134 fOriginalStreamRef_.seekg (offset, ios::beg);
137 fOriginalStreamRef_.seekg (offset, ios::cur);
140 fOriginalStreamRef_.seekg (offset, ios::end);
144 return fOriginalStreamRef_.rdbuf ()->pubseekoff (0, ios_base::cur, ios_base::in);
149 size_t ReadElements_ (span<BASIC_ISTREAM_ELEMENT_TYPE> into)
151 fOriginalStreamRef_.clear ();
152 fOriginalStreamRef_.read (into.data (), into.size ());
153 size_t n =
static_cast<size_t> (fOriginalStreamRef_.gcount ());
154 Assert (n <= into.size ());
156 if (not fOriginalStreamRef_.eof () and fOriginalStreamRef_.fail ()) [[unlikely]] {
157 static const Execution::Exception<runtime_error> kException_{
"Failed to read from istream"sv};
164 basic_istream<BASIC_ISTREAM_ELEMENT_TYPE, BASIC_ISTREAM_TRAITS_TYPE>& fOriginalStreamRef_;
176 template <
typename ELEMENT_TYPE,
typename BASIC_ISTREAM_ELEMENT_TYPE,
typename BASIC_ISTREAM_TRAITS_TYPE>
177 inline auto New (basic_istream<BASIC_ISTREAM_ELEMENT_TYPE, BASIC_ISTREAM_TRAITS_TYPE>& originalStream) ->
Ptr<ELEMENT_TYPE>
178 requires ((same_as<ELEMENT_TYPE, byte> and same_as<BASIC_ISTREAM_ELEMENT_TYPE, char>) or
179 (same_as<ELEMENT_TYPE, Characters::Character> and same_as<BASIC_ISTREAM_ELEMENT_TYPE, wchar_t>))
181 return New<ELEMENT_TYPE> (originalStream, eSeekable);
183 template <
typename ELEMENT_TYPE,
typename BASIC_ISTREAM_ELEMENT_TYPE,
typename BASIC_ISTREAM_TRAITS_TYPE>
184 inline auto New (basic_istream<BASIC_ISTREAM_ELEMENT_TYPE, BASIC_ISTREAM_TRAITS_TYPE>& originalStream,
SeekableFlag seekable) ->
Ptr<ELEMENT_TYPE>
185 requires ((same_as<ELEMENT_TYPE, byte> and same_as<BASIC_ISTREAM_ELEMENT_TYPE, char>) or
186 (same_as<ELEMENT_TYPE, Characters::Character> and same_as<BASIC_ISTREAM_ELEMENT_TYPE, wchar_t>))
188 using Rep = Private_::Rep_<ELEMENT_TYPE, BASIC_ISTREAM_ELEMENT_TYPE, BASIC_ISTREAM_TRAITS_TYPE>;
189 if constexpr (Rep::kTranscodes) {
190 Ptr<ELEMENT_TYPE> unseekable{Memory::MakeSharedPtr<Rep> (originalStream, eNotSeekable)};
191 if (seekable == eSeekable) {
192 return BufferedInputStream::New<ELEMENT_TYPE> (unseekable, eSeekable);
197 return Ptr<ELEMENT_TYPE>{Memory::MakeSharedPtr<Rep> (originalStream, seekable)};
200 template <
typename ELEMENT_TYPE,
typename BASIC_ISTREAM_ELEMENT_TYPE,
typename BASIC_ISTREAM_TRAITS_TYPE>
202 basic_istream<BASIC_ISTREAM_ELEMENT_TYPE, BASIC_ISTREAM_TRAITS_TYPE>& originalStream) -> Ptr<ELEMENT_TYPE>
203 requires ((same_as<ELEMENT_TYPE, byte> and same_as<BASIC_ISTREAM_ELEMENT_TYPE, char>) or
204 (same_as<ELEMENT_TYPE, Characters::Character> and same_as<BASIC_ISTREAM_ELEMENT_TYPE, wchar_t>))
206 return New<ELEMENT_TYPE> (internallySynchronized, originalStream, eSeekable);
208 template <
typename ELEMENT_TYPE,
typename BASIC_ISTREAM_ELEMENT_TYPE,
typename BASIC_ISTREAM_TRAITS_TYPE>
210 basic_istream<BASIC_ISTREAM_ELEMENT_TYPE, BASIC_ISTREAM_TRAITS_TYPE>& originalStream, SeekableFlag seekable) -> Ptr<ELEMENT_TYPE>
211 requires ((same_as<ELEMENT_TYPE, byte> and same_as<BASIC_ISTREAM_ELEMENT_TYPE, char>) or
212 (same_as<ELEMENT_TYPE, Characters::Character> and same_as<BASIC_ISTREAM_ELEMENT_TYPE, wchar_t>))
214 using Rep = Private_::Rep_<ELEMENT_TYPE, BASIC_ISTREAM_ELEMENT_TYPE, BASIC_ISTREAM_TRAITS_TYPE>;
215 switch (internallySynchronized) {
216 case Execution::eInternallySynchronized:
217 if constexpr (Rep::kTranscodes) {
218 if (seekable == eSeekable) {
219 return BufferedInputStream::New<ELEMENT_TYPE> (Execution::eInternallySynchronized,
220 New<ELEMENT_TYPE> (originalStream, eNotSeekable), eSeekable);
223 return InternallySynchronizedInputStream::New<Rep> ({}, originalStream, seekable);
224 case Execution::eNotKnownInternallySynchronized:
225 return New<ELEMENT_TYPE> (originalStream, seekable);
#define AssertNotImplemented()
#define RequireNotReached()
#define Stroika_ATTRIBUTE_NO_UNIQUE_ADDRESS_VCFORCE
[[msvc::no_unique_address]] isn't always broken in MSVC. Annotate with this on things where its not b...
static const UTFConvert kThe
Nearly always use this default UTFConvert.
nonvirtual span< TRG_T > ConvertSpan(span< const SRC_T > source, span< TRG_T > target) const
Convert between UTF-N encoded (including the special case of ASCII, and Latin1) character spans (e....
unique_lock< AssertExternallySynchronizedChecker > WriteContext
Instantiate AssertExternallySynchronizedChecker::WriteContext to designate an area of code where prot...
shared_lock< const AssertExternallySynchronizedChecker > ReadContext
Instantiate AssertExternallySynchronizedChecker::ReadContext to designate an area of code where prote...
A Streams::Ptr<ELEMENT_TYPE> is a smart-pointer to a stream of elements of type T.
void Throw(T &&e2Throw)
like the builtin C++ 'throw', but stamps in the current Activity context and does helpful,...