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