1/*
2 * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.
3 * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5 *
6 * This software is available to you under a choice of one of two
7 * licenses.  You may choose to be licensed under the terms of the GNU
8 * General Public License (GPL) Version 2, available from the file
9 * COPYING in the main directory of this source tree, or the
10 * OpenIB.org BSD license below:
11 *
12 *     Redistribution and use in source and binary forms, with or
13 *     without modification, are permitted provided that the following
14 *     conditions are met:
15 *
16 *      - Redistributions of source code must retain the above
17 *        copyright notice, this list of conditions and the following
18 *        disclaimer.
19 *
20 *      - Redistributions in binary form must reproduce the above
21 *        copyright notice, this list of conditions and the following
22 *        disclaimer in the documentation and/or other materials
23 *        provided with the distribution.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32 * SOFTWARE.
33 *
34 */
35
36/*
37 * Abstract:
38 *	This file contains ivector and isvector implementations.
39 *
40 */
41
42#if HAVE_CONFIG_H
43#  include <config.h>
44#endif				/* HAVE_CONFIG_H */
45
46#include <stdlib.h>
47#include <string.h>
48#include <complib/cl_ptr_vector.h>
49
50void cl_ptr_vector_construct(IN cl_ptr_vector_t * const p_vector)
51{
52	CL_ASSERT(p_vector);
53
54	memset(p_vector, 0, sizeof(cl_ptr_vector_t));
55
56	p_vector->state = CL_UNINITIALIZED;
57}
58
59cl_status_t
60cl_ptr_vector_init(IN cl_ptr_vector_t * const p_vector,
61		   IN const size_t min_size, IN const size_t grow_size)
62{
63	cl_status_t status = CL_SUCCESS;
64
65	CL_ASSERT(p_vector);
66
67	cl_ptr_vector_construct(p_vector);
68
69	p_vector->grow_size = grow_size;
70
71	/*
72	 * Set the state to initialized so that the call to set_size
73	 * doesn't assert.
74	 */
75	p_vector->state = CL_INITIALIZED;
76
77	/* get the storage needed by the user */
78	if (min_size) {
79		status = cl_ptr_vector_set_size(p_vector, min_size);
80		if (status != CL_SUCCESS)
81			cl_ptr_vector_destroy(p_vector);
82	}
83
84	return (status);
85}
86
87void cl_ptr_vector_destroy(IN cl_ptr_vector_t * const p_vector)
88{
89	CL_ASSERT(p_vector);
90	CL_ASSERT(cl_is_state_valid(p_vector->state));
91
92	/* Call the user's destructor for each element in the array. */
93	if (p_vector->state == CL_INITIALIZED) {
94		/* Destroy the page vector. */
95		if (p_vector->p_ptr_array) {
96			free((void *)p_vector->p_ptr_array);
97			p_vector->p_ptr_array = NULL;
98		}
99	}
100
101	p_vector->state = CL_UNINITIALIZED;
102}
103
104cl_status_t
105cl_ptr_vector_at(IN const cl_ptr_vector_t * const p_vector,
106		 IN const size_t index, OUT void **const p_element)
107{
108	CL_ASSERT(p_vector);
109	CL_ASSERT(p_vector->state == CL_INITIALIZED);
110
111	/* Range check */
112	if (index >= p_vector->size)
113		return (CL_INVALID_PARAMETER);
114
115	*p_element = cl_ptr_vector_get(p_vector, index);
116	return (CL_SUCCESS);
117}
118
119cl_status_t
120cl_ptr_vector_set(IN cl_ptr_vector_t * const p_vector,
121		  IN const size_t index, IN const void *const element)
122{
123	cl_status_t status;
124
125	CL_ASSERT(p_vector);
126	CL_ASSERT(p_vector->state == CL_INITIALIZED);
127
128	/* Determine if the vector has room for this element. */
129	if (index >= p_vector->size) {
130		/* Resize to accomodate the given index. */
131		status = cl_ptr_vector_set_size(p_vector, index + 1);
132
133		/* Check for failure on or before the given index. */
134		if ((status != CL_SUCCESS) && (p_vector->size < index))
135			return (status);
136	}
137
138	/* At this point, the array is guaranteed to be big enough */
139	p_vector->p_ptr_array[index] = element;
140
141	return (CL_SUCCESS);
142}
143
144void *cl_ptr_vector_remove(IN cl_ptr_vector_t * const p_vector,
145			   IN const size_t index)
146{
147	size_t src;
148	const void *element;
149
150	CL_ASSERT(p_vector);
151	CL_ASSERT(p_vector->state == CL_INITIALIZED);
152	CL_ASSERT(p_vector->size > index);
153
154	/* Store a copy of the element to return. */
155	element = p_vector->p_ptr_array[index];
156	/* Shift all items above the removed item down. */
157	if (index < --p_vector->size) {
158		for (src = index; src < p_vector->size; src++)
159			p_vector->p_ptr_array[src] =
160			    p_vector->p_ptr_array[src + 1];
161	}
162	/* Clear the entry for the element just outside of the new upper bound. */
163	p_vector->p_ptr_array[p_vector->size] = NULL;
164
165	return ((void *)element);
166}
167
168cl_status_t
169cl_ptr_vector_set_capacity(IN cl_ptr_vector_t * const p_vector,
170			   IN const size_t new_capacity)
171{
172	void *p_new_ptr_array;
173
174	CL_ASSERT(p_vector);
175	CL_ASSERT(p_vector->state == CL_INITIALIZED);
176
177	/* Do we have to do anything here? */
178	if (new_capacity <= p_vector->capacity) {
179		/* Nope */
180		return (CL_SUCCESS);
181	}
182
183	/* Allocate our pointer array. */
184	p_new_ptr_array = malloc(new_capacity * sizeof(void *));
185	if (!p_new_ptr_array)
186		return (CL_INSUFFICIENT_MEMORY);
187	else
188		memset(p_new_ptr_array, 0, new_capacity * sizeof(void *));
189
190	if (p_vector->p_ptr_array) {
191		/* Copy the old pointer array into the new. */
192		memcpy(p_new_ptr_array, p_vector->p_ptr_array,
193		       p_vector->capacity * sizeof(void *));
194
195		/* Free the old pointer array. */
196		free((void *)p_vector->p_ptr_array);
197	}
198
199	/* Set the new array. */
200	p_vector->p_ptr_array = p_new_ptr_array;
201
202	/* Update the vector with the new capactity. */
203	p_vector->capacity = new_capacity;
204
205	return (CL_SUCCESS);
206}
207
208cl_status_t
209cl_ptr_vector_set_size(IN cl_ptr_vector_t * const p_vector,
210		       IN const size_t size)
211{
212	cl_status_t status;
213	size_t new_capacity;
214
215	CL_ASSERT(p_vector);
216	CL_ASSERT(p_vector->state == CL_INITIALIZED);
217
218	/* Check to see if the requested size is the same as the existing size. */
219	if (size == p_vector->size)
220		return (CL_SUCCESS);
221
222	/* Determine if the vector has room for this element. */
223	if (size >= p_vector->capacity) {
224		if (!p_vector->grow_size)
225			return (CL_INSUFFICIENT_MEMORY);
226
227		/* Calculate the new capacity, taking into account the grow size. */
228		new_capacity = size;
229		if (size % p_vector->grow_size) {
230			/* Round up to nearest grow_size boundary. */
231			new_capacity += p_vector->grow_size -
232			    (size % p_vector->grow_size);
233		}
234
235		status = cl_ptr_vector_set_capacity(p_vector, new_capacity);
236		if (status != CL_SUCCESS)
237			return (status);
238	}
239
240	p_vector->size = size;
241	return (CL_SUCCESS);
242}
243
244cl_status_t
245cl_ptr_vector_set_min_size(IN cl_ptr_vector_t * const p_vector,
246			   IN const size_t min_size)
247{
248	CL_ASSERT(p_vector);
249	CL_ASSERT(p_vector->state == CL_INITIALIZED);
250
251	if (min_size > p_vector->size) {
252		/* We have to resize the array */
253		return (cl_ptr_vector_set_size(p_vector, min_size));
254	}
255
256	/* We didn't have to do anything */
257	return (CL_SUCCESS);
258}
259
260void
261cl_ptr_vector_apply_func(IN const cl_ptr_vector_t * const p_vector,
262			 IN cl_pfn_ptr_vec_apply_t pfn_callback,
263			 IN const void *const context)
264{
265	size_t i;
266
267	CL_ASSERT(p_vector);
268	CL_ASSERT(p_vector->state == CL_INITIALIZED);
269	CL_ASSERT(pfn_callback);
270
271	for (i = 0; i < p_vector->size; i++)
272		pfn_callback(i, (void *)p_vector->p_ptr_array[i],
273			     (void *)context);
274}
275
276size_t
277cl_ptr_vector_find_from_start(IN const cl_ptr_vector_t * const p_vector,
278			      IN cl_pfn_ptr_vec_find_t pfn_callback,
279			      IN const void *const context)
280{
281	size_t i;
282
283	CL_ASSERT(p_vector);
284	CL_ASSERT(p_vector->state == CL_INITIALIZED);
285	CL_ASSERT(pfn_callback);
286
287	for (i = 0; i < p_vector->size; i++) {
288		/* Invoke the callback */
289		if (pfn_callback(i, (void *)p_vector->p_ptr_array[i],
290				 (void *)context) == CL_SUCCESS) {
291			break;
292		}
293	}
294	return (i);
295}
296
297size_t
298cl_ptr_vector_find_from_end(IN const cl_ptr_vector_t * const p_vector,
299			    IN cl_pfn_ptr_vec_find_t pfn_callback,
300			    IN const void *const context)
301{
302	size_t i;
303
304	CL_ASSERT(p_vector);
305	CL_ASSERT(p_vector->state == CL_INITIALIZED);
306	CL_ASSERT(pfn_callback);
307
308	i = p_vector->size;
309
310	while (i) {
311		/* Invoke the callback for the current element. */
312		if (pfn_callback(i, (void *)p_vector->p_ptr_array[--i],
313				 (void *)context) == CL_SUCCESS) {
314			return (i);
315		}
316	}
317
318	return (p_vector->size);
319}
320