1// <scoped_allocator> -*- C++ -*-
2
3// Copyright (C) 2011-2019 Free Software Foundation, Inc.
4//
5// This file is part of the GNU ISO C++ Library.  This library is free
6// software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 3, or (at your option)
9// any later version.
10
11// This library is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14// GNU General Public License for more details.
15
16// Under Section 7 of GPL version 3, you are granted additional
17// permissions described in the GCC Runtime Library Exception, version
18// 3.1, as published by the Free Software Foundation.
19
20// You should have received a copy of the GNU General Public License and
21// a copy of the GCC Runtime Library Exception along with this program;
22// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23// <http://www.gnu.org/licenses/>.
24
25/** @file include/scoped_allocator
26 *  This is a Standard C++ Library header.
27 */
28
29#ifndef _SCOPED_ALLOCATOR
30#define _SCOPED_ALLOCATOR 1
31
32#pragma GCC system_header
33
34#if __cplusplus < 201103L
35# include <bits/c++0x_warning.h>
36#else
37
38#include <memory>
39#include <utility>
40#include <tuple>
41#include <bits/alloc_traits.h>
42
43namespace std _GLIBCXX_VISIBILITY(default)
44{
45_GLIBCXX_BEGIN_NAMESPACE_VERSION
46
47  /**
48   * @addtogroup allocators
49   * @{
50   */
51
52  template<typename _Alloc>
53    using __outer_allocator_t
54      = decltype(std::declval<_Alloc>().outer_allocator());
55
56  template<typename _Alloc, typename = void>
57    struct __outermost_type
58    {
59      using type = _Alloc;
60      static type& _S_outermost(_Alloc& __a) { return __a; }
61    };
62
63  template<typename _Alloc>
64    struct __outermost_type<_Alloc, __void_t<__outer_allocator_t<_Alloc>>>
65    : __outermost_type<
66      typename remove_reference<__outer_allocator_t<_Alloc>>::type
67    >
68    {
69      using __base = __outermost_type<
70        typename remove_reference<__outer_allocator_t<_Alloc>>::type
71      >;
72
73      static typename __base::type&
74      _S_outermost(_Alloc& __a)
75      { return __base::_S_outermost(__a.outer_allocator()); }
76    };
77
78  template<typename _Alloc>
79    inline typename __outermost_type<_Alloc>::type&
80    __outermost(_Alloc& __a)
81    { return __outermost_type<_Alloc>::_S_outermost(__a); }
82
83  template<typename _OuterAlloc, typename... _InnerAllocs>
84    class scoped_allocator_adaptor;
85
86  template<typename...>
87    struct __inner_type_impl;
88
89  template<typename _Outer>
90    struct __inner_type_impl<_Outer>
91    {
92      typedef scoped_allocator_adaptor<_Outer> __type;
93
94      __inner_type_impl() = default;
95      __inner_type_impl(const __inner_type_impl&) = default;
96      __inner_type_impl(__inner_type_impl&&) = default;
97      __inner_type_impl& operator=(const __inner_type_impl&) = default;
98      __inner_type_impl& operator=(__inner_type_impl&&) = default;
99
100      template<typename _Alloc>
101      __inner_type_impl(const __inner_type_impl<_Alloc>& __other)
102      { }
103
104      template<typename _Alloc>
105      __inner_type_impl(__inner_type_impl<_Alloc>&& __other)
106      { }
107
108      __type&
109      _M_get(__type* __p) noexcept { return *__p; }
110
111      const __type&
112      _M_get(const __type* __p) const noexcept { return *__p; }
113
114      tuple<>
115      _M_tie() const noexcept { return tuple<>(); }
116
117      bool
118      operator==(const __inner_type_impl&) const noexcept
119      { return true; }
120    };
121
122  template<typename _Outer, typename _InnerHead, typename... _InnerTail>
123    struct __inner_type_impl<_Outer, _InnerHead, _InnerTail...>
124    {
125      typedef scoped_allocator_adaptor<_InnerHead, _InnerTail...> __type;
126
127      __inner_type_impl() = default;
128      __inner_type_impl(const __inner_type_impl&) = default;
129      __inner_type_impl(__inner_type_impl&&) = default;
130      __inner_type_impl& operator=(const __inner_type_impl&) = default;
131      __inner_type_impl& operator=(__inner_type_impl&&) = default;
132
133      template<typename... _Allocs>
134      __inner_type_impl(const __inner_type_impl<_Allocs...>& __other)
135      : _M_inner(__other._M_inner) { }
136
137      template<typename... _Allocs>
138      __inner_type_impl(__inner_type_impl<_Allocs...>&& __other)
139      : _M_inner(std::move(__other._M_inner)) { }
140
141    template<typename... _Args>
142      explicit
143      __inner_type_impl(_Args&&... __args)
144      : _M_inner(std::forward<_Args>(__args)...) { }
145
146      __type&
147      _M_get(void*) noexcept { return _M_inner; }
148
149      const __type&
150      _M_get(const void*) const noexcept { return _M_inner; }
151
152      tuple<const _InnerHead&, const _InnerTail&...>
153      _M_tie() const noexcept
154      { return _M_inner._M_tie(); }
155
156      bool
157      operator==(const __inner_type_impl& __other) const noexcept
158      { return _M_inner == __other._M_inner; }
159
160    private:
161      template<typename...> friend class __inner_type_impl;
162      template<typename, typename...> friend class scoped_allocator_adaptor;
163
164      __type _M_inner;
165    };
166
167  /// Primary class template.
168  template<typename _OuterAlloc, typename... _InnerAllocs>
169    class scoped_allocator_adaptor
170    : public _OuterAlloc
171    {
172      typedef allocator_traits<_OuterAlloc> __traits;
173
174      typedef __inner_type_impl<_OuterAlloc, _InnerAllocs...> __inner_type;
175      __inner_type _M_inner;
176
177      template<typename _Outer, typename... _Inner>
178        friend class scoped_allocator_adaptor;
179
180      template<typename...>
181        friend class __inner_type_impl;
182
183      tuple<const _OuterAlloc&, const _InnerAllocs&...>
184      _M_tie() const noexcept
185      { return std::tuple_cat(std::tie(outer_allocator()), _M_inner._M_tie()); }
186
187      template<typename _Alloc>
188	using __outermost_alloc_traits
189	  = allocator_traits<typename __outermost_type<_Alloc>::type>;
190
191#if __cplusplus <= 201703
192      template<typename _Tp, typename... _Args>
193        void
194        _M_construct(__uses_alloc0, _Tp* __p, _Args&&... __args)
195        {
196	  typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits;
197	  _O_traits::construct(__outermost(*this), __p,
198			       std::forward<_Args>(__args)...);
199        }
200
201      typedef __uses_alloc1<typename __inner_type::__type> __uses_alloc1_;
202      typedef __uses_alloc2<typename __inner_type::__type> __uses_alloc2_;
203
204      template<typename _Tp, typename... _Args>
205        void
206        _M_construct(__uses_alloc1_, _Tp* __p, _Args&&... __args)
207        {
208	  typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits;
209	  _O_traits::construct(__outermost(*this), __p,
210			       allocator_arg, inner_allocator(),
211			       std::forward<_Args>(__args)...);
212        }
213
214      template<typename _Tp, typename... _Args>
215        void
216        _M_construct(__uses_alloc2_, _Tp* __p, _Args&&... __args)
217        {
218	  typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits;
219	  _O_traits::construct(__outermost(*this), __p,
220			       std::forward<_Args>(__args)...,
221			       inner_allocator());
222        }
223#endif // C++17
224
225      template<typename _Alloc>
226        static _Alloc
227        _S_select_on_copy(const _Alloc& __a)
228        {
229          typedef allocator_traits<_Alloc> __a_traits;
230          return __a_traits::select_on_container_copy_construction(__a);
231        }
232
233      template<std::size_t... _Indices>
234        scoped_allocator_adaptor(tuple<const _OuterAlloc&,
235                                       const _InnerAllocs&...> __refs,
236                                 _Index_tuple<_Indices...>)
237        : _OuterAlloc(_S_select_on_copy(std::get<0>(__refs))),
238          _M_inner(_S_select_on_copy(std::get<_Indices+1>(__refs))...)
239        { }
240
241      // Used to constrain constructors to disallow invalid conversions.
242      template<typename _Alloc>
243        using _Constructible = typename enable_if<
244            is_constructible<_OuterAlloc, _Alloc>::value
245          >::type;
246
247      // _GLIBCXX_RESOLVE_LIB_DEFECTS
248      // 2975. Missing case for pair construction in scoped [...] allocators
249      template<typename _Tp>
250	struct __not_pair { using type = void; };
251
252      template<typename _Tp, typename _Up>
253	struct __not_pair<pair<_Tp, _Up>> { };
254
255    public:
256      typedef _OuterAlloc                       outer_allocator_type;
257      typedef typename __inner_type::__type     inner_allocator_type;
258
259      typedef typename __traits::value_type             value_type;
260      typedef typename __traits::size_type              size_type;
261      typedef typename __traits::difference_type        difference_type;
262      typedef typename __traits::pointer                pointer;
263      typedef typename __traits::const_pointer          const_pointer;
264      typedef typename __traits::void_pointer           void_pointer;
265      typedef typename __traits::const_void_pointer     const_void_pointer;
266
267      typedef typename __or_<
268	typename __traits::propagate_on_container_copy_assignment,
269	typename allocator_traits<_InnerAllocs>::
270	  propagate_on_container_copy_assignment...>::type
271	  propagate_on_container_copy_assignment;
272
273      typedef typename __or_<
274	typename __traits::propagate_on_container_move_assignment,
275	typename allocator_traits<_InnerAllocs>::
276	  propagate_on_container_move_assignment...>::type
277	  propagate_on_container_move_assignment;
278
279      typedef typename __or_<
280	typename __traits::propagate_on_container_swap,
281	typename allocator_traits<_InnerAllocs>::
282	  propagate_on_container_swap...>::type
283	  propagate_on_container_swap;
284
285      typedef typename __and_<
286	typename __traits::is_always_equal,
287	typename allocator_traits<_InnerAllocs>::is_always_equal...>::type
288	  is_always_equal;
289
290      template <class _Tp>
291        struct rebind
292        {
293          typedef scoped_allocator_adaptor<
294            typename __traits::template rebind_alloc<_Tp>,
295            _InnerAllocs...> other;
296        };
297
298      scoped_allocator_adaptor() : _OuterAlloc(), _M_inner() { }
299
300      template<typename _Outer2, typename = _Constructible<_Outer2>>
301        scoped_allocator_adaptor(_Outer2&& __outer,
302                                 const _InnerAllocs&... __inner)
303        : _OuterAlloc(std::forward<_Outer2>(__outer)),
304          _M_inner(__inner...)
305        { }
306
307      scoped_allocator_adaptor(const scoped_allocator_adaptor& __other)
308      : _OuterAlloc(__other.outer_allocator()),
309	_M_inner(__other._M_inner)
310      { }
311
312      scoped_allocator_adaptor(scoped_allocator_adaptor&& __other)
313      : _OuterAlloc(std::move(__other.outer_allocator())),
314	_M_inner(std::move(__other._M_inner))
315      { }
316
317      template<typename _Outer2, typename = _Constructible<const _Outer2&>>
318        scoped_allocator_adaptor(
319            const scoped_allocator_adaptor<_Outer2, _InnerAllocs...>& __other)
320        : _OuterAlloc(__other.outer_allocator()),
321          _M_inner(__other._M_inner)
322        { }
323
324      template<typename _Outer2, typename = _Constructible<_Outer2>>
325        scoped_allocator_adaptor(
326            scoped_allocator_adaptor<_Outer2, _InnerAllocs...>&& __other)
327        : _OuterAlloc(std::move(__other.outer_allocator())),
328          _M_inner(std::move(__other._M_inner))
329        { }
330
331      scoped_allocator_adaptor&
332      operator=(const scoped_allocator_adaptor&) = default;
333
334      scoped_allocator_adaptor&
335      operator=(scoped_allocator_adaptor&&) = default;
336
337      inner_allocator_type& inner_allocator() noexcept
338      { return _M_inner._M_get(this); }
339
340      const inner_allocator_type& inner_allocator() const noexcept
341      { return _M_inner._M_get(this); }
342
343      outer_allocator_type& outer_allocator() noexcept
344      { return static_cast<_OuterAlloc&>(*this); }
345
346      const outer_allocator_type& outer_allocator() const noexcept
347      { return static_cast<const _OuterAlloc&>(*this); }
348
349      _GLIBCXX_NODISCARD pointer allocate(size_type __n)
350      { return __traits::allocate(outer_allocator(), __n); }
351
352      _GLIBCXX_NODISCARD pointer allocate(size_type __n, const_void_pointer __hint)
353      { return __traits::allocate(outer_allocator(), __n, __hint); }
354
355      void deallocate(pointer __p, size_type __n)
356      { return __traits::deallocate(outer_allocator(), __p, __n); }
357
358      size_type max_size() const
359      { return __traits::max_size(outer_allocator()); }
360
361#if __cplusplus <= 201703
362      template<typename _Tp, typename... _Args>
363	typename __not_pair<_Tp>::type
364	construct(_Tp* __p, _Args&&... __args)
365	{
366	  auto& __inner = inner_allocator();
367	  auto __use_tag
368	    = std::__use_alloc<_Tp, inner_allocator_type, _Args...>(__inner);
369	  _M_construct(__use_tag, __p, std::forward<_Args>(__args)...);
370	}
371
372      template<typename _T1, typename _T2, typename... _Args1,
373	       typename... _Args2>
374	void
375	construct(pair<_T1, _T2>* __p, piecewise_construct_t,
376		  tuple<_Args1...> __x, tuple<_Args2...> __y)
377	{
378	  // _GLIBCXX_RESOLVE_LIB_DEFECTS
379	  // 2203.  wrong argument types for piecewise construction
380	  auto& __inner = inner_allocator();
381	  auto __x_use_tag
382	    = std::__use_alloc<_T1, inner_allocator_type, _Args1...>(__inner);
383	  auto __y_use_tag
384	    = std::__use_alloc<_T2, inner_allocator_type, _Args2...>(__inner);
385	  typename _Build_index_tuple<sizeof...(_Args1)>::__type __x_indices;
386	  typename _Build_index_tuple<sizeof...(_Args2)>::__type __y_indices;
387	  typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits;
388	  _O_traits::construct(__outermost(*this), __p, piecewise_construct,
389			       _M_construct_p(__x_use_tag, __x_indices, __x),
390			       _M_construct_p(__y_use_tag, __y_indices, __y));
391	}
392
393      template<typename _T1, typename _T2>
394	void
395	construct(pair<_T1, _T2>* __p)
396	{ construct(__p, piecewise_construct, tuple<>(), tuple<>()); }
397
398      template<typename _T1, typename _T2, typename _Up, typename _Vp>
399	void
400	construct(pair<_T1, _T2>* __p, _Up&& __u, _Vp&& __v)
401	{
402	  construct(__p, piecewise_construct,
403		    std::forward_as_tuple(std::forward<_Up>(__u)),
404		    std::forward_as_tuple(std::forward<_Vp>(__v)));
405	}
406
407      template<typename _T1, typename _T2, typename _Up, typename _Vp>
408	void
409	construct(pair<_T1, _T2>* __p, const pair<_Up, _Vp>& __x)
410	{
411	  construct(__p, piecewise_construct,
412		    std::forward_as_tuple(__x.first),
413		    std::forward_as_tuple(__x.second));
414	}
415
416      template<typename _T1, typename _T2, typename _Up, typename _Vp>
417	void
418	construct(pair<_T1, _T2>* __p, pair<_Up, _Vp>&& __x)
419	{
420	  construct(__p, piecewise_construct,
421		    std::forward_as_tuple(std::forward<_Up>(__x.first)),
422		    std::forward_as_tuple(std::forward<_Vp>(__x.second)));
423	}
424#else // C++2a
425      template<typename _Tp, typename... _Args>
426	__attribute__((__nonnull__))
427	void
428	construct(_Tp* __p, _Args&&... __args)
429	{
430	  typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits;
431	  std::apply([__p, this](auto&&... __newargs) {
432	      _O_traits::construct(__outermost(*this), __p,
433		  std::forward<decltype(__newargs)>(__newargs)...);
434	  },
435	  uses_allocator_construction_args<_Tp>(inner_allocator(),
436	    std::forward<_Args>(__args)...));
437	}
438#endif // C++2a
439
440      template<typename _Tp>
441        void destroy(_Tp* __p)
442        {
443	  typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits;
444	  _O_traits::destroy(__outermost(*this), __p);
445	}
446
447      scoped_allocator_adaptor
448      select_on_container_copy_construction() const
449      {
450        typedef typename _Build_index_tuple<sizeof...(_InnerAllocs)>::__type
451	    _Indices;
452        return scoped_allocator_adaptor(_M_tie(), _Indices());
453      }
454
455      template <typename _OutA1, typename _OutA2, typename... _InA>
456      friend bool
457      operator==(const scoped_allocator_adaptor<_OutA1, _InA...>& __a,
458                 const scoped_allocator_adaptor<_OutA2, _InA...>& __b) noexcept;
459
460    private:
461#if __cplusplus <= 201703L
462      template<typename _Ind, typename... _Args>
463	tuple<_Args&&...>
464	_M_construct_p(__uses_alloc0, _Ind, tuple<_Args...>& __t)
465	{ return std::move(__t); }
466
467      template<size_t... _Ind, typename... _Args>
468	tuple<allocator_arg_t, inner_allocator_type&, _Args&&...>
469	_M_construct_p(__uses_alloc1_, _Index_tuple<_Ind...>,
470		       tuple<_Args...>& __t)
471	{
472	  return { allocator_arg, inner_allocator(),
473	      std::get<_Ind>(std::move(__t))...
474	  };
475	}
476
477      template<size_t... _Ind, typename... _Args>
478	tuple<_Args&&..., inner_allocator_type&>
479	_M_construct_p(__uses_alloc2_, _Index_tuple<_Ind...>,
480		       tuple<_Args...>& __t)
481	{
482	  return { std::get<_Ind>(std::move(__t))..., inner_allocator() };
483	}
484#endif // C++17
485    };
486
487  template <typename _OutA1, typename _OutA2, typename... _InA>
488    inline bool
489    operator==(const scoped_allocator_adaptor<_OutA1, _InA...>& __a,
490               const scoped_allocator_adaptor<_OutA2, _InA...>& __b) noexcept
491    {
492      return __a.outer_allocator() == __b.outer_allocator()
493          && __a._M_inner == __b._M_inner;
494    }
495
496  template <typename _OutA1, typename _OutA2, typename... _InA>
497    inline bool
498    operator!=(const scoped_allocator_adaptor<_OutA1, _InA...>& __a,
499               const scoped_allocator_adaptor<_OutA2, _InA...>& __b) noexcept
500    { return !(__a == __b); }
501
502  /// @}
503
504_GLIBCXX_END_NAMESPACE_VERSION
505} // namespace
506
507#endif // C++11
508
509#endif // _SCOPED_ALLOCATOR
510