Ugly, not-to-be-pushed sucking in of all of Boost to get windows to work.
[dyninst.git] / external / boost / dynamic_property_map.hpp
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