Embedded Template Library 1.0
Loading...
Searching...
No Matches
queue_spsc_locked.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) 2019 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_LOCKED_INCLUDED
32#define ETL_SPSC_QUEUE_LOCKED_INCLUDED
33
34#include "platform.h"
35#include "memory.h"
36#include "parameter_type.h"
37#include "memory_model.h"
38#include "integral_limits.h"
39#include "function.h"
40#include "utility.h"
41#include "placement_new.h"
42
43#include <stddef.h>
44#include <stdint.h>
45
46namespace etl
47{
48 template <size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
50 {
51 public:
52
55
56 //*************************************************************************
58 //*************************************************************************
63
64 //*************************************************************************
66 //*************************************************************************
67 bool full_from_unlocked() const
68 {
69 return full_implementation();
70 }
71
72 //*************************************************************************
74 //*************************************************************************
76 {
77 return size_implementation();
78 }
79
80 //*************************************************************************
82 //*************************************************************************
84 {
85 return empty_implementation();
86 }
87
88 //*************************************************************************
90 //*************************************************************************
92 {
93 return MAX_SIZE;
94 }
95
96 //*************************************************************************
98 //*************************************************************************
100 {
101 return MAX_SIZE;
102 }
103
104 protected:
105
107 : write_index(0),
108 read_index(0),
109 current_size(0),
111 {
112 }
113
114 //*************************************************************************
116 //*************************************************************************
118 {
119 ++index;
120
121 if (index == maximum) ETL_UNLIKELY
122 {
123 index = 0;
124 }
125
126 return index;
127 }
128
133
134 protected:
135
136 //*************************************************************************
138 //*************************************************************************
140 {
141 return MAX_SIZE - current_size;
142 }
143
144 //*************************************************************************
146 //*************************************************************************
148 {
149 return (current_size == MAX_SIZE);
150 }
151
152 //*************************************************************************
154 //*************************************************************************
156 {
157 return current_size;
158 }
159
160 //*************************************************************************
162 //*************************************************************************
164 {
165 return (current_size == 0);
166 }
167
168 //*************************************************************************
170 //*************************************************************************
171#if defined(ETL_POLYMORPHIC_SPSC_QUEUE_ISR) || defined(ETL_POLYMORPHIC_CONTAINERS)
172 public:
174 {
175 }
176#else
177 protected:
181#endif
182 };
183
184 //***************************************************************************
190 //***************************************************************************
191 template <typename T, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
192 class iqueue_spsc_locked : public iqueue_spsc_locked_base<MEMORY_MODEL>
193 {
194 private:
195
197
198 public:
199
200 typedef T value_type;
201 typedef T& reference;
202 typedef const T& const_reference;
203#if ETL_USING_CPP11
204 typedef T&& rvalue_reference;
205#endif
206 typedef typename base_t::size_type size_type;
207
208 //*************************************************************************
210 //*************************************************************************
212 {
213 return push_implementation(value);
214 }
215
216 //*************************************************************************
218 //*************************************************************************
220 {
221 lock();
222
223 bool result = push_implementation(value);
224
225 unlock();
226
227 return result;
228 }
229
230#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_LOCKED_FORCE_CPP03_IMPLEMENTATION)
231 //*************************************************************************
234 //*************************************************************************
236 {
237 return push_implementation(etl::move(value));
238 }
239
240 //*************************************************************************
243 //*************************************************************************
244 bool push(rvalue_reference value)
245 {
246 lock();
247
248 bool result = push_implementation(etl::move(value));
249
250 unlock();
251
252 return result;
253 }
254#endif
255
256#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_LOCKED_FORCE_CPP03_IMPLEMENTATION)
257 //*************************************************************************
260 //*************************************************************************
261 template <typename ... Args>
262 bool emplace_from_unlocked(Args&&... args)
263 {
264 return emplace_implementation(etl::forward<Args>(args)...);
265 }
266
267 //*************************************************************************
270 //*************************************************************************
271 template <typename ... Args>
272 bool emplace(Args&&... args)
273 {
274 lock();
275
276 bool result = emplace_implementation(etl::forward<Args>(args)...);
277
278 unlock();
279
280 return result;
281 }
282#else
283 //*************************************************************************
286 //*************************************************************************
287 template <typename T1>
288 bool emplace_from_unlocked(const T1& value1)
289 {
290 return emplace_implementation(value1);
291 }
292
293 //*************************************************************************
296 //*************************************************************************
297 template <typename T1, typename T2>
298 bool emplace_from_unlocked(const T1& value1, const T2& value2)
299 {
300 return emplace_implementation(value1, value2);
301 }
302
303 //*************************************************************************
306 //*************************************************************************
307 template <typename T1, typename T2, typename T3>
308 bool emplace_from_unlocked(const T1& value1, const T2& value2, const T3& value3)
309 {
310 return emplace_implementation(value1, value2, value3);
311 }
312
313 //*************************************************************************
316 //*************************************************************************
317 template <typename T1, typename T2, typename T3, typename T4>
318 bool emplace_from_unlocked(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
319 {
320 return emplace_implementation(value1, value2, value3, value4);
321 }
322
323 //*************************************************************************
326 //*************************************************************************
327 bool emplace()
328 {
329 lock();
330
331 bool result = emplace_implementation();
332
333 unlock();
334
335 return result;
336 }
337
338 //*************************************************************************
341 //*************************************************************************
342 template <typename T1>
343 bool emplace(const T1& value1)
344 {
345 lock();
346
347 bool result = emplace_implementation(value1);
348
349 unlock();
350
351 return result;
352 }
353
354 //*************************************************************************
357 //*************************************************************************
358 template <typename T1, typename T2>
359 bool emplace(const T1& value1, const T2& value2)
360 {
361 lock();
362
363 bool result = emplace_implementation(value1, value2);
364
365 unlock();
366
367 return result;
368 }
369
370 //*************************************************************************
373 //*************************************************************************
374 template <typename T1, typename T2, typename T3>
375 bool emplace(const T1& value1, const T2& value2, const T3& value3)
376 {
377 lock();
378
379 bool result = emplace_implementation(value1, value2, value3);
380
381 unlock();
382
383 return result;
384 }
385
386 //*************************************************************************
389 //*************************************************************************
390 template <typename T1, typename T2, typename T3, typename T4>
391 bool emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
392 {
393 lock();
394
395 bool result = emplace_implementation(value1, value2, value3, value4);
396
397 unlock();
398
399 return result;
400 }
401#endif
402
403 //*************************************************************************
406 //*************************************************************************
408 {
409 return pop_implementation(value);;
410 }
411
412 //*************************************************************************
414 //*************************************************************************
415 bool pop(reference value)
416 {
417 lock();
418
419 bool result = pop_implementation(value);
420
421 unlock();
422
423 return result;
424 }
425
426 //*************************************************************************
429 //*************************************************************************
431 {
432 return pop_implementation();
433 }
434
435 //*************************************************************************
437 //*************************************************************************
438 bool pop()
439 {
440 lock();
441
442 bool result = pop_implementation();
443
444 unlock();
445
446 return result;
447 }
448
449 //*************************************************************************
452 //*************************************************************************
454 {
455 return front_implementation();
456 }
457
458 //*************************************************************************
461 //*************************************************************************
463 {
464 return front_implementation();
465 }
466
467 //*************************************************************************
469 //*************************************************************************
471 {
472 lock();
473
474 reference result = front_implementation();
475
476 unlock();
477
478 return result;
479 }
480
481 //*************************************************************************
483 //*************************************************************************
485 {
486 lock();
487
488 const_reference result = front_implementation();
489
490 unlock();
491
492 return result;
493 }
494
495 //*************************************************************************
497 //*************************************************************************
499 {
500 while (pop_implementation())
501 {
502 // Do nothing.
503 }
504 }
505
506 //*************************************************************************
508 //*************************************************************************
509 void clear()
510 {
511 lock();
512
513 while (pop_implementation())
514 {
515 // Do nothing.
516 }
517
518 unlock();
519 }
520
521 //*************************************************************************
523 //*************************************************************************
525 {
526 lock();
527
528 size_type result = this->available_implementation();
529
530 unlock();
531
532 return result;
533 }
534
535 //*************************************************************************
537 //*************************************************************************
538 bool full() const
539 {
540 lock();
541
542 size_type result = this->full_implementation();
543
544 unlock();
545
546 return result;
547 }
548
549 //*************************************************************************
551 //*************************************************************************
553 {
554 lock();
555
556 size_type result = this->size_implementation();
557
558 unlock();
559
560 return result;
561 }
562
563 //*************************************************************************
565 //*************************************************************************
566 bool empty() const
567 {
568 lock();
569
570 bool result = this->empty_implementation();
571
572 unlock();
573
574 return result;
575 }
576
577 protected:
578
579 //*************************************************************************
581 //*************************************************************************
584 , p_buffer(p_buffer_)
585 , lock(lock_)
586 , unlock(unlock_)
587 {
588 }
589
590 private:
591
592 //*************************************************************************
594 //*************************************************************************
595 bool push_implementation(const_reference value)
596 {
597 if (this->current_size != this->MAX_SIZE)
598 {
599 ::new (&p_buffer[this->write_index]) T(value);
600
601 this->write_index = this->get_next_index(this->write_index, this->MAX_SIZE);
602
603 ++this->current_size;
604
605 return true;
606 }
607
608 // Queue is full.
609 return false;
610 }
611
612#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_LOCKED_FORCE_CPP03_IMPLEMENTATION)
613 //*************************************************************************
616 //*************************************************************************
617 bool push_implementation(rvalue_reference value)
618 {
619 if (this->current_size != this->MAX_SIZE)
620 {
621 ::new (&p_buffer[this->write_index]) T(etl::move(value));
622
623 this->write_index = this->get_next_index(this->write_index, this->MAX_SIZE);
624
625 ++this->current_size;
626
627 return true;
628 }
629
630 // Queue is full.
631 return false;
632 }
633#endif
634
635#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_LOCKED_FORCE_CPP03_IMPLEMENTATION)
636 //*************************************************************************
639 //*************************************************************************
640 template <typename ... Args>
641 bool emplace_implementation(Args&&... args)
642 {
643 if (this->current_size != this->MAX_SIZE)
644 {
645 ::new (&p_buffer[this->write_index]) T(etl::forward<Args>(args)...);
646
647 this->write_index = this->get_next_index(this->write_index, this->MAX_SIZE);
648
649 ++this->current_size;
650
651 return true;
652 }
653
654 // Queue is full.
655 return false;
656 }
657#else
658 //*************************************************************************
660 //*************************************************************************
661 bool emplace_implementation()
662 {
663 if (this->current_size != this->MAX_SIZE)
664 {
665 ::new (&p_buffer[this->write_index]) T();
666
667 this->write_index = this->get_next_index(this->write_index, this->MAX_SIZE);
668
669 ++this->current_size;
670
671 return true;
672 }
673
674 // Queue is full.
675 return false;
676 }
677
678 //*************************************************************************
680 //*************************************************************************
681 template <typename T1>
682 bool emplace_implementation(const T1& value1)
683 {
684 if (this->current_size != this->MAX_SIZE)
685 {
686 ::new (&p_buffer[this->write_index]) T(value1);
687
688 this->write_index = this->get_next_index(this->write_index, this->MAX_SIZE);
689
690 ++this->current_size;
691
692 return true;
693 }
694
695 // Queue is full.
696 return false;
697 }
698
699 //*************************************************************************
701 //*************************************************************************
702 template <typename T1, typename T2>
703 bool emplace_implementation(const T1& value1, const T2& value2)
704 {
705 if (this->current_size != this->MAX_SIZE)
706 {
707 ::new (&p_buffer[this->write_index]) T(value1, value2);
708
709 this->write_index = this->get_next_index(this->write_index, this->MAX_SIZE);
710
711 ++this->current_size;
712
713 return true;
714 }
715
716 // Queue is full.
717 return false;
718 }
719
720 //*************************************************************************
722 //*************************************************************************
723 template <typename T1, typename T2, typename T3>
724 bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3)
725 {
726 if (this->current_size != this->MAX_SIZE)
727 {
728 ::new (&p_buffer[this->write_index]) T(value1, value2, value3);
729
730 this->write_index = this->get_next_index(this->write_index, this->MAX_SIZE);
731
732 ++this->current_size;
733
734 return true;
735 }
736
737 // Queue is full.
738 return false;
739 }
740
741 //*************************************************************************
743 //*************************************************************************
744 template <typename T1, typename T2, typename T3, typename T4>
745 bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
746 {
747 if (this->current_size != this->MAX_SIZE)
748 {
749 ::new (&p_buffer[this->write_index]) T(value1, value2, value3, value4);
750
751 this->write_index = this->get_next_index(this->write_index, this->MAX_SIZE);
752
753 ++this->current_size;
754
755 return true;
756 }
757
758 // Queue is full.
759 return false;
760 }
761#endif
762
763 //*************************************************************************
766 //*************************************************************************
767 bool pop_implementation(reference value)
768 {
769 if (this->current_size == 0)
770 {
771 // Queue is empty
772 return false;
773 }
774
775#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_LOCKABLE_FORCE_CPP03_IMPLEMENTATION)
776 value = etl::move(p_buffer[this->read_index]);
777#else
778 value = p_buffer[this->read_index];
779#endif
780
781 p_buffer[this->read_index].~T();
782
783 this->read_index = this->get_next_index(this->read_index, this->MAX_SIZE);
784
785 --this->current_size;
786
787 return true;
788 }
789
790 //*************************************************************************
793 //*************************************************************************
794 reference front_implementation()
795 {
796 return p_buffer[this->read_index];
797 }
798
799 //*************************************************************************
802 //*************************************************************************
803 const_reference front_implementation() const
804 {
805 return p_buffer[this->read_index];
806 }
807
808 //*************************************************************************
811 //*************************************************************************
812 bool pop_implementation()
813 {
814 if (this->current_size == 0)
815 {
816 // Queue is empty
817 return false;
818 }
819
820 p_buffer[this->read_index].~T();
821
822 this->read_index = this->get_next_index(this->read_index, this->MAX_SIZE);
823
824 --this->current_size;
825
826 return true;
827 }
828
829 // Disable copy construction and assignment.
830 iqueue_spsc_locked(const iqueue_spsc_locked&) ETL_DELETE;
831 iqueue_spsc_locked& operator =(const iqueue_spsc_locked&) ETL_DELETE;
832
833#if ETL_USING_CPP11
834 iqueue_spsc_locked(iqueue_spsc_locked&&) = delete;
835 iqueue_spsc_locked& operator =(iqueue_spsc_locked&&) = delete;
836#endif
837
838 T* p_buffer;
839
840 const etl::ifunction<void>& lock;
841 const etl::ifunction<void>& unlock;
842 };
843
844 //***************************************************************************
851 //***************************************************************************
852 template <typename T, size_t SIZE, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
853 class queue_spsc_locked : public etl::iqueue_spsc_locked<T, MEMORY_MODEL>
854 {
855 private:
856
858
859 public:
860
861 typedef typename base_t::size_type size_type;
862
863 ETL_STATIC_ASSERT((SIZE <= etl::integral_limits<size_type>::max), "Size too large for memory model");
864
865 static ETL_CONSTANT size_type MAX_SIZE = size_type(SIZE);
866
867 //*************************************************************************
869 //*************************************************************************
870
873 : base_t(reinterpret_cast<T*>(buffer.raw), MAX_SIZE, lock_, unlock_)
874 {
875 }
876
877 //*************************************************************************
879 //*************************************************************************
881 {
882 base_t::clear();
883 }
884
885 private:
886
887 queue_spsc_locked(const queue_spsc_locked&) ETL_DELETE;
889
890#if ETL_USING_CPP11
893#endif
894
897 };
898
899 template <typename T, size_t SIZE, const size_t MEMORY_MODEL>
900 ETL_CONSTANT typename queue_spsc_locked<T, SIZE, MEMORY_MODEL>::size_type queue_spsc_locked<T, SIZE, MEMORY_MODEL>::MAX_SIZE;
901}
902
903#endif
Definition queue_spsc_locked.h:50
size_type available_from_unlocked() const
How much free space available in the queue.
Definition queue_spsc_locked.h:59
const size_type MAX_SIZE
The maximum number of items in the queue.
Definition queue_spsc_locked.h:132
bool empty_implementation() const
Is the queue empty?
Definition queue_spsc_locked.h:163
size_type available_implementation() const
How much free space available in the queue.
Definition queue_spsc_locked.h:139
bool full_from_unlocked() const
Is the queue full?
Definition queue_spsc_locked.h:67
bool empty_from_unlocked() const
Is the queue empty?
Definition queue_spsc_locked.h:83
size_type max_size() const
How many items can the queue hold.
Definition queue_spsc_locked.h:99
size_type size_from_unlocked() const
How many items in the queue?
Definition queue_spsc_locked.h:75
size_type current_size
The current size of the queue.
Definition queue_spsc_locked.h:131
size_type write_index
Where to input new data.
Definition queue_spsc_locked.h:129
bool full_implementation() const
Is the queue full?
Definition queue_spsc_locked.h:147
etl::size_type_lookup< MEMORY_MODEL >::type size_type
The type used for determining the size of queue.
Definition queue_spsc_locked.h:54
size_type capacity() const
How many items can the queue hold.
Definition queue_spsc_locked.h:91
~iqueue_spsc_locked_base()
Destructor.
Definition queue_spsc_locked.h:178
static size_type get_next_index(size_type index, size_type maximum)
Calculate the next index.
Definition queue_spsc_locked.h:117
size_type read_index
Where to get the oldest data.
Definition queue_spsc_locked.h:130
size_type size_implementation() const
How many items in the queue?
Definition queue_spsc_locked.h:155
This is the base for all queue_spsc_locked that contain a particular type.
Definition queue_spsc_locked.h:193
bool emplace(const T1 &value1, const T2 &value2, const T3 &value3, const T4 &value4)
Definition queue_spsc_locked.h:391
bool emplace(const T1 &value1)
Definition queue_spsc_locked.h:343
bool pop_from_unlocked()
Definition queue_spsc_locked.h:430
bool emplace_from_unlocked(const T1 &value1)
Definition queue_spsc_locked.h:288
reference front_from_unlocked()
Definition queue_spsc_locked.h:453
bool emplace(const T1 &value1, const T2 &value2, const T3 &value3)
Definition queue_spsc_locked.h:375
bool emplace(const T1 &value1, const T2 &value2)
Definition queue_spsc_locked.h:359
bool emplace_from_unlocked(const T1 &value1, const T2 &value2)
Definition queue_spsc_locked.h:298
iqueue_spsc_locked(T *p_buffer_, size_type max_size_, const etl::ifunction< void > &lock_, const etl::ifunction< void > &unlock_)
The constructor that is called from derived classes.
Definition queue_spsc_locked.h:582
T & reference
A reference to the type used in the queue.
Definition queue_spsc_locked.h:201
bool pop()
Pop a value from the queue and discard.
Definition queue_spsc_locked.h:438
bool pop(reference value)
Pop a value from the queue.
Definition queue_spsc_locked.h:415
void clear()
Clear the queue.
Definition queue_spsc_locked.h:509
bool emplace_from_unlocked(const T1 &value1, const T2 &value2, const T3 &value3)
Definition queue_spsc_locked.h:308
reference front()
Peek a value from the front of the queue.
Definition queue_spsc_locked.h:470
T value_type
The type stored in the queue.
Definition queue_spsc_locked.h:200
const T & const_reference
A const reference to the type used in the queue.
Definition queue_spsc_locked.h:202
const_reference front_from_unlocked() const
Definition queue_spsc_locked.h:462
bool empty() const
Is the queue empty?
Definition queue_spsc_locked.h:566
size_type size() const
How many items in the queue?
Definition queue_spsc_locked.h:552
bool push_from_unlocked(const_reference value)
Push a value to the queue.
Definition queue_spsc_locked.h:211
bool emplace()
Definition queue_spsc_locked.h:327
base_t::size_type size_type
The type used for determining the size of the queue.
Definition queue_spsc_locked.h:206
bool emplace_from_unlocked(const T1 &value1, const T2 &value2, const T3 &value3, const T4 &value4)
Definition queue_spsc_locked.h:318
const_reference front() const
Peek a value from the front of the queue.
Definition queue_spsc_locked.h:484
bool full() const
Is the queue full?
Definition queue_spsc_locked.h:538
void clear_from_unlocked()
Clear the queue from the ISR.
Definition queue_spsc_locked.h:498
bool push(const_reference value)
Push a value to the queue.
Definition queue_spsc_locked.h:219
size_type available() const
How much free space available in the queue.
Definition queue_spsc_locked.h:524
bool pop_from_unlocked(reference value)
Definition queue_spsc_locked.h:407
Definition queue_spsc_locked.h:854
queue_spsc_locked(const etl::ifunction< void > &lock_, const etl::ifunction< void > &unlock_)
Default constructor.
Definition queue_spsc_locked.h:871
~queue_spsc_locked()
Destructor.
Definition queue_spsc_locked.h:880
Definition integral_limits.h:516
bitset_ext
Definition absolute.h:38
pair holds two objects of arbitrary type
Definition utility.h:164
Definition memory_model.h:50