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 & layout = 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 & layout = 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 & layout = 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 & layout = defaultLayout) {
522 // Layout not used
523 return ostr << x;
524 }
525
526
527};
528
529
530
531template <class T>
532std::ostream & Sprinter::treeToStream(std::ostream & ostr, const T & tree, const drain::SprinterLayout & layout, short indent){
533// template <class T, bool EXCL>//
534// std::ostream & Sprinter::treeToStream(std::ostream & ostr, const Tree<T,EXCL> & tree, const drain::SprinterLayout & layout, short indent){
535
536 const bool DATA = !tree.data.empty();
537 const bool CHILDREN = !tree.empty();
538
539 if (! (DATA||CHILDREN)){
540 // Also empty element should return something, here {}, but could be "" or null ?
541 ostr << layout.mapChars.prefix << layout.mapChars.suffix; // '\n';
542 return ostr;
543 }
544
545 const std::string pad(2*indent, ' ');
546
547
548 if (DATA){
549 drain::Sprinter::toStream(ostr, tree.data, layout);
550 //return ostr;
551 /*
552 char sep = 0;
553 for (const auto & entry: tree.data){
554 if (sep){
555 ostr << sep;
556 ostr << '\n';
557 }
558 else {
559 sep = layout.mapChars.separator;
560 }
561 ostr << pad << " " << '"' << entry.first << '"' << layout.pairChars.separator << ' ';
562 drain::Sprinter::toStream(ostr, entry.second, layout);
563 }
564 */
565 if (CHILDREN)
566 ostr << layout.mapChars.separator;
567 ostr << '\n';
568 }
569
570 ostr << layout.mapChars.prefix << '\n';
571
572 if (CHILDREN){
573 char sep = 0;
574 for (const auto & entry: tree){
575 if (sep){
576 ostr << sep;
577 ostr << '\n';
578 }
579 else {
580 sep = layout.mapChars.separator;
581 }
582 ostr << pad << " " << '"' << entry.first << '"' << layout.pairChars.separator << ' '; // if empty?
583 treeToStream(ostr, entry.second, layout, indent+1); // recursion
584 }
585 ostr << '\n';
586 }
587
588 ostr << pad << layout.mapChars.suffix; // << '\n';
589
590 return ostr;
591}
592
593
594// MOVE to json files const SprinterLayout Sprinter::layoutJSON;
595
597
605template <class T, class L=SprinterLayout>
606class Sprintlet : public Sprinter {
607
608public:
609
610 const T & src;
611 SprinterLayout layout;
612
613 Sprintlet(const T & x, const SprinterLayout & layout = L()) : src(x), layout(layout) {
614 }
615 // Dangerous? Sprinter(const Sprinter<T> & x) : src(x.src){}
616
617 std::ostream & toStream(std::ostream & ostr) const {
618 return Sprinter::toStream(ostr, src, layout);
619 }
620
621 std::string str() const {
622 std::stringstream sstr;
623 Sprinter::toStream(sstr, src, layout);
624 return sstr.str();
625 }
626
627};
628
629
630template <class T, class L>
631inline
632std::ostream & operator<<(std::ostream & ostr, const Sprintlet<T,L> & sp){
633 return sp.toStream(ostr);
634}
635
636
637// Short cut (constructor wrappers)
638
639template <class T>
640inline
641Sprintlet<T> sprinter(const T & x, const char *arrayCaps, const char *mapCaps="{,}", const char *pairCaps="(:)", const char *stringCaps="\""){
642 return Sprintlet<T>(x, SprinterLayout(arrayCaps,mapCaps,pairCaps,stringCaps)); // copy const
643}
644
645// SprinterLayout
646template <class T>
647inline
648Sprintlet<T> sprinter(const T & x, const SprinterLayout & layout = Sprinter::jsonLayout){
649 return Sprintlet<T>(x, layout); // copy const
650}
651
652
653} // drain
654
655
656#endif
657
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, bool b, const SprinterLayout &layout=defaultLayout)
Single char gets styled same way as strings.
Definition Sprinter.h:493
static std::ostream & toStream(std::ostream &ostr, D *x, const SprinterLayout &layout=defaultLayout)
Pointer: redirect to actual target object.
Definition Sprinter.h:502
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:532
static const SprinterLayout lineLayout
Put each array and object element on a separate line.
Definition Sprinter.h:215
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 & toStream(std::ostream &ostr, const D *x, const SprinterLayout &layout=defaultLayout)
Pointer: redirect to actual target object.
Definition Sprinter.h:514
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 std::ostream & toStream(std::ostream &ostr, const D &x, const SprinterLayout &layout=defaultLayout)
Default, unformatted output for basetypes and types not matching the other templates.
Definition Sprinter.h:521
static const SprinterLayout jsonLayout
Resembles JSON structure: {"a":1,"b":22,"c":3}.
Definition Sprinter.h:224
Definition Sprinter.h:606
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 DataSelector.cpp:1277
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