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