1 #ifndef DYNAMIC_PROPERTY_MAP_RG09302004_HPP
2 #define DYNAMIC_PROPERTY_MAP_RG09302004_HPP
4 // Copyright 2004-5 The Trustees of Indiana University.
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)
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.
15 // Authors: Doug Gregor
20 #include <boost/config.hpp>
21 #include <boost/throw_exception.hpp>
22 #include <boost/property_map/property_map.hpp>
23 #include <boost/lexical_cast.hpp>
24 #include <boost/any.hpp>
25 #include <boost/function/function3.hpp>
26 #include <boost/type_traits/is_convertible.hpp>
28 #include <boost/mpl/bool.hpp>
32 #include <boost/type.hpp>
33 #include <boost/smart_ptr.hpp>
40 // A wrapper around lexical_cast, which does not behave as
41 // desired for std::string types.
42 template<typename Value>
43 inline Value read_value(const std::string& value)
44 { return boost::lexical_cast<Value>(value); }
47 inline std::string read_value<std::string>(const std::string& value)
53 // dynamic_property_map -
54 // This interface supports polymorphic manipulation of property maps.
55 class dynamic_property_map
58 virtual ~dynamic_property_map() { }
60 virtual boost::any get(const any& key) = 0;
61 virtual std::string get_string(const any& key) = 0;
62 virtual void put(const any& key, const any& value) = 0;
63 virtual const std::type_info& key() const = 0;
64 virtual const std::type_info& value() const = 0;
68 //////////////////////////////////////////////////////////////////////
69 // Property map exceptions
70 //////////////////////////////////////////////////////////////////////
72 struct dynamic_property_exception : public std::exception {
73 virtual ~dynamic_property_exception() throw() {}
74 virtual const char* what() const throw() = 0;
77 struct property_not_found : public dynamic_property_exception {
79 mutable std::string statement;
80 property_not_found(const std::string& property) : property(property) {}
81 virtual ~property_not_found() throw() {}
83 const char* what() const throw() {
86 std::string("Property not found: ") + property + ".";
88 return statement.c_str();
92 struct dynamic_get_failure : public dynamic_property_exception {
94 mutable std::string statement;
95 dynamic_get_failure(const std::string& property) : property(property) {}
96 virtual ~dynamic_get_failure() throw() {}
98 const char* what() const throw() {
102 "dynamic property get cannot retrieve value for property: ")
105 return statement.c_str();
109 struct dynamic_const_put_error : public dynamic_property_exception {
110 virtual ~dynamic_const_put_error() throw() {}
112 const char* what() const throw() {
113 return "Attempt to put a value into a const property map: ";
121 // dynamic_property_map_adaptor -
122 // property-map adaptor to support runtime polymorphism.
123 template<typename PropertyMap>
124 class dynamic_property_map_adaptor : public dynamic_property_map
126 typedef typename property_traits<PropertyMap>::key_type key_type;
127 typedef typename property_traits<PropertyMap>::value_type value_type;
128 typedef typename property_traits<PropertyMap>::category category;
130 // do_put - overloaded dispatches from the put() member function.
131 // Attempts to "put" to a property map that does not model
132 // WritablePropertyMap result in a runtime exception.
134 // in_value must either hold an object of value_type or a string that
135 // can be converted to value_type via iostreams.
136 void do_put(const any& in_key, const any& in_value, mpl::bool_<true>)
138 #if !(defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 95))
142 key_type key = any_cast<key_type>(in_key);
143 if (in_value.type() == typeid(value_type)) {
144 #if defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 95)
145 boost::put(property_map, key, any_cast<value_type>(in_value));
147 put(property_map, key, any_cast<value_type>(in_value));
150 // if in_value is an empty string, put a default constructed value_type.
151 std::string v = any_cast<std::string>(in_value);
153 #if defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 95)
154 boost::put(property_map, key, value_type());
156 put(property_map, key, value_type());
159 #if defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 95)
160 boost::put(property_map, key, detail::read_value<value_type>(v));
162 put(property_map, key, detail::read_value<value_type>(v));
168 void do_put(const any&, const any&, mpl::bool_<false>)
170 BOOST_THROW_EXCEPTION(dynamic_const_put_error());
174 explicit dynamic_property_map_adaptor(const PropertyMap& property_map)
175 : property_map(property_map) { }
177 virtual boost::any get(const any& key)
179 #if defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 95)
180 return boost::get(property_map, any_cast<key_type>(key));
184 return get(property_map, any_cast<key_type>(key));
188 virtual std::string get_string(const any& key)
190 #if defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 95)
191 std::ostringstream out;
192 out << boost::get(property_map, any_cast<key_type>(key));
197 std::ostringstream out;
198 out << get(property_map, any_cast<key_type>(key));
203 virtual void put(const any& in_key, const any& in_value)
205 do_put(in_key, in_value,
206 mpl::bool_<(is_convertible<category*,
207 writable_property_map_tag*>::value)>());
210 virtual const std::type_info& key() const { return typeid(key_type); }
211 virtual const std::type_info& value() const { return typeid(value_type); }
213 PropertyMap& base() { return property_map; }
214 const PropertyMap& base() const { return property_map; }
217 PropertyMap property_map;
220 } // namespace detail
223 // dynamic_properties -
224 // container for dynamic property maps
226 struct dynamic_properties
228 typedef std::multimap<std::string, boost::shared_ptr<dynamic_property_map> >
230 typedef boost::function3<boost::shared_ptr<dynamic_property_map>,
233 const boost::any&> generate_fn_type;
236 typedef property_maps_type::iterator iterator;
237 typedef property_maps_type::const_iterator const_iterator;
239 dynamic_properties() : generate_fn() { }
240 dynamic_properties(const generate_fn_type& g) : generate_fn(g) {}
242 ~dynamic_properties() {}
244 template<typename PropertyMap>
246 property(const std::string& name, PropertyMap property_map)
248 // Tbd: exception safety
249 boost::shared_ptr<dynamic_property_map> pm(
250 new detail::dynamic_property_map_adaptor<PropertyMap>(property_map));
251 property_maps.insert(property_maps_type::value_type(name, pm));
256 iterator begin() { return property_maps.begin(); }
257 const_iterator begin() const { return property_maps.begin(); }
258 iterator end() { return property_maps.end(); }
259 const_iterator end() const { return property_maps.end(); }
261 iterator lower_bound(const std::string& name)
262 { return property_maps.lower_bound(name); }
264 const_iterator lower_bound(const std::string& name) const
265 { return property_maps.lower_bound(name); }
268 insert(const std::string& name, boost::shared_ptr<dynamic_property_map> pm)
270 property_maps.insert(property_maps_type::value_type(name, pm));
273 template<typename Key, typename Value>
274 boost::shared_ptr<dynamic_property_map>
275 generate(const std::string& name, const Key& key, const Value& value)
278 BOOST_THROW_EXCEPTION(property_not_found(name));
280 return generate_fn(name,key,value);
285 property_maps_type property_maps;
286 generate_fn_type generate_fn;
289 template<typename Key, typename Value>
291 put(const std::string& name, dynamic_properties& dp, const Key& key,
294 for (dynamic_properties::iterator i = dp.lower_bound(name);
295 i != dp.end() && i->first == name; ++i) {
296 if (i->second->key() == typeid(key)) {
297 i->second->put(key, value);
302 boost::shared_ptr<dynamic_property_map> new_map = dp.generate(name, key, value);
304 new_map->put(key, value);
305 dp.insert(name, new_map);
312 #ifndef BOOST_NO_EXPLICIT_FUNCTION_TEMPLATE_ARGUMENTS
313 template<typename Value, typename Key>
315 get(const std::string& name, const dynamic_properties& dp, const Key& key)
317 for (dynamic_properties::const_iterator i = dp.lower_bound(name);
318 i != dp.end() && i->first == name; ++i) {
319 if (i->second->key() == typeid(key))
320 return any_cast<Value>(i->second->get(key));
323 BOOST_THROW_EXCEPTION(dynamic_get_failure(name));
327 template<typename Value, typename Key>
329 get(const std::string& name, const dynamic_properties& dp, const Key& key, type<Value>)
331 for (dynamic_properties::const_iterator i = dp.lower_bound(name);
332 i != dp.end() && i->first == name; ++i) {
333 if (i->second->key() == typeid(key))
334 return any_cast<Value>(i->second->get(key));
337 BOOST_THROW_EXCEPTION(dynamic_get_failure(name));
340 template<typename Key>
342 get(const std::string& name, const dynamic_properties& dp, const Key& key)
344 for (dynamic_properties::const_iterator i = dp.lower_bound(name);
345 i != dp.end() && i->first == name; ++i) {
346 if (i->second->key() == typeid(key))
347 return i->second->get_string(key);
350 BOOST_THROW_EXCEPTION(dynamic_get_failure(name));
353 // The easy way to ignore properties.
355 boost::shared_ptr<boost::dynamic_property_map>
356 ignore_other_properties(const std::string&,
359 return boost::shared_ptr<boost::dynamic_property_map>();
364 #endif // DYNAMIC_PROPERTY_MAP_RG09302004_HPP