]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/property_map/include/boost/property_map/dynamic_property_map.hpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / libs / property_map / include / 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 // Trying to work around VC++ problem that seems to relate to having too many
121 // functions named "get"
122 template <typename PMap, typename Key>
123 typename boost::property_traits<PMap>::reference
124 get_wrapper_xxx(const PMap& pmap, const Key& key) {
125 using boost::get;
126 return get(pmap, key);
127 }
128
129 //
130 // dynamic_property_map_adaptor -
131 // property-map adaptor to support runtime polymorphism.
132 template<typename PropertyMap>
133 class dynamic_property_map_adaptor : public dynamic_property_map
134 {
135 typedef typename property_traits<PropertyMap>::key_type key_type;
136 typedef typename property_traits<PropertyMap>::value_type value_type;
137 typedef typename property_traits<PropertyMap>::category category;
138
139 // do_put - overloaded dispatches from the put() member function.
140 // Attempts to "put" to a property map that does not model
141 // WritablePropertyMap result in a runtime exception.
142
143 // in_value must either hold an object of value_type or a string that
144 // can be converted to value_type via iostreams.
145 void do_put(const any& in_key, const any& in_value, mpl::bool_<true>)
146 {
147 using boost::put;
148
149 key_type key_ = any_cast<key_type>(in_key);
150 if (in_value.type() == typeid(value_type)) {
151 put(property_map_, key_, any_cast<value_type>(in_value));
152 } else {
153 // if in_value is an empty string, put a default constructed value_type.
154 std::string v = any_cast<std::string>(in_value);
155 if (v.empty()) {
156 put(property_map_, key_, value_type());
157 } else {
158 put(property_map_, key_, detail::read_value<value_type>(v));
159 }
160 }
161 }
162
163 void do_put(const any&, const any&, mpl::bool_<false>)
164 {
165 BOOST_THROW_EXCEPTION(dynamic_const_put_error());
166 }
167
168 public:
169 explicit dynamic_property_map_adaptor(const PropertyMap& property_map_)
170 : property_map_(property_map_) { }
171
172 virtual boost::any get(const any& key_)
173 {
174 return get_wrapper_xxx(property_map_, any_cast<typename boost::property_traits<PropertyMap>::key_type>(key_));
175 }
176
177 virtual std::string get_string(const any& key_)
178 {
179 std::ostringstream out;
180 out << get_wrapper_xxx(property_map_, any_cast<typename boost::property_traits<PropertyMap>::key_type>(key_));
181 return out.str();
182 }
183
184 virtual void put(const any& in_key, const any& in_value)
185 {
186 do_put(in_key, in_value,
187 mpl::bool_<(is_convertible<category*,
188 writable_property_map_tag*>::value)>());
189 }
190
191 virtual const std::type_info& key() const { return typeid(key_type); }
192 virtual const std::type_info& value() const { return typeid(value_type); }
193
194 PropertyMap& base() { return property_map_; }
195 const PropertyMap& base() const { return property_map_; }
196
197 private:
198 PropertyMap property_map_;
199 };
200
201 } // namespace detail
202
203 //
204 // dynamic_properties -
205 // container for dynamic property maps
206 //
207 struct dynamic_properties
208 {
209 typedef std::multimap<std::string, boost::shared_ptr<dynamic_property_map> >
210 property_maps_type;
211 typedef boost::function3<boost::shared_ptr<dynamic_property_map>,
212 const std::string&,
213 const boost::any&,
214 const boost::any&> generate_fn_type;
215 public:
216
217 typedef property_maps_type::iterator iterator;
218 typedef property_maps_type::const_iterator const_iterator;
219
220 dynamic_properties() : generate_fn() { }
221 dynamic_properties(const generate_fn_type& g) : generate_fn(g) {}
222
223 ~dynamic_properties() {}
224
225 template<typename PropertyMap>
226 dynamic_properties&
227 property(const std::string& name, PropertyMap property_map_)
228 {
229 boost::shared_ptr<dynamic_property_map> pm(
230 boost::static_pointer_cast<dynamic_property_map>(
231 boost::make_shared<detail::dynamic_property_map_adaptor<PropertyMap> >(property_map_)));
232 property_maps.insert(property_maps_type::value_type(name, pm));
233
234 return *this;
235 }
236
237 template<typename PropertyMap>
238 dynamic_properties
239 property(const std::string& name, PropertyMap property_map_) const
240 {
241 dynamic_properties result = *this;
242 result.property(name, property_map_);
243 return result;
244 }
245
246 iterator begin() { return property_maps.begin(); }
247 const_iterator begin() const { return property_maps.begin(); }
248 iterator end() { return property_maps.end(); }
249 const_iterator end() const { return property_maps.end(); }
250
251 iterator lower_bound(const std::string& name)
252 { return property_maps.lower_bound(name); }
253
254 const_iterator lower_bound(const std::string& name) const
255 { return property_maps.lower_bound(name); }
256
257 void
258 insert(const std::string& name, boost::shared_ptr<dynamic_property_map> pm)
259 {
260 property_maps.insert(property_maps_type::value_type(name, pm));
261 }
262
263 template<typename Key, typename Value>
264 boost::shared_ptr<dynamic_property_map>
265 generate(const std::string& name, const Key& key, const Value& value)
266 {
267 if(!generate_fn) {
268 BOOST_THROW_EXCEPTION(property_not_found(name));
269 } else {
270 return generate_fn(name,key,value);
271 }
272 }
273
274 private:
275 property_maps_type property_maps;
276 generate_fn_type generate_fn;
277 };
278
279 template<typename Key, typename Value>
280 bool
281 put(const std::string& name, dynamic_properties& dp, const Key& key,
282 const Value& value)
283 {
284 for (dynamic_properties::iterator i = dp.lower_bound(name);
285 i != dp.end() && i->first == name; ++i) {
286 if (i->second->key() == typeid(key)) {
287 i->second->put(key, value);
288 return true;
289 }
290 }
291
292 boost::shared_ptr<dynamic_property_map> new_map = dp.generate(name, key, value);
293 if (new_map.get()) {
294 new_map->put(key, value);
295 dp.insert(name, new_map);
296 return true;
297 } else {
298 return false;
299 }
300 }
301
302 template<typename Value, typename Key>
303 Value
304 get(const std::string& name, const dynamic_properties& dp, const Key& key)
305 {
306 for (dynamic_properties::const_iterator i = dp.lower_bound(name);
307 i != dp.end() && i->first == name; ++i) {
308 if (i->second->key() == typeid(key))
309 return any_cast<Value>(i->second->get(key));
310 }
311
312 BOOST_THROW_EXCEPTION(dynamic_get_failure(name));
313 }
314
315 template<typename Value, typename Key>
316 Value
317 get(const std::string& name, const dynamic_properties& dp, const Key& key, type<Value>)
318 {
319 for (dynamic_properties::const_iterator i = dp.lower_bound(name);
320 i != dp.end() && i->first == name; ++i) {
321 if (i->second->key() == typeid(key))
322 return any_cast<Value>(i->second->get(key));
323 }
324
325 BOOST_THROW_EXCEPTION(dynamic_get_failure(name));
326 }
327
328 template<typename Key>
329 std::string
330 get(const std::string& name, const dynamic_properties& dp, const Key& key)
331 {
332 for (dynamic_properties::const_iterator i = dp.lower_bound(name);
333 i != dp.end() && i->first == name; ++i) {
334 if (i->second->key() == typeid(key))
335 return i->second->get_string(key);
336 }
337
338 BOOST_THROW_EXCEPTION(dynamic_get_failure(name));
339 }
340
341 // The easy way to ignore properties.
342 inline
343 boost::shared_ptr<boost::dynamic_property_map>
344 ignore_other_properties(const std::string&,
345 const boost::any&,
346 const boost::any&) {
347 return boost::shared_ptr<boost::dynamic_property_map>();
348 }
349
350 } // namespace boost
351
352 #endif // DYNAMIC_PROPERTY_MAP_RG09302004_HPP