#include <msp/debug/demangle.h>
+#include <msp/strings/format.h>
#include "maputils.h"
using namespace std;
namespace Msp {
-key_error::key_error(const type_info &t):
- runtime_error(Debug::demangle(t.name()))
-{ }
+string key_error::make_what(const type_info &type, const string &value)
+{
+ return format("%s(%s)", Debug::demangle(type.name()), value);
+}
} // namespace Msp
#include <stdexcept>
#include <typeinfo>
+#include <msp/strings/lexicalcast.h>
namespace Msp {
+namespace MapUtilsInternal {
+
+/* This must be hidden in the internal namespace to avoid interfering with
+other things. There may be problems if a key type has operator<< for ostream
+but not LexicalConverter. */
+template<typename T>
+void operator<<(LexicalConverter &, const T &)
+{ }
+
+template<typename T>
+static std::string stringify_key(const T &k)
+{
+ try
+ {
+ LexicalConverter conv((Fmt()));
+ conv<<k;
+ return conv.get();
+ }
+ catch(const lexical_error &)
+ {
+ return "<cannot display value>";
+ }
+}
+
+} // namespace Internal
+
class key_error: public std::runtime_error
{
public:
- key_error(const std::type_info &);
- ~key_error() throw() { }
+ template<typename T>
+ key_error(const T &k):
+ runtime_error(make_what(typeid(T), MapUtilsInternal::stringify_key(k)))
+ { }
+
+ virtual ~key_error() throw() { }
+
+private:
+ static std::string make_what(const std::type_info &, const std::string &);
};
{
typename T::iterator i = map.find(key);
if(i==map.end())
- throw key_error(typeid(T));
+ throw key_error(key);
return i->second;
}
{
typename T::const_iterator i = map.find(key);
if(i==map.end())
- throw key_error(typeid(T));
+ throw key_error(key);
return i->second;
}
const typename T::iterator insert_unique(T &map, const typename T::key_type &key, const typename T::mapped_type &item)
{
if(map.count(key))
- throw key_error(typeid(T));
+ throw key_error(key);
return map.insert(typename T::value_type(key, item)).first;
}