/* __mingw_aligned_malloc and friends, implemented using Microsoft's public interfaces and with the help of the algorithm description provided by Wu Yongwei: http://sourceforge.net/mailarchive/message.php?msg_id=3847075 I hereby place this implementation in the public domain. -- Steven G. Johnson (stevenj@alum.mit.edu) */ #include #include #include /* ptrdiff_t */ #include /* memmove */ #ifdef HAVE_STDINT_H # include /* uintptr_t */ #else # define uintptr_t size_t #endif #define NOT_POWER_OF_TWO(n) (((n) & ((n) - 1))) #define UI(p) ((uintptr_t) (p)) #define CP(p) ((char *) p) #define PTR_ALIGN(p0, alignment, offset) \ ((void *) (((UI(p0) + (alignment + sizeof(void*)) + offset) \ & (~UI(alignment - 1))) \ - offset)) /* Pointer must sometimes be aligned; assume sizeof(void*) is a power of two. */ #define ORIG_PTR(p) (*(((void **) (UI(p) & (~UI(sizeof(void*) - 1)))) - 1)) void * __mingw_aligned_offset_malloc (size_t size, size_t alignment, size_t offset) { void *p0, *p; if (NOT_POWER_OF_TWO (alignment)) { errno = EINVAL; return ((void *) 0); } if (size == 0) return ((void *) 0); if (alignment < sizeof (void *)) alignment = sizeof (void *); /* Including the extra sizeof(void*) is overkill on a 32-bit machine, since malloc is already 8-byte aligned, as long as we enforce alignment >= 8 ...but oh well. */ p0 = malloc (size + (alignment + sizeof (void *))); if (!p0) return ((void *) 0); p = PTR_ALIGN (p0, alignment, offset); ORIG_PTR (p) = p0; return p; } void * __mingw_aligned_malloc (size_t size, size_t alignment) { return __mingw_aligned_offset_malloc (size, alignment, 0); } void __mingw_aligned_free (void *memblock) { if (memblock) free (ORIG_PTR (memblock)); } void * __mingw_aligned_offset_realloc (void *memblock, size_t size, size_t alignment, size_t offset) { void *p0, *p; ptrdiff_t shift; if (!memblock) return __mingw_aligned_offset_malloc (size, alignment, offset); if (NOT_POWER_OF_TWO (alignment)) goto bad; if (size == 0) { __mingw_aligned_free (memblock); return ((void *) 0); } if (alignment < sizeof (void *)) alignment = sizeof (void *); p0 = ORIG_PTR (memblock); /* It is an error for the alignment to change. */ if (memblock != PTR_ALIGN (p0, alignment, offset)) goto bad; shift = CP (memblock) - CP (p0); p0 = realloc (p0, size + (alignment + sizeof (void *))); if (!p0) return ((void *) 0); p = PTR_ALIGN (p0, alignment, offset); /* Relative shift of actual data may be different from before, ugh. */ if (shift != CP (p) - CP (p0)) /* ugh, moves more than necessary if size is increased. */ memmove (CP (p), CP (p0) + shift, size); ORIG_PTR (p) = p0; return p; bad: errno = EINVAL; return ((void *) 0); } void * __mingw_aligned_realloc (void *memblock, size_t size, size_t alignment) { return __mingw_aligned_offset_realloc (memblock, size, alignment, 0); }