PKUOS - Pintos
Pintos source browser for PKU Operating System course
list.c
Go to the documentation of this file.
1#include "list.h"
2#include "../debug.h"
3
4/** Our doubly linked lists have two header elements: the "head"
5 just before the first element and the "tail" just after the
6 last element. The `prev' link of the front header is null, as
7 is the `next' link of the back header. Their other two links
8 point toward each other via the interior elements of the list.
9
10 An empty list looks like this:
11
12 +------+ +------+
13 <---| head |<--->| tail |--->
14 +------+ +------+
15
16 A list with two elements in it looks like this:
17
18 +------+ +-------+ +-------+ +------+
19 <---| head |<--->| 1 |<--->| 2 |<--->| tail |<--->
20 +------+ +-------+ +-------+ +------+
21
22 The symmetry of this arrangement eliminates lots of special
23 cases in list processing. For example, take a look at
24 list_remove(): it takes only two pointer assignments and no
25 conditionals. That's a lot simpler than the code would be
26 without header elements.
27
28 (Because only one of the pointers in each header element is used,
29 we could in fact combine them into a single header element
30 without sacrificing this simplicity. But using two separate
31 elements allows us to do a little bit of checking on some
32 operations, which can be valuable.) */
33
34static bool is_sorted (struct list_elem *a, struct list_elem *b,
35 list_less_func *less, void *aux) UNUSED;
36
37/** Returns true if ELEM is a head, false otherwise. */
38static inline bool
39is_head (struct list_elem *elem)
40{
41 return elem != NULL && elem->prev == NULL && elem->next != NULL;
42}
43
44/** Returns true if ELEM is an interior element,
45 false otherwise. */
46static inline bool
47is_interior (struct list_elem *elem)
48{
49 return elem != NULL && elem->prev != NULL && elem->next != NULL;
50}
51
52/** Returns true if ELEM is a tail, false otherwise. */
53static inline bool
54is_tail (struct list_elem *elem)
55{
56 return elem != NULL && elem->prev != NULL && elem->next == NULL;
57}
58
59/** Initializes LIST as an empty list. */
60void
62{
63 ASSERT (list != NULL);
64 list->head.prev = NULL;
65 list->head.next = &list->tail;
66 list->tail.prev = &list->head;
67 list->tail.next = NULL;
68}
69
70/** Returns the beginning of LIST. */
71struct list_elem *
73{
74 ASSERT (list != NULL);
75 return list->head.next;
76}
77
78/** Returns the element after ELEM in its list. If ELEM is the
79 last element in its list, returns the list tail. Results are
80 undefined if ELEM is itself a list tail. */
81struct list_elem *
82list_next (struct list_elem *elem)
83{
84 ASSERT (is_head (elem) || is_interior (elem));
85 return elem->next;
86}
87
88/** Returns LIST's tail.
89
90 list_end() is often used in iterating through a list from
91 front to back. See the big comment at the top of list.h for
92 an example. */
93struct list_elem *
95{
96 ASSERT (list != NULL);
97 return &list->tail;
98}
99
100/** Returns the LIST's reverse beginning, for iterating through
101 LIST in reverse order, from back to front. */
102struct list_elem *
104{
105 ASSERT (list != NULL);
106 return list->tail.prev;
107}
108
109/** Returns the element before ELEM in its list. If ELEM is the
110 first element in its list, returns the list head. Results are
111 undefined if ELEM is itself a list head. */
112struct list_elem *
113list_prev (struct list_elem *elem)
114{
115 ASSERT (is_interior (elem) || is_tail (elem));
116 return elem->prev;
117}
118
119/** Returns LIST's head.
120
121 list_rend() is often used in iterating through a list in
122 reverse order, from back to front. Here's typical usage,
123 following the example from the top of list.h:
124
125 for (e = list_rbegin (&foo_list); e != list_rend (&foo_list);
126 e = list_prev (e))
127 {
128 struct foo *f = list_entry (e, struct foo, elem);
129 ...do something with f...
130 }
131*/
132struct list_elem *
134{
135 ASSERT (list != NULL);
136 return &list->head;
137}
138
139/** Return's LIST's head.
140
141 list_head() can be used for an alternate style of iterating
142 through a list, e.g.:
143
144 e = list_head (&list);
145 while ((e = list_next (e)) != list_end (&list))
146 {
147 ...
148 }
149*/
150struct list_elem *
152{
153 ASSERT (list != NULL);
154 return &list->head;
155}
156
157/** Return's LIST's tail. */
158struct list_elem *
160{
161 ASSERT (list != NULL);
162 return &list->tail;
163}
164
165/** Inserts ELEM just before BEFORE, which may be either an
166 interior element or a tail. The latter case is equivalent to
167 list_push_back(). */
168void
169list_insert (struct list_elem *before, struct list_elem *elem)
170{
171 ASSERT (is_interior (before) || is_tail (before));
172 ASSERT (elem != NULL);
173
174 elem->prev = before->prev;
175 elem->next = before;
176 before->prev->next = elem;
177 before->prev = elem;
178}
179
180/** Removes elements FIRST though LAST (exclusive) from their
181 current list, then inserts them just before BEFORE, which may
182 be either an interior element or a tail. */
183void
184list_splice (struct list_elem *before,
185 struct list_elem *first, struct list_elem *last)
186{
187 ASSERT (is_interior (before) || is_tail (before));
188 if (first == last)
189 return;
190 last = list_prev (last);
191
192 ASSERT (is_interior (first));
193 ASSERT (is_interior (last));
194
195 /* Cleanly remove FIRST...LAST from its current list. */
196 first->prev->next = last->next;
197 last->next->prev = first->prev;
198
199 /* Splice FIRST...LAST into new list. */
200 first->prev = before->prev;
201 last->next = before;
202 before->prev->next = first;
203 before->prev = last;
204}
205
206/** Inserts ELEM at the beginning of LIST, so that it becomes the
207 front in LIST. */
208void
209list_push_front (struct list *list, struct list_elem *elem)
210{
211 list_insert (list_begin (list), elem);
212}
213
214/** Inserts ELEM at the end of LIST, so that it becomes the
215 back in LIST. */
216void
217list_push_back (struct list *list, struct list_elem *elem)
218{
219 list_insert (list_end (list), elem);
220}
221
222/** Removes ELEM from its list and returns the element that
223 followed it. Undefined behavior if ELEM is not in a list.
224
225 A list element must be treated very carefully after removing
226 it from its list. Calling list_next() or list_prev() on ELEM
227 will return the item that was previously before or after ELEM,
228 but, e.g., list_prev(list_next(ELEM)) is no longer ELEM!
229
230 The list_remove() return value provides a convenient way to
231 iterate and remove elements from a list:
232
233 for (e = list_begin (&list); e != list_end (&list); e = list_remove (e))
234 {
235 ...do something with e...
236 }
237
238 If you need to free() elements of the list then you need to be
239 more conservative. Here's an alternate strategy that works
240 even in that case:
241
242 while (!list_empty (&list))
243 {
244 struct list_elem *e = list_pop_front (&list);
245 ...do something with e...
246 }
247*/
248struct list_elem *
249list_remove (struct list_elem *elem)
250{
251 ASSERT (is_interior (elem));
252 elem->prev->next = elem->next;
253 elem->next->prev = elem->prev;
254 return elem->next;
255}
256
257/** Removes the front element from LIST and returns it.
258 Undefined behavior if LIST is empty before removal. */
259struct list_elem *
261{
262 struct list_elem *front = list_front (list);
263 list_remove (front);
264 return front;
265}
266
267/** Removes the back element from LIST and returns it.
268 Undefined behavior if LIST is empty before removal. */
269struct list_elem *
271{
272 struct list_elem *back = list_back (list);
273 list_remove (back);
274 return back;
275}
276
277/** Returns the front element in LIST.
278 Undefined behavior if LIST is empty. */
279struct list_elem *
281{
283 return list->head.next;
284}
285
286/** Returns the back element in LIST.
287 Undefined behavior if LIST is empty. */
288struct list_elem *
290{
292 return list->tail.prev;
293}
294
295/** Returns the number of elements in LIST.
296 Runs in O(n) in the number of elements. */
297size_t
299{
300 struct list_elem *e;
301 size_t cnt = 0;
302
303 for (e = list_begin (list); e != list_end (list); e = list_next (e))
304 cnt++;
305 return cnt;
306}
307
308/** Returns true if LIST is empty, false otherwise. */
309bool
311{
312 return list_begin (list) == list_end (list);
313}
314
315/** Swaps the `struct list_elem *'s that A and B point to. */
316static void
317swap (struct list_elem **a, struct list_elem **b)
318{
319 struct list_elem *t = *a;
320 *a = *b;
321 *b = t;
322}
323
324/** Reverses the order of LIST. */
325void
327{
328 if (!list_empty (list))
329 {
330 struct list_elem *e;
331
332 for (e = list_begin (list); e != list_end (list); e = e->prev)
333 swap (&e->prev, &e->next);
334 swap (&list->head.next, &list->tail.prev);
336 }
337}
338
339/** Returns true only if the list elements A through B (exclusive)
340 are in order according to LESS given auxiliary data AUX. */
341static bool
342is_sorted (struct list_elem *a, struct list_elem *b,
343 list_less_func *less, void *aux)
344{
345 if (a != b)
346 while ((a = list_next (a)) != b)
347 if (less (a, list_prev (a), aux))
348 return false;
349 return true;
350}
351
352/** Finds a run, starting at A and ending not after B, of list
353 elements that are in nondecreasing order according to LESS
354 given auxiliary data AUX. Returns the (exclusive) end of the
355 run.
356 A through B (exclusive) must form a non-empty range. */
357static struct list_elem *
358find_end_of_run (struct list_elem *a, struct list_elem *b,
359 list_less_func *less, void *aux)
360{
361 ASSERT (a != NULL);
362 ASSERT (b != NULL);
363 ASSERT (less != NULL);
364 ASSERT (a != b);
365
366 do
367 {
368 a = list_next (a);
369 }
370 while (a != b && !less (a, list_prev (a), aux));
371 return a;
372}
373
374/** Merges A0 through A1B0 (exclusive) with A1B0 through B1
375 (exclusive) to form a combined range also ending at B1
376 (exclusive). Both input ranges must be nonempty and sorted in
377 nondecreasing order according to LESS given auxiliary data
378 AUX. The output range will be sorted the same way. */
379static void
380inplace_merge (struct list_elem *a0, struct list_elem *a1b0,
381 struct list_elem *b1,
382 list_less_func *less, void *aux)
383{
384 ASSERT (a0 != NULL);
385 ASSERT (a1b0 != NULL);
386 ASSERT (b1 != NULL);
387 ASSERT (less != NULL);
388 ASSERT (is_sorted (a0, a1b0, less, aux));
389 ASSERT (is_sorted (a1b0, b1, less, aux));
390
391 while (a0 != a1b0 && a1b0 != b1)
392 if (!less (a1b0, a0, aux))
393 a0 = list_next (a0);
394 else
395 {
396 a1b0 = list_next (a1b0);
397 list_splice (a0, list_prev (a1b0), a1b0);
398 }
399}
400
401/** Sorts LIST according to LESS given auxiliary data AUX, using a
402 natural iterative merge sort that runs in O(n lg n) time and
403 O(1) space in the number of elements in LIST. */
404void
405list_sort (struct list *list, list_less_func *less, void *aux)
406{
407 size_t output_run_cnt; /**< Number of runs output in current pass. */
408
409 ASSERT (list != NULL);
410 ASSERT (less != NULL);
411
412 /* Pass over the list repeatedly, merging adjacent runs of
413 nondecreasing elements, until only one run is left. */
414 do
415 {
416 struct list_elem *a0; /**< Start of first run. */
417 struct list_elem *a1b0; /**< End of first run, start of second. */
418 struct list_elem *b1; /**< End of second run. */
419
420 output_run_cnt = 0;
421 for (a0 = list_begin (list); a0 != list_end (list); a0 = b1)
422 {
423 /* Each iteration produces one output run. */
424 output_run_cnt++;
425
426 /* Locate two adjacent runs of nondecreasing elements
427 A0...A1B0 and A1B0...B1. */
428 a1b0 = find_end_of_run (a0, list_end (list), less, aux);
429 if (a1b0 == list_end (list))
430 break;
431 b1 = find_end_of_run (a1b0, list_end (list), less, aux);
432
433 /* Merge the runs. */
434 inplace_merge (a0, a1b0, b1, less, aux);
435 }
436 }
437 while (output_run_cnt > 1);
438
439 ASSERT (is_sorted (list_begin (list), list_end (list), less, aux));
440}
441
442/** Inserts ELEM in the proper position in LIST, which must be
443 sorted according to LESS given auxiliary data AUX.
444 Runs in O(n) average case in the number of elements in LIST. */
445void
446list_insert_ordered (struct list *list, struct list_elem *elem,
447 list_less_func *less, void *aux)
448{
449 struct list_elem *e;
450
451 ASSERT (list != NULL);
452 ASSERT (elem != NULL);
453 ASSERT (less != NULL);
454
455 for (e = list_begin (list); e != list_end (list); e = list_next (e))
456 if (less (elem, e, aux))
457 break;
458 return list_insert (e, elem);
459}
460
461/** Iterates through LIST and removes all but the first in each
462 set of adjacent elements that are equal according to LESS
463 given auxiliary data AUX. If DUPLICATES is non-null, then the
464 elements from LIST are appended to DUPLICATES. */
465void
466list_unique (struct list *list, struct list *duplicates,
467 list_less_func *less, void *aux)
468{
469 struct list_elem *elem, *next;
470
471 ASSERT (list != NULL);
472 ASSERT (less != NULL);
473 if (list_empty (list))
474 return;
475
476 elem = list_begin (list);
477 while ((next = list_next (elem)) != list_end (list))
478 if (!less (elem, next, aux) && !less (next, elem, aux))
479 {
481 if (duplicates != NULL)
482 list_push_back (duplicates, next);
483 }
484 else
485 elem = next;
486}
487
488/** Returns the element in LIST with the largest value according
489 to LESS given auxiliary data AUX. If there is more than one
490 maximum, returns the one that appears earlier in the list. If
491 the list is empty, returns its tail. */
492struct list_elem *
493list_max (struct list *list, list_less_func *less, void *aux)
494{
495 struct list_elem *max = list_begin (list);
496 if (max != list_end (list))
497 {
498 struct list_elem *e;
499
500 for (e = list_next (max); e != list_end (list); e = list_next (e))
501 if (less (max, e, aux))
502 max = e;
503 }
504 return max;
505}
506
507/** Returns the element in LIST with the smallest value according
508 to LESS given auxiliary data AUX. If there is more than one
509 minimum, returns the one that appears earlier in the list. If
510 the list is empty, returns its tail. */
511struct list_elem *
512list_min (struct list *list, list_less_func *less, void *aux)
513{
514 struct list_elem *min = list_begin (list);
515 if (min != list_end (list))
516 {
517 struct list_elem *e;
518
519 for (e = list_next (min); e != list_end (list); e = list_next (e))
520 if (less (e, min, aux))
521 min = e;
522 }
523 return min;
524}
#define ASSERT(CONDITION)
This is outside the header guard so that debug.h may be included multiple times with different settin...
Definition: debug.h:31
#define UNUSED
GCC lets us add "attributes" to functions, function parameters, etc.
Definition: debug.h:7
static int next(int pos)
Returns the position after POS within an intq.
Definition: intq.c:79
struct list_elem * list_begin(struct list *list)
Returns the beginning of LIST.
Definition: list.c:72
struct list_elem * list_min(struct list *list, list_less_func *less, void *aux)
Returns the element in LIST with the smallest value according to LESS given auxiliary data AUX.
Definition: list.c:512
struct list_elem * list_remove(struct list_elem *elem)
Removes ELEM from its list and returns the element that followed it.
Definition: list.c:249
struct list_elem * list_pop_front(struct list *list)
Removes the front element from LIST and returns it.
Definition: list.c:260
void list_push_front(struct list *list, struct list_elem *elem)
Inserts ELEM at the beginning of LIST, so that it becomes the front in LIST.
Definition: list.c:209
static void inplace_merge(struct list_elem *a0, struct list_elem *a1b0, struct list_elem *b1, list_less_func *less, void *aux)
Merges A0 through A1B0 (exclusive) with A1B0 through B1 (exclusive) to form a combined range also end...
Definition: list.c:380
struct list_elem * list_rbegin(struct list *list)
Returns the LIST's reverse beginning, for iterating through LIST in reverse order,...
Definition: list.c:103
void list_unique(struct list *list, struct list *duplicates, list_less_func *less, void *aux)
Iterates through LIST and removes all but the first in each set of adjacent elements that are equal a...
Definition: list.c:466
struct list_elem * list_front(struct list *list)
Returns the front element in LIST.
Definition: list.c:280
struct list_elem * list_prev(struct list_elem *elem)
Returns the element before ELEM in its list.
Definition: list.c:113
static bool is_sorted(struct list_elem *a, struct list_elem *b, list_less_func *less, void *aux) UNUSED
Our doubly linked lists have two header elements: the "head" just before the first element and the "t...
Definition: list.c:342
struct list_elem * list_end(struct list *list)
Returns LIST's tail.
Definition: list.c:94
bool list_empty(struct list *list)
Returns true if LIST is empty, false otherwise.
Definition: list.c:310
void list_insert(struct list_elem *before, struct list_elem *elem)
Inserts ELEM just before BEFORE, which may be either an interior element or a tail.
Definition: list.c:169
void list_splice(struct list_elem *before, struct list_elem *first, struct list_elem *last)
Removes elements FIRST though LAST (exclusive) from their current list, then inserts them just before...
Definition: list.c:184
struct list_elem * list_max(struct list *list, list_less_func *less, void *aux)
Returns the element in LIST with the largest value according to LESS given auxiliary data AUX.
Definition: list.c:493
struct list_elem * list_head(struct list *list)
Return's LIST's head.
Definition: list.c:151
void list_init(struct list *list)
Initializes LIST as an empty list.
Definition: list.c:61
struct list_elem * list_rend(struct list *list)
Returns LIST's head.
Definition: list.c:133
void list_push_back(struct list *list, struct list_elem *elem)
Inserts ELEM at the end of LIST, so that it becomes the back in LIST.
Definition: list.c:217
struct list_elem * list_tail(struct list *list)
Return's LIST's tail.
Definition: list.c:159
size_t list_size(struct list *list)
Returns the number of elements in LIST.
Definition: list.c:298
struct list_elem * list_next(struct list_elem *elem)
Returns the element after ELEM in its list.
Definition: list.c:82
void list_reverse(struct list *list)
Reverses the order of LIST.
Definition: list.c:326
struct list_elem * list_back(struct list *list)
Returns the back element in LIST.
Definition: list.c:289
void list_sort(struct list *list, list_less_func *less, void *aux)
Sorts LIST according to LESS given auxiliary data AUX, using a natural iterative merge sort that runs...
Definition: list.c:405
static void swap(struct list_elem **a, struct list_elem **b)
Swaps the `struct list_elem *'s that A and B point to.
Definition: list.c:317
static bool is_interior(struct list_elem *elem)
Returns true if ELEM is an interior element, false otherwise.
Definition: list.c:47
void list_insert_ordered(struct list *list, struct list_elem *elem, list_less_func *less, void *aux)
Inserts ELEM in the proper position in LIST, which must be sorted according to LESS given auxiliary d...
Definition: list.c:446
struct list_elem * list_pop_back(struct list *list)
Removes the back element from LIST and returns it.
Definition: list.c:270
static bool is_head(struct list_elem *elem)
Returns true if ELEM is a head, false otherwise.
Definition: list.c:39
static struct list_elem * find_end_of_run(struct list_elem *a, struct list_elem *b, list_less_func *less, void *aux)
Finds a run, starting at A and ending not after B, of list elements that are in nondecreasing order a...
Definition: list.c:358
static bool is_tail(struct list_elem *elem)
Returns true if ELEM is a tail, false otherwise.
Definition: list.c:54
bool list_less_func(const struct list_elem *a, const struct list_elem *b, void *aux)
Compares the value of two list elements A and B, given auxiliary data AUX.
Definition: list.h:165
#define NULL
Definition: stddef.h:4
Doubly linked list.
Definition: list.h:91
struct list_elem * next
Next list element.
Definition: list.h:93
struct list_elem * prev
Previous list element.
Definition: list.h:92
List.
Definition: list.h:98
struct list_elem tail
List tail.
Definition: list.h:100
struct list_elem head
List head.
Definition: list.h:99