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