]> git.uio.no Git - u/mrichter/AliRoot.git/blame - Vc/include/Vc/Allocator
update to Vc 0.7.3-dev
[u/mrichter/AliRoot.git] / Vc / include / Vc / Allocator
CommitLineData
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
31namespace AliRoot {
32namespace 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) \
48namespace 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) \
59namespace 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"
224namespace 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