key_value.hpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /* Copyright 2006-2008 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)&&(_MSC_VER>=1200)
  11. #pragma once
  12. #endif
  13. #include <boost/flyweight/detail/value_tag.hpp>
  14. #include <boost/flyweight/key_value_fwd.hpp>
  15. #include <boost/mpl/assert.hpp>
  16. #include <boost/preprocessor/repetition/enum_params.hpp>
  17. #include <boost/type_traits/aligned_storage.hpp>
  18. #include <boost/type_traits/alignment_of.hpp>
  19. #include <boost/type_traits/is_same.hpp>
  20. #include <new>
  21. /* key-value policy: flywewight lookup is based on Key, which also serves
  22. * to construct Value only when needed (new factory entry). key_value is
  23. * used to avoid the construction of temporary values when such construction
  24. * is expensive.
  25. * Optionally, KeyFromValue extracts the key from a value, which
  26. * is needed in expressions like this:
  27. *
  28. * typedef flyweight<key_value<Key,Value> > fw_t;
  29. * fw_t fw;
  30. * Value v;
  31. * fw=v; // no key explicitly given
  32. *
  33. * If no KeyFromValue is provided, this latter expression fails to compile.
  34. */
  35. namespace boost{
  36. namespace flyweights{
  37. namespace detail{
  38. template<typename Key,typename Value,typename KeyFromValue>
  39. struct optimized_key_value:value_marker
  40. {
  41. typedef Key key_type;
  42. typedef Value value_type;
  43. class rep_type
  44. {
  45. public:
  46. /* template ctors */
  47. #define BOOST_FLYWEIGHT_PERFECT_FWD_NAME explicit rep_type
  48. #define BOOST_FLYWEIGHT_PERFECT_FWD_BODY(n) \
  49. :value_ptr(0) \
  50. { \
  51. new(spc_ptr())key_type(BOOST_PP_ENUM_PARAMS(n,t)); \
  52. }
  53. #include <boost/flyweight/detail/perfect_fwd.hpp>
  54. rep_type(const value_type& x):value_ptr(&x){}
  55. rep_type(const rep_type& x):value_ptr(x.value_ptr)
  56. {
  57. if(!x.value_ptr)new(key_ptr())key_type(*x.key_ptr());
  58. }
  59. ~rep_type()
  60. {
  61. if(!value_ptr) key_ptr()->~key_type();
  62. else if(value_cted())value_ptr->~value_type();
  63. }
  64. operator const key_type&()const
  65. {
  66. if(value_ptr)return key_from_value(*value_ptr);
  67. else return *key_ptr();
  68. }
  69. operator const value_type&()const
  70. {
  71. /* This is always called after construct_value() or copy_value(),
  72. * so we access spc directly rather than through value_ptr to
  73. * save us an indirection.
  74. */
  75. return *static_cast<value_type*>(spc_ptr());
  76. }
  77. private:
  78. friend struct optimized_key_value;
  79. void* spc_ptr()const{return static_cast<void*>(&spc);}
  80. bool value_cted()const{return value_ptr==spc_ptr();}
  81. key_type* key_ptr()const
  82. {
  83. return static_cast<key_type*>(static_cast<void*>(&spc));
  84. }
  85. static const key_type& key_from_value(const value_type& x)
  86. {
  87. KeyFromValue k;
  88. return k(x);
  89. }
  90. void construct_value()const
  91. {
  92. if(!value_cted()){
  93. /* value_ptr must be ==0, oherwise copy_value would have been called */
  94. key_type k(*key_ptr());
  95. key_ptr()->~key_type();
  96. value_ptr= /* guarantees key won't be re-dted at ~rep_type if the */
  97. static_cast<value_type*>(spc_ptr())+1; /* next statement throws */
  98. value_ptr=new(spc_ptr())value_type(k);
  99. }
  100. }
  101. void copy_value()const
  102. {
  103. if(!value_cted())value_ptr=new(spc_ptr())value_type(*value_ptr);
  104. }
  105. mutable typename boost::aligned_storage<
  106. (sizeof(key_type)>sizeof(value_type))?
  107. sizeof(key_type):sizeof(value_type),
  108. (boost::alignment_of<key_type>::value >
  109. boost::alignment_of<value_type>::value)?
  110. boost::alignment_of<key_type>::value:
  111. boost::alignment_of<value_type>::value
  112. >::type spc;
  113. mutable const value_type* value_ptr;
  114. };
  115. static void construct_value(const rep_type& r)
  116. {
  117. r.construct_value();
  118. }
  119. static void copy_value(const rep_type& r)
  120. {
  121. r.copy_value();
  122. }
  123. };
  124. template<typename Key,typename Value>
  125. struct regular_key_value:value_marker
  126. {
  127. typedef Key key_type;
  128. typedef Value value_type;
  129. class rep_type
  130. {
  131. public:
  132. /* template ctors */
  133. #define BOOST_FLYWEIGHT_PERFECT_FWD_NAME explicit rep_type
  134. #define BOOST_FLYWEIGHT_PERFECT_FWD_BODY(n) \
  135. :key(BOOST_PP_ENUM_PARAMS(n,t)),value_ptr(0){}
  136. #include <boost/flyweight/detail/perfect_fwd.hpp>
  137. rep_type(const value_type& x):key(no_key_from_value_failure()){}
  138. rep_type(const rep_type& x):key(x.key),value_ptr(0){}
  139. ~rep_type()
  140. {
  141. if(value_ptr)value_ptr->~value_type();
  142. }
  143. operator const key_type&()const{return key;}
  144. operator const value_type&()const
  145. {
  146. /* This is always called after construct_value(),so we access spc
  147. * directly rather than through value_ptr to save us an indirection.
  148. */
  149. return *static_cast<value_type*>(spc_ptr());
  150. }
  151. private:
  152. friend struct regular_key_value;
  153. void* spc_ptr()const{return static_cast<void*>(&spc);}
  154. struct no_key_from_value_failure
  155. {
  156. BOOST_MPL_ASSERT_MSG(
  157. false,
  158. NO_KEY_FROM_VALUE_CONVERSION_PROVIDED,
  159. (key_type,value_type));
  160. operator const key_type&()const;
  161. };
  162. void construct_value()const
  163. {
  164. if(!value_ptr)value_ptr=new(spc_ptr())value_type(key);
  165. }
  166. key_type key;
  167. mutable typename boost::aligned_storage<
  168. sizeof(value_type),
  169. boost::alignment_of<value_type>::value
  170. >::type spc;
  171. mutable const value_type* value_ptr;
  172. };
  173. static void construct_value(const rep_type& r)
  174. {
  175. r.construct_value();
  176. }
  177. static void copy_value(const rep_type&){}
  178. };
  179. } /* namespace flyweights::detail */
  180. template<typename Key,typename Value,typename KeyFromValue>
  181. struct key_value:
  182. mpl::if_<
  183. is_same<KeyFromValue,no_key_from_value>,
  184. detail::regular_key_value<Key,Value>,
  185. detail::optimized_key_value<Key,Value,KeyFromValue>
  186. >::type
  187. {};
  188. } /* namespace flyweights */
  189. } /* namespace boost */
  190. #endif