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#include <stdexcept>
37
38#include <string>
39#include <utility> // pair
40#include <vector>
41#include <set>
42#include <list>
43#include <map>
44
45#include <drain/UniTuple.h>
46
47
48
49namespace drain {
50
51
53
58class TypeLayoutBase : public UniTuple<char,3>{
59
60public:
61
62 typedef char cstr_t;
63 cstr_t & prefix;
64 cstr_t & separator;
65 cstr_t & suffix;
66
67 inline
68 TypeLayoutBase(): // chars('\0',3), prefix(chars[0]), separator(chars[1]), suffix(chars[2]){
69 prefix(this->next()), separator(this->next()), suffix(this->next()){
70 }
71
72 inline
73 bool empty() const { // conside rename isDefined(), esp. if functions used later ?
74 return ((prefix==0) && (separator==0) && (suffix==0));
75 }
76
77
78};
79
80struct TypeLayout : public TypeLayoutBase{
81
82
84 TypeLayout(cstr_t separator=','){
85 set(0, separator, 0);
86 }
87
89 /***
90 * Notice that arguments (a,b) invoke set(a,0,b), not set(a,b).
91 */
92 TypeLayout(cstr_t prefix, cstr_t suffix){
93 set(prefix, 0, suffix);
94 }
95
97 TypeLayout(cstr_t prefix, cstr_t separator, cstr_t suffix){
98 set(prefix, separator, suffix);
99 }
100
102 TypeLayout(const char layout[4]){ // = "{,}"
103 setLayout(layout);
104 }
105
106 TypeLayout(const TypeLayout & layout){
107 this->assignSequence(layout);
108 //this->assign(layout); // NOTE: copying element by element, not involving strings possibly containing null char (premature end-or-read).
109 }
110
112
120 TypeLayout & setLayout(const char *layout);
121
122
123
124};
125
126
138
139 // char itemSeparator = ','; // consider as equal sign: KEY:VALUE
140 TypeLayout arrayChars = TypeLayout("[,]");
141 TypeLayout mapChars = TypeLayout("{,}");
142 TypeLayout pairChars = TypeLayout("(,)"); // layout for (key,value), see keyChars
143 TypeLayout stringChars = TypeLayout('"',0,'"'); // TODO: Separate value and sequence layouts?
144 TypeLayout keyChars = TypeLayout(0,0,0); // given a pair = (key,value), defined how the key is .
145 TypeLayout mapPairChars = TypeLayout(0,0,0); // When a map {entry, entry,... } is rendered, defines how
146
147 // TypeLayout stringChars = TypeLayout("\"\"");
148 // std::string boolTrue = "true";
149 // std::string boolFalse = "false";
150 // std::string nullValue = "null";
151
152 SprinterLayout(const char *arrayChars="[,]", const char *mapChars="{,}", const char *pairChars="(,)",
153 const char *stringChars=nullptr, const char *keyChars=nullptr, const char *mapPairChars=nullptr){
154 this->arrayChars.setLayout(arrayChars);
155 this->mapChars.setLayout(mapChars);
156 this->pairChars.setLayout(pairChars);
157 if (stringChars)
158 this->stringChars.setLayout(stringChars);
159 if (keyChars)
160 this->keyChars.setLayout(keyChars);
161 if (mapPairChars)
162 this->mapPairChars.setLayout(mapPairChars);
163 }
164
165 SprinterLayout(const SprinterLayout &layout):
166 arrayChars(layout.arrayChars), mapChars(layout.mapChars), pairChars(layout.pairChars),
167 stringChars(layout.stringChars), keyChars(layout.keyChars), mapPairChars(layout.mapPairChars){
168 }
169
170
171 SprinterLayout(char itemSeparator){ // ','
172 arrayChars.separator = itemSeparator;
173 mapChars.separator = itemSeparator;
174 pairChars.separator = itemSeparator;
175 mapPairChars.separator = itemSeparator;
176 }
177
178
179
180};
181
182// Mainly for debugging
183inline
184std::ostream & operator<<(std::ostream & ostr, const SprinterLayout & layout){
185 ostr << "arrayChars: " << layout.arrayChars << '\n';
186 ostr << "mapChars: " << layout.mapChars << '\n';
187 ostr << "pairChars: " << layout.pairChars << '\n';
188 ostr << "stringChars: " << layout.stringChars << '\n';
189 ostr << "keyChars: " << layout.keyChars << '\n';
190 ostr << "mapPairChars: " << layout.mapPairChars << '\n';
191 return ostr;
192}
193
199class Sprinter {
200
201public:
202
205
208
211
214
217
219
226
229
232
234
241
243
250
252 static const SprinterLayout cmdLineLayout; // = {":", ",", "=", ""};
253
255 // static const SprinterLayout dictLayout; // = {",", "?", "=", ""};
256
257 static inline
258 void prefixToStream(std::ostream & ostr, const TypeLayout & layout){
259 if (layout.prefix)
260 ostr << layout.prefix;
261 };
262
263 static inline
264 void separatorToStream(std::ostream & ostr, const TypeLayout & layout){
265 if (layout.separator)
266 ostr << layout.separator;
267 };
268
269 static inline
270 void suffixToStream(std::ostream & ostr, const TypeLayout & layout){
271 if (layout.suffix)
272 ostr << layout.suffix;
273 };
274
275
276 // Complicated, but universal...
277 template <class K, class V>
278 static
279 std::ostream & pairToStream(std::ostream & ostr, const std::pair<K,V> & x, const SprinterLayout & layout){
280
281 prefixToStream(ostr, layout.pairChars);
282
283 // EXPERIMENTAL
284 prefixToStream(ostr, layout.keyChars);
285 //toStream(ostr, x.first, layout);
286 ostr << x.first;
287 suffixToStream(ostr, layout.keyChars);
288
289 separatorToStream(ostr, layout.pairChars);
290
291 toStream(ostr, x.second, layout);
292
293 suffixToStream(ostr, layout.pairChars);
294
295 return ostr;
296 }
297
299 template <class K, class V>
300 static
301 std::ostream & mapPairToStream(std::ostream & ostr, const std::pair<K,V> & x, const SprinterLayout & layout){
302
303 prefixToStream(ostr, layout.mapPairChars);
304
305 // EXPERIMENTAL
306 prefixToStream(ostr, layout.keyChars);
307 //toStream(ostr, x.first, layout);
308 ostr << x.first;
309 suffixToStream(ostr, layout.keyChars);
310
311 separatorToStream(ostr, layout.mapPairChars);
312
313 toStream(ostr, x.second, layout); // recursion
314
315 suffixToStream(ostr, layout.mapPairChars);
316
317 return ostr;
318 }
319
320
321
323 template <class T>
324 static
325 std::ostream & sequenceToStream(std::ostream & ostr, const T & x, const SprinterLayout & layout){
326 return sequenceToStream(ostr, x, layout.arrayChars, layout);
327 }
328
329
331 template <class T>
332 static
333 std::ostream & sequenceToStream(std::ostream & ostr, const T & x, const TypeLayout & myChars, const SprinterLayout & layout){
334
335 prefixToStream(ostr, myChars);
336
337 bool first = true;
338 for (const auto & elem: x){
339
340 if (first)
341 first = false;
342 else
343 separatorToStream(ostr, myChars);
344
345 toStream(ostr, elem, layout);
346 }
347
348 suffixToStream(ostr, myChars);
349
350 return ostr;
351
352 }
353
355
362 template <class M, class K>
363 static
364 std::ostream & mapToStream(std::ostream & ostr, const M & m, const SprinterLayout & layout, const K & keys){
365
366 prefixToStream(ostr, layout.mapChars); // redesign: layout.startMap(ostr)
367 //if (layout.mapChars.prefix)
368 // ostr << layout.mapChars.prefix;
369
370 const bool MAP_PAIRS = !layout.mapPairChars.empty();
371
372 // char sep = 0; // for (const typename K::value_type & key =
373 for (typename K::const_iterator it=keys.begin(); it != keys.end(); ++it){
374
375 if (it != keys.begin())
376 separatorToStream(ostr, layout.mapChars);
377
378 typename M::const_iterator mit = m.find(*it);
379 if (mit != m.end()){
380 if (MAP_PAIRS){
381 mapPairToStream(ostr, *mit, layout);
382 }
383 else {
384 toStream(ostr, *mit, layout);
385 }
386 }
387 else {
388 std::cerr << __FILE__ << __FUNCTION__ << ':' << "missing key: " << *it << std::endl;
389 }
390
391 }
392
393 suffixToStream(ostr, layout.mapChars); // redesign: layout.endMap(ostr) or layout.mapLayout.putStart(ostr); .putEnd(ostr);
394
395 return ostr;
396
397 }
398
399
401 //template <class T, bool EXCL>
402 //static
403 //std::ostream & treeToStream(std::ostream & ostr, const Tree<T,EXCL> & tree, const drain::SprinterLayout & layout, short indent){
404 template <class T>
405 static
406 std::ostream & treeToStream(std::ostream & ostr, const T & tree, const drain::SprinterLayout & layout, short indent=0);
407
408
410 template <class T>
411 static
412 std::ostream & basicToStream(std::ostream & ostr, const T & x, const TypeLayout & myChars){
413 prefixToStream(ostr, myChars);
414 ostr << x;
415 suffixToStream(ostr, myChars);
416 return ostr;
417 }
418
419 // std::ostream & mapToStream(std::ostream & ostr, const T & x){
420
422 template <class T>
423 static
424 std::ostream & toStream(std::ostream & ostr, const std::initializer_list<T> & x, const SprinterLayout & layout = defaultLayout){
425 //ostr << x.size() << '@';
426 return sequenceToStream(ostr, x, layout.arrayChars, layout);
427 }
428
429 template <class K, class V>
430 static
431 std::ostream & toStream(std::ostream & ostr, const std::pair<K,V> & x, const SprinterLayout & layout = defaultLayout){
432 return pairToStream(ostr, x, layout);
433 }
434
435 template <class D>
436 static
437 std::ostream & toStream(std::ostream & ostr, const std::vector<D> & x, const SprinterLayout & layout = defaultLayout){
438 return sequenceToStream(ostr, x, layout.arrayChars, layout);
439 }
440
441 template <class D>
442 static
443 std::ostream & toStream(std::ostream & ostr, const std::list<D> & x, const SprinterLayout & layout = defaultLayout){
444 return sequenceToStream(ostr, x, layout.arrayChars, layout);
445 }
446
447 template <class D>
448 static
449 std::ostream & toStream(std::ostream & ostr, const std::set<D> & x, const SprinterLayout & layout = defaultLayout){
450 return sequenceToStream(ostr, x, layout.arrayChars, layout);
451 }
452
453 template <class K, class V>
454 static
455 std::ostream & toStream(std::ostream & ostr, const std::map<K,V> & x, const SprinterLayout & layout = UNSET_LAYOUT){
456
457 if (&layout == &UNSET_LAYOUT){
458 return sequenceToStream(ostr, x, jsonLayout.mapChars, jsonLayout);
459 }
460 else {
461 return sequenceToStream(ostr, x, layout.mapChars, layout);
462 }
463 //return mapToStream(ostr, x);
464 }
465
466 template <class D, size_t N>
467 static inline
468 std::ostream & toStream(std::ostream & ostr, const drain::UniTuple<D,N> & x, const SprinterLayout & layout = defaultLayout){
469 return sequenceToStream(ostr, x, layout.arrayChars, layout);
470 }
471
473 static
474 std::ostream & toStream(std::ostream & ostr, const std::string & x, const SprinterLayout & layout = defaultLayout) {
475 return basicToStream(ostr, x, layout.stringChars);
476 //return ostr << layout.stringChars.prefix << x << layout.stringChars.suffix;
477 }
478
480 static
481 std::ostream & toStream(std::ostream & ostr, const char *x, const SprinterLayout & layout = defaultLayout) {
482 return basicToStream(ostr, x, layout.stringChars);
483 //return ostr << layout.stringChars.prefix << x << layout.stringChars.suffix;
484 }
485
487 static
488 std::ostream & toStream(std::ostream & ostr, char c, const SprinterLayout & layout = defaultLayout) { // short int?
489 return basicToStream(ostr, c, layout.stringChars);
490 }
491
493 static
494 std::ostream & toStream(std::ostream & ostr, bool b, const SprinterLayout & layout = defaultLayout) { // short int?
495 //return basicToStream(ostr, b?"true":"false", layout.stringChars);
496 return ostr << (b ? "true":"false");
497 }
498
499
501 template <class D>
502 static
503 std::ostream & toStream(std::ostream & ostr, D *x, const SprinterLayout & layout = defaultLayout) {
504 if (x == nullptr)
505 return ostr << "null";
506 else if (x == 0)
507 return ostr << "null";
508 else
509 return ostr << *x;
510 }
511
513 template <class D>
514 static
515 std::ostream & toStream(std::ostream & ostr, const D *x, const SprinterLayout & layout = defaultLayout) {
516 return ostr << *x;
517 }
518
520 template <class D>
521 static
522 std::ostream & toStream(std::ostream & ostr, const D &x, const SprinterLayout & layout = defaultLayout) {
523 // Layout not used
524 return ostr << x;
525 }
526
527
528};
529
530
531
532template <class T>
533std::ostream & Sprinter::treeToStream(std::ostream & ostr, const T & tree, const drain::SprinterLayout & layout, short indent){
534// template <class T, bool EXCL>//
535// std::ostream & Sprinter::treeToStream(std::ostream & ostr, const Tree<T,EXCL> & tree, const drain::SprinterLayout & layout, short indent){
536
537 const bool DATA = !tree.data.empty();
538 const bool CHILDREN = !tree.empty();
539
540 if (! (DATA||CHILDREN)){
541 // Also empty element should return something, here {}, but could be "" or null ?
542 ostr << layout.mapChars.prefix << layout.mapChars.suffix; // '\n';
543 return ostr;
544 }
545
546 const std::string pad(2*indent, ' ');
547
548
549 if (DATA){
550 drain::Sprinter::toStream(ostr, tree.data, layout);
551 //return ostr;
552 /*
553 char sep = 0;
554 for (const auto & entry: tree.data){
555 if (sep){
556 ostr << sep;
557 ostr << '\n';
558 }
559 else {
560 sep = layout.mapChars.separator;
561 }
562 ostr << pad << " " << '"' << entry.first << '"' << layout.pairChars.separator << ' ';
563 drain::Sprinter::toStream(ostr, entry.second, layout);
564 }
565 */
566 if (CHILDREN)
567 ostr << layout.mapChars.separator;
568 ostr << '\n';
569 }
570
571 ostr << layout.mapChars.prefix << '\n';
572
573 if (CHILDREN){
574 char sep = 0;
575 for (const auto & entry: tree){
576 if (sep){
577 ostr << sep;
578 ostr << '\n';
579 }
580 else {
581 sep = layout.mapChars.separator;
582 }
583 ostr << pad << " " << '"' << entry.first << '"' << layout.pairChars.separator << ' '; // if empty?
584 treeToStream(ostr, entry.second, layout, indent+1); // recursion
585 }
586 ostr << '\n';
587 }
588
589 ostr << pad << layout.mapChars.suffix; // << '\n';
590
591 return ostr;
592}
593
594
595// MOVE to json files const SprinterLayout Sprinter::layoutJSON;
596
598
606template <class T, class L=SprinterLayout>
607class Sprintlet : public Sprinter {
608
609public:
610
611 const T & src;
612 SprinterLayout layout;
613
614 Sprintlet(const T & x, const SprinterLayout & layout = L()) : src(x), layout(layout) {
615 }
616 // Dangerous? Sprinter(const Sprinter<T> & x) : src(x.src){}
617
618 std::ostream & toStream(std::ostream & ostr) const {
619 return Sprinter::toStream(ostr, src, layout);
620 }
621
622 std::string str() const {
623 std::stringstream sstr;
624 Sprinter::toStream(sstr, src, layout);
625 return sstr.str();
626 }
627
628};
629
630
631template <class T, class L>
632inline
633std::ostream & operator<<(std::ostream & ostr, const Sprintlet<T,L> & sp){
634 return sp.toStream(ostr);
635}
636
637
638// Short cut (constructor wrappers)
639
640template <class T>
641inline
642Sprintlet<T> sprinter(const T & x, const char *arrayCaps, const char *mapCaps="{,}", const char *pairCaps="(:)", const char *stringCaps="\""){
643 return Sprintlet<T>(x, SprinterLayout(arrayCaps,mapCaps,pairCaps,stringCaps)); // copy const
644}
645
646template <class T>
647inline
648Sprintlet<T> sprinter(const T & x, const SprinterLayout & layout = SprinterLayout()){
649 return Sprintlet<T>(x, layout); // copy const
650}
651
652
653} // drain
654
655
656#endif
657
Definition Sprinter.h:199
static std::ostream & toStream(std::ostream &ostr, const std::initializer_list< T > &x, const SprinterLayout &layout=defaultLayout)
New (experimental)
Definition Sprinter.h:424
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:301
static const SprinterLayout xmlAttributeLayout
Like attributes in XML (HTML, SVG, ...) tags.
Definition Sprinter.h:231
static std::ostream & toStream(std::ostream &ostr, const char *x, const SprinterLayout &layout=defaultLayout)
Conventional type: C string.
Definition Sprinter.h:481
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:325
static const SprinterLayout pythonLayout
C++ code initializer list style: all objects with {...}, with comma ',' separator.
Definition Sprinter.h:249
static const SprinterLayout emptyLayout
Simply concatenate values without punctuation.
Definition Sprinter.h:210
static const SprinterLayout plainLayout
Display plain values, concatenating them with comma (except for strings).
Definition Sprinter.h:213
static void prefixToStream(std::ostream &ostr, const TypeLayout &layout)
Output Dictionary, which is a list.
Definition Sprinter.h:258
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:474
static const SprinterLayout defaultLayout
Displays objects with {...}, arrays with [...], pairs with (,) and strings without hyphens.
Definition Sprinter.h:207
static const SprinterLayout jsLayout
JavaScript layout. Like JSON layout, but keys without hyphens.
Definition Sprinter.h:228
static std::ostream & toStream(std::ostream &ostr, bool b, const SprinterLayout &layout=defaultLayout)
Single char gets styled same way as strings.
Definition Sprinter.h:494
static std::ostream & toStream(std::ostream &ostr, D *x, const SprinterLayout &layout=defaultLayout)
Pointer: redirect to actual target object.
Definition Sprinter.h:503
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:533
static const SprinterLayout lineLayout
Put each array and object element on a separate line.
Definition Sprinter.h:216
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:412
static const SprinterLayout cppLayout
C++ code initializer list style: all objects with {...}, with comma ',' separator.
Definition Sprinter.h:240
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:333
static std::ostream & toStream(std::ostream &ostr, char c, const SprinterLayout &layout=defaultLayout)
Single char gets styled same way as strings.
Definition Sprinter.h:488
static std::ostream & toStream(std::ostream &ostr, const D *x, const SprinterLayout &layout=defaultLayout)
Pointer: redirect to actual target object.
Definition Sprinter.h:515
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:364
static const SprinterLayout UNSET_LAYOUT
Marker for unset layout.
Definition Sprinter.h:204
static const SprinterLayout cmdLineLayout
Simulates how arguments are given to command line options.
Definition Sprinter.h:252
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:522
static const SprinterLayout jsonLayout
Resembles JSON structure: {"a":1,"b":22,"c":3}.
Definition Sprinter.h:225
Definition Sprinter.h:607
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:58
Tuple of N elements of type T.
Definition UniTuple.h:65
Definition DataSelector.cpp:1277
Definition Sprinter.h:137
Definition Sprinter.h:80
TypeLayout(const char layout[4])
Constructor accepting three-letter chars: {prefix,separator,suffix}.
Definition Sprinter.h:102
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:97
TypeLayout(cstr_t separator=',')
Constructor for simple layout using a separator but no parentheses/braces.
Definition Sprinter.h:84
TypeLayout(cstr_t prefix, cstr_t suffix)
Constructor.
Definition Sprinter.h:92