]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/engine/object.cpp
2 * Copyright 1993, 1995 Christopher Seiwald.
3 * Copyright 2011 Steven Watanabe
5 * This file is part of Jam - see jam.c for Copyright information.
9 * object.c - object manipulation routines
12 * object_new() - create an object from a string
13 * object_new_range() - create an object from a string of given length
14 * object_copy() - return a copy of an object
15 * object_free() - free an object
16 * object_str() - get the string value of an object
17 * object_done() - free string tables
19 * This implementation builds a hash table of all strings, so that multiple
20 * calls of object_new() on the same string allocate memory for the string once.
21 * Strings are never actually freed.
33 #define OBJECT_MAGIC 0xa762e0e3u
43 struct hash_item
* next
;
50 struct hash_header header
;
54 #define ALLOC_ALIGNMENT (sizeof(struct hash_item) - sizeof(struct hash_header))
56 typedef struct string_set
60 struct hash_item
* * data
;
63 static string_set strhash
;
64 static int strtotal
= 0;
65 static int strcount_in
= 0;
66 static int strcount_out
= 0;
70 * Immortal string allocator implementation speeds string allocation and cuts
71 * down on internal fragmentation.
74 #define STRING_BLOCK 4096
75 typedef struct strblock
77 struct strblock
* next
;
78 char data
[ STRING_BLOCK
];
81 static strblock
* strblock_chain
= 0;
83 /* Storage remaining in the current strblock */
84 static char * storage_start
= 0;
85 static char * storage_finish
= 0;
89 * allocate() - Allocate n bytes of immortal string storage.
92 static char * allocate( size_t n
)
94 #ifdef BJAM_NEWSTR_NO_ALLOCATE
95 return (char *)BJAM_MALLOC( n
);
97 /* See if we can grab storage from an existing block. */
98 size_t remaining
= storage_finish
- storage_start
;
99 n
= ( ( n
+ ALLOC_ALIGNMENT
- 1 ) / ALLOC_ALIGNMENT
) * ALLOC_ALIGNMENT
;
100 if ( remaining
>= n
)
102 char * result
= storage_start
;
106 else /* Must allocate a new block. */
108 strblock
* new_block
;
110 if ( nalloc
< STRING_BLOCK
)
111 nalloc
= STRING_BLOCK
;
113 /* Allocate a new block and link into the chain. */
114 new_block
= (strblock
*)BJAM_MALLOC( offsetof( strblock
, data
[ 0 ] ) +
115 nalloc
* sizeof( new_block
->data
[ 0 ] ) );
116 if ( new_block
== 0 )
118 new_block
->next
= strblock_chain
;
119 strblock_chain
= new_block
;
121 /* Take future allocations out of the larger remaining space. */
122 if ( remaining
< nalloc
- n
)
124 storage_start
= new_block
->data
+ n
;
125 storage_finish
= new_block
->data
+ nalloc
;
127 return new_block
->data
;
133 static unsigned int hash_keyval( char const * key
, int const size
)
135 unsigned int const magic
= 2147059363;
136 unsigned int hash
= 0;
139 for ( i
= 0; i
< size
/ sizeof( unsigned int ); ++i
)
142 memcpy( &val
, key
, sizeof( unsigned int ) );
143 hash
= hash
* magic
+ val
;
144 key
+= sizeof( unsigned int );
148 unsigned int val
= 0;
149 memcpy( &val
, key
, size
% sizeof( unsigned int ) );
150 hash
= hash
* magic
+ val
;
153 return hash
+ ( hash
>> 17 );
157 static void string_set_init( string_set
* set
)
161 set
->data
= (struct hash_item
* *)BJAM_MALLOC( set
->num
* sizeof( struct hash_item
* ) );
162 memset( set
->data
, 0, set
->num
* sizeof( struct hash_item
* ) );
166 static void string_set_done( string_set
* set
)
168 BJAM_FREE( set
->data
);
172 static void string_set_resize( string_set
* set
)
176 new_set
.num
= set
->num
* 2;
177 new_set
.size
= set
->size
;
178 new_set
.data
= (struct hash_item
* *)BJAM_MALLOC( sizeof( struct hash_item
*
180 memset( new_set
.data
, 0, sizeof( struct hash_item
* ) * new_set
.num
);
181 for ( i
= 0; i
< set
->num
; ++i
)
183 while ( set
->data
[ i
] )
185 struct hash_item
* temp
= set
->data
[ i
];
186 unsigned pos
= temp
->header
.hash
% new_set
.num
;
187 set
->data
[ i
] = temp
->header
.next
;
188 temp
->header
.next
= new_set
.data
[ pos
];
189 new_set
.data
[ pos
] = temp
;
192 BJAM_FREE( set
->data
);
197 static char const * string_set_insert( string_set
* set
, char const * string
,
200 unsigned hash
= hash_keyval( string
, size
);
201 unsigned pos
= hash
% set
->num
;
203 struct hash_item
* result
;
205 for ( result
= set
->data
[ pos
]; result
; result
= result
->header
.next
)
206 if ( !strncmp( result
->data
, string
, size
) && !result
->data
[ size
] )
209 if ( set
->size
>= set
->num
)
211 string_set_resize( set
);
212 pos
= hash
% set
->num
;
215 result
= (struct hash_item
*)allocate( sizeof( struct hash_header
) + size
+
217 result
->header
.hash
= hash
;
218 result
->header
.next
= set
->data
[ pos
];
220 result
->header
.magic
= OBJECT_MAGIC
;
222 memcpy( result
->data
, string
, size
);
223 result
->data
[ size
] = '\0';
224 assert( hash_keyval( result
->data
, size
) == result
->header
.hash
);
225 set
->data
[ pos
] = result
;
226 strtotal
+= size
+ 1;
233 static struct hash_item
* object_get_item( OBJECT
* obj
)
235 return (struct hash_item
*)( (char *)obj
- offsetof( struct hash_item
, data
240 static void object_validate( OBJECT
* obj
)
243 assert( object_get_item( obj
)->header
.magic
== OBJECT_MAGIC
);
248 * object_new_range() - create an object from a string of given length
251 OBJECT
* object_new_range( char const * const string
, int const size
)
255 #ifdef BJAM_NO_MEM_CACHE
257 struct hash_item
* const m
= (struct hash_item
*)BJAM_MALLOC( sizeof(
258 struct hash_header
) + size
+ 1 );
259 strtotal
+= size
+ 1;
260 memcpy( m
->data
, string
, size
);
261 m
->data
[ size
] = '\0';
263 m
->header
.magic
= OBJECT_MAGIC
;
265 return (OBJECT
*)m
->data
;
269 string_set_init( &strhash
);
270 return (OBJECT
*)string_set_insert( &strhash
, string
, size
);
276 * object_new() - create an object from a string
279 OBJECT
* object_new( char const * const string
)
281 return object_new_range( string
, strlen( string
) );
288 * object_copy() - return a copy of an object
291 OBJECT
* object_copy( OBJECT
* obj
)
293 object_validate( obj
);
294 #ifdef BJAM_NO_MEM_CACHE
295 return object_new( object_str( obj
) );
304 * object_free() - free an object
307 void object_free( OBJECT
* obj
)
309 object_validate( obj
);
310 #ifdef BJAM_NO_MEM_CACHE
311 BJAM_FREE( object_get_item( obj
) );
318 * object_str() - return the OBJECT's internal C string
321 char const * object_str( OBJECT
* obj
)
323 object_validate( obj
);
324 return (char const *)obj
;
329 * object_equal() - compare two objects
332 int object_equal( OBJECT
* lhs
, OBJECT
* rhs
)
334 object_validate( lhs
);
335 object_validate( rhs
);
336 #ifdef BJAM_NO_MEM_CACHE
337 return !strcmp( object_str( lhs
), object_str( rhs
) );
339 assert( ( lhs
== rhs
) == !strcmp( object_str( lhs
), object_str( rhs
) ) );
346 * object_hash() - returns the hash value of an object
349 unsigned int object_hash( OBJECT
* obj
)
351 object_validate( obj
);
352 #ifdef BJAM_NO_MEM_CACHE
353 return hash_keyval( object_str( obj
), strlen( object_str( obj
) ) );
355 return object_get_item( obj
)->header
.hash
;
362 * object_done() - free string tables.
367 #ifdef BJAM_NEWSTR_NO_ALLOCATE
369 for ( i
= 0; i
< strhash
.num
; ++i
)
371 while ( strhash
.data
[ i
] )
373 struct hash_item
* item
= strhash
.data
[ i
];
374 strhash
.data
[ i
] = item
->header
.next
;
379 /* Reclaim string blocks. */
380 while ( strblock_chain
)
382 strblock
* const n
= strblock_chain
->next
;
383 BJAM_FREE( strblock_chain
);
388 string_set_done( &strhash
);
392 out_printf( "%dK in strings\n", strtotal
/ 1024 );
393 if ( strcount_in
!= strcount_out
)
394 out_printf( "--- %d strings of %d dangling\n", strcount_in
-
395 strcount_out
, strcount_in
);