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_RESOURCE_ADAPTOR_HPP
12 #define BOOST_CONTAINER_PMR_RESOURCE_ADAPTOR_HPP
13 
14 #if defined (_MSC_VER)
15 #  pragma once
16 #endif
17 
18 #include <boost/config.hpp>
19 #include <boost/container/pmr/memory_resource.hpp>
20 #include <boost/container/allocator_traits.hpp>
21 #include <boost/intrusive/detail/ebo_functor_holder.hpp>
22 #include <boost/move/utility_core.hpp>
23 
24 namespace boost {
25 namespace container {
26 namespace pmr {
27 
28 //! An instance of resource_adaptor<Allocator> is an adaptor that wraps a memory_resource interface
29 //! around Allocator. In order that resource_adaptor<X<T>> and resource_adaptor<X<U>> are the same
30 //! type for any allocator template X and types T and U, resource_adaptor<Allocator> is rendered as
31 //! an alias to this class template such that Allocator is rebound to a char value type in every
32 //! specialization of the class template. The requirements on this class template are defined below.
33 //! In addition to the Allocator requirements, the parameter to resource_adaptor shall meet
34 //! the following additional requirements:
35 //!
36 //! - `typename allocator_traits<Allocator>:: pointer` shall be identical to
37 //!   `typename allocator_traits<Allocator>:: value_type*`.
38 //!
39 //! - `typename allocator_traits<Allocator>:: const_pointer` shall be identical to
40 //!   `typename allocator_traits<Allocator>:: value_type const*`.
41 //!
42 //! - `typename allocator_traits<Allocator>:: void_pointer` shall be identical to `void*`.
43 //!
44 //! - `typename allocator_traits<Allocator>:: const_void_pointer` shall be identical to `void const*`.
45 template <class Allocator>
46 class resource_adaptor_imp
47    : public  memory_resource
48    #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
49    , private ::boost::intrusive::detail::ebo_functor_holder<Allocator>
50    #endif
51 {
52    #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED
53    Allocator m_alloc;
54    #else
55    BOOST_COPYABLE_AND_MOVABLE(resource_adaptor_imp)
56    typedef ::boost::intrusive::detail::ebo_functor_holder<Allocator> ebo_alloc_t;
57    void static_assert_if_not_char_allocator() const
58    {
59       //This class can only be used with allocators type char
60       BOOST_STATIC_ASSERT((container_detail::is_same<typename Allocator::value_type, char>::value));
61    }
62    #endif
63 
64    public:
65    typedef Allocator allocator_type;
66 
67    //! <b>Effects</b>: Default constructs
68    //!   m_alloc.
resource_adaptor_imp()69    resource_adaptor_imp()
70    {  this->static_assert_if_not_char_allocator(); }
71 
72    //! <b>Effects</b>: Copy constructs
73    //!   m_alloc.
resource_adaptor_imp(const resource_adaptor_imp & other)74    resource_adaptor_imp(const resource_adaptor_imp &other)
75       : ebo_alloc_t(other.ebo_alloc_t::get())
76    {}
77 
78    //! <b>Effects</b>: Move constructs
79    //!   m_alloc.
resource_adaptor_imp(BOOST_RV_REF (resource_adaptor_imp)other)80    resource_adaptor_imp(BOOST_RV_REF(resource_adaptor_imp) other)
81       : ebo_alloc_t(::boost::move(other.get()))
82    {}
83 
84    //! <b>Effects</b>: Initializes m_alloc with
85    //!   a2.
resource_adaptor_imp(const Allocator & a2)86    explicit resource_adaptor_imp(const Allocator& a2)
87       : ebo_alloc_t(a2)
88    {  this->static_assert_if_not_char_allocator(); }
89 
90    //! <b>Effects</b>: Initializes m_alloc with
91    //!   a2.
resource_adaptor_imp(BOOST_RV_REF (Allocator)a2)92    explicit resource_adaptor_imp(BOOST_RV_REF(Allocator) a2)
93       : ebo_alloc_t(::boost::move(a2))
94    {  this->static_assert_if_not_char_allocator(); }
95 
96    //! <b>Effects</b>: Copy assigns
97    //!   m_alloc.
operator =(BOOST_COPY_ASSIGN_REF (resource_adaptor_imp)other)98    resource_adaptor_imp& operator=(BOOST_COPY_ASSIGN_REF(resource_adaptor_imp) other)
99    {  this->ebo_alloc_t::get() = other.ebo_alloc_t::get(); return *this;  }
100 
101    //! <b>Effects</b>: Move assigns
102    //!   m_alloc.
operator =(BOOST_RV_REF (resource_adaptor_imp)other)103    resource_adaptor_imp& operator=(BOOST_RV_REF(resource_adaptor_imp) other)
104    {  this->ebo_alloc_t::get() = ::boost::move(other.ebo_alloc_t::get()); return *this;  }
105 
106    //! <b>Effects</b>: Returns m_alloc.
get_allocator()107    allocator_type &get_allocator()
108    {  return this->ebo_alloc_t::get(); }
109 
110    //! <b>Effects</b>: Returns m_alloc.
get_allocator() const111    const allocator_type &get_allocator() const
112    {  return this->ebo_alloc_t::get(); }
113 
114    protected:
115    //! <b>Returns</b>: Allocated memory obtained by calling m_alloc.allocate. The size and alignment
116    //!   of the allocated memory shall meet the requirements for a class derived from memory_resource.
do_allocate(size_t bytes,size_t alignment)117    virtual void* do_allocate(size_t bytes, size_t alignment)
118    {  (void)alignment;  return this->ebo_alloc_t::get().allocate(bytes);  }
119 
120    //! <b>Requires</b>: p was previously allocated using A.allocate, where A == m_alloc, and not
121    //!   subsequently deallocated.
122    //!
123    //! <b>Effects</b>: Returns memory to the allocator using m_alloc.deallocate().
do_deallocate(void * p,size_t bytes,size_t alignment)124    virtual void do_deallocate(void* p, size_t bytes, size_t alignment)
125    {  (void)alignment; this->ebo_alloc_t::get().deallocate((char*)p, bytes);   }
126 
127    //! Let p be dynamic_cast<const resource_adaptor_imp*>(&other).
128    //!
129    //! <b>Returns</b>: false if p is null, otherwise the value of m_alloc == p->m_alloc.
do_is_equal(const memory_resource & other) const130    virtual bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT
131    {
132       const resource_adaptor_imp* p = dynamic_cast<const resource_adaptor_imp*>(&other);
133       return p && p->ebo_alloc_t::get() == this->ebo_alloc_t::get();
134    }
135 };
136 
137 #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
138 
139 //! `resource_adaptor<Allocator>` is rendered as an alias to resource_adaptor_imp class template
140 //! such that Allocator is rebound to a char value type.
141 template <class Allocator>
142 using resource_adaptor = resource_adaptor_imp
143    <typename allocator_traits<Allocator>::template rebind_alloc<char> >;
144 
145 #else
146 
147 template <class Allocator>
148 class resource_adaptor
149    : public resource_adaptor_imp
150       <typename allocator_traits<Allocator>::template portable_rebind_alloc<char>::type>
151 {
152    typedef resource_adaptor_imp
153       <typename allocator_traits<Allocator>::template portable_rebind_alloc<char>::type> base_t;
154 
155    BOOST_COPYABLE_AND_MOVABLE(resource_adaptor)
156 
157    public:
resource_adaptor()158    resource_adaptor()
159       : base_t()
160    {}
161 
resource_adaptor(const resource_adaptor & other)162    resource_adaptor(const resource_adaptor &other)
163       : base_t(other)
164    {}
165 
resource_adaptor(BOOST_RV_REF (resource_adaptor)other)166    resource_adaptor(BOOST_RV_REF(resource_adaptor) other)
167       : base_t(BOOST_MOVE_BASE(base_t, other))
168    {}
169 
resource_adaptor(const Allocator & a2)170    explicit resource_adaptor(const Allocator& a2)
171       : base_t(a2)
172    {}
173 
resource_adaptor(BOOST_RV_REF (Allocator)a2)174    explicit resource_adaptor(BOOST_RV_REF(Allocator) a2)
175       : base_t(BOOST_MOVE_BASE(base_t, a2))
176    {}
177 
operator =(BOOST_COPY_ASSIGN_REF (resource_adaptor)other)178    resource_adaptor& operator=(BOOST_COPY_ASSIGN_REF(resource_adaptor) other)
179    {  return static_cast<resource_adaptor&>(this->base_t::operator=(other));  }
180 
operator =(BOOST_RV_REF (resource_adaptor)other)181    resource_adaptor& operator=(BOOST_RV_REF(resource_adaptor) other)
182    {  return static_cast<resource_adaptor&>(this->base_t::operator=(BOOST_MOVE_BASE(base_t, other)));  }
183 
184    //get_allocator and protected functions are properly inherited
185 };
186 
187 #endif
188 
189 }  //namespace pmr {
190 }  //namespace container {
191 }  //namespace boost {
192 
193 #endif   //BOOST_CONTAINER_PMR_RESOURCE_ADAPTOR_HPP
194