]> git.uio.no Git - u/mrichter/AliRoot.git/blob - Vc/include/Vc/Allocator
update to Vc 0.7.3-dev
[u/mrichter/AliRoot.git] / Vc / include / Vc / Allocator
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