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