Embedded Template Library  1.0
queue_spsc_isr.h
Go to the documentation of this file.
1 
3 /******************************************************************************
4 The MIT License(MIT)
5 
6 Embedded Template Library.
7 https://github.com/ETLCPP/etl
8 https://www.etlcpp.com
9 
10 Copyright(c) 2018 jwellbelove
11 
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files(the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions :
18 
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21 
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29 ******************************************************************************/
30 
31 #ifndef ETL_SPSC_QUEUE_ISR_INCLUDED
32 #define ETL_SPSC_QUEUE_ISR_INCLUDED
33 
34 #include <stddef.h>
35 #include <stdint.h>
36 
37 #include "platform.h"
38 #include "alignment.h"
39 #include "parameter_type.h"
40 #include "memory_model.h"
41 #include "integral_limits.h"
42 #include "utility.h"
43 #include "placement_new.h"
44 
45 #undef ETL_FILE
46 #define ETL_FILE "46"
47 
48 namespace etl
49 {
50  template <typename T, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
52  {
53  public:
54 
57 
58  typedef T value_type;
59  typedef T& reference;
60  typedef const T& const_reference;
61 #if ETL_CPP11_SUPPORTED
62  typedef T&& rvalue_reference;
63 #endif
64 
65  //*************************************************************************
67  //*************************************************************************
69  {
70  return push_implementation(value);
71  }
72 
73 #if ETL_CPP11_SUPPORTED
74  //*************************************************************************
76  //*************************************************************************
77  bool push_from_isr(rvalue_reference value)
78  {
79  return push_implementation(etl::move(value));
80  }
81 #endif
82 
83  //*************************************************************************
87  //*************************************************************************
88 #if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_ISR_FORCE_CPP03)
89  template <typename ... Args>
90  bool emplace_from_isr(Args&&... args)
91  {
92  return emplace_implementation(etl::forward<Args>(args)...);
93  }
94 #endif
95 
96  //*************************************************************************
98  //*************************************************************************
99  bool pop_from_isr(reference value)
100  {
101  return pop_implementation(value);
102  }
103 
104 #if ETL_CPP11_SUPPORTED
105  //*************************************************************************
107  //*************************************************************************
108  bool pop_from_isr(rvalue_reference value)
109  {
110  return pop_implementation(etl::move(value));
111  }
112 #endif
113 
114  //*************************************************************************
116  //*************************************************************************
118  {
119  return pop_implementation();
120  }
121 
122  //*************************************************************************
125  //*************************************************************************
127  {
128  return MAX_SIZE - current_size;
129  }
130 
131  //*************************************************************************
133  //*************************************************************************
135  {
136  while (pop_implementation())
137  {
138  // Do nothing.
139  }
140  }
141 
142  //*************************************************************************
145  //*************************************************************************
146  bool empty_from_isr() const
147  {
148  return (current_size == 0);
149  }
150 
151  //*************************************************************************
154  //*************************************************************************
155  bool full_from_isr() const
156  {
157  return (current_size == MAX_SIZE);
158  }
159 
160  //*************************************************************************
163  //*************************************************************************
165  {
166  return current_size;
167  }
168 
169  //*************************************************************************
171  //*************************************************************************
173  {
174  return MAX_SIZE;
175  }
176 
177  //*************************************************************************
179  //*************************************************************************
181  {
182  return MAX_SIZE;
183  }
184 
185  protected:
186 
187  queue_spsc_isr_base(T* p_buffer_, size_type max_size_)
188  : p_buffer(p_buffer_),
189  write_index(0),
190  read_index(0),
191  current_size(0),
192  MAX_SIZE(max_size_)
193  {
194  }
195 
196  //*************************************************************************
198  //*************************************************************************
200  {
201  if (current_size != MAX_SIZE)
202  {
203  ::new (&p_buffer[write_index]) T(value);
204 
206 
207  ++current_size;
208 
209  return true;
210  }
211 
212  // Queue is full.
213  return false;
214  }
215 
216 #if ETL_CPP11_SUPPORTED
217  //*************************************************************************
219  //*************************************************************************
220  bool push_implementation(rvalue_reference value)
221  {
222  if (current_size != MAX_SIZE)
223  {
224  ::new (&p_buffer[write_index]) T(etl::move(value));
225 
227 
228  ++current_size;
229 
230  return true;
231  }
232 
233  // Queue is full.
234  return false;
235  }
236 #endif
237 
238 #if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_ISR_FORCE_CPP03)
239  //*************************************************************************
243  //*************************************************************************
244  template <typename ... Args>
245  bool emplace_implementation(Args&&... args)
246  {
247  if (current_size != MAX_SIZE)
248  {
249  ::new (&p_buffer[write_index]) T(etl::forward<Args>(args)...);
250 
252 
253  ++current_size;
254 
255  return true;
256  }
257 
258  // Queue is full.
259  return false;
260  }
261 #else
262  //*************************************************************************
265  //*************************************************************************
266  template <typename T1>
267  bool emplace_implementation(const T1& value1)
268  {
269  if (current_size != MAX_SIZE)
270  {
271  ::new (&p_buffer[write_index]) T(value1);
272 
274 
275  ++current_size;
276 
277  return true;
278  }
279 
280  // Queue is full.
281  return false;
282  }
283 
284  //*************************************************************************
287  //*************************************************************************
288  template <typename T1, typename T2>
289  bool emplace_implementation(const T1& value1, const T2& value2)
290  {
291  if (current_size != MAX_SIZE)
292  {
293  ::new (&p_buffer[write_index]) T(value1, value2);
294 
296 
297  ++current_size;
298 
299  return true;
300  }
301 
302  // Queue is full.
303  return false;
304  }
305 
306  //*************************************************************************
309  //*************************************************************************
310  template <typename T1, typename T2, typename T3>
311  bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3)
312  {
313  if (current_size != MAX_SIZE)
314  {
315  ::new (&p_buffer[write_index]) T(value1, value2, value3);
316 
318 
319  ++current_size;
320 
321  return true;
322  }
323 
324  // Queue is full.
325  return false;
326  }
327 
328  //*************************************************************************
331  //*************************************************************************
332  template <typename T1, typename T2, typename T3, typename T4>
333  bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
334  {
335  if (current_size != MAX_SIZE)
336  {
337  ::new (&p_buffer[write_index]) T(value1, value2, value3, value4);
338 
340 
341  ++current_size;
342 
343  return true;
344  }
345 
346  // Queue is full.
347  return false;
348  }
349 
350 #endif
351 
352  //*************************************************************************
354  //*************************************************************************
356  {
357  if (current_size == 0)
358  {
359  // Queue is empty
360  return false;
361  }
362 
363  value = p_buffer[read_index];
364  p_buffer[read_index].~T();
365 
367 
368  --current_size;
369 
370  return true;
371  }
372 
373 #if ETL_CPP11_SUPPORTED
374  //*************************************************************************
376  //*************************************************************************
377  bool pop_implementation(rvalue_reference value)
378  {
379  if (current_size == 0)
380  {
381  // Queue is empty
382  return false;
383  }
384 
385  value = etl::move(p_buffer[read_index]);
386  p_buffer[read_index].~T();
387 
389 
390  --current_size;
391 
392  return true;
393  }
394 #endif
395 
396  //*************************************************************************
398  //*************************************************************************
400  {
401  if (current_size == 0)
402  {
403  // Queue is empty
404  return false;
405  }
406 
407  p_buffer[read_index].~T();
408 
410 
411  --current_size;
412 
413  return true;
414  }
415 
416  //*************************************************************************
418  //*************************************************************************
420  {
421  ++index;
422 
423  if (index == maximum)
424  {
425  index = 0;
426  }
427 
428  return index;
429  }
430 
431  T* p_buffer;
436 
437  private:
438 
439  //*************************************************************************
441  //*************************************************************************
442 #if defined(ETL_POLYMORPHIC_SPSC_QUEUE_ISR) || defined(ETL_POLYMORPHIC_CONTAINERS)
443  public:
444  virtual ~queue_spsc_isr_base()
445  {
446  }
447 #else
448  protected:
450  {
451  }
452 #endif
453  };
454 
455  //***************************************************************************
465  //***************************************************************************
466  template <typename T, typename TAccess, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
467  class iqueue_spsc_isr : public queue_spsc_isr_base<T, MEMORY_MODEL>
468  {
469  private:
470 
472 
473  public:
474 
475  typedef typename base_t::value_type value_type;
476  typedef typename base_t::reference reference;
478 #if ETL_CPP11_SUPPORTED
479  typedef typename base_t::rvalue_reference rvalue_reference;
480 #endif
481  typedef typename base_t::size_type size_type;
482 
483  //*************************************************************************
485  //*************************************************************************
486  bool push(const_reference value)
487  {
488  TAccess::lock();
489 
490  bool result = this->push_implementation(value);
491 
492  TAccess::unlock();
493 
494  return result;
495  }
496 
497 #if ETL_CPP11_SUPPORTED
498  //*************************************************************************
500  //*************************************************************************
501  bool push(rvalue_reference value)
502  {
503  TAccess::lock();
504 
505  bool result = this->push_implementation(etl::move(value));
506 
507  TAccess::unlock();
508 
509  return result;
510  }
511 #endif
512 
513  //*************************************************************************
516  //*************************************************************************
517 #if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_ISR_FORCE_CPP03)
518  template <typename ... Args>
519  bool emplace(Args&&... args)
520  {
521  TAccess::lock();
522 
523  bool result = this->emplace_implementation(etl::forward<Args>(args)...);
524 
525  TAccess::unlock();
526 
527  return result;
528  }
529 #else
530  //*************************************************************************
533  //*************************************************************************
534  template <typename T1>
535  bool emplace(const T1& value1)
536  {
537  TAccess::lock();
538 
539  bool result = this->emplace_implementation(value1);
540 
541  TAccess::unlock();
542 
543  return result;
544  }
545 
546  //*************************************************************************
549  //*************************************************************************
550  template <typename T1, typename T2>
551  bool emplace(const T1& value1, const T2& value2)
552  {
553  TAccess::lock();
554 
555  bool result = this->emplace_implementation(value1, value2);
556 
557  TAccess::unlock();
558 
559  return result;
560  }
561 
562  //*************************************************************************
565  //*************************************************************************
566  template <typename T1, typename T2, typename T3>
567  bool emplace(const T1& value1, const T2& value2, const T3& value3)
568  {
569  TAccess::lock();
570 
571  bool result = this->emplace_implementation(value1, value2, value3);
572 
573  TAccess::unlock();
574 
575  return result;
576  }
577 
578  //*************************************************************************
581  //*************************************************************************
582  template <typename T1, typename T2, typename T3, typename T4>
583  bool emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
584  {
585  TAccess::lock();
586 
587  bool result = this->emplace_implementation(value1, value2, value3, value4);
588 
589  TAccess::unlock();
590 
591  return result;
592  }
593 #endif
594 
595  //*************************************************************************
597  //*************************************************************************
598  bool pop(reference value)
599  {
600  TAccess::lock();
601 
602  bool result = this->pop_implementation(value);
603 
604  TAccess::unlock();
605 
606  return result;
607  }
608 
609 #if ETL_CPP11_SUPPORTED
610  //*************************************************************************
612  //*************************************************************************
613  bool pop(rvalue_reference value)
614  {
615  TAccess::lock();
616 
617  bool result = this->pop_implementation(etl::move(value));
618 
619  TAccess::unlock();
620 
621  return result;
622  }
623 #endif
624 
625  //*************************************************************************
627  //*************************************************************************
628  bool pop()
629  {
630  TAccess::lock();
631 
632  bool result = this->pop_implementation();
633 
634  TAccess::unlock();
635 
636  return result;
637  }
638 
639  //*************************************************************************
641  //*************************************************************************
642  void clear()
643  {
644  TAccess::lock();
645 
646  while (this->pop_implementation())
647  {
648  // Do nothing.
649  }
650 
651  TAccess::unlock();
652  }
653 
654  //*************************************************************************
656  //*************************************************************************
657  bool empty() const
658  {
659  TAccess::lock();
660 
661  size_type result = (this->current_size == 0);
662 
663  TAccess::unlock();
664 
665  return result;
666  }
667 
668  //*************************************************************************
670  //*************************************************************************
671  bool full() const
672  {
673  TAccess::lock();
674 
675  size_type result = (this->current_size == this->MAX_SIZE);
676 
677  TAccess::unlock();
678 
679  return result;
680  }
681 
682  //*************************************************************************
684  //*************************************************************************
685  size_type size() const
686  {
687  TAccess::lock();
688 
689  size_type result = this->current_size;
690 
691  TAccess::unlock();
692 
693  return result;
694  }
695 
696  //*************************************************************************
698  //*************************************************************************
700  {
701  TAccess::lock();
702 
703  size_type result = this->MAX_SIZE - this->current_size;
704 
705  TAccess::unlock();
706 
707  return result;
708  }
709 
710  protected:
711 
712  //*************************************************************************
714  //*************************************************************************
715  iqueue_spsc_isr(T* p_buffer_, size_type max_size_)
716  : base_t(p_buffer_, max_size_)
717  {
718  }
719 
720  private:
721 
722  // Disable copy construction and assignment.
723  iqueue_spsc_isr(const iqueue_spsc_isr&) ETL_DELETE;
724  iqueue_spsc_isr& operator =(const iqueue_spsc_isr&) ETL_DELETE;
725 
726 #if ETL_CPP11_SUPPORTED
727  iqueue_spsc_isr(iqueue_spsc_isr&&) = delete;
728  iqueue_spsc_isr& operator =(iqueue_spsc_isr&&) = delete;
729 #endif
730 
731  TAccess access;
732  };
733 
734  //***************************************************************************
742  //***************************************************************************
743  template <typename T, size_t SIZE, typename TAccess, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
744  class queue_spsc_isr : public etl::iqueue_spsc_isr<T, TAccess, MEMORY_MODEL>
745  {
746  private:
747 
749 
750  public:
751 
752  typedef typename base_t::size_type size_type;
753 
754  ETL_STATIC_ASSERT((SIZE <= etl::integral_limits<size_type>::max), "Size too large for memory model");
755 
756  static const size_type MAX_SIZE = size_type(SIZE);
757 
758  //*************************************************************************
760  //*************************************************************************
762  : base_t(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE)
763  {
764  }
765 
766  //*************************************************************************
768  //*************************************************************************
770  {
771  base_t::clear();
772  }
773 
774  private:
775 
777  queue_spsc_isr& operator = (const queue_spsc_isr&);
778 
779 #if ETL_CPP11_SUPPORTED
780  queue_spsc_isr(queue_spsc_isr&&) = delete;
781  queue_spsc_isr& operator =(queue_spsc_isr&&) = delete;
782 #endif
783 
785  typename etl::aligned_storage<sizeof(T), etl::alignment_of<T>::value>::type buffer[MAX_SIZE];
786  };
787 }
788 
789 #undef ETL_FILE
790 
791 #endif
This is the base for all queue_spsc_isrs that contain a particular type.
Definition: queue_spsc_isr.h:468
bool emplace(const T1 &value1, const T2 &value2)
Definition: queue_spsc_isr.h:551
base_t::size_type size_type
The type used for determining the size of the queue.
Definition: queue_spsc_isr.h:481
size_type size() const
How many items in the queue?
Definition: queue_spsc_isr.h:685
base_t::const_reference const_reference
A const reference to the type used in the queue.
Definition: queue_spsc_isr.h:477
bool pop()
Pop a value from the queue and discard.
Definition: queue_spsc_isr.h:628
size_type available() const
How much free space available in the queue.
Definition: queue_spsc_isr.h:699
bool full() const
Is the queue full?
Definition: queue_spsc_isr.h:671
void clear()
Clear the queue.
Definition: queue_spsc_isr.h:642
bool push(const_reference value)
Push a value to the queue.
Definition: queue_spsc_isr.h:486
bool emplace(const T1 &value1, const T2 &value2, const T3 &value3)
Definition: queue_spsc_isr.h:567
base_t::value_type value_type
The type stored in the queue.
Definition: queue_spsc_isr.h:475
iqueue_spsc_isr(T *p_buffer_, size_type max_size_)
The constructor that is called from derived classes.
Definition: queue_spsc_isr.h:715
bool pop(reference value)
Pop a value from the queue.
Definition: queue_spsc_isr.h:598
bool emplace(const T1 &value1, const T2 &value2, const T3 &value3, const T4 &value4)
Definition: queue_spsc_isr.h:583
base_t::reference reference
A reference to the type used in the queue.
Definition: queue_spsc_isr.h:476
bool emplace(const T1 &value1)
Definition: queue_spsc_isr.h:535
bool empty() const
Is the queue empty?
Definition: queue_spsc_isr.h:657
Definition: queue_spsc_isr.h:52
bool full_from_isr() const
Definition: queue_spsc_isr.h:155
bool pop_implementation(reference value)
Pop a value from the queue.
Definition: queue_spsc_isr.h:355
bool push_from_isr(const_reference value)
Push a value to the queue from an ISR.
Definition: queue_spsc_isr.h:68
bool emplace_implementation(const T1 &value1, const T2 &value2)
Definition: queue_spsc_isr.h:289
T value_type
The type stored in the queue.
Definition: queue_spsc_isr.h:58
bool emplace_implementation(const T1 &value1, const T2 &value2, const T3 &value3)
Definition: queue_spsc_isr.h:311
size_type capacity() const
How many items can the queue hold.
Definition: queue_spsc_isr.h:172
bool emplace_implementation(const T1 &value1)
Definition: queue_spsc_isr.h:267
void clear_from_isr()
Clear the queue from the ISR.
Definition: queue_spsc_isr.h:134
static size_type get_next_index(size_type index, size_type maximum)
Calculate the next index.
Definition: queue_spsc_isr.h:419
size_type available_from_isr() const
Definition: queue_spsc_isr.h:126
~queue_spsc_isr_base()
Destructor.
Definition: queue_spsc_isr.h:449
etl::size_type_lookup< MEMORY_MODEL >::type size_type
The type used for determining the size of queue.
Definition: queue_spsc_isr.h:56
size_type read_index
Where to get the oldest data.
Definition: queue_spsc_isr.h:433
bool emplace_implementation(const T1 &value1, const T2 &value2, const T3 &value3, const T4 &value4)
Definition: queue_spsc_isr.h:333
size_type max_size() const
How many items can the queue hold.
Definition: queue_spsc_isr.h:180
bool pop_from_isr()
Pop a value from the queue from an ISR, and discard.
Definition: queue_spsc_isr.h:117
bool pop_implementation()
Pop a value from the queue and discard.
Definition: queue_spsc_isr.h:399
bool pop_from_isr(reference value)
Pop a value from the queue from an ISR.
Definition: queue_spsc_isr.h:99
size_type write_index
Where to input new data.
Definition: queue_spsc_isr.h:432
const size_type MAX_SIZE
The maximum number of items in the queue.
Definition: queue_spsc_isr.h:435
bool empty_from_isr() const
Definition: queue_spsc_isr.h:146
T * p_buffer
The internal buffer.
Definition: queue_spsc_isr.h:431
size_type current_size
The current size of the queue.
Definition: queue_spsc_isr.h:434
T & reference
A reference to the type used in the queue.
Definition: queue_spsc_isr.h:59
const T & const_reference
A const reference to the type used in the queue.
Definition: queue_spsc_isr.h:60
size_type size_from_isr() const
Definition: queue_spsc_isr.h:164
bool push_implementation(const_reference value)
Push a value to the queue.
Definition: queue_spsc_isr.h:199
Definition: queue_spsc_isr.h:745
queue_spsc_isr()
Default constructor.
Definition: queue_spsc_isr.h:761
~queue_spsc_isr()
Destructor.
Definition: queue_spsc_isr.h:769
Definition: alignment.h:116
Definition: integral_limits.h:54
add_rvalue_reference
Definition: type_traits_generator.h:1348
Definition: absolute.h:37
Definition: memory_model.h:48