Files
freetype/lib/ttmemory.c
2023-08-27 18:03:45 +02:00

398 lines
8.2 KiB
C

/*******************************************************************
*
* ttmemory.c 1.2
*
* Memory management component (body).
*
* Copyright 1996-1999 by
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used
* modified and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*
* Changes between 1.1 and 1.2:
*
* - the font pool is gone.
*
* - introduced the FREE macro and the Free function for
* future use in destructors.
*
* - Init_FontPool() is now a macro to allow the compilation of
* 'legacy' applications (all four test programs have been updated).
*
******************************************************************/
#include "ttdebug.h"
#include "ttmemory.h"
#include "ttengine.h"
/* required by the tracing mode */
#undef TT_COMPONENT
#define TT_COMPONENT trace_memory
#ifdef DEBUG_MEMORY
#include <stdio.h>
#define MAX_TRACKED_BLOCKS 1024
struct TMemRec_
{
void* base;
Long size;
};
typedef struct TMemRec_ TMemRec;
static TMemRec pointers[MAX_TRACKED_BLOCKS + 1];
static Int num_alloc;
static Int num_free;
static Int num_realloc; /* counts only `real' reallocations
(i.e., an existing buffer will be resized
to a value larger than zero */
static Int fail_alloc;
static Int fail_realloc;
static Int fail_free;
#endif /* DEBUG_MEMORY */
#ifndef TT_CONFIG_OPTION_THREAD_SAFE
Long TTMemory_Allocated;
Long TTMemory_MaxAllocated;
#endif
/*******************************************************************
*
* Function : TT_Alloc
*
* Description : Allocates memory from the heap buffer.
*
* Input : Size size of the memory to be allocated
* P pointer to a buffer pointer
*
* Output : Error code.
*
* NOTE : The newly allocated block should _always_ be zeroed
* on return. Many parts of the engine rely on this to
* work properly.
*
******************************************************************/
EXPORT_FUNC
TT_Error TT_Alloc( ULong Size, void** P )
{
#ifdef DEBUG_MEMORY
Int i;
#endif
if ( !P )
return TT_Err_Invalid_Argument;
if ( Size > (size_t)-1 )
return TT_Err_Out_Of_Memory;
if ( Size > 0 )
{
*P = (void*)malloc( Size );
if ( !*P )
return TT_Err_Out_Of_Memory;
#ifndef TT_CONFIG_OPTION_THREAD_SAFE
TTMemory_Allocated += Size;
TTMemory_MaxAllocated += Size;
#endif
#ifdef DEBUG_MEMORY
num_alloc++;
i = 0;
while ( i < MAX_TRACKED_BLOCKS && pointers[i].base != NULL )
i++;
if ( i >= MAX_TRACKED_BLOCKS )
fail_alloc++;
else
{
pointers[i].base = *P;
pointers[i].size = Size;
}
#endif /* DEBUG_MEMORY */
MEM_Set( *P, 0, Size );
}
else
*P = NULL;
return TT_Err_Ok;
}
#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE
/*******************************************************************
*
* Function : TT_Realloc
*
* Description : Reallocates memory from the heap buffer.
*
* Input : Size new size of the memory to be allocated;
* if zero, TT_Free() will be called
* P pointer to a buffer pointer; if *P == NULL,
* TT_Alloc() will be called
*
* Output : Error code.
*
* NOTES : It's not necessary to zero the memory in case the
* reallocated buffer is larger than before -- the
* application has to take care of this.
*
* If the memory request fails, TT_Free() will be
* called on *P, and TT_Err_Out_Of_Memory returned.
*
******************************************************************/
EXPORT_FUNC
TT_Error TT_Realloc( ULong Size, void** P )
{
void* Q;
#ifdef DEBUG_MEMORY
Int i;
#endif
if ( !P )
return TT_Err_Invalid_Argument;
if ( !*P )
return TT_Alloc( Size, P );
if ( Size == 0 )
return TT_Free( P );
if ( Size > (size_t)-1 )
{
TT_Free( *P );
return TT_Err_Out_Of_Memory;
}
Q = (void*)realloc( *P, Size );
if ( !Q )
{
TT_Free( *P );
return TT_Err_Out_Of_Memory;
}
#ifdef DEBUG_MEMORY
num_realloc++;
i = 0;
while ( i < MAX_TRACKED_BLOCKS && pointers[i].base != *P )
i++;
if ( i >= MAX_TRACKED_BLOCKS )
fail_realloc++;
else
{
#ifndef TT_CONFIG_OPTION_THREAD_SAFE
TTMemory_Allocated += Size - pointers[i].size;
if ( Size > pointers[i].size )
TTMemory_MaxAllocated += Size - pointers[i].size;
#endif
pointers[i].base = Q;
pointers[i].size = size;
}
#endif /* DEBUG_MEMORY */
*P = Q;
return TT_Err_Ok;
}
#endif /* TT_CONFIG_OPTION_EXTEND_ENGINE */
/*******************************************************************
*
* Function : TT_Free
*
* Description : Releases a previously allocated block of memory.
*
* Input : P pointer to memory block
*
* Output : Always SUCCESS.
*
* Note : The pointer must _always_ be set to NULL by this function.
*
******************************************************************/
EXPORT_FUNC
TT_Error TT_Free( void** P )
{
#ifdef DEBUG_MEMORY
Int i;
#endif /* DEBUG_MEMORY */
if ( !P || !*P )
return TT_Err_Ok;
#ifdef DEBUG_MEMORY
num_free++;
i = 0;
while ( i < MAX_TRACKED_BLOCKS && pointers[i].base != *P )
i++;
if ( i >= MAX_TRACKED_BLOCKS )
fail_free++;
else
{
#ifndef TT_CONFIG_OPTION_THREAD_SAFE
TTMemory_Allocated -= pointers[i].size;
#endif
pointers[i].base = NULL;
pointers[i].size = 0;
}
#endif /* DEBUG_MEMORY */
free( *P );
*P = NULL;
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : TTMemory_Init
*
* Description : Initializes the memory.
*
* Output : Always SUCCESS.
*
******************************************************************/
LOCAL_FUNC
TT_Error TTMemory_Init( void )
{
#ifdef DEBUG_MEMORY
Int i;
for ( i = 0; i < MAX_TRACKED_BLOCKS; i++ )
{
pointers[i].base = NULL;
pointers[i].size = 0;
}
num_alloc = 0;
num_realloc = 0;
num_free = 0;
fail_alloc = 0;
fail_realloc = 0;
fail_free = 0;
#endif
#ifndef TT_CONFIG_OPTION_THREAD_SAFE
TTMemory_Allocated = 0;
TTMemory_MaxAllocated = 0;
#endif
return TT_Err_Ok;
}
/*******************************************************************
*
* Function : TTMemory_Done
*
* Description : Finalizes memory usage.
*
* Output : Always SUCCESS.
*
******************************************************************/
LOCAL_FUNC
TT_Error TTMemory_Done( void )
{
#ifdef DEBUG_MEMORY
Int i, num_leaked, tot_leaked;
num_leaked = 0;
tot_leaked = 0;
for ( i = 0; i < MAX_TRACKED_BLOCKS; i++ )
{
if ( pointers[i].base )
{
num_leaked ++;
tot_leaked += pointers[i].size;
}
}
fprintf( stderr,
"%d memory allocations, of which %d failed\n",
num_alloc,
fail_alloc );
fprintf( stderr,
"%d memory reallocations, of which %d failed\n",
num_realloc,
fail_realloc );
fprintf( stderr,
"%d memory frees, of which %d failed\n",
num_free,
fail_free );
if ( num_leaked > 0 )
{
fprintf( stderr,
"There are %d leaked memory blocks, totalizing %d bytes\n",
num_leaked, tot_leaked );
for ( i = 0; i < MAX_TRACKED_BLOCKS; i++ )
{
if ( pointers[i].base )
{
fprintf( stderr,
"index: %4d (base: $%08lx, size: %08ld)\n",
i,
(long)pointers[i].base,
pointers[i].size );
}
}
}
else
fprintf( stderr, "No memory leaks !\n" );
#endif /* DEBUG_MEMORY */
return TT_Err_Ok;
}
/* END */