Loading...
Searching...
No Matches
SmartMap.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 SMARTMAP_H
32#define SMARTMAP_H
33
34#include <drain/Log.h>
35#include <iostream>
36#include <string>
37#include <list>
38#include <map>
39#include <syslog.h>
40
41#include <drain/SmartMapTools.h>
42#include <drain/Sprinter.h>
43#include <drain/StringTools.h>
44
45
46
47// TODO: use SmartMapTools for assignments
48
49namespace drain {
50
52
61template<class T>
62class SmartMap : public std::map<std::string, T> {
63
64public:
65
66 typedef SmartMap<T> smap_t;
67
68 typedef std::map<std::string, T> map_t;
69 typedef typename map_t::key_type key_t;
70 typedef typename map_t::mapped_type value_t; // == T
71 typedef typename map_t::value_type entry_t; // pair<key_t,value_t>
72
73 typedef std::list<std::string> keylist_t;
74
76 typedef typename map_t::iterator iterator;
77 typedef typename map_t::const_iterator const_iterator;
78
79
82
85
90 inline
92
93 // Copy constructor. Does not copy items.
96 inline
98
99
100 virtual
101 inline
102 ~SmartMap(){};
103
104
105 virtual inline
106 void clear(){
107 map_t::clear();
108 keyList.clear();
109 }
110
111 inline
112 bool hasKey(const std::string &key) const {
113 return (this->find(key) != this->end());
114 }
115
117
122 inline
123 std::string get(const std::string &key, const std::string & defaultValue) const {
124 const_iterator it = this->find(key);
125 if (it == this->end())
126 return defaultValue;
127 else {
128 // return static_cast<std::string>(it->second); DOES NOT WORK, http://stackoverflow.com/questions/7741531/conversion-operator-template-specialization
129 return it->second;
130 }
131 }
132
133
134 inline
135 std::string get(const std::string & key, const char *defaultValue) const {
136 return get(key, std::string(defaultValue));
137 }
138
139
141
146 template <class T2>
147 T2 get(const std::string &key, const T2 &defaultValue) const { //T2 defaultValue) const {
148 const_iterator it = this->find(key);
149 if (it == this->end())
150 return defaultValue;
151 else
152 return static_cast<T2>(it->second);
153 }
154
156
161 inline
162 virtual
163 T & operator[](const std::string &key){
164
165 iterator it = this->find(key);
166 if (it != this->end()) {
167 return it->second;
168 }
169 else {
170 // Create:
171 keyList.push_back(key);
172 T & element = map_t::operator[](key);
173 //element.setSeparator(arraySeparator);
174 return element;
175 }
176 }
177
179 inline
180 virtual
181 const T & operator[](const std::string &key) const {
182
183 const_iterator it = this->find(key);
184 if (it != this->end()) {
185 return it->second;
186 }
187 else {
188 static const T empty;
189 return empty;
190 }
191 }
192
193
195 virtual inline
196 const keylist_t & getKeyList() const {
197 return keyList;
198 }
199
200
201 inline
202 const map_t & getMap() const {
203 return *this;
204 };
205
207 template <class T2>
208 void exportMap(std::map<std::string,T2> & m) const {
209 for (const_iterator it = this->begin(); it != this->end(); ++it)
210 m[it->first] = it->second;
211 }
212
214
217 /*
218 template <class V,bool STRICT=false> // TODO: true...
219 //void importEntry(const std::string & key, const T2 & value, bool updateOnly = true){
220 void importEntry(const std::string & key, const V & value){ //, bool updateOnly = true) { //, unsigned int criticality = LOG_DEBUG){
221 */
222
226 template <bool STRICT=true>
227 inline
228 void importEntries(const std::string & entries, char assignmentChar='=', char separatorChar=0); // { //, bool updateOnly = false);
229 // MapTools::setValues<smap_t,STRICT>(*this, entries, separatorChar, assignmentChar); // const std::string & trimChars = ""
230 //}
231 //, unsigned int criticality = LOG_ERR);
232
233
238 template <bool STRICT=true>
239 void importEntries(const std::list<std::string> & entries, char assignmentChar='='){ //; //, bool updateOnly = false);
240 //SmartMapTools::setValues<T,STRICT>(*this, getKeyList(), entries, assignmentChar);
241 MapTools::setValues<smap_t,STRICT>(*this, getKeyList(), entries, assignmentChar);
242 }
243
245
250 template <class S,bool STRICT=true>
251 void importMap(const std::map<std::string,S> & m){ //, bool updateOnly = false){ //, unsigned int criticality = LOG_ERR){
252 // SmartMapTools::setValues<map_t,S,STRICT>(*this, m);
253 // SmartMapTools::setValues(*this, m);
254 MapTools::setValues<smap_t,S,STRICT>(*this, m);
255 //new
256 //for (typename std::map<std::string,S>::const_iterator it = m.begin(); it != m.end(); ++it)
257 // importEntry(it->first, it->second); //, updateOnly); //, criticality); // false);
258
259 }
260
262
269 template <class T2,bool STRICT=true>
270 void importCastableMap(const drain::SmartMap<T2> & m){ //, bool updateOnly = false, unsigned int criticality = LOG_ERR){
271 SmartMapTools::setCastableValues<smap_t,T2,STRICT>(*this, m);
272 }
273
274
275
277
280 template <class T2>
281 inline
282 void updateFromMap(const std::map<std::string,T2> & m){
283 importMap<T2,false>(m); //, LOG_DEBUG);
284 }
285
287 template <class T2>
288 inline
290 importCastableMap<T2,false>(m); //, true);
291 // for (typename SmartMap<T2>::const_iterator it = m.begin(); it != m.end(); ++it)
292 // importEntry(it->first, (const Castable &)it->second, LOG_DEBUG); //true);
293 }
294
295
297 // TODO: consider: std::string assignmentChars="=:", std::string separatorChars=", ", std::string trimChars=" \t\n\r",
298 inline
299 void setValues(const std::string & entries, char assignmentChar='=', char separatorChar=0){ // char separatorChar=','
300 importEntries<true>(entries, assignmentChar, separatorChar); //, false); //, LOG_ERR);
301 }
302
303 inline
304 void setValues(const char * entries, char assignmentChar='=', char separatorChar=0){
305 importEntries<true>(entries, assignmentChar, separatorChar); //, false); //, LOG_ERR);
306 }
307
308 // status?
309 template <class S>
310 void setValuesSEQ(const S & sequence);
311
313 inline
314 void updateValues(const std::string & entries, char assignmentChar='=', char separatorChar=0){// char separatorChar=','
315 importEntries<false>(entries, assignmentChar, separatorChar); //, true); //, LOG_DEBUG);
316 }
317
318
319 inline
320 void getKeys(std::ostream &ostr) const {
321
322 const keylist_t & l = getKeyList();
323 for (keylist_t::const_iterator it = l.begin(); it != l.end(); ++it ){
324 if (it != l.begin())
325 ostr << ',';
326 ostr << *it;
327 }
328
329 }
330
332 inline
333 std::string getKeys() const {
334 std::stringstream s;
335 getKeys((std::ostream &)s);
336 return s.str();
337 };
338
340 inline
341 void getValues(std::ostream &ostr) const {
342
343 const keylist_t & l = getKeyList();
344 for (keylist_t::const_iterator it = l.begin(); it != l.end(); ++it ){
345 if (it != l.begin())
346 ostr << ',';
347 if (this->find(*it) != this->end())
348 ostr << (*this)[*it]; // << this->find(*it).getType();
349 else {
350 ostr << "*SMARTMAP::FAIL* " << __FUNCTION__;
351 }
352 }
353
354 }
355
357 inline
358 std::string getValues() const {
359 std::stringstream s;
360 getValues(s);
361 return s.str();
362 };
363
364
366 /*
367 * \param equal - typically =, :, or -
368 * \param start - typically hyphen or leading parenthesis (, {, [
369 * \param end - typically hyphen or trailing parenthesis ), }, [
370 * \param separator - typically comma or semicolon
371 */
372 // template <class S>
373 // S & toStream(S & ostr, char equal='=', char startChar=0, char endChar=0, char separatorChar=0) const;
374 std::ostream & toStream(std::ostream & ostr, char equal='=', char startChar='{', char endChar='}', char separatorChar=',') const {
375 //drain::TypeLayout pairLayout(equal);
376 drain::TypeLayout mainLayout(startChar, separatorChar, endChar);
378 //layout.pairChars.separator = equal;
379 layout.pairChars.separator = equal;
380 //layout.arrayChars.setLayout();
381 return Sprinter::sequenceToStream(ostr, getMap(), mainLayout, layout);
382 //return Sprinter::sequenceToStream(ostr, vmap.getMap(), layout.mapChars, layout);
383 //return Sprinter::mapToStream(ostr, *this, Sprinter::jsonLayout, this->getKeyList());
384 }
385
386 //std::string toStr(char equal='=', char start='{', char end='}', char separator=0) const {
387 std::string toStr(char equal='=', char start=0, char end=0, char separator=0) const {
388 std::stringstream sstr;
389 toStream(sstr, equal, start, end, separator);
390 return sstr.str();
391 }
392
394 //void toJSON(std::ostream & ostr = std::cout, size_t indent = 0) const;
395
397 // void valuesToJSON(std::ostream & ostr = std::cout) const;
398
400 void dump(std::ostream & ostr = std::cout) const;
401
402
403
405 // ?? If specific, allows also "key=value,key1=value2,...".
417 // \param updateOnly - if true, skip non-existing entries silently
418 //void assignEntries2(const std::string & entries, bool updateOnly = false, char assignmentChar='=', char separatorChar=0){
419
420protected:
421
422
424 // std::list<std::string> orderedKeyList;
425
426 mutable std::list<std::string> keyList;
427
428};
429
430
431// to be Replaced by MapTools:
432// MapTools::setValues<smap_t,STRICT>(*this, entries, separatorChar, assignmentChar);
433template <class T>
434template <bool STRICT>
435void SmartMap<T>::importEntries(const std::string & entries, char assignmentChar, char separatorChar){ //, bool updateOnly){
436
437 // void importEntries(const std::string & entries, char assignmentChar='=', char separatorChar=0);
438
439 Logger mout(__FILE__, __FUNCTION__);
440 //mout.debug(10) << entries << mout.endl;
441
442 if (entries.empty()){ //old
443 return;
444 }
445
446
447 separatorChar = separatorChar ? separatorChar : separator;
448
449 std::list<std::string> l;
450 drain::StringTools::split(entries, l, separatorChar);
451 MapTools::setValues<smap_t,STRICT>(*this, this->getKeyList(), l, assignmentChar);
452
453 /*
454 // Input parameter assignments, separated by the separator: "a=1", "b=2", "c=3", ...
455 std::list<std::string> p;
456 // separatorChar = separatorChar ? separatorChar : separator;
457 if (separatorChar)
458 drain::StringTools::split(entries, p, std::string(1, separatorChar)); // separators);
459 else {
460 // no separator => single-param cmd, BUT explicit key=value possible
461 // mout.warn("push back entries:" , entries );
462 p.push_back(entries);
463 }
464 importEntries<STRICT>(p, assignmentChar);
465 */
466}
467
468
469/*
470
471template <class T>
472template <bool STRICT>
473void SmartMap<T>::importEntries(const std::list<std::string> & p, char assignmentChar){ // , bool updateOnly){
474
475 Logger mout(__FILE__, __FUNCTION__);
476
477 // NUEVO3 SmartMapTools::setValues<T,STRICT>(*this, p, assignmentChar);
478
479 //SmartMapTools::setValues<T,STRICT>(*this, getKeyList(), p, assignmentChar);
480
481 const std::string assignmentChars(1, assignmentChar);
482
483 const std::list<std::string> & keys = getKeyList();
484 std::list<std::string>::const_iterator kit = keys.begin();
485
486
487 bool acceptOrderedParams = true;
488
489 // mout.warn(" assignmentChar: " , assignmentChar );
490 // mout.warn(" size: " , this->size() );
491
492 for (std::list<std::string>::const_iterator pit = p.begin(); pit != p.end(); ++pit){
493
494 //mout.warn(" entry: " , *pit );
495
496 // Check specific assignment, ie. check if the key=value is given explicitly.
497 if (assignmentChar){ // typically '='
498 std::string key;
499 std::string value;
500 if (StringTools::split2(*pit, key, value, assignmentChars)){
501 // mout.warn(" specified " , key , "=\t" , value );
502 if (this->size()==1){
503 iterator it = this->begin();
504 if (key == it->first)
505 it->second = value;
506 else
507 it->second = *pit;
508 return;
509 }
510
511 importEntry<std::string,STRICT>(key, value); //, criticality);
512 acceptOrderedParams = false;
513 continue;
514 }
515 else {
516 // mout.warn(" could not split: " , *pit );
517 }
518 }
519
520 // Key and assignment symbol not given.
521
522 if (kit != keys.end()){
523 // Assignment-by-order
524 if (!acceptOrderedParams){
525 mout.warn("positional arg '" , *pit , "' for [", *kit , "] given after explicit args" );
526 }
527 //mout.warn(" ordered " , );
528 (*this)[*kit] = *pit; // does not need to call import() because *kit exists.
529 ++kit; // NUEVO
530 }
531 else {
532 //mout.log(criticality)
533 // << "too many (over "<< this->size() << ") params, run out of keys with entry=" << *pit << mout.endl;
534 if (STRICT){
535 mout.error("too many (over ", this->size() , ") params, run out of keys with entry=" , *pit );
536 }
537
538 }
539
540 }
541
542}
543*/
544
545
546template <class T>
547template <class S>
548void SmartMap<T>::setValuesSEQ(const S & sequence){
549
550 Logger log(__FILE__, __FUNCTION__);
551
552 const std::list<std::string> & keys = getKeyList();
553 std::list<std::string>::const_iterator kit = keys.begin();
554
555 for (typename S::const_iterator it = sequence.begin(); it != sequence.end(); ++it){
556
557 if (kit != keys.end()){
558 // Assignment-by-order
559 (*this)[*kit] = *it; // does not need to call import() because *kit exists.
560 ++kit; // NUEVO
561 }
562 else {
563 log.error() << "too many ("<< sequence.size() << ") params for map of size ("<< this->size() << "), run out of keys with entry=" << *it << log.endl;
564 }
565
566 }
567
568}
569
570/*
571template <class T>
572std::ostream & SmartMap<T>::toStream(std::ostream & ostr, char equal, char startChar, char endChar, char separatorChar) const {
573
574 // Otherways ok, but key order not used: Sprinter::sequenceToStream(ostr, *this, Sprinter::jsonLayout);
575 //return Sprinter::mapToStream(ostr, *this, Sprinter::jsonLayout, this->getKeyList());
576
577
578 const std::list<std::string> & keys = this->getKeyList();
579
580 separatorChar = separatorChar ? separatorChar : this->separator;
581 //separatorChar = separatorChar ? separatorChar : ','; // needed?
582 char sep = 0;
583
584 for (std::list<std::string>::const_iterator it = keys.begin(); it != keys.end(); ++it){
585
586 if (sep){
587 //if (it != keys.begin())
588 ostr << sep;
589 }
590 else {
591 sep = separator;
592 }
593
594 ostr << *it << equal;
595 if (startChar)
596 ostr << startChar;
597 ostr << (*this)[*it];
598 if (endChar)
599 ostr << endChar;
600
601 }
602}
603 */
604
605/*
606template <class T>
607void SmartMap<T>::toJSON(std::ostream & ostr, size_t indent) const {
608
609 const std::string space(indent, ' ');
610
611 char sep = 0;
612 ostr << "{\n";
613
614 // NOTE: alphabetic order. Should JSON dump have orig. order?
615 for (const_iterator it = this->begin(); it != this->end(); ++it){
616
617 const std::string & key = it->first;
618 const T & item = it->second; //(*this)[key];
619
620 if (sep){
621 ostr << sep;
622 ostr << '\n';
623 }
624 else {
625 sep = ',';
626 }
627 //ostr << '\n';
628 ostr << space << "\"" << key << "\" : ";
629
630 //if (item.getType() == typeid(std::string)){
631 if (item.T::isString()){
632 //
633 ostr << '"';
634 // ostr << '"' << item.getCharArray() << '"';
635 const char *c = item.getCharArray();
636 while (*c != '\0'){
637 if (*c == '"')
638 ostr << '\\'; // TODO; implement also \n \t ...
639 ostr << *c;
640 ++c;
641 }
642 ostr << '"';
643 //ostr << '"' << item << '"';
644 }
645 else {
646 switch (item.T::getElementCount()) {
647 case 0:
648 ostr << '[' << ']'; // or NaN?
649 break;
650 case 1:
651 ostr << item;
652 break;
653 default:
654 Sprinter::toStream(ostr, item, Sprinter::plainLayout);
655 // JSONwriter::toStream(item, ostr); // Better! Forces commas.
656 // ostr << '[' << item << ']';
657 }
658 }
659 }
660 // ostr << "{\n \"value\":" << *this << ",\n";
661 // ostr << " \"type\":" << drain::Type::getTypeChar(getType()) << ",\n";
662 ostr << "\n" << space << "}\n"; // \n needed?
663}
664
665template <class T>
666void SmartMap<T>::valuesToJSON(std::ostream & ostr) const {
667
668
669 char sep = 0;
670
671 if (this->size() > 1)
672 ostr << "[";
673
674 // NOTE: alphabetic order. Should JSON dump have orig. order?
675 for (const_iterator it = this->begin(); it != this->end(); ++it){
676
677 //const std::string & key = it->first;
678 const T & item = it->second; //(*this)[key];
679
680 if (sep){
681 ostr << sep;
682 ostr << ' ';
683 }
684 else {
685 sep = ',';
686 }
687
688 if (item.T::isString()){
689 ostr << '"';
690 const char *c = item.getCharArray();
691 while (*c != '\0'){
692 if (*c == '"')
693 ostr << '\\'; // TODO; implement also \n \t ...
694 ostr << *c;
695 ++c;
696 }
697 ostr << '"';
698 //ostr << '"' << item << '"';
699 }
700 else {
701 switch (item.T::getElementCount()) {
702 case 0:
703 ostr << '[' << ']'; // or NaN?
704 break;
705 case 1:
706 ostr << item;
707 break;
708 default:
709 ostr << '[' << item << ']';
710 }
711 }
712
713 }
714
715 if (this->size() > 1)
716 ostr << "]";
717
718}
719*/
720
721
722template <class T>
723void SmartMap<T>::dump(std::ostream & ostr) const {
724
725 //const std::string space(indent, ' ');
726 for (const_iterator it = this->begin(); it != this->end(); ++it){
727 ostr << it->first << ':' << ' ';
728 it->second.info(ostr);
729 ostr << '\n';
730 }
731
732}
733
734template<class T>
735std::ostream &operator<<(std::ostream &ostr, const SmartMap<T> & m){
736 m.toStream(ostr, '=', 0, 0, m.separator);
737 return ostr;
738}
739
740/*
741template <class T>
742//template <>
743inline
744std::ostream & Sprinter::toStream(std::ostream & ostr, const SmartMap<T> & smap, const SprinterLayout & layout){
745 return Sprinter::mapToStream(ostr, smap.getMap(), layout, smap.getKeys());
746}
747*/
748
749} // drain
750
751
752#endif // Drain
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition Log.h:313
A base class for smart maps providing methods for importing and exporting values, among others.
Definition SmartMap.h:62
map_t::iterator iterator
Needed?
Definition SmartMap.h:76
void importEntries(const std::list< std::string > &entries, char assignmentChar='=')
Definition SmartMap.h:239
char arraySeparator
Default separator character for array elements (std::vector's)
Definition SmartMap.h:84
std::string getKeys() const
Convenience function for std::string output.
Definition SmartMap.h:333
std::list< std::string > keyList
Assigns values from std::string of type "value,value2,...valueN".
Definition SmartMap.h:426
virtual const T & operator[](const std::string &key) const
Unlike with std::map, operator[] const is defined, returning reference to a static empty instance.
Definition SmartMap.h:181
char separator
Default character used for splitting input and output. See setValues.
Definition SmartMap.h:81
virtual const keylist_t & getKeyList() const
Derived versions may produce an ordered set of keys.
Definition SmartMap.h:196
void importCastableMap(const drain::SmartMap< T2 > &m)
Assign values from a map, possibly extending the map.
Definition SmartMap.h:270
std::string getValues() const
Convenience function for std::string output.
Definition SmartMap.h:358
void exportMap(std::map< std::string, T2 > &m) const
Copies the contents to another map.
Definition SmartMap.h:208
virtual T & operator[](const std::string &key)
Returns an element. Creates one, conditionally.
Definition SmartMap.h:163
void getValues(std::ostream &ostr) const
Dumps the values.
Definition SmartMap.h:341
void updateFromMap(const std::map< std::string, T2 > &m)
Assign values from a map. Updates existing entries only.
Definition SmartMap.h:282
const map_t & getMap() const
Definition SmartMap.h:202
void updateFromCastableMap(const drain::SmartMap< T2 > &m)
Convenience.
Definition SmartMap.h:289
void importEntries(const std::string &entries, char assignmentChar='=', char separatorChar=0)
Assigns a value to given key; if the entry does not exist, tries to create it with directly with oper...
Definition SmartMap.h:435
std::string get(const std::string &key, const std::string &defaultValue) const
Retrieves a value, or default value if value is unset.
Definition SmartMap.h:123
void updateValues(const std::string &entries, char assignmentChar='=', char separatorChar=0)
Sets applicable values ie. modifies existing entries only. In ordered maps, skips extra entries silen...
Definition SmartMap.h:314
void dump(std::ostream &ostr=std::cout) const
Write map as a JSON code.
Definition SmartMap.h:723
T2 get(const std::string &key, const T2 &defaultValue) const
Retrieves a value, if set, else returns the given default value.
Definition SmartMap.h:147
SmartMap(char separator='\0', char arraySeparator=':')
Definition SmartMap.h:91
std::ostream & toStream(std::ostream &ostr, char equal='=', char startChar='{', char endChar='}', char separatorChar=',') const
Note: parameters discarded.
Definition SmartMap.h:374
void setValues(const std::string &entries, char assignmentChar='=', char separatorChar=0)
Sets values. If strictness==STRICTLY_CLOSED, throws exception if tries to assign a non-existing entry...
Definition SmartMap.h:299
void importMap(const std::map< std::string, S > &m)
Assign values from a map, overriding existing entries.
Definition SmartMap.h:251
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 jsonLayout
Resembles JSON structure: {"a":1,"b":22,"c":3}.
Definition Sprinter.h:224
static void split(const std::string &s, T &sequence, const C &separators, const std::string &trimChars=" \t\n")
Splits and trims a given std::string to a std Sequence.
Definition StringTools.h:487
Definition DataSelector.cpp:1277
Definition Sprinter.h:136
Definition Sprinter.h:79