File indexing completed on 2025-01-18 09:50:16
0001 #ifndef BOOST_PROPERTY_MAP_DYNAMIC_PROPERTY_MAP_HPP
0002 #define BOOST_PROPERTY_MAP_DYNAMIC_PROPERTY_MAP_HPP
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020 #include <boost/config.hpp>
0021 #include <boost/throw_exception.hpp>
0022 #include <boost/property_map/property_map.hpp>
0023 #include <boost/lexical_cast.hpp>
0024 #include <boost/any.hpp>
0025 #include <boost/function/function3.hpp>
0026 #include <boost/type_traits/is_convertible.hpp>
0027 #include <boost/mpl/bool.hpp>
0028 #include <boost/type.hpp>
0029 #include <boost/type_index.hpp>
0030 #include <boost/smart_ptr.hpp>
0031 #include <exception>
0032 #include <map>
0033 #include <sstream>
0034 #include <stdexcept>
0035 #include <string>
0036 #include <typeinfo>
0037
0038 namespace boost {
0039
0040 namespace detail {
0041
0042
0043
0044
0045 template<typename Value>
0046 inline Value read_value(const std::string& value)
0047 { return boost::lexical_cast<Value>(value); }
0048
0049 template<>
0050 inline std::string read_value<std::string>(const std::string& value)
0051 { return value; }
0052
0053 }
0054
0055
0056
0057
0058 class dynamic_property_map
0059 {
0060 public:
0061 virtual ~dynamic_property_map() { }
0062
0063 virtual boost::any get(const any& key) = 0;
0064 virtual std::string get_string(const any& key) = 0;
0065 virtual void put(const any& key, const any& value) = 0;
0066 virtual const std::type_info& key() const = 0;
0067 virtual const std::type_info& value() const = 0;
0068 };
0069
0070
0071
0072
0073
0074
0075 struct dynamic_property_exception : public std::exception {
0076 ~dynamic_property_exception() throw() BOOST_OVERRIDE {}
0077 const char* what() const throw() BOOST_OVERRIDE = 0;
0078 };
0079
0080 struct property_not_found : public dynamic_property_exception {
0081 std::string property;
0082 mutable std::string statement;
0083 property_not_found(const std::string& property) : property(property) {}
0084 ~property_not_found() throw() BOOST_OVERRIDE {}
0085
0086 const char* what() const throw() BOOST_OVERRIDE {
0087 if(statement.empty())
0088 statement =
0089 std::string("Property not found: ") + property + ".";
0090
0091 return statement.c_str();
0092 }
0093 };
0094
0095 struct dynamic_get_failure : public dynamic_property_exception {
0096 std::string property;
0097 mutable std::string statement;
0098 dynamic_get_failure(const std::string& property) : property(property) {}
0099 ~dynamic_get_failure() throw() BOOST_OVERRIDE {}
0100
0101 const char* what() const throw() BOOST_OVERRIDE {
0102 if(statement.empty())
0103 statement =
0104 std::string(
0105 "dynamic property get cannot retrieve value for property: ")
0106 + property + ".";
0107
0108 return statement.c_str();
0109 }
0110 };
0111
0112 struct dynamic_const_put_error : public dynamic_property_exception {
0113 ~dynamic_const_put_error() throw() BOOST_OVERRIDE {}
0114
0115 const char* what() const throw() BOOST_OVERRIDE {
0116 return "Attempt to put a value into a const property map: ";
0117 }
0118 };
0119
0120
0121 namespace detail {
0122
0123
0124
0125 template <typename PMap, typename Key>
0126 typename boost::property_traits<PMap>::reference
0127 get_wrapper_xxx(const PMap& pmap, const Key& key) {
0128 using boost::get;
0129 return get(pmap, key);
0130 }
0131
0132
0133
0134
0135 template<typename PropertyMap>
0136 class dynamic_property_map_adaptor : public dynamic_property_map
0137 {
0138 typedef typename property_traits<PropertyMap>::key_type key_type;
0139 typedef typename property_traits<PropertyMap>::value_type value_type;
0140 typedef typename property_traits<PropertyMap>::category category;
0141
0142
0143
0144
0145
0146
0147
0148 void do_put(const any& in_key, const any& in_value, mpl::bool_<true>)
0149 {
0150 using boost::put;
0151
0152 key_type key_ = any_cast<key_type>(in_key);
0153 if (in_value.type() == boost::typeindex::type_id<value_type>()) {
0154 put(property_map_, key_, any_cast<value_type>(in_value));
0155 } else {
0156
0157 std::string v = any_cast<std::string>(in_value);
0158 if (v.empty()) {
0159 put(property_map_, key_, value_type());
0160 } else {
0161 put(property_map_, key_, detail::read_value<value_type>(v));
0162 }
0163 }
0164 }
0165
0166 void do_put(const any&, const any&, mpl::bool_<false>)
0167 {
0168 BOOST_THROW_EXCEPTION(dynamic_const_put_error());
0169 }
0170
0171 public:
0172 explicit dynamic_property_map_adaptor(const PropertyMap& property_map_)
0173 : property_map_(property_map_) { }
0174
0175 boost::any get(const any& key_) BOOST_OVERRIDE
0176 {
0177 return get_wrapper_xxx(property_map_, any_cast<typename boost::property_traits<PropertyMap>::key_type>(key_));
0178 }
0179
0180 std::string get_string(const any& key_) BOOST_OVERRIDE
0181 {
0182 std::ostringstream out;
0183 out << get_wrapper_xxx(property_map_, any_cast<typename boost::property_traits<PropertyMap>::key_type>(key_));
0184 return out.str();
0185 }
0186
0187 void put(const any& in_key, const any& in_value) BOOST_OVERRIDE
0188 {
0189 do_put(in_key, in_value,
0190 mpl::bool_<(is_convertible<category*,
0191 writable_property_map_tag*>::value)>());
0192 }
0193
0194 const std::type_info& key() const BOOST_OVERRIDE { return typeid(key_type); }
0195 const std::type_info& value() const BOOST_OVERRIDE { return typeid(value_type); }
0196
0197 PropertyMap& base() { return property_map_; }
0198 const PropertyMap& base() const { return property_map_; }
0199
0200 private:
0201 PropertyMap property_map_;
0202 };
0203
0204 }
0205
0206
0207
0208
0209
0210 struct dynamic_properties
0211 {
0212 typedef std::multimap<std::string, boost::shared_ptr<dynamic_property_map> >
0213 property_maps_type;
0214 typedef boost::function3<boost::shared_ptr<dynamic_property_map>,
0215 const std::string&,
0216 const boost::any&,
0217 const boost::any&> generate_fn_type;
0218 public:
0219
0220 typedef property_maps_type::iterator iterator;
0221 typedef property_maps_type::const_iterator const_iterator;
0222
0223 dynamic_properties() : generate_fn() { }
0224 dynamic_properties(const generate_fn_type& g) : generate_fn(g) {}
0225
0226 ~dynamic_properties() {}
0227
0228 template<typename PropertyMap>
0229 dynamic_properties&
0230 property(const std::string& name, PropertyMap property_map_)
0231 {
0232 boost::shared_ptr<dynamic_property_map> pm(
0233 boost::static_pointer_cast<dynamic_property_map>(
0234 boost::make_shared<detail::dynamic_property_map_adaptor<PropertyMap> >(property_map_)));
0235 property_maps.insert(property_maps_type::value_type(name, pm));
0236
0237 return *this;
0238 }
0239
0240 template<typename PropertyMap>
0241 dynamic_properties
0242 property(const std::string& name, PropertyMap property_map_) const
0243 {
0244 dynamic_properties result = *this;
0245 result.property(name, property_map_);
0246 return result;
0247 }
0248
0249 iterator begin() { return property_maps.begin(); }
0250 const_iterator begin() const { return property_maps.begin(); }
0251 iterator end() { return property_maps.end(); }
0252 const_iterator end() const { return property_maps.end(); }
0253
0254 iterator lower_bound(const std::string& name)
0255 { return property_maps.lower_bound(name); }
0256
0257 const_iterator lower_bound(const std::string& name) const
0258 { return property_maps.lower_bound(name); }
0259
0260 void
0261 insert(const std::string& name, boost::shared_ptr<dynamic_property_map> pm)
0262 {
0263 property_maps.insert(property_maps_type::value_type(name, pm));
0264 }
0265
0266 template<typename Key, typename Value>
0267 boost::shared_ptr<dynamic_property_map>
0268 generate(const std::string& name, const Key& key, const Value& value)
0269 {
0270 if(!generate_fn) {
0271 BOOST_THROW_EXCEPTION(property_not_found(name));
0272 } else {
0273 return generate_fn(name,key,value);
0274 }
0275 }
0276
0277 private:
0278 property_maps_type property_maps;
0279 generate_fn_type generate_fn;
0280 };
0281
0282 template<typename Key, typename Value>
0283 bool
0284 put(const std::string& name, dynamic_properties& dp, const Key& key,
0285 const Value& value)
0286 {
0287 for (dynamic_properties::iterator i = dp.lower_bound(name);
0288 i != dp.end() && i->first == name; ++i) {
0289 if (i->second->key() == typeid(key)) {
0290 i->second->put(key, value);
0291 return true;
0292 }
0293 }
0294
0295 boost::shared_ptr<dynamic_property_map> new_map = dp.generate(name, key, value);
0296 if (new_map.get()) {
0297 new_map->put(key, value);
0298 dp.insert(name, new_map);
0299 return true;
0300 } else {
0301 return false;
0302 }
0303 }
0304
0305 template<typename Value, typename Key>
0306 Value
0307 get(const std::string& name, const dynamic_properties& dp, const Key& key)
0308 {
0309 for (dynamic_properties::const_iterator i = dp.lower_bound(name);
0310 i != dp.end() && i->first == name; ++i) {
0311 if (i->second->key() == typeid(key))
0312 return any_cast<Value>(i->second->get(key));
0313 }
0314
0315 BOOST_THROW_EXCEPTION(dynamic_get_failure(name));
0316 }
0317
0318 template<typename Value, typename Key>
0319 Value
0320 get(const std::string& name, const dynamic_properties& dp, const Key& key, type<Value>)
0321 {
0322 for (dynamic_properties::const_iterator i = dp.lower_bound(name);
0323 i != dp.end() && i->first == name; ++i) {
0324 if (i->second->key() == typeid(key))
0325 return any_cast<Value>(i->second->get(key));
0326 }
0327
0328 BOOST_THROW_EXCEPTION(dynamic_get_failure(name));
0329 }
0330
0331 template<typename Key>
0332 std::string
0333 get(const std::string& name, const dynamic_properties& dp, const Key& key)
0334 {
0335 for (dynamic_properties::const_iterator i = dp.lower_bound(name);
0336 i != dp.end() && i->first == name; ++i) {
0337 if (i->second->key() == typeid(key))
0338 return i->second->get_string(key);
0339 }
0340
0341 BOOST_THROW_EXCEPTION(dynamic_get_failure(name));
0342 }
0343
0344
0345 inline
0346 boost::shared_ptr<boost::dynamic_property_map>
0347 ignore_other_properties(const std::string&,
0348 const boost::any&,
0349 const boost::any&) {
0350 return boost::shared_ptr<boost::dynamic_property_map>();
0351 }
0352
0353 }
0354
0355 #endif