Merge zizzer:/bk/m5
[gem5.git] / base / res_list.hh
1 /*
2 * Copyright (c) 2001-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #ifndef __RES_LIST_HH__
30 #define __RES_LIST_HH__
31
32 #include "base/cprintf.hh"
33 #include <assert.h>
34
35 #define DEBUG_REMOVE 0
36
37 #define DEBUG_MEMORY 0
38 //#define DEBUG_MEMORY DEBUG
39
40 class res_list_base
41 {
42 #if DEBUG_MEMORY
43 protected:
44 static long long allocated_elements;
45 static long long allocated_lists;
46
47 public:
48 long long get_elements(void) {
49 return allocated_elements;
50 }
51 long long get_lists(void) {
52 return allocated_lists;
53 }
54
55 #endif
56 };
57
58 #if DEBUG_MEMORY
59 extern void what_the(void);
60 #endif
61
62 template<class T>
63 class res_list : public res_list_base
64 {
65 public:
66 class iterator;
67
68 class res_element
69 {
70 res_element *next;
71 res_element *prev;
72 T *data;
73 bool allocate_data;
74
75 public:
76 // always adds to the END of the list
77 res_element(res_element *_prev, bool allocate);
78 ~res_element();
79 void dump(void);
80
81 friend class res_list<T>;
82 friend class res_list<T>::iterator;
83 };
84
85 class iterator
86 {
87 private:
88 res_element *p;
89
90 friend class res_list<T>;
91
92 public:
93 // Constructors
94 iterator(res_element *q) : p(q) {}
95 iterator(void) { p=0; };
96
97 void dump(void);
98 T* data_ptr(void);
99 res_element *res_el_ptr(void) { return p;}
100 void point_to(T &d) { p->data = &d; }
101
102 iterator next(void) { return iterator(p->next); }
103 iterator prev(void) { return iterator(p->prev); }
104 bool operator== (iterator x) { return (x.p == this->p); }
105 bool operator != (iterator x) { return (x.p != this->p); }
106 T &operator * (void) { return *(p->data); }
107 T* operator -> (void) { return p->data; }
108 bool isnull(void) { return (p==0); }
109 bool notnull(void) { return (p!=0); }
110 };
111
112 private:
113 iterator unused_elements;
114 iterator head_ptr;
115 iterator tail_ptr;
116
117 unsigned base_elements;
118 unsigned extra_elements;
119 unsigned active_elements;
120 bool allocate_storage;
121 unsigned build_size;
122
123 int remove_count;
124
125 //
126 // Allocate new elements, and assign them to the unused_elements
127 // list.
128 //
129 unsigned allocate_elements(unsigned num, bool allocate_storage);
130
131 public:
132 //
133 // List Constructor
134 //
135 res_list(unsigned size, bool alloc_storage = false,
136 unsigned build_sz = 5);
137
138 //
139 // List Destructor
140 //
141 ~res_list();
142
143 iterator head(void) {return head_ptr;};
144 iterator tail(void) {return tail_ptr;};
145
146 unsigned num_free(void) { return size() - count(); }
147 unsigned size(void) { return base_elements + extra_elements; }
148 unsigned count(void) { return active_elements; }
149 bool empty(void) { return count() == 0; }
150 bool full(void);
151
152 //
153 // Insert with data copy
154 //
155 iterator insert_after(iterator prev, T *d);
156 iterator insert_after(iterator prev, T &d);
157 iterator insert_before(iterator prev, T *d);
158 iterator insert_before(iterator prev, T &d);
159
160 //
161 // Insert new list element (no data copy)
162 //
163 iterator insert_after(iterator prev);
164 iterator insert_before(iterator prev);
165
166 iterator add_tail(T *d) { return insert_after(tail_ptr, d); }
167 iterator add_tail(T &d) { return insert_after(tail_ptr, d); }
168 iterator add_tail(void) { return insert_after(tail_ptr); }
169 iterator add_head(T *d) { return insert_before(head_ptr, d); }
170 iterator add_head(T &d) { return insert_before(head_ptr, d); }
171 iterator add_head(void) { return insert_before(head_ptr); }
172
173 iterator remove(iterator q);
174 iterator remove_head(void) {return remove(head_ptr);}
175 iterator remove_tail(void) {return remove(tail_ptr);}
176
177 bool in_list(iterator j);
178 void free_extras(void);
179 void clear(void);
180 void dump(void);
181 void raw_dump(void);
182 };
183
184 template <class T>
185 inline
186 res_list<T>::res_element::res_element(res_element *_prev, bool allocate)
187 {
188 allocate_data = allocate;
189 prev = _prev;
190 next = 0;
191
192 if (prev)
193 prev->next = this;
194
195 if (allocate)
196 data = new T;
197 else
198 data = 0;
199
200 #if DEBUG_MEMORY
201 ++allocated_elements;
202 #endif
203 }
204
205 template <class T>
206 inline
207 res_list<T>::res_element::~res_element(void)
208 {
209 if (prev)
210 prev->next = next;
211
212 if (next)
213 next->prev = prev;
214
215 if (allocate_data)
216 delete data;
217
218 #if DEBUG_MEMORY
219 --allocated_elements;
220 #endif
221 }
222
223 template <class T>
224 inline void
225 res_list<T>::res_element::dump(void)
226 {
227 cprintf(" prev = %#x\n", prev);
228 cprintf(" next = %#x\n", next);
229 cprintf(" data = %#x\n", data);
230 }
231
232 template <class T>
233 inline void
234 res_list<T>::iterator::dump(void)
235 {
236 if (p && p->data)
237 p->data->dump();
238 else {
239 if (!p)
240 cprintf(" Null Pointer\n");
241 else
242 cprintf(" Null 'data' Pointer\n");
243 }
244 }
245
246 template <class T>
247 inline T *
248 res_list<T>::iterator::data_ptr(void)
249 {
250 if (p)
251 return p->data;
252 else
253 return 0;
254 }
255
256
257 //
258 // Allocate new elements, and assign them to the unused_elements
259 // list.
260 //
261 template <class T>
262 inline unsigned
263 res_list<T>::allocate_elements(unsigned num, bool allocate_storage)
264 {
265 res_element *pnew, *plast = 0, *pfirst=0;
266
267 for (int i=0; i<num; ++i) {
268 pnew = new res_element(plast, allocate_storage);
269 if (i==0)
270 pfirst = pnew;
271 plast = pnew;
272 }
273
274 if (unused_elements.notnull()) {
275 // Add these new elements to the front of the list
276 plast->next = unused_elements.res_el_ptr();
277 unused_elements.res_el_ptr()->prev = plast;
278 }
279
280 unused_elements = iterator(pfirst);
281
282 return num;
283 }
284
285 template <class T>
286 inline
287 res_list<T>::res_list(unsigned size, bool alloc_storage, unsigned build_sz)
288 {
289 #if DEBUG_MEMORY
290 ++allocated_lists;
291 #endif
292 extra_elements = 0;
293 active_elements = 0;
294 build_size = build_sz;
295 allocate_storage = alloc_storage;
296 remove_count = 0;
297
298 // Create the new elements
299 base_elements = allocate_elements(size, alloc_storage);
300
301 // The list of active elements
302 head_ptr = iterator(0);
303 tail_ptr = iterator(0);
304 }
305
306 //
307 // List Destructor
308 //
309 template <class T>
310 inline
311 res_list<T>::~res_list(void)
312 {
313 iterator n;
314
315 #if DEBUG_MEMORY
316 --allocated_lists;
317 #endif
318
319 // put everything into the unused list
320 clear();
321
322 // rudely delete all the res_elements
323 for (iterator p = unused_elements;
324 p.notnull();
325 p = n) {
326
327 n = p.next();
328
329 // delete the res_element
330 // (it will take care of deleting the data)
331 delete p.res_el_ptr();
332 }
333 }
334
335 template <class T>
336 inline bool
337 res_list<T>::full(void)
338 {
339 if (build_size)
340 return false;
341 else
342 return unused_elements.isnull();
343 }
344
345 //
346 // Insert with data copy
347 //
348 template <class T>
349 inline typename res_list<T>::iterator
350 res_list<T>::insert_after(iterator prev, T *d)
351 {
352 iterator p;
353
354 if (!allocate_storage)
355 this->panic("Can't copy data... not allocating storage");
356
357 p = insert_after(prev);
358 if (p.notnull())
359 *p = *d;
360
361 return p;
362 }
363
364
365 template <class T>
366 inline typename res_list<T>::iterator
367 res_list<T>::insert_after(iterator prev, T &d)
368 {
369 iterator p;
370
371 p = insert_after(prev);
372 if (p.notnull()) {
373
374 if (allocate_storage) {
375 // if we allocate storage, then copy the contents of the
376 // specified object to our object
377 *p = d;
378 }
379 else {
380 // if we don't allocate storage, then we just want to
381 // point to the specified object
382 p.point_to(d);
383 }
384 }
385
386 return p;
387 }
388
389
390 template <class T>
391 inline typename res_list<T>::iterator
392 res_list<T>::insert_after(iterator prev)
393 {
394
395 #if DEBUG_MEMORY
396 if (active_elements > 2*base_elements) {
397 what_the();
398 }
399 #endif
400
401 // If we have no unused elements, make some more
402 if (unused_elements.isnull()) {
403
404 if (build_size == 0) {
405 return 0; // No space left, and can't allocate more....
406 }
407
408 extra_elements += allocate_elements(build_size, allocate_storage);
409 }
410
411 // grab the first unused element
412 res_element *p = unused_elements.res_el_ptr();
413
414 unused_elements = unused_elements.next();
415
416 ++active_elements;
417
418 // Insert the new element
419 if (head_ptr.isnull()) {
420 //
421 // Special case #1: Empty List
422 //
423 head_ptr = p;
424 tail_ptr = p;
425 p->prev = 0;
426 p->next = 0;
427 }
428 else if (prev.isnull()) {
429 //
430 // Special case #2: Insert at head
431 //
432
433 // our next ptr points to old head element
434 p->next = head_ptr.res_el_ptr();
435
436 // our element becomes the new head element
437 head_ptr = p;
438
439 // no previous element for the head
440 p->prev = 0;
441
442 // old head element points back to this element
443 p->next->prev = p;
444 }
445 else if (prev.next().isnull()) {
446 //
447 // Special case #3 Insert at tail
448 //
449
450 // our prev pointer points to old tail element
451 p->prev = tail_ptr.res_el_ptr();
452
453 // our element becomes the new tail
454 tail_ptr = p;
455
456 // no next element for the tail
457 p->next = 0;
458
459 // old tail element point to this element
460 p->prev->next = p;
461 }
462 else {
463 //
464 // Normal insertion (after prev)
465 //
466 p->prev = prev.res_el_ptr();
467 p->next = prev.next().res_el_ptr();
468
469 prev.res_el_ptr()->next = p;
470 p->next->prev = p;
471 }
472
473 return iterator(p);
474 }
475
476 template <class T>
477 inline typename res_list<T>::iterator
478 res_list<T>::insert_before(iterator next, T &d)
479 {
480 iterator p;
481
482 p = insert_before(next);
483 if (p.notnull()) {
484
485 if (allocate_storage) {
486 // if we allocate storage, then copy the contents of the
487 // specified object to our object
488 *p = d;
489 }
490 else {
491 // if we don't allocate storage, then we just want to
492 // point to the specified object
493 p.point_to(d);
494 }
495 }
496
497 return p;
498 }
499
500
501 template <class T>
502 inline typename res_list<T>::iterator
503 res_list<T>::insert_before(iterator next)
504 {
505
506 #if DEBUG_MEMORY
507 if (active_elements > 2*base_elements) {
508 what_the();
509 }
510 #endif
511
512 // If we have no unused elements, make some more
513 if (unused_elements.isnull()) {
514
515 if (build_size == 0) {
516 return 0; // No space left, and can't allocate more....
517 }
518
519 extra_elements += allocate_elements(build_size, allocate_storage);
520 }
521
522 // grab the first unused element
523 res_element *p = unused_elements.res_el_ptr();
524
525 unused_elements = unused_elements.next();
526
527 ++active_elements;
528
529 // Insert the new element
530 if (head_ptr.isnull()) {
531 //
532 // Special case #1: Empty List
533 //
534 head_ptr = p;
535 tail_ptr = p;
536 p->prev = 0;
537 p->next = 0;
538 }
539 else if (next.isnull()) {
540 //
541 // Special case #2 Insert at tail
542 //
543
544 // our prev pointer points to old tail element
545 p->prev = tail_ptr.res_el_ptr();
546
547 // our element becomes the new tail
548 tail_ptr = p;
549
550 // no next element for the tail
551 p->next = 0;
552
553 // old tail element point to this element
554 p->prev->next = p;
555 }
556 else if (next.prev().isnull()) {
557 //
558 // Special case #3: Insert at head
559 //
560
561 // our next ptr points to old head element
562 p->next = head_ptr.res_el_ptr();
563
564 // our element becomes the new head element
565 head_ptr = p;
566
567 // no previous element for the head
568 p->prev = 0;
569
570 // old head element points back to this element
571 p->next->prev = p;
572 }
573 else {
574 //
575 // Normal insertion (before next)
576 //
577 p->next = next.res_el_ptr();
578 p->prev = next.prev().res_el_ptr();
579
580 next.res_el_ptr()->prev = p;
581 p->prev->next = p;
582 }
583
584 return iterator(p);
585 }
586
587
588 template <class T>
589 inline typename res_list<T>::iterator
590 res_list<T>::remove(iterator q)
591 {
592 res_element *p = q.res_el_ptr();
593 iterator n = 0;
594
595 // Handle the special cases
596 if (active_elements == 1) { // This is the only element
597 head_ptr = 0;
598 tail_ptr = 0;
599 }
600 else if (q == head_ptr) { // This is the head element
601 head_ptr = q.next();
602 head_ptr.res_el_ptr()->prev = 0;
603
604 n = head_ptr;
605 }
606 else if (q == tail_ptr) { // This is the tail element
607 tail_ptr = q.prev();
608 tail_ptr.res_el_ptr()->next = 0;
609 }
610 else { // This is between two elements
611 p->prev->next = p->next;
612 p->next->prev = p->prev;
613
614 // Get the "next" element for return
615 n = p->next;
616 }
617
618 --active_elements;
619
620 // Put this element back onto the unused list
621 p->next = unused_elements.res_el_ptr();
622 p->prev = 0;
623 if (p->next) { // NULL if unused list is empty
624 p->next->prev = p;
625 }
626
627 if (!allocate_storage) {
628 p->data = 0;
629 }
630
631 unused_elements = q;
632
633 // A little "garbage collection"
634 if (++remove_count > 10) {
635 // free_extras();
636 remove_count = 0;
637 }
638
639 #if DEBUG_REMOVE
640 unsigned unused_count = 0;
641 for (iterator i=unused_elements;
642 i.notnull();
643 i = i.next()) {
644
645 ++unused_count;
646 }
647
648 assert((active_elements+unused_count) == (base_elements+extra_elements));
649 #endif
650
651 return iterator(n);
652 }
653
654
655 template <class T>
656 inline bool
657 res_list<T>::in_list(iterator j)
658 {
659 iterator i;
660
661 for (i=head(); i.notnull(); i=i.next()) {
662 if (j.res_el_ptr() == i.res_el_ptr()) {
663 return true;
664 }
665 }
666
667 return false;
668 }
669
670 template <class T>
671 inline void
672 res_list<T>::free_extras(void)
673 {
674 unsigned num_unused = base_elements + extra_elements - active_elements;
675 unsigned to_free = extra_elements;
676 res_element *p;
677
678
679 if (extra_elements != 0) {
680 //
681 // Free min(extra_elements, # unused elements)
682 //
683 if (extra_elements > num_unused) {
684 to_free = num_unused;
685 }
686
687 p = unused_elements.res_el_ptr();
688 for (int i=0; i<to_free; ++i) {
689 res_element *q = p->next;
690
691 delete p;
692
693 p = q;
694 }
695
696 // update the unused element pointer to point to the first
697 // element that wasn't deleted.
698 unused_elements = iterator(p);
699
700 // Update the number of extra elements
701 extra_elements -= to_free;
702 }
703
704 return;
705 }
706
707
708 template <class T>
709 inline void
710 res_list<T>::clear(void)
711 {
712 iterator i,n;
713
714 for (i=head_ptr; i.notnull(); i=n) {
715 n = i.next();
716 remove(i);
717 }
718
719 free_extras();
720 }
721
722 template <class T>
723 inline void
724 res_list<T>::dump(void)
725 {
726 for (iterator i=head(); !i.isnull(); i=i.next())
727 i->dump();
728 }
729
730 template <class T>
731 inline void
732 res_list<T>::raw_dump(void)
733 {
734 int j = 0;
735 res_element *p;
736 for (iterator i=head(); !i.isnull(); i=i.next()) {
737 cprintf("Element %d:\n", j);
738
739 if (i.notnull()) {
740 p = i.res_el_ptr();
741 cprintf(" points to res_element @ %#x\n", p);
742 p->dump();
743 cprintf(" Data Element:\n");
744 i->dump();
745 }
746 else {
747 cprintf(" NULL iterator!\n");
748 }
749
750 ++j;
751 }
752
753 }
754
755 #endif // __RES_LIST_HH__