1321936Shselasky/* 2321936Shselasky * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved. 3321936Shselasky * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. 4321936Shselasky * Copyright (c) 1996-2003 Intel Corporation. All rights reserved. 5321936Shselasky * 6321936Shselasky * This software is available to you under a choice of one of two 7321936Shselasky * licenses. You may choose to be licensed under the terms of the GNU 8321936Shselasky * General Public License (GPL) Version 2, available from the file 9321936Shselasky * COPYING in the main directory of this source tree, or the 10321936Shselasky * OpenIB.org BSD license below: 11321936Shselasky * 12321936Shselasky * Redistribution and use in source and binary forms, with or 13321936Shselasky * without modification, are permitted provided that the following 14321936Shselasky * conditions are met: 15321936Shselasky * 16321936Shselasky * - Redistributions of source code must retain the above 17321936Shselasky * copyright notice, this list of conditions and the following 18321936Shselasky * disclaimer. 19321936Shselasky * 20321936Shselasky * - Redistributions in binary form must reproduce the above 21321936Shselasky * copyright notice, this list of conditions and the following 22321936Shselasky * disclaimer in the documentation and/or other materials 23321936Shselasky * provided with the distribution. 24321936Shselasky * 25321936Shselasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26321936Shselasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27321936Shselasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28321936Shselasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29321936Shselasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30321936Shselasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31321936Shselasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32321936Shselasky * SOFTWARE. 33321936Shselasky * 34321936Shselasky */ 35321936Shselasky 36321936Shselasky/* 37321936Shselasky * Abstract: 38321936Shselasky * This file contains ivector and isvector implementations. 39321936Shselasky * 40321936Shselasky */ 41321936Shselasky 42321936Shselasky#if HAVE_CONFIG_H 43321936Shselasky# include <config.h> 44321936Shselasky#endif /* HAVE_CONFIG_H */ 45321936Shselasky 46321936Shselasky#include <stdlib.h> 47321936Shselasky#include <string.h> 48321936Shselasky#include <complib/cl_vector.h> 49321936Shselasky 50321936Shselasky/* 51321936Shselasky * Define the maximum size for array pages in an cl_vector_t. 52321936Shselasky * This size is in objects, not bytes. 53321936Shselasky */ 54321936Shselasky#define SVEC_MAX_PAGE_SIZE 0x1000 55321936Shselasky 56321936Shselasky/* 57321936Shselasky * cl_vector_copy_general 58321936Shselasky * 59321936Shselasky * Description: 60321936Shselasky * copy operator used when size of the user object doesn't fit one of the 61321936Shselasky * other optimized copy functions. 62321936Shselasky * 63321936Shselasky * Inputs: 64321936Shselasky * p_src - source for copy 65321936Shselasky * 66321936Shselasky * Outputs: 67321936Shselasky * p_dest - destination for copy 68321936Shselasky * 69321936Shselasky * Returns: 70321936Shselasky * None 71321936Shselasky * 72321936Shselasky */ 73321936Shselaskystatic void cl_vector_copy_general(OUT void *const p_dest, 74321936Shselasky IN const void *const p_src, 75321936Shselasky IN const size_t size) 76321936Shselasky{ 77321936Shselasky memcpy(p_dest, p_src, size); 78321936Shselasky} 79321936Shselasky 80321936Shselasky/* 81321936Shselasky * cl_vector_copy8 82321936Shselasky * 83321936Shselasky * Description: 84321936Shselasky * copy operator used when the user structure is only 8 bits long. 85321936Shselasky * 86321936Shselasky * Inputs: 87321936Shselasky * p_src - source for copy 88321936Shselasky * 89321936Shselasky * Outputs: 90321936Shselasky * p_dest - destination for copy 91321936Shselasky * 92321936Shselasky * Returns: 93321936Shselasky * None 94321936Shselasky * 95321936Shselasky */ 96321936Shselaskystatic void cl_vector_copy8(OUT void *const p_dest, 97321936Shselasky IN const void *const p_src, IN const size_t size) 98321936Shselasky{ 99321936Shselasky CL_ASSERT(size == sizeof(uint8_t)); 100321936Shselasky UNUSED_PARAM(size); 101321936Shselasky 102321936Shselasky *(uint8_t *) p_dest = *(uint8_t *) p_src; 103321936Shselasky} 104321936Shselasky 105321936Shselasky/* 106321936Shselasky * cl_vector_copy16 107321936Shselasky * 108321936Shselasky * Description: 109321936Shselasky * copy operator used when the user structure is only 16 bits long. 110321936Shselasky * 111321936Shselasky * Inputs: 112321936Shselasky * p_src - source for copy 113321936Shselasky * 114321936Shselasky * Outputs: 115321936Shselasky * p_dest - destination for copy 116321936Shselasky * 117321936Shselasky * Returns: 118321936Shselasky * None 119321936Shselasky * 120321936Shselasky */ 121321936Shselaskyvoid cl_vector_copy16(OUT void *const p_dest, 122321936Shselasky IN const void *const p_src, IN const size_t size) 123321936Shselasky{ 124321936Shselasky CL_ASSERT(size == sizeof(uint16_t)); 125321936Shselasky UNUSED_PARAM(size); 126321936Shselasky 127321936Shselasky *(uint16_t *) p_dest = *(uint16_t *) p_src; 128321936Shselasky} 129321936Shselasky 130321936Shselasky/* 131321936Shselasky * cl_vector_copy32 132321936Shselasky * 133321936Shselasky * Description: 134321936Shselasky * copy operator used when the user structure is only 32 bits long. 135321936Shselasky * 136321936Shselasky * Inputs: 137321936Shselasky * p_src - source for copy 138321936Shselasky * 139321936Shselasky * Outputs: 140321936Shselasky * p_dest - destination for copy 141321936Shselasky * 142321936Shselasky * Returns: 143321936Shselasky * None 144321936Shselasky * 145321936Shselasky */ 146321936Shselaskyvoid cl_vector_copy32(OUT void *const p_dest, 147321936Shselasky IN const void *const p_src, IN const size_t size) 148321936Shselasky{ 149321936Shselasky CL_ASSERT(size == sizeof(uint32_t)); 150321936Shselasky UNUSED_PARAM(size); 151321936Shselasky 152321936Shselasky *(uint32_t *) p_dest = *(uint32_t *) p_src; 153321936Shselasky} 154321936Shselasky 155321936Shselasky/* 156321936Shselasky * cl_vector_copy64 157321936Shselasky * 158321936Shselasky * Description: 159321936Shselasky * copy operator used when the user structure is only 64 bits long. 160321936Shselasky * 161321936Shselasky * Inputs: 162321936Shselasky * p_src - source for copy 163321936Shselasky * 164321936Shselasky * Outputs: 165321936Shselasky * p_dest - destination for copy 166321936Shselasky * 167321936Shselasky * Returns: 168321936Shselasky * None 169321936Shselasky * 170321936Shselasky */ 171321936Shselaskyvoid cl_vector_copy64(OUT void *const p_dest, 172321936Shselasky IN const void *const p_src, IN const size_t size) 173321936Shselasky{ 174321936Shselasky CL_ASSERT(size == sizeof(uint64_t)); 175321936Shselasky UNUSED_PARAM(size); 176321936Shselasky 177321936Shselasky *(uint64_t *) p_dest = *(uint64_t *) p_src; 178321936Shselasky} 179321936Shselasky 180321936Shselaskyvoid cl_vector_construct(IN cl_vector_t * const p_vector) 181321936Shselasky{ 182321936Shselasky CL_ASSERT(p_vector); 183321936Shselasky 184321936Shselasky memset(p_vector, 0, sizeof(cl_vector_t)); 185321936Shselasky 186321936Shselasky p_vector->state = CL_UNINITIALIZED; 187321936Shselasky} 188321936Shselasky 189321936Shselaskycl_status_t cl_vector_init(IN cl_vector_t * const p_vector, 190321936Shselasky IN const size_t min_size, IN const size_t grow_size, 191321936Shselasky IN const size_t element_size, 192321936Shselasky IN cl_pfn_vec_init_t pfn_init OPTIONAL, 193321936Shselasky IN cl_pfn_vec_dtor_t pfn_dtor OPTIONAL, 194321936Shselasky IN const void *const context) 195321936Shselasky{ 196321936Shselasky cl_status_t status = CL_SUCCESS; 197321936Shselasky 198321936Shselasky CL_ASSERT(p_vector); 199321936Shselasky CL_ASSERT(element_size); 200321936Shselasky 201321936Shselasky cl_vector_construct(p_vector); 202321936Shselasky 203321936Shselasky p_vector->grow_size = grow_size; 204321936Shselasky p_vector->element_size = element_size; 205321936Shselasky p_vector->pfn_init = pfn_init; 206321936Shselasky p_vector->pfn_dtor = pfn_dtor; 207321936Shselasky p_vector->context = context; 208321936Shselasky 209321936Shselasky /* 210321936Shselasky * Try to choose a smart copy operator 211321936Shselasky * someday, we could simply let the users pass one in 212321936Shselasky */ 213321936Shselasky switch (element_size) { 214321936Shselasky case sizeof(uint8_t): 215321936Shselasky p_vector->pfn_copy = cl_vector_copy8; 216321936Shselasky break; 217321936Shselasky 218321936Shselasky case sizeof(uint16_t): 219321936Shselasky p_vector->pfn_copy = cl_vector_copy16; 220321936Shselasky break; 221321936Shselasky 222321936Shselasky case sizeof(uint32_t): 223321936Shselasky p_vector->pfn_copy = cl_vector_copy32; 224321936Shselasky break; 225321936Shselasky 226321936Shselasky case sizeof(uint64_t): 227321936Shselasky p_vector->pfn_copy = cl_vector_copy64; 228321936Shselasky break; 229321936Shselasky 230321936Shselasky default: 231321936Shselasky p_vector->pfn_copy = cl_vector_copy_general; 232321936Shselasky break; 233321936Shselasky } 234321936Shselasky 235321936Shselasky /* 236321936Shselasky * Set the state to initialized so that the call to set_size 237321936Shselasky * doesn't assert. 238321936Shselasky */ 239321936Shselasky p_vector->state = CL_INITIALIZED; 240321936Shselasky 241321936Shselasky /* Initialize the allocation list */ 242321936Shselasky cl_qlist_init(&p_vector->alloc_list); 243321936Shselasky 244321936Shselasky /* get the storage needed by the user */ 245321936Shselasky if (min_size) { 246321936Shselasky status = cl_vector_set_size(p_vector, min_size); 247321936Shselasky if (status != CL_SUCCESS) 248321936Shselasky cl_vector_destroy(p_vector); 249321936Shselasky } 250321936Shselasky 251321936Shselasky return (status); 252321936Shselasky} 253321936Shselasky 254321936Shselaskyvoid cl_vector_destroy(IN cl_vector_t * const p_vector) 255321936Shselasky{ 256321936Shselasky size_t i; 257321936Shselasky void *p_element; 258321936Shselasky 259321936Shselasky CL_ASSERT(p_vector); 260321936Shselasky CL_ASSERT(cl_is_state_valid(p_vector->state)); 261321936Shselasky 262321936Shselasky /* Call the user's destructor for each element in the array. */ 263321936Shselasky if (p_vector->state == CL_INITIALIZED) { 264321936Shselasky if (p_vector->pfn_dtor) { 265321936Shselasky for (i = 0; i < p_vector->size; i++) { 266321936Shselasky p_element = p_vector->p_ptr_array[i]; 267321936Shselasky /* Sanity check! */ 268321936Shselasky CL_ASSERT(p_element); 269321936Shselasky p_vector->pfn_dtor(p_element, 270321936Shselasky (void *)p_vector->context); 271321936Shselasky } 272321936Shselasky } 273321936Shselasky 274321936Shselasky /* Deallocate the pages */ 275321936Shselasky while (!cl_is_qlist_empty(&p_vector->alloc_list)) 276321936Shselasky free(cl_qlist_remove_head(&p_vector->alloc_list)); 277321936Shselasky 278321936Shselasky /* Destroy the page vector. */ 279321936Shselasky if (p_vector->p_ptr_array) { 280321936Shselasky free(p_vector->p_ptr_array); 281321936Shselasky p_vector->p_ptr_array = NULL; 282321936Shselasky } 283321936Shselasky } 284321936Shselasky 285321936Shselasky p_vector->state = CL_UNINITIALIZED; 286321936Shselasky} 287321936Shselasky 288321936Shselaskycl_status_t cl_vector_at(IN const cl_vector_t * const p_vector, 289321936Shselasky IN const size_t index, OUT void *const p_element) 290321936Shselasky{ 291321936Shselasky CL_ASSERT(p_vector); 292321936Shselasky CL_ASSERT(p_vector->state == CL_INITIALIZED); 293321936Shselasky 294321936Shselasky /* Range check */ 295321936Shselasky if (index >= p_vector->size) 296321936Shselasky return (CL_INVALID_PARAMETER); 297321936Shselasky 298321936Shselasky cl_vector_get(p_vector, index, p_element); 299321936Shselasky return (CL_SUCCESS); 300321936Shselasky} 301321936Shselasky 302321936Shselaskycl_status_t cl_vector_set(IN cl_vector_t * const p_vector, 303321936Shselasky IN const size_t index, IN void *const p_element) 304321936Shselasky{ 305321936Shselasky cl_status_t status; 306321936Shselasky void *p_dest; 307321936Shselasky 308321936Shselasky CL_ASSERT(p_vector); 309321936Shselasky CL_ASSERT(p_vector->state == CL_INITIALIZED); 310321936Shselasky CL_ASSERT(p_element); 311321936Shselasky 312321936Shselasky /* Determine if the vector has room for this element. */ 313321936Shselasky if (index >= p_vector->size) { 314321936Shselasky /* Resize to accomodate the given index. */ 315321936Shselasky status = cl_vector_set_size(p_vector, index + 1); 316321936Shselasky 317321936Shselasky /* Check for failure on or before the given index. */ 318321936Shselasky if ((status != CL_SUCCESS) && (p_vector->size < index)) 319321936Shselasky return (status); 320321936Shselasky } 321321936Shselasky 322321936Shselasky /* At this point, the array is guaranteed to be big enough */ 323321936Shselasky p_dest = cl_vector_get_ptr(p_vector, index); 324321936Shselasky /* Sanity check! */ 325321936Shselasky CL_ASSERT(p_dest); 326321936Shselasky 327321936Shselasky /* Copy the data into the array */ 328321936Shselasky p_vector->pfn_copy(p_dest, p_element, p_vector->element_size); 329321936Shselasky 330321936Shselasky return (CL_SUCCESS); 331321936Shselasky} 332321936Shselasky 333321936Shselaskycl_status_t cl_vector_set_capacity(IN cl_vector_t * const p_vector, 334321936Shselasky IN const size_t new_capacity) 335321936Shselasky{ 336321936Shselasky size_t new_elements; 337321936Shselasky size_t alloc_size; 338321936Shselasky size_t i; 339321936Shselasky cl_list_item_t *p_buf; 340321936Shselasky void *p_new_ptr_array; 341321936Shselasky 342321936Shselasky CL_ASSERT(p_vector); 343321936Shselasky CL_ASSERT(p_vector->state == CL_INITIALIZED); 344321936Shselasky 345321936Shselasky /* Do we have to do anything here? */ 346321936Shselasky if (new_capacity <= p_vector->capacity) { 347321936Shselasky /* Nope */ 348321936Shselasky return (CL_SUCCESS); 349321936Shselasky } 350321936Shselasky 351321936Shselasky /* Allocate our pointer array. */ 352321936Shselasky p_new_ptr_array = malloc(new_capacity * sizeof(void *)); 353321936Shselasky if (!p_new_ptr_array) 354321936Shselasky return (CL_INSUFFICIENT_MEMORY); 355321936Shselasky else 356321936Shselasky memset(p_new_ptr_array, 0, new_capacity * sizeof(void *)); 357321936Shselasky 358321936Shselasky if (p_vector->p_ptr_array) { 359321936Shselasky /* Copy the old pointer array into the new. */ 360321936Shselasky memcpy(p_new_ptr_array, p_vector->p_ptr_array, 361321936Shselasky p_vector->capacity * sizeof(void *)); 362321936Shselasky 363321936Shselasky /* Free the old pointer array. */ 364321936Shselasky free(p_vector->p_ptr_array); 365321936Shselasky } 366321936Shselasky 367321936Shselasky /* Set the new array. */ 368321936Shselasky p_vector->p_ptr_array = p_new_ptr_array; 369321936Shselasky 370321936Shselasky /* 371321936Shselasky * We have to add capacity to the array. Determine how many 372321936Shselasky * elements to add. 373321936Shselasky */ 374321936Shselasky new_elements = new_capacity - p_vector->capacity; 375321936Shselasky /* Determine the allocation size for the new array elements. */ 376321936Shselasky alloc_size = new_elements * p_vector->element_size; 377321936Shselasky 378321936Shselasky p_buf = (cl_list_item_t *) malloc(alloc_size + sizeof(cl_list_item_t)); 379321936Shselasky if (!p_buf) 380321936Shselasky return (CL_INSUFFICIENT_MEMORY); 381321936Shselasky else 382321936Shselasky memset(p_buf, 0, alloc_size + sizeof(cl_list_item_t)); 383321936Shselasky 384321936Shselasky cl_qlist_insert_tail(&p_vector->alloc_list, p_buf); 385321936Shselasky /* Advance the buffer pointer past the list item. */ 386321936Shselasky p_buf++; 387321936Shselasky 388321936Shselasky for (i = p_vector->capacity; i < new_capacity; i++) { 389321936Shselasky p_vector->p_ptr_array[i] = p_buf; 390321936Shselasky /* Move the buffer pointer to the next element. */ 391321936Shselasky p_buf = (void *)(((uint8_t *) p_buf) + p_vector->element_size); 392321936Shselasky } 393321936Shselasky 394321936Shselasky /* Update the vector with the new capactity. */ 395321936Shselasky p_vector->capacity = new_capacity; 396321936Shselasky 397321936Shselasky return (CL_SUCCESS); 398321936Shselasky} 399321936Shselasky 400321936Shselaskycl_status_t cl_vector_set_size(IN cl_vector_t * const p_vector, 401321936Shselasky IN const size_t size) 402321936Shselasky{ 403321936Shselasky cl_status_t status; 404321936Shselasky size_t new_capacity; 405321936Shselasky size_t index; 406321936Shselasky void *p_element; 407321936Shselasky 408321936Shselasky CL_ASSERT(p_vector); 409321936Shselasky CL_ASSERT(p_vector->state == CL_INITIALIZED); 410321936Shselasky 411321936Shselasky /* Check to see if the requested size is the same as the existing size. */ 412321936Shselasky if (size == p_vector->size) 413321936Shselasky return (CL_SUCCESS); 414321936Shselasky 415321936Shselasky /* Determine if the vector has room for this element. */ 416321936Shselasky if (size >= p_vector->capacity) { 417321936Shselasky if (!p_vector->grow_size) 418321936Shselasky return (CL_INSUFFICIENT_MEMORY); 419321936Shselasky 420321936Shselasky /* Calculate the new capacity, taking into account the grow size. */ 421321936Shselasky new_capacity = size; 422321936Shselasky if (size % p_vector->grow_size) { 423321936Shselasky /* Round up to nearest grow_size boundary. */ 424321936Shselasky new_capacity += p_vector->grow_size - 425321936Shselasky (size % p_vector->grow_size); 426321936Shselasky } 427321936Shselasky 428321936Shselasky status = cl_vector_set_capacity(p_vector, new_capacity); 429321936Shselasky if (status != CL_SUCCESS) 430321936Shselasky return (status); 431321936Shselasky } 432321936Shselasky 433321936Shselasky /* Are we growing the array and need to invoke an initializer callback? */ 434321936Shselasky if (size > p_vector->size && p_vector->pfn_init) { 435321936Shselasky for (index = p_vector->size; index < size; index++) { 436321936Shselasky /* Get a pointer to this element */ 437321936Shselasky p_element = cl_vector_get_ptr(p_vector, index); 438321936Shselasky 439321936Shselasky /* Call the user's initializer and trap failures. */ 440321936Shselasky status = 441321936Shselasky p_vector->pfn_init(p_element, 442321936Shselasky (void *)p_vector->context); 443321936Shselasky if (status != CL_SUCCESS) { 444321936Shselasky /* Call the destructor for this object */ 445321936Shselasky if (p_vector->pfn_dtor) 446321936Shselasky p_vector->pfn_dtor(p_element, 447321936Shselasky (void *)p_vector-> 448321936Shselasky context); 449321936Shselasky 450321936Shselasky /* Return the failure status to the caller. */ 451321936Shselasky return (status); 452321936Shselasky } 453321936Shselasky 454321936Shselasky /* The array just grew by one element */ 455321936Shselasky p_vector->size++; 456321936Shselasky } 457321936Shselasky } else if (p_vector->pfn_dtor) { 458321936Shselasky /* The array is shrinking and there is a destructor to invoke. */ 459321936Shselasky for (index = size; index < p_vector->size; index++) { 460321936Shselasky /* compute the address of the new elements */ 461321936Shselasky p_element = cl_vector_get_ptr(p_vector, index); 462321936Shselasky /* call the user's destructor */ 463321936Shselasky p_vector->pfn_dtor(p_element, 464321936Shselasky (void *)p_vector->context); 465321936Shselasky } 466321936Shselasky } 467321936Shselasky 468321936Shselasky p_vector->size = size; 469321936Shselasky return (CL_SUCCESS); 470321936Shselasky} 471321936Shselasky 472321936Shselaskycl_status_t cl_vector_set_min_size(IN cl_vector_t * const p_vector, 473321936Shselasky IN const size_t min_size) 474321936Shselasky{ 475321936Shselasky CL_ASSERT(p_vector); 476321936Shselasky CL_ASSERT(p_vector->state == CL_INITIALIZED); 477321936Shselasky 478321936Shselasky if (min_size > p_vector->size) { 479321936Shselasky /* We have to resize the array */ 480321936Shselasky return (cl_vector_set_size(p_vector, min_size)); 481321936Shselasky } 482321936Shselasky 483321936Shselasky /* We didn't have to do anything */ 484321936Shselasky return (CL_SUCCESS); 485321936Shselasky} 486321936Shselasky 487321936Shselaskyvoid cl_vector_apply_func(IN const cl_vector_t * const p_vector, 488321936Shselasky IN cl_pfn_vec_apply_t pfn_callback, 489321936Shselasky IN const void *const context) 490321936Shselasky{ 491321936Shselasky size_t i; 492321936Shselasky void *p_element; 493321936Shselasky 494321936Shselasky CL_ASSERT(p_vector); 495321936Shselasky CL_ASSERT(p_vector->state == CL_INITIALIZED); 496321936Shselasky CL_ASSERT(pfn_callback); 497321936Shselasky 498321936Shselasky for (i = 0; i < p_vector->size; i++) { 499321936Shselasky p_element = cl_vector_get_ptr(p_vector, i); 500321936Shselasky pfn_callback(i, p_element, (void *)context); 501321936Shselasky } 502321936Shselasky} 503321936Shselasky 504321936Shselaskysize_t cl_vector_find_from_start(IN const cl_vector_t * const p_vector, 505321936Shselasky IN cl_pfn_vec_find_t pfn_callback, 506321936Shselasky IN const void *const context) 507321936Shselasky{ 508321936Shselasky size_t i; 509321936Shselasky void *p_element; 510321936Shselasky 511321936Shselasky CL_ASSERT(p_vector); 512321936Shselasky CL_ASSERT(p_vector->state == CL_INITIALIZED); 513321936Shselasky CL_ASSERT(pfn_callback); 514321936Shselasky 515321936Shselasky for (i = 0; i < p_vector->size; i++) { 516321936Shselasky p_element = cl_vector_get_ptr(p_vector, i); 517321936Shselasky /* Invoke the callback */ 518321936Shselasky if (pfn_callback(i, p_element, (void *)context) == CL_SUCCESS) 519321936Shselasky break; 520321936Shselasky } 521321936Shselasky return (i); 522321936Shselasky} 523321936Shselasky 524321936Shselaskysize_t cl_vector_find_from_end(IN const cl_vector_t * const p_vector, 525321936Shselasky IN cl_pfn_vec_find_t pfn_callback, 526321936Shselasky IN const void *const context) 527321936Shselasky{ 528321936Shselasky size_t i; 529321936Shselasky void *p_element; 530321936Shselasky 531321936Shselasky CL_ASSERT(p_vector); 532321936Shselasky CL_ASSERT(p_vector->state == CL_INITIALIZED); 533321936Shselasky CL_ASSERT(pfn_callback); 534321936Shselasky 535321936Shselasky i = p_vector->size; 536321936Shselasky 537321936Shselasky while (i) { 538321936Shselasky /* Get a pointer to the element in the array. */ 539321936Shselasky p_element = cl_vector_get_ptr(p_vector, --i); 540321936Shselasky CL_ASSERT(p_element); 541321936Shselasky 542321936Shselasky /* Invoke the callback for the current element. */ 543321936Shselasky if (pfn_callback(i, p_element, (void *)context) == CL_SUCCESS) 544321936Shselasky return (i); 545321936Shselasky } 546321936Shselasky 547321936Shselasky return (p_vector->size); 548321936Shselasky} 549