Embedded Template Library 1.0
Loading...
Searching...
No Matches
queue_spsc_isr.h
Go to the documentation of this file.
1
2
3/******************************************************************************
4The MIT License(MIT)
5
6Embedded Template Library.
7https://github.com/ETLCPP/etl
8https://www.etlcpp.com
9
10Copyright(c) 2018 John Wellbelove
11
12Permission is hereby granted, free of charge, to any person obtaining a copy
13of this software and associated documentation files(the "Software"), to deal
14in the Software without restriction, including without limitation the rights
15to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16copies of the Software, and to permit persons to whom the Software is
17furnished to do so, subject to the following conditions :
18
19The above copyright notice and this permission notice shall be included in all
20copies or substantial portions of the Software.
21
22THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28SOFTWARE.
29******************************************************************************/
30
31#ifndef ETL_SPSC_QUEUE_ISR_INCLUDED
32#define ETL_SPSC_QUEUE_ISR_INCLUDED
33
34#include "platform.h"
35#include "alignment.h"
36#include "integral_limits.h"
37#include "memory_model.h"
38#include "mutex.h"
39#include "parameter_type.h"
40#include "placement_new.h"
41#include "utility.h"
42
43#include <stddef.h>
44#include <stdint.h>
45
46namespace etl
47{
48 //***************************************************************************
51 //***************************************************************************
52 class queue_spsc_isr_exception : public exception
53 {
54 public:
55
56 queue_spsc_isr_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
57 : exception(reason_, file_name_, line_number_)
58 {
59 }
60 };
61
62 //***************************************************************************
65 //***************************************************************************
66 class queue_spsc_isr_empty : public queue_spsc_isr_exception
67 {
68 public:
69
70 queue_spsc_isr_empty(string_type file_name_, numeric_type line_number_)
71 : queue_spsc_isr_exception(ETL_ERROR_TEXT("queue_spsc_isr:empty", ETL_QUEUE_SPSC_ISR_FILE_ID"A"), file_name_, line_number_)
72 {
73 }
74 };
75
76 template <typename T, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
77 class queue_spsc_isr_base
78 {
79 public:
80
83
84 typedef T value_type;
85 typedef T& reference;
86 typedef const T& const_reference;
87#if ETL_USING_CPP11
88 typedef T&& rvalue_reference;
89#endif
90
91 //*************************************************************************
93 //*************************************************************************
95 {
96 return push_implementation(value);
97 }
98
99#if ETL_USING_CPP11
100 //*************************************************************************
102 //*************************************************************************
103 bool push_from_isr(rvalue_reference value)
104 {
105 return push_implementation(etl::move(value));
106 }
107#endif
108
109 //*************************************************************************
114 //*************************************************************************
115#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_ISR_FORCE_CPP03_IMPLEMENTATION)
116 template <typename... Args>
117 bool emplace_from_isr(Args&&... args)
118 {
119 return emplace_implementation(etl::forward<Args>(args)...);
120 }
121#endif
122
123 //*************************************************************************
125 //*************************************************************************
127 {
128 return pop_implementation(value);
129 }
130
131 //*************************************************************************
133 //*************************************************************************
135 {
136 return pop_implementation();
137 }
138
139 //*************************************************************************
143 //*************************************************************************
145 {
146 ETL_ASSERT_CHECK_EXTRA(!empty_from_isr(), ETL_ERROR(queue_spsc_isr_empty));
147
148 return front_implementation();
149 }
150
151 //*************************************************************************
155 //*************************************************************************
157 {
158 ETL_ASSERT_CHECK_EXTRA(!empty_from_isr(), ETL_ERROR(queue_spsc_isr_empty));
159
160 return front_implementation();
161 }
162
163 //*************************************************************************
166 //*************************************************************************
168 {
169 return MAX_SIZE - current_size;
170 }
171
172 //*************************************************************************
174 //*************************************************************************
176 {
177 while (pop_implementation())
178 {
179 // Do nothing.
180 }
181 }
182
183 //*************************************************************************
186 //*************************************************************************
187 bool empty_from_isr() const
188 {
189 return (current_size == 0);
190 }
191
192 //*************************************************************************
195 //*************************************************************************
196 bool full_from_isr() const
197 {
198 return (current_size == MAX_SIZE);
199 }
200
201 //*************************************************************************
204 //*************************************************************************
206 {
207 return current_size;
208 }
209
210 //*************************************************************************
212 //*************************************************************************
214 {
215 return MAX_SIZE;
216 }
217
218 //*************************************************************************
220 //*************************************************************************
222 {
223 return MAX_SIZE;
224 }
225
226 protected:
227
228 queue_spsc_isr_base(T* p_buffer_, size_type max_size_)
229 : p_buffer(p_buffer_)
230 , write_index(0)
231 , read_index(0)
232 , current_size(0)
233 , MAX_SIZE(max_size_)
234 {
235 }
236
237 //*************************************************************************
239 //*************************************************************************
241 {
242 if (current_size != MAX_SIZE)
243 {
244 ::new (&p_buffer[write_index]) T(value);
245
247
248 ++current_size;
249
250 return true;
251 }
252
253 // Queue is full.
254 return false;
255 }
256
257#if ETL_USING_CPP11
258 //*************************************************************************
260 //*************************************************************************
261 bool push_implementation(rvalue_reference value)
262 {
263 if (current_size != MAX_SIZE)
264 {
265 ::new (&p_buffer[write_index]) T(etl::move(value));
266
268
269 ++current_size;
270
271 return true;
272 }
273
274 // Queue is full.
275 return false;
276 }
277#endif
278
279#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_ISR_FORCE_CPP03_IMPLEMENTATION)
280 //*************************************************************************
285 //*************************************************************************
286 template <typename... Args>
287 bool emplace_implementation(Args&&... args)
288 {
289 if (current_size != MAX_SIZE)
290 {
291 ::new (&p_buffer[write_index]) T(etl::forward<Args>(args)...);
292
294
295 ++current_size;
296
297 return true;
298 }
299
300 // Queue is full.
301 return false;
302 }
303#else
304 //*************************************************************************
308 //*************************************************************************
310 {
311 if (current_size != MAX_SIZE)
312 {
313 ::new (&p_buffer[write_index]) T();
314
316
317 ++current_size;
318
319 return true;
320 }
321
322 // Queue is full.
323 return false;
324 }
325
326 //*************************************************************************
330 //*************************************************************************
331 template <typename T1>
332 bool emplace_implementation(const T1& value1)
333 {
334 if (current_size != MAX_SIZE)
335 {
336 ::new (&p_buffer[write_index]) T(value1);
337
339
340 ++current_size;
341
342 return true;
343 }
344
345 // Queue is full.
346 return false;
347 }
348
349 //*************************************************************************
353 //*************************************************************************
354 template <typename T1, typename T2>
355 bool emplace_implementation(const T1& value1, const T2& value2)
356 {
357 if (current_size != MAX_SIZE)
358 {
359 ::new (&p_buffer[write_index]) T(value1, value2);
360
362
363 ++current_size;
364
365 return true;
366 }
367
368 // Queue is full.
369 return false;
370 }
371
372 //*************************************************************************
376 //*************************************************************************
377 template <typename T1, typename T2, typename T3>
378 bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3)
379 {
380 if (current_size != MAX_SIZE)
381 {
382 ::new (&p_buffer[write_index]) T(value1, value2, value3);
383
385
386 ++current_size;
387
388 return true;
389 }
390
391 // Queue is full.
392 return false;
393 }
394
395 //*************************************************************************
399 //*************************************************************************
400 template <typename T1, typename T2, typename T3, typename T4>
401 bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
402 {
403 if (current_size != MAX_SIZE)
404 {
405 ::new (&p_buffer[write_index]) T(value1, value2, value3, value4);
406
408
409 ++current_size;
410
411 return true;
412 }
413
414 // Queue is full.
415 return false;
416 }
417
418#endif
419
420 //*************************************************************************
422 //*************************************************************************
424 {
425 if (current_size == 0)
426 {
427 // Queue is empty
428 return false;
429 }
430
431#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_LOCKABLE_FORCE_CPP03_IMPLEMENTATION)
432 value = etl::move(p_buffer[read_index]);
433#else
434 value = p_buffer[read_index];
435#endif
436
437 p_buffer[read_index].~T();
438
440
441 --current_size;
442
443 return true;
444 }
445
446 //*************************************************************************
448 //*************************************************************************
453
454 //*************************************************************************
456 //*************************************************************************
458 {
459 return p_buffer[read_index];
460 }
461
462 //*************************************************************************
464 //*************************************************************************
466 {
467 if (current_size == 0)
468 {
469 // Queue is empty
470 return false;
471 }
472
473 p_buffer[read_index].~T();
474
476
477 --current_size;
478
479 return true;
480 }
481
482 //*************************************************************************
484 //*************************************************************************
486 {
487 ++index;
488
489 if (index == maximum) ETL_UNLIKELY
490 {
491 index = 0;
492 }
493
494 return index;
495 }
496
502
503 private:
504
505 //*************************************************************************
507 //*************************************************************************
508#if defined(ETL_POLYMORPHIC_SPSC_QUEUE_ISR) || defined(ETL_POLYMORPHIC_CONTAINERS)
509
510 public:
511
512 virtual ~queue_spsc_isr_base() {}
513#else
514
515 protected:
516
518#endif
519 };
520
521 //***************************************************************************
531 //***************************************************************************
532 template <typename T, typename TAccess, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
533 class iqueue_spsc_isr : public queue_spsc_isr_base<T, MEMORY_MODEL>
534 {
535 private:
536
537 typedef queue_spsc_isr_base<T, MEMORY_MODEL> base_t;
538
539 public:
540
542 typedef typename base_t::reference reference;
544#if ETL_USING_CPP11
545 typedef typename base_t::rvalue_reference rvalue_reference;
546#endif
547 typedef typename base_t::size_type size_type;
548
549 //*************************************************************************
551 //*************************************************************************
553 {
554 TAccess::lock();
555
556 bool result = this->push_implementation(value);
557
558 TAccess::unlock();
559
560 return result;
561 }
562
563#if ETL_USING_CPP11
564 //*************************************************************************
566 //*************************************************************************
567 bool push(rvalue_reference value)
568 {
569 TAccess::lock();
570
571 bool result = this->push_implementation(etl::move(value));
572
573 TAccess::unlock();
574
575 return result;
576 }
577#endif
578
579 //*************************************************************************
583 //*************************************************************************
584#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_ISR_FORCE_CPP03_IMPLEMENTATION)
585 template <typename... Args>
586 bool emplace(Args&&... args)
587 {
588 TAccess::lock();
589
590 bool result = this->emplace_implementation(etl::forward<Args>(args)...);
591
592 TAccess::unlock();
593
594 return result;
595 }
596#else
597 //*************************************************************************
601 //*************************************************************************
602 bool emplace()
603 {
604 TAccess::lock();
605
606 bool result = this->emplace_implementation();
607
608 TAccess::unlock();
609
610 return result;
611 }
612
613 //*************************************************************************
617 //*************************************************************************
618 template <typename T1>
619 bool emplace(const T1& value1)
620 {
621 TAccess::lock();
622
623 bool result = this->emplace_implementation(value1);
624
625 TAccess::unlock();
626
627 return result;
628 }
629
630 //*************************************************************************
634 //*************************************************************************
635 template <typename T1, typename T2>
636 bool emplace(const T1& value1, const T2& value2)
637 {
638 TAccess::lock();
639
640 bool result = this->emplace_implementation(value1, value2);
641
642 TAccess::unlock();
643
644 return result;
645 }
646
647 //*************************************************************************
651 //*************************************************************************
652 template <typename T1, typename T2, typename T3>
653 bool emplace(const T1& value1, const T2& value2, const T3& value3)
654 {
655 TAccess::lock();
656
657 bool result = this->emplace_implementation(value1, value2, value3);
658
659 TAccess::unlock();
660
661 return result;
662 }
663
664 //*************************************************************************
668 //*************************************************************************
669 template <typename T1, typename T2, typename T3, typename T4>
670 bool emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
671 {
672 TAccess::lock();
673
674 bool result = this->emplace_implementation(value1, value2, value3, value4);
675
676 TAccess::unlock();
677
678 return result;
679 }
680#endif
681
682 //*************************************************************************
684 //*************************************************************************
685 bool pop(reference value)
686 {
687 TAccess::lock();
688
689 bool result = this->pop_implementation(value);
690
691 TAccess::unlock();
692
693 return result;
694 }
695
696 //*************************************************************************
698 //*************************************************************************
699 bool pop()
700 {
701 TAccess::lock();
702
703 bool result = this->pop_implementation();
704
705 TAccess::unlock();
706
707 return result;
708 }
709
710 //*************************************************************************
714 //*************************************************************************
716 {
717#if ETL_CHECKING_EXTRA
718 TAccess::lock();
719 if (!this->empty_from_isr())
720 {
721 reference inner_result = this->front_implementation();
722 TAccess::unlock();
723 return inner_result;
724 }
725 else
726 {
727 TAccess::unlock();
728 ETL_ASSERT_FAIL(ETL_ERROR(queue_spsc_isr_empty));
729 // fall through to return something to satisfy the compiler, even
730 // though this should never be reached due to undefined behaviour.
731 }
732#endif
733 TAccess::lock();
734 reference result = this->front_implementation();
735 TAccess::unlock();
736 return result;
737 }
738
739 //*************************************************************************
743 //*************************************************************************
745 {
746#if ETL_CHECKING_EXTRA
747 TAccess::lock();
748 if (!this->empty_from_isr())
749 {
750 const_reference inner_result = this->front_implementation();
751 TAccess::unlock();
752 return inner_result;
753 }
754 else
755 {
756 TAccess::unlock();
757 ETL_ASSERT_FAIL(ETL_ERROR(queue_spsc_isr_empty));
758 // fall through to return something to satisfy the compiler, even
759 // though this should never be reached due to undefined behaviour.
760 }
761#endif
762 TAccess::lock();
763 const_reference result = this->front_implementation();
764 TAccess::unlock();
765 return result;
766 }
767
768 //*************************************************************************
770 //*************************************************************************
771 void clear()
772 {
773 TAccess::lock();
774
775 if ETL_IF_CONSTEXPR (etl::is_trivially_destructible<T>::value)
776 {
777 this->write_index = 0;
778 this->read_index = 0;
779 this->current_size = 0;
780 }
781 else
782 {
783 while (pop())
784 {
785 // Do nothing.
786 }
787 }
788
789 TAccess::unlock();
790 }
791
792 //*************************************************************************
794 //*************************************************************************
795 bool empty() const
796 {
797 TAccess::lock();
798
799 bool result = (this->current_size == 0);
800
801 TAccess::unlock();
802
803 return result;
804 }
805
806 //*************************************************************************
808 //*************************************************************************
809 bool full() const
810 {
811 TAccess::lock();
812
813 bool result = (this->current_size == this->MAX_SIZE);
814
815 TAccess::unlock();
816
817 return result;
818 }
819
820 //*************************************************************************
822 //*************************************************************************
824 {
825 TAccess::lock();
826
827 size_type result = this->current_size;
828
829 TAccess::unlock();
830
831 return result;
832 }
833
834 //*************************************************************************
836 //*************************************************************************
838 {
839 TAccess::lock();
840
841 size_type result = this->MAX_SIZE - this->current_size;
842
843 TAccess::unlock();
844
845 return result;
846 }
847
848 protected:
849
850 //*************************************************************************
852 //*************************************************************************
853 iqueue_spsc_isr(T* p_buffer_, size_type max_size_)
854 : base_t(p_buffer_, max_size_)
855 {
856 }
857
858 private:
859
860 // Disable copy construction and assignment.
861 iqueue_spsc_isr(const iqueue_spsc_isr&) ETL_DELETE;
862 iqueue_spsc_isr& operator=(const iqueue_spsc_isr&) ETL_DELETE;
863
864#if ETL_USING_CPP11
866 iqueue_spsc_isr& operator=(iqueue_spsc_isr&&) = delete;
867#endif
868
869 TAccess access;
870 };
871
872 //***************************************************************************
881 //***************************************************************************
882 template <typename T, size_t SIZE, typename TAccess, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
883 class queue_spsc_isr : public etl::iqueue_spsc_isr<T, TAccess, MEMORY_MODEL>
884 {
885 private:
886
888
889 public:
890
891 typedef typename base_t::size_type size_type;
892
893 ETL_STATIC_ASSERT((SIZE <= etl::integral_limits<size_type>::max), "Size too large for memory model");
894
895 static ETL_CONSTANT size_type MAX_SIZE = size_type(SIZE);
896
897 //*************************************************************************
899 //*************************************************************************
901 : base_t(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE)
902 {
903 }
904
905 //*************************************************************************
907 //*************************************************************************
909 {
911 }
912
913 private:
914
915 queue_spsc_isr(const queue_spsc_isr&) ETL_DELETE;
916 queue_spsc_isr& operator=(const queue_spsc_isr&) ETL_DELETE;
917
918#if ETL_USING_CPP11
919 queue_spsc_isr(queue_spsc_isr&&) = delete;
920 queue_spsc_isr& operator=(queue_spsc_isr&&) = delete;
921#endif
922
924 typename etl::aligned_storage<sizeof(T), etl::alignment_of<T>::value>::type buffer[MAX_SIZE];
925 };
926
927 template <typename T, size_t SIZE, typename TAccess, const size_t MEMORY_MODEL>
929} // namespace etl
930
931#endif
This is the base for all queue_spsc_isrs that contain a particular type.
Definition queue_spsc_isr.h:534
bool emplace(const T1 &value1, const T2 &value2)
Definition queue_spsc_isr.h:636
base_t::size_type size_type
The type used for determining the size of the queue.
Definition queue_spsc_isr.h:547
size_type size() const
How many items in the queue?
Definition queue_spsc_isr.h:823
const_reference front() const
Definition queue_spsc_isr.h:744
base_t::const_reference const_reference
A const reference to the type used in the queue.
Definition queue_spsc_isr.h:543
bool pop()
Pop a value from the queue and discard.
Definition queue_spsc_isr.h:699
size_type available() const
How much free space available in the queue.
Definition queue_spsc_isr.h:837
reference front()
Definition queue_spsc_isr.h:715
bool full() const
Is the queue full?
Definition queue_spsc_isr.h:809
void clear()
Clear the queue.
Definition queue_spsc_isr.h:771
bool push(const_reference value)
Push a value to the queue.
Definition queue_spsc_isr.h:552
bool emplace(const T1 &value1, const T2 &value2, const T3 &value3)
Definition queue_spsc_isr.h:653
base_t::value_type value_type
The type stored in the queue.
Definition queue_spsc_isr.h:541
iqueue_spsc_isr(T *p_buffer_, size_type max_size_)
The constructor that is called from derived classes.
Definition queue_spsc_isr.h:853
bool pop(reference value)
Pop a value from the queue.
Definition queue_spsc_isr.h:685
bool emplace(const T1 &value1, const T2 &value2, const T3 &value3, const T4 &value4)
Definition queue_spsc_isr.h:670
base_t::reference reference
A reference to the type used in the queue.
Definition queue_spsc_isr.h:542
bool emplace(const T1 &value1)
Definition queue_spsc_isr.h:619
bool empty() const
Is the queue empty?
Definition queue_spsc_isr.h:795
bool emplace()
Definition queue_spsc_isr.h:602
Definition queue_spsc_isr.h:78
bool emplace_implementation()
Definition queue_spsc_isr.h:309
bool full_from_isr() const
Definition queue_spsc_isr.h:196
bool pop_implementation(reference value)
Pop a value from the queue.
Definition queue_spsc_isr.h:423
bool push_from_isr(const_reference value)
Push a value to the queue from an ISR.
Definition queue_spsc_isr.h:94
const_reference front_from_isr() const
Definition queue_spsc_isr.h:156
reference front_from_isr()
Definition queue_spsc_isr.h:144
bool emplace_implementation(const T1 &value1, const T2 &value2)
Definition queue_spsc_isr.h:355
T value_type
The type stored in the queue.
Definition queue_spsc_isr.h:84
bool emplace_implementation(const T1 &value1, const T2 &value2, const T3 &value3)
Definition queue_spsc_isr.h:378
size_type capacity() const
How many items can the queue hold.
Definition queue_spsc_isr.h:213
bool emplace_implementation(const T1 &value1)
Definition queue_spsc_isr.h:332
void clear_from_isr()
Clear the queue from the ISR.
Definition queue_spsc_isr.h:175
static size_type get_next_index(size_type index, size_type maximum)
Calculate the next index.
Definition queue_spsc_isr.h:485
size_type available_from_isr() const
Definition queue_spsc_isr.h:167
~queue_spsc_isr_base()
Destructor.
Definition queue_spsc_isr.h:517
etl::size_type_lookup< MEMORY_MODEL >::type size_type
The type used for determining the size of queue.
Definition queue_spsc_isr.h:82
size_type read_index
Where to get the oldest data.
Definition queue_spsc_isr.h:499
const_reference front_implementation() const
Peek a value at the front of the queue.
Definition queue_spsc_isr.h:457
bool emplace_implementation(const T1 &value1, const T2 &value2, const T3 &value3, const T4 &value4)
Definition queue_spsc_isr.h:401
size_type max_size() const
How many items can the queue hold.
Definition queue_spsc_isr.h:221
bool pop_from_isr()
Pop a value from the queue from an ISR, and discard.
Definition queue_spsc_isr.h:134
bool pop_implementation()
Pop a value from the queue and discard.
Definition queue_spsc_isr.h:465
bool pop_from_isr(reference value)
Pop a value from the queue from an ISR.
Definition queue_spsc_isr.h:126
size_type write_index
Where to input new data.
Definition queue_spsc_isr.h:498
const size_type MAX_SIZE
Definition queue_spsc_isr.h:501
bool empty_from_isr() const
Definition queue_spsc_isr.h:187
T * p_buffer
The internal buffer.
Definition queue_spsc_isr.h:497
size_type current_size
Definition queue_spsc_isr.h:500
T & reference
A reference to the type used in the queue.
Definition queue_spsc_isr.h:85
const T & const_reference
A const reference to the type used in the queue.
Definition queue_spsc_isr.h:86
size_type size_from_isr() const
Definition queue_spsc_isr.h:205
bool push_implementation(const_reference value)
Push a value to the queue.
Definition queue_spsc_isr.h:240
reference front_implementation()
Peek a value at the front of the queue.
Definition queue_spsc_isr.h:449
Definition queue_spsc_isr.h:884
queue_spsc_isr()
Default constructor.
Definition queue_spsc_isr.h:900
~queue_spsc_isr()
Destructor.
Definition queue_spsc_isr.h:908
Definition alignment.h:251
ETL_EXCEPTION_CONSTEXPR exception(string_type reason_, string_type, numeric_type)
Constructor.
Definition exception.h:81
Definition integral_limits.h:518
Definition queue_spsc_isr.h:67
bitset_ext
Definition absolute.h:40
Definition memory_model.h:50