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>
49 class iqueue_spsc_locked_base
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),
110 MAX_SIZE(max_size_)
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
196 typedef iqueue_spsc_locked_base<MEMORY_MODEL> base_t;
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 //*************************************************************************
235 bool push_from_unlocked(rvalue_reference value)
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 if ETL_IF_CONSTEXPR(etl::is_trivially_destructible<T>::value)
514 {
515 this->write_index = 0;
516 this->read_index = 0;
517 this->current_size = 0;
518 }
519 else
520 {
521 while (pop_implementation())
522 {
523 // Do nothing.
524 }
525 }
526
527 unlock();
528 }
529
530 //*************************************************************************
532 //*************************************************************************
534 {
535 lock();
536
537 size_type result = this->available_implementation();
538
539 unlock();
540
541 return result;
542 }
543
544 //*************************************************************************
546 //*************************************************************************
547 bool full() const
548 {
549 lock();
550
551 size_type result = this->full_implementation();
552
553 unlock();
554
555 return result;
556 }
557
558 //*************************************************************************
560 //*************************************************************************
562 {
563 lock();
564
565 size_type result = this->size_implementation();
566
567 unlock();
568
569 return result;
570 }
571
572 //*************************************************************************
574 //*************************************************************************
575 bool empty() const
576 {
577 lock();
578
579 bool result = this->empty_implementation();
580
581 unlock();
582
583 return result;
584 }
585
586 protected:
587
588 //*************************************************************************
590 //*************************************************************************
591 iqueue_spsc_locked(T* p_buffer_, size_type max_size_, const etl::ifunction<void>& lock_, const etl::ifunction<void>& unlock_)
592 : base_t(max_size_)
593 , p_buffer(p_buffer_)
594 , lock(lock_)
595 , unlock(unlock_)
596 {
597 }
598
599 private:
600
601 //*************************************************************************
603 //*************************************************************************
604 bool push_implementation(const_reference value)
605 {
606 if (this->current_size != this->MAX_SIZE)
607 {
608 ::new (&p_buffer[this->write_index]) T(value);
609
610 this->write_index = this->get_next_index(this->write_index, this->MAX_SIZE);
611
612 ++this->current_size;
613
614 return true;
615 }
616
617 // Queue is full.
618 return false;
619 }
620
621#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_LOCKED_FORCE_CPP03_IMPLEMENTATION)
622 //*************************************************************************
625 //*************************************************************************
626 bool push_implementation(rvalue_reference value)
627 {
628 if (this->current_size != this->MAX_SIZE)
629 {
630 ::new (&p_buffer[this->write_index]) T(etl::move(value));
631
632 this->write_index = this->get_next_index(this->write_index, this->MAX_SIZE);
633
634 ++this->current_size;
635
636 return true;
637 }
638
639 // Queue is full.
640 return false;
641 }
642#endif
643
644#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_LOCKED_FORCE_CPP03_IMPLEMENTATION)
645 //*************************************************************************
648 //*************************************************************************
649 template <typename ... Args>
650 bool emplace_implementation(Args&&... args)
651 {
652 if (this->current_size != this->MAX_SIZE)
653 {
654 ::new (&p_buffer[this->write_index]) T(etl::forward<Args>(args)...);
655
656 this->write_index = this->get_next_index(this->write_index, this->MAX_SIZE);
657
658 ++this->current_size;
659
660 return true;
661 }
662
663 // Queue is full.
664 return false;
665 }
666#else
667 //*************************************************************************
669 //*************************************************************************
670 bool emplace_implementation()
671 {
672 if (this->current_size != this->MAX_SIZE)
673 {
674 ::new (&p_buffer[this->write_index]) T();
675
676 this->write_index = this->get_next_index(this->write_index, this->MAX_SIZE);
677
678 ++this->current_size;
679
680 return true;
681 }
682
683 // Queue is full.
684 return false;
685 }
686
687 //*************************************************************************
689 //*************************************************************************
690 template <typename T1>
691 bool emplace_implementation(const T1& value1)
692 {
693 if (this->current_size != this->MAX_SIZE)
694 {
695 ::new (&p_buffer[this->write_index]) T(value1);
696
697 this->write_index = this->get_next_index(this->write_index, this->MAX_SIZE);
698
699 ++this->current_size;
700
701 return true;
702 }
703
704 // Queue is full.
705 return false;
706 }
707
708 //*************************************************************************
710 //*************************************************************************
711 template <typename T1, typename T2>
712 bool emplace_implementation(const T1& value1, const T2& value2)
713 {
714 if (this->current_size != this->MAX_SIZE)
715 {
716 ::new (&p_buffer[this->write_index]) T(value1, value2);
717
718 this->write_index = this->get_next_index(this->write_index, this->MAX_SIZE);
719
720 ++this->current_size;
721
722 return true;
723 }
724
725 // Queue is full.
726 return false;
727 }
728
729 //*************************************************************************
731 //*************************************************************************
732 template <typename T1, typename T2, typename T3>
733 bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3)
734 {
735 if (this->current_size != this->MAX_SIZE)
736 {
737 ::new (&p_buffer[this->write_index]) T(value1, value2, value3);
738
739 this->write_index = this->get_next_index(this->write_index, this->MAX_SIZE);
740
741 ++this->current_size;
742
743 return true;
744 }
745
746 // Queue is full.
747 return false;
748 }
749
750 //*************************************************************************
752 //*************************************************************************
753 template <typename T1, typename T2, typename T3, typename T4>
754 bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
755 {
756 if (this->current_size != this->MAX_SIZE)
757 {
758 ::new (&p_buffer[this->write_index]) T(value1, value2, value3, value4);
759
760 this->write_index = this->get_next_index(this->write_index, this->MAX_SIZE);
761
762 ++this->current_size;
763
764 return true;
765 }
766
767 // Queue is full.
768 return false;
769 }
770#endif
771
772 //*************************************************************************
775 //*************************************************************************
776 bool pop_implementation(reference value)
777 {
778 if (this->current_size == 0)
779 {
780 // Queue is empty
781 return false;
782 }
783
784#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_LOCKABLE_FORCE_CPP03_IMPLEMENTATION)
785 value = etl::move(p_buffer[this->read_index]);
786#else
787 value = p_buffer[this->read_index];
788#endif
789
790 p_buffer[this->read_index].~T();
791
792 this->read_index = this->get_next_index(this->read_index, this->MAX_SIZE);
793
794 --this->current_size;
795
796 return true;
797 }
798
799 //*************************************************************************
802 //*************************************************************************
803 reference front_implementation()
804 {
805 return p_buffer[this->read_index];
806 }
807
808 //*************************************************************************
811 //*************************************************************************
812 const_reference front_implementation() const
813 {
814 return p_buffer[this->read_index];
815 }
816
817 //*************************************************************************
820 //*************************************************************************
821 bool pop_implementation()
822 {
823 if (this->current_size == 0)
824 {
825 // Queue is empty
826 return false;
827 }
828
829 p_buffer[this->read_index].~T();
830
831 this->read_index = this->get_next_index(this->read_index, this->MAX_SIZE);
832
833 --this->current_size;
834
835 return true;
836 }
837
838 // Disable copy construction and assignment.
839 iqueue_spsc_locked(const iqueue_spsc_locked&) ETL_DELETE;
840 iqueue_spsc_locked& operator =(const iqueue_spsc_locked&) ETL_DELETE;
841
842#if ETL_USING_CPP11
844 iqueue_spsc_locked& operator =(iqueue_spsc_locked&&) = delete;
845#endif
846
847 T* p_buffer;
848
849 const etl::ifunction<void>& lock;
850 const etl::ifunction<void>& unlock;
851 };
852
853 //***************************************************************************
860 //***************************************************************************
861 template <typename T, size_t SIZE, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
862 class queue_spsc_locked : public etl::iqueue_spsc_locked<T, MEMORY_MODEL>
863 {
864 private:
865
867
868 public:
869
870 typedef typename base_t::size_type size_type;
871
872 ETL_STATIC_ASSERT((SIZE <= etl::integral_limits<size_type>::max), "Size too large for memory model");
873
874 static ETL_CONSTANT size_type MAX_SIZE = size_type(SIZE);
875
876 //*************************************************************************
878 //*************************************************************************
879
881 const etl::ifunction<void>& unlock_)
882 : base_t(reinterpret_cast<T*>(buffer.raw), MAX_SIZE, lock_, unlock_)
883 {
884 }
885
886 //*************************************************************************
888 //*************************************************************************
890 {
892 }
893
894 private:
895
896 queue_spsc_locked(const queue_spsc_locked&) ETL_DELETE;
897 queue_spsc_locked& operator = (const queue_spsc_locked&) ETL_DELETE;
898
899#if ETL_USING_CPP11
901 queue_spsc_locked& operator =(queue_spsc_locked&&) = delete;
902#endif
903
906 };
907
908 template <typename T, size_t SIZE, const size_t MEMORY_MODEL>
910}
911
912#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
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:591
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:575
size_type size() const
How many items in the queue?
Definition queue_spsc_locked.h:561
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:547
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:533
bool pop_from_unlocked(reference value)
Definition queue_spsc_locked.h:407
Definition queue_spsc_locked.h:863
queue_spsc_locked(const etl::ifunction< void > &lock_, const etl::ifunction< void > &unlock_)
Default constructor.
Definition queue_spsc_locked.h:880
~queue_spsc_locked()
Destructor.
Definition queue_spsc_locked.h:889
Definition memory.h:2183
Definition function.h:54
Definition integral_limits.h:516
bitset_ext
Definition absolute.h:39
Definition memory_model.h:50