Stroika Library 3.0d25
 
Loading...
Searching...
No Matches
Variant/JSON/Writer.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#include "Stroika/Foundation/StroikaPreComp.h"
5
6#include "Stroika/Foundation/Characters/FloatConversion.h"
8#include "Stroika/Foundation/Containers/SortedMapping.h"
10#include "Stroika/Foundation/Streams/TextToBinary.h"
11
12#include "Writer.h"
13
14using std::byte;
15
16using namespace Stroika::Foundation;
19using namespace Stroika::Foundation::Streams;
20
23using Memory::MakeSharedPtr;
24
25/*
26 * TODO:
27 * No known issues
28 */
29
30namespace {
31 // Writer::Options, and what follows from them
32 struct OptionValues_ final : Variant::JSON::Writer::Options {
33 OptionValues_ (const Variant::JSON::Writer::Options& o)
34 : Variant::JSON::Writer::Options{o}
35 {
36 if (not fPrettyPrint) {
37 fSpacesPerIndent = 0;
38 }
39 if (fSpacesPerIndent != 0) {
40 fIndentSpace = String{" "sv}.Repeat (fSpacesPerIndent);
41 }
42 }
43 String fIndentSpace;
44 };
45}
46
47/*
48 ********************************************************************************
49 ********************* DataExchange::JSON::PrettyPrint **************************
50 ********************************************************************************
51 */
52namespace {
53 void Indent_ (const OptionValues_& options, const OutputStream::Ptr<Character>& out, int indentLevel)
54 {
55 // if test not needed, but speed tweak (especially since incorporates options.fPrettyPrint check
56 if (options.fSpacesPerIndent != 0) {
57 constexpr bool kSpeedTweak_ = true;
58 if constexpr (kSpeedTweak_) {
59 for (int i = 0; i < indentLevel; ++i) {
60 out.Write (options.fIndentSpace);
61 }
62 }
63 else {
64 out.Write (options.fIndentSpace.Repeat (indentLevel));
65 }
66 }
67 }
68}
69namespace {
70 void PrettyPrint_ (const OptionValues_& options, const VariantValue& v, const OutputStream::Ptr<Character>& out, int indentLevel);
71 void PrettyPrint_Null_ (const OptionValues_& /*options*/, const OutputStream::Ptr<Character>& out)
72 {
73 out.Write ("null"sv);
74 }
75 void PrettyPrint_ (const OptionValues_& /*options*/, bool v, const OutputStream::Ptr<Character>& out)
76 {
77 if (v) {
78 out.Write ("true"sv);
79 }
80 else {
81 out.Write ("false"sv);
82 }
83 }
84 void PrettyPrint_ (const OptionValues_& /*options*/, long long int v, const OutputStream::Ptr<Character>& out)
85 {
86 wchar_t buf[1024];
87 (void)::swprintf (buf, std::size (buf), L"%lld", v);
88 out.Write (buf);
89 }
90 void PrettyPrint_ (const OptionValues_& /*options*/, unsigned long long int v, const OutputStream::Ptr<Character>& out)
91 {
92 wchar_t buf[1024];
93 (void)::swprintf (buf, std::size (buf), L"%llu", v);
94 out.Write (buf);
95 }
96 void PrettyPrint_ (const OptionValues_& options, const String& v, const OutputStream::Ptr<Character>& out);
97 void PrettyPrint_ (const OptionValues_& options, long double v, const OutputStream::Ptr<Character>& out)
98 {
99 String tmp{Characters::FloatConversion::ToString (v, options.fFloatOptions)};
100 if (isnan (v) or isinf (v)) {
101 Require (options.fAllowNANInf);
102 PrettyPrint_ (options, tmp, out);
103 }
104 else {
105 out.Write (tmp);
106 }
107 }
108 template <typename CHARITERATOR>
109 void PrettyPrint_ (const OptionValues_& /*options*/, CHARITERATOR start, CHARITERATOR end, const OutputStream::Ptr<Character>& out)
110 {
111 // A backslash can be followed by "\/bfnrtu (@ see http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf)
113 sb.Append ('\"');
114 for (auto i = start; i != end; ++i) {
115 switch (*i) {
116 case '\"':
117 sb.Append ("\\\""sv);
118 break;
119 case '\b':
120 sb.Append ("\\b"sv);
121 break;
122 case '\f':
123 sb.Append ("\\f"sv);
124 break;
125 case '\n':
126 sb.Append ("\\n"sv);
127 break;
128 case '\r':
129 sb.Append ("\\r"sv);
130 break;
131 case '\t':
132 sb.Append ("\\t"sv);
133 break;
134 case '\\':
135 sb.Append ("\\\\"sv);
136 break;
137 default:
138 // JSON rule is Any code point except " or \ or control character. So OK to emit most large unicode chars - just not control chars
139 Character c = *i;
140 if (c.IsSurrogatePair ()) [[unlikely]] {
141 wchar_t buf[20];
142 (void)::swprintf (buf, std::size (buf), L"\\u%04x\\u%04x", c.GetSurrogatePair ().first, c.GetSurrogatePair ().second);
143 sb.Append (buf);
144 }
145 else if (c.IsControl ()) [[unlikely]] {
146 wchar_t buf[10];
147 (void)::swprintf (buf, std::size (buf), L"\\u%04x", static_cast<char16_t> (c.GetCharacterCode ()));
148 sb.Append (buf);
149 }
150 else {
151 sb.Append (c);
152 }
153 break;
154 }
155 }
156 sb.Append ('\"');
157 Memory::StackBuffer<wchar_t> probablyIgnoredBuf;
158 out.Write (sb.GetData (&probablyIgnoredBuf));
159 }
160 void PrettyPrint_ (const OptionValues_& options, const wstring& v, const OutputStream::Ptr<Character>& out)
161 {
162 PrettyPrint_ (options, v.begin (), v.end (), out);
163 }
164 void PrettyPrint_ (const OptionValues_& options, const String& v, const OutputStream::Ptr<Character>& out)
165 {
167 span<const char32_t> p = v.GetData (&ignored);
168 PrettyPrint_ (options, p.data (), p.data () + p.size (), out);
169 }
170 void PrettyPrint_ (const OptionValues_& options, const vector<VariantValue>& v, const OutputStream::Ptr<Character>& out, int indentLevel)
171 {
172 out.Write ('[');
173 if (options.fPrettyPrint) {
174 out.Write (options.fLineTermination);
175 }
176 for (auto i = v.begin (); i != v.end (); ++i) {
177 Indent_ (options, out, indentLevel + 1);
178 PrettyPrint_ (options, *i, out, indentLevel + 1);
179 if (i + 1 != v.end ()) {
180 out.Write (',');
181 }
182 if (options.fPrettyPrint) {
183 out.Write (options.fLineTermination);
184 }
185 }
186 Indent_ (options, out, indentLevel);
187 out.Write (']');
188 }
189 void PrettyPrint_ (const OptionValues_& options, const Mapping<String, VariantValue>& v, const OutputStream::Ptr<Character>& out, int indentLevel)
190 {
191 out.Write ('{');
192 if (options.fPrettyPrint) {
193 out.Write (options.fLineTermination);
194 }
196 if (options.fCanonicalize) {
198 }
199 for (auto i = vv.begin (); i != vv.end ();) {
200 Indent_ (options, out, indentLevel + 1);
201 PrettyPrint_ (options, i->fKey, out, indentLevel + 1);
202 out.Write (" : "sv);
203 PrettyPrint_ (options, i->fValue, out, indentLevel + 1);
204 ++i;
205 if (i != v.end ()) {
206 out.Write (',');
207 }
208 if (options.fPrettyPrint) {
209 out.Write (options.fLineTermination);
210 }
211 }
212 Indent_ (options, out, indentLevel);
213 out.Write ('}');
214 }
215 void PrettyPrint_ (const OptionValues_& options, const VariantValue& v, const OutputStream::Ptr<Character>& out, int indentLevel)
216 {
217 switch (v.GetType ()) {
218 case VariantValue::eNull:
219 PrettyPrint_Null_ (options, out);
220 break;
221 case VariantValue::eBoolean:
222 PrettyPrint_ (options, v.As<bool> (), out);
223 break;
224 case VariantValue::eInteger:
225 PrettyPrint_ (options, v.As<long long int> (), out);
226 break;
227 case VariantValue::eUnsignedInteger:
228 PrettyPrint_ (options, v.As<unsigned long long int> (), out);
229 break;
230 case VariantValue::eFloat:
231 PrettyPrint_ (options, v.As<long double> (), out);
232 break;
233 case VariantValue::eMap:
234 PrettyPrint_ (options, v.As<Mapping<String, VariantValue>> (), out, indentLevel);
235 break;
236 case VariantValue::eArray:
237 PrettyPrint_ (options, v.As<vector<VariantValue>> (), out, indentLevel);
238 break;
239 default:
240 PrettyPrint_ (options, v.As<String> (), out);
241 }
242 }
243}
244
245/*
246 ********************************************************************************
247 ************************** DataExchange::JSON::Writer **************************
248 ********************************************************************************
249 */
250class Variant::JSON::Writer::Rep_ final : public Variant::Writer::_IRep, Memory::UseBlockAllocationIfAppropriate<Rep_> {
251public:
252 OptionValues_ fOptions_;
253 Rep_ (const Options& options)
254 : fOptions_{options}
255 {
256 }
257 Rep_ (const OptionValues_& options)
258 : fOptions_{options}
259 {
260 }
261 virtual optional<filesystem::path> GetDefaultFileSuffix () const override
262 {
263 return ".json"sv;
264 }
265 virtual void Write (const VariantValue& v, const OutputStream::Ptr<byte>& out) const override
266 {
267 OutputStream::Ptr<Character> textOut = TextToBinary::Writer::New (out, UnicodeExternalEncodings::eUTF8, ByteOrderMark::eDontInclude);
268 PrettyPrint_ (fOptions_, v, textOut, 0);
269 if (fOptions_.fPrettyPrint) {
270 textOut.Write (fOptions_.fLineTermination); // a single elt not LF terminated, but the entire doc should be.
271 }
272 }
273 virtual void Write (const VariantValue& v, const OutputStream::Ptr<Character>& out) const override
274 {
275 PrettyPrint_ (fOptions_, v, out, 0);
276 }
277};
278
279#if qCompilerAndStdLib_default_member_initializer_needed_within_enclosing_class_Buggy
280Variant::JSON::Writer::Writer ()
281 : Writer{Options{}}
282{
283}
284#endif
285
286Variant::JSON::Writer::Writer (const Options& options)
287 : inherited{MakeSharedPtr<Rep_> (options)}
288{
289}
auto MakeSharedPtr(ARGS_TYPE &&... args) -> shared_ptr< T >
same as make_shared, but if type T has block allocation, then use block allocation for the 'shared pa...
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.
constexpr bool IsControl() const noexcept
constexpr char32_t GetCharacterCode() const noexcept
Return the char32_t UNICODE code-point associated with this character.
constexpr pair< char16_t, char16_t > GetSurrogatePair() const
Similar to String, but intended to more efficiently construct a String. Mutable type (String is large...
nonvirtual span< const CHAR_T > GetData(Memory::StackBuffer< CHAR_T > *probablyIgnoredBuf) const
access a span of data located inside the StringBuilder. Return internal pointer, or pointer internal ...
nonvirtual void Append(span< const CHAR_T > s)
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
nonvirtual String Repeat(unsigned int count) const
Definition String.cpp:1483
static span< const CHAR_TYPE > GetData(const PeekSpanData &pds, Memory::StackBuffer< CHAR_TYPE, STACK_BUFFER_SZ > *possiblyUsedBuffer)
return the constant character data inside the string (rep) in the form of a span, possibly quickly an...
Definition String.inl:965
A Mapping uniquely associates two elements: a key and a value (use Assocation to allow multiple value...
Simple variant-value (case variant union) object, with (variant) basic types analogous to a value in ...
Logically halfway between std::array and std::vector; Smart 'direct memory array' - which when needed...
OutputStream<>::Ptr is Smart pointer to a stream-based sink of data.
nonvirtual void Write(span< ELEMENT_TYPE2, EXTENT_2 > elts) const
static constexpr default_sentinel_t end() noexcept
Support for ranged for, and STL syntax in general.
STRING_TYPE ToString(FLOAT_TYPE f, const ToStringOptions &options={})
Ptr New(const Streams::OutputStream::Ptr< byte > &src, const Characters::CodeCvt<> &char2OutputConverter)