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