1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
|
/*
* Copyright 1993, 1995 Christopher Seiwald.
*
* This file is part of Jam - see jam.c for Copyright information.
*/
# include "jam.h"
# include "newstr.h"
# include "hash.h"
# include "compile.h"
# include <stddef.h>
# include <stdlib.h>
/*
* newstr.c - string manipulation routines
*
* To minimize string copying, string creation, copying, and freeing
* is done through newstr.
*
* External functions:
*
* newstr() - return a dynamically allocated copy of a string
* copystr() - return a copy of a string previously returned by newstr()
* freestr() - free a string returned by newstr() or copystr()
* donestr() - free string tables
*
* Once a string is passed to newstr(), the returned string is readonly.
*
* This implementation builds a hash table of all strings, so that multiple
* calls of newstr() on the same string allocate memory for the string once.
* Strings are never actually freed.
*/
typedef char *STRING;
static struct hash *strhash = 0;
static int strtotal = 0;
static int strcount_in = 0;
static int strcount_out = 0;
/*
* Immortal string allocator implementation speeds string allocation
* and cuts down on internal fragmentation
*/
# define STRING_BLOCK 4096
typedef struct strblock
{
struct strblock* next;
char data[STRING_BLOCK];
} strblock;
static strblock* strblock_chain = 0;
/* Storage remaining in the current strblock */
static char* storage_start = 0;
static char* storage_finish = 0;
/* */
#define SIMPLE_ALLOC 0
/*/
#define SIMPLE_ALLOC 1
/* */
/*
* allocate() - Allocate n bytes of immortal string storage
*/
static char* allocate(size_t n)
{
#if SIMPLE_ALLOC
return (char*)malloc(n);
#else
/* See if we can grab storage from an existing block */
size_t remaining = storage_finish - storage_start;
if ( remaining >= n )
{
char* result = storage_start;
storage_start += n;
return result;
}
else /* Must allocate a new block */
{
strblock* new_block;
size_t nalloc = n;
if ( nalloc < STRING_BLOCK )
nalloc = STRING_BLOCK;
/* allocate a new block and link into the chain */
new_block = (strblock*)malloc( offsetof( strblock, data[0] ) + nalloc * sizeof(new_block->data[0]) );
if ( new_block == 0 )
return 0;
new_block->next = strblock_chain;
strblock_chain = new_block;
/* Take future allocations out of the larger remaining space */
if ( remaining < nalloc - n )
{
storage_start = new_block->data + n;
storage_finish = new_block->data + nalloc;
}
return new_block->data;
}
#endif
}
/*
* newstr() - return a dynamically allocated copy of a string
*/
char *
newstr( char *string )
{
STRING str, *s = &str;
if( !strhash )
strhash = hashinit( sizeof( STRING ), "strings" );
*s = string;
if( hashenter( strhash, (HASHDATA **)&s ) )
{
int l = strlen( string );
char *m = (char *)allocate( l + 1 );
strtotal += l + 1;
memcpy( m, string, l + 1 );
*s = m;
if ( DEBUG_PROFILE )
profile_memory( l+1 );
}
strcount_in += 1;
return *s;
}
/*
* copystr() - return a copy of a string previously returned by newstr()
*/
char *
copystr( char *s )
{
strcount_in += 1;
return s;
}
/*
* freestr() - free a string returned by newstr() or copystr()
*/
void
freestr( char *s )
{
strcount_out += 1;
}
/*
* donestr() - free string tables
*/
void
donestr()
{
/* Reclaim string blocks */
while ( strblock_chain != 0 )
{
strblock* n = strblock_chain->next;
free(strblock_chain);
strblock_chain = n;
}
hashdone( strhash );
if( DEBUG_MEM )
printf( "%dK in strings\n", strtotal / 1024 );
/* printf( "--- %d strings of %d dangling\n", strcount_in-strcount_out, strcount_in ); */
}
|