]> git.tdb.fi Git - libs/core.git/blob - source/core/maputils.h
Fix an overload resolution problem in formatting values for 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 dummy struct is used to introduce a conversion, making the overloaded
13 operator below worse than the templated one provided in lexicalcast.h. */
14 struct Any
15 {
16         template<typename T>
17         Any(const T &) { }
18 };
19
20 /* This must be hidden in the internal namespace to avoid interfering with
21 other things. */
22 inline void operator<<(LexicalConverter &, Any)
23 { }
24
25 template<typename T>
26 static std::string stringify_key(const T &k)
27 {
28         try
29         {
30                 LexicalConverter conv((Fmt()));
31                 conv<<k;
32                 return conv.get();
33         }
34         catch(const lexical_error &)
35         {
36                 return "<cannot display value>";
37         }
38 }
39
40 } // namespace Internal
41
42 class key_error: public std::runtime_error
43 {
44 public:
45         template<typename T>
46         key_error(const T &k):
47                 runtime_error(make_what(typeid(T), MapUtilsInternal::stringify_key(k)))
48         { }
49
50         virtual ~key_error() throw() { }
51
52 private:
53         static std::string make_what(const std::type_info &, const std::string &);
54 };
55
56
57 template<typename T>
58 typename T::mapped_type &get_item(T &map, const typename T::key_type &key)
59 {
60         typename T::iterator i = map.find(key);
61         if(i==map.end())
62                 throw key_error(key);
63
64         return i->second;
65 }
66
67 template<typename T>
68 const typename T::mapped_type &get_item(const T &map, const typename T::key_type &key)
69 {
70         typename T::const_iterator i = map.find(key);
71         if(i==map.end())
72                 throw key_error(key);
73
74         return i->second;
75 }
76
77 template<typename T>
78 const typename T::iterator insert_unique(T &map, const typename T::key_type &key, const typename T::mapped_type &item)
79 {
80         if(map.count(key))
81                 throw key_error(key);
82
83         return map.insert(typename T::value_type(key, item)).first;
84 }
85
86 } // namespace Msp
87
88 #endif