Loading...
Searching...
No Matches
Sprinter.h
1/*
2
3MIT License
4
5Copyright (c) 2017 FMI Open Development / Markus Peura, first.last@fmi.fi
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24
25*/
26/*
27Part of Rack development has been done in the BALTRAD projects part-financed
28by the European Union (European Regional Development Fund and European
29Neighbourhood Partnership Instrument, Baltic Sea Region Programme 2007-2013)
30*/
31#ifndef DRAIN_SPRINTER
32#define DRAIN_SPRINTER
33
34#include <string.h> // strlen
35#include <iostream>
36
37#include <string>
38#include <utility> // pair
39#include <vector>
40#include <set>
41#include <list>
42#include <map>
43
44#include <drain/UniTuple.h>
45
46
47
48namespace drain {
49
50
52
57class TypeLayoutBase : public UniTuple<char,3>{
58
59public:
60
61 typedef char cstr_t;
62 cstr_t & prefix;
63 cstr_t & separator;
64 cstr_t & suffix;
65
66 inline
67 TypeLayoutBase(): // chars('\0',3), prefix(chars[0]), separator(chars[1]), suffix(chars[2]){
68 prefix(this->next()), separator(this->next()), suffix(this->next()){
69 }
70
71 inline
72 bool empty() const { // conside rename isDefined(), esp. if functions used later ?
73 return ((prefix==0) && (separator==0) && (suffix==0));
74 }
75
76
77};
78
79struct TypeLayout : public TypeLayoutBase{
80
81
83 TypeLayout(cstr_t separator=','){
84 set(0, separator, 0);
85 }
86
88 /***
89 * Notice that arguments (a,b) invoke set(a,0,b), not set(a,b).
90 */
91 TypeLayout(cstr_t prefix, cstr_t suffix){
92 set(prefix, 0, suffix);
93 }
94
96 TypeLayout(cstr_t prefix, cstr_t separator, cstr_t suffix){
97 set(prefix, separator, suffix);
98 }
99
101 TypeLayout(const char layout[4]){ // = "{,}"
102 setLayout(layout);
103 }
104
105 TypeLayout(const TypeLayout & layout){
106 this->assignSequence(layout);
107 //this->assign(layout); // NOTE: copying element by element, not involving strings possibly containing null char (premature end-or-read).
108 }
109
111
119 TypeLayout & setLayout(const char *layout);
120
121
122
123};
124
125
137
138 // char itemSeparator = ','; // consider as equal sign: KEY:VALUE
139 TypeLayout arrayChars = TypeLayout("[,]");
140 TypeLayout mapChars = TypeLayout("{,}");
141 TypeLayout pairChars = TypeLayout("(,)"); // layout for (key,value), see keyChars
142 TypeLayout stringChars = TypeLayout('"',0,'"'); // TODO: Separate value and sequence layouts?
143 TypeLayout keyChars = TypeLayout(0,0,0); // given a pair = (key,value), defined how the key is .
144 TypeLayout mapPairChars = TypeLayout(0,0,0); // When a map {entry, entry,... } is rendered, defines how
145
146 // TypeLayout stringChars = TypeLayout("\"\"");
147 // std::string boolTrue = "true";
148 // std::string boolFalse = "false";
149 // std::string nullValue = "null";
150
151 SprinterLayout(const char *arrayChars="[,]", const char *mapChars="{,}", const char *pairChars="(,)",
152 const char *stringChars=nullptr, const char *keyChars=nullptr, const char *mapPairChars=nullptr){
153 this->arrayChars.setLayout(arrayChars);
154 this->mapChars.setLayout(mapChars);
155 this->pairChars.setLayout(pairChars);
156 if (stringChars)
157 this->stringChars.setLayout(stringChars);
158 if (keyChars)
159 this->keyChars.setLayout(keyChars);
160 if (mapPairChars)
161 this->mapPairChars.setLayout(mapPairChars);
162 }
163
164 SprinterLayout(const SprinterLayout &layout):
165 arrayChars(layout.arrayChars), mapChars(layout.mapChars), pairChars(layout.pairChars),
166 stringChars(layout.stringChars), keyChars(layout.keyChars), mapPairChars(layout.mapPairChars){
167 }
168
169
170 SprinterLayout(char itemSeparator){ // ','
171 arrayChars.separator = itemSeparator;
172 mapChars.separator = itemSeparator;
173 pairChars.separator = itemSeparator;
174 mapPairChars.separator = itemSeparator;
175 }
176
177
178
179};
180
181// Mainly for debugging
182inline
183std::ostream & operator<<(std::ostream & ostr, const SprinterLayout & layout){
184 ostr << "arrayChars: " << layout.arrayChars << '\n';
185 ostr << "mapChars: " << layout.mapChars << '\n';
186 ostr << "pairChars: " << layout.pairChars << '\n';
187 ostr << "stringChars: " << layout.stringChars << '\n';
188 ostr << "keyChars: " << layout.keyChars << '\n';
189 ostr << "mapPairChars: " << layout.mapPairChars << '\n';
190 return ostr;
191}
192
198class Sprinter {
199
200public:
201
204
207
210
213
216
218
225
228
231
233
240
242
249
251 static const SprinterLayout cmdLineLayout; // = {":", ",", "=", ""};
252
254 // static const SprinterLayout dictLayout; // = {",", "?", "=", ""};
255
256 static inline
257 void prefixToStream(std::ostream & ostr, const TypeLayout & layout){
258 if (layout.prefix)
259 ostr << layout.prefix;
260 };
261
262 static inline
263 void separatorToStream(std::ostream & ostr, const TypeLayout & layout){
264 if (layout.separator)
265 ostr << layout.separator;
266 };
267
268 static inline
269 void suffixToStream(std::ostream & ostr, const TypeLayout & layout){
270 if (layout.suffix)
271 ostr << layout.suffix;
272 };
273
274
275 // Complicated, but universal...
276 template <class K, class V>
277 static
278 std::ostream & pairToStream(std::ostream & ostr, const std::pair<K,V> & x, const SprinterLayout & layout){
279
280 prefixToStream(ostr, layout.pairChars);
281
282 // EXPERIMENTAL
283 prefixToStream(ostr, layout.keyChars);
284 //toStream(ostr, x.first, layout);
285 ostr << x.first;
286 suffixToStream(ostr, layout.keyChars);
287
288 separatorToStream(ostr, layout.pairChars);
289
290 toStream(ostr, x.second, layout);
291
292 suffixToStream(ostr, layout.pairChars);
293
294 return ostr;
295 }
296
298 template <class K, class V>
299 static
300 std::ostream & mapPairToStream(std::ostream & ostr, const std::pair<K,V> & x, const SprinterLayout & layout){
301
302 prefixToStream(ostr, layout.mapPairChars);
303
304 // EXPERIMENTAL
305 prefixToStream(ostr, layout.keyChars);
306 //toStream(ostr, x.first, layout);
307 ostr << x.first;
308 suffixToStream(ostr, layout.keyChars);
309
310 separatorToStream(ostr, layout.mapPairChars);
311
312 toStream(ostr, x.second, layout); // recursion
313
314 suffixToStream(ostr, layout.mapPairChars);
315
316 return ostr;
317 }
318
319
320
322 template <class T>
323 static
324 std::ostream & sequenceToStream(std::ostream & ostr, const T & x, const SprinterLayout & layout){
325 return sequenceToStream(ostr, x, layout.arrayChars, layout);
326 }
327
328
330 template <class T>
331 static
332 std::ostream & sequenceToStream(std::ostream & ostr, const T & x, const TypeLayout & myChars, const SprinterLayout & layout){
333
334 prefixToStream(ostr, myChars);
335
336 bool first = true;
337 for (const auto & elem: x){
338
339 if (first)
340 first = false;
341 else
342 separatorToStream(ostr, myChars);
343
344 toStream(ostr, elem, layout);
345 }
346
347 suffixToStream(ostr, myChars);
348
349 return ostr;
350
351 }
352
354
361 template <class M, class K>
362 static
363 std::ostream & mapToStream(std::ostream & ostr, const M & m, const SprinterLayout & layout, const K & keys){
364
365 prefixToStream(ostr, layout.mapChars); // redesign: layout.startMap(ostr)
366 //if (layout.mapChars.prefix)
367 // ostr << layout.mapChars.prefix;
368
369 const bool MAP_PAIRS = !layout.mapPairChars.empty();
370
371 // char sep = 0; // for (const typename K::value_type & key =
372 for (typename K::const_iterator it=keys.begin(); it != keys.end(); ++it){
373
374 if (it != keys.begin())
375 separatorToStream(ostr, layout.mapChars);
376
377 typename M::const_iterator mit = m.find(*it);
378 if (mit != m.end()){
379 if (MAP_PAIRS){
380 mapPairToStream(ostr, *mit, layout);
381 }
382 else {
383 toStream(ostr, *mit, layout);
384 }
385 }
386 else {
387 std::cerr << __FILE__ << __FUNCTION__ << ':' << "missing key: " << *it << std::endl;
388 }
389
390 }
391
392 suffixToStream(ostr, layout.mapChars); // redesign: layout.endMap(ostr) or layout.mapLayout.putStart(ostr); .putEnd(ostr);
393
394 return ostr;
395
396 }
397
398
400 //template <class T, bool EXCL>
401 //static
402 //std::ostream & treeToStream(std::ostream & ostr, const Tree<T,EXCL> & tree, const drain::SprinterLayout & layout, short indent){
403 template <class T>
404 static
405 std::ostream & treeToStream(std::ostream & ostr, const T & tree, const drain::SprinterLayout & layout, short indent=0);
406
407
409 template <class T>
410 static
411 std::ostream & basicToStream(std::ostream & ostr, const T & x, const TypeLayout & myChars){
412 prefixToStream(ostr, myChars);
413 ostr << x;
414 suffixToStream(ostr, myChars);
415 return ostr;
416 }
417
418 // std::ostream & mapToStream(std::ostream & ostr, const T & x){
419
421 template <class T>
422 static
423 std::ostream & toStream(std::ostream & ostr, const std::initializer_list<T> & x, const SprinterLayout & layout = defaultLayout){
424 //ostr << x.size() << '@';
425 return sequenceToStream(ostr, x, layout.arrayChars, layout);
426 }
427
428 template <class K, class V>
429 static
430 std::ostream & toStream(std::ostream & ostr, const std::pair<K,V> & x, const SprinterLayout & layout = defaultLayout){
431 return pairToStream(ostr, x, layout);
432 }
433
434 template <class D>
435 static
436 std::ostream & toStream(std::ostream & ostr, const std::vector<D> & x, const SprinterLayout & layout = defaultLayout){
437 return sequenceToStream(ostr, x, layout.arrayChars, layout);
438 }
439
440 template <class D>
441 static
442 std::ostream & toStream(std::ostream & ostr, const std::list<D> & x, const SprinterLayout & layout = defaultLayout){
443 return sequenceToStream(ostr, x, layout.arrayChars, layout);
444 }
445
446 template <class D>
447 static
448 std::ostream & toStream(std::ostream & ostr, const std::set<D> & x, const SprinterLayout & layout = defaultLayout){
449 return sequenceToStream(ostr, x, layout.arrayChars, layout);
450 }
451
452 template <class K, class V>
453 static
454 std::ostream & toStream(std::ostream & ostr, const std::map<K,V> & x, const SprinterLayout & layout = UNSET_LAYOUT){
455
456 if (&layout == &UNSET_LAYOUT){
457 return sequenceToStream(ostr, x, jsonLayout.mapChars, jsonLayout);
458 }
459 else {
460 return sequenceToStream(ostr, x, layout.mapChars, layout);
461 }
462 //return mapToStream(ostr, x);
463 }
464
465 template <class D, size_t N>
466 static inline
467 std::ostream & toStream(std::ostream & ostr, const drain::UniTuple<D,N> & x, const SprinterLayout & layout = defaultLayout){
468 return sequenceToStream(ostr, x, layout.arrayChars, layout);
469 }
470
472 static
473 std::ostream & toStream(std::ostream & ostr, const std::string & x, const SprinterLayout & layout = defaultLayout) {
474 return basicToStream(ostr, x, layout.stringChars);
475 //return ostr << layout.stringChars.prefix << x << layout.stringChars.suffix;
476 }
477
479 static
480 std::ostream & toStream(std::ostream & ostr, const char *x, const SprinterLayout & layout = defaultLayout) {
481 return basicToStream(ostr, x, layout.stringChars);
482 //return ostr << layout.stringChars.prefix << x << layout.stringChars.suffix;
483 }
484
486 static
487 std::ostream & toStream(std::ostream & ostr, char c, const SprinterLayout & layout = defaultLayout) { // short int?
488 return basicToStream(ostr, c, layout.stringChars);
489 }
490
492 static
493 std::ostream & toStream(std::ostream & ostr, bool b, const SprinterLayout & = defaultLayout) { // short int?
494 //return basicToStream(ostr, b?"true":"false", layout.stringChars);
495 return ostr << (b ? "true":"false");
496 }
497
498
500 template <class D>
501 static
502 std::ostream & toStream(std::ostream & ostr, D *x, const SprinterLayout & = defaultLayout) {
503 if (x == nullptr)
504 return ostr << "null";
505 else if (x == 0)
506 return ostr << "null";
507 else
508 return ostr << *x;
509 }
510
512 template <class D>
513 static
514 std::ostream & toStream(std::ostream & ostr, const D *x, const SprinterLayout & = defaultLayout) {
515 return ostr << *x;
516 }
517
519 template <class D>
520 static
521 std::ostream & toStream(std::ostream & ostr, const D &x, const SprinterLayout & = defaultLayout) {
522 return ostr << x;
523 }
524
525
526};
527
528
529
530template <class T>
531std::ostream & Sprinter::treeToStream(std::ostream & ostr, const T & tree, const drain::SprinterLayout & layout, short indent){
532// template <class T, bool EXCL>//
533// std::ostream & Sprinter::treeToStream(std::ostream & ostr, const Tree<T,EXCL> & tree, const drain::SprinterLayout & layout, short indent){
534
535 const bool DATA = !tree.data.empty();
536 const bool CHILDREN = !tree.empty();
537
538 if (! (DATA||CHILDREN)){
539 // Also empty element should return something, here {}, but could be "" or null ?
540 ostr << layout.mapChars.prefix << layout.mapChars.suffix; // '\n';
541 return ostr;
542 }
543
544 const std::string pad(2*indent, ' ');
545
546
547 if (DATA){
548 drain::Sprinter::toStream(ostr, tree.data, layout);
549 //return ostr;
550 /*
551 char sep = 0;
552 for (const auto & entry: tree.data){
553 if (sep){
554 ostr << sep;
555 ostr << '\n';
556 }
557 else {
558 sep = layout.mapChars.separator;
559 }
560 ostr << pad << " " << '"' << entry.first << '"' << layout.pairChars.separator << ' ';
561 drain::Sprinter::toStream(ostr, entry.second, layout);
562 }
563 */
564 if (CHILDREN)
565 ostr << layout.mapChars.separator;
566 ostr << '\n';
567 }
568
569 ostr << layout.mapChars.prefix << '\n';
570
571 if (CHILDREN){
572 char sep = 0;
573 for (const auto & entry: tree){
574 if (sep){
575 ostr << sep;
576 ostr << '\n';
577 }
578 else {
579 sep = layout.mapChars.separator;
580 }
581 ostr << pad << " " << '"' << entry.first << '"' << layout.pairChars.separator << ' '; // if empty?
582 treeToStream(ostr, entry.second, layout, indent+1); // recursion
583 }
584 ostr << '\n';
585 }
586
587 ostr << pad << layout.mapChars.suffix; // << '\n';
588
589 return ostr;
590}
591
592
593// MOVE to json files const SprinterLayout Sprinter::layoutJSON;
594
596
604template <class T, class L=SprinterLayout>
605class Sprintlet : public Sprinter {
606
607public:
608
609 const T & src;
610 SprinterLayout layout;
611
612 Sprintlet(const T & x, const SprinterLayout & layout = L()) : src(x), layout(layout) {
613 }
614 // Dangerous? Sprinter(const Sprinter<T> & x) : src(x.src){}
615
616 std::ostream & toStream(std::ostream & ostr) const {
617 return Sprinter::toStream(ostr, src, layout);
618 }
619
620 std::string str() const {
621 std::stringstream sstr;
622 Sprinter::toStream(sstr, src, layout);
623 return sstr.str();
624 }
625
626};
627
628
629template <class T, class L>
630inline
631std::ostream & operator<<(std::ostream & ostr, const Sprintlet<T,L> & sp){
632 return sp.toStream(ostr);
633}
634
635
636// Short cut (constructor wrappers)
637
638template <class T>
639inline
640Sprintlet<T> sprinter(const T & x, const char *arrayCaps, const char *mapCaps="{,}", const char *pairCaps="(:)", const char *stringCaps="\""){
641 return Sprintlet<T>(x, SprinterLayout(arrayCaps,mapCaps,pairCaps,stringCaps)); // copy const
642}
643
644// SprinterLayout
645template <class T>
646inline
647Sprintlet<T> sprinter(const T & x, const SprinterLayout & layout = Sprinter::jsonLayout){
648 return Sprintlet<T>(x, layout); // copy const
649}
650
651
652} // drain
653
654
655#endif
656
Definition Sprinter.h:198
static std::ostream & toStream(std::ostream &ostr, const std::initializer_list< T > &x, const SprinterLayout &layout=defaultLayout)
New (experimental)
Definition Sprinter.h:423
static std::ostream & mapPairToStream(std::ostream &ostr, const std::pair< K, V > &x, const SprinterLayout &layout)
If (key,value) pairs needs specific layout in maps, use this. (Compare with list of tuples).
Definition Sprinter.h:300
static const SprinterLayout xmlAttributeLayout
Like attributes in XML (HTML, SVG, ...) tags.
Definition Sprinter.h:230
static std::ostream & toStream(std::ostream &ostr, const char *x, const SprinterLayout &layout=defaultLayout)
Conventional type: C string.
Definition Sprinter.h:480
static std::ostream & sequenceToStream(std::ostream &ostr, const T &x, const SprinterLayout &layout)
Convenience: if sequence type (array, list, set, map) not given, assume array.
Definition Sprinter.h:324
static const SprinterLayout pythonLayout
C++ code initializer list style: all objects with {...}, with comma ',' separator.
Definition Sprinter.h:248
static const SprinterLayout emptyLayout
Simply concatenate values without punctuation.
Definition Sprinter.h:209
static const SprinterLayout plainLayout
Display plain values, concatenating them with comma (except for strings).
Definition Sprinter.h:212
static void prefixToStream(std::ostream &ostr, const TypeLayout &layout)
Output Dictionary, which is a list.
Definition Sprinter.h:257
static std::ostream & toStream(std::ostream &ostr, const std::string &x, const SprinterLayout &layout=defaultLayout)
Conventional type: std::string. Notice prefix revealed.
Definition Sprinter.h:473
static const SprinterLayout defaultLayout
Displays objects with {...}, arrays with [...], pairs with (,) and strings without hyphens.
Definition Sprinter.h:206
static const SprinterLayout jsLayout
JavaScript layout. Like JSON layout, but keys without hyphens.
Definition Sprinter.h:227
static std::ostream & toStream(std::ostream &ostr, D *x, const SprinterLayout &=defaultLayout)
Pointer: redirect to actual target object.
Definition Sprinter.h:502
static std::ostream & toStream(std::ostream &ostr, const D &x, const SprinterLayout &=defaultLayout)
Default, unformatted output for basetypes and types not matching the other templates.
Definition Sprinter.h:521
static std::ostream & treeToStream(std::ostream &ostr, const T &tree, const drain::SprinterLayout &layout, short indent=0)
Write drain::Tree's or any trees that have tree::data[] member.
Definition Sprinter.h:531
static std::ostream & toStream(std::ostream &ostr, const D *x, const SprinterLayout &=defaultLayout)
Pointer: redirect to actual target object.
Definition Sprinter.h:514
static const SprinterLayout lineLayout
Put each array and object element on a separate line.
Definition Sprinter.h:215
static std::ostream & toStream(std::ostream &ostr, bool b, const SprinterLayout &=defaultLayout)
Single char gets styled same way as strings.
Definition Sprinter.h:493
static std::ostream & basicToStream(std::ostream &ostr, const T &x, const TypeLayout &myChars)
Routine for non-sequence types that may like prefix and suffix, anyway.
Definition Sprinter.h:411
static const SprinterLayout cppLayout
C++ code initializer list style: all objects with {...}, with comma ',' separator.
Definition Sprinter.h:239
static std::ostream & sequenceToStream(std::ostream &ostr, const T &x, const TypeLayout &myChars, const SprinterLayout &layout)
Print sequence x with myChars, continue recursively with layout.
Definition Sprinter.h:332
static std::ostream & toStream(std::ostream &ostr, char c, const SprinterLayout &layout=defaultLayout)
Single char gets styled same way as strings.
Definition Sprinter.h:487
static std::ostream & mapToStream(std::ostream &ostr, const M &m, const SprinterLayout &layout, const K &keys)
Given a sequence or subsequence of keys, output values of a map in that order.
Definition Sprinter.h:363
static const SprinterLayout UNSET_LAYOUT
Marker for unset layout.
Definition Sprinter.h:203
static const SprinterLayout cmdLineLayout
Simulates how arguments are given to command line options.
Definition Sprinter.h:251
static const SprinterLayout jsonLayout
Resembles JSON structure: {"a":1,"b":22,"c":3}.
Definition Sprinter.h:224
Definition Sprinter.h:605
tuplebase_t & assignSequence(T &sequence, bool LENIENT=false)
Proposed for tuples only; derived classes should not shadow this.
Definition TupleBase.h:287
Small container for printing style for putting of structured objects (array, maps,...
Definition Sprinter.h:57
Tuple of N elements of type T.
Definition UniTuple.h:65
Definition Data.h:1473
Definition Sprinter.h:136
Definition Sprinter.h:79
TypeLayout(const char layout[4])
Constructor accepting three-letter chars: {prefix,separator,suffix}.
Definition Sprinter.h:101
TypeLayout & setLayout(const char *layout)
Set layout with a single string, for example: "{,}" .
Definition Sprinter.cpp:41
TypeLayout(cstr_t prefix, cstr_t separator, cstr_t suffix)
Constructor.
Definition Sprinter.h:96
TypeLayout(cstr_t separator=',')
Constructor for simple layout using a separator but no parentheses/braces.
Definition Sprinter.h:83
TypeLayout(cstr_t prefix, cstr_t suffix)
Constructor.
Definition Sprinter.h:91