libstdc++
scoped_allocator
Go to the documentation of this file.
1 // <scoped_allocator> -*- C++ -*-
2 
3 // Copyright (C) 2011-2016 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 <utility>
39 #include <tuple>
40 #include <bits/alloc_traits.h>
41 
42 namespace std _GLIBCXX_VISIBILITY(default)
43 {
44 _GLIBCXX_BEGIN_NAMESPACE_VERSION
45 
46  /**
47  * @addtogroup allocators
48  * @{
49  */
50 
51  template<typename _Alloc>
52  inline auto
53  __do_outermost(_Alloc& __a, int) -> decltype(__a.outer_allocator())
54  { return __a.outer_allocator(); }
55 
56  template<typename _Alloc>
57  inline _Alloc&
58  __do_outermost(_Alloc& __a, ...)
59  { return __a; }
60 
61  // TODO: make recursive (see note in 20.12.4/1)
62  template<typename _Alloc>
63  inline auto
64  __outermost(_Alloc& __a)
65  -> decltype(__do_outermost(__a, 0))
66  { return __do_outermost(__a, 0); }
67 
68  template<typename _OuterAlloc, typename... _InnerAllocs>
69  class scoped_allocator_adaptor;
70 
71  template<typename...>
72  struct __inner_type_impl;
73 
74  template<typename _Outer>
75  struct __inner_type_impl<_Outer>
76  {
77  typedef scoped_allocator_adaptor<_Outer> __type;
78 
79  __inner_type_impl() = default;
80  __inner_type_impl(const __inner_type_impl&) = default;
81  __inner_type_impl(__inner_type_impl&&) = default;
82  __inner_type_impl& operator=(const __inner_type_impl&) = default;
83  __inner_type_impl& operator=(__inner_type_impl&&) = default;
84 
85  template<typename _Alloc>
86  __inner_type_impl(const __inner_type_impl<_Alloc>& __other)
87  { }
88 
89  template<typename _Alloc>
90  __inner_type_impl(__inner_type_impl<_Alloc>&& __other)
91  { }
92 
93  __type&
94  _M_get(__type* __p) noexcept { return *__p; }
95 
96  const __type&
97  _M_get(const __type* __p) const noexcept { return *__p; }
98 
99  tuple<>
100  _M_tie() const noexcept { return tuple<>(); }
101 
102  bool
103  operator==(const __inner_type_impl&) const noexcept
104  { return true; }
105  };
106 
107  template<typename _Outer, typename _InnerHead, typename... _InnerTail>
108  struct __inner_type_impl<_Outer, _InnerHead, _InnerTail...>
109  {
110  typedef scoped_allocator_adaptor<_InnerHead, _InnerTail...> __type;
111 
112  __inner_type_impl() = default;
113  __inner_type_impl(const __inner_type_impl&) = default;
114  __inner_type_impl(__inner_type_impl&&) = default;
115  __inner_type_impl& operator=(const __inner_type_impl&) = default;
116  __inner_type_impl& operator=(__inner_type_impl&&) = default;
117 
118  template<typename... _Allocs>
119  __inner_type_impl(const __inner_type_impl<_Allocs...>& __other)
120  : _M_inner(__other._M_inner) { }
121 
122  template<typename... _Allocs>
123  __inner_type_impl(__inner_type_impl<_Allocs...>&& __other)
124  : _M_inner(std::move(__other._M_inner)) { }
125 
126  template<typename... _Args>
127  explicit
128  __inner_type_impl(_Args&&... __args)
129  : _M_inner(std::forward<_Args>(__args)...) { }
130 
131  __type&
132  _M_get(void*) noexcept { return _M_inner; }
133 
134  const __type&
135  _M_get(const void*) const noexcept { return _M_inner; }
136 
137  tuple<const _InnerHead&, const _InnerTail&...>
138  _M_tie() const noexcept
139  { return _M_inner._M_tie(); }
140 
141  bool
142  operator==(const __inner_type_impl& __other) const noexcept
143  { return _M_inner == __other._M_inner; }
144 
145  private:
146  template<typename...> friend class __inner_type_impl;
147  template<typename, typename...> friend class scoped_allocator_adaptor;
148 
149  __type _M_inner;
150  };
151 
152  /// Primary class template.
153  template<typename _OuterAlloc, typename... _InnerAllocs>
154  class scoped_allocator_adaptor
155  : public _OuterAlloc
156  {
157  typedef allocator_traits<_OuterAlloc> __traits;
158 
159  typedef __inner_type_impl<_OuterAlloc, _InnerAllocs...> __inner_type;
160  __inner_type _M_inner;
161 
162  template<typename _Outer, typename... _Inner>
163  friend class scoped_allocator_adaptor;
164 
165  template<typename...>
166  friend class __inner_type_impl;
167 
168  tuple<const _OuterAlloc&, const _InnerAllocs&...>
169  _M_tie() const noexcept
170  { return std::tuple_cat(std::tie(outer_allocator()), _M_inner._M_tie()); }
171 
172  template<typename _Alloc>
173  using __outermost_type = typename
174  std::decay<decltype(__outermost(std::declval<_Alloc&>()))>::type;
175 
176  template<typename _Alloc>
177  using __outermost_alloc_traits
178  = allocator_traits<__outermost_type<_Alloc>>;
179 
180  template<typename _Tp, typename... _Args>
181  void
182  _M_construct(__uses_alloc0, _Tp* __p, _Args&&... __args)
183  {
184  typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits;
185  _O_traits::construct(__outermost(*this), __p,
186  std::forward<_Args>(__args)...);
187  }
188 
189  typedef __uses_alloc1<typename __inner_type::__type> __uses_alloc1_;
190  typedef __uses_alloc2<typename __inner_type::__type> __uses_alloc2_;
191 
192  template<typename _Tp, typename... _Args>
193  void
194  _M_construct(__uses_alloc1_, _Tp* __p, _Args&&... __args)
195  {
196  typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits;
197  _O_traits::construct(__outermost(*this), __p,
198  allocator_arg, inner_allocator(),
199  std::forward<_Args>(__args)...);
200  }
201 
202  template<typename _Tp, typename... _Args>
203  void
204  _M_construct(__uses_alloc2_, _Tp* __p, _Args&&... __args)
205  {
206  typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits;
207  _O_traits::construct(__outermost(*this), __p,
208  std::forward<_Args>(__args)...,
209  inner_allocator());
210  }
211 
212  template<typename _Alloc>
213  static _Alloc
214  _S_select_on_copy(const _Alloc& __a)
215  {
216  typedef allocator_traits<_Alloc> __a_traits;
217  return __a_traits::select_on_container_copy_construction(__a);
218  }
219 
220  template<std::size_t... _Indices>
221  scoped_allocator_adaptor(tuple<const _OuterAlloc&,
222  const _InnerAllocs&...> __refs,
223  _Index_tuple<_Indices...>)
224  : _OuterAlloc(_S_select_on_copy(std::get<0>(__refs))),
225  _M_inner(_S_select_on_copy(std::get<_Indices+1>(__refs))...)
226  { }
227 
228  public:
229  typedef _OuterAlloc outer_allocator_type;
230  typedef typename __inner_type::__type inner_allocator_type;
231 
232  typedef typename __traits::value_type value_type;
233  typedef typename __traits::size_type size_type;
234  typedef typename __traits::difference_type difference_type;
235  typedef typename __traits::pointer pointer;
236  typedef typename __traits::const_pointer const_pointer;
237  typedef typename __traits::void_pointer void_pointer;
238  typedef typename __traits::const_void_pointer const_void_pointer;
239 
240  typedef typename __or_<
241  typename __traits::propagate_on_container_copy_assignment,
242  typename allocator_traits<_InnerAllocs>::
243  propagate_on_container_copy_assignment...>::type
244  propagate_on_container_copy_assignment;
245 
246  typedef typename __or_<
247  typename __traits::propagate_on_container_move_assignment,
248  typename allocator_traits<_InnerAllocs>::
249  propagate_on_container_move_assignment...>::type
250  propagate_on_container_move_assignment;
251 
252  typedef typename __or_<
253  typename __traits::propagate_on_container_swap,
254  typename allocator_traits<_InnerAllocs>::
255  propagate_on_container_swap...>::type
256  propagate_on_container_swap;
257 
258  typedef typename __and_<
259  typename __traits::is_always_equal,
260  typename allocator_traits<_InnerAllocs>::is_always_equal...>::type
261  is_always_equal;
262 
263  template <class _Tp>
264  struct rebind
265  {
266  typedef scoped_allocator_adaptor<
267  typename __traits::template rebind_alloc<_Tp>,
268  _InnerAllocs...> other;
269  };
270 
271  scoped_allocator_adaptor() : _OuterAlloc(), _M_inner() { }
272 
273  template<typename _Outer2>
274  scoped_allocator_adaptor(_Outer2&& __outer,
275  const _InnerAllocs&... __inner)
276  : _OuterAlloc(std::forward<_Outer2>(__outer)),
277  _M_inner(__inner...)
278  { }
279 
280  scoped_allocator_adaptor(const scoped_allocator_adaptor& __other)
281  : _OuterAlloc(__other.outer_allocator()),
282  _M_inner(__other._M_inner)
283  { }
284 
285  scoped_allocator_adaptor(scoped_allocator_adaptor&& __other)
286  : _OuterAlloc(std::move(__other.outer_allocator())),
287  _M_inner(std::move(__other._M_inner))
288  { }
289 
290  template<typename _Outer2>
291  scoped_allocator_adaptor(
292  const scoped_allocator_adaptor<_Outer2, _InnerAllocs...>& __other)
293  : _OuterAlloc(__other.outer_allocator()),
294  _M_inner(__other._M_inner)
295  { }
296 
297  template<typename _Outer2>
298  scoped_allocator_adaptor(
299  scoped_allocator_adaptor<_Outer2, _InnerAllocs...>&& __other)
300  : _OuterAlloc(std::move(__other.outer_allocator())),
301  _M_inner(std::move(__other._M_inner))
302  { }
303 
304  scoped_allocator_adaptor&
305  operator=(const scoped_allocator_adaptor&) = default;
306 
307  scoped_allocator_adaptor&
308  operator=(scoped_allocator_adaptor&&) = default;
309 
310  inner_allocator_type& inner_allocator() noexcept
311  { return _M_inner._M_get(this); }
312 
313  const inner_allocator_type& inner_allocator() const noexcept
314  { return _M_inner._M_get(this); }
315 
316  outer_allocator_type& outer_allocator() noexcept
317  { return static_cast<_OuterAlloc&>(*this); }
318 
319  const outer_allocator_type& outer_allocator() const noexcept
320  { return static_cast<const _OuterAlloc&>(*this); }
321 
322  pointer allocate(size_type __n)
323  { return __traits::allocate(outer_allocator(), __n); }
324 
325  pointer allocate(size_type __n, const_void_pointer __hint)
326  { return __traits::allocate(outer_allocator(), __n, __hint); }
327 
328  void deallocate(pointer __p, size_type __n)
329  { return __traits::deallocate(outer_allocator(), __p, __n); }
330 
331  size_type max_size() const
332  { return __traits::max_size(outer_allocator()); }
333 
334  template<typename _Tp, typename... _Args>
335  void construct(_Tp* __p, _Args&&... __args)
336  {
337  auto& __inner = inner_allocator();
338  auto __use_tag
339  = __use_alloc<_Tp, inner_allocator_type, _Args...>(__inner);
340  _M_construct(__use_tag, __p, std::forward<_Args>(__args)...);
341  }
342 
343  template<typename _T1, typename _T2, typename... _Args1,
344  typename... _Args2>
345  void
346  construct(pair<_T1, _T2>* __p, piecewise_construct_t,
347  tuple<_Args1...> __x, tuple<_Args2...> __y)
348  {
349  // _GLIBCXX_RESOLVE_LIB_DEFECTS
350  // 2203. wrong argument types for piecewise construction
351  auto& __inner = inner_allocator();
352  auto __x_use_tag
353  = __use_alloc<_T1, inner_allocator_type, _Args1...>(__inner);
354  auto __y_use_tag
355  = __use_alloc<_T2, inner_allocator_type, _Args2...>(__inner);
356  typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits;
357  _O_traits::construct(__outermost(*this), __p, piecewise_construct,
358  _M_construct_p(__x_use_tag, __x),
359  _M_construct_p(__y_use_tag, __y));
360  }
361 
362  template<typename _T1, typename _T2>
363  void
364  construct(pair<_T1, _T2>* __p)
365  { construct(__p, piecewise_construct, tuple<>(), tuple<>()); }
366 
367  template<typename _T1, typename _T2, typename _Up, typename _Vp>
368  void
369  construct(pair<_T1, _T2>* __p, _Up&& __u, _Vp&& __v)
370  {
371  construct(__p, piecewise_construct,
372  std::forward_as_tuple(std::forward<_Up>(__u)),
373  std::forward_as_tuple(std::forward<_Vp>(__v)));
374  }
375 
376  template<typename _T1, typename _T2, typename _Up, typename _Vp>
377  void
378  construct(pair<_T1, _T2>* __p, const pair<_Up, _Vp>& __x)
379  {
380  construct(__p, piecewise_construct,
381  std::forward_as_tuple(__x.first),
382  std::forward_as_tuple(__x.second));
383  }
384 
385  template<typename _T1, typename _T2, typename _Up, typename _Vp>
386  void
387  construct(pair<_T1, _T2>* __p, pair<_Up, _Vp>&& __x)
388  {
389  construct(__p, piecewise_construct,
390  std::forward_as_tuple(std::forward<_Up>(__x.first)),
391  std::forward_as_tuple(std::forward<_Vp>(__x.second)));
392  }
393 
394  template<typename _Tp>
395  void destroy(_Tp* __p)
396  {
397  typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits;
398  _O_traits::destroy(__outermost(*this), __p);
399  }
400 
401  scoped_allocator_adaptor
402  select_on_container_copy_construction() const
403  {
404  typedef typename _Build_index_tuple<sizeof...(_InnerAllocs)>::__type
405  _Indices;
406  return scoped_allocator_adaptor(_M_tie(), _Indices());
407  }
408 
409  template <typename _OutA1, typename _OutA2, typename... _InA>
410  friend bool
411  operator==(const scoped_allocator_adaptor<_OutA1, _InA...>& __a,
412  const scoped_allocator_adaptor<_OutA2, _InA...>& __b) noexcept;
413 
414  private:
415  template<typename _Tuple>
416  _Tuple&&
417  _M_construct_p(__uses_alloc0, _Tuple& __t)
418  { return std::move(__t); }
419 
420  template<typename... _Args>
421  std::tuple<allocator_arg_t, inner_allocator_type&, _Args...>
422  _M_construct_p(__uses_alloc1_, std::tuple<_Args...>& __t)
423  {
424  typedef std::tuple<allocator_arg_t, inner_allocator_type&> _Tuple;
425  return std::tuple_cat(_Tuple(allocator_arg, inner_allocator()),
426  std::move(__t));
427  }
428 
429  template<typename... _Args>
430  std::tuple<_Args..., inner_allocator_type&>
431  _M_construct_p(__uses_alloc2_, std::tuple<_Args...>& __t)
432  {
433  typedef std::tuple<inner_allocator_type&> _Tuple;
434  return std::tuple_cat(std::move(__t), _Tuple(inner_allocator()));
435  }
436  };
437 
438  template <typename _OutA1, typename _OutA2, typename... _InA>
439  inline bool
440  operator==(const scoped_allocator_adaptor<_OutA1, _InA...>& __a,
441  const scoped_allocator_adaptor<_OutA2, _InA...>& __b) noexcept
442  {
443  return __a.outer_allocator() == __b.outer_allocator()
444  && __a._M_inner == __b._M_inner;
445  }
446 
447  template <typename _OutA1, typename _OutA2, typename... _InA>
448  inline bool
449  operator!=(const scoped_allocator_adaptor<_OutA1, _InA...>& __a,
450  const scoped_allocator_adaptor<_OutA2, _InA...>& __b) noexcept
451  { return !(__a == __b); }
452 
453  /// @}
454 
455 _GLIBCXX_END_NAMESPACE_VERSION
456 } // namespace
457 
458 #endif // C++11
459 
460 #endif // _SCOPED_ALLOCATOR