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 ..._Allocs> struct __get_is_always_equal;
175
176template <class _A0>
177struct __get_is_always_equal<_A0>
178{
179    static const bool value = allocator_traits<_A0>::is_always_equal::value;
180};
181
182template <class _A0, class ..._Allocs>
183struct __get_is_always_equal<_A0, _Allocs...>
184{
185    static const bool value =
186        allocator_traits<_A0>::is_always_equal::value &&
187        __get_is_always_equal<_Allocs...>::value;
188};
189
190template <class ..._Allocs>
191class __scoped_allocator_storage;
192
193template <class _OuterAlloc, class... _InnerAllocs>
194class __scoped_allocator_storage<_OuterAlloc, _InnerAllocs...>
195    : public _OuterAlloc
196{
197    typedef _OuterAlloc outer_allocator_type;
198protected:
199    typedef scoped_allocator_adaptor<_InnerAllocs...> inner_allocator_type;
200
201private:
202    inner_allocator_type __inner_;
203
204protected:
205
206    _LIBCPP_INLINE_VISIBILITY
207    __scoped_allocator_storage() _NOEXCEPT {}
208
209    template <class _OuterA2,
210              class = typename enable_if<
211                        is_constructible<outer_allocator_type, _OuterA2>::value
212                      >::type>
213        _LIBCPP_INLINE_VISIBILITY
214        __scoped_allocator_storage(_OuterA2&& __outerAlloc,
215                                   const _InnerAllocs& ...__innerAllocs) _NOEXCEPT
216            : outer_allocator_type(_VSTD::forward<_OuterA2>(__outerAlloc)),
217              __inner_(__innerAllocs...) {}
218
219    template <class _OuterA2,
220              class = typename enable_if<
221                        is_constructible<outer_allocator_type, const _OuterA2&>::value
222                      >::type>
223        _LIBCPP_INLINE_VISIBILITY
224        __scoped_allocator_storage(
225            const __scoped_allocator_storage<_OuterA2, _InnerAllocs...>& __other) _NOEXCEPT
226            : outer_allocator_type(__other.outer_allocator()),
227              __inner_(__other.inner_allocator()) {}
228
229    template <class _OuterA2,
230              class = typename enable_if<
231                        is_constructible<outer_allocator_type, _OuterA2>::value
232                      >::type>
233        _LIBCPP_INLINE_VISIBILITY
234        __scoped_allocator_storage(
235            __scoped_allocator_storage<_OuterA2, _InnerAllocs...>&& __other) _NOEXCEPT
236            : outer_allocator_type(_VSTD::move(__other.outer_allocator())),
237              __inner_(_VSTD::move(__other.inner_allocator())) {}
238
239    template <class _OuterA2,
240              class = typename enable_if<
241                        is_constructible<outer_allocator_type, _OuterA2>::value
242                      >::type>
243        _LIBCPP_INLINE_VISIBILITY
244        __scoped_allocator_storage(_OuterA2&& __o,
245                                   const inner_allocator_type& __i) _NOEXCEPT
246            : outer_allocator_type(_VSTD::forward<_OuterA2>(__o)),
247              __inner_(__i)
248        {
249        }
250
251    _LIBCPP_INLINE_VISIBILITY
252    inner_allocator_type& inner_allocator() _NOEXCEPT             {return __inner_;}
253    _LIBCPP_INLINE_VISIBILITY
254    const inner_allocator_type& inner_allocator() const _NOEXCEPT {return __inner_;}
255
256    _LIBCPP_INLINE_VISIBILITY
257    outer_allocator_type& outer_allocator() _NOEXCEPT
258        {return static_cast<outer_allocator_type&>(*this);}
259    _LIBCPP_INLINE_VISIBILITY
260    const outer_allocator_type& outer_allocator() const _NOEXCEPT
261        {return static_cast<const outer_allocator_type&>(*this);}
262
263    scoped_allocator_adaptor<outer_allocator_type, _InnerAllocs...>
264    _LIBCPP_INLINE_VISIBILITY
265    select_on_container_copy_construction() const _NOEXCEPT
266        {
267            return scoped_allocator_adaptor<outer_allocator_type, _InnerAllocs...>
268            (
269                allocator_traits<outer_allocator_type>::
270                    select_on_container_copy_construction(outer_allocator()),
271                allocator_traits<inner_allocator_type>::
272                    select_on_container_copy_construction(inner_allocator())
273            );
274        }
275
276    template <class...> friend class __scoped_allocator_storage;
277};
278
279template <class _OuterAlloc>
280class __scoped_allocator_storage<_OuterAlloc>
281    : public _OuterAlloc
282{
283    typedef _OuterAlloc outer_allocator_type;
284protected:
285    typedef scoped_allocator_adaptor<_OuterAlloc> inner_allocator_type;
286
287    _LIBCPP_INLINE_VISIBILITY
288    __scoped_allocator_storage() _NOEXCEPT {}
289
290    template <class _OuterA2,
291              class = typename enable_if<
292                        is_constructible<outer_allocator_type, _OuterA2>::value
293                      >::type>
294        _LIBCPP_INLINE_VISIBILITY
295        __scoped_allocator_storage(_OuterA2&& __outerAlloc) _NOEXCEPT
296            : outer_allocator_type(_VSTD::forward<_OuterA2>(__outerAlloc)) {}
297
298    template <class _OuterA2,
299              class = typename enable_if<
300                        is_constructible<outer_allocator_type, const _OuterA2&>::value
301                      >::type>
302        _LIBCPP_INLINE_VISIBILITY
303        __scoped_allocator_storage(
304            const __scoped_allocator_storage<_OuterA2>& __other) _NOEXCEPT
305            : outer_allocator_type(__other.outer_allocator()) {}
306
307    template <class _OuterA2,
308              class = typename enable_if<
309                        is_constructible<outer_allocator_type, _OuterA2>::value
310                      >::type>
311        _LIBCPP_INLINE_VISIBILITY
312        __scoped_allocator_storage(
313            __scoped_allocator_storage<_OuterA2>&& __other) _NOEXCEPT
314            : outer_allocator_type(_VSTD::move(__other.outer_allocator())) {}
315
316    _LIBCPP_INLINE_VISIBILITY
317    inner_allocator_type& inner_allocator() _NOEXCEPT
318        {return static_cast<inner_allocator_type&>(*this);}
319    _LIBCPP_INLINE_VISIBILITY
320    const inner_allocator_type& inner_allocator() const _NOEXCEPT
321        {return static_cast<const inner_allocator_type&>(*this);}
322
323    _LIBCPP_INLINE_VISIBILITY
324    outer_allocator_type& outer_allocator() _NOEXCEPT
325        {return static_cast<outer_allocator_type&>(*this);}
326    _LIBCPP_INLINE_VISIBILITY
327    const outer_allocator_type& outer_allocator() const _NOEXCEPT
328        {return static_cast<const outer_allocator_type&>(*this);}
329
330    _LIBCPP_INLINE_VISIBILITY
331    scoped_allocator_adaptor<outer_allocator_type>
332    select_on_container_copy_construction() const _NOEXCEPT
333        {return scoped_allocator_adaptor<outer_allocator_type>(
334            allocator_traits<outer_allocator_type>::
335                select_on_container_copy_construction(outer_allocator())
336        );}
337
338    __scoped_allocator_storage(const outer_allocator_type& __o,
339                               const inner_allocator_type& __i) _NOEXCEPT;
340
341    template <class...> friend class __scoped_allocator_storage;
342};
343
344// __outermost
345
346template <class _Alloc>
347decltype(declval<_Alloc>().outer_allocator(), true_type())
348__has_outer_allocator_test(_Alloc&& __a);
349
350template <class _Alloc>
351false_type
352__has_outer_allocator_test(const volatile _Alloc& __a);
353
354template <class _Alloc>
355struct __has_outer_allocator
356    : public common_type
357             <
358                 decltype(__has_outer_allocator_test(declval<_Alloc&>()))
359             >::type
360{
361};
362
363template <class _Alloc, bool = __has_outer_allocator<_Alloc>::value>
364struct __outermost
365{
366    typedef _Alloc type;
367    _LIBCPP_INLINE_VISIBILITY
368    type& operator()(type& __a) const _NOEXCEPT {return __a;}
369};
370
371template <class _Alloc>
372struct __outermost<_Alloc, true>
373{
374    typedef typename remove_reference
375                     <
376                        decltype(_VSTD::declval<_Alloc>().outer_allocator())
377                     >::type                                    _OuterAlloc;
378    typedef typename __outermost<_OuterAlloc>::type             type;
379    _LIBCPP_INLINE_VISIBILITY
380    type& operator()(_Alloc& __a) const _NOEXCEPT
381        {return __outermost<_OuterAlloc>()(__a.outer_allocator());}
382};
383
384template <class _OuterAlloc, class... _InnerAllocs>
385class _LIBCPP_TYPE_VIS_ONLY scoped_allocator_adaptor<_OuterAlloc, _InnerAllocs...>
386    : public __scoped_allocator_storage<_OuterAlloc, _InnerAllocs...>
387{
388    typedef __scoped_allocator_storage<_OuterAlloc, _InnerAllocs...> base;
389    typedef allocator_traits<_OuterAlloc>             _OuterTraits;
390public:
391    typedef _OuterAlloc                               outer_allocator_type;
392    typedef typename base::inner_allocator_type       inner_allocator_type;
393    typedef typename _OuterTraits::size_type          size_type;
394    typedef typename _OuterTraits::difference_type    difference_type;
395    typedef typename _OuterTraits::pointer            pointer;
396    typedef typename _OuterTraits::const_pointer      const_pointer;
397    typedef typename _OuterTraits::void_pointer       void_pointer;
398    typedef typename _OuterTraits::const_void_pointer const_void_pointer;
399
400    typedef integral_constant
401            <
402                bool,
403                __get_poc_copy_assignment<outer_allocator_type,
404                                          _InnerAllocs...>::value
405            > propagate_on_container_copy_assignment;
406    typedef integral_constant
407            <
408                bool,
409                __get_poc_move_assignment<outer_allocator_type,
410                                          _InnerAllocs...>::value
411            > propagate_on_container_move_assignment;
412    typedef integral_constant
413            <
414                bool,
415                __get_poc_swap<outer_allocator_type, _InnerAllocs...>::value
416            > propagate_on_container_swap;
417    typedef integral_constant
418            <
419                bool,
420                __get_is_always_equal<outer_allocator_type, _InnerAllocs...>::value
421            > is_always_equal;
422
423    template <class _Tp>
424    struct rebind
425    {
426        typedef scoped_allocator_adaptor
427        <
428            typename _OuterTraits::template rebind_alloc<_Tp>, _InnerAllocs...
429        > other;
430    };
431
432    _LIBCPP_INLINE_VISIBILITY
433    scoped_allocator_adaptor() _NOEXCEPT {}
434    template <class _OuterA2,
435              class = typename enable_if<
436                        is_constructible<outer_allocator_type, _OuterA2>::value
437                      >::type>
438        _LIBCPP_INLINE_VISIBILITY
439        scoped_allocator_adaptor(_OuterA2&& __outerAlloc,
440                                 const _InnerAllocs& ...__innerAllocs) _NOEXCEPT
441            : base(_VSTD::forward<_OuterA2>(__outerAlloc), __innerAllocs...) {}
442    // scoped_allocator_adaptor(const scoped_allocator_adaptor& __other) = default;
443    template <class _OuterA2,
444              class = typename enable_if<
445                        is_constructible<outer_allocator_type, const _OuterA2&>::value
446                      >::type>
447        _LIBCPP_INLINE_VISIBILITY
448        scoped_allocator_adaptor(
449            const scoped_allocator_adaptor<_OuterA2, _InnerAllocs...>& __other) _NOEXCEPT
450                : base(__other) {}
451    template <class _OuterA2,
452              class = typename enable_if<
453                        is_constructible<outer_allocator_type, _OuterA2>::value
454                      >::type>
455        _LIBCPP_INLINE_VISIBILITY
456        scoped_allocator_adaptor(
457            scoped_allocator_adaptor<_OuterA2, _InnerAllocs...>&& __other) _NOEXCEPT
458                : base(_VSTD::move(__other)) {}
459
460    // ~scoped_allocator_adaptor() = default;
461
462    _LIBCPP_INLINE_VISIBILITY
463    inner_allocator_type& inner_allocator() _NOEXCEPT
464        {return base::inner_allocator();}
465    _LIBCPP_INLINE_VISIBILITY
466    const inner_allocator_type& inner_allocator() const _NOEXCEPT
467        {return base::inner_allocator();}
468
469    _LIBCPP_INLINE_VISIBILITY
470    outer_allocator_type& outer_allocator() _NOEXCEPT
471        {return base::outer_allocator();}
472    _LIBCPP_INLINE_VISIBILITY
473    const outer_allocator_type& outer_allocator() const _NOEXCEPT
474        {return base::outer_allocator();}
475
476    _LIBCPP_INLINE_VISIBILITY
477    pointer allocate(size_type __n)
478        {return allocator_traits<outer_allocator_type>::
479            allocate(outer_allocator(), __n);}
480    _LIBCPP_INLINE_VISIBILITY
481    pointer allocate(size_type __n, const_void_pointer __hint)
482        {return allocator_traits<outer_allocator_type>::
483            allocate(outer_allocator(), __n, __hint);}
484
485    _LIBCPP_INLINE_VISIBILITY
486    void deallocate(pointer __p, size_type __n) _NOEXCEPT
487        {allocator_traits<outer_allocator_type>::
488            deallocate(outer_allocator(), __p, __n);}
489
490    _LIBCPP_INLINE_VISIBILITY
491    size_type max_size() const
492        {return allocator_traits<outer_allocator_type>::max_size(outer_allocator());}
493
494    template <class _Tp, class... _Args>
495        _LIBCPP_INLINE_VISIBILITY
496        void construct(_Tp* __p, _Args&& ...__args)
497            {__construct(__uses_alloc_ctor<_Tp, inner_allocator_type, _Args...>(),
498                         __p, _VSTD::forward<_Args>(__args)...);}
499    template <class _Tp>
500        _LIBCPP_INLINE_VISIBILITY
501        void destroy(_Tp* __p)
502            {
503                typedef __outermost<outer_allocator_type> _OM;
504                allocator_traits<typename _OM::type>::
505                                         destroy(_OM()(outer_allocator()), __p);
506            }
507
508    _LIBCPP_INLINE_VISIBILITY
509    scoped_allocator_adaptor select_on_container_copy_construction() const _NOEXCEPT
510        {return base::select_on_container_copy_construction();}
511
512private:
513
514    template <class _OuterA2,
515              class = typename enable_if<
516                        is_constructible<outer_allocator_type, _OuterA2>::value
517                      >::type>
518    _LIBCPP_INLINE_VISIBILITY
519    scoped_allocator_adaptor(_OuterA2&& __o,
520                             const inner_allocator_type& __i) _NOEXCEPT
521        : base(_VSTD::forward<_OuterA2>(__o), __i) {}
522
523    template <class _Tp, class... _Args>
524        _LIBCPP_INLINE_VISIBILITY
525        void __construct(integral_constant<int, 0>, _Tp* __p, _Args&& ...__args)
526            {
527                typedef __outermost<outer_allocator_type> _OM;
528                allocator_traits<typename _OM::type>::construct
529                (
530                    _OM()(outer_allocator()),
531                    __p,
532                    _VSTD::forward<_Args>(__args)...
533                );
534            }
535
536    template <class _Tp, class... _Args>
537        _LIBCPP_INLINE_VISIBILITY
538        void __construct(integral_constant<int, 1>, _Tp* __p, _Args&& ...__args)
539            {
540                typedef __outermost<outer_allocator_type> _OM;
541                allocator_traits<typename _OM::type>::construct
542                (
543                    _OM()(outer_allocator()),
544                    __p,
545                    allocator_arg,
546                    inner_allocator(),
547                    _VSTD::forward<_Args>(__args)...
548                );
549            }
550
551    template <class _Tp, class... _Args>
552        _LIBCPP_INLINE_VISIBILITY
553        void __construct(integral_constant<int, 2>, _Tp* __p, _Args&& ...__args)
554            {
555                typedef __outermost<outer_allocator_type> _OM;
556                allocator_traits<typename _OM::type>::construct
557                (
558                    _OM()(outer_allocator()),
559                    __p,
560                    _VSTD::forward<_Args>(__args)...,
561                    inner_allocator()
562                );
563            }
564
565    template <class...> friend class __scoped_allocator_storage;
566};
567
568template <class _OuterA1, class _OuterA2>
569inline _LIBCPP_INLINE_VISIBILITY
570bool
571operator==(const scoped_allocator_adaptor<_OuterA1>& __a,
572           const scoped_allocator_adaptor<_OuterA2>& __b) _NOEXCEPT
573{
574    return __a.outer_allocator() == __b.outer_allocator();
575}
576
577template <class _OuterA1, class _OuterA2, class _InnerA0, class... _InnerAllocs>
578inline _LIBCPP_INLINE_VISIBILITY
579bool
580operator==(const scoped_allocator_adaptor<_OuterA1, _InnerA0, _InnerAllocs...>& __a,
581           const scoped_allocator_adaptor<_OuterA2, _InnerA0, _InnerAllocs...>& __b) _NOEXCEPT
582{
583    return __a.outer_allocator() == __b.outer_allocator() &&
584           __a.inner_allocator() == __b.inner_allocator();
585}
586
587template <class _OuterA1, class _OuterA2, class... _InnerAllocs>
588inline _LIBCPP_INLINE_VISIBILITY
589bool
590operator!=(const scoped_allocator_adaptor<_OuterA1, _InnerAllocs...>& __a,
591           const scoped_allocator_adaptor<_OuterA2, _InnerAllocs...>& __b) _NOEXCEPT
592{
593    return !(__a == __b);
594}
595
596#endif  // !defined(_LIBCPP_HAS_NO_RVALUE_REFERENCES) && !defined(_LIBCPP_HAS_NO_ADVANCED_SFINAE)
597
598_LIBCPP_END_NAMESPACE_STD
599
600#endif  // _LIBCPP_SCOPED_ALLOCATOR
601