Merge branch 'feature/correct-rotarydelta-homing' into upstreamedge
[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 while (is_full());
117 head_i = next(head_i);
118 }
119
120 template<class kind> void HeapRing<kind>::consume_tail()
121 {
122 if (!is_empty())
123 tail_i = next(tail_i);
124 }
125
126 /*
127 * queue status accessors
128 */
129
130 template<class kind> bool HeapRing<kind>::is_full()
131 {
132 __disable_irq();
133 bool r = (next(head_i) == tail_i);
134 __enable_irq();
135
136 return r;
137 }
138
139 template<class kind> bool HeapRing<kind>::is_empty()
140 {
141 __disable_irq();
142 bool r = (head_i == tail_i);
143 __enable_irq();
144
145 return r;
146 }
147
148 /*
149 * resize
150 */
151
152 template<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
166 if (ring)
167 delete [] ring;
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
210 template<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 }