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