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