]> git.sesse.net Git - casparcg/blob - dependencies/boost/boost/property_map/dynamic_property_map.hpp
Manually merged pull request #222
[casparcg] / dependencies / boost / boost / property_map / 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/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>
27 #include <typeinfo>
28 #include <boost/mpl/bool.hpp>
29 #include <stdexcept>
30 #include <sstream>
31 #include <map>
32 #include <boost/type.hpp>
33 #include <boost/smart_ptr.hpp>
34
35 namespace boost {
36
37 namespace detail {
38
39   // read_value -
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); }
45
46   template<>
47   inline std::string read_value<std::string>(const std::string& value)
48   { return value; }
49
50 }
51
52
53 // dynamic_property_map -
54 //  This interface supports polymorphic manipulation of property maps.
55 class dynamic_property_map
56 {
57 public:
58   virtual ~dynamic_property_map() { }
59
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;
65 };
66
67
68 //////////////////////////////////////////////////////////////////////
69 // Property map exceptions
70 //////////////////////////////////////////////////////////////////////
71
72 struct dynamic_property_exception : public std::exception {
73   virtual ~dynamic_property_exception() throw() {}
74   virtual const char* what() const throw() = 0;
75 };
76
77 struct property_not_found : public dynamic_property_exception {
78   std::string property;
79   mutable std::string statement;
80   property_not_found(const std::string& property) : property(property) {}
81   virtual ~property_not_found() throw() {}
82
83   const char* what() const throw() {
84     if(statement.empty())
85       statement =
86         std::string("Property not found: ") + property + ".";
87
88     return statement.c_str();
89   }
90 };
91
92 struct dynamic_get_failure : public dynamic_property_exception {
93   std::string property;
94   mutable std::string statement;
95   dynamic_get_failure(const std::string& property) : property(property) {}
96   virtual ~dynamic_get_failure() throw() {}
97
98   const char* what() const throw() {
99     if(statement.empty())
100       statement =
101         std::string(
102          "dynamic property get cannot retrieve value for  property: ")
103         + property + ".";
104
105     return statement.c_str();
106   }
107 };
108
109 struct dynamic_const_put_error  : public dynamic_property_exception {
110   virtual ~dynamic_const_put_error() throw() {}
111
112   const char* what() const throw() {
113     return "Attempt to put a value into a const property map: ";
114   }
115 };
116
117
118 namespace detail {
119
120 //
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
125 {
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;
129
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.
133
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>)
137   {
138 #if !(defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 95))
139     using boost::put;
140 #endif
141
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));
146 #else
147       put(property_map, key, any_cast<value_type>(in_value));
148 #endif
149     } else {
150       //  if in_value is an empty string, put a default constructed value_type.
151       std::string v = any_cast<std::string>(in_value);
152       if (v.empty()) {
153 #if defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 95)
154         boost::put(property_map, key, value_type());
155 #else
156         put(property_map, key, value_type());
157 #endif
158       } else {
159 #if defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 95)
160         boost::put(property_map, key, detail::read_value<value_type>(v));
161 #else
162         put(property_map, key, detail::read_value<value_type>(v));
163 #endif
164       }
165     }
166   }
167
168   void do_put(const any&, const any&, mpl::bool_<false>)
169   {
170     BOOST_THROW_EXCEPTION(dynamic_const_put_error());
171   }
172
173 public:
174   explicit dynamic_property_map_adaptor(const PropertyMap& property_map)
175     : property_map(property_map) { }
176
177   virtual boost::any get(const any& key)
178   {
179 #if defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 95)
180     return boost::get(property_map, any_cast<key_type>(key));
181 #else
182     using boost::get;
183
184     return get(property_map, any_cast<key_type>(key));
185 #endif
186   }
187
188   virtual std::string get_string(const any& key)
189   {
190 #if defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ == 95)
191     std::ostringstream out;
192     out << boost::get(property_map, any_cast<key_type>(key));
193     return out.str();
194 #else
195     using boost::get;
196
197     std::ostringstream out;
198     out << get(property_map, any_cast<key_type>(key));
199     return out.str();
200 #endif
201   }
202
203   virtual void put(const any& in_key, const any& in_value)
204   {
205     do_put(in_key, in_value,
206            mpl::bool_<(is_convertible<category*,
207                                       writable_property_map_tag*>::value)>());
208   }
209
210   virtual const std::type_info& key()   const { return typeid(key_type); }
211   virtual const std::type_info& value() const { return typeid(value_type); }
212
213   PropertyMap&       base()       { return property_map; }
214   const PropertyMap& base() const { return property_map; }
215
216 private:
217   PropertyMap property_map;
218 };
219
220 } // namespace detail
221
222 //
223 // dynamic_properties -
224 //   container for dynamic property maps
225 //
226 struct dynamic_properties
227 {
228   typedef std::multimap<std::string, boost::shared_ptr<dynamic_property_map> >
229     property_maps_type;
230   typedef boost::function3<boost::shared_ptr<dynamic_property_map>,
231                            const std::string&,
232                            const boost::any&,
233                            const boost::any&> generate_fn_type;
234 public:
235
236   typedef property_maps_type::iterator iterator;
237   typedef property_maps_type::const_iterator const_iterator;
238
239   dynamic_properties() : generate_fn() { }
240   dynamic_properties(const generate_fn_type& g) : generate_fn(g) {}
241
242   ~dynamic_properties() {}
243
244   template<typename PropertyMap>
245   dynamic_properties&
246   property(const std::string& name, PropertyMap property_map)
247   {
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));
252
253     return *this;
254   }
255
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(); }
260
261   iterator lower_bound(const std::string& name)
262   { return property_maps.lower_bound(name); }
263
264   const_iterator lower_bound(const std::string& name) const
265   { return property_maps.lower_bound(name); }
266
267   void
268   insert(const std::string& name, boost::shared_ptr<dynamic_property_map> pm)
269   {
270     property_maps.insert(property_maps_type::value_type(name, pm));
271   }
272
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)
276   {
277     if(!generate_fn) {
278       BOOST_THROW_EXCEPTION(property_not_found(name));
279     } else {
280       return generate_fn(name,key,value);
281     }
282   }
283
284 private:
285   property_maps_type property_maps;
286   generate_fn_type generate_fn;
287 };
288
289 template<typename Key, typename Value>
290 bool
291 put(const std::string& name, dynamic_properties& dp, const Key& key,
292     const Value& value)
293 {
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);
298       return true;
299     }
300   }
301
302   boost::shared_ptr<dynamic_property_map> new_map = dp.generate(name, key, value);
303   if (new_map.get()) {
304     new_map->put(key, value);
305     dp.insert(name, new_map);
306     return true;
307   } else {
308     return false;
309   }
310 }
311
312 #ifndef BOOST_NO_EXPLICIT_FUNCTION_TEMPLATE_ARGUMENTS 
313 template<typename Value, typename Key>
314 Value
315 get(const std::string& name, const dynamic_properties& dp, const Key& key)
316 {
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));
321   }
322
323   BOOST_THROW_EXCEPTION(dynamic_get_failure(name));
324 }
325 #endif
326
327 template<typename Value, typename Key>
328 Value
329 get(const std::string& name, const dynamic_properties& dp, const Key& key, type<Value>)
330 {
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));
335   }
336
337   BOOST_THROW_EXCEPTION(dynamic_get_failure(name));
338 }
339
340 template<typename Key>
341 std::string
342 get(const std::string& name, const dynamic_properties& dp, const Key& key)
343 {
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);
348   }
349
350   BOOST_THROW_EXCEPTION(dynamic_get_failure(name));
351 }
352
353 // The easy way to ignore properties.
354 inline
355 boost::shared_ptr<boost::dynamic_property_map> 
356 ignore_other_properties(const std::string&,
357                         const boost::any&,
358                         const boost::any&) {
359   return boost::shared_ptr<boost::dynamic_property_map>();
360 }
361
362 } // namespace boost
363
364 #endif // DYNAMIC_PROPERTY_MAP_RG09302004_HPP