Friendly LWM2M client
SafeQueue.h
Go to the documentation of this file.
1 
27 #ifndef SAFE_QUEUE_H_
28 #define SAFE_QUEUE_H_
29 
30 
31 #include <string.h>
32 #include <vector>
33 
34 
39 #include <WppGuard.h>
47 #define SQ_GUARD_CREATE(name) wpp::WppGuard name
55 #define SQ_GUARD_LOCK(name) name.lock()
63 #define SQ_GUARD_UNLOCK(name) name.unlock()
72 #define SQ_GUARD_TRY_LOCK(name) name.try_lock()
73 
74 
75 #define SAFE_QUEUE_DEF_ELEM_CNT 0x01
76 
77 
98 template <typename T, size_t SIZE>
99 class SafeQueue {
100 public:
102 
114  bool push(const T * const data, size_t elements_cnt = SAFE_QUEUE_DEF_ELEM_CNT);
115 
125  bool pop(size_t elements_cnt = SAFE_QUEUE_DEF_ELEM_CNT);
126 
137  std::vector<T> to_vector(size_t elements_cnt = SIZE);
138 
147  T* front();
148 
157  T* back();
158 
169  T* at(size_t i);
170 
182  bool front(T* data);
183 
195  bool back(T* data);
196 
209  bool at(size_t i, T* data);
210 
216  void clear();
217 
223  bool is_empty();
224 
230  bool is_full();
231 
237  size_t size();
238 
247  size_t available_space();
248 
254  uint32_t element_size();
255 
256 private:
260  inline size_t _get_next_index(size_t base_index, size_t elements_cnt = SAFE_QUEUE_DEF_ELEM_CNT);
261  inline size_t _get_prev_index(size_t base_index, size_t elements_cnt = SAFE_QUEUE_DEF_ELEM_CNT);
262 
263  inline bool _check_remove_ability(size_t elements_cnt = SAFE_QUEUE_DEF_ELEM_CNT);
264  inline bool _check_add_ability(size_t elements_cnt = SAFE_QUEUE_DEF_ELEM_CNT);
265 
266 private:
267  SQ_GUARD_CREATE(_push_guard);
268  SQ_GUARD_CREATE(_pop_guard);
269  size_t _front_i = 0x00, _end_i = 0x00, _counter = 0x00;
270  T _buffer[SIZE];
271 };
272 
273 
274 /* ------------- Public methods -------------*/
275 
276 template <typename T, size_t SIZE>
277 bool SafeQueue<T, SIZE>::push(const T * const data, size_t elements_cnt) {
278  if (!SQ_GUARD_TRY_LOCK(_push_guard)) return false;
279 
280  /* Check _buffer available space */
281  if (!elements_cnt || _check_add_ability(elements_cnt) == false) {
282  SQ_GUARD_UNLOCK(_push_guard);
283  return false;
284  }
285 
286  for (size_t i = 0; i < elements_cnt; i++) {
287  memcpy((uint8_t *)(_buffer + _end_i), (uint8_t *)(data + i), sizeof(T));
288  _end_i = _get_next_index(_end_i);
289  _counter++;
290  }
291 
292  SQ_GUARD_UNLOCK(_push_guard);
293  return true;
294 }
295 
296 template <typename T, size_t SIZE>
297 bool SafeQueue<T, SIZE>::pop(size_t elements_cnt) {
298  if (!SQ_GUARD_TRY_LOCK(_pop_guard)) return false;
299 
300  /* Maybe the _buffer available elements not enough */
301  if (_check_remove_ability(elements_cnt) == false) {
302  SQ_GUARD_UNLOCK(_pop_guard);
303  return false;
304  }
305 
306  _front_i = _get_next_index(_front_i, elements_cnt);
307  _counter -= elements_cnt;
308 
309  SQ_GUARD_UNLOCK(_pop_guard);
310  return true;
311 }
312 
313 template <typename T, size_t SIZE>
314 std::vector<T> SafeQueue<T, SIZE>::to_vector(size_t elements_cnt) {
315  SQ_GUARD_LOCK(_pop_guard);
316 
317  /* Maybe the _buffer available elements not enough */
318  if (!elements_cnt || elements_cnt > size()) {
319  SQ_GUARD_UNLOCK(_pop_guard);
320  return std::vector<T>();
321  }
322 
323  size_t end_of_range_index = _get_next_index(_front_i, elements_cnt);
324  uint8_t is_out_of_range = _front_i >= end_of_range_index;
325 
334  std::vector<T> converted (_buffer + _front_i, (is_out_of_range)? _buffer + SIZE : _buffer + end_of_range_index);
335  if (is_out_of_range) converted.insert(converted.end(), _buffer, _buffer + end_of_range_index);
336 
337  SQ_GUARD_UNLOCK(_pop_guard);
338  return converted;
339 }
340 
341 template <typename T, size_t SIZE>
343  if (is_empty()) return NULL;
344  return _buffer + _front_i;
345 }
346 
347 template <typename T, size_t SIZE>
349  if (is_empty()) return NULL;
350  return _buffer + _get_prev_index(_end_i);
351 }
352 
353 template <typename T, size_t SIZE>
355  if (is_empty() || i >= size()) return NULL;
356  return _buffer + ((_front_i + i) % SIZE);
357 }
358 
359 template <typename T, size_t SIZE>
361  if (!SQ_GUARD_TRY_LOCK(_pop_guard)) return false;
362 
363  if (!data || is_empty()) {
364  SQ_GUARD_UNLOCK(_pop_guard);
365  return false;
366  }
367  memcpy((uint8_t *)data, (uint8_t *)(_buffer + _front_i), sizeof(T));
368 
369  SQ_GUARD_UNLOCK(_pop_guard);
370  return true;
371 }
372 
373 template <typename T, size_t SIZE>
375  if (!SQ_GUARD_TRY_LOCK(_pop_guard)) return false;
376 
377  if (!data || is_empty()) {
378  SQ_GUARD_UNLOCK(_pop_guard);
379  return false;
380  }
381  memcpy((uint8_t *)data, (uint8_t *)(_buffer + _get_prev_index(_end_i)), sizeof(T));
382 
383  SQ_GUARD_UNLOCK(_pop_guard);
384  return true;
385 }
386 
387 template <typename T, size_t SIZE>
388 bool SafeQueue<T, SIZE>::at(size_t i, T* data) {
389  if (!SQ_GUARD_TRY_LOCK(_pop_guard)) return false;
390 
391  if (!data || is_empty() || i >= size()) {
392  SQ_GUARD_UNLOCK(_pop_guard);
393  return false;
394  }
395  memcpy((uint8_t *)data, (uint8_t *)(_buffer + ((_front_i + i) % SIZE)), sizeof(T));
396 
397  SQ_GUARD_UNLOCK(_pop_guard);
398  return true;
399 }
400 
401 template <typename T, size_t SIZE>
403  pop(size());
404 }
405 
406 template <typename T, size_t SIZE>
408  return _counter == 0x00;
409 }
410 
411 template <typename T, size_t SIZE>
413  return _counter == SIZE;
414 }
415 
416 template <typename T, size_t SIZE>
418  return _counter;
419 }
420 
421 template <typename T, size_t SIZE>
423  return SIZE - _counter;
424 }
425 
426 template <typename T, size_t SIZE>
428  return sizeof(T);
429 }
430 
431 
432 /* ------------- Private methods -------------*/
433 template <typename T, size_t SIZE>
434 size_t SafeQueue<T, SIZE>::_get_next_index(size_t base_index, size_t elements_cnt) {
435  return (base_index + elements_cnt) % SIZE;
436 }
437 
438 template <typename T, size_t SIZE>
439 size_t SafeQueue<T, SIZE>::_get_prev_index(size_t base_index, size_t elements_cnt) {
440  return (base_index >= elements_cnt)? (base_index - elements_cnt) : (SIZE - (elements_cnt - base_index));
441 }
442 
443 template <typename T, size_t SIZE>
444 bool SafeQueue<T, SIZE>::_check_remove_ability(size_t elements_cnt) {
445  return size() >= elements_cnt;
446 }
447 
448 template <typename T, size_t SIZE>
449 bool SafeQueue<T, SIZE>::_check_add_ability(size_t elements_cnt) {
450  return (SIZE - size()) >= elements_cnt;
451 }
452 
453 #endif /* SAFE_QUEUE_H_ */
#define SQ_GUARD_LOCK(name)
Macro for locking the specified guard object. The lock() method is used to acquire the lock on the gu...
Definition: SafeQueue.h:55
#define SQ_GUARD_UNLOCK(name)
Macro for unlocking the specified guard object. The unlock() method is used to release the lock on th...
Definition: SafeQueue.h:63
#define SQ_GUARD_TRY_LOCK(name)
Macro for trying to lock the specified guard object. The try_lock() method is used to attempt to acqu...
Definition: SafeQueue.h:72
#define SAFE_QUEUE_DEF_ELEM_CNT
Definition: SafeQueue.h:75
SafeQueue is an implementation of the thread/IRQ safe queue that does not use dynamic memory,...
Definition: SafeQueue.h:99
bool front(T *data)
Returns the first element in the queue and copies it to the specified memory location....
Definition: SafeQueue.h:360
void clear()
Clears the queue.
Definition: SafeQueue.h:402
T * at(size_t i)
Returns a pointer to the element at the specified index in the queue. The at() method does not guaran...
Definition: SafeQueue.h:354
T * front()
Returns a pointer to the first element in the queue. The front() method does not guarantee that the p...
Definition: SafeQueue.h:342
size_t available_space()
Returns the number of additional elements the queue can hold.
Definition: SafeQueue.h:422
uint32_t element_size()
Returns the size of each element in the queue.
Definition: SafeQueue.h:427
bool push(const T *const data, size_t elements_cnt=SAFE_QUEUE_DEF_ELEM_CNT)
Adds an element or an array of elements to the queue. The push() method can be simultaneously called ...
Definition: SafeQueue.h:277
bool is_empty()
Checks if the queue is empty.
Definition: SafeQueue.h:407
size_t size()
Returns the current size of the queue.
Definition: SafeQueue.h:417
bool back(T *data)
Returns the last element in the queue and copies it to the specified memory location....
Definition: SafeQueue.h:374
bool at(size_t i, T *data)
Returns the element at the specified index in the queue and copies it to the specified memory locatio...
Definition: SafeQueue.h:388
T * back()
Returns a pointer to the last element in the queue. The back() method does not guarantee that the poi...
Definition: SafeQueue.h:348
std::vector< T > to_vector(size_t elements_cnt=SIZE)
Converts the contents of the queue to a vector. The to_vector() method creates a vector containing a ...
Definition: SafeQueue.h:314
bool pop(size_t elements_cnt=SAFE_QUEUE_DEF_ELEM_CNT)
Removes a specified number of elements from the queue. The pop() method can be simultaneously called ...
Definition: SafeQueue.h:297
bool is_full()
Checks if the queue is full.
Definition: SafeQueue.h:412