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 "parameter_type.h"
39#include "placement_new.h"
40#include "utility.h"
41
42#include <stddef.h>
43
44namespace etl
45{
46 //***************************************************************************
49 //***************************************************************************
50 class queue_spsc_isr_exception : public exception
51 {
52 public:
53
54 queue_spsc_isr_exception(string_type reason_, string_type file_name_, numeric_type line_number_)
55 : exception(reason_, file_name_, line_number_)
56 {
57 }
58 };
59
60 //***************************************************************************
63 //***************************************************************************
64 class queue_spsc_isr_empty : public queue_spsc_isr_exception
65 {
66 public:
67
68 queue_spsc_isr_empty(string_type file_name_, numeric_type line_number_)
69 : queue_spsc_isr_exception(ETL_ERROR_TEXT("queue_spsc_isr:empty", ETL_QUEUE_SPSC_ISR_FILE_ID"A"), file_name_, line_number_)
70 {
71 }
72 };
73
74 template <typename T, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
75 class queue_spsc_isr_base
76 {
77 public:
78
81
82 typedef T value_type;
83 typedef T& reference;
84 typedef const T& const_reference;
85#if ETL_USING_CPP11
86 typedef T&& rvalue_reference;
87#endif
88
89 //*************************************************************************
91 //*************************************************************************
93 {
94 return push_implementation(value);
95 }
96
97#if ETL_USING_CPP11
98 //*************************************************************************
100 //*************************************************************************
101 bool push_from_isr(rvalue_reference value)
102 {
103 return push_implementation(etl::move(value));
104 }
105#endif
106
107 //*************************************************************************
112 //*************************************************************************
113#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_ISR_FORCE_CPP03_IMPLEMENTATION)
114 template <typename... Args>
115 bool emplace_from_isr(Args&&... args)
116 {
117 return emplace_implementation(etl::forward<Args>(args)...);
118 }
119#endif
120
121 //*************************************************************************
123 //*************************************************************************
125 {
126 return pop_implementation(value);
127 }
128
129 //*************************************************************************
131 //*************************************************************************
133 {
134 return pop_implementation();
135 }
136
137 //*************************************************************************
141 //*************************************************************************
143 {
144 ETL_ASSERT_CHECK_EXTRA(!empty_from_isr(), ETL_ERROR(queue_spsc_isr_empty));
145
146 return front_implementation();
147 }
148
149 //*************************************************************************
153 //*************************************************************************
155 {
156 ETL_ASSERT_CHECK_EXTRA(!empty_from_isr(), ETL_ERROR(queue_spsc_isr_empty));
157
158 return front_implementation();
159 }
160
161 //*************************************************************************
164 //*************************************************************************
166 {
167 return MAX_SIZE - current_size;
168 }
169
170 //*************************************************************************
172 //*************************************************************************
174 {
175 while (pop_implementation())
176 {
177 // Do nothing.
178 }
179 }
180
181 //*************************************************************************
184 //*************************************************************************
185 bool empty_from_isr() const
186 {
187 return (current_size == 0);
188 }
189
190 //*************************************************************************
193 //*************************************************************************
194 bool full_from_isr() const
195 {
196 return (current_size == MAX_SIZE);
197 }
198
199 //*************************************************************************
202 //*************************************************************************
204 {
205 return current_size;
206 }
207
208 //*************************************************************************
210 //*************************************************************************
212 {
213 return MAX_SIZE;
214 }
215
216 //*************************************************************************
218 //*************************************************************************
220 {
221 return MAX_SIZE;
222 }
223
224 protected:
225
226 queue_spsc_isr_base(T* p_buffer_, size_type max_size_)
227 : p_buffer(p_buffer_)
228 , write_index(0)
229 , read_index(0)
230 , current_size(0)
231 , MAX_SIZE(max_size_)
232 {
233 }
234
235 //*************************************************************************
237 //*************************************************************************
239 {
240 if (current_size != MAX_SIZE)
241 {
242 ::new (&p_buffer[write_index]) T(value);
243
245
246 ++current_size;
247
248 return true;
249 }
250
251 // Queue is full.
252 return false;
253 }
254
255#if ETL_USING_CPP11
256 //*************************************************************************
258 //*************************************************************************
259 bool push_implementation(rvalue_reference value)
260 {
261 if (current_size != MAX_SIZE)
262 {
263 ::new (&p_buffer[write_index]) T(etl::move(value));
264
266
267 ++current_size;
268
269 return true;
270 }
271
272 // Queue is full.
273 return false;
274 }
275#endif
276
277#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_ISR_FORCE_CPP03_IMPLEMENTATION)
278 //*************************************************************************
283 //*************************************************************************
284 template <typename... Args>
285 bool emplace_implementation(Args&&... args)
286 {
287 if (current_size != MAX_SIZE)
288 {
289 ::new (&p_buffer[write_index]) T(etl::forward<Args>(args)...);
290
292
293 ++current_size;
294
295 return true;
296 }
297
298 // Queue is full.
299 return false;
300 }
301#else
302 //*************************************************************************
306 //*************************************************************************
308 {
309 if (current_size != MAX_SIZE)
310 {
311 ::new (&p_buffer[write_index]) T();
312
314
315 ++current_size;
316
317 return true;
318 }
319
320 // Queue is full.
321 return false;
322 }
323
324 //*************************************************************************
328 //*************************************************************************
329 template <typename T1>
330 bool emplace_implementation(const T1& value1)
331 {
332 if (current_size != MAX_SIZE)
333 {
334 ::new (&p_buffer[write_index]) T(value1);
335
337
338 ++current_size;
339
340 return true;
341 }
342
343 // Queue is full.
344 return false;
345 }
346
347 //*************************************************************************
351 //*************************************************************************
352 template <typename T1, typename T2>
353 bool emplace_implementation(const T1& value1, const T2& value2)
354 {
355 if (current_size != MAX_SIZE)
356 {
357 ::new (&p_buffer[write_index]) T(value1, value2);
358
360
361 ++current_size;
362
363 return true;
364 }
365
366 // Queue is full.
367 return false;
368 }
369
370 //*************************************************************************
374 //*************************************************************************
375 template <typename T1, typename T2, typename T3>
376 bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3)
377 {
378 if (current_size != MAX_SIZE)
379 {
380 ::new (&p_buffer[write_index]) T(value1, value2, value3);
381
383
384 ++current_size;
385
386 return true;
387 }
388
389 // Queue is full.
390 return false;
391 }
392
393 //*************************************************************************
397 //*************************************************************************
398 template <typename T1, typename T2, typename T3, typename T4>
399 bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
400 {
401 if (current_size != MAX_SIZE)
402 {
403 ::new (&p_buffer[write_index]) T(value1, value2, value3, value4);
404
406
407 ++current_size;
408
409 return true;
410 }
411
412 // Queue is full.
413 return false;
414 }
415
416#endif
417
418 //*************************************************************************
420 //*************************************************************************
422 {
423 if (current_size == 0)
424 {
425 // Queue is empty
426 return false;
427 }
428
429#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_LOCKABLE_FORCE_CPP03_IMPLEMENTATION)
430 value = etl::move(p_buffer[read_index]);
431#else
432 value = p_buffer[read_index];
433#endif
434
435 p_buffer[read_index].~T();
436
438
439 --current_size;
440
441 return true;
442 }
443
444 //*************************************************************************
446 //*************************************************************************
451
452 //*************************************************************************
454 //*************************************************************************
456 {
457 return p_buffer[read_index];
458 }
459
460 //*************************************************************************
462 //*************************************************************************
464 {
465 if (current_size == 0)
466 {
467 // Queue is empty
468 return false;
469 }
470
471 p_buffer[read_index].~T();
472
474
475 --current_size;
476
477 return true;
478 }
479
480 //*************************************************************************
482 //*************************************************************************
484 {
485 ++index;
486
487 if (index == maximum) ETL_UNLIKELY
488 {
489 index = 0;
490 }
491
492 return index;
493 }
494
500
501 private:
502
503 //*************************************************************************
505 //*************************************************************************
506#if defined(ETL_POLYMORPHIC_SPSC_QUEUE_ISR) || defined(ETL_POLYMORPHIC_CONTAINERS)
507
508 public:
509
510 virtual ~queue_spsc_isr_base() {}
511#else
512
513 protected:
514
516#endif
517 };
518
519 //***************************************************************************
529 //***************************************************************************
530 template <typename T, typename TAccess, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
531 class iqueue_spsc_isr : public queue_spsc_isr_base<T, MEMORY_MODEL>
532 {
533 private:
534
535 typedef queue_spsc_isr_base<T, MEMORY_MODEL> base_t;
536
537 public:
538
540 typedef typename base_t::reference reference;
542#if ETL_USING_CPP11
543 typedef typename base_t::rvalue_reference rvalue_reference;
544#endif
545 typedef typename base_t::size_type size_type;
546
547 //*************************************************************************
549 //*************************************************************************
551 {
552 TAccess::lock();
553
554 bool result = this->push_implementation(value);
555
556 TAccess::unlock();
557
558 return result;
559 }
560
561#if ETL_USING_CPP11
562 //*************************************************************************
564 //*************************************************************************
565 bool push(rvalue_reference value)
566 {
567 TAccess::lock();
568
569 bool result = this->push_implementation(etl::move(value));
570
571 TAccess::unlock();
572
573 return result;
574 }
575#endif
576
577 //*************************************************************************
581 //*************************************************************************
582#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_ISR_FORCE_CPP03_IMPLEMENTATION)
583 template <typename... Args>
584 bool emplace(Args&&... args)
585 {
586 TAccess::lock();
587
588 bool result = this->emplace_implementation(etl::forward<Args>(args)...);
589
590 TAccess::unlock();
591
592 return result;
593 }
594#else
595 //*************************************************************************
599 //*************************************************************************
600 bool emplace()
601 {
602 TAccess::lock();
603
604 bool result = this->emplace_implementation();
605
606 TAccess::unlock();
607
608 return result;
609 }
610
611 //*************************************************************************
615 //*************************************************************************
616 template <typename T1>
617 bool emplace(const T1& value1)
618 {
619 TAccess::lock();
620
621 bool result = this->emplace_implementation(value1);
622
623 TAccess::unlock();
624
625 return result;
626 }
627
628 //*************************************************************************
632 //*************************************************************************
633 template <typename T1, typename T2>
634 bool emplace(const T1& value1, const T2& value2)
635 {
636 TAccess::lock();
637
638 bool result = this->emplace_implementation(value1, value2);
639
640 TAccess::unlock();
641
642 return result;
643 }
644
645 //*************************************************************************
649 //*************************************************************************
650 template <typename T1, typename T2, typename T3>
651 bool emplace(const T1& value1, const T2& value2, const T3& value3)
652 {
653 TAccess::lock();
654
655 bool result = this->emplace_implementation(value1, value2, value3);
656
657 TAccess::unlock();
658
659 return result;
660 }
661
662 //*************************************************************************
666 //*************************************************************************
667 template <typename T1, typename T2, typename T3, typename T4>
668 bool emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
669 {
670 TAccess::lock();
671
672 bool result = this->emplace_implementation(value1, value2, value3, value4);
673
674 TAccess::unlock();
675
676 return result;
677 }
678#endif
679
680 //*************************************************************************
682 //*************************************************************************
683 bool pop(reference value)
684 {
685 TAccess::lock();
686
687 bool result = this->pop_implementation(value);
688
689 TAccess::unlock();
690
691 return result;
692 }
693
694 //*************************************************************************
696 //*************************************************************************
697 bool pop()
698 {
699 TAccess::lock();
700
701 bool result = this->pop_implementation();
702
703 TAccess::unlock();
704
705 return result;
706 }
707
708 //*************************************************************************
712 //*************************************************************************
714 {
715#if ETL_CHECKING_EXTRA
716 TAccess::lock();
717 if (!this->empty_from_isr())
718 {
719 reference inner_result = this->front_implementation();
720 TAccess::unlock();
721 return inner_result;
722 }
723 else
724 {
725 TAccess::unlock();
726 ETL_ASSERT_FAIL(ETL_ERROR(queue_spsc_isr_empty));
727 // fall through to return something to satisfy the compiler, even
728 // though this should never be reached due to undefined behaviour.
729 }
730#endif
731 TAccess::lock();
732 reference result = this->front_implementation();
733 TAccess::unlock();
734 return result;
735 }
736
737 //*************************************************************************
741 //*************************************************************************
743 {
744#if ETL_CHECKING_EXTRA
745 TAccess::lock();
746 if (!this->empty_from_isr())
747 {
748 const_reference inner_result = this->front_implementation();
749 TAccess::unlock();
750 return inner_result;
751 }
752 else
753 {
754 TAccess::unlock();
755 ETL_ASSERT_FAIL(ETL_ERROR(queue_spsc_isr_empty));
756 // fall through to return something to satisfy the compiler, even
757 // though this should never be reached due to undefined behaviour.
758 }
759#endif
760 TAccess::lock();
761 const_reference result = this->front_implementation();
762 TAccess::unlock();
763 return result;
764 }
765
766 //*************************************************************************
768 //*************************************************************************
769 void clear()
770 {
771 TAccess::lock();
772
773 if ETL_IF_CONSTEXPR (etl::is_trivially_destructible<T>::value)
774 {
775 this->write_index = 0;
776 this->read_index = 0;
777 this->current_size = 0;
778 }
779 else
780 {
781 while (pop())
782 {
783 // Do nothing.
784 }
785 }
786
787 TAccess::unlock();
788 }
789
790 //*************************************************************************
792 //*************************************************************************
793 bool empty() const
794 {
795 TAccess::lock();
796
797 bool result = (this->current_size == 0);
798
799 TAccess::unlock();
800
801 return result;
802 }
803
804 //*************************************************************************
806 //*************************************************************************
807 bool full() const
808 {
809 TAccess::lock();
810
811 bool result = (this->current_size == this->MAX_SIZE);
812
813 TAccess::unlock();
814
815 return result;
816 }
817
818 //*************************************************************************
820 //*************************************************************************
822 {
823 TAccess::lock();
824
825 size_type result = this->current_size;
826
827 TAccess::unlock();
828
829 return result;
830 }
831
832 //*************************************************************************
834 //*************************************************************************
836 {
837 TAccess::lock();
838
839 size_type result = this->MAX_SIZE - this->current_size;
840
841 TAccess::unlock();
842
843 return result;
844 }
845
846 protected:
847
848 //*************************************************************************
850 //*************************************************************************
851 iqueue_spsc_isr(T* p_buffer_, size_type max_size_)
852 : base_t(p_buffer_, max_size_)
853 {
854 }
855
856 private:
857
858 // Disable copy construction and assignment.
859 iqueue_spsc_isr(const iqueue_spsc_isr&) ETL_DELETE;
860 iqueue_spsc_isr& operator=(const iqueue_spsc_isr&) ETL_DELETE;
861
862#if ETL_USING_CPP11
864 iqueue_spsc_isr& operator=(iqueue_spsc_isr&&) = delete;
865#endif
866
867 TAccess access;
868 };
869
870 //***************************************************************************
879 //***************************************************************************
880 template <typename T, size_t SIZE, typename TAccess, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
881 class queue_spsc_isr : public etl::iqueue_spsc_isr<T, TAccess, MEMORY_MODEL>
882 {
883 private:
884
886
887 public:
888
889 typedef typename base_t::size_type size_type;
890
891 ETL_STATIC_ASSERT((SIZE <= etl::integral_limits<size_type>::max), "Size too large for memory model");
892
893 static ETL_CONSTANT size_type MAX_SIZE = size_type(SIZE);
894
895 //*************************************************************************
897 //*************************************************************************
899 : base_t(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE)
900 {
901 }
902
903 //*************************************************************************
905 //*************************************************************************
907 {
909 }
910
911 private:
912
913 queue_spsc_isr(const queue_spsc_isr&) ETL_DELETE;
914 queue_spsc_isr& operator=(const queue_spsc_isr&) ETL_DELETE;
915
916#if ETL_USING_CPP11
917 queue_spsc_isr(queue_spsc_isr&&) = delete;
918 queue_spsc_isr& operator=(queue_spsc_isr&&) = delete;
919#endif
920
922 typename etl::aligned_storage<sizeof(T), etl::alignment_of<T>::value>::type buffer[MAX_SIZE];
923 };
924
925 template <typename T, size_t SIZE, typename TAccess, const size_t MEMORY_MODEL>
927} // namespace etl
928
929#endif
This is the base for all queue_spsc_isrs that contain a particular type.
Definition queue_spsc_isr.h:532
bool emplace(const T1 &value1, const T2 &value2)
Definition queue_spsc_isr.h:634
base_t::size_type size_type
The type used for determining the size of the queue.
Definition queue_spsc_isr.h:545
size_type size() const
How many items in the queue?
Definition queue_spsc_isr.h:821
const_reference front() const
Definition queue_spsc_isr.h:742
base_t::const_reference const_reference
A const reference to the type used in the queue.
Definition queue_spsc_isr.h:541
bool pop()
Pop a value from the queue and discard.
Definition queue_spsc_isr.h:697
size_type available() const
How much free space available in the queue.
Definition queue_spsc_isr.h:835
reference front()
Definition queue_spsc_isr.h:713
bool full() const
Is the queue full?
Definition queue_spsc_isr.h:807
void clear()
Clear the queue.
Definition queue_spsc_isr.h:769
bool push(const_reference value)
Push a value to the queue.
Definition queue_spsc_isr.h:550
bool emplace(const T1 &value1, const T2 &value2, const T3 &value3)
Definition queue_spsc_isr.h:651
base_t::value_type value_type
The type stored in the queue.
Definition queue_spsc_isr.h:539
iqueue_spsc_isr(T *p_buffer_, size_type max_size_)
The constructor that is called from derived classes.
Definition queue_spsc_isr.h:851
bool pop(reference value)
Pop a value from the queue.
Definition queue_spsc_isr.h:683
bool emplace(const T1 &value1, const T2 &value2, const T3 &value3, const T4 &value4)
Definition queue_spsc_isr.h:668
base_t::reference reference
A reference to the type used in the queue.
Definition queue_spsc_isr.h:540
bool emplace(const T1 &value1)
Definition queue_spsc_isr.h:617
bool empty() const
Is the queue empty?
Definition queue_spsc_isr.h:793
bool emplace()
Definition queue_spsc_isr.h:600
Definition queue_spsc_isr.h:76
bool emplace_implementation()
Definition queue_spsc_isr.h:307
bool full_from_isr() const
Definition queue_spsc_isr.h:194
bool pop_implementation(reference value)
Pop a value from the queue.
Definition queue_spsc_isr.h:421
bool push_from_isr(const_reference value)
Push a value to the queue from an ISR.
Definition queue_spsc_isr.h:92
const_reference front_from_isr() const
Definition queue_spsc_isr.h:154
reference front_from_isr()
Definition queue_spsc_isr.h:142
bool emplace_implementation(const T1 &value1, const T2 &value2)
Definition queue_spsc_isr.h:353
T value_type
The type stored in the queue.
Definition queue_spsc_isr.h:82
bool emplace_implementation(const T1 &value1, const T2 &value2, const T3 &value3)
Definition queue_spsc_isr.h:376
size_type capacity() const
How many items can the queue hold.
Definition queue_spsc_isr.h:211
bool emplace_implementation(const T1 &value1)
Definition queue_spsc_isr.h:330
void clear_from_isr()
Clear the queue from the ISR.
Definition queue_spsc_isr.h:173
static size_type get_next_index(size_type index, size_type maximum)
Calculate the next index.
Definition queue_spsc_isr.h:483
size_type available_from_isr() const
Definition queue_spsc_isr.h:165
~queue_spsc_isr_base()
Destructor.
Definition queue_spsc_isr.h:515
etl::size_type_lookup< MEMORY_MODEL >::type size_type
The type used for determining the size of queue.
Definition queue_spsc_isr.h:80
size_type read_index
Where to get the oldest data.
Definition queue_spsc_isr.h:497
const_reference front_implementation() const
Peek a value at the front of the queue.
Definition queue_spsc_isr.h:455
bool emplace_implementation(const T1 &value1, const T2 &value2, const T3 &value3, const T4 &value4)
Definition queue_spsc_isr.h:399
size_type max_size() const
How many items can the queue hold.
Definition queue_spsc_isr.h:219
bool pop_from_isr()
Pop a value from the queue from an ISR, and discard.
Definition queue_spsc_isr.h:132
bool pop_implementation()
Pop a value from the queue and discard.
Definition queue_spsc_isr.h:463
bool pop_from_isr(reference value)
Pop a value from the queue from an ISR.
Definition queue_spsc_isr.h:124
size_type write_index
Where to input new data.
Definition queue_spsc_isr.h:496
const size_type MAX_SIZE
Definition queue_spsc_isr.h:499
bool empty_from_isr() const
Definition queue_spsc_isr.h:185
T * p_buffer
The internal buffer.
Definition queue_spsc_isr.h:495
size_type current_size
Definition queue_spsc_isr.h:498
T & reference
A reference to the type used in the queue.
Definition queue_spsc_isr.h:83
const T & const_reference
A const reference to the type used in the queue.
Definition queue_spsc_isr.h:84
size_type size_from_isr() const
Definition queue_spsc_isr.h:203
bool push_implementation(const_reference value)
Push a value to the queue.
Definition queue_spsc_isr.h:238
reference front_implementation()
Peek a value at the front of the queue.
Definition queue_spsc_isr.h:447
Definition queue_spsc_isr.h:882
queue_spsc_isr()
Default constructor.
Definition queue_spsc_isr.h:898
~queue_spsc_isr()
Destructor.
Definition queue_spsc_isr.h:906
Definition alignment.h:251
ETL_EXCEPTION_CONSTEXPR exception(string_type reason_, string_type, numeric_type)
Constructor.
Definition exception.h:81
Definition integral_limits.h:517
Definition queue_spsc_isr.h:65
Definition absolute.h:40
Definition memory_model.h:50