4 * (C) Copyright Linus Torvalds 2003-2005
8 // Pointer list manipulation
9 // -------------------------
19 __DECLARE_ALLOCATOR(struct ptr_list
, ptrlist
);
20 __ALLOCATOR(struct ptr_list
, "ptr list", ptrlist
);
21 __ALLOCATOR(struct ptr_list
, "rl ptr list", rl_ptrlist
);
24 // get the size of a ptrlist
25 // @head: the head of the list
26 // @return: the size of the list given by @head.
27 int ptr_list_size(struct ptr_list
*head
)
32 struct ptr_list
*list
= head
;
34 nr
+= list
->nr
- list
->rm
;
35 } while ((list
= list
->next
) != head
);
41 // test if a list is empty
42 // @head: the head of the list
43 // @return: ``true`` if the list is empty, ``false`` otherwise.
44 bool ptr_list_empty(const struct ptr_list
*head
)
46 const struct ptr_list
*list
= head
;
52 if (list
->nr
- list
->rm
)
54 } while ((list
= list
->next
) != head
);
60 // test is a list contains more than one element
61 // @head: the head of the list
62 // @return: ``true`` if the list has more than 1 element, ``false`` otherwise.
63 bool ptr_list_multiple(const struct ptr_list
*head
)
65 const struct ptr_list
*list
= head
;
72 nr
+= list
->nr
- list
->rm
;
75 } while ((list
= list
->next
) != head
);
81 // get the first element of a ptrlist
82 // @head: the head of the list
83 // @return: the first element of the list or ``NULL`` if the list is empty
84 void *first_ptr_list(struct ptr_list
*head
)
86 struct ptr_list
*list
= head
;
91 while (list
->nr
== 0) {
96 return PTR_ENTRY_NOTAG(list
, 0);
100 // get the last element of a ptrlist
101 // @head: the head of the list
102 // @return: the last element of the list or ``NULL`` if the list is empty
103 void *last_ptr_list(struct ptr_list
*head
)
105 struct ptr_list
*list
;
110 while (list
->nr
== 0) {
115 return PTR_ENTRY_NOTAG(list
, list
->nr
-1);
119 // get the nth element of a ptrlist
120 // @head: the head of the list
121 // @return: the nth element of the list or ``NULL`` if the list is too short.
122 void *ptr_list_nth_entry(struct ptr_list
*list
, unsigned int idx
)
124 struct ptr_list
*head
= list
;
130 unsigned int nr
= list
->nr
;
133 return list
->list
[idx
];
136 } while ((list
= list
->next
) != head
);
141 // linearize the entries of a list
143 // @head: the list to be linearized
144 // @arr: a ``void*`` array to fill with @head's entries
145 // @max: the maximum number of entries to store into @arr
146 // @return: the number of entries linearized.
148 // Linearize the entries of a list up to a total of @max,
149 // and return the nr of entries linearized.
151 // The array to linearize into (@arr) should really
152 // be ``void *x[]``, but we want to let people fill in any kind
153 // of pointer array, so let's just call it ``void **``.
154 int linearize_ptr_list(struct ptr_list
*head
, void **arr
, int max
)
157 if (head
&& max
> 0) {
158 struct ptr_list
*list
= head
;
164 memcpy(arr
, list
->list
, i
*sizeof(void *));
170 } while ((list
= list
->next
) != head
);
178 // @listp: a pointer to the list to be packed.
180 // When we've walked the list and deleted entries,
181 // we may need to re-pack it so that we don't have
182 // any empty blocks left (empty blocks upset the
184 void pack_ptr_list(struct ptr_list
**listp
)
186 struct ptr_list
*head
= *listp
;
189 struct ptr_list
*entry
= head
;
191 struct ptr_list
*next
;
195 struct ptr_list
*prev
;
197 __free_ptrlist(entry
);
204 __free_ptrlist(entry
);
213 } while (entry
!= head
);
218 // split a ptrlist block
219 // @head: the ptrlist block to be splitted
221 // A new block is inserted just after @head and the entries
222 // at the half end of @head are moved to this new block.
223 // The goal being to create space inside @head for a new entry.
224 void split_ptr_list_head(struct ptr_list
*head
)
226 int old
= head
->nr
, nr
= old
/ 2;
227 struct ptr_list
*newlist
= __alloc_ptrlist(0);
228 struct ptr_list
*next
= head
->next
;
232 newlist
->next
= next
;
233 next
->prev
= newlist
;
234 newlist
->prev
= head
;
235 head
->next
= newlist
;
237 memcpy(newlist
->list
, head
->list
+ old
, nr
* sizeof(void *));
238 memset(head
->list
+ old
, 0xf0, nr
* sizeof(void *));
243 // add an entry to a ptrlist
244 // @listp: a pointer to the list
245 // @ptr: the entry to add to the list
246 // @return: the address where the new entry is stored.
248 // :note: code must not use this function and should use
249 // :func:`add_ptr_list` instead.
250 void **__add_ptr_list(struct ptr_list
**listp
, void *ptr
)
252 struct ptr_list
*list
= *listp
;
253 struct ptr_list
*last
= NULL
; /* gcc complains needlessly */
257 if (!list
|| (nr
= (last
= list
->prev
)->nr
) >= LIST_NODE_NR
) {
258 struct ptr_list
*newlist
;
261 newlist
= __alloc_rl_ptrlist(0);
263 newlist
= __alloc_ptrlist(0);
265 newlist
->next
= newlist
;
266 newlist
->prev
= newlist
;
269 newlist
->prev
= last
;
270 newlist
->next
= list
;
271 list
->prev
= newlist
;
272 last
->next
= newlist
;
277 ret
= last
->list
+ nr
;
285 // add a tagged entry to a ptrlist
286 // @listp: a pointer to the list
287 // @ptr: the entry to add to the list
288 // @tag: the tag to add to @ptr
289 // @return: the address where the new entry is stored.
291 // :note: code must not use this function and should use
292 // :func:`add_ptr_list_tag` instead.
293 void **__add_ptr_list_tag(struct ptr_list
**listp
, void *ptr
, unsigned long tag
)
295 /* The low two bits are reserved for tags */
296 assert((3 & (unsigned long)ptr
) == 0);
297 assert((~3 & tag
) == 0);
299 ptr
= (void *)(tag
| (unsigned long)ptr
);
301 return __add_ptr_list(listp
, ptr
);
305 // test if some entry is already present in a ptrlist
306 // @list: the head of the list
307 // @entry: the entry to test
308 // @return: ``true`` if the entry is already present, ``false`` otherwise.
309 bool lookup_ptr_list_entry(const struct ptr_list
*head
, const void *entry
)
311 const struct ptr_list
*list
= head
;
318 for (i
= 0; i
< nr
; i
++)
319 if (list
->list
[i
] == entry
)
321 } while ((list
= list
->next
) != head
);
326 // delete an entry from a ptrlist
327 // @list: a pointer to the list
328 // @entry: the item to be deleted
329 // @count: the minimum number of times @entry should be deleted or 0.
330 int delete_ptr_list_entry(struct ptr_list
**list
, void *entry
, int count
)
334 FOR_EACH_PTR(*list
, ptr
) {
336 DELETE_CURRENT_PTR(ptr
);
340 } END_FOR_EACH_PTR(ptr
);
348 // replace an entry in a ptrlist
349 // @list: a pointer to the list
350 // @old_ptr: the entry to be replaced
351 // @new_ptr: the new entry
352 // @count: the minimum number of times @entry should be deleted or 0.
353 int replace_ptr_list_entry(struct ptr_list
**list
, void *old_ptr
,
354 void *new_ptr
, int count
)
358 FOR_EACH_PTR(*list
, ptr
) {
360 REPLACE_CURRENT_PTR(ptr
, new_ptr
);
364 }END_FOR_EACH_PTR(ptr
);
371 // remove the last entry of a ptrlist
372 // @head: a pointer to the list
373 // @return: the last elemant of the list or NULL if the list is empty.
375 // :note: this doesn't repack the list
376 void * undo_ptr_list_last(struct ptr_list
**head
)
378 struct ptr_list
*last
, *first
= *head
;
388 ptr
= last
->list
[nr
];
389 last
->list
[nr
] = (void *)0xf1f1f1f1;
392 } while (last
!= first
);
397 // remove the last entry and repack the list
398 // @head: a pointer to the list
399 // @return: the last elemant of the list or NULL if the list is empty.
400 void * delete_ptr_list_last(struct ptr_list
**head
)
403 struct ptr_list
*last
, *first
= *head
;
409 ptr
= last
->list
[--last
->nr
];
411 first
->prev
= last
->prev
;
412 last
->prev
->next
= first
;
415 __free_ptrlist(last
);
421 // concat two ptrlists
422 // @a: the source list
423 // @b: a pointer to the destination list.
424 // The element of @a are added at the end of @b.
425 void concat_ptr_list(struct ptr_list
*a
, struct ptr_list
**b
)
428 FOR_EACH_PTR(a
, entry
) {
429 add_ptr_list(b
, entry
);
430 } END_FOR_EACH_PTR(entry
);
434 // copy the elements of a list at the end of another list.
435 // @listp: a pointer to the destination list.
436 // @src: the head of the source list.
437 void copy_ptr_list(struct ptr_list
**listp
, struct ptr_list
*src
)
439 struct ptr_list
*head
, *tail
;
440 struct ptr_list
*cur
= src
;
454 struct ptr_list
*next
;
457 for (i
= 0; i
< nr
;) {
458 void *ptr
= cur
->list
[i
++];
461 if (idx
>= LIST_NODE_NR
) {
462 struct ptr_list
*prev
= tail
;
463 tail
= __alloc_ptrlist(0);
469 tail
->list
[idx
++] = ptr
;
475 } while (cur
!= src
);
484 // @listp: a pointer to the list
485 // Each blocks of the list are freed (but the entries
486 // themselves are not freed).
488 // :note: code must not use this function and should use
489 // the macro :func:`free_ptr_list` instead.
490 void __free_ptr_list(struct ptr_list
**listp
)
492 struct ptr_list
*tmp
, *list
= *listp
;
497 list
->prev
->next
= NULL
;