2 * Copyright 1993, 1995 Christopher Seiwald.
4 * This file is part of Jam - see jam.c for Copyright information.
15 * newstr.c - string manipulation routines
17 * To minimize string copying, string creation, copying, and freeing
18 * is done through newstr.
22 * newstr() - return a dynamically allocated copy of a string
23 * copystr() - return a copy of a string previously returned by newstr()
24 * freestr() - free a string returned by newstr() or copystr()
25 * str_done() - free string tables
27 * Once a string is passed to newstr(), the returned string is readonly.
29 * This implementation builds a hash table of all strings, so that multiple
30 * calls of newstr() on the same string allocate memory for the string once.
31 * Strings are never actually freed.
34 typedef char * STRING;
36 static struct hash * strhash = 0;
37 static int strtotal = 0;
38 static int strcount_in = 0;
39 static int strcount_out = 0;
43 * Immortal string allocator implementation speeds string allocation and cuts
44 * down on internal fragmentation.
47 # define STRING_BLOCK 4096
48 typedef struct strblock
50 struct strblock * next;
51 char data[STRING_BLOCK];
54 static strblock * strblock_chain = 0;
56 /* Storage remaining in the current strblock */
57 static char * storage_start = 0;
58 static char * storage_finish = 0;
62 * allocate() - Allocate n bytes of immortal string storage.
65 static char * allocate( size_t const n )
67 #ifdef BJAM_NEWSTR_NO_ALLOCATE
68 return (char*)BJAM_MALLOC_ATOMIC(n);
70 /* See if we can grab storage from an existing block. */
71 size_t remaining = storage_finish - storage_start;
74 char * result = storage_start;
78 else /* Must allocate a new block. */
82 if ( nalloc < STRING_BLOCK )
83 nalloc = STRING_BLOCK;
85 /* Allocate a new block and link into the chain. */
86 new_block = (strblock *)BJAM_MALLOC( offsetof( strblock, data[0] ) + nalloc * sizeof( new_block->data[0] ) );
89 new_block->next = strblock_chain;
90 strblock_chain = new_block;
92 /* Take future allocations out of the larger remaining space. */
93 if ( remaining < nalloc - n )
95 storage_start = new_block->data + n;
96 storage_finish = new_block->data + nalloc;
98 return new_block->data;
105 * newstr() - return a dynamically allocated copy of a string.
108 char * newstr( char * string )
114 strhash = hashinit( sizeof( STRING ), "strings" );
118 if ( hashenter( strhash, (HASHDATA **)&s ) )
120 int l = strlen( string );
121 char * m = (char *)allocate( l + 1 );
124 memcpy( m, string, l + 1 );
134 * copystr() - return a copy of a string previously returned by newstr()
137 char * copystr( char * s )
145 * freestr() - free a string returned by newstr() or copystr()
148 void freestr( char * s )
155 * str_done() - free string tables.
160 /* Reclaim string blocks. */
161 while ( strblock_chain != 0 )
163 strblock * n = strblock_chain->next;
164 BJAM_FREE(strblock_chain);
171 printf( "%dK in strings\n", strtotal / 1024 );
173 /* printf( "--- %d strings of %d dangling\n", strcount_in-strcount_out, strcount_in ); */