4#include "Stroika/Foundation/StroikaPreComp.h"
10#if qStroika_Foundation_Common_Platform_POSIX
13#elif qStroika_Foundation_Common_Platform_Windows
21#include "Stroika/Foundation/Execution/Activity.h"
22#include "Stroika/Foundation/Execution/Common.h"
23#include "Stroika/Foundation/Execution/Exceptions.h"
24#include "Stroika/Foundation/Execution/Throw.h"
25#if qStroika_Foundation_Common_Platform_Windows
26#include "Stroika/Foundation/Execution/Platform/Windows/Exception.h"
38using namespace Stroika::Foundation::Debug;
40using namespace Stroika::Foundation::IO;
42using namespace Stroika::Foundation::IO::FileSystem::FileInputStream;
43using namespace Stroika::Foundation::Streams;
54 Rep_ (
const Rep_&) =
delete;
55 Rep_ (
const filesystem::path& fileName,
SeekableFlag seekable)
57 , fSeekable_{seekable}
58 , fFileName_{fileName}
62#if qStroika_Foundation_Common_Platform_Windows
63 errno_t e = ::_wsopen_s (&fFD_, fileName.c_str (), (O_RDONLY | O_BINARY), _SH_DENYNO, 0);
73#if USE_NOISY_TRACE_IN_THIS_MODULE_
79 , fSeekable_{seekable}
80 , fAdoptFDPolicy_{adoptFDPolicy}
82#if USE_NOISY_TRACE_IN_THIS_MODULE_
83 DbgTrace (
"attached fd: {}"_f, fFD_);
88#if USE_NOISY_TRACE_IN_THIS_MODULE_
90 if (fAdoptFDPolicy_ == AdoptFDPolicy::eCloseOnDestruction and IsOpenRead ()) {
94 if (fAdoptFDPolicy_ == AdoptFDPolicy::eCloseOnDestruction and IsOpenRead ()) {
95#if qStroika_Foundation_Common_Platform_Windows
102 nonvirtual Rep_& operator= (
const Rep_&) =
delete;
106 return fSeekable_ == eSeekable;
111 if (fAdoptFDPolicy_ == AdoptFDPolicy::eCloseOnDestruction) {
112#if qStroika_Foundation_Common_Platform_Windows
120 Ensure (not IsOpenRead ());
128#if qStroika_Foundation_Common_Platform_POSIX
129 pollfd pollData{fFD_, POLLIN, 0};
131 Assert (pollResult >= 0);
132 if (pollResult == 0) {
140#if qStroika_Foundation_Common_Platform_Windows
148 if (fSeekable_ == eSeekable) {
150 auto eof = SeekRead (Whence::eFromEnd, 0);
151 SeekRead (eFromStart, saved);
152 Ensure (eof >= saved);
161 Require (not intoBuffer.empty ());
162 size_t nRequested = intoBuffer.size ();
163#if USE_NOISY_TRACE_IN_THIS_MODULE_
164 Debug::TraceContextBumper ctx{L
"FileInputStream::Rep_::Read", L
"nRequested: %llu",
static_cast<unsigned long long> (nRequested)};
167 auto readingFromFileActivity =
LazyEvalActivity{[&] () ->
String {
return "reading from {}"_f(fFileName_); }};
170 if (blockFlag == NoDataAvailableHandling::eDontBlock) {
171#if qStroika_Foundation_Common_Platform_POSIX
172 pollfd pollData{fFD_, POLLIN, 0};
174 Assert (pollResult >= 0);
175 if (pollResult == 0) {
182#if qStroika_Foundation_Common_Platform_Windows
205#if qStroika_Foundation_Common_Platform_Windows
206 return intoBuffer.subspan (0,
static_cast<size_t> (ThrowPOSIXErrNoIfNegative (
207 ::_read (fFD_, intoBuffer.data (), Math::PinToMaxForType<unsigned int> (nRequested)))));
209 return intoBuffer.subspan (0,
static_cast<size_t> (ThrowPOSIXErrNoIfNegative (::read (fFD_, intoBuffer.data (), nRequested))));
215#if qStroika_Foundation_Common_Platform_Windows
217#elif qStroika_Foundation_Common_Platform_Linux
225 using namespace Streams;
226#if USE_NOISY_TRACE_IN_THIS_MODULE_
229 static const auto kException_ = range_error{
"seek"};
233 if (offset < 0) [[unlikely]] {
236#if qStroika_Foundation_Common_Platform_Windows
238#elif qStroika_Foundation_Common_Platform_Linux
245#if qStroika_Foundation_Common_Platform_Windows
247#elif qStroika_Foundation_Common_Platform_Linux
254#if qStroika_Foundation_Common_Platform_Windows
256#elif qStroika_Foundation_Common_Platform_Linux
270 AdoptFDPolicy fAdoptFDPolicy_{AdoptFDPolicy::eCloseOnDestruction};
271 optional<filesystem::path> fFileName_;
281auto FileInputStream::New (
const filesystem::path& fileName,
SeekableFlag seekable) ->
Ptr
283 return Ptr{Memory::MakeSharedPtr<Rep_> (fileName, seekable)};
288 return Ptr{Memory::MakeSharedPtr<Rep_> (fd, adoptFDPolicy, seekable)};
293 switch (internallySynchronized) {
294 case Execution::eInternallySynchronized:
295 return Streams::InternallySynchronizedInputStream::New<Rep_> ({}, fileName, seekable);
296 case Execution::eNotKnownInternallySynchronized:
297 return New (fileName, seekable);
307 switch (internallySynchronized) {
308 case Execution::eInternallySynchronized:
309 return Streams::InternallySynchronizedInputStream::New<Rep_> ({}, fd, adoptFDPolicy, seekable);
310 case Execution::eNotKnownInternallySynchronized:
311 return New (fd, adoptFDPolicy, seekable);
314 return New (fd, adoptFDPolicy, seekable);
320#if USE_NOISY_TRACE_IN_THIS_MODULE_
321 Debug::TraceContextBumper ctx{
"FileInputStream::New",
"fileName: {}, seekable: {}, bufferFlag: {}", fileName, seekable, bufferFlag};
324 switch (bufferFlag) {
326 return Streams::BufferedInputStream::New<byte> (in);
337#if USE_NOISY_TRACE_IN_THIS_MODULE_
338 Debug::TraceContextBumper ctx{
"FileInputStream::New",
"fd: {}, seekable: {}, bufferFlag: {}"_f, fd, seekable, bufferFlag};
341 switch (bufferFlag) {
343 return Streams::BufferedInputStream::New<byte> (in);
#define AssertNotImplemented()
#define RequireNotReached()
#define AssertNotReached()
conditional_t< qStroika_Foundation_Memory_PreferBlockAllocation and andTrueCheck, BlockAllocationUseHelper< T >, Common::Empty > UseBlockAllocationIfAppropriate
Use this to enable block allocation for a particular class. Beware of subclassing.
NoDataAvailableHandling
If eDontBlock passed to most Stream APIs, then when the code would do a blocking read,...
int64_t SignedSeekOffsetType
String is like std::u32string, except it is much easier to use, often much more space efficient,...
NOT a real mutex - just a debugging infrastructure support tool so in debug builds can be assured thr...
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...
static INT_TYPE ThrowPOSIXErrNoIfNegative(INT_TYPE returnCode, const path &p1={}, const path &p2={})
static void ThrowPOSIXErrNo(errno_t errNo, const path &p1={}, const path &p2={})
treats errNo as a POSIX errno value, and throws a FileSystem::Exception (subclass of @std::filesystem...
static void ThrowSystemErrNo(int sysErr, const path &p1={}, const path &p2={})
treats errNo as a platform-defined error number, and throws a FileSystem::Exception (subclass of @std...
virtual bool IsSeekable() const =0
A Streams::Ptr<ELEMENT_TYPE> is a smart-pointer to a stream of elements of type T.
void Throw(T &&e2Throw)
identical to builtin C++ 'throw' except that it does helpful, type dependent DbgTrace() messages firs...
auto Handle_ErrNoResultInterruption(CALL call) -> decltype(call())
Handle UNIX EINTR system call behavior - fairly transparently - just effectively removes them from th...
INT_TYPE ThrowPOSIXErrNoIfNegative(INT_TYPE returnCode)