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