1 /*
2 (c) 2014-2015 Glen Joseph Fernandes
3 glenjofe at gmail dot com
4 
5 Distributed under the Boost Software
6 License, Version 1.0.
7 http://boost.org/LICENSE_1_0.txt
8 */
9 #ifndef BOOST_ALIGN_ALIGNED_ALLOCATOR_ADAPTOR_HPP
10 #define BOOST_ALIGN_ALIGNED_ALLOCATOR_ADAPTOR_HPP
11 
12 #include <boost/config.hpp>
13 #include <boost/static_assert.hpp>
14 #include <boost/align/align.hpp>
15 #include <boost/align/aligned_allocator_adaptor_forward.hpp>
16 #include <boost/align/alignment_of.hpp>
17 #include <boost/align/detail/addressof.hpp>
18 #include <boost/align/detail/is_alignment_constant.hpp>
19 #include <boost/align/detail/max_align.hpp>
20 #include <new>
21 
22 #if !defined(BOOST_NO_CXX11_ALLOCATOR)
23 #include <memory>
24 #endif
25 
26 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
27 #include <utility>
28 #endif
29 
30 namespace boost {
31 namespace alignment {
32 
33 template<class Allocator, std::size_t Alignment>
34 class aligned_allocator_adaptor
35     : public Allocator {
36     BOOST_STATIC_ASSERT(detail::
37         is_alignment_constant<Alignment>::value);
38 
39 #if !defined(BOOST_NO_CXX11_ALLOCATOR)
40     typedef std::allocator_traits<Allocator> traits;
41 
42     typedef typename traits::
43         template rebind_alloc<char> char_alloc;
44 
45     typedef typename traits::
46         template rebind_traits<char> char_traits;
47 
48     typedef typename char_traits::pointer char_ptr;
49 #else
50     typedef typename Allocator::
51         template rebind<char>::other char_alloc;
52 
53     typedef typename char_alloc::pointer char_ptr;
54 #endif
55 
56     enum {
57         ptr_align = alignment_of<char_ptr>::value
58     };
59 
60 public:
61 #if !defined(BOOST_NO_CXX11_ALLOCATOR)
62     typedef typename traits::value_type value_type;
63     typedef typename traits::size_type size_type;
64 #else
65     typedef typename Allocator::value_type value_type;
66     typedef typename Allocator::size_type size_type;
67 #endif
68 
69     typedef value_type* pointer;
70     typedef const value_type* const_pointer;
71     typedef void* void_pointer;
72     typedef const void* const_void_pointer;
73     typedef std::ptrdiff_t difference_type;
74 
75 private:
76     enum {
77         min_align = detail::max_align<Alignment,
78             detail::max_align<alignment_of<value_type>::value,
79                 alignment_of<char_ptr>::value>::value>::value
80     };
81 
82 public:
83     template<class U>
84     struct rebind {
85 #if !defined(BOOST_NO_CXX11_ALLOCATOR)
86         typedef aligned_allocator_adaptor<typename traits::
87             template rebind_alloc<U>, Alignment> other;
88 #else
89         typedef aligned_allocator_adaptor<typename Allocator::
90             template rebind<U>::other, Alignment> other;
91 #endif
92     };
93 
94 #if !defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS)
95     aligned_allocator_adaptor() = default;
96 #else
aligned_allocator_adaptor()97     aligned_allocator_adaptor()
98         : Allocator() {
99     }
100 #endif
101 
102 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
103     template<class A>
aligned_allocator_adaptor(A && alloc)104     explicit aligned_allocator_adaptor(A&& alloc) BOOST_NOEXCEPT
105         : Allocator(std::forward<A>(alloc)) {
106     }
107 #else
108     template<class A>
aligned_allocator_adaptor(const A & alloc)109     explicit aligned_allocator_adaptor(const A& alloc)
110         BOOST_NOEXCEPT
111         : Allocator(alloc) {
112     }
113 #endif
114 
115     template<class U>
aligned_allocator_adaptor(const aligned_allocator_adaptor<U,Alignment> & other)116     aligned_allocator_adaptor(const aligned_allocator_adaptor<U,
117         Alignment>& other) BOOST_NOEXCEPT
118         : Allocator(other.base()) {
119     }
120 
base()121     Allocator& base() BOOST_NOEXCEPT {
122         return static_cast<Allocator&>(*this);
123     }
124 
base() const125     const Allocator& base() const BOOST_NOEXCEPT {
126         return static_cast<const Allocator&>(*this);
127     }
128 
allocate(size_type size)129     pointer allocate(size_type size) {
130         std::size_t n1 = size * sizeof(value_type);
131         std::size_t n2 = n1 + min_align - ptr_align;
132         char_alloc a(base());
133         char_ptr p1 = a.allocate(sizeof p1 + n2);
134         void* p2 = detail::addressof(*p1) + sizeof p1;
135         (void)align(min_align, n1, p2, n2);
136         void* p3 = static_cast<char_ptr*>(p2) - 1;
137         ::new(p3) char_ptr(p1);
138         return static_cast<pointer>(p2);
139     }
140 
allocate(size_type size,const_void_pointer hint)141     pointer allocate(size_type size, const_void_pointer hint) {
142         std::size_t n1 = size * sizeof(value_type);
143         std::size_t n2 = n1 + min_align - ptr_align;
144         char_ptr h = char_ptr();
145         if (hint) {
146             h = *(static_cast<const char_ptr*>(hint) - 1);
147         }
148         char_alloc a(base());
149 #if !defined(BOOST_NO_CXX11_ALLOCATOR)
150         char_ptr p1 = char_traits::allocate(a, sizeof p1 + n2, h);
151 #else
152         char_ptr p1 = a.allocate(sizeof p1 + n2, h);
153 #endif
154         void* p2 = detail::addressof(*p1) + sizeof p1;
155         (void)align(min_align, n1, p2, n2);
156         void* p3 = static_cast<char_ptr*>(p2) - 1;
157         ::new(p3) char_ptr(p1);
158         return static_cast<pointer>(p2);
159     }
160 
deallocate(pointer ptr,size_type size)161     void deallocate(pointer ptr, size_type size) {
162         char_ptr* p1 = reinterpret_cast<char_ptr*>(ptr) - 1;
163         char_ptr p2 = *p1;
164         p1->~char_ptr();
165         char_alloc a(base());
166         a.deallocate(p2, size * sizeof(value_type) +
167             min_align - ptr_align + sizeof p2);
168     }
169 };
170 
171 template<class A1, class A2, std::size_t Alignment>
operator ==(const aligned_allocator_adaptor<A1,Alignment> & a,const aligned_allocator_adaptor<A2,Alignment> & b)172 inline bool operator==(const aligned_allocator_adaptor<A1,
173     Alignment>& a, const aligned_allocator_adaptor<A2,
174     Alignment>& b) BOOST_NOEXCEPT
175 {
176     return a.base() == b.base();
177 }
178 
179 template<class A1, class A2, std::size_t Alignment>
operator !=(const aligned_allocator_adaptor<A1,Alignment> & a,const aligned_allocator_adaptor<A2,Alignment> & b)180 inline bool operator!=(const aligned_allocator_adaptor<A1,
181     Alignment>& a, const aligned_allocator_adaptor<A2,
182     Alignment>& b) BOOST_NOEXCEPT
183 {
184     return !(a == b);
185 }
186 
187 } /* :alignment */
188 } /* :boost */
189 
190 #endif
191