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