dynamic_property_map.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. #ifndef BOOST_PROPERTY_MAP_DYNAMIC_PROPERTY_MAP_HPP
  2. #define BOOST_PROPERTY_MAP_DYNAMIC_PROPERTY_MAP_HPP
  3. // Copyright 2004-5 The Trustees of Indiana University.
  4. // Use, modification and distribution is subject to the Boost Software
  5. // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. // dynamic_property_map.hpp -
  8. // Support for runtime-polymorphic property maps. This header is factored
  9. // out of Doug Gregor's routines for reading GraphML files for use in reading
  10. // GraphViz graph files.
  11. // Authors: Doug Gregor
  12. // Ronald Garcia
  13. //
  14. #include <boost/config.hpp>
  15. #include <boost/throw_exception.hpp>
  16. #include <boost/property_map/property_map.hpp>
  17. #include <boost/lexical_cast.hpp>
  18. #include <boost/any.hpp>
  19. #include <boost/function/function3.hpp>
  20. #include <boost/type_traits/is_convertible.hpp>
  21. #include <boost/mpl/bool.hpp>
  22. #include <boost/type.hpp>
  23. #include <boost/type_index.hpp>
  24. #include <boost/smart_ptr.hpp>
  25. #include <exception>
  26. #include <map>
  27. #include <sstream>
  28. #include <stdexcept>
  29. #include <string>
  30. #include <typeinfo>
  31. namespace boost {
  32. namespace detail {
  33. // read_value -
  34. // A wrapper around lexical_cast, which does not behave as
  35. // desired for std::string types.
  36. template<typename Value>
  37. inline Value read_value(const std::string& value)
  38. { return boost::lexical_cast<Value>(value); }
  39. template<>
  40. inline std::string read_value<std::string>(const std::string& value)
  41. { return value; }
  42. }
  43. // dynamic_property_map -
  44. // This interface supports polymorphic manipulation of property maps.
  45. class dynamic_property_map
  46. {
  47. public:
  48. virtual ~dynamic_property_map() { }
  49. virtual boost::any get(const any& key) = 0;
  50. virtual std::string get_string(const any& key) = 0;
  51. virtual void put(const any& key, const any& value) = 0;
  52. virtual const std::type_info& key() const = 0;
  53. virtual const std::type_info& value() const = 0;
  54. };
  55. //////////////////////////////////////////////////////////////////////
  56. // Property map exceptions
  57. //////////////////////////////////////////////////////////////////////
  58. struct dynamic_property_exception : public std::exception {
  59. ~dynamic_property_exception() throw() BOOST_OVERRIDE {}
  60. const char* what() const throw() BOOST_OVERRIDE = 0;
  61. };
  62. struct property_not_found : public dynamic_property_exception {
  63. std::string property;
  64. mutable std::string statement;
  65. property_not_found(const std::string& property) : property(property) {}
  66. ~property_not_found() throw() BOOST_OVERRIDE {}
  67. const char* what() const throw() BOOST_OVERRIDE {
  68. if(statement.empty())
  69. statement =
  70. std::string("Property not found: ") + property + ".";
  71. return statement.c_str();
  72. }
  73. };
  74. struct dynamic_get_failure : public dynamic_property_exception {
  75. std::string property;
  76. mutable std::string statement;
  77. dynamic_get_failure(const std::string& property) : property(property) {}
  78. ~dynamic_get_failure() throw() BOOST_OVERRIDE {}
  79. const char* what() const throw() BOOST_OVERRIDE {
  80. if(statement.empty())
  81. statement =
  82. std::string(
  83. "dynamic property get cannot retrieve value for property: ")
  84. + property + ".";
  85. return statement.c_str();
  86. }
  87. };
  88. struct dynamic_const_put_error : public dynamic_property_exception {
  89. ~dynamic_const_put_error() throw() BOOST_OVERRIDE {}
  90. const char* what() const throw() BOOST_OVERRIDE {
  91. return "Attempt to put a value into a const property map: ";
  92. }
  93. };
  94. namespace detail {
  95. // Trying to work around VC++ problem that seems to relate to having too many
  96. // functions named "get"
  97. template <typename PMap, typename Key>
  98. typename boost::property_traits<PMap>::reference
  99. get_wrapper_xxx(const PMap& pmap, const Key& key) {
  100. using boost::get;
  101. return get(pmap, key);
  102. }
  103. //
  104. // dynamic_property_map_adaptor -
  105. // property-map adaptor to support runtime polymorphism.
  106. template<typename PropertyMap>
  107. class dynamic_property_map_adaptor : public dynamic_property_map
  108. {
  109. typedef typename property_traits<PropertyMap>::key_type key_type;
  110. typedef typename property_traits<PropertyMap>::value_type value_type;
  111. typedef typename property_traits<PropertyMap>::category category;
  112. // do_put - overloaded dispatches from the put() member function.
  113. // Attempts to "put" to a property map that does not model
  114. // WritablePropertyMap result in a runtime exception.
  115. // in_value must either hold an object of value_type or a string that
  116. // can be converted to value_type via iostreams.
  117. void do_put(const any& in_key, const any& in_value, mpl::bool_<true>)
  118. {
  119. using boost::put;
  120. key_type key_ = any_cast<key_type>(in_key);
  121. if (in_value.type() == boost::typeindex::type_id<value_type>()) {
  122. put(property_map_, key_, any_cast<value_type>(in_value));
  123. } else {
  124. // if in_value is an empty string, put a default constructed value_type.
  125. std::string v = any_cast<std::string>(in_value);
  126. if (v.empty()) {
  127. put(property_map_, key_, value_type());
  128. } else {
  129. put(property_map_, key_, detail::read_value<value_type>(v));
  130. }
  131. }
  132. }
  133. void do_put(const any&, const any&, mpl::bool_<false>)
  134. {
  135. BOOST_THROW_EXCEPTION(dynamic_const_put_error());
  136. }
  137. public:
  138. explicit dynamic_property_map_adaptor(const PropertyMap& property_map_)
  139. : property_map_(property_map_) { }
  140. boost::any get(const any& key_) BOOST_OVERRIDE
  141. {
  142. return get_wrapper_xxx(property_map_, any_cast<typename boost::property_traits<PropertyMap>::key_type>(key_));
  143. }
  144. std::string get_string(const any& key_) BOOST_OVERRIDE
  145. {
  146. std::ostringstream out;
  147. out << get_wrapper_xxx(property_map_, any_cast<typename boost::property_traits<PropertyMap>::key_type>(key_));
  148. return out.str();
  149. }
  150. void put(const any& in_key, const any& in_value) BOOST_OVERRIDE
  151. {
  152. do_put(in_key, in_value,
  153. mpl::bool_<(is_convertible<category*,
  154. writable_property_map_tag*>::value)>());
  155. }
  156. const std::type_info& key() const BOOST_OVERRIDE { return typeid(key_type); }
  157. const std::type_info& value() const BOOST_OVERRIDE { return typeid(value_type); }
  158. PropertyMap& base() { return property_map_; }
  159. const PropertyMap& base() const { return property_map_; }
  160. private:
  161. PropertyMap property_map_;
  162. };
  163. } // namespace detail
  164. //
  165. // dynamic_properties -
  166. // container for dynamic property maps
  167. //
  168. struct dynamic_properties
  169. {
  170. typedef std::multimap<std::string, boost::shared_ptr<dynamic_property_map> >
  171. property_maps_type;
  172. typedef boost::function3<boost::shared_ptr<dynamic_property_map>,
  173. const std::string&,
  174. const boost::any&,
  175. const boost::any&> generate_fn_type;
  176. public:
  177. typedef property_maps_type::iterator iterator;
  178. typedef property_maps_type::const_iterator const_iterator;
  179. dynamic_properties() : generate_fn() { }
  180. dynamic_properties(const generate_fn_type& g) : generate_fn(g) {}
  181. ~dynamic_properties() {}
  182. template<typename PropertyMap>
  183. dynamic_properties&
  184. property(const std::string& name, PropertyMap property_map_)
  185. {
  186. boost::shared_ptr<dynamic_property_map> pm(
  187. boost::static_pointer_cast<dynamic_property_map>(
  188. boost::make_shared<detail::dynamic_property_map_adaptor<PropertyMap> >(property_map_)));
  189. property_maps.insert(property_maps_type::value_type(name, pm));
  190. return *this;
  191. }
  192. template<typename PropertyMap>
  193. dynamic_properties
  194. property(const std::string& name, PropertyMap property_map_) const
  195. {
  196. dynamic_properties result = *this;
  197. result.property(name, property_map_);
  198. return result;
  199. }
  200. iterator begin() { return property_maps.begin(); }
  201. const_iterator begin() const { return property_maps.begin(); }
  202. iterator end() { return property_maps.end(); }
  203. const_iterator end() const { return property_maps.end(); }
  204. iterator lower_bound(const std::string& name)
  205. { return property_maps.lower_bound(name); }
  206. const_iterator lower_bound(const std::string& name) const
  207. { return property_maps.lower_bound(name); }
  208. void
  209. insert(const std::string& name, boost::shared_ptr<dynamic_property_map> pm)
  210. {
  211. property_maps.insert(property_maps_type::value_type(name, pm));
  212. }
  213. template<typename Key, typename Value>
  214. boost::shared_ptr<dynamic_property_map>
  215. generate(const std::string& name, const Key& key, const Value& value)
  216. {
  217. if(!generate_fn) {
  218. BOOST_THROW_EXCEPTION(property_not_found(name));
  219. } else {
  220. return generate_fn(name,key,value);
  221. }
  222. }
  223. private:
  224. property_maps_type property_maps;
  225. generate_fn_type generate_fn;
  226. };
  227. template<typename Key, typename Value>
  228. bool
  229. put(const std::string& name, dynamic_properties& dp, const Key& key,
  230. const Value& value)
  231. {
  232. for (dynamic_properties::iterator i = dp.lower_bound(name);
  233. i != dp.end() && i->first == name; ++i) {
  234. if (i->second->key() == typeid(key)) {
  235. i->second->put(key, value);
  236. return true;
  237. }
  238. }
  239. boost::shared_ptr<dynamic_property_map> new_map = dp.generate(name, key, value);
  240. if (new_map.get()) {
  241. new_map->put(key, value);
  242. dp.insert(name, new_map);
  243. return true;
  244. } else {
  245. return false;
  246. }
  247. }
  248. template<typename Value, typename Key>
  249. Value
  250. get(const std::string& name, const dynamic_properties& dp, const Key& key)
  251. {
  252. for (dynamic_properties::const_iterator i = dp.lower_bound(name);
  253. i != dp.end() && i->first == name; ++i) {
  254. if (i->second->key() == typeid(key))
  255. return any_cast<Value>(i->second->get(key));
  256. }
  257. BOOST_THROW_EXCEPTION(dynamic_get_failure(name));
  258. }
  259. template<typename Value, typename Key>
  260. Value
  261. get(const std::string& name, const dynamic_properties& dp, const Key& key, type<Value>)
  262. {
  263. for (dynamic_properties::const_iterator i = dp.lower_bound(name);
  264. i != dp.end() && i->first == name; ++i) {
  265. if (i->second->key() == typeid(key))
  266. return any_cast<Value>(i->second->get(key));
  267. }
  268. BOOST_THROW_EXCEPTION(dynamic_get_failure(name));
  269. }
  270. template<typename Key>
  271. std::string
  272. get(const std::string& name, const dynamic_properties& dp, const Key& key)
  273. {
  274. for (dynamic_properties::const_iterator i = dp.lower_bound(name);
  275. i != dp.end() && i->first == name; ++i) {
  276. if (i->second->key() == typeid(key))
  277. return i->second->get_string(key);
  278. }
  279. BOOST_THROW_EXCEPTION(dynamic_get_failure(name));
  280. }
  281. // The easy way to ignore properties.
  282. inline
  283. boost::shared_ptr<boost::dynamic_property_map>
  284. ignore_other_properties(const std::string&,
  285. const boost::any&,
  286. const boost::any&) {
  287. return boost::shared_ptr<boost::dynamic_property_map>();
  288. }
  289. } // namespace boost
  290. #endif // BOOST_PROPERTY_MAP_DYNAMIC_PROPERTY_MAP_HPP