HeapRing: add some sanity checks
[clinton/Smoothieware.git] / src / libs / HeapRing.cpp
CommitLineData
cc1e352c
MM
1#include "HeapRing.h"
2
3#include <cstdlib>
4
5#include "cmsis.h"
6
7/*
8 * constructors
9 */
10
11template<class kind> HeapRing<kind>::HeapRing()
12{
13 head_i = tail_i = length = 0;
14 ring = NULL;
15}
16
17template<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
29template<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
41template<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
52template<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
67template<class kind> kind& HeapRing<kind>::head()
68{
69 return ring[head_i];
70}
71
72template<class kind> kind& HeapRing<kind>::tail()
73{
74 return ring[tail_i];
75}
76
77template<class kind> kind& HeapRing<kind>::item(unsigned int i)
78{
79 return ring[i];
80}
81
82template<class kind> void HeapRing<kind>::push_front(kind& item)
83{
84 ring[head_i] = item;
85 head_i = next(head_i);
86}
87
88template<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
99template<class kind> kind* HeapRing<kind>::head_ref()
100{
101 return &ring[head_i];
102}
103
104template<class kind> kind* HeapRing<kind>::tail_ref()
105{
106 return &ring[tail_i];
107}
108
109template<class kind> kind* HeapRing<kind>::item_ref(unsigned int i)
110{
111 return &ring[i];
112}
113
114template<class kind> void HeapRing<kind>::produce_head()
115{
1b918dbb 116 while (is_full());
cc1e352c
MM
117 head_i = next(head_i);
118}
119
120template<class kind> void HeapRing<kind>::consume_tail()
121{
1b918dbb
MM
122 if (!is_empty())
123 tail_i = next(tail_i);
cc1e352c
MM
124}
125
126/*
127 * queue status accessors
128 */
129
130template<class kind> bool HeapRing<kind>::is_full()
131{
1b918dbb
MM
132 __disable_irq();
133 bool r = (next(head_i) == tail_i);
134 __enable_irq();
135
136 return r;
cc1e352c
MM
137}
138
139template<class kind> bool HeapRing<kind>::is_empty()
140{
1b918dbb
MM
141 __disable_irq();
142 bool r = (head_i == tail_i);
143 __enable_irq();
144
145 return r;
cc1e352c
MM
146}
147
148/*
149 * resize
150 */
151
152template<class kind> bool HeapRing<kind>::resize(unsigned int length)
153{
154 if (is_empty())
155 {
156 if (length == 0)
157 {
158 __disable_irq();
159
160 if (is_empty()) // check again in case something was pushed
161 {
162 head_i = tail_i = this->length = 0;
163
164 __enable_irq();
165
b6691e01
MM
166 if (ring)
167 delete [] ring;
cc1e352c
MM
168 ring = NULL;
169
170 return true;
171 }
172
173 __enable_irq();
174
175 return false;
176 }
177
178 // Note: we don't use realloc so we can fall back to the existing ring if allocation fails
179 kind* newring = new kind[length];
180
181 if (newring != NULL)
182 {
183 kind* oldring = ring;
184
185 __disable_irq();
186
187 if (is_empty()) // check again in case something was pushed while malloc did its thing
188 {
189 ring = newring;
190 this->length = length;
191 head_i = tail_i = 0;
192
193 __enable_irq();
194
195 if (oldring)
196 delete [] oldring;
197
198 return true;
199 }
200
201 __enable_irq();
202
203 delete [] newring;
204 }
205 }
206
207 return false;
208}
209
210template<class kind> bool HeapRing<kind>::provide(kind* buffer, unsigned int length)
211{
212 __disable_irq();
213
214 if (is_empty())
215 {
216 kind* oldring = ring;
217
218 if ((buffer != NULL) && (length > 0))
219 {
220 ring = buffer;
221 this->length = length;
222 head_i = tail_i = 0;
223
224 __enable_irq();
225
226 if (oldring)
227 delete [] oldring;
228 return true;
229 }
230 }
231
232 __enable_irq();
233
234 return false;
235}