Stroika Library 3.0d23x
 
Loading...
Searching...
No Matches
TextToBinary.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
5#include "Stroika/Foundation/Streams/InternallySynchronizedOutputStream.h"
6
7namespace Stroika::Foundation::Streams::TextToBinary {
8
9 namespace Private_ {
10 class UnSeekable_CodeCvt_Rep_ final : public OutputStream::IRep<Character> {
11 public:
12 UnSeekable_CodeCvt_Rep_ (const OutputStream::Ptr<byte>& src, const Characters::CodeCvt<Character>& converter)
13 : _fSource{src}
14 , _fConverter{converter}
15 {
16 RequireNotNull (src);
17 }
18
19 protected:
20 virtual bool IsSeekable () const override
21 {
22 return false;
23 }
24 virtual void CloseWrite () override
25 {
26 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
27 if (IsOpenWrite ()) {
28 _fSource.Close ();
29 }
30 Ensure (not IsOpenWrite ());
31 }
32 virtual bool IsOpenWrite () const override
33 {
34 return _fSource.IsOpen ();
35 }
36 virtual SeekOffsetType GetWriteOffset () const override
37 {
39 Require (IsOpenWrite ());
40 return 0;
41 }
42 virtual SeekOffsetType SeekWrite (Whence /*whence*/, SignedSeekOffsetType /*offset*/) override
43 {
44 AssertNotImplemented (); // not seekable
45 Require (IsOpenWrite ());
46 return 0;
47 }
48 virtual void Write (span<const Character> elts) override
49 {
50 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
51 Require (IsOpenWrite ());
52 Memory::StackBuffer<byte> cvtBuf{elts.size () * 5}; // excessive but start with that
53 auto srcSpan = elts;
54 auto trgSpan = span<byte>{cvtBuf.data (), cvtBuf.size ()};
55 trgSpan = _fConverter.Characters2Bytes (srcSpan, trgSpan);
56 _fSource.Write (trgSpan);
57 }
58 virtual void Flush () override
59 {
60 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
61 Require (IsOpenWrite ());
62 _fSource.Flush ();
63 }
64
65 protected:
66 OutputStream::Ptr<byte> _fSource;
67 Characters::CodeCvt<Character> _fConverter;
68 std::mbstate_t _fMBState_{};
69 [[no_unique_address]] Debug::AssertExternallySynchronizedMutex fThisAssertExternallySynchronized_;
70 };
71
72 template <Characters ::IUNICODECanUnambiguouslyConvertFrom OUTPUT_CHAR_T>
73 class UnSeekable_UTFConverter_Rep_ final : public OutputStream::IRep<Character> {
74 public:
75 template <typename CONVERTER>
76 UnSeekable_UTFConverter_Rep_ (const OutputStream::Ptr<byte>& src, CONVERTER&& converter)
77 : _fSource{src}
78 , _fConverter{forward<CONVERTER> (converter)}
79 {
80 RequireNotNull (src);
81 }
82 UnSeekable_UTFConverter_Rep_ (const OutputStream::Ptr<byte>& src)
83 : _fSource{src}
84 , _fConverter{Characters::UTFConvert::kThe}
85 {
86 }
87
88 protected:
89 virtual bool IsSeekable () const override
90 {
91 return false;
92 }
93 virtual void CloseWrite () override
94 {
95 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
96 if (IsOpenWrite ()) {
97 _fSource.Close ();
98 }
99 Ensure (not IsOpenWrite ());
100 }
101 virtual bool IsOpenWrite () const override
102 {
103 return _fSource.IsOpen ();
104 }
105 virtual SeekOffsetType GetWriteOffset () const override
106 {
108 Require (IsOpenWrite ());
109 return 0;
110 }
111 virtual SeekOffsetType SeekWrite (Whence /*whence*/, SignedSeekOffsetType /*offset*/) override
112 {
113 AssertNotImplemented (); // not seekable
114 Require (IsOpenWrite ());
115 return 0;
116 }
117 virtual void Write (span<const Character> elts) override
118 {
119 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
120 Require (IsOpenWrite ());
121 auto srcSpan = elts;
122 Memory::StackBuffer<OUTPUT_CHAR_T> cvtBuf{_fConverter.ComputeTargetBufferSize<OUTPUT_CHAR_T> (srcSpan)};
123 auto trgSpan = span<OUTPUT_CHAR_T>{cvtBuf.data (), cvtBuf.size ()};
124 auto r = _fConverter.ConvertSpan (srcSpan, trgSpan);
125 auto trgBytes = as_bytes (r);
126 _fSource.Write (trgBytes);
127 }
128 virtual void Flush () override
129 {
130 Debug::AssertExternallySynchronizedMutex::WriteContext declareContext{fThisAssertExternallySynchronized_};
131 Require (IsOpenWrite ());
132 _fSource.Flush ();
133 }
134
135 protected:
136 OutputStream::Ptr<byte> _fSource;
137 Characters::UTFConvert _fConverter;
138 [[no_unique_address]] Debug::AssertExternallySynchronizedMutex fThisAssertExternallySynchronized_;
139 };
140 }
141
142 /*
143 ********************************************************************************
144 ************************ TextToBinary::Writer::New *****************************
145 ********************************************************************************
146 */
147 namespace Writer {
148 inline auto New (const OutputStream::Ptr<Character>& src) -> OutputStream::Ptr<Character>
149 {
150 return src;
151 }
152 inline OutputStream::Ptr<Character> New (const OutputStream::Ptr<byte>& src, const Characters::CodeCvt<>& char2OutputConverter)
153 {
154 return OutputStream::Ptr<Character>{Memory::MakeSharedPtr<Private_::UnSeekable_CodeCvt_Rep_> (src, char2OutputConverter)};
155 }
157 {
159 if (bom == Characters::ByteOrderMark::eInclude) {
161 }
162 // handle a few common cases more efficiently, without vectoring through CodeCvt<> (which has an extra level of indirection)
163 switch (e) {
164 case Characters::UnicodeExternalEncodings::eUTF8:
165 return Ptr{Memory::MakeSharedPtr<Private_::UnSeekable_UTFConverter_Rep_<char8_t>> (src)};
166 case Characters::UnicodeExternalEncodings::eUTF16:
167 return Ptr{Memory::MakeSharedPtr<Private_::UnSeekable_UTFConverter_Rep_<char16_t>> (src)};
168 case Characters::UnicodeExternalEncodings::eUTF32:
169 return Ptr{Memory::MakeSharedPtr<Private_::UnSeekable_UTFConverter_Rep_<char32_t>> (src)};
170 default:
171 // but default to using the CodeCvt writer
172 return New (src, Characters::CodeCvt<Character> (e));
173 }
174 }
175 template <typename... ARGS>
176 inline OutputStream::Ptr<Character> New (Execution::InternallySynchronized internallySynchronized, ARGS... args)
177 {
178 switch (internallySynchronized) {
179 case Execution::eNotKnownInternallySynchronized:
180 return New (forward<ARGS...> (args...));
181 case Execution::eInternallySynchronized:
182 // @todo could explicitly specialize more cases and handle more efficiently, but using the REP overload of InternallySynchronizedInputStream
183 return InternallySynchronizedOutputStream::New ({}, New (forward<ARGS...> (args...)));
184 }
185 }
186 }
187
188}
#define AssertNotImplemented()
Definition Assertions.h:401
#define RequireNotNull(p)
Definition Assertions.h:347
CodeCvt unifies byte <-> unicode conversions, vaguely inspired by (and wraps) std::codecvt,...
Definition CodeCvt.h:118
unique_lock< AssertExternallySynchronizedMutex > WriteContext
Instantiate AssertExternallySynchronizedMutex::WriteContext to designate an area of code where protec...
virtual void Write(span< const ELEMENT_TYPE > elts)=0
OutputStream<>::Ptr is Smart pointer to a stream-based sink of data.
nonvirtual void Write(span< ELEMENT_TYPE2, EXTENT_2 > elts) const
A Streams::Ptr<ELEMENT_TYPE> is a smart-pointer to a stream of elements of type T.
Definition Stream.h:170
constexpr span< const byte > GetByteOrderMark(UnicodeExternalEncodings e) noexcept
UnicodeExternalEncodings
list of external UNICODE character encodings, for file IO (eDEFAULT = eUTF8)
Definition UTFConvert.h:31
Ptr New(const Streams::OutputStream::Ptr< byte > &src, const Characters::CodeCvt<> &char2OutputConverter)
Streams::OutputStream::Ptr< Character > Ptr
TextToBinary::Writer wrap some sink (typically a binary stream), and produce a text sink you can Writ...