1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 2 3 #ifndef _LISTMACRO_H_ 4 #define _LISTMACRO_H_ 5 6 #include <assert.h> 7 8 // assumes efficient realloc() 9 10 #define declarePList(List, T) \ 11 typedef T *T##_pointer; \ 12 declareList(List, T##_pointer); 13 14 #define implementPList(List, T) \ 15 typedef T *T##_pointer; \ 16 implementList(List, T##_pointer); 17 18 #define declareList(List, T) \ 19 class List { \ 20 public: \ 21 List(); \ 22 ~List(); \ 23 \ 24 long count() const { return m_count; } \ 25 T &item(long index) const { \ 26 if (!range_check(index, "item")) return m_items[0]; \ 27 return m_items[index]; \ 28 } \ 29 T *array(long index, long) { \ 30 return m_items + index; \ 31 } \ 32 \ 33 void append(const T &); \ 34 void remove(long index); \ 35 void remove_all(); \ 36 void move_to_start(long index); \ 37 void move_to_end(long index); \ 38 \ 39 private: \ 40 bool range_check(long, const char *) const; \ 41 T *m_items; \ 42 long m_count; \ 43 }; 44 45 #define implementList(List, T) \ 46 \ 47 List::List() : m_items(0), m_count(0) { } \ 48 \ 49 List::~List() { remove_all(); } \ 50 \ 51 void *operator new(size_t, void *m, List *) { return m; } \ 52 \ 53 void List::append(const T &item) { \ 54 if (m_items) { \ 55 m_items = (T *)realloc(m_items, (m_count + 1) * sizeof(T)); \ 56 } else { \ 57 m_items = (T *)malloc(sizeof(T)); \ 58 } \ 59 assert(m_items); \ 60 new (&m_items[m_count++], this) T(item); \ 61 } \ 62 \ 63 void List::remove(long index) { \ 64 if (!range_check(index, "remove")) return; \ 65 m_items[index].T::~T(); \ 66 memmove(m_items+index, m_items+index+1, (m_count-index-1) * sizeof(T)); \ 67 if (m_count == 1) { \ 68 free((void *)m_items); m_items = 0; \ 69 } else { \ 70 m_items = (T *)realloc(m_items, (m_count - 1) * sizeof(T)); \ 71 } \ 72 --m_count; \ 73 } \ 74 \ 75 void List::remove_all() { \ 76 while (m_count > 0) remove(0); \ 77 } \ 78 \ 79 void List::move_to_start(long index) { \ 80 if (!range_check(index, "move_to_start")) return; \ 81 T temp(m_items[index]); \ 82 m_items[index].T::~T(); \ 83 if (index > 0) memmove(m_items+1, m_items, index * sizeof(T)); \ 84 new (&m_items[0], this) T(temp); \ 85 } \ 86 \ 87 void List::move_to_end(long index) { \ 88 if (!range_check(index, "move_to_end")) return; \ 89 T temp(m_items[index]); \ 90 m_items[index].T::~T(); \ 91 if (index < m_count-1) memmove(m_items+index, m_items+index+1, \ 92 (m_count-index-1) * sizeof(T)); \ 93 new (&m_items[m_count-1], this) T(temp); \ 94 }\ 95 \ 96 bool List::range_check(long index, const char *fn) const { \ 97 if (index >= 0 && index < m_count) return true; \ 98 fprintf(stderr, "wmx: ERROR: Index %ld out of range for %ld-valued list in %s::%s\n", index, m_count, #List, fn); \ 99 return false; \ 100 } 101 102 #endif 103