1 /*
2 * SPDX-FileCopyrightText: Copyright (c) 2015-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3 * SPDX-License-Identifier: MIT
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23 #include "containers/vector.h"
24
25 CONT_VTABLE_DEFN(Vector, vectIterRange_IMPL, NULL);
26
27 /**
28 * Check if the given index is contained in vector, that is if
29 * ((index >= 0) && (index < pVector->size))
30 */
31 static NvBool _vectIndexCheck(Vector *pVector, NvU32 index);
32
33 /**
34 * Reallocates container.
35 *
36 * Allocate a memory of 'newSize' bytes, then copy 'copySize' bytes from the old
37 * vector memory to the new one.
38 */
39 static NvBool _vectReallocHelper(Vector *pVector, NvU32 newSize, NvU32 copySize);
40
vectInit_IMPL(Vector * pVector,PORT_MEM_ALLOCATOR * pAllocator,NvU32 capacity,NvU32 valueSize)41 NV_STATUS vectInit_IMPL
42 (
43 Vector *pVector,
44 PORT_MEM_ALLOCATOR *pAllocator,
45 NvU32 capacity,
46 NvU32 valueSize
47 )
48 {
49 NV_ASSERT_OR_RETURN(pVector != NULL, NV_ERR_INVALID_ARGUMENT);
50 NV_ASSERT_OR_RETURN(pAllocator != NULL, NV_ERR_INVALID_ARGUMENT);
51 NV_CHECKED_ONLY(pVector->versionNumber++);
52
53 portMemSet(pVector, 0, sizeof(*pVector));
54 CONT_VTABLE_INIT(Vector, pVector);
55 pVector->pAllocator = pAllocator;
56 pVector->valueSize = valueSize;
57 pVector->capacity = capacity;
58 pVector->size = 0;
59
60 if (capacity > 0)
61 {
62 pVector->pHead = PORT_ALLOC(pVector->pAllocator,
63 capacity * pVector->valueSize);
64 if (NULL == pVector->pHead)
65 {
66 return NV_ERR_NO_MEMORY;
67 }
68
69 portMemSet(pVector->pHead, 0, capacity * pVector->valueSize);
70 }
71 return NV_OK;
72 }
73
vectDestroy_IMPL(Vector * pVector)74 void vectDestroy_IMPL(Vector *pVector)
75 {
76 NV_ASSERT_OR_RETURN_VOID(pVector != NULL);
77 NV_CHECKED_ONLY(pVector->versionNumber++);
78
79 PORT_FREE(pVector->pAllocator, pVector->pHead);
80 pVector->pHead = NULL;
81 pVector->capacity = 0;
82 pVector->size = 0;
83 }
84
vectClear_IMPL(Vector * pVector)85 void vectClear_IMPL(Vector *pVector)
86 {
87 NV_ASSERT_OR_RETURN_VOID(pVector != NULL);
88 NV_CHECKED_ONLY(pVector->versionNumber++);
89 pVector->size = 0;
90 }
91
vectAt_IMPL(Vector * pVector,NvU32 index)92 void *vectAt_IMPL
93 (
94 Vector *pVector,
95 NvU32 index
96 )
97 {
98 NV_ASSERT_OR_RETURN(pVector != NULL, NULL);
99 if ((pVector->size == 0) || !_vectIndexCheck(pVector, index))
100 {
101 return NULL;
102 }
103 return (void *)((NvU8 *)pVector->pHead + index * pVector->valueSize);
104 }
105
vectCapacity_IMPL(Vector * pVector)106 NvU32 vectCapacity_IMPL
107 (
108 Vector *pVector
109 )
110 {
111 NV_ASSERT_OR_RETURN(pVector != NULL, 0);
112 return pVector->capacity;
113 }
114
vectCount_IMPL(Vector * pVector)115 NvU32 vectCount_IMPL
116 (
117 Vector *pVector
118 )
119 {
120 NV_ASSERT_OR_RETURN(pVector != NULL, 0);
121 return pVector->size;
122 }
123
vectIsEmpty_IMPL(Vector * pVector)124 NvBool vectIsEmpty_IMPL
125 (
126 Vector *pVector
127 )
128 {
129 NV_ASSERT_OR_RETURN(pVector != NULL, 0);
130
131 return pVector->size == 0;
132 }
133
vectTrim_IMPL(Vector * pVector,NvU32 n)134 NV_STATUS vectTrim_IMPL
135 (
136 Vector *pVector,
137 NvU32 n
138 )
139 {
140 NV_ASSERT_OR_RETURN(pVector != NULL, NV_ERR_INVALID_ARGUMENT);
141 NV_CHECKED_ONLY(pVector->versionNumber++);
142
143 if (n > pVector->capacity)
144 {
145 return NV_OK;
146 }
147
148 if (n < pVector->size)
149 {
150 n = pVector->size;
151 }
152
153 if (!_vectReallocHelper(pVector,
154 n * pVector->valueSize,
155 pVector->size * pVector->valueSize))
156 {
157 return NV_ERR_NO_MEMORY;
158 }
159 return NV_OK;
160 }
161
vectReserve_IMPL(Vector * pVector,NvU32 n)162 NV_STATUS vectReserve_IMPL
163 (
164 Vector *pVector,
165 NvU32 n
166 )
167 {
168 NV_ASSERT_OR_RETURN(pVector != NULL, NV_ERR_INVALID_ARGUMENT);
169 NV_ASSERT_OR_RETURN(n > 0, NV_ERR_INVALID_ARGUMENT);
170 NV_CHECKED_ONLY(pVector->versionNumber++);
171
172 if (n > pVector->capacity)
173 {
174 if (!_vectReallocHelper(pVector,
175 n * pVector->valueSize,
176 pVector->size * pVector->valueSize))
177 {
178 return NV_ERR_NO_MEMORY;
179 }
180 }
181 return NV_OK;
182 }
183
vectInsert_IMPL(Vector * pVector,NvU32 index,const void * pData)184 void *vectInsert_IMPL
185 (
186 Vector *pVector,
187 NvU32 index,
188 const void *pData
189 )
190 {
191 void *dst;
192 void *src;
193 NvU32 i;
194 NV_ASSERT_OR_RETURN(pVector != NULL, NULL);
195 NV_CHECKED_ONLY(pVector->versionNumber++);
196 if (pVector->size != index)
197 {
198 NV_ASSERT_OR_RETURN(_vectIndexCheck(pVector, index), NULL);
199 }
200 if (pVector->size + 1 > pVector->capacity)
201 {
202 // resize the container by the factor of 2, newcapacity = capacity * 2
203 NvU32 newCapacity = pVector->capacity == 0 ? 10 : pVector->capacity * 2;
204
205 if (!_vectReallocHelper(pVector,
206 newCapacity * pVector->valueSize,
207 pVector->size * pVector->valueSize))
208 return NULL;
209 }
210
211 for (i = pVector->size; i > index; i--)
212 {
213 dst = (void *)((NvU8 *)pVector->pHead + i * pVector->valueSize);
214 src = (void *)((NvU8 *)pVector->pHead + (i - 1) * pVector->valueSize);
215 portMemCopy(dst, pVector->valueSize, src, pVector->valueSize);
216 }
217 pVector->size++;
218 dst = (void *)((NvU8 *)pVector->pHead + index * pVector->valueSize);
219 portMemCopy(dst, pVector->valueSize, pData, pVector->valueSize);
220
221 return dst;
222 }
223
vectRemove_IMPL(Vector * pVector,NvU32 index)224 void vectRemove_IMPL
225 (
226 Vector *pVector,
227 NvU32 index
228 )
229 {
230 void *src;
231 void *dst;
232 NvU32 i;
233 NV_ASSERT_OR_RETURN_VOID(pVector != NULL);
234 NV_CHECKED_ONLY(pVector->versionNumber++);
235 NV_ASSERT_OR_RETURN_VOID(_vectIndexCheck(pVector, index));
236
237 for (i = index; i < pVector->size - 1; i++)
238 {
239 dst = (void *)((NvU8 *)pVector->pHead + i * pVector->valueSize);
240 src = (void *)((NvU8 *)pVector->pHead + (i + 1) * pVector->valueSize);
241 portMemCopy(dst, pVector->valueSize, src, pVector->valueSize);
242 }
243
244 pVector->size--;
245 }
246
vectAppend_IMPL(Vector * pVector,const void * pData)247 void *vectAppend_IMPL
248 (
249 Vector *pVector,
250 const void *pData
251 )
252 {
253 return vectInsert_IMPL(pVector, pVector->size, pData);
254 }
255
vectPrepend_IMPL(Vector * pVector,const void * pData)256 void *vectPrepend_IMPL
257 (
258 Vector *pVector,
259 const void *pData
260 )
261 {
262 return vectInsert_IMPL(pVector, 0, pData);
263 }
264
vectIterRange_IMPL(Vector * pVector,void * pFirst,void * pLast)265 VectorIterBase vectIterRange_IMPL
266 (
267 Vector *pVector,
268 void *pFirst,
269 void *pLast
270 )
271 {
272 VectorIterBase it;
273 NvU32 first = ~0U;
274 NvU32 last = ~0U;
275 NV_ASSERT(pVector != NULL);
276
277 if (pFirst != NULL)
278 {
279 first = (NvU32)(((NvU8 *)pFirst - (NvU8 *)pVector->pHead) /
280 pVector->valueSize);
281 }
282 if (pLast != NULL)
283 {
284 last = (NvU32)(((NvU8 *)pLast - (NvU8 *)pVector->pHead) /
285 pVector->valueSize);
286 }
287
288 NV_CHECKED_ONLY(it.versionNumber = pVector->versionNumber);
289 NV_CHECKED_ONLY(it.bValid = NV_TRUE);
290
291 if ((pVector->size == 0) || (pFirst == NULL) || (first >= pVector->size) ||
292 (pLast == NULL) || (last >= pVector->size))
293 {
294 it.pVector = pVector;
295 it.nextIndex = -1;
296 it.prevIndex = -1;
297 it.firstIndex = -1;
298 it.lastIndex = -1;
299 it.bForward = NV_TRUE;
300 it.pValue = NULL;
301 return it;
302 }
303 it.pVector = pVector;
304 it.nextIndex = first;
305 it.prevIndex = last;
306 it.firstIndex = first;
307 it.lastIndex = last;
308 it.bForward = (first <= last);
309 it.pValue = NULL;
310 return it;
311 }
312
vectIterNext_IMPL(VectorIterBase * pIter,void ** ppValue)313 NvBool vectIterNext_IMPL
314 (
315 VectorIterBase *pIter,
316 void **ppValue
317 )
318 {
319 NV_ASSERT_OR_RETURN(pIter != NULL, NV_FALSE);
320 NV_ASSERT_OR_RETURN(ppValue != NULL, NV_FALSE);
321
322 if (pIter->nextIndex == -1)
323 {
324 return NV_FALSE;
325 }
326
327 #if PORT_IS_CHECKED_BUILD
328 if (pIter->bValid && !CONT_ITER_IS_VALID(pIter->pVector, pIter))
329 {
330 NV_ASSERT(CONT_ITER_IS_VALID(pIter->pVector, pIter));
331 PORT_DUMP_STACK();
332 pIter->bValid = NV_FALSE;
333 }
334 #endif
335
336 *ppValue = (void *)((NvU8 *)pIter->pVector->pHead +
337 pIter->nextIndex * pIter->pVector->valueSize);
338
339 pIter->prevIndex = pIter->bForward ? pIter->nextIndex - 1 :
340 pIter->nextIndex + 1;
341
342 if (pIter->nextIndex == pIter->lastIndex)
343 {
344 pIter->nextIndex = -1;
345 }
346 else
347 {
348 pIter->nextIndex = pIter->bForward ? pIter->nextIndex + 1 :
349 pIter->nextIndex - 1;
350 }
351
352 return NV_TRUE;
353 }
354
vectIterPrev_IMPL(VectorIterBase * pIter,void ** ppValue)355 NvBool vectIterPrev_IMPL
356 (
357 VectorIterBase *pIter,
358 void **ppValue
359 )
360 {
361 NV_ASSERT_OR_RETURN(pIter != NULL, NV_FALSE);
362 NV_ASSERT_OR_RETURN(ppValue != NULL, NV_FALSE);
363
364 if (pIter->prevIndex == -1)
365 {
366 return NV_FALSE;
367 }
368
369 #if PORT_IS_CHECKED_BUILD
370 if (pIter->bValid && !CONT_ITER_IS_VALID(pIter->pVector, pIter))
371 {
372 NV_ASSERT(CONT_ITER_IS_VALID(pIter->pVector, pIter));
373 PORT_DUMP_STACK();
374 pIter->bValid = NV_FALSE;
375 }
376 #endif
377
378 *ppValue = (void *)((NvU8 *)pIter->pVector->pHead +
379 pIter->prevIndex * pIter->pVector->valueSize);
380
381 pIter->nextIndex = pIter->bForward ? pIter->prevIndex + 1 :
382 pIter->prevIndex - 1;
383
384 if (pIter->prevIndex == pIter->firstIndex)
385 {
386 pIter->prevIndex = -1;
387 }
388 else
389 {
390 pIter->prevIndex = pIter->bForward ? pIter->prevIndex - 1 :
391 pIter->prevIndex + 1;
392 }
393
394 return NV_TRUE;
395 }
396
_vectReallocHelper(Vector * pVector,NvU32 newSize,NvU32 copySize)397 static NvBool _vectReallocHelper
398 (
399 Vector *pVector,
400 NvU32 newSize,
401 NvU32 copySize
402 )
403 {
404 void *pNewArray;
405 void *pCopiedArray;
406
407 NV_ASSERT_OR_RETURN(newSize >= copySize, NV_FALSE);
408
409 pNewArray = PORT_ALLOC(pVector->pAllocator, newSize);
410 if (pNewArray == NULL && newSize > 0)
411 {
412 return NV_FALSE;
413 }
414 portMemSet(pNewArray, 0, newSize);
415
416 if (copySize > 0)
417 {
418 pCopiedArray = portMemCopy(pNewArray, newSize,
419 pVector->pHead, copySize);
420 if (NULL == pCopiedArray)
421 {
422 NV_ASSERT(pCopiedArray);
423 PORT_FREE(pVector->pAllocator, pNewArray);
424 return NV_FALSE;
425 }
426
427 PORT_FREE(pVector->pAllocator, pVector->pHead);
428 pNewArray = pCopiedArray;
429 }
430
431 pVector->pHead = pNewArray;
432 pVector->capacity = newSize / pVector->valueSize;
433 pVector->size = copySize / pVector->valueSize;
434
435 return NV_TRUE;
436 }
437
_vectIndexCheck(Vector * pVector,NvU32 index)438 static NvBool _vectIndexCheck
439 (
440 Vector *pVector,
441 NvU32 index
442 )
443 {
444 void *pActualOffset, *pLastElem;
445
446 if (pVector->size == 0)
447 {
448 return NV_FALSE;
449 }
450
451 pActualOffset = (void *)((NvU8 *)pVector->pHead +
452 index * pVector->valueSize);
453
454 pLastElem = (void *)((NvU8 *)pVector->pHead +
455 (pVector->size - 1) * pVector->valueSize);
456
457 return ((void *)pVector->pHead <= pActualOffset &&
458 pActualOffset <= (void *)pLastElem);
459 }
460
vectIsValid_IMPL(void * pVect)461 NvBool vectIsValid_IMPL(void *pVect)
462 {
463 #if NV_TYPEOF_SUPPORTED
464 return NV_TRUE;
465 #else
466 if (CONT_VTABLE_VALID((Vector*)pVect))
467 return NV_TRUE;
468
469 NV_ASSERT_FAILED("vtable not valid!");
470 CONT_VTABLE_INIT(Vector, (Vector*)pVect);
471 return NV_FALSE;
472 #endif
473 }
474