Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / server / supernova / utilities / malloc_aligned.hpp
blob3c50c56be7098f512283a0b68020edf4c6223e9d
1 // functions for aligned memory allocation
2 // Copyright (C) 2009 Tim Blechmann
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; see the file COPYING. If not, write to
16 // the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 // Boston, MA 02111-1307, USA.
19 #ifndef UTILITIES_MALLOC_ALIGNED_HPP
20 #define UTILITIES_MALLOC_ALIGNED_HPP
22 #include <cstdlib>
23 #include <cstring>
25 #include <boost/noncopyable.hpp>
27 #ifdef __SSE2__
28 #include <xmmintrin.h>
29 #elif defined(HAVE_TBB)
30 #include <tbb/cache_aligned_allocator.h>
31 #endif /* HAVE_TBB */
33 #ifdef _MSC_VER
34 #include <malloc.h>
35 #endif
37 #include "function_attributes.h"
39 namespace nova {
41 #if _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600
42 /* we have posix_memalign */
44 /* memory alignment constraints:
46 * - 16 byte for SSE operations
47 * - the cache lines size of modern x86 cpus is 64 bytes (pentium-m, pentium 4, core, k8)
49 const int malloc_memory_alignment = 64;
51 inline void* MALLOC malloc_aligned(std::size_t nbytes)
53 void * ret;
54 int status = posix_memalign(&ret, malloc_memory_alignment, nbytes);
55 if (!status)
56 return ret;
57 else
58 return 0;
61 inline void free_aligned(void *ptr)
63 free(ptr);
66 #elif defined(__APPLE__)
68 const int malloc_memory_alignment = 64;
70 /* apple's malloc implementation returns 16-byte aligned chunks */
71 inline void* MALLOC malloc_aligned(std::size_t nbytes)
73 return malloc(nbytes);
76 inline void free_aligned(void *ptr)
78 free(ptr);
82 #elif defined(__SSE2__)
84 const int malloc_memory_alignment = 64;
86 inline void* MALLOC malloc_aligned(std::size_t nbytes)
88 return _mm_malloc(nbytes, malloc_memory_alignment);
91 inline void free_aligned(void *ptr)
93 _mm_free(ptr);
96 #elif defined(_MSC_VER)
98 const int malloc_memory_alignment = 64;
100 inline void* MALLOC malloc_aligned(std::size_t nbytes)
102 return _aligned_malloc(nbytes, malloc_memory_alignment);
105 inline void free_aligned(void *ptr)
107 _aligned_free(ptr);
110 #elif defined(HAVE_TBB)
112 inline void* MALLOC malloc_aligned(std::size_t nbytes)
114 tbb::cache_aligned_allocator<void*> ca_alloc;
115 return static_cast<void*>(ca_alloc.allocate(nbytes));
118 inline void free_aligned(void *ptr)
120 tbb::cache_aligned_allocator<void*> ca_alloc;
121 ca_alloc.deallocate(static_cast<void**>(ptr), 0);
124 #else
126 /* on other systems, we use the aligned memory allocation taken
127 * from thomas grill's implementation for pd */
128 #define VECTORALIGNMENT 128
129 inline void* MALLOC malloc_aligned(std::size_t nbytes)
131 void* vec = malloc(nbytes+ (VECTORALIGNMENT/8-1) + sizeof(void *));
133 if (vec != NULL) {
134 /* get alignment of first possible signal vector byte */
135 long alignment = ((long)vec+sizeof(void *))&(VECTORALIGNMENT/8-1);
136 /* calculate aligned pointer */
137 void *ret = (unsigned char *)vec+sizeof(void *)+(alignment == 0?0:VECTORALIGNMENT/8-alignment);
138 /* save original memory location */
139 *(void **)((unsigned char *)ret-sizeof(void *)) = vec;
140 return ret;
141 } else
142 return 0;
145 inline void free_aligned(void *ptr)
147 if (ptr == NULL)
148 return;
150 /* get original memory location */
151 void *ori = *(void **)((unsigned char *)ptr-sizeof(void *));
152 free(ori);
155 #undef VECTORALIGNMENT
157 #endif
159 inline void * calloc_aligned(std::size_t nbytes)
161 void * ret = malloc_aligned(nbytes);
162 if (ret)
163 std::memset(ret, 0, nbytes);
164 return ret;
167 template <typename T>
168 T* malloc_aligned(std::size_t n)
170 return static_cast<T*>(malloc_aligned(n * sizeof(T)));
173 template <typename T>
174 T* calloc_aligned(std::size_t n)
176 return static_cast<T*>(calloc_aligned(n * sizeof(T)));
180 /** aligned allocator. uses malloc_aligned and free_aligned internally
181 * */
182 template <class T>
183 class aligned_allocator
185 public:
186 typedef std::size_t size_type;
187 typedef std::ptrdiff_t difference_type;
188 typedef T* pointer;
189 typedef const T* const_pointer;
190 typedef T& reference;
191 typedef const T& const_reference;
192 typedef T value_type;
194 template <class U> struct rebind
196 typedef aligned_allocator<U> other;
199 aligned_allocator(void)
202 template <class U>
203 aligned_allocator(aligned_allocator<U> const & rhs)
206 pointer address(reference x) const
208 return &x;
211 const_pointer address(const_reference x) const
213 return &x;
216 pointer allocate(size_type n, const void* hint = 0)
218 pointer ret = malloc_aligned<T>(n);
219 if (ret == 0)
220 throw std::bad_alloc();
221 return ret;
224 void deallocate(pointer p, size_type n)
226 return free_aligned(p);
229 size_type max_size() const throw()
231 return size_type(-1) / sizeof(T);
234 void construct(pointer p, const T& val = T())
236 ::new(p) T(val);
239 void destroy(pointer p)
241 p->~T();
246 template<typename T, typename U>
247 bool operator==( aligned_allocator<T> const& left, aligned_allocator<U> const& right )
249 return !(left != right);
252 template<typename T, typename U>
253 bool operator!=( aligned_allocator<T> const& left, aligned_allocator<U> const& right )
255 return true;
259 /** smart-pointer, freeing the managed pointer via free_aligned */
260 template<class T, bool managed = true>
261 class aligned_storage_ptr
263 public:
264 explicit aligned_storage_ptr(T * p = 0):
265 ptr(p)
268 ~aligned_storage_ptr(void)
270 if (managed && ptr)
271 free_aligned(ptr);
274 void reset(T * p = 0)
276 if (managed && ptr)
277 free_aligned(ptr);
278 ptr = p;
281 T & operator*() const
283 return *ptr;
286 T * operator->() const
288 return ptr;
291 T * get() const
293 return ptr;
296 aligned_storage_ptr & operator=(T * p)
298 reset(p);
299 return *this;
302 operator bool() const
304 return bool(ptr);
307 void swap(aligned_storage_ptr & b)
309 T * p = ptr;
310 ptr = b.ptr;
311 b.ptr = p;
314 private:
315 T * ptr;
318 } /* namespace nova */
320 #endif /* UTILITIES_MALLOC_ALIGNED_HPP */