Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / functional / factory.hpp
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
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
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
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
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:
103     explicit fc_delete(const A& a) BOOST_NOEXCEPT
104         : base(boost::empty_init_t(), a) { }
105
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:
115     explicit fc_allocate(const A& a)
116         : a_(a)
117         , p_(a_.allocate(1)) { }
118
119     ~fc_allocate() {
120         if (p_) {
121             a_.deallocate(p_, 1);
122         }
123     }
124
125     A& state() BOOST_NOEXCEPT {
126         return a_;
127     }
128
129     typename A::value_type* get() const BOOST_NOEXCEPT {
130         return boost::to_address(p_);
131     }
132
133     R release(fc_tag<factory_alloc_for_pointee_and_deleter>) {
134         return R(release(), fc_delete<A>(a_), a_);
135     }
136
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
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>
175     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:
258     factory() BOOST_NOEXCEPT
259         : base(empty_init_t()) { }
260
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>
267     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
273     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>
280     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>
287     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>
294     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>
301     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>
308     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>
315     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>
324     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>
333     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>
342     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>
351     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