1 // =============================================================================
2 // PROJECT CHRONO - http://projectchrono.org
3 //
4 // Copyright (c) 2014 projectchrono.org
5 // All rights reserved.
6 //
7 // Use of this source code is governed by a BSD-style license that can be found
8 // in the LICENSE file at the top level of the distribution and at
9 // http://projectchrono.org/license-chrono.txt.
10 //
11 // =============================================================================
12 
13 
14 #ifndef CHALIGNEDALLOCATOR_H
15 #define CHALIGNEDALLOCATOR_H
16 
17 
18 #if defined(__GLIBC__) && ((__GLIBC__>=2 && __GLIBC_MINOR__ >= 8) || __GLIBC__>2) \
19  && defined(__LP64__)
20 #define GLIBC_MALLOC_ALREADY_ALIGNED 1
21 #else
22 #define GLIBC_MALLOC_ALREADY_ALIGNED 0
23 #endif
24 
25 #if defined(__FreeBSD__) && !defined(__arm__) && !defined(__mips__)
26 #define FREEBSD_MALLOC_ALREADY_ALIGNED 1
27 #else
28 #define FREEBSD_MALLOC_ALREADY_ALIGNED 0
29 #endif
30 
31 #if (defined(__APPLE__) \
32  || defined(_WIN64) \
33  || GLIBC_MALLOC_ALREADY_ALIGNED \
34  || FREEBSD_MALLOC_ALREADY_ALIGNED)
35 #define MALLOC_ALREADY_ALIGNED 1
36 #else
37 #define MALLOC_ALREADY_ALIGNED 0
38 #endif
39 
40 #if ((defined __QNXNTO__) || (defined _GNU_SOURCE) || ((defined _XOPEN_SOURCE) && (_XOPEN_SOURCE >= 600))) \
41  && (defined _POSIX_ADVISORY_INFO) && (_POSIX_ADVISORY_INFO > 0)
42 #define HAS_POSIX_MEMALIGN 1
43 #else
44 #define HAS_POSIX_MEMALIGN 0
45 #endif
46 
47 #if SSE_INSTR_SET > 0
48 #define HAS_MM_MALLOC 1
49 #else
50 #define HAS_MM_MALLOC 0
51 #endif
52 
53 
54 #include <cstdlib>
55 #include <memory>
56 #include <cstddef>
57 
58 
59 namespace chrono {
60 
61     template <class T, int N>
62     class aligned_allocator
63     {
64 
65     public:
66 
67         typedef T value_type;
68         typedef T& reference;
69         typedef const T& const_reference;
70         typedef T* pointer;
71         typedef const T* const_pointer;
72         typedef size_t size_type;
73         typedef ptrdiff_t difference_type;
74 
75         template <class U>
76         struct rebind
77         {
78             typedef aligned_allocator<U, N> other;
79         };
80 
throw()81         inline aligned_allocator() throw() {}
throw()82         inline aligned_allocator(const aligned_allocator&) throw() {}
83 
84         template <class U>
aligned_allocator(const aligned_allocator<U,N> &)85         inline aligned_allocator(const aligned_allocator<U, N>&) throw() {}
86 
throw()87         inline ~aligned_allocator() throw() {}
88 
address(reference r)89         static inline pointer address(reference r) { return &r; }
90 
address(const_reference r)91         static inline const_pointer address(const_reference r)
92         {
93             return &r;
94         }
95 
96         pointer allocate(size_type n, typename std::allocator<void>::const_pointer hint = 0);
97         static inline void deallocate(pointer p, size_type);
98 
construct(pointer p,const_reference value)99         static inline void construct(pointer p, const_reference value) { new (p) value_type(value); }
100 
destroy(pointer p)101         static inline void destroy(pointer p) { p->~value_type(); }
102 
max_size()103         static inline size_type max_size() throw() { return size_type(-1) / sizeof(T); }
104 
105         inline bool operator==(const aligned_allocator&) { return true; }
106         inline bool operator!=(const aligned_allocator& rhs) { return !operator==(rhs); }
107     };
108 
109     namespace detail
110     {
_aligned_malloc(size_t size,size_t alignment)111         inline void* _aligned_malloc(size_t size, size_t alignment)
112         {
113             void* res = nullptr;
114             void* ptr = malloc(size + alignment);
115             if (ptr != nullptr)
116             {
117                 res = reinterpret_cast<void*>((reinterpret_cast<size_t>(ptr) & ~(size_t(alignment - 1))) + alignment);
118                 *(reinterpret_cast<void**>(res) - 1) = ptr;
119             }
120             return res;
121         }
122     }
123 
aligned_malloc(size_t size,size_t alignment)124     inline void* aligned_malloc(size_t size, size_t alignment)
125     {
126 #if MALLOC_ALREADY_ALIGNED
127         return malloc(size);
128 #elif HAS_MM_MALLOC
129         return _mm_malloc(size, alignment);
130 #elif HAS_POSIX_MEMALIGN
131         void* res;
132         const int failed = posix_memalign(&res, size, alignment);
133         if (failed) res = 0;
134         return res;
135 #elif (defined _MSC_VER)
136         return _aligned_malloc(size, alignment);
137 #else
138         return detail::_aligned_malloc(size, alignment);
139 #endif
140     }
141 
142     namespace detail
143     {
_aligned_free(void * ptr)144         inline void _aligned_free(void* ptr)
145         {
146             if (ptr != nullptr)
147                 free(*(reinterpret_cast<void**>(ptr) - 1));
148         }
149     }
150 
aligned_free(void * ptr)151     inline void aligned_free(void* ptr)
152     {
153 #if MALLOC_ALREADY_ALIGNED
154         free(ptr);
155 #elif HAS_MM_MALLOC
156         _mm_free(ptr);
157 #elif HAS_POSIX_MEMALIGN
158         free(ptr);
159 #elif defined(_MSC_VER)
160         _aligned_free(ptr);
161 #else
162         detail::_aligned_free(ptr);
163 #endif
164     }
165 
166     template <class T, int N>
167     typename aligned_allocator<T, N>::pointer
allocate(size_type n,typename std::allocator<void>::const_pointer hint)168         aligned_allocator<T, N>::allocate(size_type n, typename std::allocator<void>::const_pointer hint)
169     {
170         pointer res = reinterpret_cast<pointer>(aligned_malloc(sizeof(T)*n, N));
171         if (res == nullptr)
172             throw std::bad_alloc();
173         return res;
174     }
175 
176     template <class T, int N>
deallocate(pointer p,size_type)177     void aligned_allocator<T, N>::deallocate(pointer p, size_type)
178     {
179         aligned_free(p);
180     }
181 
182 
183 }  // end namespace chrono
184 
185 #endif
186