1// -*- C++ -*-
2//===-------------------------- scoped_allocator --------------------------===//
3//
4//                     The LLVM Compiler Infrastructure
5//
6// This file is dual licensed under the MIT and the University of Illinois Open
7// Source Licenses. See LICENSE.TXT for details.
8//
9//===----------------------------------------------------------------------===//
10
11#ifndef _LIBCPP_SCOPED_ALLOCATOR
12#define _LIBCPP_SCOPED_ALLOCATOR
13
14/*
15    scoped_allocator synopsis
16
17namespace std
18{
19
20template <class OuterAlloc, class... InnerAllocs>
21class scoped_allocator_adaptor : public OuterAlloc
22{
23    typedef allocator_traits<OuterAlloc> OuterTraits; // exposition only
24    scoped_allocator_adaptor<InnerAllocs...> inner;   // exposition only
25public:
26
27    typedef OuterAlloc outer_allocator_type;
28    typedef see below inner_allocator_type;
29
30    typedef typename OuterTraits::value_type value_type;
31    typedef typename OuterTraits::size_type size_type;
32    typedef typename OuterTraits::difference_type difference_type;
33    typedef typename OuterTraits::pointer pointer;
34    typedef typename OuterTraits::const_pointer const_pointer;
35    typedef typename OuterTraits::void_pointer void_pointer;
36    typedef typename OuterTraits::const_void_pointer const_void_pointer;
37
38    typedef see below propagate_on_container_copy_assignment;
39    typedef see below propagate_on_container_move_assignment;
40    typedef see below propagate_on_container_swap;
41
42    template <class Tp>
43        struct rebind
44        {
45            typedef scoped_allocator_adaptor<
46                OuterTraits::template rebind_alloc<Tp>, InnerAllocs...> other;
47        };
48
49    scoped_allocator_adaptor();
50    template <class OuterA2>
51        scoped_allocator_adaptor(OuterA2&& outerAlloc,
52                                 const InnerAllocs&... innerAllocs);
53    scoped_allocator_adaptor(const scoped_allocator_adaptor& other);
54    template <class OuterA2>
55        scoped_allocator_adaptor(const scoped_allocator_adaptor<OuterA2, InnerAllocs...>& other);
56    template <class OuterA2>
57        scoped_allocator_adaptor(const scoped_allocator_adaptor<OuterA2, InnerAllocs...>&& other);
58
59    ~scoped_allocator_adaptor();
60
61    inner_allocator_type& inner_allocator();
62    const inner_allocator_type& inner_allocator() const;
63
64    outer_allocator_type& outer_allocator();
65    const outer_allocator_type& outer_allocator() const;
66
67    pointer allocate(size_type n);
68    pointer allocate(size_type n, const_void_pointer hint);
69    void deallocate(pointer p, size_type n);
70
71    size_type max_size() const;
72    template <class T, class... Args> void construct(T* p, Args&& args);
73    template <class T1, class T2, class... Args1, class... Args2>
74        void construct(pair<T1, T2>* p, piecewise_construct t, tuple<Args1...> x,
75                       tuple<Args2...> y);
76    template <class T1, class T2>
77        void construct(pair<T1, T2>* p);
78    template <class T1, class T2, class U, class V>
79        void construct(pair<T1, T2>* p, U&& x, V&& y);
80    template <class T1, class T2, class U, class V>
81        void construct(pair<T1, T2>* p, const pair<U, V>& x);
82    template <class T1, class T2, class U, class V>
83        void construct(pair<T1, T2>* p, pair<U, V>&& x);
84    template <class T> void destroy(T* p);
85
86    scoped_allocator_adaptor select_on_container_copy_construction() const;
87};
88
89template <class OuterA1, class OuterA2, class... InnerAllocs>
90    bool
91    operator==(const scoped_allocator_adaptor<OuterA1, InnerAllocs...>& a,
92               const scoped_allocator_adaptor<OuterA2, InnerAllocs...>& b);
93
94template <class OuterA1, class OuterA2, class... InnerAllocs>
95    bool
96    operator!=(const scoped_allocator_adaptor<OuterA1, InnerAllocs...>& a,
97               const scoped_allocator_adaptor<OuterA2, InnerAllocs...>& b);
98
99}  // std
100
101*/
102
103#include <__config>
104#include <memory>
105
106#pragma GCC system_header
107
108_LIBCPP_BEGIN_NAMESPACE_STD
109
110#if !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_ADVANCED_SFINAE)
111
112// scoped_allocator_adaptor
113
114template <class ..._Allocs>
115class scoped_allocator_adaptor;
116
117template <class ..._Allocs> struct __get_poc_copy_assignment;
118
119template <class _A0>
120struct __get_poc_copy_assignment<_A0>
121{
122    static const bool value = allocator_traits<_A0>::
123                              propagate_on_container_copy_assignment::value;
124};
125
126template <class _A0, class ..._Allocs>
127struct __get_poc_copy_assignment<_A0, _Allocs...>
128{
129    static const bool value =
130        allocator_traits<_A0>::propagate_on_container_copy_assignment::value ||
131        __get_poc_copy_assignment<_Allocs...>::value;
132};
133
134template <class ..._Allocs> struct __get_poc_move_assignment;
135
136template <class _A0>
137struct __get_poc_move_assignment<_A0>
138{
139    static const bool value = allocator_traits<_A0>::
140                              propagate_on_container_move_assignment::value;
141};
142
143template <class _A0, class ..._Allocs>
144struct __get_poc_move_assignment<_A0, _Allocs...>
145{
146    static const bool value =
147        allocator_traits<_A0>::propagate_on_container_move_assignment::value ||
148        __get_poc_move_assignment<_Allocs...>::value;
149};
150
151template <class ..._Allocs> struct __get_poc_swap;
152
153template <class _A0>
154struct __get_poc_swap<_A0>
155{
156    static const bool value = allocator_traits<_A0>::
157                              propagate_on_container_swap::value;
158};
159
160template <class _A0, class ..._Allocs>
161struct __get_poc_swap<_A0, _Allocs...>
162{
163    static const bool value =
164        allocator_traits<_A0>::propagate_on_container_swap::value ||
165        __get_poc_swap<_Allocs...>::value;
166};
167
168template <class ..._Allocs>
169class __scoped_allocator_storage;
170
171template <class _OuterAlloc, class... _InnerAllocs>
172class __scoped_allocator_storage<_OuterAlloc, _InnerAllocs...>
173    : public _OuterAlloc
174{
175    typedef _OuterAlloc outer_allocator_type;
176protected:
177    typedef scoped_allocator_adaptor<_InnerAllocs...> inner_allocator_type;
178
179private:
180    inner_allocator_type __inner_;
181
182protected:
183
184    _LIBCPP_INLINE_VISIBILITY
185    __scoped_allocator_storage() {}
186
187    template <class _OuterA2,
188              class = typename enable_if<
189                        is_constructible<outer_allocator_type, _OuterA2>::value
190                      >::type>
191        _LIBCPP_INLINE_VISIBILITY
192        __scoped_allocator_storage(_OuterA2&& __outerAlloc,
193                                   const _InnerAllocs& ...__innerAllocs)
194            : outer_allocator_type(_STD::forward<_OuterA2>(__outerAlloc)),
195              __inner_(__innerAllocs...) {}
196
197    template <class _OuterA2,
198              class = typename enable_if<
199                        is_constructible<outer_allocator_type, const _OuterA2&>::value
200                      >::type>
201        _LIBCPP_INLINE_VISIBILITY
202        __scoped_allocator_storage(
203            const __scoped_allocator_storage<_OuterA2, _InnerAllocs...>& __other)
204            : outer_allocator_type(__other.outer_allocator()),
205              __inner_(__other.inner_allocator()) {}
206
207    template <class _OuterA2,
208              class = typename enable_if<
209                        is_constructible<outer_allocator_type, _OuterA2>::value
210                      >::type>
211        _LIBCPP_INLINE_VISIBILITY
212        __scoped_allocator_storage(
213            __scoped_allocator_storage<_OuterA2, _InnerAllocs...>&& __other)
214            : outer_allocator_type(_STD::move(__other.outer_allocator())),
215              __inner_(_STD::move(__other.inner_allocator())) {}
216
217    template <class _OuterA2,
218              class = typename enable_if<
219                        is_constructible<outer_allocator_type, _OuterA2>::value
220                      >::type>
221        _LIBCPP_INLINE_VISIBILITY
222        __scoped_allocator_storage(_OuterA2&& __o,
223                                   const inner_allocator_type& __i)
224            : outer_allocator_type(_STD::forward<_OuterA2>(__o)),
225              __inner_(__i)
226        {
227        }
228
229    _LIBCPP_INLINE_VISIBILITY
230    inner_allocator_type& inner_allocator()             {return __inner_;}
231    _LIBCPP_INLINE_VISIBILITY
232    const inner_allocator_type& inner_allocator() const {return __inner_;}
233
234    _LIBCPP_INLINE_VISIBILITY
235    outer_allocator_type& outer_allocator()
236        {return static_cast<outer_allocator_type&>(*this);}
237    _LIBCPP_INLINE_VISIBILITY
238    const outer_allocator_type& outer_allocator() const
239        {return static_cast<const outer_allocator_type&>(*this);}
240
241    scoped_allocator_adaptor<outer_allocator_type, _InnerAllocs...>
242    _LIBCPP_INLINE_VISIBILITY
243    select_on_container_copy_construction() const
244        {
245            return scoped_allocator_adaptor<outer_allocator_type, _InnerAllocs...>
246            (
247                allocator_traits<outer_allocator_type>::
248                    select_on_container_copy_construction(outer_allocator()),
249                allocator_traits<inner_allocator_type>::
250                    select_on_container_copy_construction(inner_allocator())
251            );
252        }
253
254    template <class...> friend class __scoped_allocator_storage;
255};
256
257template <class _OuterAlloc>
258class __scoped_allocator_storage<_OuterAlloc>
259    : public _OuterAlloc
260{
261    typedef _OuterAlloc outer_allocator_type;
262protected:
263    typedef scoped_allocator_adaptor<_OuterAlloc> inner_allocator_type;
264
265    _LIBCPP_INLINE_VISIBILITY
266    __scoped_allocator_storage() {}
267
268    template <class _OuterA2,
269              class = typename enable_if<
270                        is_constructible<outer_allocator_type, _OuterA2>::value
271                      >::type>
272        _LIBCPP_INLINE_VISIBILITY
273        __scoped_allocator_storage(_OuterA2&& __outerAlloc)
274            : outer_allocator_type(_STD::forward<_OuterA2>(__outerAlloc)) {}
275
276    template <class _OuterA2,
277              class = typename enable_if<
278                        is_constructible<outer_allocator_type, const _OuterA2&>::value
279                      >::type>
280        _LIBCPP_INLINE_VISIBILITY
281        __scoped_allocator_storage(
282            const __scoped_allocator_storage<_OuterA2>& __other)
283            : outer_allocator_type(__other.outer_allocator()) {}
284
285    template <class _OuterA2,
286              class = typename enable_if<
287                        is_constructible<outer_allocator_type, _OuterA2>::value
288                      >::type>
289        _LIBCPP_INLINE_VISIBILITY
290        __scoped_allocator_storage(
291            __scoped_allocator_storage<_OuterA2>&& __other)
292            : outer_allocator_type(_STD::move(__other.outer_allocator())) {}
293
294    _LIBCPP_INLINE_VISIBILITY
295    inner_allocator_type& inner_allocator()
296        {return static_cast<inner_allocator_type&>(*this);}
297    _LIBCPP_INLINE_VISIBILITY
298    const inner_allocator_type& inner_allocator() const
299        {return static_cast<const inner_allocator_type&>(*this);}
300
301    _LIBCPP_INLINE_VISIBILITY
302    outer_allocator_type& outer_allocator()
303        {return static_cast<outer_allocator_type&>(*this);}
304    _LIBCPP_INLINE_VISIBILITY
305    const outer_allocator_type& outer_allocator() const
306        {return static_cast<const outer_allocator_type&>(*this);}
307
308    _LIBCPP_INLINE_VISIBILITY
309    scoped_allocator_adaptor<outer_allocator_type>
310    select_on_container_copy_construction() const
311        {return scoped_allocator_adaptor<outer_allocator_type>(
312            allocator_traits<outer_allocator_type>::
313                select_on_container_copy_construction(outer_allocator())
314        );}
315
316    __scoped_allocator_storage(const outer_allocator_type& __o,
317                               const inner_allocator_type& __i);
318
319    template <class...> friend class __scoped_allocator_storage;
320};
321
322// __outermost
323
324template <class _Alloc>
325decltype(declval<_Alloc>().outer_allocator(), true_type())
326__has_outer_allocator_test(_Alloc&& __a);
327
328template <class _Alloc>
329false_type
330__has_outer_allocator_test(const volatile _Alloc& __a);
331
332template <class _Alloc>
333struct __has_outer_allocator
334    : public common_type
335             <
336                 decltype(__has_outer_allocator_test(declval<_Alloc&>()))
337             >::type
338{
339};
340
341template <class _Alloc, bool = __has_outer_allocator<_Alloc>::value>
342struct __outermost
343{
344    typedef _Alloc type;
345    _LIBCPP_INLINE_VISIBILITY
346    type& operator()(type& __a) const {return __a;}
347};
348
349template <class _Alloc>
350struct __outermost<_Alloc, true>
351{
352    typedef typename remove_reference
353                     <
354                        decltype(_STD::declval<_Alloc>().outer_allocator())
355                     >::type                                    _OuterAlloc;
356    typedef typename __outermost<_OuterAlloc>::type             type;
357    _LIBCPP_INLINE_VISIBILITY
358    type& operator()(_Alloc& __a) const
359        {return __outermost<_OuterAlloc>()(__a.outer_allocator());}
360};
361
362template <class _OuterAlloc, class... _InnerAllocs>
363class _LIBCPP_VISIBLE scoped_allocator_adaptor<_OuterAlloc, _InnerAllocs...>
364    : public __scoped_allocator_storage<_OuterAlloc, _InnerAllocs...>
365{
366    typedef __scoped_allocator_storage<_OuterAlloc, _InnerAllocs...> base;
367    typedef allocator_traits<_OuterAlloc>             _OuterTraits;
368public:
369    typedef _OuterAlloc                               outer_allocator_type;
370    typedef typename base::inner_allocator_type       inner_allocator_type;
371    typedef typename _OuterTraits::size_type          size_type;
372    typedef typename _OuterTraits::difference_type    difference_type;
373    typedef typename _OuterTraits::pointer            pointer;
374    typedef typename _OuterTraits::const_pointer      const_pointer;
375    typedef typename _OuterTraits::void_pointer       void_pointer;
376    typedef typename _OuterTraits::const_void_pointer const_void_pointer;
377
378    typedef integral_constant
379            <
380                bool,
381                __get_poc_copy_assignment<outer_allocator_type,
382                                          _InnerAllocs...>::value
383            > propagate_on_container_copy_assignment;
384    typedef integral_constant
385            <
386                bool,
387                __get_poc_move_assignment<outer_allocator_type,
388                                          _InnerAllocs...>::value
389            > propagate_on_container_move_assignment;
390    typedef integral_constant
391            <
392                bool,
393                __get_poc_swap<outer_allocator_type, _InnerAllocs...>::value
394            > propagate_on_container_swap;
395
396    template <class _Tp>
397    struct rebind
398    {
399        typedef scoped_allocator_adaptor
400        <
401            typename _OuterTraits::template rebind_alloc<_Tp>, _InnerAllocs...
402        > other;
403    };
404
405    _LIBCPP_INLINE_VISIBILITY
406    scoped_allocator_adaptor() {}
407    template <class _OuterA2,
408              class = typename enable_if<
409                        is_constructible<outer_allocator_type, _OuterA2>::value
410                      >::type>
411        _LIBCPP_INLINE_VISIBILITY
412        scoped_allocator_adaptor(_OuterA2&& __outerAlloc,
413                                 const _InnerAllocs& ...__innerAllocs)
414            : base(_STD::forward<_OuterA2>(__outerAlloc), __innerAllocs...) {}
415    // scoped_allocator_adaptor(const scoped_allocator_adaptor& __other) = default;
416    template <class _OuterA2,
417              class = typename enable_if<
418                        is_constructible<outer_allocator_type, const _OuterA2&>::value
419                      >::type>
420        _LIBCPP_INLINE_VISIBILITY
421        scoped_allocator_adaptor(
422            const scoped_allocator_adaptor<_OuterA2, _InnerAllocs...>& __other)
423                : base(__other) {}
424    template <class _OuterA2,
425              class = typename enable_if<
426                        is_constructible<outer_allocator_type, _OuterA2>::value
427                      >::type>
428        _LIBCPP_INLINE_VISIBILITY
429        scoped_allocator_adaptor(
430            scoped_allocator_adaptor<_OuterA2, _InnerAllocs...>&& __other)
431                : base(_STD::move(__other)) {}
432
433    // ~scoped_allocator_adaptor() = default;
434
435    _LIBCPP_INLINE_VISIBILITY
436    inner_allocator_type& inner_allocator()
437        {return base::inner_allocator();}
438    _LIBCPP_INLINE_VISIBILITY
439    const inner_allocator_type& inner_allocator() const
440        {return base::inner_allocator();}
441
442    _LIBCPP_INLINE_VISIBILITY
443    outer_allocator_type& outer_allocator()
444        {return base::outer_allocator();}
445    _LIBCPP_INLINE_VISIBILITY
446    const outer_allocator_type& outer_allocator() const
447        {return base::outer_allocator();}
448
449    _LIBCPP_INLINE_VISIBILITY
450    pointer allocate(size_type __n)
451        {return allocator_traits<outer_allocator_type>::
452            allocate(outer_allocator(), __n);}
453    _LIBCPP_INLINE_VISIBILITY
454    pointer allocate(size_type __n, const_void_pointer __hint)
455        {return allocator_traits<outer_allocator_type>::
456            allocate(outer_allocator(), __n, __hint);}
457
458    _LIBCPP_INLINE_VISIBILITY
459    void deallocate(pointer __p, size_type __n)
460        {allocator_traits<outer_allocator_type>::
461            deallocate(outer_allocator(), __p, __n);}
462
463    _LIBCPP_INLINE_VISIBILITY
464    size_type max_size() const
465        {return allocator_traits<outer_allocator_type>::max_size(outer_allocator());}
466
467    template <class _Tp, class... _Args>
468        _LIBCPP_INLINE_VISIBILITY
469        void construct(_Tp* __p, _Args&& ...__args)
470            {__construct(__uses_alloc_ctor<_Tp, inner_allocator_type, _Args...>(),
471                         __p, _STD::forward<_Args>(__args)...);}
472    template <class _Tp>
473        _LIBCPP_INLINE_VISIBILITY
474        void destroy(_Tp* __p)
475            {
476                typedef __outermost<outer_allocator_type> _OM;
477                allocator_traits<typename _OM::type>::
478                                         destroy(_OM()(outer_allocator()), __p);
479            }
480
481    _LIBCPP_INLINE_VISIBILITY
482    scoped_allocator_adaptor select_on_container_copy_construction() const
483        {return base::select_on_container_copy_construction();}
484
485private:
486
487    template <class _OuterA2,
488              class = typename enable_if<
489                        is_constructible<outer_allocator_type, _OuterA2>::value
490                      >::type>
491    _LIBCPP_INLINE_VISIBILITY
492    scoped_allocator_adaptor(_OuterA2&& __o,
493                             const inner_allocator_type& __i)
494        : base(_STD::forward<_OuterA2>(__o), __i) {}
495
496    template <class _Tp, class... _Args>
497        _LIBCPP_INLINE_VISIBILITY
498        void __construct(integral_constant<int, 0>, _Tp* __p, _Args&& ...__args)
499            {
500                typedef __outermost<outer_allocator_type> _OM;
501                allocator_traits<typename _OM::type>::construct
502                (
503                    _OM()(outer_allocator()),
504                    __p,
505                    _STD::forward<_Args>(__args)...
506                );
507            }
508
509    template <class _Tp, class... _Args>
510        _LIBCPP_INLINE_VISIBILITY
511        void __construct(integral_constant<int, 1>, _Tp* __p, _Args&& ...__args)
512            {
513                typedef __outermost<outer_allocator_type> _OM;
514                allocator_traits<typename _OM::type>::construct
515                (
516                    _OM()(outer_allocator()),
517                    __p,
518                    allocator_arg,
519                    inner_allocator(),
520                    _STD::forward<_Args>(__args)...
521                );
522            }
523
524    template <class _Tp, class... _Args>
525        _LIBCPP_INLINE_VISIBILITY
526        void __construct(integral_constant<int, 2>, _Tp* __p, _Args&& ...__args)
527            {
528                typedef __outermost<outer_allocator_type> _OM;
529                allocator_traits<typename _OM::type>::construct
530                (
531                    _OM()(outer_allocator()),
532                    __p,
533                    _STD::forward<_Args>(__args)...,
534                    inner_allocator()
535                );
536            }
537
538    template <class...> friend class __scoped_allocator_storage;
539};
540
541template <class _OuterA1, class _OuterA2>
542inline _LIBCPP_INLINE_VISIBILITY
543bool
544operator==(const scoped_allocator_adaptor<_OuterA1>& __a,
545           const scoped_allocator_adaptor<_OuterA2>& __b)
546{
547    return __a.outer_allocator() == __b.outer_allocator();
548}
549
550template <class _OuterA1, class _OuterA2, class _InnerA0, class... _InnerAllocs>
551inline _LIBCPP_INLINE_VISIBILITY
552bool
553operator==(const scoped_allocator_adaptor<_OuterA1, _InnerA0, _InnerAllocs...>& __a,
554           const scoped_allocator_adaptor<_OuterA2, _InnerA0, _InnerAllocs...>& __b)
555{
556    return __a.outer_allocator() == __b.outer_allocator() &&
557           __a.inner_allocator() == __b.inner_allocator();
558}
559
560template <class _OuterA1, class _OuterA2, class... _InnerAllocs>
561inline _LIBCPP_INLINE_VISIBILITY
562bool
563operator!=(const scoped_allocator_adaptor<_OuterA1, _InnerAllocs...>& __a,
564           const scoped_allocator_adaptor<_OuterA2, _InnerAllocs...>& __b)
565{
566    return !(__a == __b);
567}
568
569#endif  // !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_ADVANCED_SFINAE)
570
571_LIBCPP_END_NAMESPACE_STD
572
573#endif  // _LIBCPP_SCOPED_ALLOCATOR
574