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