add HeapRing: a new RingBuffer constructed from the trials and tribulations of the...
[clinton/Smoothieware.git] / src / libs / HeapRing.cpp
1 #include "HeapRing.h"
2
3 #include <cstdlib>
4
5 #include "cmsis.h"
6
7 /*
8 * constructors
9 */
10
11 template<class kind> HeapRing<kind>::HeapRing()
12 {
13 head_i = tail_i = length = 0;
14 ring = NULL;
15 }
16
17 template<class kind> HeapRing<kind>::HeapRing(unsigned int length)
18 {
19 head_i = tail_i = 0;
20 ring = new kind[length];
21 // TODO: handle allocation failure
22 this->length = length;
23 }
24
25 /*
26 * destructor
27 */
28
29 template<class kind> HeapRing<kind>::~HeapRing()
30 {
31 head_i = tail_i = length = 0;
32 if (ring)
33 delete [] ring;
34 ring = NULL;
35 }
36
37 /*
38 * index accessors (protected)
39 */
40
41 template<class kind> unsigned int HeapRing<kind>::next(unsigned int item)
42 {
43 if (length == 0)
44 return 0;
45
46 if (++item >= length)
47 return 0;
48
49 return item;
50 }
51
52 template<class kind> unsigned int HeapRing<kind>::prev(unsigned int item)
53 {
54 if (length == 0)
55 return 0;
56
57 if (item == 0)
58 return (length - 1);
59 else
60 return (item - 1);
61 }
62
63 /*
64 * reference accessors
65 */
66
67 template<class kind> kind& HeapRing<kind>::head()
68 {
69 return ring[head_i];
70 }
71
72 template<class kind> kind& HeapRing<kind>::tail()
73 {
74 return ring[tail_i];
75 }
76
77 template<class kind> kind& HeapRing<kind>::item(unsigned int i)
78 {
79 return ring[i];
80 }
81
82 template<class kind> void HeapRing<kind>::push_front(kind& item)
83 {
84 ring[head_i] = item;
85 head_i = next(head_i);
86 }
87
88 template<class kind> kind& HeapRing<kind>::pop_back()
89 {
90 kind& r = ring[tail_i];
91 tail_i = next(tail_i);
92 return r;
93 }
94
95 /*
96 * pointer accessors
97 */
98
99 template<class kind> kind* HeapRing<kind>::head_ref()
100 {
101 return &ring[head_i];
102 }
103
104 template<class kind> kind* HeapRing<kind>::tail_ref()
105 {
106 return &ring[tail_i];
107 }
108
109 template<class kind> kind* HeapRing<kind>::item_ref(unsigned int i)
110 {
111 return &ring[i];
112 }
113
114 template<class kind> void HeapRing<kind>::produce_head()
115 {
116 head_i = next(head_i);
117 }
118
119 template<class kind> void HeapRing<kind>::consume_tail()
120 {
121 tail_i = next(tail_i);
122 }
123
124 /*
125 * queue status accessors
126 */
127
128 template<class kind> bool HeapRing<kind>::is_full()
129 {
130 return (next(head_i) == tail_i);
131 }
132
133 template<class kind> bool HeapRing<kind>::is_empty()
134 {
135 return (head_i == tail_i);
136 }
137
138 /*
139 * resize
140 */
141
142 template<class kind> bool HeapRing<kind>::resize(unsigned int length)
143 {
144 if (is_empty())
145 {
146 if (length == 0)
147 {
148 __disable_irq();
149
150 if (is_empty()) // check again in case something was pushed
151 {
152 head_i = tail_i = this->length = 0;
153
154 __enable_irq();
155
156 free(ring);
157 ring = NULL;
158
159 return true;
160 }
161
162 __enable_irq();
163
164 return false;
165 }
166
167 // Note: we don't use realloc so we can fall back to the existing ring if allocation fails
168 kind* newring = new kind[length];
169
170 if (newring != NULL)
171 {
172 kind* oldring = ring;
173
174 __disable_irq();
175
176 if (is_empty()) // check again in case something was pushed while malloc did its thing
177 {
178 ring = newring;
179 this->length = length;
180 head_i = tail_i = 0;
181
182 __enable_irq();
183
184 if (oldring)
185 delete [] oldring;
186
187 return true;
188 }
189
190 __enable_irq();
191
192 delete [] newring;
193 }
194 }
195
196 return false;
197 }
198
199 template<class kind> bool HeapRing<kind>::provide(kind* buffer, unsigned int length)
200 {
201 __disable_irq();
202
203 if (is_empty())
204 {
205 kind* oldring = ring;
206
207 if ((buffer != NULL) && (length > 0))
208 {
209 ring = buffer;
210 this->length = length;
211 head_i = tail_i = 0;
212
213 __enable_irq();
214
215 if (oldring)
216 delete [] oldring;
217 return true;
218 }
219 }
220
221 __enable_irq();
222
223 return false;
224 }