doubango/branches/2.0/doubango/tinySAK/src/tsk_memory.c

174 lines
6.0 KiB
C

/*
* Copyright (C) 2010-2011 Mamadou Diop.
*
* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
*
* This file is part of Open Source Doubango Framework.
*
* DOUBANGO is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* DOUBANGO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with DOUBANGO.
*
*/
/**@file tsk_memory.c
* @brief Useful memory management functions to handle memory.
* As I'm a lazy man, some definition come from <ahref="http://www.cplusplus.com">this website</a>
*
* @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
*
*/
#include "tsk_memory.h"
#include "tsk_debug.h"
#include <stdarg.h>
#include <ctype.h>
#include <stdio.h>
/**@defgroup tsk_memory_group Utility functions for memory management.
*/
/**@ingroup tsk_memory_group
* Allocates a block of size bytes of memory, returning a pointer to the beginning of the block.
* The content of the newly allocated block of memory is not initialized, remaining with indeterminate values.
* @param size Size of the memory block, in bytes.
* @retval On success, a pointer to the memory block allocated by the function.
* It is up to you to free the returned pointer.
*/
void* tsk_malloc(tsk_size_t size)
{
void *ret = malloc(size);
if(!ret){
TSK_DEBUG_ERROR("Memory allocation failed");
}
return ret;
}
/**@ingroup tsk_memory_group
* Reallocate memory block.
* In case that ptr is NULL, the function behaves exactly as @a tsk_malloc, assigning a new block of size bytes and returning a pointer to the beginning of it.
* The function may move the memory block to a new location, in which case the new location is returned. The content of the memory block is preserved up to the lesser of the
* new and old sizes, even if the block is moved. If the new size is larger, the value of the newly allocated portion is indeterminate.
* In case that the size is 0, the memory previously allocated in ptr is deallocated as if a call to free was made, and a NULL pointer is returned.
* @param ptr Pointer to a memory block previously allocated with malloc, calloc or realloc to be reallocated.
* If this is NULL, a new block is allocated and a pointer to it is returned by the function.
* @param size New size for the memory block, in bytes.
* If it is 0 and ptr points to an existing block of memory, the memory block pointed by ptr is deallocated and a NULL pointer is returned.
* @retval A pointer to the reallocated memory block, which may be either the same as the ptr argument or a new location.
* The type of this pointer is void*, which can be cast to the desired type of data pointer in order to be dereferenceable.
* If the function failed to allocate the requested block of memory, a NULL pointer is returned.
* It is up to you to free the returned pointer.
*/
void* tsk_realloc (void* ptr, tsk_size_t size)
{
void *ret = tsk_null;
if(size) {
if(ptr){
if(!(ret = realloc(ptr, size))){
TSK_DEBUG_ERROR("Memory reallocation failed");
}
}
else{
if(!(ret = calloc(size, 1))){
TSK_DEBUG_ERROR("Memory allocation (%u) failed", (unsigned)size);
}
}
}
return ret;
}
/**@ingroup tsk_memory_group
* Deallocate space in memory.
* @param ptr Pointer to a memory block previously allocated with @a tsk_malloc, @a tsk_calloc or @a tsk_realloc to be deallocated.
* If a null pointer is passed as argument, no action occurs.
*/
void tsk_free(void** ptr)
{
if(ptr && *ptr){
free(*ptr);
*ptr = tsk_null;
}
}
/**@ingroup tsk_memory_group
* Allocates a block of memory for an array of num elements, each of them size bytes long, and initializes all its bits to zero.
* The effective result is the allocation of an zero-initialized memory block of (num * size) bytes.
* @param num Number of elements to be allocated
* @param size Size of elements
* @retval A pointer to the memory block allocated by the function. The type of this pointer is always void*, which can be cast to the desired type of data pointer in order to be dereferenceable.
* If the function failed to allocate the requested block of memory, a NULL pointer is returned.
* It is up to you to free the returned pointer.
*/
void* tsk_calloc(tsk_size_t num, tsk_size_t size)
{
void* ret = tsk_null;
if(num && size){
ret = calloc(num, size);
if(!ret){
TSK_DEBUG_ERROR("Memory allocation failed. num=%u and size=%u", (unsigned)num, (unsigned)size);
}
}
return ret;
}
void* tsk_malloc_aligned(tsk_size_t size, tsk_size_t alignment)
{
#if TSK_UNDER_WINDOWS && !TSK_UNDER_WINDOWS_CE && !TSK_UNDER_WINDOWS_RT
return _aligned_malloc(size, alignment);
#else
void* ret = malloc(size + alignment);
if (ret) {
long pad = ((~(long)ret) % alignment) + 1;
ret = ((uint8_t*)ret) + pad; // pad
((uint8_t*)ret)[-1] = (uint8_t)pad; // store the pad for later use
}
return ret;
#endif
}
void* tsk_realloc_aligned(void * ptr, tsk_size_t size, tsk_size_t alignment)
{
#if TSK_UNDER_WINDOWS && !TSK_UNDER_WINDOWS_CE && !TSK_UNDER_WINDOWS_RT
return _aligned_realloc(ptr, size, alignment);
#else
tsk_free_aligned(ptr);
return tsk_malloc_aligned(size, alignment);
#endif
}
void tsk_free_aligned(void** ptr)
{
if (ptr && *ptr) {
void* ptr_ = *ptr;
#if TSK_UNDER_WINDOWS && !TSK_UNDER_WINDOWS_CE && !TSK_UNDER_WINDOWS_RT
_aligned_free(ptr_);
#else
free((((uint8_t*)ptr_) - ((uint8_t*)ptr_)[-1]));
#endif
*ptr = tsk_null;
}
}
void* tsk_calloc_aligned(tsk_size_t num, tsk_size_t size, tsk_size_t alignment)
{
void* ptr = tsk_malloc_aligned((size * num), alignment);
if (ptr) {
memset(ptr, 0, (size * num));
}
return ptr;
}