Stroika Library 3.0d25
 
Loading...
Searching...
No Matches
OutputStreamFromStdOStream.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
6#include "Stroika/Foundation/Execution/Exceptions.h"
8#include "Stroika/Foundation/Execution/Throw.h"
11#include "Stroika/Foundation/Streams/InternallySynchronizedOutputStream.h"
12
13namespace Stroika::Foundation::Streams::iostream::OutputStreamFromStdOStream {
14
15 namespace Private_ {
16 template <typename ELEMENT_TYPE, typename BASIC_OSTREAM_ELEMENT_TYPE, typename BASIC_OSTREAM_TRAITS_TYPE>
17 class Rep_ : public OutputStream::IRep<ELEMENT_TYPE> {
18 public:
19 /**
20 * Characters to a 16-bit wchar_t - UTF-16, where a Character is one element or two: so this converts, and cannot
21 * seek, its offsets counting Characters but the ostream's counting wchar_ts
22 */
23 static constexpr bool kTranscodes = sizeof (ELEMENT_TYPE) != sizeof (BASIC_OSTREAM_ELEMENT_TYPE);
24
25 private:
26 bool fOpen_{true};
27
28 public:
29 Rep_ (basic_ostream<BASIC_OSTREAM_ELEMENT_TYPE, BASIC_OSTREAM_TRAITS_TYPE>& originalStream)
30 : fOriginalStreamRef_{originalStream}
31 {
32 }
33
34 protected:
35 virtual bool IsSeekable () const override
36 {
37 Debug::AssertExternallySynchronizedChecker::ReadContext declareContext{fThisAssertExternallySynchronized_};
38 return not kTranscodes;
39 }
40 virtual void CloseWrite () override
41 {
42 Debug::AssertExternallySynchronizedChecker::WriteContext declareContext{fThisAssertExternallySynchronized_};
43 fOpen_ = false;
44 Ensure (not IsOpenWrite ());
45 }
46 virtual bool IsOpenWrite () const override
47 {
48 Debug::AssertExternallySynchronizedChecker::ReadContext declareContext{fThisAssertExternallySynchronized_};
49 return fOpen_;
50 }
51 virtual SeekOffsetType GetWriteOffset () const override
52 {
53 Debug::AssertExternallySynchronizedChecker::ReadContext declareContext{fThisAssertExternallySynchronized_};
54 Require (IsOpenWrite ());
55 if constexpr (kTranscodes) {
56 return fOffset_;
57 }
58 else {
59 // instead of tellg () - avoids issue with EOF where fail bit set???
60 return fOriginalStreamRef_.rdbuf ()->pubseekoff (0, ios_base::cur, ios_base::out);
61 }
62 }
63 virtual SeekOffsetType SeekWrite (Whence whence, SignedSeekOffsetType offset) override
64 {
65 Debug::AssertExternallySynchronizedChecker::WriteContext declareContext{fThisAssertExternallySynchronized_};
66 Require (IsOpenWrite ());
67 Require (IsSeekable ());
68 switch (whence) {
69 case eFromStart:
70 fOriginalStreamRef_.seekp (offset, ios::beg);
71 break;
72 case eFromCurrent:
73 fOriginalStreamRef_.seekp (offset, ios::cur);
74 break;
75 case eFromEnd:
76 fOriginalStreamRef_.seekp (offset, ios::end);
77 break;
78 }
79 return fOriginalStreamRef_.tellp ();
80 }
81 virtual void Write (span<const ELEMENT_TYPE> elts) override
82 {
83 Require (not elts.empty ());
84 Require (IsOpenWrite ());
85 Debug::AssertExternallySynchronizedChecker::WriteContext declareContext{fThisAssertExternallySynchronized_};
86
87 if constexpr (kTranscodes) {
88 Memory::StackBuffer<BASIC_OSTREAM_ELEMENT_TYPE> units{
89 Memory::eUninitialized, Characters::UTFConvert::ComputeTargetBufferSize<BASIC_OSTREAM_ELEMENT_TYPE> (elts)};
90 span<BASIC_OSTREAM_ELEMENT_TYPE> converted = Characters::UTFConvert::kThe.ConvertSpan (elts, span{units});
91 fOriginalStreamRef_.write (converted.data (), converted.size ());
92 fOffset_ += elts.size ();
93 }
94 else {
95 fOriginalStreamRef_.write (reinterpret_cast<const BASIC_OSTREAM_ELEMENT_TYPE*> (elts.data ()), elts.size ());
96 }
97 if (fOriginalStreamRef_.fail ()) [[unlikely]] {
98 static const Execution::Exception<runtime_error> kException_{"Failed to write from ostream"sv};
99 Execution::Throw (kException_);
100 }
101 }
102 virtual void Flush () override
103 {
104 Debug::AssertExternallySynchronizedChecker::WriteContext declareContext{fThisAssertExternallySynchronized_};
105 Require (IsOpenWrite ());
106 fOriginalStreamRef_.flush ();
107 if (fOriginalStreamRef_.fail ()) [[unlikely]] {
108 static const Execution::Exception<runtime_error> kException_{"Failed to flush ostream"sv};
109 Execution::Throw (kException_);
110 }
111 }
112
113 private:
114 basic_ostream<BASIC_OSTREAM_ELEMENT_TYPE, BASIC_OSTREAM_TRAITS_TYPE>& fOriginalStreamRef_;
115 SeekOffsetType fOffset_{0}; // Characters written - kTranscodes only, where the ostream's offsets count its elements
116 Stroika_ATTRIBUTE_NO_UNIQUE_ADDRESS_VCFORCE Debug::AssertExternallySynchronizedChecker fThisAssertExternallySynchronized_;
117 };
118 }
119
120 /*
121 ********************************************************************************
122 **************** OutputStreamFromStdOStream<ELEMENT_TYPE>::New *****************
123 ********************************************************************************
124 */
125 template <typename ELEMENT_TYPE, typename BASIC_OSTREAM_ELEMENT_TYPE, typename BASIC_OSTREAM_TRAITS_TYPE>
126 inline auto New (basic_ostream<BASIC_OSTREAM_ELEMENT_TYPE, BASIC_OSTREAM_TRAITS_TYPE>& originalStream) -> Ptr<ELEMENT_TYPE>
127 requires ((same_as<ELEMENT_TYPE, byte> and same_as<BASIC_OSTREAM_ELEMENT_TYPE, char>) or
128 (same_as<ELEMENT_TYPE, Characters::Character> and same_as<BASIC_OSTREAM_ELEMENT_TYPE, wchar_t>))
129 {
130 return Ptr<ELEMENT_TYPE>{Memory::MakeSharedPtr<Private_::Rep_<ELEMENT_TYPE, BASIC_OSTREAM_ELEMENT_TYPE, BASIC_OSTREAM_TRAITS_TYPE>> (originalStream)};
131 }
132 template <typename ELEMENT_TYPE, typename BASIC_OSTREAM_ELEMENT_TYPE, typename BASIC_OSTREAM_TRAITS_TYPE>
133 inline auto New (Execution::InternallySynchronized internallySynchronized,
134 basic_ostream<BASIC_OSTREAM_ELEMENT_TYPE, BASIC_OSTREAM_TRAITS_TYPE>& originalStream) -> Ptr<ELEMENT_TYPE>
135 requires ((same_as<ELEMENT_TYPE, byte> and same_as<BASIC_OSTREAM_ELEMENT_TYPE, char>) or
136 (same_as<ELEMENT_TYPE, Characters::Character> and same_as<BASIC_OSTREAM_ELEMENT_TYPE, wchar_t>))
137 {
138 switch (internallySynchronized) {
139 case Execution::eInternallySynchronized:
140 return InternallySynchronizedOutputStream::New<Private_::Rep_<ELEMENT_TYPE, BASIC_OSTREAM_ELEMENT_TYPE, BASIC_OSTREAM_TRAITS_TYPE>> (
141 {}, originalStream);
142 case Execution::eNotKnownInternallySynchronized:
143 return New<ELEMENT_TYPE> (originalStream);
144 default:
146 return nullptr;
147 }
148 }
149
150}
#define RequireNotReached()
Definition Assertions.h:388
#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...
Definition StdCompat.h:481
static const UTFConvert kThe
Nearly always use this default UTFConvert.
Definition UTFConvert.h:374
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.
Definition Stream.h:170
void Throw(T &&e2Throw)
like the builtin C++ 'throw', but stamps in the current Activity context and does helpful,...
Definition Throw.inl:54