Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
LoggingInputOutputStream.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include "InternallySynchronizedInputOutputStream.h"
5
6namespace Stroika::Foundation::Streams::LoggingInputOutputStream {
7
8 namespace Private_ {
9
10 template <typename ELEMENT_TYPE>
11 class Rep_ : public InputOutputStream::IRep<ELEMENT_TYPE> {
12 public:
13 Rep_ (const typename InputOutputStream::Ptr<ELEMENT_TYPE>& realStream, const typename OutputStream::Ptr<ELEMENT_TYPE>& logInput,
14 const typename OutputStream::Ptr<ELEMENT_TYPE>& logOutput)
15 : fRealStream_{realStream}
16 , fLogInput_{logInput}
17 , fLogOutput_{logOutput}
18 {
19 Require (not realStream.IsSeekable () or (logInput.IsSeekable () and logOutput.IsSeekable ())); // since may need to delegate seeks
20 }
21
22 // Streams::_IRep<ELEMENT_TYPE>
23 public:
24 virtual bool IsSeekable () const override
25 {
26 return fRealStream_.IsSeekable ();
27 }
28
29 // InputStream::IRep
30 public:
31 virtual void CloseRead () override
32 {
33 if (IsOpenRead ()) {
34 fRealStream_.CloseRead ();
35 fLogInput_.Close ();
36 }
37 Ensure (not IsOpenRead ());
38 }
39 virtual bool IsOpenRead () const override
40 {
41 return fRealStream_.IsOpenRead ();
42 }
43 virtual SeekOffsetType GetReadOffset () const override
44 {
45 return fRealStream_.GetReadOffset ();
46 }
47 virtual SeekOffsetType SeekRead (Whence whence, SignedSeekOffsetType offset) override
48 {
49 SeekOffsetType result = fRealStream_.SeekRead (whence, offset);
50 // @todo - perhaps should seek the fLogInput_ stream? But not clear by how much
51 // DEFINITELY should or read logging will produce weird ansers - and least write SOME SORT OF NOTE that a seek happened! (like seeked from pos X to Y in stream)
52 return result;
53 }
54 virtual optional<size_t> AvailableToRead () override
55 {
56 return fRealStream_.AvailableToRead ();
57 }
58 virtual optional<span<ELEMENT_TYPE>> Read (span<ELEMENT_TYPE> intoBuffer, NoDataAvailableHandling blockFlag) override
59 {
60 optional<span<ELEMENT_TYPE>> result = fRealStream_.Read (intoBuffer, blockFlag);
61 if (result) {
62 fLogInput_.Write (*result);
63 }
64 return result;
65 }
66
67 // OutputStream::IRep
68 public:
69 virtual void CloseWrite () override
70 {
71 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
72 if (IsOpenWrite ()) {
73 fRealStream_.CloseWrite ();
74 }
75 Assert (fRealStream_ == nullptr);
76 Ensure (not IsOpenWrite ());
77 }
78 virtual bool IsOpenWrite () const override
79 {
80 Debug::AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
81 return fRealStream_.IsOpenWrite ();
82 }
83 virtual SeekOffsetType GetWriteOffset () const override
84 {
85 Debug::AssertExternallySynchronizedMutex::ReadContext declareContext{fThisAssertExternallySynchronized_};
86 return fRealStream_.GetWriteOffset ();
87 }
88 virtual SeekOffsetType SeekWrite (Whence whence, SignedSeekOffsetType offset) override
89 {
90 Require (IsOpenWrite ());
91 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
92 SeekOffsetType o1 = fRealStream_.SeekWrite (whence, offset);
93 [[maybe_unused]] SeekOffsetType o2 = fLogOutput_.Seek (whence, offset); // @todo - not sure if/how mcuh to see - since not totally in sync
94 return o1;
95 }
96 virtual void Flush () override
97 {
98 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
99 Require (IsOpenWrite ());
100 fRealStream_.Flush ();
101 }
102 // pointer must refer to valid memory at least bufSize long, and cannot be nullptr. BufSize must always be >= 1.
103 // Writes always succeed fully or throw.
104 virtual void Write (span<const ELEMENT_TYPE> elts) override
105 {
106 Require (not elts.empty ()); // for OutputStream<byte> - this function requires non-empty write
107 Require (IsOpenWrite ());
108 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
109 fRealStream_.Write (elts);
110 fLogOutput_.Write (elts);
111 }
112
113 private:
114 typename InputOutputStream::Ptr<ELEMENT_TYPE> fRealStream_;
115 typename OutputStream::Ptr<ELEMENT_TYPE> fLogInput_;
116 typename OutputStream::Ptr<ELEMENT_TYPE> fLogOutput_;
117 [[no_unique_address]] Debug::AssertExternallySynchronizedMutex fThisAssertExternallySynchronized_;
118 };
119 }
120
121 /*
122 ********************************************************************************
123 **************** Streams::LoggingInputOutputStream::Rep_ ***********************
124 ********************************************************************************
125 */
126 template <typename ELEMENT_TYPE>
127 inline Ptr<ELEMENT_TYPE> New (const typename InputOutputStream::Ptr<ELEMENT_TYPE>& realStream,
128 const typename OutputStream::Ptr<ELEMENT_TYPE>& logInput, const typename OutputStream::Ptr<ELEMENT_TYPE>& logOutput)
129 {
130 return _mkPtr (make_shared<Private_::Rep_> (realStream, logInput, logOutput));
131 }
132 template <typename ELEMENT_TYPE>
133 inline Ptr<ELEMENT_TYPE> New (Execution::InternallySynchronized internallySynchronized, const typename InputOutputStream::Ptr<ELEMENT_TYPE>& realStream,
134 const typename OutputStream::Ptr<ELEMENT_TYPE>& logInput, const typename OutputStream::Ptr<ELEMENT_TYPE>& logOutput)
135 {
136 switch (internallySynchronized) {
137 case Execution::eInternallySynchronized:
138 return InternallySynchronizedInputOutputStream::New<Private_::Rep_> ({}, realStream, logInput, logOutput);
139 case Execution::eNotKnownInternallySynchronized:
140 return New<ELEMENT_TYPE> (realStream, logInput, logOutput);
141 default:
143 return nullptr;
144 }
145 }
146
147}
#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...
InputOutputStream is single stream object that acts much as a InputStream::Ptr and an OutputStream::P...
OutputStream<>::Ptr is Smart pointer to a stream-based sink of data.
A Streams::Ptr<ELEMENT_TYPE> is a smart-pointer to a stream of elements of type T.
Definition Stream.h:170