00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #ifndef PEEKABOT_ANY_MAP_HH_INCLUDED
00012 #define PEEKABOT_ANY_MAP_HH_INCLUDED
00013
00014
00015 #include <map>
00016 #include <string>
00017 #include <stdexcept>
00018 #include <boost/any.hpp>
00019 #include <boost/function.hpp>
00020 #include <boost/utility/enable_if.hpp>
00021 #include <boost/type_traits.hpp>
00022 #include <boost/mpl/not.hpp>
00023
00024
00025 namespace peekabot
00026 {
00034 class AnyMap
00035 {
00036 class ValHolder
00037 {
00038 public:
00039 virtual ~ValHolder() {}
00040
00041 virtual ValHolder *clone() const = 0;
00042
00043 virtual boost::any get() const = 0;
00044
00045 virtual void set(const boost::any &val) = 0;
00046 };
00047
00048 class IntrinsicVal : public ValHolder
00049 {
00050 public:
00051 IntrinsicVal(const boost::any &val) : m_val(val) {}
00052
00053 virtual ValHolder *clone() const
00054 {
00055 return new IntrinsicVal(m_val);
00056 }
00057
00058 virtual boost::any get() const
00059 {
00060 return m_val;
00061 }
00062
00063 virtual void set(const boost::any &val)
00064 {
00065 m_val = val;
00066 }
00067
00068 private:
00069 boost::any m_val;
00070 };
00071
00072 template<typename T>
00073 class Adapter : public ValHolder
00074 {
00075 public:
00076 Adapter(
00077 boost::function<T ()> getter,
00078 boost::function<void (const T &)> setter)
00079 : m_getter(getter), m_setter(setter) {}
00080
00081 virtual ValHolder *clone() const
00082 {
00083 return new Adapter<T>(m_getter, m_setter);
00084 }
00085
00086 virtual boost::any get() const
00087 {
00088 return wrap<T>(m_getter());
00089 }
00090
00091 virtual void set(const boost::any &val)
00092 {
00093 if( m_setter )
00094 m_setter(unwrap<T>(val));
00095 else
00096 throw std::runtime_error(
00097 "The (adapted) value is read only");
00098 }
00099
00100 private:
00101 template<typename U>
00102 static inline typename boost::enable_if<
00103 boost::mpl::not_<boost::is_same<U, boost::any> >,
00104 boost::any>::type wrap(const U &x)
00105 {
00106 return boost::any(x);
00107 }
00108
00109 template<typename U>
00110 static inline typename boost::enable_if<
00111 boost::is_same<U, boost::any>,
00112 boost::any>::type wrap(const boost::any &x)
00113 {
00114 return x;
00115 }
00116
00117 template<typename U>
00118 static inline typename boost::enable_if<
00119 boost::mpl::not_<boost::is_same<U, boost::any> >,
00120 U>::type unwrap(const boost::any &x)
00121 {
00122 return boost::any_cast<U>(x);
00123 }
00124
00125 template<typename U>
00126 static inline typename boost::enable_if<
00127 boost::is_same<U, boost::any>,
00128 boost::any>::type unwrap(const boost::any &x)
00129 {
00130 return x;
00131 }
00132
00133 private:
00134 boost::function<T (void)> m_getter;
00135 boost::function<void (const T &)> m_setter;
00136 };
00137
00138 public:
00139 typedef std::string KeyType;
00140
00141 class NoSuchKey : public std::runtime_error
00142 {
00143 public:
00144 NoSuchKey(const std::string &msg) : std::runtime_error(msg) {}
00145 };
00146
00147 class TypeMismatch : public std::runtime_error
00148 {
00149 public:
00150 TypeMismatch(const std::string &msg) : std::runtime_error(msg) {}
00151 };
00152
00153
00154
00155 AnyMap() {}
00156
00157 AnyMap(const AnyMap &other)
00158 {
00159 for( KVMap::const_iterator it = other.m_kv_map.begin();
00160 it != other.m_kv_map.end(); ++it )
00161 {
00162 m_kv_map.insert(std::make_pair(it->first, it->second->clone()));
00163 }
00164 }
00165
00166 ~AnyMap()
00167 {
00168 clear();
00169 }
00170
00171 AnyMap &operator=(const AnyMap &other)
00172 {
00173 clear();
00174
00175 for( KVMap::const_iterator it = other.m_kv_map.begin();
00176 it != other.m_kv_map.end(); ++it )
00177 {
00178 m_kv_map.insert(std::make_pair(it->first, it->second->clone()));
00179 }
00180
00181 return *this;
00182 }
00183
00184 template<typename T>
00185 T get(const KeyType &key) const
00186 {
00187 KVMap::const_iterator it = m_kv_map.find(key);
00188 if( it == m_kv_map.end() )
00189 throw NoSuchKey("No such key");
00190 else
00191 {
00192 try
00193 {
00194 return boost::any_cast<T>(it->second->get());
00195 }
00196 catch(boost::bad_any_cast &)
00197 {
00198 throw TypeMismatch("Value type mismatch");
00199 }
00200 }
00201 }
00202
00203 template<typename T> inline
00204 void set(const KeyType &key, const T &val)
00205 {
00206 set(key, boost::any(val));
00207 }
00208
00209 void set(const KeyType &key, const boost::any &val)
00210 {
00211 KVMap::iterator it = m_kv_map.find(key);
00212 if( it == m_kv_map.end() )
00213 insert(key, val);
00214 else
00215 it->second->set(boost::any(val));
00216 }
00217
00218 void erase(const KeyType &key)
00219 {
00220 KVMap::iterator it = m_kv_map.find(key);
00221 if( it == m_kv_map.end() )
00222 throw std::runtime_error("No such key");
00223 else
00224 {
00225 delete it->second;
00226 m_kv_map.erase(it);
00227 }
00228 }
00229
00230 void clear()
00231 {
00232 for( KVMap::iterator it = m_kv_map.begin();
00233 it != m_kv_map.end(); ++it )
00234 {
00235 delete it->second;
00236 }
00237 m_kv_map.clear();
00238 }
00239
00240 inline std::size_t count(const KeyType &key) const
00241 {
00242 return m_kv_map.count(key);
00243 }
00244
00245 template<typename T>
00246 bool has_type(const KeyType &key) const
00247 {
00248 KVMap::const_iterator it = m_kv_map.find(key);
00249 if( it == m_kv_map.end() )
00250 return false;
00251 else
00252 {
00253 try
00254 {
00255 boost::any_cast<T>(it->second->get());
00256 return true;
00257 }
00258 catch(...)
00259 {
00260 return false;
00261 }
00262 }
00263 }
00264
00265 inline void insert(const KeyType &key, const boost::any &val)
00266 {
00267 ValHolder *p = new IntrinsicVal(val);
00268 insert(key, p);
00269 }
00270
00271 template<typename T> inline
00272 void insert(const KeyType &key, const T &val)
00273 {
00274 insert(key, boost::any(val));
00275 }
00276
00277 template<typename T> inline
00278 void insert_adapter(
00279 const KeyType &key,
00280 boost::function<T ()> getter,
00281 boost::function<void (const T &)> setter =
00282 boost::function<void (const T &)>())
00283 {
00284 ValHolder *p = new Adapter<T>(getter, setter);
00285 insert(key, p);
00286 }
00287
00288 private:
00289 void insert(const KeyType &key, ValHolder *p) throw()
00290 {
00291 KVMap::iterator it = m_kv_map.find(key);
00292 if( it != m_kv_map.end() )
00293 {
00294 delete it->second;
00295 it->second = p;
00296 }
00297 else
00298 {
00299 m_kv_map.insert(std::make_pair(key, p));
00300 }
00301 }
00302
00303 private:
00304 typedef std::map<KeyType, ValHolder *> KVMap;
00305
00306 KVMap m_kv_map;
00307 };
00308 }
00309
00310
00311 #endif // PEEKABOT_ANY_MAP_HH_INCLUDED