• Main Page
  • Related Pages
  • Classes
  • Files
  • File List

src/AnyMap.hh

00001 /*
00002  * Copyright Staffan Gimåker 2009.
00003  *
00004  * ---
00005  *
00006  * Distributed under the Boost Software License, Version 1.0.
00007  * (See accompanying file LICENSE_1_0.txt or copy at
00008  * http://www.boost.org/LICENSE_1_0.txt)
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

Generated on Sun Jan 30 2011 for peekabot by  doxygen 1.7.1