2 * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.
\r
3 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
\r
4 * Copyright (c) 2005 Mellanox Technologies, Inc. All rights reserved.
\r
6 * This software is available to you under the OpenIB.org BSD license
\r
9 * Redistribution and use in source and binary forms, with or
\r
10 * without modification, are permitted provided that the following
\r
11 * conditions are met:
\r
13 * - Redistributions of source code must retain the above
\r
14 * copyright notice, this list of conditions and the following
\r
17 * - Redistributions in binary form must reproduce the above
\r
18 * copyright notice, this list of conditions and the following
\r
19 * disclaimer in the documentation and/or other materials
\r
20 * provided with the distribution.
\r
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
\r
23 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
\r
24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
\r
25 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
\r
26 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
\r
27 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
28 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
\r
37 * This file contains ivector and isvector implementations.
\r
44 #include <complib/cl_vector.h>
\r
45 #include <complib/cl_memory.h>
\r
49 * Define the maximum size for array pages in an cl_vector_t.
\r
50 * This size is in objects, not bytes.
\r
52 #define SVEC_MAX_PAGE_SIZE 0x1000
\r
57 * cl_vector_copy_general
\r
60 * copy operator used when size of the user object doesn't fit one of the
\r
61 * other optimized copy functions.
\r
64 * p_src - source for copy
\r
67 * p_dest - destination for copy
\r
74 cl_vector_copy_general(
\r
75 OUT void* const p_dest,
\r
76 IN const void* const p_src,
\r
77 IN const size_t size )
\r
79 cl_memcpy( p_dest, p_src, size );
\r
87 * copy operator used when the user structure is only 8 bits long.
\r
90 * p_src - source for copy
\r
93 * p_dest - destination for copy
\r
101 OUT void* const p_dest,
\r
102 IN const void* const p_src,
\r
103 IN const size_t size )
\r
105 CL_ASSERT( size == sizeof(uint8_t) );
\r
106 UNUSED_PARAM( size );
\r
108 *(uint8_t*)p_dest = *(uint8_t*)p_src;
\r
116 * copy operator used when the user structure is only 16 bits long.
\r
119 * p_src - source for copy
\r
122 * p_dest - destination for copy
\r
130 OUT void* const p_dest,
\r
131 IN const void* const p_src,
\r
132 IN const size_t size )
\r
134 CL_ASSERT( size == sizeof(uint16_t) );
\r
135 UNUSED_PARAM( size );
\r
137 *(uint16_t*)p_dest = *(uint16_t*)p_src;
\r
145 * copy operator used when the user structure is only 32 bits long.
\r
148 * p_src - source for copy
\r
151 * p_dest - destination for copy
\r
159 OUT void* const p_dest,
\r
160 IN const void* const p_src,
\r
161 IN const size_t size )
\r
163 CL_ASSERT( size == sizeof(uint32_t) );
\r
164 UNUSED_PARAM( size );
\r
166 *(uint32_t*)p_dest = *(uint32_t*)p_src;
\r
174 * copy operator used when the user structure is only 64 bits long.
\r
177 * p_src - source for copy
\r
180 * p_dest - destination for copy
\r
188 OUT void* const p_dest,
\r
189 IN const void* const p_src,
\r
190 IN const size_t size )
\r
192 CL_ASSERT( size == sizeof(uint64_t) );
\r
193 UNUSED_PARAM( size );
\r
195 *(uint64_t*)p_dest = *(uint64_t*)p_src;
\r
200 cl_vector_construct(
\r
201 IN cl_vector_t* const p_vector )
\r
203 CL_ASSERT( p_vector );
\r
205 cl_memclr( p_vector, sizeof(cl_vector_t) );
\r
207 p_vector->state = CL_UNINITIALIZED;
\r
213 IN cl_vector_t* const p_vector,
\r
214 IN const size_t min_size,
\r
215 IN const size_t grow_size,
\r
216 IN const size_t element_size,
\r
217 IN cl_pfn_vec_init_t pfn_init OPTIONAL,
\r
218 IN cl_pfn_vec_dtor_t pfn_dtor OPTIONAL,
\r
219 IN const void* const context )
\r
221 cl_status_t status = CL_SUCCESS;
\r
223 CL_ASSERT( p_vector );
\r
224 CL_ASSERT( element_size );
\r
226 cl_vector_construct( p_vector );
\r
228 p_vector->grow_size = grow_size;
\r
229 p_vector->element_size = element_size;
\r
230 p_vector->pfn_init = pfn_init;
\r
231 p_vector->pfn_dtor = pfn_dtor;
\r
232 p_vector->context = context;
\r
235 * Try to choose a smart copy operator
\r
236 * someday, we could simply let the users pass one in
\r
238 switch( element_size )
\r
240 case sizeof(uint8_t):
\r
241 p_vector->pfn_copy = cl_vector_copy8;
\r
244 case sizeof(uint16_t):
\r
245 p_vector->pfn_copy = cl_vector_copy16;
\r
248 case sizeof(uint32_t):
\r
249 p_vector->pfn_copy = cl_vector_copy32;
\r
252 case sizeof(uint64_t):
\r
253 p_vector->pfn_copy = cl_vector_copy64;
\r
257 p_vector->pfn_copy = cl_vector_copy_general;
\r
262 * Set the state to initialized so that the call to set_size
\r
265 p_vector->state = CL_INITIALIZED;
\r
267 /* Initialize the allocation list */
\r
268 cl_qlist_init( &p_vector->alloc_list );
\r
270 /* get the storage needed by the user */
\r
273 status = cl_vector_set_size( p_vector, min_size );
\r
274 if( status != CL_SUCCESS )
\r
275 cl_vector_destroy( p_vector );
\r
284 IN cl_vector_t* const p_vector )
\r
289 CL_ASSERT( p_vector );
\r
290 CL_ASSERT( cl_is_state_valid( p_vector->state ) );
\r
292 /* Call the user's destructor for each element in the array. */
\r
293 if( p_vector->state == CL_INITIALIZED )
\r
295 if( p_vector->pfn_dtor )
\r
297 for( i = 0; i < p_vector->size; i++ )
\r
299 p_element = p_vector->p_ptr_array[i];
\r
300 /* Sanity check! */
\r
301 CL_ASSERT( p_element );
\r
302 p_vector->pfn_dtor( p_element, (void*)p_vector->context );
\r
306 /* Deallocate the pages */
\r
307 while( !cl_is_qlist_empty( &p_vector->alloc_list ) )
\r
308 cl_free( cl_qlist_remove_head( &p_vector->alloc_list ) );
\r
310 /* Destroy the page vector. */
\r
311 if( p_vector->p_ptr_array )
\r
313 cl_free( p_vector->p_ptr_array );
\r
314 p_vector->p_ptr_array = NULL;
\r
318 p_vector->state = CL_UNINITIALIZED;
\r
324 IN const cl_vector_t* const p_vector,
\r
325 IN const size_t index,
\r
326 OUT void* const p_element )
\r
328 CL_ASSERT( p_vector );
\r
329 CL_ASSERT( p_vector->state == CL_INITIALIZED );
\r
332 if( index >= p_vector->size )
\r
333 return( CL_INVALID_PARAMETER );
\r
335 cl_vector_get( p_vector, index, p_element );
\r
336 return( CL_SUCCESS );
\r
342 IN cl_vector_t* const p_vector,
\r
343 IN const size_t index,
\r
344 IN void* const p_element )
\r
346 cl_status_t status;
\r
349 CL_ASSERT( p_vector );
\r
350 CL_ASSERT( p_vector->state == CL_INITIALIZED );
\r
351 CL_ASSERT( p_element );
\r
353 /* Determine if the vector has room for this element. */
\r
354 if( index >= p_vector->size )
\r
356 /* Resize to accomodate the given index. */
\r
357 status = cl_vector_set_size( p_vector, index + 1 );
\r
359 /* Check for failure on or before the given index. */
\r
360 if( (status != CL_SUCCESS) && (p_vector->size < index) )
\r
364 /* At this point, the array is guaranteed to be big enough */
\r
365 p_dest = cl_vector_get_ptr( p_vector, index );
\r
366 /* Sanity check! */
\r
367 CL_ASSERT( p_dest );
\r
369 /* Copy the data into the array */
\r
370 p_vector->pfn_copy( p_dest, p_element, p_vector->element_size );
\r
372 return( CL_SUCCESS );
\r
377 cl_vector_set_capacity(
\r
378 IN cl_vector_t* const p_vector,
\r
379 IN const size_t new_capacity )
\r
381 size_t new_elements;
\r
384 cl_list_item_t *p_buf;
\r
385 void *p_new_ptr_array;
\r
387 CL_ASSERT( p_vector );
\r
388 CL_ASSERT( p_vector->state == CL_INITIALIZED );
\r
390 /* Do we have to do anything here? */
\r
391 if( new_capacity <= p_vector->capacity )
\r
394 return( CL_SUCCESS );
\r
397 /* Allocate our pointer array. */
\r
398 p_new_ptr_array = cl_zalloc( new_capacity * sizeof(void*) );
\r
399 if( !p_new_ptr_array )
\r
400 return( CL_INSUFFICIENT_MEMORY );
\r
402 if( p_vector->p_ptr_array )
\r
404 /* Copy the old pointer array into the new. */
\r
405 cl_memcpy( p_new_ptr_array, p_vector->p_ptr_array,
\r
406 p_vector->capacity * sizeof(void*) );
\r
408 /* Free the old pointer array. */
\r
409 cl_free( p_vector->p_ptr_array );
\r
412 /* Set the new array. */
\r
413 p_vector->p_ptr_array = p_new_ptr_array;
\r
416 * We have to add capacity to the array. Determine how many
\r
419 new_elements = new_capacity - p_vector->capacity;
\r
420 /* Determine the allocation size for the new array elements. */
\r
421 alloc_size = new_elements * p_vector->element_size;
\r
423 p_buf = (cl_list_item_t*)cl_zalloc( alloc_size + sizeof(cl_list_item_t) );
\r
425 return( CL_INSUFFICIENT_MEMORY );
\r
427 cl_qlist_insert_tail( &p_vector->alloc_list, p_buf );
\r
428 /* Advance the buffer pointer past the list item. */
\r
431 for( i = p_vector->capacity; i < new_capacity; i++ )
\r
433 p_vector->p_ptr_array[i] = p_buf;
\r
434 /* Move the buffer pointer to the next element. */
\r
435 p_buf = (void*)(((uint8_t*)p_buf) + p_vector->element_size);
\r
438 /* Update the vector with the new capactity. */
\r
439 p_vector->capacity = new_capacity;
\r
441 return( CL_SUCCESS );
\r
446 cl_vector_set_size(
\r
447 IN cl_vector_t* const p_vector,
\r
448 IN const size_t size )
\r
450 cl_status_t status;
\r
451 size_t new_capacity;
\r
455 CL_ASSERT( p_vector );
\r
456 CL_ASSERT( p_vector->state == CL_INITIALIZED );
\r
458 /* Check to see if the requested size is the same as the existing size. */
\r
459 if( size == p_vector->size )
\r
460 return( CL_SUCCESS );
\r
462 /* Determine if the vector has room for this element. */
\r
463 if( size > p_vector->capacity )
\r
465 if( !p_vector->grow_size )
\r
466 return( CL_INSUFFICIENT_MEMORY );
\r
468 /* Calculate the new capacity, taking into account the grow size. */
\r
469 new_capacity = size;
\r
470 if( size % p_vector->grow_size )
\r
472 /* Round up to nearest grow_size boundary. */
\r
473 new_capacity += p_vector->grow_size -
\r
474 (size % p_vector->grow_size);
\r
477 status = cl_vector_set_capacity( p_vector, new_capacity );
\r
478 if( status != CL_SUCCESS )
\r
482 /* Are we growing the array and need to invoke an initializer callback? */
\r
483 if( size > p_vector->size && p_vector->pfn_init )
\r
485 for( index = p_vector->size; index < size; index++ )
\r
487 /* Get a pointer to this element */
\r
488 p_element = cl_vector_get_ptr( p_vector, index );
\r
490 /* Call the user's initializer and trap failures. */
\r
491 status = p_vector->pfn_init( p_element, (void*)p_vector->context );
\r
492 if( status != CL_SUCCESS )
\r
494 /* Call the destructor for this object */
\r
495 if( p_vector->pfn_dtor )
\r
496 p_vector->pfn_dtor( p_element, (void*)p_vector->context );
\r
498 /* Return the failure status to the caller. */
\r
502 /* The array just grew by one element */
\r
506 else if( p_vector->pfn_dtor )
\r
508 /* The array is shrinking and there is a destructor to invoke. */
\r
509 for( index = size; index < p_vector->size; index++ )
\r
511 /* compute the address of the new elements */
\r
512 p_element = cl_vector_get_ptr( p_vector, index );
\r
513 /* call the user's destructor */
\r
514 p_vector->pfn_dtor( p_element, (void*)p_vector->context );
\r
518 p_vector->size = size;
\r
519 return( CL_SUCCESS );
\r
524 cl_vector_set_min_size(
\r
525 IN cl_vector_t* const p_vector,
\r
526 IN const size_t min_size )
\r
528 CL_ASSERT( p_vector );
\r
529 CL_ASSERT( p_vector->state == CL_INITIALIZED );
\r
531 if( min_size > p_vector->size )
\r
533 /* We have to resize the array */
\r
534 return( cl_vector_set_size( p_vector, min_size ) );
\r
537 /* We didn't have to do anything */
\r
538 return( CL_SUCCESS );
\r
543 cl_vector_apply_func(
\r
544 IN const cl_vector_t* const p_vector,
\r
545 IN cl_pfn_vec_apply_t pfn_callback,
\r
546 IN const void* const context )
\r
551 CL_ASSERT( p_vector );
\r
552 CL_ASSERT( p_vector->state == CL_INITIALIZED );
\r
553 CL_ASSERT( pfn_callback );
\r
555 for( i = 0; i < p_vector->size; i++ )
\r
557 p_element = cl_vector_get_ptr( p_vector, i );
\r
558 pfn_callback( i, p_element, (void*)context );
\r
564 cl_vector_find_from_start(
\r
565 IN const cl_vector_t* const p_vector,
\r
566 IN cl_pfn_vec_find_t pfn_callback,
\r
567 IN const void* const context )
\r
572 CL_ASSERT( p_vector );
\r
573 CL_ASSERT( p_vector->state == CL_INITIALIZED );
\r
574 CL_ASSERT( pfn_callback );
\r
576 for( i = 0; i < p_vector->size; i++ )
\r
578 p_element = cl_vector_get_ptr( p_vector, i );
\r
579 /* Invoke the callback */
\r
580 if( pfn_callback( i, p_element, (void*)context ) == CL_SUCCESS )
\r
588 cl_vector_find_from_end(
\r
589 IN const cl_vector_t* const p_vector,
\r
590 IN cl_pfn_vec_find_t pfn_callback,
\r
591 IN const void* const context )
\r
596 CL_ASSERT( p_vector );
\r
597 CL_ASSERT( p_vector->state == CL_INITIALIZED );
\r
598 CL_ASSERT( pfn_callback );
\r
600 i = p_vector->size;
\r
604 /* Get a pointer to the element in the array. */
\r
605 p_element = cl_vector_get_ptr( p_vector, --i );
\r
606 CL_ASSERT( p_element );
\r
608 /* Invoke the callback for the current element. */
\r
609 if( pfn_callback( i, p_element, (void*)context ) == CL_SUCCESS )
\r
613 return( p_vector->size );
\r