source: NonGTP/Boost/boost/dynamic_property_map.hpp @ 857

Revision 857, 10.6 KB checked in by igarcia, 19 years ago (diff)
RevLine 
[857]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
33namespace boost {
34
35namespace 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.
53class dynamic_property_map
54{
55public:
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
70struct dynamic_property_exception : public std::exception {
71  virtual ~dynamic_property_exception() throw() {}
72  virtual const char* what() const throw() = 0;
73};
74
75struct 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
90struct 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
107struct 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
116namespace detail {
117
118//
119// dynamic_property_map_adaptor -
120//   property-map adaptor to support runtime polymorphism.
121template<typename PropertyMap>
122class 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
171public:
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
214private:
215  PropertyMap property_map;
216};
217
218} // namespace detail
219
220//
221// dynamic_properties -
222//   container for dynamic property maps
223//
224struct 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;
232public:
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
290private:
291  property_maps_type property_maps;
292  generate_fn_type generate_fn;
293};
294
295template<typename Key, typename Value>
296bool
297put(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
319template<typename Value, typename Key>
320Value
321get(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
333template<typename Value, typename Key>
334Value
335get(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
346template<typename Key>
347std::string
348get(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
Note: See TracBrowser for help on using the repository browser.