factory.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. /*
  2. Copyright 2007 Tobias Schwinger
  3. Copyright 2019 Glen Joseph Fernandes
  4. (glenjofe@gmail.com)
  5. Distributed under the Boost Software License, Version 1.0.
  6. (http://www.boost.org/LICENSE_1_0.txt)
  7. */
  8. #ifndef BOOST_FUNCTIONAL_FACTORY_HPP
  9. #define BOOST_FUNCTIONAL_FACTORY_HPP
  10. #include <boost/config.hpp>
  11. #include <boost/core/empty_value.hpp>
  12. #include <boost/core/pointer_traits.hpp>
  13. #include <boost/type_traits/remove_cv.hpp>
  14. #if !defined(BOOST_NO_CXX11_ALLOCATOR)
  15. #include <memory>
  16. #endif
  17. #include <new>
  18. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \
  19. !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
  20. #include <utility>
  21. #endif
  22. namespace boost {
  23. enum factory_alloc_propagation {
  24. factory_alloc_for_pointee_and_deleter,
  25. factory_passes_alloc_to_smart_pointer
  26. };
  27. namespace detail {
  28. template<factory_alloc_propagation>
  29. struct fc_tag { };
  30. #if !defined(BOOST_NO_CXX11_ALLOCATOR)
  31. template<class A, class T>
  32. struct fc_rebind {
  33. typedef typename std::allocator_traits<A>::template rebind_alloc<T> type;
  34. };
  35. template<class A>
  36. struct fc_pointer {
  37. typedef typename std::allocator_traits<A>::pointer type;
  38. };
  39. #else
  40. template<class A, class T>
  41. struct fc_rebind {
  42. typedef typename A::template rebind<T>::other type;
  43. };
  44. template<class A>
  45. struct fc_pointer {
  46. typedef typename A::pointer type;
  47. };
  48. #endif
  49. #if !defined(BOOST_NO_CXX11_ALLOCATOR) && \
  50. !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \
  51. !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
  52. template<class A, class T>
  53. inline void
  54. fc_destroy(A& a, T* p)
  55. {
  56. std::allocator_traits<A>::destroy(a, p);
  57. }
  58. #else
  59. template<class A, class T>
  60. inline void
  61. fc_destroy(A&, T* p)
  62. {
  63. p->~T();
  64. }
  65. #endif
  66. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \
  67. !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
  68. #if !defined(BOOST_NO_CXX11_ALLOCATOR)
  69. template<class A, class T, class... Args>
  70. inline void
  71. fc_construct(A& a, T* p, Args&&... args)
  72. {
  73. std::allocator_traits<A>::construct(a, p, std::forward<Args>(args)...);
  74. }
  75. #else
  76. template<class A, class T, class... Args>
  77. inline void
  78. fc_construct(A&, T* p, Args&&... args)
  79. {
  80. ::new((void*)p) T(std::forward<Args>(args)...);
  81. }
  82. #endif
  83. #endif
  84. template<class A>
  85. class fc_delete
  86. : boost::empty_value<A> {
  87. typedef boost::empty_value<A> base;
  88. public:
  89. explicit fc_delete(const A& a) BOOST_NOEXCEPT
  90. : base(boost::empty_init_t(), a) { }
  91. void operator()(typename fc_pointer<A>::type p) {
  92. boost::detail::fc_destroy(base::get(), boost::to_address(p));
  93. base::get().deallocate(p, 1);
  94. }
  95. };
  96. template<class R, class A>
  97. class fc_allocate {
  98. public:
  99. explicit fc_allocate(const A& a)
  100. : a_(a)
  101. , p_(a_.allocate(1)) { }
  102. ~fc_allocate() {
  103. if (p_) {
  104. a_.deallocate(p_, 1);
  105. }
  106. }
  107. A& state() BOOST_NOEXCEPT {
  108. return a_;
  109. }
  110. typename A::value_type* get() const BOOST_NOEXCEPT {
  111. return boost::to_address(p_);
  112. }
  113. R release(fc_tag<factory_alloc_for_pointee_and_deleter>) {
  114. return R(release(), fc_delete<A>(a_), a_);
  115. }
  116. R release(fc_tag<factory_passes_alloc_to_smart_pointer>) {
  117. return R(release(), fc_delete<A>(a_));
  118. }
  119. private:
  120. typedef typename fc_pointer<A>::type pointer;
  121. pointer release() BOOST_NOEXCEPT {
  122. pointer p = p_;
  123. p_ = pointer();
  124. return p;
  125. }
  126. fc_allocate(const fc_allocate&);
  127. fc_allocate& operator=(const fc_allocate&);
  128. A a_;
  129. pointer p_;
  130. };
  131. } /* detail */
  132. template<class Pointer, class Allocator = void,
  133. factory_alloc_propagation Policy = factory_alloc_for_pointee_and_deleter>
  134. class factory;
  135. template<class Pointer, factory_alloc_propagation Policy>
  136. class factory<Pointer, void, Policy> {
  137. public:
  138. typedef typename remove_cv<Pointer>::type result_type;
  139. private:
  140. typedef typename pointer_traits<result_type>::element_type type;
  141. public:
  142. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \
  143. !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
  144. template<class... Args>
  145. result_type operator()(Args&&... args) const {
  146. return result_type(new type(std::forward<Args>(args)...));
  147. }
  148. #else
  149. result_type operator()() const {
  150. return result_type(new type());
  151. }
  152. template<class A0>
  153. result_type operator()(A0& a0) const {
  154. return result_type(new type(a0));
  155. }
  156. template<class A0, class A1>
  157. result_type operator()(A0& a0, A1& a1) const {
  158. return result_type(new type(a0, a1));
  159. }
  160. template<class A0, class A1, class A2>
  161. result_type operator()(A0& a0, A1& a1, A2& a2) const {
  162. return result_type(new type(a0, a1, a2));
  163. }
  164. template<class A0, class A1, class A2, class A3>
  165. result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3) const {
  166. return result_type(new type(a0, a1, a2, a3));
  167. }
  168. template<class A0, class A1, class A2, class A3, class A4>
  169. result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4) const {
  170. return result_type(new type(a0, a1, a2, a3, a4));
  171. }
  172. template<class A0, class A1, class A2, class A3, class A4, class A5>
  173. result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4,
  174. A5& a5) const {
  175. return result_type(new type(a0, a1, a2, a3, a4, a5));
  176. }
  177. template<class A0, class A1, class A2, class A3, class A4, class A5,
  178. class A6>
  179. result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5,
  180. A6& a6) const {
  181. return result_type(new type(a0, a1, a2, a3, a4, a5, a6));
  182. }
  183. template<class A0, class A1, class A2, class A3, class A4, class A5,
  184. class A6, class A7>
  185. result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5,
  186. A6& a6, A7& a7) const {
  187. return result_type(new type(a0, a1, a2, a3, a4, a5, a6, a7));
  188. }
  189. template<class A0, class A1, class A2, class A3, class A4, class A5,
  190. class A6, class A7, class A8>
  191. result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5,
  192. A6& a6, A7& a7, A8& a8) const {
  193. return result_type(new type(a0, a1, a2, a3, a4, a5, a6, a7, a8));
  194. }
  195. template<class A0, class A1, class A2, class A3, class A4, class A5,
  196. class A6, class A7, class A8, class A9>
  197. result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5,
  198. A6& a6, A7& a7, A8& a8, A9& a9) const {
  199. return result_type(new type(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9));
  200. }
  201. #endif
  202. };
  203. template<class Pointer, class Allocator, factory_alloc_propagation Policy>
  204. class factory
  205. : empty_value<typename detail::fc_rebind<Allocator,
  206. typename pointer_traits<typename
  207. remove_cv<Pointer>::type>::element_type>::type> {
  208. public:
  209. typedef typename remove_cv<Pointer>::type result_type;
  210. private:
  211. typedef typename pointer_traits<result_type>::element_type type;
  212. typedef typename detail::fc_rebind<Allocator, type>::type allocator;
  213. typedef empty_value<allocator> base;
  214. public:
  215. factory() BOOST_NOEXCEPT
  216. : base(empty_init_t()) { }
  217. explicit factory(const Allocator& a) BOOST_NOEXCEPT
  218. : base(empty_init_t(), a) { }
  219. #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \
  220. !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
  221. template<class... Args>
  222. result_type operator()(Args&&... args) const {
  223. detail::fc_allocate<result_type, allocator> s(base::get());
  224. detail::fc_construct(s.state(), s.get(), std::forward<Args>(args)...);
  225. return s.release(detail::fc_tag<Policy>());
  226. }
  227. #else
  228. result_type operator()() const {
  229. detail::fc_allocate<result_type, allocator> s(base::get());
  230. ::new((void*)s.get()) type();
  231. return s.release(detail::fc_tag<Policy>());
  232. }
  233. template<class A0>
  234. result_type operator()(A0& a0) const {
  235. detail::fc_allocate<result_type, allocator> s(base::get());
  236. ::new((void*)s.get()) type(a0);
  237. return s.release(detail::fc_tag<Policy>());
  238. }
  239. template<class A0, class A1>
  240. result_type operator()(A0& a0, A1& a1) const {
  241. detail::fc_allocate<result_type, allocator> s(base::get());
  242. ::new((void*)s.get()) type(a0, a1);
  243. return s.release(detail::fc_tag<Policy>());
  244. }
  245. template<class A0, class A1, class A2>
  246. result_type operator()(A0& a0, A1& a1, A2& a2) const {
  247. detail::fc_allocate<result_type, allocator> s(base::get());
  248. ::new((void*)s.get()) type(a0, a1, a2);
  249. return s.release(detail::fc_tag<Policy>());
  250. }
  251. template<class A0, class A1, class A2, class A3>
  252. result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3) const {
  253. detail::fc_allocate<result_type, allocator> s(base::get());
  254. ::new((void*)s.get()) type(a0, a1, a2, a3);
  255. return s.release(detail::fc_tag<Policy>());
  256. }
  257. template<class A0, class A1, class A2, class A3, class A4>
  258. result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4) const {
  259. detail::fc_allocate<result_type, allocator> s(base::get());
  260. ::new((void*)s.get()) type(a0, a1, a2, a3, a4);
  261. return s.release(detail::fc_tag<Policy>());
  262. }
  263. template<class A0, class A1, class A2, class A3, class A4, class A5>
  264. result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4,
  265. A5& a5) const {
  266. detail::fc_allocate<result_type, allocator> s(base::get());
  267. ::new((void*)s.get()) type(a0, a1, a2, a3, a4, a5);
  268. return s.release(detail::fc_tag<Policy>());
  269. }
  270. template<class A0, class A1, class A2, class A3, class A4, class A5,
  271. class A6>
  272. result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5,
  273. A6& a6) const {
  274. detail::fc_allocate<result_type, allocator> s(base::get());
  275. ::new((void*)s.get()) type(a0, a1, a2, a3, a4, a5, a6);
  276. return s.release(detail::fc_tag<Policy>());
  277. }
  278. template<class A0, class A1, class A2, class A3, class A4, class A5,
  279. class A6, class A7>
  280. result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5,
  281. A6& a6, A7& a7) const {
  282. detail::fc_allocate<result_type, allocator> s(base::get());
  283. ::new((void*)s.get()) type(a0, a1, a2, a3, a4, a5, a6, a7);
  284. return s.release(detail::fc_tag<Policy>());
  285. }
  286. template<class A0, class A1, class A2, class A3, class A4, class A5,
  287. class A6, class A7, class A8>
  288. result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5,
  289. A6& a6, A7& a7, A8& a8) const {
  290. detail::fc_allocate<result_type, allocator> s(base::get());
  291. ::new((void*)s.get()) type(a0, a1, a2, a3, a4, a5, a6, a7, a8);
  292. return s.release(detail::fc_tag<Policy>());
  293. }
  294. template<class A0, class A1, class A2, class A3, class A4, class A5,
  295. class A6, class A7, class A8, class A9>
  296. result_type operator()(A0& a0, A1& a1, A2& a2, A3& a3, A4& a4, A5& a5,
  297. A6& a6, A7& a7, A8& a8, A9& a9) const {
  298. detail::fc_allocate<result_type, allocator> s(base::get());
  299. ::new((void*)s.get()) type(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9);
  300. return s.release(detail::fc_tag<Policy>());
  301. }
  302. #endif
  303. };
  304. template<class Pointer, class Allocator, factory_alloc_propagation Policy>
  305. class factory<Pointer&, Allocator, Policy> { };
  306. } /* boost */
  307. #endif