]>
git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/engine/object.cpp
fc625e6f5b622764369ef06d8503050cf615442d
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 #if !defined(BJAM_NO_MEM_CACHE) || (BJAM_NO_MEM_CACHE == 0)
64 static string_set strhash
;
66 static int32_t strtotal
= 0;
67 static int32_t strcount_in
= 0;
68 static int32_t strcount_out
= 0;
72 * Immortal string allocator implementation speeds string allocation and cuts
73 * down on internal fragmentation.
76 #define STRING_BLOCK 4096
77 typedef struct strblock
79 struct strblock
* next
;
80 char data
[ STRING_BLOCK
];
83 static strblock
* strblock_chain
= 0;
85 #if !defined(BJAM_NO_MEM_CACHE) || (BJAM_NO_MEM_CACHE == 0)
86 /* Storage remaining in the current strblock */
87 static char * storage_start
= 0;
88 static char * storage_finish
= 0;
92 * allocate() - Allocate n bytes of immortal string storage.
95 static char * allocate( int32_t n
)
97 #ifdef BJAM_NEWSTR_NO_ALLOCATE
98 return (char *)BJAM_MALLOC( n
);
100 /* See if we can grab storage from an existing block. */
101 int32_t remaining
= int32_t(storage_finish
- storage_start
);
102 n
= ( ( n
+ ALLOC_ALIGNMENT
- 1 ) / ALLOC_ALIGNMENT
) * ALLOC_ALIGNMENT
;
103 if ( remaining
>= n
)
105 char * result
= storage_start
;
109 else /* Must allocate a new block. */
111 strblock
* new_block
;
113 if ( nalloc
< STRING_BLOCK
)
114 nalloc
= STRING_BLOCK
;
116 /* Allocate a new block and link into the chain. */
117 new_block
= (strblock
*)BJAM_MALLOC( offsetof( strblock
, data
[ 0 ] ) +
118 size_t(nalloc
) * sizeof( new_block
->data
[ 0 ] ) );
119 if ( new_block
== 0 )
121 new_block
->next
= strblock_chain
;
122 strblock_chain
= new_block
;
124 /* Take future allocations out of the larger remaining space. */
125 if ( remaining
< nalloc
- n
)
127 storage_start
= new_block
->data
+ n
;
128 storage_finish
= new_block
->data
+ nalloc
;
130 return new_block
->data
;
137 static unsigned int hash_keyval( char const * key
, int32_t size
)
139 unsigned int const magic
= 2147059363;
140 unsigned int hash
= 0;
143 for ( i
= 0; i
< size
/ sizeof( unsigned int ); ++i
)
146 memcpy( &val
, key
, sizeof( unsigned int ) );
147 hash
= hash
* magic
+ val
;
148 key
+= sizeof( unsigned int );
152 unsigned int val
= 0;
153 memcpy( &val
, key
, size
% sizeof( unsigned int ) );
154 hash
= hash
* magic
+ val
;
157 return hash
+ ( hash
>> 17 );
161 #if !defined(BJAM_NO_MEM_CACHE) || (BJAM_NO_MEM_CACHE == 0)
162 static void string_set_init( string_set
* set
)
166 set
->data
= (struct hash_item
* *)BJAM_MALLOC( set
->num
* sizeof( struct hash_item
* ) );
167 memset( set
->data
, 0, set
->num
* sizeof( struct hash_item
* ) );
171 static void string_set_done( string_set
* set
)
173 BJAM_FREE( set
->data
);
177 static void string_set_resize( string_set
* set
)
180 new_set
.num
= set
->num
* 2;
181 new_set
.size
= set
->size
;
182 new_set
.data
= (struct hash_item
* *)BJAM_MALLOC( sizeof( struct hash_item
*
184 memset( new_set
.data
, 0, sizeof( struct hash_item
* ) * new_set
.num
);
185 for ( int32_t i
= 0; i
< set
->num
; ++i
)
187 while ( set
->data
[ i
] )
189 struct hash_item
* temp
= set
->data
[ i
];
190 unsigned pos
= temp
->header
.hash
% new_set
.num
;
191 set
->data
[ i
] = temp
->header
.next
;
192 temp
->header
.next
= new_set
.data
[ pos
];
193 new_set
.data
[ pos
] = temp
;
196 BJAM_FREE( set
->data
);
201 static char const * string_set_insert( string_set
* set
, char const * string
,
204 unsigned hash
= hash_keyval( string
, size
);
205 unsigned pos
= hash
% set
->num
;
207 struct hash_item
* result
;
209 for ( result
= set
->data
[ pos
]; result
; result
= result
->header
.next
)
210 if ( !strncmp( result
->data
, string
, size
) && !result
->data
[ size
] )
213 if ( set
->size
>= set
->num
)
215 string_set_resize( set
);
216 pos
= hash
% set
->num
;
219 result
= (struct hash_item
*)allocate( sizeof( struct hash_header
) + size
+
221 result
->header
.hash
= hash
;
222 result
->header
.next
= set
->data
[ pos
];
224 result
->header
.magic
= OBJECT_MAGIC
;
226 memcpy( result
->data
, string
, size
);
227 result
->data
[ size
] = '\0';
228 assert( hash_keyval( result
->data
, size
) == result
->header
.hash
);
229 set
->data
[ pos
] = result
;
230 strtotal
+= size
+ 1;
239 * object_new_range() - create an object from a string of given length
242 OBJECT
* object_new_range( char const * const string
, int32_t size
)
246 #ifdef BJAM_NO_MEM_CACHE
248 struct hash_item
* const m
= (struct hash_item
*)BJAM_MALLOC( sizeof(
249 struct hash_header
) + size
+ 1 );
250 strtotal
+= size
+ 1;
251 memcpy( m
->data
, string
, size
);
252 m
->data
[ size
] = '\0';
254 m
->header
.magic
= OBJECT_MAGIC
;
256 return (OBJECT
*)m
->data
;
260 string_set_init( &strhash
);
261 return (OBJECT
*)string_set_insert( &strhash
, string
, size
);
267 * object_new() - create an object from a string
270 OBJECT
* object_new( char const * const string
)
272 return object_new_range( string
, int32_t(strlen( string
)) );
278 static struct hash_item
* object_get_item( OBJECT
* obj
)
280 return (struct hash_item
*)( (char *)obj
- offsetof( struct hash_item
, data
285 static void object_validate( OBJECT
* obj
)
288 assert( object_get_item( obj
)->header
.magic
== OBJECT_MAGIC
);
293 * object_copy() - return a copy of an object
296 OBJECT
* object_copy( OBJECT
* obj
)
298 object_validate( obj
);
299 #ifdef BJAM_NO_MEM_CACHE
300 return object_new( object_str( obj
) );
309 * object_free() - free an object
312 void object_free( OBJECT
* obj
)
314 object_validate( obj
);
315 #ifdef BJAM_NO_MEM_CACHE
316 BJAM_FREE( object_get_item( obj
) );
323 * object_str() - return the OBJECT's internal C string
326 char const * object_str( OBJECT
* obj
)
328 object_validate( obj
);
329 return (char const *)obj
;
334 * object_equal() - compare two objects
337 int object_equal( OBJECT
* lhs
, OBJECT
* rhs
)
339 object_validate( lhs
);
340 object_validate( rhs
);
341 #ifdef BJAM_NO_MEM_CACHE
342 return !strcmp( object_str( lhs
), object_str( rhs
) );
344 assert( ( lhs
== rhs
) == !strcmp( object_str( lhs
), object_str( rhs
) ) );
351 * object_hash() - returns the hash value of an object
354 unsigned int object_hash( OBJECT
* obj
)
356 object_validate( obj
);
357 #ifdef BJAM_NO_MEM_CACHE
358 return hash_keyval( object_str( obj
), strlen( object_str( obj
) ) );
360 return object_get_item( obj
)->header
.hash
;
367 * object_done() - free string tables.
372 #ifdef BJAM_NEWSTR_NO_ALLOCATE
374 for ( i
= 0; i
< strhash
.num
; ++i
)
376 while ( strhash
.data
[ i
] )
378 struct hash_item
* item
= strhash
.data
[ i
];
379 strhash
.data
[ i
] = item
->header
.next
;
384 /* Reclaim string blocks. */
385 while ( strblock_chain
)
387 strblock
* const n
= strblock_chain
->next
;
388 BJAM_FREE( strblock_chain
);
393 #if !defined(BJAM_NO_MEM_CACHE) || (BJAM_NO_MEM_CACHE == 0)
394 string_set_done( &strhash
);
399 out_printf( "%dK in strings\n", strtotal
/ 1024 );
400 if ( strcount_in
!= strcount_out
)
401 out_printf( "--- %d strings of %d dangling\n", strcount_in
-
402 strcount_out
, strcount_in
);