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