]> git.tdb.fi Git - libs/core.git/blob - source/core/maputils.h
Store the value of the key in key_error
[libs/core.git] / source / core / maputils.h
1 #ifndef MSP_CORE_MAPUTILS_H_
2 #define MSP_CORE_MAPUTILS_H_
3
4 #include <stdexcept>
5 #include <typeinfo>
6 #include <msp/strings/lexicalcast.h>
7
8 namespace Msp {
9
10 namespace MapUtilsInternal {
11
12 /* This must be hidden in the internal namespace to avoid interfering with
13 other things.  There may be problems if a key type has operator<< for ostream
14 but not LexicalConverter. */
15 template<typename T>
16 void operator<<(LexicalConverter &, const T &)
17 { }
18
19 template<typename T>
20 static std::string stringify_key(const T &k)
21 {
22         try
23         {
24                 LexicalConverter conv((Fmt()));
25                 conv<<k;
26                 return conv.get();
27         }
28         catch(const lexical_error &)
29         {
30                 return "<cannot display value>";
31         }
32 }
33
34 } // namespace Internal
35
36 class key_error: public std::runtime_error
37 {
38 public:
39         template<typename T>
40         key_error(const T &k):
41                 runtime_error(make_what(typeid(T), MapUtilsInternal::stringify_key(k)))
42         { }
43
44         virtual ~key_error() throw() { }
45
46 private:
47         static std::string make_what(const std::type_info &, const std::string &);
48 };
49
50
51 template<typename T>
52 typename T::mapped_type &get_item(T &map, const typename T::key_type &key)
53 {
54         typename T::iterator i = map.find(key);
55         if(i==map.end())
56                 throw key_error(key);
57
58         return i->second;
59 }
60
61 template<typename T>
62 const typename T::mapped_type &get_item(const T &map, const typename T::key_type &key)
63 {
64         typename T::const_iterator i = map.find(key);
65         if(i==map.end())
66                 throw key_error(key);
67
68         return i->second;
69 }
70
71 template<typename T>
72 const typename T::iterator insert_unique(T &map, const typename T::key_type &key, const typename T::mapped_type &item)
73 {
74         if(map.count(key))
75                 throw key_error(key);
76
77         return map.insert(typename T::value_type(key, item)).first;
78 }
79
80 } // namespace Msp
81
82 #endif