key_value.hpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. /* Copyright 2006-2024 Joaquin M Lopez Munoz.
  2. * Distributed under the Boost Software License, Version 1.0.
  3. * (See accompanying file LICENSE_1_0.txt or copy at
  4. * http://www.boost.org/LICENSE_1_0.txt)
  5. *
  6. * See http://www.boost.org/libs/flyweight for library home page.
  7. */
  8. #ifndef BOOST_FLYWEIGHT_KEY_VALUE_HPP
  9. #define BOOST_FLYWEIGHT_KEY_VALUE_HPP
  10. #if defined(_MSC_VER)
  11. #pragma once
  12. #endif
  13. #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
  14. #include <boost/assert.hpp>
  15. #include <boost/config/workaround.hpp>
  16. #include <boost/flyweight/detail/perfect_fwd.hpp>
  17. #include <boost/flyweight/detail/value_tag.hpp>
  18. #include <boost/flyweight/key_value_fwd.hpp>
  19. #include <boost/mpl/assert.hpp>
  20. #include <boost/type_traits/aligned_storage.hpp>
  21. #include <boost/type_traits/alignment_of.hpp>
  22. #include <boost/type_traits/declval.hpp>
  23. #include <boost/type_traits/is_same.hpp>
  24. #include <new>
  25. /* key-value policy: flywewight lookup is based on Key, which also serves
  26. * to construct Value only when needed (new factory entry). key_value is
  27. * used to avoid the construction of temporary values when such construction
  28. * is expensive.
  29. * Optionally, KeyFromValue extracts the key from a value, which
  30. * is needed in expressions like this:
  31. *
  32. * typedef flyweight<key_value<Key,Value> > fw_t;
  33. * fw_t fw;
  34. * Value v;
  35. * fw=v; // no key explicitly given
  36. *
  37. * If no KeyFromValue is provided, this latter expression fails to compile.
  38. */
  39. namespace boost{
  40. namespace flyweights{
  41. namespace detail{
  42. template<typename Key,typename Value,typename KeyFromValue>
  43. struct variant_key_value:value_marker
  44. {
  45. typedef Key key_type;
  46. typedef Value value_type;
  47. class rep_type
  48. {
  49. public:
  50. /* template ctors */
  51. #define BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY(args) \
  52. :value_cted(false) \
  53. { \
  54. new(key_ptr())key_type(BOOST_FLYWEIGHT_FORWARD(args)); \
  55. }
  56. BOOST_FLYWEIGHT_PERFECT_FWD(
  57. explicit rep_type,
  58. BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY)
  59. #undef BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY
  60. rep_type(const rep_type& x):value_cted(false)
  61. {
  62. if(!x.value_cted)new(key_ptr())key_type(*x.key_ptr());
  63. else new(key_ptr())key_type(key_from_value(*x.value_ptr()));
  64. }
  65. rep_type(const value_type& x):value_cted(false)
  66. {
  67. new(key_ptr())key_type(key_from_value(x));
  68. }
  69. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  70. rep_type(rep_type&& x):value_cted(false)
  71. {
  72. if(!x.value_cted)new(key_ptr())key_type(std::move(*x.key_ptr()));
  73. else new(key_ptr())key_type(key_from_value(*x.value_ptr()));
  74. }
  75. rep_type(value_type&& x):value_cted(false)
  76. {
  77. new(key_ptr())key_type(key_from_value(x));
  78. }
  79. #endif
  80. ~rep_type()
  81. {
  82. if(value_cted)value_ptr()->~value_type();
  83. else key_ptr()->~key_type();
  84. }
  85. operator const key_type&()const
  86. BOOST_NOEXCEPT_IF(noexcept(
  87. boost::declval<KeyFromValue>()(boost::declval<const value_type&>())))
  88. {
  89. if(value_cted)return key_from_value(*value_ptr());
  90. else return *key_ptr();
  91. }
  92. operator const value_type&()const
  93. {
  94. BOOST_ASSERT(value_cted);
  95. return *value_ptr();
  96. }
  97. private:
  98. friend struct variant_key_value;
  99. key_type* key_ptr()const
  100. {
  101. return static_cast<key_type*>(static_cast<void*>(&key_spc));
  102. }
  103. value_type* value_ptr()const
  104. {
  105. return static_cast<value_type*>(static_cast<void*>(&value_spc));
  106. }
  107. static const key_type& key_from_value(const value_type& x)
  108. {
  109. KeyFromValue k;
  110. return k(x);
  111. }
  112. void key_construct_value()const
  113. {
  114. if(!value_cted){
  115. new(value_ptr())value_type(*key_ptr());
  116. key_ptr()->~key_type();
  117. value_cted=true;
  118. }
  119. }
  120. void copy_construct_value(const value_type& x)const
  121. {
  122. if(!value_cted){
  123. new(value_ptr())value_type(x);
  124. key_ptr()->~key_type();
  125. value_cted=true;
  126. }
  127. }
  128. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  129. void move_construct_value(value_type&& x)const
  130. {
  131. if(!value_cted){
  132. new(value_ptr())value_type(std::move(x));
  133. key_ptr()->~key_type();
  134. value_cted=true;
  135. }
  136. }
  137. #endif
  138. mutable typename boost::aligned_storage<
  139. sizeof(key_type),
  140. boost::alignment_of<key_type>::value
  141. >::type key_spc;
  142. mutable typename boost::aligned_storage<
  143. sizeof(value_type),
  144. boost::alignment_of<value_type>::value
  145. >::type value_spc;
  146. mutable bool value_cted;
  147. };
  148. static void key_construct_value(const rep_type& r)
  149. {
  150. r.key_construct_value();
  151. }
  152. static void copy_construct_value(const rep_type& r,const value_type& x)
  153. {
  154. r.copy_construct_value(x);
  155. }
  156. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  157. static void move_construct_value(const rep_type& r,value_type&& x)
  158. {
  159. r.move_construct_value(std::move(x));
  160. }
  161. #endif
  162. };
  163. template<typename Key,typename Value>
  164. struct product_key_value:value_marker
  165. {
  166. typedef Key key_type;
  167. typedef Value value_type;
  168. class rep_type
  169. {
  170. public:
  171. /* template ctors */
  172. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)&&\
  173. !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)&&\
  174. BOOST_WORKAROUND(__GNUC__,<=4)&&(__GNUC__<4||__GNUC_MINOR__<=4)
  175. /* GCC 4.4.2 (and probably prior) bug: the default ctor generated by the
  176. * variadic temmplate ctor below fails to value-initialize key.
  177. */
  178. rep_type():key(),value_cted(false){}
  179. #endif
  180. #define BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY(args) \
  181. :key(BOOST_FLYWEIGHT_FORWARD(args)),value_cted(false){}
  182. BOOST_FLYWEIGHT_PERFECT_FWD(
  183. explicit rep_type,
  184. BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY)
  185. #undef BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY
  186. rep_type(const rep_type& x):key(x.key),value_cted(false){}
  187. rep_type(const value_type&):key(no_key_from_value_failure()){}
  188. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  189. rep_type(rep_type&& x):key(std::move(x.key)),value_cted(false){}
  190. rep_type(value_type&&):key(no_key_from_value_failure()){}
  191. #endif
  192. ~rep_type()
  193. {
  194. if(value_cted)value_ptr()->~value_type();
  195. }
  196. operator const key_type&()const BOOST_NOEXCEPT{return key;}
  197. operator const value_type&()const
  198. {
  199. BOOST_ASSERT(value_cted);
  200. return *value_ptr();
  201. }
  202. private:
  203. friend struct product_key_value;
  204. value_type* value_ptr()const
  205. {
  206. return static_cast<value_type*>(static_cast<void*>(&value_spc));
  207. }
  208. struct no_key_from_value_failure
  209. {
  210. BOOST_MPL_ASSERT_MSG(
  211. false,
  212. NO_KEY_FROM_VALUE_CONVERSION_PROVIDED,
  213. (key_type,value_type));
  214. operator const key_type&()const;
  215. };
  216. void key_construct_value()const
  217. {
  218. if(!value_cted){
  219. new(value_ptr())value_type(key);
  220. value_cted=true;
  221. }
  222. }
  223. key_type key;
  224. mutable typename boost::aligned_storage<
  225. sizeof(value_type),
  226. boost::alignment_of<value_type>::value
  227. >::type value_spc;
  228. mutable bool value_cted;
  229. };
  230. static void key_construct_value(const rep_type& r)
  231. {
  232. r.key_construct_value();
  233. }
  234. /* [copy|move]_construct_value() can't really ever be called, provided to
  235. * avoid compile errors (it is the no_key_from_value_failure compile error
  236. * we want to appear in these cases).
  237. */
  238. static void copy_construct_value(const rep_type&,const value_type&){}
  239. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  240. static void move_construct_value(const rep_type&,value_type&&){}
  241. #endif
  242. };
  243. } /* namespace flyweights::detail */
  244. template<typename Key,typename Value,typename KeyFromValue>
  245. struct key_value:
  246. mpl::if_<
  247. is_same<KeyFromValue,no_key_from_value>,
  248. detail::product_key_value<Key,Value>,
  249. detail::variant_key_value<Key,Value,KeyFromValue>
  250. >::type
  251. {};
  252. } /* namespace flyweights */
  253. } /* namespace boost */
  254. #endif