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/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>
27
#include <boost/mpl/bool.hpp>
31
#include <boost/type.hpp>
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); }
45
inline std::string read_value<std::string>(const std::string& value)
51
// dynamic_property_map -
52
// This interface supports polymorphic manipulation of property maps.
53
class dynamic_property_map
56
virtual ~dynamic_property_map() { }
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;
66
//////////////////////////////////////////////////////////////////////
67
// Property map exceptions
68
//////////////////////////////////////////////////////////////////////
70
struct dynamic_property_exception : public std::exception {
71
virtual ~dynamic_property_exception() throw() {}
72
virtual const char* what() const throw() = 0;
75
struct property_not_found : public dynamic_property_exception {
77
mutable std::string statement;
78
property_not_found(const std::string& property) : property(property) {}
79
virtual ~property_not_found() throw() {}
81
const char* what() const throw() {
84
std::string("Property not found: ") + property + ".";
86
return statement.c_str();
90
struct dynamic_get_failure : public dynamic_property_exception {
92
mutable std::string statement;
93
dynamic_get_failure(const std::string& property) : property(property) {}
94
virtual ~dynamic_get_failure() throw() {}
96
const char* what() const throw() {
100
"dynamic property get cannot retrieve value for property: ")
103
return statement.c_str();
107
struct dynamic_const_put_error : public dynamic_property_exception {
108
virtual ~dynamic_const_put_error() throw() {}
110
const char* what() const throw() {
111
return "Attempt to put a value into a const property map: ";
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
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;
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.
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>)
136
#if !(defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 95))
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));
145
put(property_map, key, any_cast<value_type>(in_value));
148
// if in_value is an empty string, put a default constructed value_type.
149
std::string v = any_cast<std::string>(in_value);
151
#if defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 95)
152
boost::put(property_map, key, value_type());
154
put(property_map, key, value_type());
157
#if defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 95)
158
boost::put(property_map, key, detail::read_value<value_type>(v));
160
put(property_map, key, detail::read_value<value_type>(v));
166
void do_put(const any&, const any&, mpl::bool_<false>)
168
throw dynamic_const_put_error();
172
explicit dynamic_property_map_adaptor(const PropertyMap& property_map)
173
: property_map(property_map) { }
175
virtual boost::any get(const any& key)
177
#if defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 95)
178
return boost::get(property_map, any_cast<key_type>(key));
182
return get(property_map, any_cast<key_type>(key));
186
virtual std::string get_string(const any& key)
188
#if defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 95)
189
std::ostringstream out;
190
out << boost::get(property_map, any_cast<key_type>(key));
195
std::ostringstream out;
196
out << get(property_map, any_cast<key_type>(key));
201
virtual void put(const any& in_key, const any& in_value)
203
do_put(in_key, in_value,
204
mpl::bool_<(is_convertible<category*,
205
writable_property_map_tag*>::value)>());
208
virtual const std::type_info& key() const { return typeid(key_type); }
209
virtual const std::type_info& value() const { return typeid(value_type); }
211
PropertyMap& base() { return property_map; }
212
const PropertyMap& base() const { return property_map; }
215
PropertyMap property_map;
218
} // namespace detail
221
// dynamic_properties -
222
// container for dynamic property maps
224
struct dynamic_properties
226
typedef std::multimap<std::string, dynamic_property_map*>
228
typedef boost::function3<std::auto_ptr<dynamic_property_map>,
231
const boost::any&> generate_fn_type;
234
typedef property_maps_type::iterator iterator;
235
typedef property_maps_type::const_iterator const_iterator;
237
dynamic_properties() : generate_fn() { }
238
dynamic_properties(const generate_fn_type& g) : generate_fn(g) {}
240
~dynamic_properties()
242
for (property_maps_type::iterator i = property_maps.begin();
243
i != property_maps.end(); ++i) {
248
template<typename PropertyMap>
250
property(const std::string& name, PropertyMap property_map)
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();
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(); }
267
iterator lower_bound(const std::string& name)
268
{ return property_maps.lower_bound(name); }
270
const_iterator lower_bound(const std::string& name) const
271
{ return property_maps.lower_bound(name); }
274
insert(const std::string& name, std::auto_ptr<dynamic_property_map> pm)
276
property_maps.insert(property_maps_type::value_type(name, pm.release()));
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)
284
throw property_not_found(name);
286
return generate_fn(name,key,value);
291
property_maps_type property_maps;
292
generate_fn_type generate_fn;
295
template<typename Key, typename Value>
297
put(const std::string& name, dynamic_properties& dp, const Key& key,
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);
308
std::auto_ptr<dynamic_property_map> new_map = dp.generate(name, key, value);
310
new_map->put(key, value);
311
dp.insert(name, new_map);
318
#ifndef BOOST_NO_EXPLICIT_FUNCTION_TEMPLATE_ARGUMENTS
319
template<typename Value, typename Key>
321
get(const std::string& name, const dynamic_properties& dp, const Key& key)
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));
329
throw dynamic_get_failure(name);
333
template<typename Value, typename Key>
335
get(const std::string& name, const dynamic_properties& dp, const Key& key, type<Value>)
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));
343
throw dynamic_get_failure(name);
346
template<typename Key>
348
get(const std::string& name, const dynamic_properties& dp, const Key& key)
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);
356
throw dynamic_get_failure(name);
359
// The easy way to ignore properties.
361
std::auto_ptr<boost::dynamic_property_map>
362
ignore_other_properties(const std::string&,
365
return std::auto_ptr<boost::dynamic_property_map>(0);
370
#endif // DYNAMIC_PROPERTY_MAP_RG09302004_HPP