factory.hpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. /*=============================================================================
  2. Copyright (c) 2007 Tobias Schwinger
  3. Use modification and distribution are subject to the Boost Software
  4. License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  5. http://www.boost.org/LICENSE_1_0.txt).
  6. ==============================================================================*/
  7. #ifndef BOOST_FUNCTIONAL_FACTORY_HPP_INCLUDED
  8. # ifndef BOOST_PP_IS_ITERATING
  9. # include <boost/preprocessor/iteration/iterate.hpp>
  10. # include <boost/preprocessor/repetition/enum_params.hpp>
  11. # include <boost/preprocessor/repetition/enum_binary_params.hpp>
  12. # include <boost/preprocessor/repetition/enum_trailing_params.hpp>
  13. # include <new>
  14. # include <boost/pointee.hpp>
  15. # include <boost/get_pointer.hpp>
  16. # include <boost/non_type.hpp>
  17. # include <boost/type_traits/remove_cv.hpp>
  18. # if defined(BOOST_FUNCTIONAL_FACTORY_SUPPORT_NONE_T)
  19. # include <boost/none_t.hpp>
  20. # endif
  21. # ifndef BOOST_FUNCTIONAL_FACTORY_MAX_ARITY
  22. # define BOOST_FUNCTIONAL_FACTORY_MAX_ARITY 10
  23. # elif BOOST_FUNCTIONAL_FACTORY_MAX_ARITY < 3
  24. # undef BOOST_FUNCTIONAL_FACTORY_MAX_ARITY
  25. # define BOOST_FUNCTIONAL_FACTORY_MAX_ARITY 3
  26. # endif
  27. namespace boost
  28. {
  29. enum factory_alloc_propagation
  30. {
  31. factory_alloc_for_pointee_and_deleter,
  32. factory_passes_alloc_to_smart_pointer
  33. };
  34. #if defined(BOOST_FUNCTIONAL_FACTORY_SUPPORT_NONE_T)
  35. template< typename Pointer, class Allocator = boost::none_t,
  36. factory_alloc_propagation AP = factory_alloc_for_pointee_and_deleter >
  37. class factory;
  38. #else
  39. template< typename Pointer, class Allocator = void,
  40. factory_alloc_propagation AP = factory_alloc_for_pointee_and_deleter >
  41. class factory;
  42. #endif
  43. //----- ---- --- -- - - - -
  44. template< typename Pointer, factory_alloc_propagation AP >
  45. class factory<Pointer, void, AP>
  46. {
  47. public:
  48. typedef typename boost::remove_cv<Pointer>::type result_type;
  49. typedef typename boost::pointee<result_type>::type value_type;
  50. factory()
  51. { }
  52. # define BOOST_PP_FILENAME_1 <boost/functional/factory.hpp>
  53. # define BOOST_PP_ITERATION_LIMITS (0,BOOST_FUNCTIONAL_FACTORY_MAX_ARITY)
  54. # include BOOST_PP_ITERATE()
  55. };
  56. #if defined(BOOST_FUNCTIONAL_FACTORY_SUPPORT_NONE_T)
  57. template< typename Pointer, factory_alloc_propagation AP >
  58. class factory<Pointer, boost::none_t, AP>
  59. : public factory<Pointer, void, AP>
  60. {};
  61. #endif
  62. template< class Pointer, class Allocator, factory_alloc_propagation AP >
  63. class factory
  64. #if defined(BOOST_NO_CXX11_ALLOCATOR)
  65. : private Allocator::template rebind< typename boost::pointee<
  66. typename boost::remove_cv<Pointer>::type >::type >::other
  67. #else
  68. : private std::allocator_traits<Allocator>::template rebind_alloc<
  69. typename boost::pointee< typename boost::remove_cv<Pointer>::type >::type >
  70. #endif
  71. {
  72. public:
  73. typedef typename boost::remove_cv<Pointer>::type result_type;
  74. typedef typename boost::pointee<result_type>::type value_type;
  75. #if defined(BOOST_NO_CXX11_ALLOCATOR)
  76. typedef typename Allocator::template rebind<value_type>::other
  77. allocator_type;
  78. #else
  79. typedef typename std::allocator_traits<Allocator>::template rebind_alloc<value_type>
  80. allocator_type;
  81. typedef std::allocator_traits<allocator_type> allocator_traits;
  82. #endif
  83. explicit factory(allocator_type const & a = allocator_type())
  84. : allocator_type(a)
  85. { }
  86. private:
  87. struct deleter
  88. : allocator_type
  89. {
  90. inline deleter(allocator_type const& that)
  91. : allocator_type(that)
  92. { }
  93. allocator_type& get_allocator() const
  94. {
  95. return *const_cast<allocator_type*>(
  96. static_cast<allocator_type const*>(this));
  97. }
  98. void operator()(value_type* ptr) const
  99. {
  100. if (!! ptr) {
  101. #if defined(BOOST_NO_CXX11_ALLOCATOR)
  102. ptr->~value_type();
  103. const_cast<allocator_type*>(static_cast<allocator_type const*>(
  104. this))->deallocate(ptr,1);
  105. #else
  106. allocator_traits::destroy(this->get_allocator(), ptr);
  107. allocator_traits::deallocate(this->get_allocator(),ptr,1);
  108. #endif
  109. }
  110. }
  111. };
  112. inline allocator_type& get_allocator() const
  113. {
  114. return *const_cast<allocator_type*>(
  115. static_cast<allocator_type const*>(this));
  116. }
  117. inline result_type make_pointer(value_type* ptr, boost::non_type<
  118. factory_alloc_propagation,factory_passes_alloc_to_smart_pointer>)
  119. const
  120. {
  121. return result_type(ptr,deleter(this->get_allocator()));
  122. }
  123. inline result_type make_pointer(value_type* ptr, boost::non_type<
  124. factory_alloc_propagation,factory_alloc_for_pointee_and_deleter>)
  125. const
  126. {
  127. return result_type(ptr,deleter(this->get_allocator()),
  128. this->get_allocator());
  129. }
  130. public:
  131. # define BOOST_TMP_MACRO
  132. # define BOOST_PP_FILENAME_1 <boost/functional/factory.hpp>
  133. # define BOOST_PP_ITERATION_LIMITS (0,BOOST_FUNCTIONAL_FACTORY_MAX_ARITY)
  134. # include BOOST_PP_ITERATE()
  135. # undef BOOST_TMP_MACRO
  136. };
  137. template< typename Pointer, class Allocator, factory_alloc_propagation AP >
  138. class factory<Pointer&, Allocator, AP>;
  139. // forbidden, would create a dangling reference
  140. }
  141. # define BOOST_FUNCTIONAL_FACTORY_HPP_INCLUDED
  142. # else // defined(BOOST_PP_IS_ITERATING)
  143. # define N BOOST_PP_ITERATION()
  144. # if !defined(BOOST_TMP_MACRO)
  145. # if N > 0
  146. template< BOOST_PP_ENUM_PARAMS(N, typename T) >
  147. # endif
  148. inline result_type operator()(BOOST_PP_ENUM_BINARY_PARAMS(N,T,& a)) const
  149. {
  150. return result_type( new value_type(BOOST_PP_ENUM_PARAMS(N,a)) );
  151. }
  152. # else // defined(BOOST_TMP_MACRO)
  153. # if N > 0
  154. template< BOOST_PP_ENUM_PARAMS(N, typename T) >
  155. # endif
  156. inline result_type operator()(BOOST_PP_ENUM_BINARY_PARAMS(N,T,& a)) const
  157. {
  158. #if defined(BOOST_NO_CXX11_ALLOCATOR)
  159. value_type* memory = this->get_allocator().allocate(1);
  160. #else
  161. value_type* memory = allocator_traits::allocate(this->get_allocator(), 1);
  162. #endif
  163. try
  164. {
  165. #if defined(BOOST_NO_CXX11_ALLOCATOR)
  166. new(memory) value_type(BOOST_PP_ENUM_PARAMS(N,a));
  167. #else
  168. allocator_traits::construct(this->get_allocator(), memory
  169. BOOST_PP_ENUM_TRAILING_PARAMS(N,a));
  170. #endif
  171. }
  172. catch (...) {
  173. #if defined(BOOST_NO_CXX11_ALLOCATOR)
  174. this->get_allocator().deallocate(memory,1);
  175. #else
  176. allocator_traits::deallocate(this->get_allocator(), memory, 1);
  177. #endif
  178. throw;
  179. }
  180. return make_pointer(memory, boost::non_type<factory_alloc_propagation,AP>());
  181. }
  182. # endif
  183. # undef N
  184. # endif // defined(BOOST_PP_IS_ITERATING)
  185. #endif // include guard