1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
/**
* Copyright (C) Mellanox Technologies Ltd. 2001-2013. ALL RIGHTS RESERVED.
* Copyright (C) Huawei Technologies Co., Ltd. 2020. ALL RIGHTS RESERVED.
*
* See file LICENSE for terms.
*/
/*
* Array element layout:
*
* 64 32 1 0
* +-----------------+----------------+---+
* free: | free_ahead | next index | 1 |
* +-----------------+----------------+---+
* used: | user pointer | 0 |
* +-----------------+----------------+---+
*
*
* free_ahead is the number of consecutive free elements ahead.
*
* The remove / insert algorithm works as follows:
* On remove of an index: If start[index+1] is free ==>
* start[index].free_elements_ahead = start[index+1].free_elements_ahead+1
* Then, the removed index is pushed to the HEAD of the freelist.
* NOTE, that if start[index+1] is free ==> It's already in the freelist !!!
*
* On insert, we fetch the first entry of the freelist and we rely on the
* fact that the remove/insert mechanism effectively implements a LIFO
* freelist, i.e. the last item pushed into the freelist will be fetched
* first ==> There is no chance that index+1 will be fetched before index,
* since index+1 was already in the list before index was put into the list.
*
* Therefore, we can rely on the free_size_ahead field to tell how many free
* elements are from any index in the freelist.
*
* To clarify, "free_ahead" is a best-effort optimization, so when it is not
* updated on removal - the for-each code runs slower, but still correctly.
* This decision was made in order to preserve the O(1) performance of
* ucs_ptr_array_remove() - at the expense of ptr_array_for_each() performance.
* If we wanted to favor ptr_array_for_each() we had to update "free_ahead"
* values in all the empty cells before the changed one, a noticeable overhead.
* Instead, the for-each checks if the cell is empty even if it's indicated as
* such by "free_ahead". As for insert() - a new cell can be either inserted
* right after an occupied cell (no need to update "free_ahead") or instead of
* a removed cell (so that "free_ahead" already points to it). The resulting
* effect is that "free_ahead" may have "false positives" but never "false
* negatives". Set() is different, because it "messes" with this logic - and
* can create that "false negative". This is why it requires such a complicated
* update of the "free_ahead" (unless the set overwrites an occupied cell).
*
*/
typedef uint64_t ucs_ptr_array_elem_t;
/**
* A sparse array of pointers.
*/
typedef struct ucs_ptr_array ucs_ptr_array_t;
/* Flags added to lower bits of the value */
/**
* Initialize the array.
*
* @param [in] ptr_array Pointer to a ptr array.
* @param [in] name The name of the ptr array.
*/
void ;
/**
* Cleanup the array.
*
* @param ptr_array Pointer to a ptr array.
* @param leak_check Whether to check for leaks (elements which were not
* freed from this ptr array).
*/
void ;
/**
* Insert a pointer to the array.
*
* @param [in] ptr_array Pointer to a ptr array.
* @param [in] value Pointer to insert. Must be 8-byte aligned.
*
* @return The index to which the value was inserted.
*
* Complexity: amortized O(1)
*
* @note The array will grow if needed.
*/
unsigned ;
/**
* Allocate a number of contiguous array slots.
*
* @param [in] ptr_array Pointer to a ptr array.
* @param [in] element_count Number of slots to allocate
*
* @return The index of the requested amount of slots (initialized to zero).
*
* Complexity: O(n*n) - not recommended for data-path
*
* @note The array will grow if needed.
* @note Use @ref ucs_ptr_array_remove to "deallocate" the slots.
*/
unsigned
;
/**
* Set a pointer in the array, overwriting the contents of the slot.
*
* @param [in] ptr_array Pointer to a ptr array.
* @param [in] element_index Index of slot.
* @param [in] new_val Value to put into slot given by index.
*
* Complexity: O(n)
*/
void ;
/**
* Remove a pointer from the array.
*
* @param [in] ptr_array Pointer to a ptr array.
* @param [in] element_index Index to remove from.
*
* Complexity: O(1)
*/
void ;
/**
* Replace pointer in the array, assuming the slot is occupied.
*
* @param [in] ptr_array Pointer to a ptr array.
* @param [in] element_index Index of slot.
* @param [in] new_val Value to put into slot given by index.
*
* @return Old value of the slot
*/
void *;
/**
* Get the current number of elements in the ptr array.
*
* @param [in] ptr_array Pointer to a ptr array.
*
* @return Number of elements of the ptr array.
*/
static UCS_F_ALWAYS_INLINE unsigned
/**
* Check whether the ptr array is empty.
*
* @param [in] ptr_array Pointer to a ptr array.
*
* @return Whether the ptr array is empty.
*/
static UCS_F_ALWAYS_INLINE int
/**
* Retrieve a value from the array.
*
* @param [in] _ptr_array Pointer to a ptr array.
* @param [in] _index Index to retrieve the value from.
* @param [out] _var Filled with the value.
*
* @return Whether the value is present and valid.
*
* Complexity: O(1)
*/
/**
* For-each user function: Calculates how many free elements are ahead.
*
* @param [in] ptr_array Pointer to a ptr array.
* @param [in] element_index Index of slot
*
* @return size_elem - The number of free elements ahead if free, if not 1.
*/
static UCS_F_ALWAYS_INLINE uint32_t
/**
* Check if element is free.
*
* @param [in] _elem An element in the ptr array.
*
* @return 1 if the element is free and 0 if it's occupied.
*/
/**
* Iterate over all valid elements in the array.
*
* @param [out] _var Pointer to current array element in the foreach.
* @param [out] _index Index variable to use as iterator (unsigned).
* @param [in] _ptr_array Pointer to a ptr array.
*/
/**
* Locked interface
*/
/* Locked ptr array */
typedef struct ucs_ptr_array_locked ucs_ptr_array_locked_t;
/**
* Locked array init
*
* @param [in] locked_ptr_array Pointer to a locked ptr array.
* @param [in] name The name of the ptr array.
*
* @return Success or failure.
*/
ucs_status_t
;
/**
* Cleanup the locked array.
*
* @param [in] locked_ptr_array Pointer to a locked ptr array.
* @param leak_check Whether to check for leaks (elements which were not
* freed from this ptr array).
*/
void ;
/**
* Insert a pointer to the locked array.
*
* @param [in] locked_ptr_array Pointer to a locked ptr array.
* @param [in] value Pointer to insert. Must be 8-byte aligned.
*
* @return The index to which the value was inserted.
*
* Complexity: Amortized O(1)
*
* @note The array will grow if needed.
*/
unsigned ;
/**
* Allocate a number of contiguous slots in the locked array.
*
* @param [in] locked_ptr_array Pointer to a locked ptr array.
* @param [in] element_count Number of slots to allocate
*
* @return The index of the requested amount of slots (initialized to zero).
*
* Complexity: O(n*n) - not recommended for data-path
*
* @note The array will grow if needed.
* @note Use @ref ucs_ptr_array_locked_remove to "deallocate" the slots.
*/
unsigned
;
/**
* Set a pointer in the array, overwriting the contents of the slot.
*
* @param [in] locked_ptr_array Pointer to a locked ptr array.
* @param [in] element_index Index of slot.
* @param [in] new_val Value to put into slot given by index.
*
* Complexity: O(n)
*/
void ;
/**
* Remove a pointer from the locked array.
*
* @param [in] locked_ptr_array Pointer to a locked ptr array.
* @param [in] element_index Index to remove from.
*
* Complexity: O(1)
*/
void ;
/**
* Replace pointer in the locked array, assuming the slot is occupied.
*
* @param [in] locked_ptr_array Pointer to a locked ptr array.
* @param [in] element_index Index of slot.
* @param [in] new_val Value to put into slot given by index.
*
* @return Old value of the slot
*
* Complexity: O(1)
*/
void *;
/**
* Acquire the ptr_array lock.
*
* @param [in] _locked_ptr_array Pointer to a locked ptr array.
*/
/**
* Release the ptr_array lock.
*
* @param [in] _locked_ptr_array Pointer to a locked ptr array.
*/
/**
* Retrieves a value from the locked array.
*
* @param [in] locked_ptr_array Pointer to a locked ptr array.
* @param [in] element_index Index to retrieve the value from.
* @param [out] var Filled with the value.
*
* @return Whether the value is present and valid.
*
* Complexity: O(1)
*/
static UCS_F_ALWAYS_INLINE int
/**
* Get the number of elements in the locked ptr array
*
* @param [in] locked_ptr_array Pointer to a locked ptr array.
*
* @return Number of elements in the locked ptr array.
*/
static UCS_F_ALWAYS_INLINE unsigned
/**
* Check whether the locked ptr array is empty.
*
* @param [in] ptr_array Pointer to a locked ptr array.
*
* @return Whether the locked ptr array is empty.
*/
static UCS_F_ALWAYS_INLINE int
/**
* If foreach locked ptr_array is finalized, releases lock.
*
* @param [in] locked_ptr_array Pointer to a locked ptr array.
* @param [in] element_index The current for loop index.
*
* @return is_continue_loop for the for() loop end condition.
*/
static UCS_F_ALWAYS_INLINE int
/**
* Iterate over all valid elements in the locked array.
*
* Please notice that using break or return are not allowed in
* this implementation.
* Using break or return would require releasing the lock before by calling,
* ucs_ptr_array_locked_release_lock(_locked_ptr_array);
*
* @param [out] _var Pointer to current array element in the foreach.
* @param [out] _index Index variable to use as iterator (unsigned).
* @param [in] _locked_ptr_array Pointer to a locked ptr array.
*/
/* PTR_ARRAY_H_ */