8db82bac78066db183e27a6f088d63d8c24ea8b9
[libi2ncommon] / src / i2n_configdata.hpp
1 /** @file
2  *
3  * @author Reinhard Pfau \<Reinhard.Pfau@intra2net.com\>
4  * 
5  * @copyright &copy; Copyright 2007-2008 by Intra2net AG
6  * @license commercial
7  *
8  * info@intra2net.com
9  */
10
11 #ifndef __I2N_CONFIGDATA_HPP__
12 #define __I2N_CONFIGDATA_HPP__
13
14 #include <vector>
15 #include <map>
16 #include <algorithm>
17 #include <sstream>
18
19
20 namespace I2n
21 {
22
23
24
25 /**
26  * key-value data storage with some additional features.
27  * This class is meant to hold data from config files.
28  *
29  * Basic ideas:
30  *
31  * - the keys are remembered in the order they are put into the list
32  * - each key can hold multiple values
33  * - the values for each key are remembered in the order they were added
34  * - if a single value for a key is requested than the last value is returned.
35  * .
36  * @tparam KeyType the type for the keys
37  * @tparam ValueType the type for the values.
38  */
39 template <
40     class KeyType,
41     class ValueType
42 >
43 class KeyValueData
44 {
45     public:
46
47         typedef std::vector<KeyType> KeyListType;
48         typedef std::vector<ValueType> ValueListType;
49         typedef std::map<KeyType, ValueListType> StorageType;
50
51     public:
52
53         /**
54          * @brief adaptor class for accessing values within the list for a given key.
55          * 
56          * This is returned by KeyValueList::operator[](const std::string&) for
57          * more convenient access.
58          * 
59          * This class is designed to be used in transient contexts.
60          */
61         class ValueAdaptor
62         {
63                 // make parent class my friend since the constructors are private!
64                 friend class KeyValueData;
65
66             public:
67
68                 /**
69                  * cast operator for ValueType.
70                  * @return the (last) value for the key
71                  */
72                 operator ValueType () const
73                 {
74                     return m_kv.getValue(m_key);
75                 } // eo operator ValueType() const
76
77
78                 /**
79                  * cast operator for ValueListType.
80                  * @return the value list for the key.
81                  */
82                 operator ValueListType () const
83                 {
84                     return m_kv.getValues(m_key);
85                 } // eo operator ValueListType() const
86
87
88                 /**
89                  * performs setValue().
90                  * @param value the value which should be set for the key.
91                  * @return reference to this (for chaining).
92                  */
93                 ValueAdaptor& operator = (const ValueType& value)
94                 {
95                     m_kv.setValue(m_key,value);
96                     return *this;
97                 } // eo operator =(const ValueType&)
98
99
100                 /**
101                  * performs setValues()
102                  * @param values the new values (/value list) which should be set for the key.
103                  * @return reference to this (for chaining).
104                  */
105                 ValueAdaptor& operator = (const ValueListType& values)
106                 {
107                     m_kv.setValues(m_key, values);
108                     return *this;
109                 } // eo operator =(const ValueListType&);
110
111
112                 /**
113                  * performs addValue().
114                  * @param value the value which should be added to the value list for the key,
115                  * @return reference to this (for chaining).
116                  */
117                 ValueAdaptor& operator += (const ValueType& value)
118                 {
119                     m_kv.addValue(m_key,value);
120                     return *this;
121                 } // eo operator +=(const ValueType&)
122
123
124                 /**
125                  * performs addValues().
126                  * @param values the new values (/value list) which should be added to the value list for the key.
127                  * @return reference to this (for chaining).
128                  */
129                 ValueAdaptor& operator += (const ValueListType& values)
130                 {
131                     m_kv.addValues(m_key, values);
132                     return *this;
133                 } // eo operator +=(const ValueListType)
134
135
136             private:
137
138                 ValueAdaptor(KeyValueData& kv, const KeyType& key)
139                 : m_kv(kv)
140                 , m_key(key)
141                 {
142                 }
143
144                 ValueAdaptor(const ValueAdaptor& other)
145                 : m_kv(other.m_kv)
146                 , m_key(other.m_key)
147                 {
148                 }
149
150                 ValueAdaptor& operator =(const ValueAdaptor&);
151
152             private:
153                 KeyValueData& m_kv;
154                 KeyType       m_key;
155         }; // eo class ValueAdaptor
156
157     public:
158
159         KeyValueData()
160         {
161         } // eo KeyValueData
162
163
164
165         ~KeyValueData()
166         {
167         } // eo ~KeyValueData
168
169
170
171         /**
172         * set a value for a key.
173         * This erases an existing value list for that key and set's a new (single) value.
174         * @param key the key.
175         * @param value the value.
176         */
177         KeyValueData& setValue(const KeyType& key, const ValueType& value)
178         {
179             typename StorageType::iterator it= m_storage.find(key);
180             if (it == m_storage.end())
181             {
182                 m_key_list.push_back(key);
183                 m_storage[key].push_back(value);
184             }
185             else
186             {
187                 it->second.clear();
188                 it->second.push_back(value);
189             }
190             return *this;
191         } // eo setValue(const KeyType&,const ValueType&)
192
193
194
195         /**
196         * set a new value list for a key.
197         * Erases the key when the new value list is empty.
198         * Else the value list for the key is replaced with the new values.
199         * @param key the key
200         * @param values the new value list.
201         */
202         KeyValueData& setValues(const KeyType& key, const ValueListType& values)
203         {
204             typename StorageType::iterator it= m_storage.find(key);
205             if (it == m_storage.end())
206             {
207                 m_key_list.push_back(key);
208                 m_storage[key]= values;
209             }
210             else
211             {
212                 if (values.empty())
213                 {
214                     deleteKey(key);
215                 }
216                 else
217                 {
218                     it->second= values;
219                 }
220             }
221             return *this;
222         } // eo setValues(const KeyType&,const ValueListType&)
223
224
225
226         /**
227         * adds a new value to the value list of a key.
228         *
229         * @param key the key
230         * @param value the new value
231         */
232         KeyValueData& addValue(const KeyType& key, const ValueType& value)
233         {
234             typename StorageType::iterator it= m_storage.find(key);
235             if (it == m_storage.end())
236             {
237                 m_key_list.push_back(key);
238                 m_storage[key].push_back(value);
239             }
240             else
241             {
242                 it->second.push_back(value);
243             }
244             return *this;
245         } // eo addValue(const KeyType&,const ValueType&)
246
247
248
249         /**
250         * adds new values to the value list of a key.
251         *
252         * @param key the key
253         * @param values the new value list
254         */
255         KeyValueData& addValues(const KeyType& key, const ValueListType& values)
256         {
257             typename StorageType::iterator it= m_storage.find(key);
258             if (it == m_storage.end())
259             {
260                 m_key_list.push_back(key);
261                 m_storage[key]= values;
262             }
263             else
264             {
265                 std::copy(values.begin(), values.end(), std::back_inserter(it->second));
266             }
267             return *this;
268         } // eo addValues(const KeyType&,const ValueListType&)
269
270
271
272         /**
273          * @brief removes a value from a value list of a key.
274          * @param key the key.
275          * @param value the value which should be removed (once).
276          * @return self reference.
277          * @note only the first occurance of the value is removed!
278          */
279         KeyValueData& removeValue(const KeyType& key, const ValueType& value)
280         {
281             typename StorageType::iterator it= m_storage.find(key);
282             if (it != m_storage.end())
283             {
284                 for( typename ValueListType::iterator it_val= it->second.begin();
285                     it_val != it->second.end();
286                     ++it_val)
287                 {
288                     if ( *it_val == value)
289                     {
290                         it->second.erase(it_val);
291                         break;
292                     }
293                 }
294                 if (it->second.empty())
295                 {
296                     deleteKey( key );
297                 }
298             }
299             return *this;
300         } // eo removeValue
301
302
303         /**
304          * retrieve the (single) value for a key.
305          * If the value list of the key has multiple values, the last one returned.
306          * @param key the key
307          * @param[out] value the resulting value if found
308          * @return @a true iff the key has a value (i,e, the key exits).
309          */
310         bool getValue(const KeyType& key, ValueType& value) const
311         {
312             typename StorageType::const_iterator it= m_storage.find(key);
313             if (it == m_storage.end())
314             {
315                 return false;
316             }
317             else
318             {
319                 value= it->second.back();
320                 return true;
321             }
322         } // eo getValue(const KeyType&, ValueType&)
323
324
325
326         /**
327          * retrieve the value list for a key.
328          * @param key the key
329          * @param[out] values the resulting value list if found
330          * @return @a true iff the key has values (i,e, the key exits).
331          */
332         bool getValues(const KeyType& key, ValueListType& values) const
333         {
334             typename StorageType::const_iterator it= m_storage.find(key);
335             if (it == m_storage.end())
336             {
337                 return false;
338             }
339             else
340             {
341                 values= it->second;
342                 return true;
343             }
344         } // eo getValues(const KeyType&, ValueListType&)
345
346
347
348         /**
349          * retrieve the (single) value for a key.
350          * If the value list of the key has multiple values, the last one returned.
351          * @param key the key
352          * @return the value of the key (default contructed value if key not found)
353          */
354         ValueType getValue(const KeyType& key) const
355         {
356             ValueType value;
357             getValue( key, value);
358             return value;
359         } // eo getValue(const KeyType&)
360
361
362
363         /**
364          * retrieve the value list for a key.
365          * @param key the key
366          * @return the value of the key (empty if key not found)
367          */
368         ValueListType getValues(const KeyType& key) const
369         {
370             ValueListType values;
371             getValues( key, values);
372             return values;
373         } // eo getValues(const KeyType&)
374
375
376
377         /**
378          * retrieve the (single) value for a key.
379          * If the value list of the key has multiple values, the last one returned.
380          * If the key wasn't found (i.e. no value) then the default value is returned.
381          * @param key the key
382          * @param default_value the value which is returned if the key wasn't found.
383          * @return the value of the key (default_value if key not found)
384          */
385         ValueType getValueOrDefault(const KeyType& key, const ValueType& default_value) const
386         {
387             ValueType value;
388             if (getValue( key, value))
389             {
390                 return value;
391             }
392             return default_value;
393         } // eo getValueOrDefault(const KeyType&,const ValueType&)
394
395
396
397         /**
398         * removes a key (and it's values) from the list.
399         * @param key the key.
400         */
401         void deleteKey(const KeyType& key)
402         {
403             typename StorageType::iterator it= m_storage.find(key);
404             if (it == m_storage.end())
405             {
406                 return;
407             }
408             m_storage.erase(it);
409             typename KeyListType::iterator itk= std::find(m_key_list.begin(), m_key_list.end(), key);
410             if (itk != m_key_list.end())
411             {
412                 m_key_list.erase(itk);
413             }
414         } // eo deleteKey(const KeyType&)
415
416
417
418         /**
419         * returns if a key exists in the list.
420         * @param key the key which should be looked for.
421         * @return @a true if the key is in the list.
422         */
423         bool hasKey(const KeyType& key) const
424         {
425             return (m_storage.find(key) != m_storage.end());
426         } // eo hasKey(const KeyType&)
427
428
429
430         /**
431         * delivers the list of keys.
432         * @param[out] result_list the key list
433         */
434         void getKeys(KeyListType& result_list) const
435         {
436             result_list= m_key_list;
437         } // eo getKeys(KeyListType&) const
438
439
440
441         /**
442          * deliviers the list of keys.
443          * @return the list of keys.
444          */
445         KeyListType getKeys() const
446         {
447             return m_key_list;
448         } // eo getKeys() const
449
450
451
452         /**
453          * returns if the list is empty (i.e. has no keys)
454          * @return @a true iff the list has no keys (and values).
455          */
456         bool empty() const
457         {
458             return m_key_list.empty();
459         } // eo empty
460
461
462
463         /**
464          * @brief index operator for more readable access.
465          * @param key the key which should be indexed.
466          * @return an instance of ValueAdaptor initialized with the key.
467          */
468         ValueAdaptor operator [] (const KeyType& key)
469         {
470             return ValueAdaptor(*this, key);
471         } // eo operator[](const KeyType&)
472
473
474         /**
475          * @brief returns if the current iunstance is equal to another one (of the same type).
476          * @param rhs the orher instance to compare with.
477          * @return @a true iff the two instances are equal.
478          */
479         bool operator==( const KeyValueData& rhs)
480         {
481             return m_key_list == rhs.m_key_list and m_storage == rhs.m_storage;
482         } // eo operator==(const KeyValueData&)
483
484
485         /**
486          * @brief clears the list.
487          * 
488          * Well, it just deletes all entries.
489          */
490         void clear()
491         {
492             m_storage.clear();
493             m_key_list.clear();
494         } // eo clear
495
496
497         /**
498          * @brief exchanges the internal data with another instance.
499          * @param other 
500          */
501         void swap(KeyValueData& other)
502         {
503             if (this != &other)
504             {
505                 m_storage.swap( other.m_storage );
506                 m_key_list.swap( other.m_key_list );
507             }
508         } // eo swap(KeyValueData&)
509
510
511     protected:
512
513         /**
514          * returns a reference to the last value of the value list for a given key; creating it if the key doesn't
515          * already exist.
516          * This method is only for derived classes to optimize accessing of the values.
517          * @param key the key for which the reference is needed.
518          * @return reference to the last value of the value list for the key.
519          */
520         ValueType& getValueRef(const KeyType& key)
521         {
522             typename KeyListType::iterator it=
523               std::find( m_key_list.begin(), m_key_list.end(), key );
524             if (it == m_key_list.end())
525             {
526                 m_key_list.push_back(key);
527             }
528             if (m_storage[key].empty())
529             {
530                 ValueType v;
531                 m_storage[key].push_back( v );
532             }
533             return m_storage[key].back();
534         } // eo getValueRef(const KeyType&)
535
536
537         /**
538          * @brief returns a reference to the last value of the value list for a given key.
539          * @param key the key for which the reference is needed.
540          * @return reference to the last value of the value list for the key or to internal
541          *  value if no values are existing.
542          *
543          * This method is only for derived classes to optimize accessing of the values.
544          *
545          * @note The method returns a reference to an internal value if no approbiate value
546          * exists! It's up to the derived class to deal with that.
547          */
548         const ValueType& getConstValueRef(const KeyType& key) const
549         {
550             static ValueType empty_value;
551             typename StorageType::const_iterator storage_it= m_storage.find(key);
552             if (storage_it == m_storage.end()
553                 or storage_it->second.empty() )
554             {
555                 return empty_value;
556             }
557             return storage_it->second.back();
558         } // eo getConstValueRef(const KeyType&)
559
560
561         /**
562          * @brief returns a reference to the value list for a given key.
563          * @param key the key for which the reference is needed.
564          * @return reference to the value list for the key.
565          *
566          * This method is only for derived classes to optimize accessing of the values.
567          *
568          * @note The method returns a reference to an internal value if no approbiate value
569          * exists! It's up to the derived class to deal with that.
570          */
571         const ValueListType& getConstValuesRef(const KeyType& key) const
572         {
573             static ValueListType empty_value;
574             typename StorageType::const_iterator storage_it= m_storage.find(key);
575             if ( storage_it == m_storage.end() )
576             {
577                 return empty_value;
578             }
579             return storage_it->second;
580         } // eo getConstValuesRef(const KeyType&)
581
582
583
584     private:
585
586         StorageType m_storage;
587         KeyListType m_key_list;
588
589 }; // eo KeyValueData
590
591
592
593
594 /**
595  * grouped key value list.
596  * This (template) class provides storage for groups whose values are key-value lists.
597  * Basically it's a key-value list, wohse values are another key-value list.
598  *
599  * If used with std::string for all key types, it provides a storage suitable for holding they
600  * (for example) the content of INI style config files.
601  *
602  * @param GroupKeyType type for the group keys.
603  * @param KeyType type for the keys (within a group)
604  * @param ValueType type for the values (within a group)
605  */
606 template<
607     class GroupKeyType,
608     class KeyType,
609     class ValueType
610 >
611 class GroupedKeyValueData
612 : public KeyValueData<GroupKeyType, KeyValueData<KeyType,ValueType> >
613 {
614         typedef KeyValueData<GroupKeyType, KeyValueData<KeyType,ValueType> > inherited;
615
616     public:
617
618         typedef KeyValueData<KeyType,ValueType> GroupDataType;
619
620     public:
621
622         GroupedKeyValueData()
623         {
624         }
625
626
627         ~GroupedKeyValueData()
628         {
629         }
630
631
632         /*
633         ** overridden methods:
634         */
635
636         /**
637          * add (new) group data to a group.
638          * This differs from KeyValueData::addValue in a way that it merges the group data into
639          * an existing group instead of appending a new data group.
640          * @param group_key the key of the group.
641          * @param value the new data which should be added to the group.
642          */
643         void addValue(const GroupKeyType& group_key, const GroupDataType& value)
644         {
645             if (value.empty())
646             {
647                 return;
648             }
649             GroupDataType& group_data= getValueRef(group_key);
650
651             typename GroupDataType::KeyListType keys = value.getKeys();
652             for(typename GroupDataType::KeyListType::const_iterator it_key= keys.begin();
653                 it_key != keys.end();
654                 ++it_key)
655             {
656                 typename GroupDataType::ValueListType values= value.getValues(*it_key);
657                 if (values.empty()) continue;
658                 group_data.addValues( *it_key, value.getValues(*it_key) );
659             }
660         } // eo addValue(const GroupKey&,const GroupData&)
661
662
663         /**
664          * set new group values.
665          * This differs from KeyValueData::setValues in a way that it merges all values to a single
666          * data group.
667          * @param group_key the key of the group.
668          * @param values the list of data grups which are merged together to the new group value.
669          */
670         void setValues(const GroupKeyType& group_key, const typename inherited::ValueListType& values)
671         {
672             if (values.empty())
673             {
674                 inherited::deleteKey(group_key);
675                 return;
676             }
677             // note: since (the overridden method) addValue() already does what we need,
678             // we just clear the data and iterate over the new values list:
679             getValueRef(group_key).clear();
680             for(typename inherited::ValueListType::const_iterator it= values.begin();
681                 it != values.end();
682                 ++it)
683             {
684                 addValue(group_key, *it);
685             }
686             if ( getValueRef(group_key).empty())
687             {
688                 deleteKey(group_key);
689             }
690         } // eo setValues(const GroupKeyType&,const ValueListType&)
691
692
693         /**
694          * add new group values.
695          * This differs from KeyValueList::addValues in a way that the new values are merged into
696          * a single data groupo.
697          * @param group_key 
698          * @param values 
699          */
700         void addValues(const GroupKeyType& group_key, const typename inherited::ValueListType& values)
701         {
702             if (values.empty())
703             {
704                 return;
705             }
706             // like in setValues(); we just use our new addValue() to do the job:
707             for(typename inherited::ValueListType::const_iterator it= values.begin();
708                 it != values.end();
709                 ++it)
710             {
711                 addValue(group_key, *it);
712             }
713         } // eo addValues(const GroupKeyType&,const ValueListType&)
714
715
716
717         /*
718         ** additional methods:
719         */
720
721
722         GroupDataType& operator[](const GroupKeyType& key)
723         {
724             return getValueRef(key);
725         } // eo operator [](const groupKey&)
726
727
728         const GroupDataType& operator[](const GroupKeyType& key) const
729         {
730             return getConstValueRef(key);
731         } // eo operator [](const groupKey&) const
732
733
734         /**
735          * check if a group exists (alias for hasKey(const GroupKey&) const).
736          * @param group_key the key og the group which is looked for.
737          * @return @a true iff the group exists.
738          */
739         bool hasGroup(const GroupKeyType& group_key) const
740         {
741             return inherited::hasKey(group_key);
742         } // eo hasGroup(const GroupKeyType&) const
743
744
745         /**
746          * check if a key within a group exists.
747          * @param group_key the group which should be looked in.
748          * @param key the key which should be tested.
749          * @return @a true iff the group exists and the key exists within that group.
750          */
751         bool hasKey(const GroupKeyType& group_key, const KeyType& key) const
752         {
753             if (!hasGroup(group_key))
754             {
755                 return false;
756             }
757             return getConstValueRef(group_key).hasKey(key);
758         } // eo hasKey(const GroupKeyType&,const KeyType&) const
759
760
761
762 }; // eo GroupedKeyValueData
763
764
765
766 /*
767 ** typedef the most common case; suitable for holding the content of
768 ** INI style config files.
769 */
770
771
772 typedef GroupedKeyValueData<
773     std::string,
774     std::string,
775     std::string
776 > ConfigData;
777
778 typedef ConfigData::GroupDataType ConfigSectionData;
779
780
781
782 } // eo namespace I2n
783
784
785
786 #endif