]>
Commit | Line | Data |
---|---|---|
c017a39f | 1 | /* This file is part of the Vc library. {{{ |
2 | ||
3 | Copyright (C) 2012 Matthias Kretz <kretz@kde.org> | |
4 | ||
5 | Vc is free software: you can redistribute it and/or modify | |
6 | it under the terms of the GNU Lesser General Public License as | |
7 | published by the Free Software Foundation, either version 3 of | |
8 | the License, or (at your option) any later version. | |
9 | ||
10 | Vc is distributed in the hope that it will be useful, but | |
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU Lesser General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Lesser General Public | |
16 | License along with Vc. If not, see <http://www.gnu.org/licenses/>. | |
17 | ||
18 | }}}*/ | |
19 | ||
20 | #ifndef VC_ALLOCATOR_H | |
21 | #define VC_ALLOCATOR_H | |
22 | ||
23 | #include <new> | |
24 | #include <cstddef> | |
25 | #include <cstdlib> | |
26 | #include "common/macros.h" | |
27 | #ifdef VC_CXX11 | |
28 | #include <utility> | |
29 | #endif | |
30 | ||
31 | namespace AliRoot { | |
32 | namespace Vc | |
33 | { | |
34 | using std::size_t; | |
35 | using std::ptrdiff_t; | |
36 | ||
37 | /** | |
38 | * \headerfile Allocator <Vc/Allocator> | |
39 | * \ingroup Utilities | |
40 | * | |
41 | * Convenience macro to set the default allocator for a given \p Type to Vc::Allocator. | |
42 | * | |
43 | * \param Type Your type that you want to use with STL containers. | |
44 | * | |
45 | * \note You have to use this macro in the global namespace. | |
46 | */ | |
47 | #define VC_DECLARE_ALLOCATOR(Type) \ | |
48 | namespace std \ | |
49 | { \ | |
50 | template<> class allocator<Type> : public ::AliRoot::Vc::Allocator<Type> \ | |
51 | { \ | |
52 | public: \ | |
53 | template<typename U> struct rebind { typedef ::std::allocator<U> other; }; \ | |
54 | }; \ | |
55 | } | |
56 | #ifdef VC_MSVC | |
57 | #undef Vc_DECLARE_ALLOCATOR | |
58 | #define Vc_DECLARE_ALLOCATOR(Type) \ | |
59 | namespace std \ | |
60 | { \ | |
61 | template<> class allocator<Type> : public ::AliRoot::Vc::Allocator<Type> \ | |
62 | { \ | |
63 | public: \ | |
64 | template<typename U> struct rebind { typedef ::std::allocator<U> other; }; \ | |
65 | /* MSVC brokenness: the following function is optional - just doesn't compile without it */ \ | |
66 | const allocator &select_on_container_copy_construction() const { return *this; } \ | |
67 | }; \ | |
68 | } | |
69 | #endif | |
70 | ||
71 | /** | |
72 | * \headerfile Allocator <Vc/Allocator> | |
73 | * An allocator that uses global new and supports over-aligned types, as per [C++11 20.6.9]. | |
74 | * | |
75 | * Meant as a simple replacement for the allocator defined in the C++ Standard. | |
76 | * Allocation is done using the global new/delete operators. But if the alignment property of \p | |
77 | * T is larger than the size of a pointer, the allocate function allocates slightly more memory | |
78 | * to adjust the pointer for correct alignment. | |
79 | * | |
80 | * If the \p T does not require over-alignment no additional memory will be allocated. | |
81 | * | |
82 | * \tparam T The type of objects to allocate. | |
83 | * | |
84 | * Example: | |
85 | * \code | |
86 | * struct Data { | |
87 | * Vc::float_v x, y, z; | |
88 | * }; | |
89 | * | |
90 | * void fun() | |
91 | * { | |
92 | * std::vector<Data> dat0; // this will use std::allocator<Data>, which probably ignores the | |
93 | * // alignment requirements for Data. Thus any access to dat0 may | |
94 | * // crash your program. | |
95 | * | |
96 | * std::vector<Data, Vc::Allocator<Data> > dat1; // now std::vector will get correctly aligned | |
97 | * // memory. Accesses to dat1 are safe. | |
98 | * ... | |
99 | * \endcode | |
100 | * | |
101 | * %Vc ships a macro to conveniently tell STL to use Vc::Allocator per default for a given type: | |
102 | * \code | |
103 | * struct Data { | |
104 | * Vc::float_v x, y, z; | |
105 | * }; | |
106 | * VC_DECLARE_ALLOCATOR(Data) | |
107 | * | |
108 | * void fun() | |
109 | * { | |
110 | * std::vector<Data> dat0; // good now | |
111 | * ... | |
112 | * \endcode | |
113 | * | |
114 | * \ingroup Utilities | |
115 | */ | |
116 | template<typename T> class Allocator | |
117 | { | |
118 | private: | |
119 | enum Constants { | |
120 | #ifdef VC_HAVE_STD_MAX_ALIGN_T | |
121 | NaturalAlignment = alignof(std::max_align_t), | |
122 | #elif defined(VC_HAVE_MAX_ALIGN_T) | |
123 | NaturalAlignment = alignof(::max_align_t), | |
124 | #else | |
125 | NaturalAlignment = sizeof(void *) > Vc_ALIGNOF(long double) ? sizeof(void *) : | |
126 | (Vc_ALIGNOF(long double) > Vc_ALIGNOF(long long) ? Vc_ALIGNOF(long double) : Vc_ALIGNOF(long long)), | |
127 | #endif | |
128 | Alignment = Vc_ALIGNOF(T), | |
129 | /* The number of extra bytes allocated must be large enough to put a pointer right | |
130 | * before the adjusted address. This pointer stores the original address, which is | |
131 | * required to call ::operator delete in deallocate. | |
132 | * | |
133 | * The address we get from ::operator new is a multiple of NaturalAlignment: | |
134 | * p = N * NaturalAlignment | |
135 | * | |
136 | * Since all alignments are powers of two, Alignment is a multiple of NaturalAlignment: | |
137 | * Alignment = k * NaturalAlignment | |
138 | * | |
139 | * two cases: | |
140 | * 1. If p is already aligned to Alignment then allocate will return p + Alignment. In | |
141 | * this case there are Alignment Bytes available to store a pointer. | |
142 | * 2. If p is not aligned then p + (k - (N modulo k)) * NaturalAlignment will be | |
143 | * returned. Since NaturalAlignment >= sizeof(void*) the pointer fits. | |
144 | */ | |
145 | ExtraBytes = Alignment > NaturalAlignment ? Alignment : 0, | |
146 | AlignmentMask = Alignment - 1 | |
147 | }; | |
148 | public: | |
149 | typedef size_t size_type; | |
150 | typedef ptrdiff_t difference_type; | |
151 | typedef T* pointer; | |
152 | typedef const T* const_pointer; | |
153 | typedef T& reference; | |
154 | typedef const T& const_reference; | |
155 | typedef T value_type; | |
156 | ||
157 | template<typename U> struct rebind { typedef Allocator<U> other; }; | |
158 | ||
159 | Allocator() throw() { } | |
160 | Allocator(const Allocator&) throw() { } | |
161 | template<typename U> Allocator(const Allocator<U>&) throw() { } | |
162 | ||
163 | pointer address(reference x) const { return &x; } | |
164 | const_pointer address(const_reference x) const { return &x; } | |
165 | ||
166 | pointer allocate(size_type n, const void* = 0) | |
167 | { | |
168 | if (n > this->max_size()) { | |
169 | throw std::bad_alloc(); | |
170 | } | |
171 | ||
172 | char *p = static_cast<char *>(::operator new(n * sizeof(T) + ExtraBytes)); | |
173 | if (ExtraBytes > 0) { | |
174 | char *const pp = p; | |
175 | p += ExtraBytes; | |
176 | const char *null = 0; | |
177 | p -= ((p - null) & AlignmentMask); // equivalent to p &= ~AlignmentMask; | |
178 | reinterpret_cast<char **>(p)[-1] = pp; | |
179 | } | |
180 | return reinterpret_cast<pointer>(p); | |
181 | } | |
182 | ||
183 | void deallocate(pointer p, size_type) | |
184 | { | |
185 | if (ExtraBytes > 0) { | |
186 | p = reinterpret_cast<pointer *>(p)[-1]; | |
187 | } | |
188 | ::operator delete(p); | |
189 | } | |
190 | ||
191 | size_type max_size() const throw() { return size_t(-1) / sizeof(T); } | |
192 | ||
193 | #ifdef VC_MSVC | |
194 | // MSVC brokenness: the following function is optional - just doesn't compile without it | |
195 | const Allocator &select_on_container_copy_construction() const { return *this; } | |
196 | ||
197 | // MSVC also requires a function that neither C++98 nor C++11 mention | |
198 | // but it doesn't support variadic templates... otherwise the VC_CXX11 clause would be nice | |
199 | void construct(pointer p) { ::new(p) T(); } | |
200 | ||
201 | // we still need the C++98 version: | |
202 | void construct(pointer p, const T& __val) { ::new(p) T(__val); } | |
203 | void destroy(pointer p) { p->~T(); } | |
204 | #elif defined(VC_CXX11) | |
205 | template<typename U, typename... Args> void construct(U* p, Args&&... args) | |
206 | { | |
207 | ::new(p) U(std::forward<Args>(args)...); | |
208 | } | |
209 | template<typename U> void destroy(U* p) { p->~U(); } | |
210 | #else | |
211 | void construct(pointer p, const T& __val) { ::new(p) T(__val); } | |
212 | void destroy(pointer p) { p->~T(); } | |
213 | #endif | |
214 | }; | |
215 | ||
216 | template<typename T> inline bool operator==(const Allocator<T>&, const Allocator<T>&) { return true; } | |
217 | template<typename T> inline bool operator!=(const Allocator<T>&, const Allocator<T>&) { return false; } | |
218 | ||
219 | } // namespace Vc | |
220 | } // namespace AliRoot | |
221 | ||
222 | #include "common/undomacros.h" | |
223 | #include "vector.h" | |
224 | namespace std | |
225 | { | |
226 | template<typename T> class allocator<Vc::Vector<T> > : public ::AliRoot::Vc::Allocator<Vc::Vector<T> > | |
227 | { | |
228 | public: | |
229 | template<typename U> struct rebind { typedef ::std::allocator<U> other; }; | |
230 | #ifdef VC_MSVC | |
231 | // MSVC brokenness: the following function is optional - just doesn't compile without it | |
232 | const allocator &select_on_container_copy_construction() const { return *this; } | |
233 | #endif | |
234 | }; | |
235 | } | |
236 | ||
237 | #endif // VC_ALLOCATOR_H | |
238 | ||
239 | // vim: ft=cpp et sw=4 sts=4 |