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
194
195class Sprinter {
196
197public:
198
201
204
207
210
213
215
222
225
228
230
237
239
246
248 static const SprinterLayout cmdLineLayout; // = {":", ",", "=", ""};
249
251 // static const SprinterLayout dictLayout; // = {",", "?", "=", ""};
252
253 static inline
254 void prefixToStream(std::ostream & ostr, const TypeLayout & layout){
255 if (layout.prefix)
256 ostr << layout.prefix;
257 };
258
259 static inline
260 void separatorToStream(std::ostream & ostr, const TypeLayout & layout){
261 if (layout.separator)
262 ostr << layout.separator;
263 };
264
265 static inline
266 void suffixToStream(std::ostream & ostr, const TypeLayout & layout){
267 if (layout.suffix)
268 ostr << layout.suffix;
269 };
270
271
272 // Complicated, but universal...
273 template <class K, class V>
274 static
275 std::ostream & pairToStream(std::ostream & ostr, const std::pair<K,V> & x, const SprinterLayout & layout){
276
277 prefixToStream(ostr, layout.pairChars);
278
279 // EXPERIMENTAL
280 prefixToStream(ostr, layout.keyChars);
281 //toStream(ostr, x.first, layout);
282 ostr << x.first;
283 suffixToStream(ostr, layout.keyChars);
284
285 separatorToStream(ostr, layout.pairChars);
286
287 toStream(ostr, x.second, layout);
288
289 suffixToStream(ostr, layout.pairChars);
290
291 return ostr;
292 }
293
295 template <class K, class V>
296 static
297 std::ostream & mapPairToStream(std::ostream & ostr, const std::pair<K,V> & x, const SprinterLayout & layout){
298
299 prefixToStream(ostr, layout.mapPairChars);
300
301 // EXPERIMENTAL
302 prefixToStream(ostr, layout.keyChars);
303 //toStream(ostr, x.first, layout);
304 ostr << x.first;
305 suffixToStream(ostr, layout.keyChars);
306
307 separatorToStream(ostr, layout.mapPairChars);
308
309 toStream(ostr, x.second, layout); // recursion
310
311 suffixToStream(ostr, layout.mapPairChars);
312
313 return ostr;
314 }
315
316
317
319 template <class T>
320 static
321 std::ostream & sequenceToStream(std::ostream & ostr, const T & x, const SprinterLayout & layout){
322 return sequenceToStream(ostr, x, layout.arrayChars, layout);
323 }
324
325
327 template <class T>
328 static
329 std::ostream & sequenceToStream(std::ostream & ostr, const T & x, const TypeLayout & myChars, const SprinterLayout & layout){
330
331 prefixToStream(ostr, myChars);
332
333 bool first = true;
334 for (const auto & elem: x){
335
336 if (first)
337 first = false;
338 else
339 separatorToStream(ostr, myChars);
340
341 toStream(ostr, elem, layout);
342 }
343
344 suffixToStream(ostr, myChars);
345
346 return ostr;
347
348 }
349
351
358 template <class M, class K>
359 static
360 std::ostream & mapToStream(std::ostream & ostr, const M & m, const SprinterLayout & layout, const K & keys){
361
362 prefixToStream(ostr, layout.mapChars); // redesign: layout.startMap(ostr)
363 //if (layout.mapChars.prefix)
364 // ostr << layout.mapChars.prefix;
365
366 const bool MAP_PAIRS = !layout.mapPairChars.empty();
367
368 // char sep = 0; // for (const typename K::value_type & key =
369 for (typename K::const_iterator it=keys.begin(); it != keys.end(); ++it){
370
371 if (it != keys.begin())
372 separatorToStream(ostr, layout.mapChars);
373
374 typename M::const_iterator mit = m.find(*it);
375 if (mit != m.end()){
376 if (MAP_PAIRS){
377 mapPairToStream(ostr, *mit, layout);
378 }
379 else {
380 toStream(ostr, *mit, layout);
381 }
382 }
383 else {
384 std::cerr << __FILE__ << __FUNCTION__ << ':' << "missing key: " << *it << std::endl;
385 }
386
387 }
388
389 suffixToStream(ostr, layout.mapChars); // redesign: layout.endMap(ostr) or layout.mapLayout.putStart(ostr); .putEnd(ostr);
390
391 return ostr;
392
393 }
394
395
397 //template <class T, bool EXCL>
398 //static
399 //std::ostream & treeToStream(std::ostream & ostr, const Tree<T,EXCL> & tree, const drain::SprinterLayout & layout, short indent){
400 template <class T>
401 static
402 std::ostream & treeToStream(std::ostream & ostr, const T & tree, const drain::SprinterLayout & layout, short indent=0);
403
404
406 template <class T>
407 static
408 std::ostream & basicToStream(std::ostream & ostr, const T & x, const TypeLayout & myChars){
409 prefixToStream(ostr, myChars);
410 ostr << x;
411 suffixToStream(ostr, myChars);
412 return ostr;
413 }
414
415 // std::ostream & mapToStream(std::ostream & ostr, const T & x){
416
418 template <class T>
419 static
420 std::ostream & toStream(std::ostream & ostr, const std::initializer_list<T> & x, const SprinterLayout & layout = defaultLayout){
421 //ostr << x.size() << '@';
422 return sequenceToStream(ostr, x, layout.arrayChars, layout);
423 }
424
425 template <class K, class V>
426 static
427 std::ostream & toStream(std::ostream & ostr, const std::pair<K,V> & x, const SprinterLayout & layout = defaultLayout){
428 return pairToStream(ostr, x, layout);
429 }
430
431 template <class D>
432 static
433 std::ostream & toStream(std::ostream & ostr, const std::vector<D> & x, const SprinterLayout & layout = defaultLayout){
434 return sequenceToStream(ostr, x, layout.arrayChars, layout);
435 }
436
437 template <class D>
438 static
439 std::ostream & toStream(std::ostream & ostr, const std::list<D> & x, const SprinterLayout & layout = defaultLayout){
440 return sequenceToStream(ostr, x, layout.arrayChars, layout);
441 }
442
443 template <class D>
444 static
445 std::ostream & toStream(std::ostream & ostr, const std::set<D> & x, const SprinterLayout & layout = defaultLayout){
446 return sequenceToStream(ostr, x, layout.arrayChars, layout);
447 }
448
449 template <class K, class V>
450 static
451 std::ostream & toStream(std::ostream & ostr, const std::map<K,V> & x, const SprinterLayout & layout = UNSET_LAYOUT){
452
453 if (&layout == &UNSET_LAYOUT){
454 return sequenceToStream(ostr, x, jsonLayout.mapChars, jsonLayout);
455 }
456 else {
457 return sequenceToStream(ostr, x, layout.mapChars, layout);
458 }
459 //return mapToStream(ostr, x);
460 }
461
462 template <class D, size_t N>
463 static inline
464 std::ostream & toStream(std::ostream & ostr, const drain::UniTuple<D,N> & x, const SprinterLayout & layout = defaultLayout){
465 return sequenceToStream(ostr, x, layout.arrayChars, layout);
466 }
467
469 static
470 std::ostream & toStream(std::ostream & ostr, const std::string & x, const SprinterLayout & layout = defaultLayout) {
471 return basicToStream(ostr, x, layout.stringChars);
472 //return ostr << layout.stringChars.prefix << x << layout.stringChars.suffix;
473 }
474
476 static
477 std::ostream & toStream(std::ostream & ostr, const char *x, const SprinterLayout & layout = defaultLayout) {
478 return basicToStream(ostr, x, layout.stringChars);
479 //return ostr << layout.stringChars.prefix << x << layout.stringChars.suffix;
480 }
481
483 static
484 std::ostream & toStream(std::ostream & ostr, char c, const SprinterLayout & layout = defaultLayout) { // short int?
485 return basicToStream(ostr, c, layout.stringChars);
486 }
487
489 static
490 std::ostream & toStream(std::ostream & ostr, bool b, const SprinterLayout & layout = defaultLayout) { // short int?
491 //return basicToStream(ostr, b?"true":"false", layout.stringChars);
492 return ostr << (b ? "true":"false");
493 }
494
495
497 template <class D>
498 static
499 std::ostream & toStream(std::ostream & ostr, D *x, const SprinterLayout & layout = defaultLayout) {
500 if (x == nullptr)
501 return ostr << "null";
502 else if (x == 0)
503 return ostr << "null";
504 else
505 return ostr << *x;
506 }
507
509 template <class D>
510 static
511 std::ostream & toStream(std::ostream & ostr, const D *x, const SprinterLayout & layout = defaultLayout) {
512 return ostr << *x;
513 }
514
516 template <class D>
517 static
518 std::ostream & toStream(std::ostream & ostr, const D &x, const SprinterLayout & layout = defaultLayout) {
519 // Layout not used
520 return ostr << x;
521 }
522
523
524};
525
526
527
528template <class T>
529std::ostream & Sprinter::treeToStream(std::ostream & ostr, const T & tree, const drain::SprinterLayout & layout, short indent){
530// template <class T, bool EXCL>//
531// std::ostream & Sprinter::treeToStream(std::ostream & ostr, const Tree<T,EXCL> & tree, const drain::SprinterLayout & layout, short indent){
532
533 const bool DATA = !tree.data.empty();
534 const bool CHILDREN = !tree.empty();
535
536 if (! (DATA||CHILDREN)){
537 // Also empty element should return something, here {}, but could be "" or null ?
538 ostr << layout.mapChars.prefix << layout.mapChars.suffix; // '\n';
539 return ostr;
540 }
541
542 const std::string pad(2*indent, ' ');
543
544
545 if (DATA){
546 drain::Sprinter::toStream(ostr, tree.data, layout);
547 //return ostr;
548 /*
549 char sep = 0;
550 for (const auto & entry: tree.data){
551 if (sep){
552 ostr << sep;
553 ostr << '\n';
554 }
555 else {
556 sep = layout.mapChars.separator;
557 }
558 ostr << pad << " " << '"' << entry.first << '"' << layout.pairChars.separator << ' ';
559 drain::Sprinter::toStream(ostr, entry.second, layout);
560 }
561 */
562 if (CHILDREN)
563 ostr << layout.mapChars.separator;
564 ostr << '\n';
565 }
566
567 ostr << layout.mapChars.prefix << '\n';
568
569 if (CHILDREN){
570 char sep = 0;
571 for (const auto & entry: tree){
572 if (sep){
573 ostr << sep;
574 ostr << '\n';
575 }
576 else {
577 sep = layout.mapChars.separator;
578 }
579 ostr << pad << " " << '"' << entry.first << '"' << layout.pairChars.separator << ' '; // if empty?
580 treeToStream(ostr, entry.second, layout, indent+1); // recursion
581 }
582 ostr << '\n';
583 }
584
585 ostr << pad << layout.mapChars.suffix; // << '\n';
586
587 return ostr;
588}
589
590
591// MOVE to json files const SprinterLayout Sprinter::layoutJSON;
592
594
602template <class T, class L=SprinterLayout>
603class Sprintlet : public Sprinter {
604
605public:
606
607 const T & src;
608 SprinterLayout layout;
609
610 Sprintlet(const T & x, const SprinterLayout & layout = L()) : src(x), layout(layout) {
611 }
612 // Dangerous? Sprinter(const Sprinter<T> & x) : src(x.src){}
613
614 std::ostream & toStream(std::ostream & ostr) const {
615 return Sprinter::toStream(ostr, src, layout);
616 }
617
618 std::string str() const {
619 std::stringstream sstr;
620 Sprinter::toStream(sstr, src, layout);
621 return sstr.str();
622 }
623
624};
625
626
627template <class T, class L>
628inline
629std::ostream & operator<<(std::ostream & ostr, const Sprintlet<T,L> & sp){
630 return sp.toStream(ostr);
631}
632
633
634// Short cut (constructor wrappers)
635
636template <class T>
637inline
638Sprintlet<T> sprinter(const T & x, const char *arrayCaps, const char *mapCaps="{,}", const char *pairCaps="(:)", const char *stringCaps="\""){
639 return Sprintlet<T>(x, SprinterLayout(arrayCaps,mapCaps,pairCaps,stringCaps)); // copy const
640}
641
642template <class T>
643inline
644Sprintlet<T> sprinter(const T & x, const SprinterLayout & layout = SprinterLayout()){
645 return Sprintlet<T>(x, layout); // copy const
646}
647
648
649} // drain
650
651
652#endif
653
Definition Sprinter.h:195
static std::ostream & toStream(std::ostream &ostr, const std::initializer_list< T > &x, const SprinterLayout &layout=defaultLayout)
New (experimental)
Definition Sprinter.h:420
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:297
static const SprinterLayout xmlAttributeLayout
Like attributes in XML (HTML, SVG, ...) tags.
Definition Sprinter.h:227
static std::ostream & toStream(std::ostream &ostr, const char *x, const SprinterLayout &layout=defaultLayout)
Conventional type: C string.
Definition Sprinter.h:477
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:321
static const SprinterLayout pythonLayout
C++ code initializer list style: all objects with {...}, with comma ',' separator.
Definition Sprinter.h:245
static const SprinterLayout emptyLayout
Simply concatenate values without punctuation.
Definition Sprinter.h:206
static const SprinterLayout plainLayout
Display plain values, concatenating them with comma (except for strings).
Definition Sprinter.h:209
static void prefixToStream(std::ostream &ostr, const TypeLayout &layout)
Output Dictionary, which is a list.
Definition Sprinter.h:254
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:470
static const SprinterLayout defaultLayout
Displays objects with {...}, arrays with [...], pairs with (,) and strings without hyphens.
Definition Sprinter.h:203
static const SprinterLayout jsLayout
JavaScript layout. Like JSON layout, but keys without hyphens.
Definition Sprinter.h:224
static std::ostream & toStream(std::ostream &ostr, bool b, const SprinterLayout &layout=defaultLayout)
Single char gets styled same way as strings.
Definition Sprinter.h:490
static std::ostream & toStream(std::ostream &ostr, D *x, const SprinterLayout &layout=defaultLayout)
Pointer: redirect to actual target object.
Definition Sprinter.h:499
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:529
static const SprinterLayout lineLayout
Put each array and object element on a separate line.
Definition Sprinter.h:212
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:408
static const SprinterLayout cppLayout
C++ code initializer list style: all objects with {...}, with comma ',' separator.
Definition Sprinter.h:236
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:329
static std::ostream & toStream(std::ostream &ostr, char c, const SprinterLayout &layout=defaultLayout)
Single char gets styled same way as strings.
Definition Sprinter.h:484
static std::ostream & toStream(std::ostream &ostr, const D *x, const SprinterLayout &layout=defaultLayout)
Pointer: redirect to actual target object.
Definition Sprinter.h:511
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:360
static const SprinterLayout UNSET_LAYOUT
Marker for unset layout.
Definition Sprinter.h:200
static const SprinterLayout cmdLineLayout
Simulates how arguments are given to command line options.
Definition Sprinter.h:248
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:518
static const SprinterLayout jsonLayout
Resembles JSON structure: {"a":1,"b":22,"c":3}.
Definition Sprinter.h:221
Definition Sprinter.h:603
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