text: /*
   * @mindmaze_header@
   */
  #if HAVE_CONFIG_H
  # include <config.h>
  #endif
  
  #include "mmlib.h"
  #include "mmerrno.h"
  #include <stdlib.h>
  #include "mmpredefs.h"
  
  #ifdef HAVE__ALIGNED_MALLOC
  #include <malloc.h>
  #endif
  
  static
  void* internal_aligned_alloc(size_t alignment, size_t size)
  {
  	void * ptr = NULL;
  
  #if defined (HAVE_POSIX_MEMALIGN)
  
  	int ret = posix_memalign(&ptr, alignment, size);
  	if (ret) {
  		errno = ret;
  		ptr = NULL;
  	}
  
  #elif defined (HAVE_ALIGNED_ALLOC)
  
  	ptr = aligned_alloc(alignment, size);
  
  #elif defined (HAVE__ALIGNED_MALLOC)
  
  	if (!MM_IS_POW2(alignment) || (alignment < sizeof(void*))) {
  		ptr = NULL;
  		errno = EINVAL;
  	} else {
  		ptr = _aligned_malloc(size, alignment);
  	}
  
  #else
  #  error Cannot find aligned allocation primitive
  #endif /* if defined (HAVE_POSIX_MEMALIGN) */
  
  	return ptr;
  }
  
  
  /**
   * mm_aligned_alloc() - Allocate memory on a specified alignment boundary.
   * @alignment:  alignment value, must be a power of 2
   * @size:       size of the requested memory allocation
   *
   * This allocates a block of @size bytes whose address is a multiple of
   * @alignment.
   *
   * Use mm_aligned_free() to deallocate data returned by mm_aligned_alloc().
   *
   * Returns: A pointer to the memory block that was allocated in case of
   * success. Otherwise NULL is returned and error state set accordingly
   */
  API_EXPORTED
  void* mm_aligned_alloc(size_t alignment, size_t size)
  {
  	void * ptr = internal_aligned_alloc(alignment, size);
  
  	if (!ptr) {
  		mm_raise_from_errno("Cannot allocate buffer "
  		                    "(alignment=%zu, size=%zu)",
  		                    alignment, size);
  		return NULL;
  	}
  
  	return ptr;
  }
  
  
  /**
   * mm_aligned_free() - Free memory allocated with mm_aligned_alloc()
   * @ptr:        data to dellocate
   *
   * This function cause the space pointed to by @ptr to be deallocated. If
   * ptr is a NULL pointer, no action occur (this is not an error). Otherwise
   * the behavior is undefined if the space has not been allocated with
   * mm_aligned_alloc().
   */
  API_EXPORTED
  void mm_aligned_free(void* ptr)
  {
  #ifdef HAVE__ALIGNED_MALLOC
  	_aligned_free(ptr);
  #else
  	free(ptr);
  #endif
  }
  
  
  /**
   * _mm_malloca_on_heap() - heap memory allocation version of mm_malloca()
   * @size:       size of memory to be allocated
   *
   * Function called when mm_malloca() cannot allocate on stack because @size is
   * too big. The allocation will be attempted on heap.
   *
   * NOTE: although this is function is exported, this should not be used
   * anywhere excepting by the mm_malloca() macro.
   *
   * Return: the pointer on allocated memory in case of success. The return value
   * is then ensured to be of value MM_STK_ALIGN modulo (2*MM_STK_ALIGN). This
   * particularity will be used to recognize when a memory block has been
   * allocated on stack or on heap. In case of failure (likely due to @size too
   * large), NULL is returned.
   */
  API_EXPORTED
  void* _mm_malloca_on_heap(size_t size)
  {
  	char * ptr;
  	size_t alloc_size;
  
  	// Increase allocated size to guarantee alignment requirement
  	alloc_size = size + 2*MM_STK_ALIGN;
  	if (alloc_size < size) {
  		mm_raise_error(ENOMEM, "size=%zu is too big", size);
  		return NULL;
  	}
  
  	// Allocate memory block
  	ptr = internal_aligned_alloc(2*MM_STK_ALIGN, alloc_size);
  	if (ptr == NULL) {
  		mm_raise_from_errno("malloca_on_heap(%zu) failed", alloc_size);
  		return NULL;
  	}
  
  	// Get pointer aligned on MM_STK_ALIGN modulo (2*MM_STK_ALIGN)
  	ptr += MM_STK_ALIGN;
  
  	return ptr;
  }
  
  
  /**
   * _mm_freea_on_heap() - deallocate memory when mm_malloca() has used heap
   * @ptr:        memory block to deallocate
   *
   * Function called when mm_freea() has detected that @ptr has been allocated on
   * heap.
   *
   * NOTE: although this is function is exported, this should not be used
   * anywhere excepting by the mm_freea() macro.
   */
  API_EXPORTED
  void _mm_freea_on_heap(void* ptr)
  {
  	char* base = ptr;
  
  	mm_aligned_free(base - MM_STK_ALIGN);
  }
  