replace obsolete call to ftime(3)
[libi2ncommon] / src / i2n_configdata.hpp
CommitLineData
0e23f538
TJ
1/*
2The software in this package is distributed under the GNU General
3Public License version 2 (with a special exception described below).
4
5A copy of GNU General Public License (GPL) is included in this distribution,
6in the file COPYING.GPL.
7
8As a special exception, if other files instantiate templates or use macros
9or inline functions from this file, or you compile this file and link it
10with other works to produce a work based on this file, this file
11does not by itself cause the resulting work to be covered
12by the GNU General Public License.
13
14However the source code for this file must still be made available
15in accordance with section (3) of the GNU General Public License.
16
17This exception does not invalidate any other reasons why a work based
18on this file might be covered by the GNU General Public License.
19*/
d0f059fd
RP
20/** @file
21 *
0e23f538 22 * @author Reinhard Pfau
d0f059fd
RP
23 *
24 * @copyright © Copyright 2007-2008 by Intra2net AG
d0f059fd
RP
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
36namespace 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 */
55template <
56 class KeyType,
57 class ValueType
58>
59class 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 */
622template<
623 class GroupKeyType,
624 class KeyType,
625 class ValueType
626>
627class 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 {
9f5eb22d 740 return inherited::getValueRef(key);
d0f059fd
RP
741 } // eo operator [](const groupKey&)
742
743
744 const GroupDataType& operator[](const GroupKeyType& key) const
745 {
9f5eb22d 746 return inherited::getConstValueRef(key);
d0f059fd
RP
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 }
9f5eb22d 773 return inherited::getConstValueRef(group_key).hasKey(key);
d0f059fd
RP
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
788typedef GroupedKeyValueData<
789 std::string,
790 std::string,
791 std::string
792> ConfigData;
793
794typedef ConfigData::GroupDataType ConfigSectionData;
795
796
797
798} // eo namespace I2n
799
800
801
802#endif