SHOW:
|
|
- or go back to the newest paste.
1 | // не рабочий пока вариант , с ошибками | |
2 | #include <cassert> | |
3 | #include <cmath> | |
4 | #include <stdexcept> | |
5 | #include <sstream> | |
6 | #include <stack> | |
7 | #include <string> | |
8 | #include <optional> | |
9 | #include <memory> | |
10 | #include <unordered_map> | |
11 | #include <variant> | |
12 | ||
13 | #include "test_runner.h" | |
14 | ||
15 | using namespace std; | |
16 | ||
17 | void PrintJsonString(std::ostream &out, std::string_view str) | |
18 | { | |
19 | string str_formatted(str); | |
20 | for(size_t i = 0; i < str_formatted.length(); i++) | |
21 | { | |
22 | if(str[i] == '"' || str[i] == '\\') | |
23 | { | |
24 | str = str_formatted.insert(i,"\\"); | |
25 | i++; | |
26 | } | |
27 | } | |
28 | out << str_formatted; | |
29 | } | |
30 | ||
31 | class NoneContext | |
32 | { | |
33 | public: | |
34 | NoneContext(ostream& out, | |
35 | bool render_start_symbol = true, | |
36 | bool render_stop_symbol = true, | |
37 | bool render_null_value = true){}; | |
38 | }; | |
39 | ||
40 | template<typename Ancestor> | |
41 | class ArrayContext; | |
42 | ||
43 | template<typename Ancestor> | |
44 | class ObjectKeyContext; | |
45 | ||
46 | template<typename Ancestor> | |
47 | class ObjectValueContext; | |
48 | ||
49 | class AbstractContext | |
50 | { | |
51 | public: | |
52 | AbstractContext(ostream& out, | |
53 | bool render_start_symbol = true, | |
54 | bool render_stop_symbol = true, | |
55 | bool render_null_value = true) : | |
56 | out_(out), | |
57 | render_start_symbol_(render_start_symbol), | |
58 | render_stop_symbol_(render_stop_symbol), | |
59 | render_null_value_(render_null_value){} | |
60 | ||
61 | void WriteNumber(int64_t); | |
62 | void WriteString(std::string_view); | |
63 | void WriteBoolean(bool); | |
64 | void WriteNull(); | |
65 | ||
66 | protected: | |
67 | void InsertDelimeter_(); | |
68 | ostream& out_; | |
69 | bool render_start_symbol_; | |
70 | bool render_stop_symbol_; | |
71 | bool render_null_value_; | |
72 | ||
73 | }; | |
74 | ||
75 | template<typename Ancestor> | |
76 | class ArrayContext : public AbstractContext | |
77 | { | |
78 | public: | |
79 | ArrayContext(std::ostream &out, | |
80 | bool render_start_symbol = true, | |
81 | bool render_stop_symbol = true, | |
82 | bool render_null_value = true); | |
83 | ~ArrayContext(); | |
84 | ||
85 | ArrayContext<Ancestor>& Number(int64_t); | |
86 | ArrayContext<Ancestor>& String(std::string_view); | |
87 | ArrayContext<Ancestor>& Boolean(bool); | |
88 | ArrayContext<Ancestor>& Null(); | |
89 | ||
90 | ArrayContext<ArrayContext<Ancestor>> BeginArray(); | |
91 | Ancestor EndArray(); | |
92 | ObjectKeyContext<ArrayContext<Ancestor>> BeginObject(); | |
93 | ||
94 | }; | |
95 | ||
96 | ArrayContext<NoneContext> PrintJsonArray(std::ostream &out) | |
97 | { | |
98 | return ArrayContext<NoneContext>(out); | |
99 | } | |
100 | ||
101 | template<typename Ancestor> | |
102 | ArrayContext<Ancestor>::ArrayContext(std::ostream &out, | |
103 | bool render_start_symbol, | |
104 | bool render_stop_symbol, | |
105 | bool render_null_value) | |
106 | : AbstractContext | |
107 | (out, | |
108 | render_start_symbol, | |
109 | render_stop_symbol, | |
110 | render_null_value) | |
111 | { | |
112 | if(this->render_start_symbol_) | |
113 | this->out_ << "["; | |
114 | } | |
115 | ||
116 | template<typename Ancestor> | |
117 | ArrayContext<Ancestor>::~ArrayContext() | |
118 | { | |
119 | if(this->render_stop_symbol_) | |
120 | this->out_ << "]"; | |
121 | } | |
122 | ||
123 | template<typename Ancestor> | |
124 | ArrayContext<Ancestor>& ArrayContext<Ancestor>::Number(int64_t value) | |
125 | { | |
126 | this->WriteNumber(value); | |
127 | return *this; | |
128 | } | |
129 | ||
130 | template<typename Ancestor> | |
131 | ArrayContext<Ancestor>& ArrayContext<Ancestor>::String(string_view value) | |
132 | { | |
133 | this->WriteString(value); | |
134 | return *this; | |
135 | } | |
136 | ||
137 | template<typename Ancestor> | |
138 | ArrayContext<Ancestor>& ArrayContext<Ancestor>::Boolean(bool value) | |
139 | { | |
140 | this->WriteBoolean(value); | |
141 | return *this; | |
142 | } | |
143 | ||
144 | template<typename Ancestor> | |
145 | ArrayContext<Ancestor>& ArrayContext<Ancestor>::Null() | |
146 | { | |
147 | this->WriteNull(); | |
148 | return *this; | |
149 | } | |
150 | ||
151 | void AbstractContext::WriteNumber(int64_t number) | |
152 | { | |
153 | InsertDelimeter_(); | |
154 | out_ << number; | |
155 | } | |
156 | ||
157 | void AbstractContext::WriteString(std::string_view str) | |
158 | { | |
159 | InsertDelimeter_(); | |
160 | out_ << '"'; | |
161 | PrintJsonString(out_, str); | |
162 | out_ << '"'; | |
163 | } | |
164 | ||
165 | void AbstractContext::WriteBoolean(bool value) | |
166 | { | |
167 | InsertDelimeter_(); | |
168 | value ? out_ << "true" : out_ << "false"; | |
169 | } | |
170 | ||
171 | void AbstractContext::WriteNull() | |
172 | { | |
173 | InsertDelimeter_(); | |
174 | out_ << "null"; | |
175 | } | |
176 | ||
177 | void AbstractContext::InsertDelimeter_() | |
178 | { | |
179 | if(this->render_start_symbol_) | |
180 | { | |
181 | this->render_start_symbol_ = false; | |
182 | } | |
183 | else | |
184 | { | |
185 | this->out_ << ','; | |
186 | } | |
187 | } | |
188 | ||
189 | template <typename Ancestor> | |
190 | ArrayContext<ArrayContext<Ancestor>> ArrayContext<Ancestor>::BeginArray() | |
191 | { | |
192 | InsertDelimeter_(); | |
193 | return ArrayContext<ArrayContext<Ancestor>>(out_); | |
194 | } | |
195 | ||
196 | template <typename Ancestor> | |
197 | Ancestor ArrayContext<Ancestor>::EndArray() | |
198 | { | |
199 | if(render_stop_symbol_) | |
200 | out_ << ']'; | |
201 | render_stop_symbol_ = false; | |
202 | return Ancestor(out_, false, false, false); | |
203 | } | |
204 | ||
205 | template <typename Ancestor> | |
206 | ObjectKeyContext<ArrayContext<Ancestor>> ArrayContext<Ancestor>::BeginObject() | |
207 | { | |
208 | InsertDelimeter_(); | |
209 | return ObjectKeyContext<ArrayContext<Ancestor>>(out_); | |
210 | } | |
211 | ||
212 | template<typename Ancestor> | |
213 | class ObjectKeyContext : public AbstractContext | |
214 | { | |
215 | public: | |
216 | ObjectKeyContext(std::ostream &out, | |
217 | bool render_start_symbol = true, | |
218 | bool render_stop_symbol = true, | |
219 | bool render_null_value = true); | |
220 | ~ObjectKeyContext(); | |
221 | Ancestor EndObject(); | |
222 | ObjectValueContext<Ancestor> Key(std::string_view key); | |
223 | }; | |
224 | ||
225 | ObjectKeyContext<NoneContext> PrintJsonObject(std::ostream &out) | |
226 | { | |
227 | return ObjectKeyContext<NoneContext>(out); | |
228 | } | |
229 | ||
230 | template<typename Ancestor> | |
231 | ObjectKeyContext<Ancestor>::ObjectKeyContext(std::ostream &out, | |
232 | bool render_start_symbol, | |
233 | bool render_stop_symbol, | |
234 | bool render_null_value) | |
235 | : AbstractContext | |
236 | (out, | |
237 | render_start_symbol, | |
238 | render_stop_symbol, | |
239 | render_null_value) | |
240 | { | |
241 | if(this->render_start_symbol_) | |
242 | this->out_ << "{"; | |
243 | } | |
244 | ||
245 | template<typename Ancestor> | |
246 | ObjectValueContext<Ancestor> ObjectKeyContext<Ancestor>::Key(std::string_view key) | |
247 | { | |
248 | this->InsertDelimeter_(); | |
249 | this->out_ << '"'; | |
250 | PrintJsonString(this->out_, key); | |
251 | this->out_ << '"'; | |
252 | return ObjectValueContext<Ancestor>(this->out_); | |
253 | } | |
254 | ||
255 | template<typename Ancestor> | |
256 | ObjectKeyContext<Ancestor>::~ObjectKeyContext() | |
257 | { | |
258 | if(!this->render_stop_symbol_ && this->render_null_value_) | |
259 | this->out_ << "null}"; | |
260 | if(this->render_stop_symbol_) | |
261 | this->out_ << "}"; | |
262 | } | |
263 | ||
264 | template <typename Ancestor> | |
265 | Ancestor ObjectKeyContext<Ancestor>::EndObject() | |
266 | { | |
267 | this->render_stop_symbol_ = false; | |
268 | this->render_null_value_ = false; | |
269 | return Ancestor(out_, false, false, false); | |
270 | } | |
271 | ||
272 | template<typename Ancestor> | |
273 | class ObjectValueContext : public AbstractContext | |
274 | { | |
275 | public: | |
276 | ObjectValueContext(std::ostream &out, | |
277 | bool render_start_symbol = true, | |
278 | bool render_stop_symbol = true, | |
279 | bool render_null_value = true); | |
280 | ||
281 | ~ObjectValueContext(); | |
282 | ObjectKeyContext<Ancestor> Number(int64_t); | |
283 | ObjectKeyContext<Ancestor> String(std::string_view); | |
284 | ObjectKeyContext<Ancestor> Boolean(bool); | |
285 | ObjectKeyContext<Ancestor> Null(); | |
286 | ||
287 | ArrayContext<ObjectKeyContext<Ancestor>> BeginArray(); | |
288 | ObjectKeyContext<ObjectKeyContext<Ancestor>> BeginObject(); | |
289 | ||
290 | }; | |
291 | ||
292 | template<typename Ancestor> | |
293 | ObjectValueContext<Ancestor>::ObjectValueContext(std::ostream &out, | |
294 | bool render_start_symbol, | |
295 | bool render_stop_symbol, | |
296 | bool render_null_value) | |
297 | : AbstractContext | |
298 | (out, | |
299 | render_start_symbol, | |
300 | render_stop_symbol, | |
301 | render_null_value) | |
302 | { | |
303 | if(this->render_start_symbol_) | |
304 | this->out_ << ":"; | |
305 | } | |
306 | ||
307 | template<typename Ancestor> | |
308 | ObjectValueContext<Ancestor>::~ObjectValueContext() | |
309 | { | |
310 | } | |
311 | ||
312 | template<typename Ancestor> | |
313 | ObjectKeyContext<Ancestor> ObjectValueContext<Ancestor>::Number(int64_t value) | |
314 | { | |
315 | this->WriteNumber(value); | |
316 | return ObjectKeyContext<Ancestor>(this->out_, false, false, false); | |
317 | } | |
318 | ||
319 | template<typename Ancestor> | |
320 | ObjectKeyContext<Ancestor> ObjectValueContext<Ancestor>::String(string_view value) | |
321 | { | |
322 | this->WriteString(value); | |
323 | return ObjectKeyContext<Ancestor>(this->out_, false, false, false); | |
324 | } | |
325 | ||
326 | template<typename Ancestor> | |
327 | ObjectKeyContext<Ancestor> ObjectValueContext<Ancestor>::Boolean(bool value) | |
328 | { | |
329 | this->WriteBoolean(value); | |
330 | return ObjectKeyContext<Ancestor>(this->out_, false, false, false); | |
331 | } | |
332 | ||
333 | template<typename Ancestor> | |
334 | ObjectKeyContext<Ancestor> ObjectValueContext<Ancestor>::Null() | |
335 | { | |
336 | this->WriteNull(); | |
337 | return ObjectKeyContext<Ancestor>(this->out_, false, false, false); | |
338 | } | |
339 | ||
340 | template <typename Ancestor> | |
341 | ArrayContext<ObjectKeyContext<Ancestor>> ObjectValueContext<Ancestor>::BeginArray() | |
342 | { | |
343 | InsertDelimeter_(); | |
344 | return ArrayContext<ObjectKeyContext<Ancestor>>(out_); | |
345 | } | |
346 | ||
347 | template <typename Ancestor> | |
348 | ObjectKeyContext<ObjectKeyContext<Ancestor>> ObjectValueContext<Ancestor>::BeginObject() | |
349 | { | |
350 | InsertDelimeter_(); | |
351 | return ObjectKeyContext<ObjectKeyContext<Ancestor>>(out_, true, false); | |
352 | } | |
353 | ||
354 | //------------------------------------------- TESTING SECTION -------------------------------------------// | |
355 | ||
356 | void TestPrintJsonString() | |
357 | { | |
358 | std::ostringstream output; | |
359 | PrintJsonString(output, "Hello, \"world\""); | |
360 | ASSERT_EQUAL(output.str(), "Hello, \\\"world\\\""); | |
361 | } | |
362 | ||
363 | void TestArray() | |
364 | { | |
365 | std::ostringstream output; | |
366 | ||
367 | { | |
368 | auto json = PrintJsonArray(output); | |
369 | json | |
370 | .Number(5) | |
371 | .Number(6) | |
372 | .BeginArray() | |
373 | .Number(7) | |
374 | .EndArray() | |
375 | .Number(8) | |
376 | .String("bingo!") | |
377 | .EndArray(); | |
378 | } | |
379 | ||
380 | ASSERT_EQUAL(output.str(), R"([5,6,[7],8,"bingo!"])"); | |
381 | } | |
382 | ||
383 | void TestArrayWOEnd() | |
384 | { | |
385 | std::ostringstream output; | |
386 | ||
387 | { | |
388 | auto json = PrintJsonArray(output); | |
389 | json | |
390 | .Number(5) | |
391 | .Number(6) | |
392 | .BeginArray() | |
393 | .Number(7); | |
394 | } | |
395 | ||
396 | ASSERT_EQUAL(output.str(), R"([5,6,[7]])"); | |
397 | } | |
398 | ||
399 | void TestObject() | |
400 | { | |
401 | std::ostringstream output; | |
402 | ||
403 | { | |
404 | auto json = PrintJsonObject(output); | |
405 | json | |
406 | .Key("id1") | |
407 | .Number(1234) | |
408 | .Key("id2") | |
409 | .Boolean(false) | |
410 | .Key("") | |
411 | .Null() | |
412 | .Key("\"") | |
413 | .String("\\"); | |
414 | } | |
415 | ||
416 | ASSERT_EQUAL(output.str(), R"({"id1":1234,"id2":false,"":null,"\"":"\\"})"); | |
417 | } | |
418 | ||
419 | void TestAutoClose() | |
420 | { | |
421 | std::ostringstream output; | |
422 | ||
423 | { | |
424 | auto json = PrintJsonArray(output); | |
425 | json.BeginArray().BeginObject(); | |
426 | } | |
427 | ||
428 | ASSERT_EQUAL(output.str(), R"([[{}]])"); | |
429 | } | |
430 | ||
431 | void TetsEx1() | |
432 | { | |
433 | std::ostringstream output; | |
434 | { | |
435 | auto json = PrintJsonArray(output); | |
436 | json | |
437 | .Null() | |
438 | .String("Hello") | |
439 | .Number(123) | |
440 | .Boolean(false) | |
441 | .EndArray(); | |
442 | } | |
443 | ASSERT_EQUAL(output.str(), R"([null,"Hello",123,false])"); | |
444 | } | |
445 | ||
446 | void TetsEx2() | |
447 | { | |
448 | std::ostringstream output; | |
449 | { | |
450 | auto json = PrintJsonArray(output); | |
451 | json | |
452 | .String("Hello") | |
453 | .BeginArray() | |
454 | .String("World"); | |
455 | } | |
456 | ASSERT_EQUAL(output.str(), R"(["Hello",["World"]])"); | |
457 | } | |
458 | ||
459 | void TetsEx3() | |
460 | { | |
461 | std::ostringstream output; | |
462 | { | |
463 | auto json = PrintJsonObject(output); | |
464 | json | |
465 | .Key("foo") | |
466 | .BeginArray() | |
467 | .String("Hello") | |
468 | .EndArray() | |
469 | .Key("foo") // повторяющиеся ключи допускаются | |
470 | .BeginObject() | |
471 | .Key("foo"); | |
472 | } | |
473 | ASSERT_EQUAL(output.str(), R"({"foo":["Hello"],"foo":{"foo":null}})"); | |
474 | } | |
475 | ||
476 | void TestEndObject_1() | |
477 | { | |
478 | std::ostringstream output; | |
479 | ||
480 | { | |
481 | auto json = PrintJsonArray(output); | |
482 | json | |
483 | .BeginObject() | |
484 | .Key("as") | |
485 | .Null() | |
486 | .EndObject() | |
487 | .BeginObject(); | |
488 | } | |
489 | ||
490 | ASSERT_EQUAL(output.str(), R"([{"as":null,{}}])"); | |
491 | } | |
492 | ||
493 | void TestEndObject_2() | |
494 | { | |
495 | std::ostringstream output; | |
496 | ||
497 | { | |
498 | auto json = PrintJsonArray(output); | |
499 | json | |
500 | .BeginObject() | |
501 | .Key("as") | |
502 | .BeginObject() | |
503 | .EndObject() | |
504 | .Key("as") | |
505 | .Null() | |
506 | .EndObject() | |
507 | .BeginObject(); | |
508 | } | |
509 | ||
510 | ASSERT_EQUAL(output.str(), R"([{"as":null,{}}])"); | |
511 | } | |
512 | ||
513 | int main() | |
514 | { | |
515 | TestRunner tr; | |
516 | RUN_TEST(tr, TestPrintJsonString); | |
517 | RUN_TEST(tr, TestArray); | |
518 | RUN_TEST(tr, TestArrayWOEnd); | |
519 | RUN_TEST(tr, TestObject); | |
520 | RUN_TEST(tr, TestAutoClose); | |
521 | RUN_TEST(tr, TetsEx1); | |
522 | RUN_TEST(tr, TetsEx2); | |
523 | RUN_TEST(tr, TetsEx3); | |
524 | RUN_TEST(tr, TestEndObject_1); | |
525 | ||
526 | PrintJsonArray(std::cout) | |
527 | .Null() | |
528 | .String("Hello") | |
529 | .Number(123) | |
530 | .Boolean(false) | |
531 | .BeginObject() | |
532 | .Key("A") | |
533 | .BeginArray() | |
534 | .Null() | |
535 | .String("Hello") | |
536 | .Number(123) | |
537 | .EndArray(); | |
538 | ||
539 | return 0; | |
540 | } |