change support python version
[platform/upstream/boost.git] / boost / container / scoped_allocator.hpp
1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Pablo Halpern 2009. Distributed under the Boost
4 // Software License, Version 1.0. (See accompanying file
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 //////////////////////////////////////////////////////////////////////////////
8 //
9 // (C) Copyright Ion Gaztanaga 2011-2013. Distributed under the Boost
10 // Software License, Version 1.0. (See accompanying file
11 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
12 //
13 // See http://www.boost.org/libs/container for documentation.
14 //
15 //////////////////////////////////////////////////////////////////////////////
16
17 #ifndef BOOST_CONTAINER_ALLOCATOR_SCOPED_ALLOCATOR_HPP
18 #define BOOST_CONTAINER_ALLOCATOR_SCOPED_ALLOCATOR_HPP
19
20 #if defined (_MSC_VER)
21 #  pragma once 
22 #endif
23
24 #include <boost/container/detail/config_begin.hpp>
25 #include <boost/container/detail/workaround.hpp>
26
27 #include <boost/container/allocator_traits.hpp>
28 #include <boost/container/scoped_allocator_fwd.hpp>
29 #include <boost/container/detail/dispatch_uses_allocator.hpp>
30
31 #include <boost/container/detail/mpl.hpp>
32 #include <boost/container/detail/pair.hpp>
33 #include <boost/container/detail/type_traits.hpp>
34
35 #include <boost/move/adl_move_swap.hpp>
36 #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
37 #include <boost/move/detail/fwd_macros.hpp>
38 #endif
39 #include <boost/move/utility_core.hpp>
40
41 #include <boost/core/no_exceptions_support.hpp>
42
43 namespace boost { namespace container {
44
45 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
46
47 namespace dtl {
48
49 template <typename Allocator>
50 struct is_scoped_allocator_imp
51 {
52    typedef char yes_type;
53    struct no_type{ char dummy[2]; };
54
55    template <typename T>
56    static yes_type test(typename T::outer_allocator_type*);
57
58    template <typename T>
59    static int test(...);
60
61    static const bool value = (sizeof(yes_type) == sizeof(test<Allocator>(0)));
62 };
63
64 template<class MaybeScopedAlloc, bool = is_scoped_allocator_imp<MaybeScopedAlloc>::value >
65 struct outermost_allocator_type_impl
66 {
67    typedef typename MaybeScopedAlloc::outer_allocator_type outer_type;
68    typedef typename outermost_allocator_type_impl<outer_type>::type type;
69 };
70
71 template<class MaybeScopedAlloc>
72 struct outermost_allocator_type_impl<MaybeScopedAlloc, false>
73 {
74    typedef MaybeScopedAlloc type;
75 };
76
77 template<class MaybeScopedAlloc, bool = is_scoped_allocator_imp<MaybeScopedAlloc>::value >
78 struct outermost_allocator_imp
79 {
80    typedef MaybeScopedAlloc type;
81
82    static type &get(MaybeScopedAlloc &a)
83    {  return a;  }
84
85    static const type &get(const MaybeScopedAlloc &a)
86    {  return a;  }
87 };
88
89 template<class MaybeScopedAlloc>
90 struct outermost_allocator_imp<MaybeScopedAlloc, true>
91 {
92    typedef typename MaybeScopedAlloc::outer_allocator_type outer_type;
93    typedef typename outermost_allocator_type_impl<outer_type>::type type;
94
95    static type &get(MaybeScopedAlloc &a)
96    {  return outermost_allocator_imp<outer_type>::get(a.outer_allocator());  }
97
98    static const type &get(const MaybeScopedAlloc &a)
99    {  return outermost_allocator_imp<outer_type>::get(a.outer_allocator());  }
100 };
101
102 }  //namespace dtl {
103
104 template <typename Allocator>
105 struct is_scoped_allocator
106    : dtl::is_scoped_allocator_imp<Allocator>
107 {};
108
109 template <typename Allocator>
110 struct outermost_allocator
111    : dtl::outermost_allocator_imp<Allocator>
112 {};
113
114 template <typename Allocator>
115 typename outermost_allocator<Allocator>::type &
116    get_outermost_allocator(Allocator &a)
117 {  return outermost_allocator<Allocator>::get(a);   }
118
119 template <typename Allocator>
120 const typename outermost_allocator<Allocator>::type &
121    get_outermost_allocator(const Allocator &a)
122 {  return outermost_allocator<Allocator>::get(a);   }
123
124 namespace dtl {
125
126 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
127
128 template <typename OuterAlloc, class ...InnerAllocs>
129 class scoped_allocator_adaptor_base
130    : public OuterAlloc
131 {
132    typedef allocator_traits<OuterAlloc> outer_traits_type;
133    BOOST_COPYABLE_AND_MOVABLE(scoped_allocator_adaptor_base)
134
135    public:
136    template <class OuterA2>
137    struct rebind_base
138    {
139       typedef scoped_allocator_adaptor_base<OuterA2, InnerAllocs...> other;
140    };
141
142    typedef OuterAlloc outer_allocator_type;
143    typedef scoped_allocator_adaptor<InnerAllocs...>   inner_allocator_type;
144    typedef allocator_traits<inner_allocator_type>     inner_traits_type;
145    typedef scoped_allocator_adaptor
146       <OuterAlloc, InnerAllocs...>                    scoped_allocator_type;
147    typedef dtl::bool_<
148       outer_traits_type::propagate_on_container_copy_assignment::value ||
149       inner_allocator_type::propagate_on_container_copy_assignment::value
150       > propagate_on_container_copy_assignment;
151    typedef dtl::bool_<
152       outer_traits_type::propagate_on_container_move_assignment::value ||
153       inner_allocator_type::propagate_on_container_move_assignment::value
154       > propagate_on_container_move_assignment;
155    typedef dtl::bool_<
156       outer_traits_type::propagate_on_container_swap::value ||
157       inner_allocator_type::propagate_on_container_swap::value
158       > propagate_on_container_swap;
159    typedef dtl::bool_<
160       outer_traits_type::is_always_equal::value &&
161       inner_allocator_type::is_always_equal::value
162       > is_always_equal;
163
164    scoped_allocator_adaptor_base()
165       {}
166
167    template <class OuterA2>
168    scoped_allocator_adaptor_base(BOOST_FWD_REF(OuterA2) outerAlloc, const InnerAllocs &...args)
169       : outer_allocator_type(::boost::forward<OuterA2>(outerAlloc))
170       , m_inner(args...)
171       {}
172
173    scoped_allocator_adaptor_base(const scoped_allocator_adaptor_base& other)
174       : outer_allocator_type(other.outer_allocator())
175       , m_inner(other.inner_allocator())
176       {}
177
178    scoped_allocator_adaptor_base(BOOST_RV_REF(scoped_allocator_adaptor_base) other)
179       : outer_allocator_type(::boost::move(other.outer_allocator()))
180       , m_inner(::boost::move(other.inner_allocator()))
181       {}
182
183    template <class OuterA2>
184    scoped_allocator_adaptor_base
185       (const scoped_allocator_adaptor_base<OuterA2, InnerAllocs...>& other)
186       : outer_allocator_type(other.outer_allocator())
187       , m_inner(other.inner_allocator())
188       {}
189
190    template <class OuterA2>
191    scoped_allocator_adaptor_base
192       (BOOST_RV_REF_BEG scoped_allocator_adaptor_base
193          <OuterA2, InnerAllocs...> BOOST_RV_REF_END other)
194       : outer_allocator_type(other.outer_allocator())
195       , m_inner(other.inner_allocator())
196       {}
197
198    public:
199    struct internal_type_t{};
200
201    template <class OuterA2>
202    scoped_allocator_adaptor_base
203       ( internal_type_t
204       , BOOST_FWD_REF(OuterA2) outerAlloc
205       , const inner_allocator_type &inner)
206       : outer_allocator_type(::boost::forward<OuterA2>(outerAlloc))
207       , m_inner(inner)
208    {}
209
210    public:
211
212    scoped_allocator_adaptor_base &operator=
213       (BOOST_COPY_ASSIGN_REF(scoped_allocator_adaptor_base) other)
214    {
215       outer_allocator_type::operator=(other.outer_allocator());
216       m_inner = other.inner_allocator();
217       return *this;
218    }
219
220    scoped_allocator_adaptor_base &operator=(BOOST_RV_REF(scoped_allocator_adaptor_base) other)
221    {
222       outer_allocator_type::operator=(boost::move(other.outer_allocator()));
223       m_inner = ::boost::move(other.inner_allocator());
224       return *this;
225    }
226
227    void swap(scoped_allocator_adaptor_base &r)
228    {
229       boost::adl_move_swap(this->outer_allocator(), r.outer_allocator());
230       boost::adl_move_swap(this->m_inner, r.inner_allocator());
231    }
232
233    friend void swap(scoped_allocator_adaptor_base &l, scoped_allocator_adaptor_base &r)
234    {  l.swap(r);  }
235
236    inner_allocator_type&       inner_allocator() BOOST_NOEXCEPT_OR_NOTHROW
237       { return m_inner; }
238
239    inner_allocator_type const& inner_allocator() const BOOST_NOEXCEPT_OR_NOTHROW
240       { return m_inner; }
241
242    outer_allocator_type      & outer_allocator() BOOST_NOEXCEPT_OR_NOTHROW
243       { return static_cast<outer_allocator_type&>(*this); }
244
245    const outer_allocator_type &outer_allocator() const BOOST_NOEXCEPT_OR_NOTHROW
246       { return static_cast<const outer_allocator_type&>(*this); }
247
248    scoped_allocator_type select_on_container_copy_construction() const
249    {
250       return scoped_allocator_type
251          (internal_type_t()
252          ,outer_traits_type::select_on_container_copy_construction(this->outer_allocator())
253          ,inner_traits_type::select_on_container_copy_construction(this->inner_allocator())
254          );
255    }
256
257    private:
258    inner_allocator_type m_inner;
259 };
260
261 #else //#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
262
263 //Let's add a dummy first template parameter to allow creating
264 //specializations up to maximum InnerAlloc count
265 template <typename OuterAlloc, bool Dummy, BOOST_MOVE_CLASSDFLT9>
266 class scoped_allocator_adaptor_base;
267
268 //Specializations for the adaptor with InnerAlloc allocators
269
270 #define BOOST_CONTAINER_SCOPED_ALLOCATOR_ADAPTOR_BASE_CODE(N)\
271 template <typename OuterAlloc BOOST_MOVE_I##N BOOST_MOVE_CLASS##N>\
272 class scoped_allocator_adaptor_base<OuterAlloc, true, BOOST_MOVE_TARG##N>\
273    : public OuterAlloc\
274 {\
275    typedef allocator_traits<OuterAlloc> outer_traits_type;\
276    BOOST_COPYABLE_AND_MOVABLE(scoped_allocator_adaptor_base)\
277    \
278    public:\
279    template <class OuterA2>\
280    struct rebind_base\
281    {\
282       typedef scoped_allocator_adaptor_base<OuterA2, true, BOOST_MOVE_TARG##N> other;\
283    };\
284    \
285    typedef OuterAlloc outer_allocator_type;\
286    typedef scoped_allocator_adaptor<BOOST_MOVE_TARG##N> inner_allocator_type;\
287    typedef scoped_allocator_adaptor<OuterAlloc, BOOST_MOVE_TARG##N> scoped_allocator_type;\
288    typedef allocator_traits<inner_allocator_type> inner_traits_type;\
289    typedef dtl::bool_<\
290       outer_traits_type::propagate_on_container_copy_assignment::value ||\
291       inner_allocator_type::propagate_on_container_copy_assignment::value\
292       > propagate_on_container_copy_assignment;\
293    typedef dtl::bool_<\
294       outer_traits_type::propagate_on_container_move_assignment::value ||\
295       inner_allocator_type::propagate_on_container_move_assignment::value\
296       > propagate_on_container_move_assignment;\
297    typedef dtl::bool_<\
298       outer_traits_type::propagate_on_container_swap::value ||\
299       inner_allocator_type::propagate_on_container_swap::value\
300       > propagate_on_container_swap;\
301    \
302    typedef dtl::bool_<\
303       outer_traits_type::is_always_equal::value &&\
304       inner_allocator_type::is_always_equal::value\
305       > is_always_equal;\
306    \
307    scoped_allocator_adaptor_base(){}\
308    \
309    template <class OuterA2>\
310    scoped_allocator_adaptor_base(BOOST_FWD_REF(OuterA2) outerAlloc, BOOST_MOVE_CREF##N)\
311       : outer_allocator_type(::boost::forward<OuterA2>(outerAlloc))\
312       , m_inner(BOOST_MOVE_ARG##N)\
313       {}\
314    \
315    scoped_allocator_adaptor_base(const scoped_allocator_adaptor_base& other)\
316       : outer_allocator_type(other.outer_allocator())\
317       , m_inner(other.inner_allocator())\
318       {}\
319    \
320    scoped_allocator_adaptor_base(BOOST_RV_REF(scoped_allocator_adaptor_base) other)\
321       : outer_allocator_type(::boost::move(other.outer_allocator()))\
322       , m_inner(::boost::move(other.inner_allocator()))\
323       {}\
324    \
325    template <class OuterA2>\
326    scoped_allocator_adaptor_base\
327       (const scoped_allocator_adaptor_base<OuterA2, true, BOOST_MOVE_TARG##N>& other)\
328       : outer_allocator_type(other.outer_allocator())\
329       , m_inner(other.inner_allocator())\
330       {}\
331    \
332    template <class OuterA2>\
333    scoped_allocator_adaptor_base\
334       (BOOST_RV_REF_BEG scoped_allocator_adaptor_base<OuterA2, true, BOOST_MOVE_TARG##N> BOOST_RV_REF_END other)\
335       : outer_allocator_type(other.outer_allocator())\
336       , m_inner(other.inner_allocator())\
337       {}\
338    \
339    public:\
340    struct internal_type_t{};\
341    \
342    template <class OuterA2>\
343    scoped_allocator_adaptor_base\
344       ( internal_type_t, BOOST_FWD_REF(OuterA2) outerAlloc, const inner_allocator_type &inner)\
345       : outer_allocator_type(::boost::forward<OuterA2>(outerAlloc))\
346       , m_inner(inner)\
347    {}\
348    \
349    public:\
350    scoped_allocator_adaptor_base &operator=\
351       (BOOST_COPY_ASSIGN_REF(scoped_allocator_adaptor_base) other)\
352    {\
353       outer_allocator_type::operator=(other.outer_allocator());\
354       m_inner = other.inner_allocator();\
355       return *this;\
356    }\
357    \
358    scoped_allocator_adaptor_base &operator=(BOOST_RV_REF(scoped_allocator_adaptor_base) other)\
359    {\
360       outer_allocator_type::operator=(boost::move(other.outer_allocator()));\
361       m_inner = ::boost::move(other.inner_allocator());\
362       return *this;\
363    }\
364    \
365    void swap(scoped_allocator_adaptor_base &r)\
366    {\
367       boost::adl_move_swap(this->outer_allocator(), r.outer_allocator());\
368       boost::adl_move_swap(this->m_inner, r.inner_allocator());\
369    }\
370    \
371    friend void swap(scoped_allocator_adaptor_base &l, scoped_allocator_adaptor_base &r)\
372    {  l.swap(r);  }\
373    \
374    inner_allocator_type&       inner_allocator()\
375       { return m_inner; }\
376    \
377    inner_allocator_type const& inner_allocator() const\
378       { return m_inner; }\
379    \
380    outer_allocator_type      & outer_allocator()\
381       { return static_cast<outer_allocator_type&>(*this); }\
382    \
383    const outer_allocator_type &outer_allocator() const\
384       { return static_cast<const outer_allocator_type&>(*this); }\
385    \
386    scoped_allocator_type select_on_container_copy_construction() const\
387    {\
388       return scoped_allocator_type\
389          (internal_type_t()\
390          ,outer_traits_type::select_on_container_copy_construction(this->outer_allocator())\
391          ,inner_traits_type::select_on_container_copy_construction(this->inner_allocator())\
392          );\
393    }\
394    private:\
395    inner_allocator_type m_inner;\
396 };\
397 //!
398 BOOST_MOVE_ITERATE_1TO9(BOOST_CONTAINER_SCOPED_ALLOCATOR_ADAPTOR_BASE_CODE)
399 #undef BOOST_CONTAINER_SCOPED_ALLOCATOR_ADAPTOR_BASE_CODE
400
401 #endif   //#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
402
403 #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
404    #define BOOST_CONTAINER_SCOPEDALLOC_DUMMYTRUE      ,true
405    #define BOOST_CONTAINER_SCOPEDALLOC_ALLINNER       BOOST_MOVE_TARG9
406    #define BOOST_CONTAINER_SCOPEDALLOC_ALLINNERCLASS  BOOST_MOVE_CLASS9
407 #else
408    #define BOOST_CONTAINER_SCOPEDALLOC_DUMMYTRUE
409    #define BOOST_CONTAINER_SCOPEDALLOC_ALLINNER       InnerAllocs...
410    #define BOOST_CONTAINER_SCOPEDALLOC_ALLINNERCLASS  typename... InnerAllocs
411 #endif
412
413 //Specialization for adaptor without any InnerAlloc
414 template <typename OuterAlloc>
415 class scoped_allocator_adaptor_base< OuterAlloc BOOST_CONTAINER_SCOPEDALLOC_DUMMYTRUE>
416    : public OuterAlloc
417 {
418    BOOST_COPYABLE_AND_MOVABLE(scoped_allocator_adaptor_base)
419    public:
420
421    template <class U>
422    struct rebind_base
423    {
424       typedef scoped_allocator_adaptor_base
425          <typename allocator_traits<OuterAlloc>::template portable_rebind_alloc<U>::type
426          BOOST_CONTAINER_SCOPEDALLOC_DUMMYTRUE > other;
427    };
428
429    typedef OuterAlloc                           outer_allocator_type;
430    typedef allocator_traits<OuterAlloc>         outer_traits_type;
431    typedef scoped_allocator_adaptor<OuterAlloc> inner_allocator_type;
432    typedef inner_allocator_type                 scoped_allocator_type;
433    typedef allocator_traits<inner_allocator_type>   inner_traits_type;
434    typedef typename outer_traits_type::
435       propagate_on_container_copy_assignment    propagate_on_container_copy_assignment;
436    typedef typename outer_traits_type::
437       propagate_on_container_move_assignment    propagate_on_container_move_assignment;
438    typedef typename outer_traits_type::
439       propagate_on_container_swap               propagate_on_container_swap;
440    typedef typename outer_traits_type::
441       is_always_equal                           is_always_equal;
442
443    scoped_allocator_adaptor_base()
444       {}
445
446    template <class OuterA2>
447    scoped_allocator_adaptor_base(BOOST_FWD_REF(OuterA2) outerAlloc)
448       : outer_allocator_type(::boost::forward<OuterA2>(outerAlloc))
449       {}
450
451    scoped_allocator_adaptor_base(const scoped_allocator_adaptor_base& other)
452       : outer_allocator_type(other.outer_allocator())
453       {}
454
455    scoped_allocator_adaptor_base(BOOST_RV_REF(scoped_allocator_adaptor_base) other)
456       : outer_allocator_type(::boost::move(other.outer_allocator()))
457       {}
458
459    template <class OuterA2>
460    scoped_allocator_adaptor_base
461       (const scoped_allocator_adaptor_base<OuterA2 BOOST_CONTAINER_SCOPEDALLOC_DUMMYTRUE>& other)
462       : outer_allocator_type(other.outer_allocator())
463       {}
464
465    template <class OuterA2>
466    scoped_allocator_adaptor_base
467       (BOOST_RV_REF_BEG scoped_allocator_adaptor_base<OuterA2 BOOST_CONTAINER_SCOPEDALLOC_DUMMYTRUE> BOOST_RV_REF_END other)
468       : outer_allocator_type(other.outer_allocator())
469       {}
470
471    public:
472    struct internal_type_t{};
473
474    template <class OuterA2>
475    scoped_allocator_adaptor_base(internal_type_t, BOOST_FWD_REF(OuterA2) outerAlloc, const inner_allocator_type &)
476       : outer_allocator_type(::boost::forward<OuterA2>(outerAlloc))
477       {}
478
479    public:
480    scoped_allocator_adaptor_base &operator=(BOOST_COPY_ASSIGN_REF(scoped_allocator_adaptor_base) other)
481    {
482       outer_allocator_type::operator=(other.outer_allocator());
483       return *this;
484    }
485
486    scoped_allocator_adaptor_base &operator=(BOOST_RV_REF(scoped_allocator_adaptor_base) other)
487    {
488       outer_allocator_type::operator=(boost::move(other.outer_allocator()));
489       return *this;
490    }
491
492    void swap(scoped_allocator_adaptor_base &r)
493    {
494       boost::adl_move_swap(this->outer_allocator(), r.outer_allocator());
495    }
496
497    friend void swap(scoped_allocator_adaptor_base &l, scoped_allocator_adaptor_base &r)
498    {  l.swap(r);  }
499
500    inner_allocator_type&       inner_allocator()
501       { return static_cast<inner_allocator_type&>(*this); }
502
503    inner_allocator_type const& inner_allocator() const
504       { return static_cast<const inner_allocator_type&>(*this); }
505
506    outer_allocator_type      & outer_allocator()
507       { return static_cast<outer_allocator_type&>(*this); }
508
509    const outer_allocator_type &outer_allocator() const
510       { return static_cast<const outer_allocator_type&>(*this); }
511
512    scoped_allocator_type select_on_container_copy_construction() const
513    {
514       return scoped_allocator_type
515          (internal_type_t()
516          ,outer_traits_type::select_on_container_copy_construction(this->outer_allocator())
517          //Don't use inner_traits_type::select_on_container_copy_construction(this->inner_allocator())
518          //as inner_allocator() is equal to *this and that would trigger an infinite loop
519          , this->inner_allocator()
520          );
521    }
522 };
523
524 }  //namespace dtl {
525
526 #endif   //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
527
528 //Scoped allocator
529 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
530
531 #if !defined(BOOST_CONTAINER_UNIMPLEMENTED_PACK_EXPANSION_TO_FIXED_LIST)
532
533 //! This class is a C++03-compatible implementation of std::scoped_allocator_adaptor.
534 //! The class template scoped_allocator_adaptor is an allocator template that specifies
535 //! the memory resource (the outer allocator) to be used by a container (as any other
536 //! allocator does) and also specifies an inner allocator resource to be passed to
537 //! the constructor of every element within the container.
538 //!
539 //! This adaptor is
540 //! instantiated with one outer and zero or more inner allocator types. If
541 //! instantiated with only one allocator type, the inner allocator becomes the
542 //! scoped_allocator_adaptor itself, thus using the same allocator resource for the
543 //! container and every element within the container and, if the elements themselves
544 //! are containers, each of their elements recursively. If instantiated with more than
545 //! one allocator, the first allocator is the outer allocator for use by the container,
546 //! the second allocator is passed to the constructors of the container's elements,
547 //! and, if the elements themselves are containers, the third allocator is passed to
548 //! the elements' elements, and so on. If containers are nested to a depth greater
549 //! than the number of allocators, the last allocator is used repeatedly, as in the
550 //! single-allocator case, for any remaining recursions.
551 //!
552 //! [<b>Note</b>: The
553 //! scoped_allocator_adaptor is derived from the outer allocator type so it can be
554 //! substituted for the outer allocator type in most expressions. -end note]
555 //!
556 //! In the construct member functions, <code>OUTERMOST(x)</code> is x if x does not have
557 //! an <code>outer_allocator()</code> member function and
558 //! <code>OUTERMOST(x.outer_allocator())</code> otherwise; <code>OUTERMOST_ALLOC_TRAITS(x)</code> is
559 //! <code>allocator_traits<decltype(OUTERMOST(x))></code>.
560 //!
561 //! [<b>Note</b>: <code>OUTERMOST(x)</code> and
562 //! <code>OUTERMOST_ALLOC_TRAITS(x)</code> are recursive operations. It is incumbent upon
563 //! the definition of <code>outer_allocator()</code> to ensure that the recursion terminates.
564 //! It will terminate for all instantiations of scoped_allocator_adaptor. -end note]
565 template <typename OuterAlloc, typename ...InnerAllocs>
566 class scoped_allocator_adaptor
567
568 #else // #if !defined(BOOST_CONTAINER_UNIMPLEMENTED_PACK_EXPANSION_TO_FIXED_LIST)
569
570 template <typename OuterAlloc, typename ...InnerAllocs>
571 class scoped_allocator_adaptor<OuterAlloc, InnerAllocs...>
572
573 #endif   // #if !defined(BOOST_CONTAINER_UNIMPLEMENTED_PACK_EXPANSION_TO_FIXED_LIST)
574
575 #else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
576
577 template <typename OuterAlloc, BOOST_MOVE_CLASS9>
578 class scoped_allocator_adaptor
579 #endif
580
581    : public dtl::scoped_allocator_adaptor_base
582          <OuterAlloc BOOST_CONTAINER_SCOPEDALLOC_DUMMYTRUE, BOOST_CONTAINER_SCOPEDALLOC_ALLINNER>
583 {
584    BOOST_COPYABLE_AND_MOVABLE(scoped_allocator_adaptor)
585
586    public:
587    #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
588    typedef dtl::scoped_allocator_adaptor_base
589       <OuterAlloc BOOST_CONTAINER_SCOPEDALLOC_DUMMYTRUE, BOOST_CONTAINER_SCOPEDALLOC_ALLINNER> base_type;
590    typedef typename base_type::internal_type_t              internal_type_t;
591    #endif   //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
592    typedef OuterAlloc                                       outer_allocator_type;
593    //! Type: For exposition only
594    //!
595    typedef allocator_traits<OuterAlloc>                     outer_traits_type;
596    //! Type: <code>scoped_allocator_adaptor<OuterAlloc></code> if <code>sizeof...(InnerAllocs)</code> is zero; otherwise,
597    //! <code>scoped_allocator_adaptor<InnerAllocs...></code>.
598    typedef typename base_type::inner_allocator_type         inner_allocator_type;
599    typedef allocator_traits<inner_allocator_type>           inner_traits_type;
600    typedef typename outer_traits_type::value_type           value_type;
601    typedef typename outer_traits_type::size_type            size_type;
602    typedef typename outer_traits_type::difference_type      difference_type;
603    typedef typename outer_traits_type::pointer              pointer;
604    typedef typename outer_traits_type::const_pointer        const_pointer;
605    typedef typename outer_traits_type::void_pointer         void_pointer;
606    typedef typename outer_traits_type::const_void_pointer   const_void_pointer;
607    //! Type: A type with a constant boolean <code>value</code> == true if
608    //!`allocator_traits<Allocator>:: propagate_on_container_copy_assignment::value` is
609    //! true for any <code>Allocator</code> in the set of <code>OuterAlloc</code> and <code>InnerAllocs...</code>, false otherwise.
610    typedef typename base_type::
611       propagate_on_container_copy_assignment                propagate_on_container_copy_assignment;
612    //! Type: A type with a constant boolean <code>value</code> == true if
613    //!`allocator_traits<Allocator>:: propagate_on_container_move_assignment::value` is
614    //! true for any <code>Allocator</code> in the set of <code>OuterAlloc</code> and <code>InnerAllocs...</code>, false otherwise.
615    typedef typename base_type::
616       propagate_on_container_move_assignment                propagate_on_container_move_assignment;
617
618    //! Type: A type with a constant boolean <code>value</code> == true if
619    //! `allocator_traits<Allocator>:: propagate_on_container_swap::value` is
620    //! true for any <code>Allocator</code> in the set of <code>OuterAlloc</code> and <code>InnerAllocs...</code>, false otherwise.
621    typedef typename base_type::
622       propagate_on_container_swap                           propagate_on_container_swap;
623
624    //! Type: A type with a constant boolean <code>value</code> == true if
625    //!`allocator_traits<Allocator>:: is_always_equal::value` is
626    //! true for all <code>Allocator</code> in the set of <code>OuterAlloc</code> and <code>InnerAllocs...</code>, false otherwise.
627    typedef typename base_type::
628       is_always_equal                           is_always_equal;
629
630    //! Type: Rebinds scoped allocator to
631    //!    <code>typedef scoped_allocator_adaptor
632    //!      < typename outer_traits_type::template portable_rebind_alloc<U>::type
633    //!      , InnerAllocs... ></code>
634    template <class U>
635    struct rebind
636    {
637       typedef scoped_allocator_adaptor
638          < typename outer_traits_type::template portable_rebind_alloc<U>::type
639          , BOOST_CONTAINER_SCOPEDALLOC_ALLINNER> other;
640    };
641
642    //! <b>Effects</b>: value-initializes the OuterAlloc base class
643    //! and the inner allocator object.
644    scoped_allocator_adaptor()
645       {}
646
647    ~scoped_allocator_adaptor()
648       {}
649
650    //! <b>Effects</b>: initializes each allocator within the adaptor with
651    //! the corresponding allocator from other.
652    scoped_allocator_adaptor(const scoped_allocator_adaptor& other)
653       : base_type(other.base())
654       {}
655
656    //! <b>Effects</b>: move constructs each allocator within the adaptor with
657    //! the corresponding allocator from other.
658    scoped_allocator_adaptor(BOOST_RV_REF(scoped_allocator_adaptor) other)
659       : base_type(::boost::move(other.base()))
660       {}
661
662    #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
663
664    //! <b>Requires</b>: OuterAlloc shall be constructible from OuterA2.
665    //!
666    //! <b>Effects</b>: initializes the OuterAlloc base class with boost::forward<OuterA2>(outerAlloc) and inner
667    //! with innerAllocs...(hence recursively initializing each allocator within the adaptor with the
668    //! corresponding allocator from the argument list).
669    template <class OuterA2>
670    scoped_allocator_adaptor(BOOST_FWD_REF(OuterA2) outerAlloc, const InnerAllocs & ...innerAllocs)
671       : base_type(::boost::forward<OuterA2>(outerAlloc), innerAllocs...)
672       {}
673    #else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
674
675    #define BOOST_CONTAINER_SCOPED_ALLOCATOR_ADAPTOR_RELATED_ALLOCATOR_CONSTRUCTOR_CODE(N)\
676    template <class OuterA2>\
677    scoped_allocator_adaptor(BOOST_FWD_REF(OuterA2) outerAlloc BOOST_MOVE_I##N BOOST_MOVE_CREF##N)\
678       : base_type(::boost::forward<OuterA2>(outerAlloc) BOOST_MOVE_I##N BOOST_MOVE_ARG##N)\
679       {}\
680    //
681    BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_SCOPED_ALLOCATOR_ADAPTOR_RELATED_ALLOCATOR_CONSTRUCTOR_CODE)
682    #undef BOOST_CONTAINER_SCOPED_ALLOCATOR_ADAPTOR_RELATED_ALLOCATOR_CONSTRUCTOR_CODE
683
684    #endif   // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
685
686    //! <b>Requires</b>: OuterAlloc shall be constructible from OuterA2.
687    //!
688    //! <b>Effects</b>: initializes each allocator within the adaptor with the corresponding allocator from other.
689    template <class OuterA2>
690    scoped_allocator_adaptor(const scoped_allocator_adaptor<OuterA2, BOOST_CONTAINER_SCOPEDALLOC_ALLINNER> &other)
691       : base_type(other.base())
692       {}
693
694    //! <b>Requires</b>: OuterAlloc shall be constructible from OuterA2.
695    //!
696    //! <b>Effects</b>: initializes each allocator within the adaptor with the corresponding allocator
697    //! rvalue from other.
698    template <class OuterA2>
699    scoped_allocator_adaptor(BOOST_RV_REF_BEG scoped_allocator_adaptor
700       <OuterA2, BOOST_CONTAINER_SCOPEDALLOC_ALLINNER> BOOST_RV_REF_END other)
701       : base_type(::boost::move(other.base()))
702       {}
703
704    scoped_allocator_adaptor &operator=(BOOST_COPY_ASSIGN_REF(scoped_allocator_adaptor) other)
705    {  return static_cast<scoped_allocator_adaptor&>(base_type::operator=(static_cast<const base_type &>(other))); }
706
707    scoped_allocator_adaptor &operator=(BOOST_RV_REF(scoped_allocator_adaptor) other)
708    {  return static_cast<scoped_allocator_adaptor&>(base_type::operator=(boost::move(other.base()))); }
709
710    #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED
711    //! <b>Effects</b>: swaps *this with r.
712    //!
713    void swap(scoped_allocator_adaptor &r);
714
715    //! <b>Effects</b>: swaps *this with r.
716    //!
717    friend void swap(scoped_allocator_adaptor &l, scoped_allocator_adaptor &r);
718
719    //! <b>Returns</b>:
720    //!   <code>static_cast<OuterAlloc&>(*this)</code>.
721    outer_allocator_type      & outer_allocator() BOOST_NOEXCEPT_OR_NOTHROW;
722
723    //! <b>Returns</b>:
724    //!   <code>static_cast<const OuterAlloc&>(*this)</code>.
725    const outer_allocator_type &outer_allocator() const BOOST_NOEXCEPT_OR_NOTHROW;
726
727    //! <b>Returns</b>:
728    //!   *this if <code>sizeof...(InnerAllocs)</code> is zero; otherwise, inner.
729    inner_allocator_type&       inner_allocator() BOOST_NOEXCEPT_OR_NOTHROW;
730
731    //! <b>Returns</b>:
732    //!   *this if <code>sizeof...(InnerAllocs)</code> is zero; otherwise, inner.
733    inner_allocator_type const& inner_allocator() const BOOST_NOEXCEPT_OR_NOTHROW;
734
735    #endif   //BOOST_CONTAINER_DOXYGEN_INVOKED
736
737    //! <b>Returns</b>:
738    //!   <code>allocator_traits<OuterAlloc>:: max_size(outer_allocator())</code>.
739    size_type max_size() const BOOST_NOEXCEPT_OR_NOTHROW
740    {  return outer_traits_type::max_size(this->outer_allocator());   }
741
742    //! <b>Effects</b>:
743    //!   calls <code>OUTERMOST_ALLOC_TRAITS(*this):: destroy(OUTERMOST(*this), p)</code>.
744    template <class T>
745    void destroy(T* p) BOOST_NOEXCEPT_OR_NOTHROW
746    {
747       allocator_traits<typename outermost_allocator<OuterAlloc>::type>
748          ::destroy(get_outermost_allocator(this->outer_allocator()), p);
749    }
750
751    //! <b>Returns</b>:
752    //! <code>allocator_traits<OuterAlloc>::allocate(outer_allocator(), n)</code>.
753    pointer allocate(size_type n)
754    {  return outer_traits_type::allocate(this->outer_allocator(), n);   }
755
756    //! <b>Returns</b>:
757    //! <code>allocator_traits<OuterAlloc>::allocate(outer_allocator(), n, hint)</code>.
758    pointer allocate(size_type n, const_void_pointer hint)
759    {  return outer_traits_type::allocate(this->outer_allocator(), n, hint);   }
760
761    //! <b>Effects</b>:
762    //! <code>allocator_traits<OuterAlloc>::deallocate(outer_allocator(), p, n)</code>.
763    void deallocate(pointer p, size_type n)
764    {  outer_traits_type::deallocate(this->outer_allocator(), p, n);  }
765
766    #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED
767    //! <b>Returns</b>: A new scoped_allocator_adaptor object where each allocator
768    //! Allocator in the adaptor is initialized from the result of calling
769    //! <code>allocator_traits<Allocator>::select_on_container_copy_construction()</code> on
770    //! the corresponding allocator in *this.
771    scoped_allocator_adaptor select_on_container_copy_construction() const;
772    #endif   //BOOST_CONTAINER_DOXYGEN_INVOKED
773
774    #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
775    base_type &base()             { return *this; }
776
777    const base_type &base() const { return *this; }
778    #endif   //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
779
780    #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
781
782    //! <b>Effects</b>:
783    //! 1) If <code>uses_allocator<T, inner_allocator_type>::value</code> is false calls
784    //!    <code>OUTERMOST_ALLOC_TRAITS(*this)::
785    //!       construct(OUTERMOST(*this), p, std::forward<Args>(args)...)</code>.
786    //!
787    //! 2) Otherwise, if <code>uses_allocator<T, inner_allocator_type>::value</code> is true and
788    //!    <code>is_constructible<T, allocator_arg_t, inner_allocator_type, Args...>:: value</code> is true, calls
789    //!    <code>OUTERMOST_ALLOC_TRAITS(*this):: construct(OUTERMOST(*this), p, allocator_arg,
790    //!    inner_allocator(), std::forward<Args>(args)...)</code>.
791    //!
792    //! [<b>Note</b>: In compilers without advanced decltype SFINAE support, <code>is_constructible</code> can't
793    //! be implemented so that condition will be replaced by
794    //! constructible_with_allocator_prefix<T>::value. -end note]
795    //!
796    //! 3) Otherwise, if uses_allocator<T, inner_allocator_type>::value is true and
797    //!    <code>is_constructible<T, Args..., inner_allocator_type>:: value</code> is true, calls
798    //!    <code>OUTERMOST_ALLOC_TRAITS(*this):: construct(OUTERMOST(*this), p,
799    //!    std::forward<Args>(args)..., inner_allocator())</code>.
800    //!
801    //! [<b>Note</b>: In compilers without advanced decltype SFINAE support, <code>is_constructible</code> can't be
802    //! implemented so that condition will be replaced by
803    //! <code>constructible_with_allocator_suffix<T>:: value</code>. -end note]
804    //!
805    //! 4) Otherwise, the program is ill-formed.
806    //!
807    //! [<b>Note</b>: An error will result if <code>uses_allocator</code> evaluates
808    //! to true but the specific constructor does not take an allocator. This definition prevents a silent
809    //! failure to pass an inner allocator to a contained element. -end note]
810    template < typename T, class ...Args>
811    void construct(T* p, BOOST_FWD_REF(Args)...args)
812    {
813       dtl::dispatch_uses_allocator
814          ( (get_outermost_allocator)(this->outer_allocator())
815          , this->inner_allocator(), p, ::boost::forward<Args>(args)...);
816    }
817
818    #else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
819
820    //Disable this overload if the first argument is pair as some compilers have
821    //overload selection problems when the first parameter is a pair.
822    #define BOOST_CONTAINER_SCOPED_ALLOCATOR_CONSTRUCT_CODE(N) \
823    template < typename T BOOST_MOVE_I##N BOOST_MOVE_CLASSQ##N >\
824    void construct(T* p BOOST_MOVE_I##N BOOST_MOVE_UREFQ##N)\
825    {\
826       dtl::dispatch_uses_allocator\
827          ( (get_outermost_allocator)(this->outer_allocator())\
828          , this->inner_allocator(), p BOOST_MOVE_I##N BOOST_MOVE_FWDQ##N);\
829    }\
830    //
831    BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_SCOPED_ALLOCATOR_CONSTRUCT_CODE)
832    #undef BOOST_CONTAINER_SCOPED_ALLOCATOR_CONSTRUCT_CODE
833
834    #endif   // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
835
836    #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
837
838    public:
839    //Internal function
840    template <class OuterA2>
841    scoped_allocator_adaptor(internal_type_t, BOOST_FWD_REF(OuterA2) outer, const inner_allocator_type& inner)
842       : base_type(internal_type_t(), ::boost::forward<OuterA2>(outer), inner)
843    {}
844
845    #endif   //#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
846 };
847
848 /// @cond
849
850 template<bool ZeroInner>
851 struct scoped_allocator_operator_equal
852 {
853    //Optimize equal outer allocator types with 
854    //allocator_traits::equal which uses is_always_equal
855    template<class IA>
856    static bool equal_outer(const IA &l, const IA &r)
857    {  return allocator_traits<IA>::equal(l, r);  }
858
859    //Otherwise compare it normally
860    template<class IA1, class IA2>
861    static bool equal_outer(const IA1 &l, const IA2 &r)
862    {  return l == r;  }
863
864    //Otherwise compare it normally
865    template<class IA>
866    static bool equal_inner(const IA &l, const IA &r)
867    {  return allocator_traits<IA>::equal(l, r);  }
868 };
869
870 template<>
871 struct scoped_allocator_operator_equal<true>
872    : scoped_allocator_operator_equal<false>
873 {
874    //when inner allocator count is zero,
875    //inner_allocator_type is the same as outer_allocator_type
876    //so both types can be different in operator==
877    template<class IA1, class IA2>
878    static bool equal_inner(const IA1 &, const IA2 &)
879    {  return true;  }
880 };
881
882 /// @endcond
883
884 template <typename OuterA1, typename OuterA2, BOOST_CONTAINER_SCOPEDALLOC_ALLINNERCLASS>
885 inline bool operator==(const scoped_allocator_adaptor<OuterA1, BOOST_CONTAINER_SCOPEDALLOC_ALLINNER>& a
886                       ,const scoped_allocator_adaptor<OuterA2, BOOST_CONTAINER_SCOPEDALLOC_ALLINNER>& b)
887 {
888    #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
889    const bool has_zero_inner = sizeof...(InnerAllocs) == 0u;
890    #else
891    const bool has_zero_inner = boost::container::dtl::is_same<P0, void>::value;
892    #endif
893    typedef scoped_allocator_operator_equal<has_zero_inner> equal_t;
894    return equal_t::equal_outer(a.outer_allocator(), b.outer_allocator()) &&
895           equal_t::equal_inner(a.inner_allocator(), b.inner_allocator());
896 }
897
898 template <typename OuterA1, typename OuterA2, BOOST_CONTAINER_SCOPEDALLOC_ALLINNERCLASS>
899 inline bool operator!=(const scoped_allocator_adaptor<OuterA1, BOOST_CONTAINER_SCOPEDALLOC_ALLINNER>& a
900                       ,const scoped_allocator_adaptor<OuterA2, BOOST_CONTAINER_SCOPEDALLOC_ALLINNER>& b)
901 {  return !(a == b);   }
902
903 }} // namespace boost { namespace container {
904
905 #include <boost/container/detail/config_end.hpp>
906
907 #endif //  BOOST_CONTAINER_ALLOCATOR_SCOPED_ALLOCATOR_HPP