| 1 | #ifndef DYNAMIC_PROPERTY_MAP_RG09302004_HPP | 
|---|
| 2 | #define DYNAMIC_PROPERTY_MAP_RG09302004_HPP | 
|---|
| 3 |  | 
|---|
| 4 | // Copyright 2004-5 The Trustees of Indiana University. | 
|---|
| 5 |  | 
|---|
| 6 | // Use, modification and distribution is subject to the Boost Software | 
|---|
| 7 | // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at | 
|---|
| 8 | // http://www.boost.org/LICENSE_1_0.txt) | 
|---|
| 9 |  | 
|---|
| 10 | //  dynamic_property_map.hpp - | 
|---|
| 11 | //    Support for runtime-polymorphic property maps.  This header is factored | 
|---|
| 12 | //  out of Doug Gregor's routines for reading GraphML files for use in reading | 
|---|
| 13 | //  GraphViz graph files. | 
|---|
| 14 |  | 
|---|
| 15 | //  Authors: Doug Gregor | 
|---|
| 16 | //           Ronald Garcia | 
|---|
| 17 | // | 
|---|
| 18 |  | 
|---|
| 19 |  | 
|---|
| 20 | #include <boost/config.hpp> | 
|---|
| 21 | #include <boost/property_map.hpp> | 
|---|
| 22 | #include <boost/lexical_cast.hpp> | 
|---|
| 23 | #include <boost/any.hpp> | 
|---|
| 24 | #include <boost/function/function3.hpp> | 
|---|
| 25 | #include <boost/type_traits/is_convertible.hpp> | 
|---|
| 26 | #include <typeinfo> | 
|---|
| 27 | #include <boost/mpl/bool.hpp> | 
|---|
| 28 | #include <stdexcept> | 
|---|
| 29 | #include <sstream> | 
|---|
| 30 | #include <map> | 
|---|
| 31 | #include <boost/type.hpp> | 
|---|
| 32 |  | 
|---|
| 33 | namespace boost { | 
|---|
| 34 |  | 
|---|
| 35 | namespace detail { | 
|---|
| 36 |  | 
|---|
| 37 |   // read_value - | 
|---|
| 38 |   //   A wrapper around lexical_cast, which does not behave as | 
|---|
| 39 |   //   desired for std::string types. | 
|---|
| 40 |   template<typename Value> | 
|---|
| 41 |   inline Value read_value(const std::string& value) | 
|---|
| 42 |   { return boost::lexical_cast<Value>(value); } | 
|---|
| 43 |  | 
|---|
| 44 |   template<> | 
|---|
| 45 |   inline std::string read_value<std::string>(const std::string& value) | 
|---|
| 46 |   { return value; } | 
|---|
| 47 |  | 
|---|
| 48 | } | 
|---|
| 49 |  | 
|---|
| 50 |  | 
|---|
| 51 | // dynamic_property_map - | 
|---|
| 52 | //  This interface supports polymorphic manipulation of property maps. | 
|---|
| 53 | class dynamic_property_map | 
|---|
| 54 | { | 
|---|
| 55 | public: | 
|---|
| 56 |   virtual ~dynamic_property_map() { } | 
|---|
| 57 |  | 
|---|
| 58 |   virtual boost::any get(const any& key) = 0; | 
|---|
| 59 |   virtual std::string get_string(const any& key) = 0; | 
|---|
| 60 |   virtual void put(const any& key, const any& value) = 0; | 
|---|
| 61 |   virtual const std::type_info& key() const = 0; | 
|---|
| 62 |   virtual const std::type_info& value() const = 0; | 
|---|
| 63 | }; | 
|---|
| 64 |  | 
|---|
| 65 |  | 
|---|
| 66 | ////////////////////////////////////////////////////////////////////// | 
|---|
| 67 | // Property map exceptions | 
|---|
| 68 | ////////////////////////////////////////////////////////////////////// | 
|---|
| 69 |  | 
|---|
| 70 | struct dynamic_property_exception : public std::exception { | 
|---|
| 71 |   virtual ~dynamic_property_exception() throw() {} | 
|---|
| 72 |   virtual const char* what() const throw() = 0; | 
|---|
| 73 | }; | 
|---|
| 74 |  | 
|---|
| 75 | struct property_not_found : public dynamic_property_exception { | 
|---|
| 76 |   std::string property; | 
|---|
| 77 |   mutable std::string statement; | 
|---|
| 78 |   property_not_found(const std::string& property) : property(property) {} | 
|---|
| 79 |   virtual ~property_not_found() throw() {} | 
|---|
| 80 |  | 
|---|
| 81 |   const char* what() const throw() { | 
|---|
| 82 |     if(statement.empty()) | 
|---|
| 83 |       statement = | 
|---|
| 84 |         std::string("Property not found: ") + property + "."; | 
|---|
| 85 |  | 
|---|
| 86 |     return statement.c_str(); | 
|---|
| 87 |   } | 
|---|
| 88 | }; | 
|---|
| 89 |  | 
|---|
| 90 | struct dynamic_get_failure : public dynamic_property_exception { | 
|---|
| 91 |   std::string property; | 
|---|
| 92 |   mutable std::string statement; | 
|---|
| 93 |   dynamic_get_failure(const std::string& property) : property(property) {} | 
|---|
| 94 |   virtual ~dynamic_get_failure() throw() {} | 
|---|
| 95 |  | 
|---|
| 96 |   const char* what() const throw() { | 
|---|
| 97 |     if(statement.empty()) | 
|---|
| 98 |       statement = | 
|---|
| 99 |         std::string( | 
|---|
| 100 |          "dynamic property get cannot retrieve value for  property: ") | 
|---|
| 101 |         + property + "."; | 
|---|
| 102 |  | 
|---|
| 103 |     return statement.c_str(); | 
|---|
| 104 |   } | 
|---|
| 105 | }; | 
|---|
| 106 |  | 
|---|
| 107 | struct dynamic_const_put_error  : public dynamic_property_exception { | 
|---|
| 108 |   virtual ~dynamic_const_put_error() throw() {} | 
|---|
| 109 |  | 
|---|
| 110 |   const char* what() const throw() { | 
|---|
| 111 |     return "Attempt to put a value into a const property map: "; | 
|---|
| 112 |   } | 
|---|
| 113 | }; | 
|---|
| 114 |  | 
|---|
| 115 |  | 
|---|
| 116 | namespace detail { | 
|---|
| 117 |  | 
|---|
| 118 | // | 
|---|
| 119 | // dynamic_property_map_adaptor - | 
|---|
| 120 | //   property-map adaptor to support runtime polymorphism. | 
|---|
| 121 | template<typename PropertyMap> | 
|---|
| 122 | class dynamic_property_map_adaptor : public dynamic_property_map | 
|---|
| 123 | { | 
|---|
| 124 |   typedef typename property_traits<PropertyMap>::key_type key_type; | 
|---|
| 125 |   typedef typename property_traits<PropertyMap>::value_type value_type; | 
|---|
| 126 |   typedef typename property_traits<PropertyMap>::category category; | 
|---|
| 127 |  | 
|---|
| 128 |   // do_put - overloaded dispatches from the put() member function. | 
|---|
| 129 |   //   Attempts to "put" to a property map that does not model | 
|---|
| 130 |   //   WritablePropertyMap result in a runtime exception. | 
|---|
| 131 |  | 
|---|
| 132 |   //   in_value must either hold an object of value_type or a string that | 
|---|
| 133 |   //   can be converted to value_type via iostreams. | 
|---|
| 134 |   void do_put(const any& in_key, const any& in_value, mpl::bool_<true>) | 
|---|
| 135 |   { | 
|---|
| 136 | #if !(defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 95)) | 
|---|
| 137 |     using boost::put; | 
|---|
| 138 | #endif | 
|---|
| 139 |  | 
|---|
| 140 |     key_type key = any_cast<key_type>(in_key); | 
|---|
| 141 |     if (in_value.type() == typeid(value_type)) { | 
|---|
| 142 | #if defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 95) | 
|---|
| 143 |       boost::put(property_map, key, any_cast<value_type>(in_value)); | 
|---|
| 144 | #else | 
|---|
| 145 |       put(property_map, key, any_cast<value_type>(in_value)); | 
|---|
| 146 | #endif | 
|---|
| 147 |     } else { | 
|---|
| 148 |       //  if in_value is an empty string, put a default constructed value_type. | 
|---|
| 149 |       std::string v = any_cast<std::string>(in_value); | 
|---|
| 150 |       if (v.empty()) { | 
|---|
| 151 | #if defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 95) | 
|---|
| 152 |         boost::put(property_map, key, value_type()); | 
|---|
| 153 | #else | 
|---|
| 154 |         put(property_map, key, value_type()); | 
|---|
| 155 | #endif | 
|---|
| 156 |       } else { | 
|---|
| 157 | #if defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 95) | 
|---|
| 158 |         boost::put(property_map, key, detail::read_value<value_type>(v)); | 
|---|
| 159 | #else | 
|---|
| 160 |         put(property_map, key, detail::read_value<value_type>(v)); | 
|---|
| 161 | #endif | 
|---|
| 162 |       } | 
|---|
| 163 |     } | 
|---|
| 164 |   } | 
|---|
| 165 |  | 
|---|
| 166 |   void do_put(const any&, const any&, mpl::bool_<false>) | 
|---|
| 167 |   { | 
|---|
| 168 |     throw dynamic_const_put_error(); | 
|---|
| 169 |   } | 
|---|
| 170 |  | 
|---|
| 171 | public: | 
|---|
| 172 |   explicit dynamic_property_map_adaptor(const PropertyMap& property_map) | 
|---|
| 173 |     : property_map(property_map) { } | 
|---|
| 174 |  | 
|---|
| 175 |   virtual boost::any get(const any& key) | 
|---|
| 176 |   { | 
|---|
| 177 | #if defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 95) | 
|---|
| 178 |     return boost::get(property_map, any_cast<key_type>(key)); | 
|---|
| 179 | #else | 
|---|
| 180 |     using boost::get; | 
|---|
| 181 |  | 
|---|
| 182 |     return get(property_map, any_cast<key_type>(key)); | 
|---|
| 183 | #endif | 
|---|
| 184 |   } | 
|---|
| 185 |  | 
|---|
| 186 |   virtual std::string get_string(const any& key) | 
|---|
| 187 |   { | 
|---|
| 188 | #if defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 95) | 
|---|
| 189 |     std::ostringstream out; | 
|---|
| 190 |     out << boost::get(property_map, any_cast<key_type>(key)); | 
|---|
| 191 |     return out.str(); | 
|---|
| 192 | #else | 
|---|
| 193 |     using boost::get; | 
|---|
| 194 |  | 
|---|
| 195 |     std::ostringstream out; | 
|---|
| 196 |     out << get(property_map, any_cast<key_type>(key)); | 
|---|
| 197 |     return out.str(); | 
|---|
| 198 | #endif | 
|---|
| 199 |   } | 
|---|
| 200 |  | 
|---|
| 201 |   virtual void put(const any& in_key, const any& in_value) | 
|---|
| 202 |   { | 
|---|
| 203 |     do_put(in_key, in_value, | 
|---|
| 204 |            mpl::bool_<(is_convertible<category*, | 
|---|
| 205 |                                       writable_property_map_tag*>::value)>()); | 
|---|
| 206 |   } | 
|---|
| 207 |  | 
|---|
| 208 |   virtual const std::type_info& key()   const { return typeid(key_type); } | 
|---|
| 209 |   virtual const std::type_info& value() const { return typeid(value_type); } | 
|---|
| 210 |  | 
|---|
| 211 |   PropertyMap&       base()       { return property_map; } | 
|---|
| 212 |   const PropertyMap& base() const { return property_map; } | 
|---|
| 213 |  | 
|---|
| 214 | private: | 
|---|
| 215 |   PropertyMap property_map; | 
|---|
| 216 | }; | 
|---|
| 217 |  | 
|---|
| 218 | } // namespace detail | 
|---|
| 219 |  | 
|---|
| 220 | // | 
|---|
| 221 | // dynamic_properties - | 
|---|
| 222 | //   container for dynamic property maps | 
|---|
| 223 | // | 
|---|
| 224 | struct dynamic_properties | 
|---|
| 225 | { | 
|---|
| 226 |   typedef std::multimap<std::string, dynamic_property_map*> | 
|---|
| 227 |     property_maps_type; | 
|---|
| 228 |   typedef boost::function3<std::auto_ptr<dynamic_property_map>, | 
|---|
| 229 |                            const std::string&, | 
|---|
| 230 |                            const boost::any&, | 
|---|
| 231 |                            const boost::any&> generate_fn_type; | 
|---|
| 232 | public: | 
|---|
| 233 |  | 
|---|
| 234 |   typedef property_maps_type::iterator iterator; | 
|---|
| 235 |   typedef property_maps_type::const_iterator const_iterator; | 
|---|
| 236 |  | 
|---|
| 237 |   dynamic_properties() : generate_fn() { } | 
|---|
| 238 |   dynamic_properties(const generate_fn_type& g) : generate_fn(g) {} | 
|---|
| 239 |  | 
|---|
| 240 |   ~dynamic_properties() | 
|---|
| 241 |   { | 
|---|
| 242 |     for (property_maps_type::iterator i = property_maps.begin(); | 
|---|
| 243 |          i != property_maps.end(); ++i) { | 
|---|
| 244 |       delete i->second; | 
|---|
| 245 |     } | 
|---|
| 246 |   } | 
|---|
| 247 |  | 
|---|
| 248 |   template<typename PropertyMap> | 
|---|
| 249 |   dynamic_properties& | 
|---|
| 250 |   property(const std::string& name, PropertyMap property_map) | 
|---|
| 251 |   { | 
|---|
| 252 |     // Tbd: exception safety | 
|---|
| 253 |     std::auto_ptr<dynamic_property_map> pm( | 
|---|
| 254 |       new detail::dynamic_property_map_adaptor<PropertyMap>(property_map)); | 
|---|
| 255 |     property_maps_type::iterator i = | 
|---|
| 256 |       property_maps.insert(property_maps_type::value_type(name, 0)); | 
|---|
| 257 |     i->second = pm.release(); | 
|---|
| 258 |  | 
|---|
| 259 |     return *this; | 
|---|
| 260 |   } | 
|---|
| 261 |  | 
|---|
| 262 |   iterator       begin()       { return property_maps.begin(); } | 
|---|
| 263 |   const_iterator begin() const { return property_maps.begin(); } | 
|---|
| 264 |   iterator       end()         { return property_maps.end(); } | 
|---|
| 265 |   const_iterator end() const   { return property_maps.end(); } | 
|---|
| 266 |  | 
|---|
| 267 |   iterator lower_bound(const std::string& name) | 
|---|
| 268 |   { return property_maps.lower_bound(name); } | 
|---|
| 269 |  | 
|---|
| 270 |   const_iterator lower_bound(const std::string& name) const | 
|---|
| 271 |   { return property_maps.lower_bound(name); } | 
|---|
| 272 |  | 
|---|
| 273 |   void | 
|---|
| 274 |   insert(const std::string& name, std::auto_ptr<dynamic_property_map> pm) | 
|---|
| 275 |   { | 
|---|
| 276 |     property_maps.insert(property_maps_type::value_type(name, pm.release())); | 
|---|
| 277 |   } | 
|---|
| 278 |  | 
|---|
| 279 |   template<typename Key, typename Value> | 
|---|
| 280 |   std::auto_ptr<dynamic_property_map> | 
|---|
| 281 |   generate(const std::string& name, const Key& key, const Value& value) | 
|---|
| 282 |   { | 
|---|
| 283 |     if(!generate_fn) { | 
|---|
| 284 |       throw property_not_found(name); | 
|---|
| 285 |     } else { | 
|---|
| 286 |       return generate_fn(name,key,value); | 
|---|
| 287 |     } | 
|---|
| 288 |   } | 
|---|
| 289 |  | 
|---|
| 290 | private: | 
|---|
| 291 |   property_maps_type property_maps; | 
|---|
| 292 |   generate_fn_type generate_fn; | 
|---|
| 293 | }; | 
|---|
| 294 |  | 
|---|
| 295 | template<typename Key, typename Value> | 
|---|
| 296 | bool | 
|---|
| 297 | put(const std::string& name, dynamic_properties& dp, const Key& key, | 
|---|
| 298 |     const Value& value) | 
|---|
| 299 | { | 
|---|
| 300 |   for (dynamic_properties::iterator i = dp.lower_bound(name); | 
|---|
| 301 |        i != dp.end() && i->first == name; ++i) { | 
|---|
| 302 |     if (i->second->key() == typeid(key)) { | 
|---|
| 303 |       i->second->put(key, value); | 
|---|
| 304 |       return true; | 
|---|
| 305 |     } | 
|---|
| 306 |   } | 
|---|
| 307 |  | 
|---|
| 308 |   std::auto_ptr<dynamic_property_map> new_map = dp.generate(name, key, value); | 
|---|
| 309 |   if (new_map.get()) { | 
|---|
| 310 |     new_map->put(key, value); | 
|---|
| 311 |     dp.insert(name, new_map); | 
|---|
| 312 |     return true; | 
|---|
| 313 |   } else { | 
|---|
| 314 |     return false; | 
|---|
| 315 |   } | 
|---|
| 316 | } | 
|---|
| 317 |  | 
|---|
| 318 | #ifndef BOOST_NO_EXPLICIT_FUNCTION_TEMPLATE_ARGUMENTS  | 
|---|
| 319 | template<typename Value, typename Key> | 
|---|
| 320 | Value | 
|---|
| 321 | get(const std::string& name, const dynamic_properties& dp, const Key& key) | 
|---|
| 322 | { | 
|---|
| 323 |   for (dynamic_properties::const_iterator i = dp.lower_bound(name); | 
|---|
| 324 |        i != dp.end() && i->first == name; ++i) { | 
|---|
| 325 |     if (i->second->key() == typeid(key)) | 
|---|
| 326 |       return any_cast<Value>(i->second->get(key)); | 
|---|
| 327 |   } | 
|---|
| 328 |  | 
|---|
| 329 |   throw dynamic_get_failure(name); | 
|---|
| 330 | } | 
|---|
| 331 | #endif | 
|---|
| 332 |  | 
|---|
| 333 | template<typename Value, typename Key> | 
|---|
| 334 | Value | 
|---|
| 335 | get(const std::string& name, const dynamic_properties& dp, const Key& key, type<Value>) | 
|---|
| 336 | { | 
|---|
| 337 |   for (dynamic_properties::const_iterator i = dp.lower_bound(name); | 
|---|
| 338 |        i != dp.end() && i->first == name; ++i) { | 
|---|
| 339 |     if (i->second->key() == typeid(key)) | 
|---|
| 340 |       return any_cast<Value>(i->second->get(key)); | 
|---|
| 341 |   } | 
|---|
| 342 |  | 
|---|
| 343 |   throw dynamic_get_failure(name); | 
|---|
| 344 | } | 
|---|
| 345 |  | 
|---|
| 346 | template<typename Key> | 
|---|
| 347 | std::string | 
|---|
| 348 | get(const std::string& name, const dynamic_properties& dp, const Key& key) | 
|---|
| 349 | { | 
|---|
| 350 |   for (dynamic_properties::const_iterator i = dp.lower_bound(name); | 
|---|
| 351 |        i != dp.end() && i->first == name; ++i) { | 
|---|
| 352 |     if (i->second->key() == typeid(key)) | 
|---|
| 353 |       return i->second->get_string(key); | 
|---|
| 354 |   } | 
|---|
| 355 |  | 
|---|
| 356 |   throw dynamic_get_failure(name); | 
|---|
| 357 | } | 
|---|
| 358 |  | 
|---|
| 359 |  | 
|---|
| 360 | } | 
|---|
| 361 |  | 
|---|
| 362 | #endif // DYNAMIC_PROPERTY_MAP_RG09302004_HPP | 
|---|