key_value.hpp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /* Copyright 2006-2018 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/detail/workaround.hpp>
  15. #include <boost/flyweight/detail/perfect_fwd.hpp>
  16. #include <boost/flyweight/detail/value_tag.hpp>
  17. #include <boost/flyweight/key_value_fwd.hpp>
  18. #include <boost/mpl/assert.hpp>
  19. #include <boost/type_traits/aligned_storage.hpp>
  20. #include <boost/type_traits/alignment_of.hpp>
  21. #include <boost/type_traits/is_same.hpp>
  22. #include <new>
  23. /* key-value policy: flywewight lookup is based on Key, which also serves
  24. * to construct Value only when needed (new factory entry). key_value is
  25. * used to avoid the construction of temporary values when such construction
  26. * is expensive.
  27. * Optionally, KeyFromValue extracts the key from a value, which
  28. * is needed in expressions like this:
  29. *
  30. * typedef flyweight<key_value<Key,Value> > fw_t;
  31. * fw_t fw;
  32. * Value v;
  33. * fw=v; // no key explicitly given
  34. *
  35. * If no KeyFromValue is provided, this latter expression fails to compile.
  36. */
  37. namespace boost{
  38. namespace flyweights{
  39. namespace detail{
  40. template<typename Key,typename Value,typename KeyFromValue>
  41. struct optimized_key_value:value_marker
  42. {
  43. typedef Key key_type;
  44. typedef Value value_type;
  45. class rep_type
  46. {
  47. public:
  48. /* template ctors */
  49. #define BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY(args) \
  50. :value_ptr(0) \
  51. { \
  52. new(spc_ptr())key_type(BOOST_FLYWEIGHT_FORWARD(args)); \
  53. }
  54. BOOST_FLYWEIGHT_PERFECT_FWD(
  55. explicit rep_type,
  56. BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY)
  57. #undef BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY
  58. rep_type(const rep_type& x):value_ptr(x.value_ptr)
  59. {
  60. if(!x.value_ptr)new(key_ptr())key_type(*x.key_ptr());
  61. }
  62. rep_type(const value_type& x):value_ptr(&x){}
  63. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  64. rep_type(rep_type&& x):value_ptr(x.value_ptr)
  65. {
  66. if(!x.value_ptr)new(key_ptr())key_type(std::move(*x.key_ptr()));
  67. }
  68. rep_type(value_type&& x):value_ptr(&x){}
  69. #endif
  70. ~rep_type()
  71. {
  72. if(!value_ptr) key_ptr()->~key_type();
  73. else if(value_cted())value_ptr->~value_type();
  74. }
  75. operator const key_type&()const
  76. {
  77. if(value_ptr)return key_from_value(*value_ptr);
  78. else return *key_ptr();
  79. }
  80. operator const value_type&()const
  81. {
  82. /* This is always called after construct_value() or copy_value(),
  83. * so we access spc directly rather than through value_ptr to
  84. * save us an indirection.
  85. */
  86. return *static_cast<value_type*>(spc_ptr());
  87. }
  88. private:
  89. friend struct optimized_key_value;
  90. void* spc_ptr()const{return static_cast<void*>(&spc);}
  91. bool value_cted()const{return value_ptr==spc_ptr();}
  92. key_type* key_ptr()const
  93. {
  94. return static_cast<key_type*>(static_cast<void*>(&spc));
  95. }
  96. static const key_type& key_from_value(const value_type& x)
  97. {
  98. KeyFromValue k;
  99. return k(x);
  100. }
  101. void construct_value()const
  102. {
  103. if(!value_cted()){
  104. /* value_ptr must be ==0, oherwise copy_value would have been called */
  105. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  106. key_type k(std::move(*key_ptr()));
  107. #else
  108. key_type k(*key_ptr());
  109. #endif
  110. key_ptr()->~key_type();
  111. value_ptr= /* guarantees key won't be re-dted at ~rep_type if the */
  112. static_cast<value_type*>(spc_ptr())+1; /* next statement throws */
  113. value_ptr=new(spc_ptr())value_type(k);
  114. }
  115. }
  116. void copy_value()const
  117. {
  118. if(!value_cted())value_ptr=new(spc_ptr())value_type(*value_ptr);
  119. }
  120. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  121. void move_value()const
  122. {
  123. if(!value_cted())value_ptr=
  124. new(spc_ptr())value_type(std::move(const_cast<value_type&>(*value_ptr)));
  125. }
  126. #endif
  127. mutable typename boost::aligned_storage<
  128. (sizeof(key_type)>sizeof(value_type))?
  129. sizeof(key_type):sizeof(value_type),
  130. (boost::alignment_of<key_type>::value >
  131. boost::alignment_of<value_type>::value)?
  132. boost::alignment_of<key_type>::value:
  133. boost::alignment_of<value_type>::value
  134. >::type spc;
  135. mutable const value_type* value_ptr;
  136. };
  137. static void construct_value(const rep_type& r)
  138. {
  139. r.construct_value();
  140. }
  141. static void copy_value(const rep_type& r)
  142. {
  143. r.copy_value();
  144. }
  145. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  146. static void move_value(const rep_type& r)
  147. {
  148. r.move_value();
  149. }
  150. #endif
  151. };
  152. template<typename Key,typename Value>
  153. struct regular_key_value:value_marker
  154. {
  155. typedef Key key_type;
  156. typedef Value value_type;
  157. class rep_type
  158. {
  159. public:
  160. /* template ctors */
  161. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)&&\
  162. !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)&&\
  163. BOOST_WORKAROUND(__GNUC__,<=4)&&(__GNUC__<4||__GNUC_MINOR__<=4)
  164. /* GCC 4.4.2 (and probably prior) bug: the default ctor generated by the
  165. * variadic temmplate ctor below fails to value-initialize key.
  166. */
  167. rep_type():key(),value_ptr(0){}
  168. #endif
  169. #define BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY(args) \
  170. :key(BOOST_FLYWEIGHT_FORWARD(args)),value_ptr(0){}
  171. BOOST_FLYWEIGHT_PERFECT_FWD(
  172. explicit rep_type,
  173. BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY)
  174. #undef BOOST_FLYWEIGHT_PERFECT_FWD_CTR_BODY
  175. rep_type(const rep_type& x):key(x.key),value_ptr(0){}
  176. rep_type(const value_type&):key(no_key_from_value_failure()){}
  177. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  178. rep_type(rep_type&& x):key(std::move(x.key)),value_ptr(0){}
  179. rep_type(value_type&&):key(no_key_from_value_failure()){}
  180. #endif
  181. ~rep_type()
  182. {
  183. if(value_ptr)value_ptr->~value_type();
  184. }
  185. operator const key_type&()const{return key;}
  186. operator const value_type&()const
  187. {
  188. /* This is always called after construct_value(),so we access spc
  189. * directly rather than through value_ptr to save us an indirection.
  190. */
  191. return *static_cast<value_type*>(spc_ptr());
  192. }
  193. private:
  194. friend struct regular_key_value;
  195. void* spc_ptr()const{return static_cast<void*>(&spc);}
  196. struct no_key_from_value_failure
  197. {
  198. BOOST_MPL_ASSERT_MSG(
  199. false,
  200. NO_KEY_FROM_VALUE_CONVERSION_PROVIDED,
  201. (key_type,value_type));
  202. operator const key_type&()const;
  203. };
  204. void construct_value()const
  205. {
  206. if(!value_ptr)value_ptr=new(spc_ptr())value_type(key);
  207. }
  208. key_type key;
  209. mutable typename boost::aligned_storage<
  210. sizeof(value_type),
  211. boost::alignment_of<value_type>::value
  212. >::type spc;
  213. mutable const value_type* value_ptr;
  214. };
  215. static void construct_value(const rep_type& r)
  216. {
  217. r.construct_value();
  218. }
  219. /* copy_value() and move_value() can't really ever be called, provided to avoid
  220. * compile errors (it is the no_key_from_value_failure compile error we want to
  221. * appear in these cases).
  222. */
  223. static void copy_value(const rep_type&){}
  224. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
  225. static void move_value(const rep_type&){}
  226. #endif
  227. };
  228. } /* namespace flyweights::detail */
  229. template<typename Key,typename Value,typename KeyFromValue>
  230. struct key_value:
  231. mpl::if_<
  232. is_same<KeyFromValue,no_key_from_value>,
  233. detail::regular_key_value<Key,Value>,
  234. detail::optimized_key_value<Key,Value,KeyFromValue>
  235. >::type
  236. {};
  237. } /* namespace flyweights */
  238. } /* namespace boost */
  239. #endif