1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2015-2015. 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 // See http://www.boost.org/libs/container for documentation.
8 //
9 //////////////////////////////////////////////////////////////////////////////
10 
11 #ifndef BOOST_CONTAINER_PMR_POLYMORPHIC_ALLOCATOR_HPP
12 #define BOOST_CONTAINER_PMR_POLYMORPHIC_ALLOCATOR_HPP
13 
14 #if defined (_MSC_VER)
15 #  pragma once
16 #endif
17 
18 #include <boost/config.hpp>
19 #include <boost/move/detail/type_traits.hpp>
20 #include <boost/move/utility_core.hpp>
21 #include <boost/container/detail/dispatch_uses_allocator.hpp>
22 #include <boost/container/new_allocator.hpp>
23 #include <boost/container/pmr/memory_resource.hpp>
24 #include <boost/container/pmr/global_resource.hpp>
25 
26 #include <cstddef>
27 
28 namespace boost {
29 namespace container {
30 namespace pmr {
31 
32 //! A specialization of class template `polymorphic_allocator` conforms to the Allocator requirements.
33 //! Constructed with different memory resources, different instances of the same specialization of
34 //! `polymorphic_allocator` can exhibit entirely different allocation behavior. This runtime
35 //! polymorphism allows objects that use polymorphic_allocator to behave as if they used different
36 //! allocator types at run time even though they use the same static allocator type.
37 template <class T>
38 class polymorphic_allocator
39 {
40    public:
41    typedef T value_type;
42 
43    //! <b>Effects</b>: Sets m_resource to
44    //! `get_default_resource()`.
45    polymorphic_allocator() BOOST_NOEXCEPT
46       : m_resource(::boost::container::pmr::get_default_resource())
47    {}
48 
49    //! <b>Requires</b>: r is non-null.
50    //!
51    //! <b>Effects</b>: Sets m_resource to r.
52    //!
53    //! <b>Throws</b>: Nothing
54    //!
55    //! <b>Notes</b>: This constructor provides an implicit conversion from memory_resource*.
56    //!   Non-standard extension: if r is null m_resource is set to get_default_resource().
57    polymorphic_allocator(memory_resource* r)
58       : m_resource(r ? r : ::boost::container::pmr::get_default_resource())
59    {}
60 
61    //! <b>Effects</b>: Sets m_resource to
62    //!   other.resource().
63    polymorphic_allocator(const polymorphic_allocator& other)
64       : m_resource(other.m_resource)
65    {}
66 
67    //! <b>Effects</b>: Sets m_resource to
68    //!   other.resource().
69    template <class U>
70    polymorphic_allocator(const polymorphic_allocator<U>& other) BOOST_NOEXCEPT
71       : m_resource(other.resource())
72    {}
73 
74    //! <b>Effects</b>: Sets m_resource to
75    //!   other.resource().
76    polymorphic_allocator& operator=(const polymorphic_allocator& other)
77    {  m_resource = other.m_resource;   return *this;  }
78 
79    //! <b>Returns</b>: Equivalent to
80    //!   `static_cast<T*>(m_resource->allocate(n * sizeof(T), alignof(T)))`.
81    T* allocate(size_t n)
82    {  return static_cast<T*>(m_resource->allocate(n*sizeof(T), ::boost::move_detail::alignment_of<T>::value));  }
83 
84    //! <b>Requires</b>: p was allocated from a memory resource, x, equal to *m_resource,
85    //! using `x.allocate(n * sizeof(T), alignof(T))`.
86    //!
87    //! <b>Effects</b>: Equivalent to m_resource->deallocate(p, n * sizeof(T), alignof(T)).
88    //!
89    //! <b>Throws</b>: Nothing.
90    void deallocate(T* p, size_t n)
91    {  m_resource->deallocate(p, n*sizeof(T), ::boost::move_detail::alignment_of<T>::value);  }
92 
93    #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
94    //! <b>Requires</b>: Uses-allocator construction of T with allocator
95    //!   `*this` and constructor arguments `std::forward<Args>(args)...`
96    //!   is well-formed. [Note: uses-allocator construction is always well formed for
97    //!   types that do not use allocators. - end note]
98    //!
99    //! <b>Effects</b>: Construct a T object at p by uses-allocator construction with allocator
query_yes_no(question, default=False)100    //!   `*this` and constructor arguments `std::forward<Args>(args)...`.
101    //!
102    //! <b>Throws</b>: Nothing unless the constructor for T throws.
103    template < typename U, class ...Args>
104    void construct(U* p, BOOST_FWD_REF(Args)...args)
105    {
106       new_allocator<U> na;
107       dtl::dispatch_uses_allocator
108          (na, *this, p, ::boost::forward<Args>(args)...);
109    }
110 
111    #else // #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
112 
113    //Disable this overload if the first argument is pair as some compilers have
114    //overload selection problems when the first parameter is a pair.
115    #define BOOST_CONTAINER_PMR_POLYMORPHIC_ALLOCATOR_CONSTRUCT_CODE(N) \
116    template < typename U BOOST_MOVE_I##N BOOST_MOVE_CLASSQ##N >\
117    void construct(U* p BOOST_MOVE_I##N BOOST_MOVE_UREFQ##N)\
118    {\
119       new_allocator<U> na;\
120       dtl::dispatch_uses_allocator\
121          (na, *this, p BOOST_MOVE_I##N BOOST_MOVE_FWDQ##N);\
122    }\
123    //
124    BOOST_MOVE_ITERATE_0TO9(BOOST_CONTAINER_PMR_POLYMORPHIC_ALLOCATOR_CONSTRUCT_CODE)
125    #undef BOOST_CONTAINER_PMR_POLYMORPHIC_ALLOCATOR_CONSTRUCT_CODE
126 
127    #endif   //#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
128 
129    //! <b>Effects</b>:
130    //!   p->~U().
131    template <class U>
132    void destroy(U* p)
133    {  (void)p; p->~U(); }
134 
135    //! <b>Returns</b>: Equivalent to
136    //!   `polymorphic_allocator()`.
137    polymorphic_allocator select_on_container_copy_construction() const
138    {  return polymorphic_allocator();  }
139 
140    //! <b>Returns</b>:
141    //!   m_resource.
142    memory_resource* resource() const
143    {  return m_resource;  }
144 
145    private:
146    memory_resource* m_resource;
147 };
148 
149 //! <b>Returns</b>:
150 //!   `*a.resource() == *b.resource()`.
151 template <class T1, class T2>
152 bool operator==(const polymorphic_allocator<T1>& a, const polymorphic_allocator<T2>& b) BOOST_NOEXCEPT
153 {  return *a.resource() == *b.resource();  }
154 
155 
156 //! <b>Returns</b>:
157 //!   `! (a == b)`.
158 template <class T1, class T2>
159 bool operator!=(const polymorphic_allocator<T1>& a, const polymorphic_allocator<T2>& b) BOOST_NOEXCEPT
160 {  return *a.resource() != *b.resource();  }
161 
162 }  //namespace pmr {
163 }  //namespace container {
164 }  //namespace boost {
165 
166 #endif   //BOOST_CONTAINER_PMR_POLYMORPHIC_ALLOCATOR_HPP
167