Embedded Template Library 1.0
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 //*************************************************************************
60 {
62 }
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:
179 {
180 }
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 //*************************************************************************
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 template <typename T1>
328 bool emplace(const T1& value1)
329 {
330 lock();
331
332 bool result = emplace_implementation(value1);
333
334 unlock();
335
336 return result;
337 }
338
339 //*************************************************************************
342 //*************************************************************************
343 template <typename T1, typename T2>
344 bool emplace(const T1& value1, const T2& value2)
345 {
346 lock();
347
348 bool result = emplace_implementation(value1, value2);
349
350 unlock();
351
352 return result;
353 }
354
355 //*************************************************************************
358 //*************************************************************************
359 template <typename T1, typename T2, typename T3>
360 bool emplace(const T1& value1, const T2& value2, const T3& value3)
361 {
362 lock();
363
364 bool result = emplace_implementation(value1, value2, value3);
365
366 unlock();
367
368 return result;
369 }
370
371 //*************************************************************************
374 //*************************************************************************
375 template <typename T1, typename T2, typename T3, typename T4>
376 bool emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
377 {
378 lock();
379
380 bool result = emplace_implementation(value1, value2, value3, value4);
381
382 unlock();
383
384 return result;
385 }
386#endif
387
388 //*************************************************************************
391 //*************************************************************************
393 {
394 return pop_implementation(value);;
395 }
396
397 //*************************************************************************
399 //*************************************************************************
400 bool pop(reference value)
401 {
402 lock();
403
404 bool result = pop_implementation(value);
405
406 unlock();
407
408 return result;
409 }
410
411 //*************************************************************************
414 //*************************************************************************
416 {
417 return pop_implementation();
418 }
419
420 //*************************************************************************
422 //*************************************************************************
423 bool pop()
424 {
425 lock();
426
427 bool result = pop_implementation();
428
429 unlock();
430
431 return result;
432 }
433
434 //*************************************************************************
437 //*************************************************************************
439 {
440 return front_implementation();
441 }
442
443 //*************************************************************************
446 //*************************************************************************
448 {
449 return front_implementation();
450 }
451
452 //*************************************************************************
454 //*************************************************************************
456 {
457 lock();
458
459 reference result = front_implementation();
460
461 unlock();
462
463 return result;
464 }
465
466 //*************************************************************************
468 //*************************************************************************
470 {
471 lock();
472
473 const_reference result = front_implementation();
474
475 unlock();
476
477 return result;
478 }
479
480 //*************************************************************************
482 //*************************************************************************
484 {
485 while (pop_implementation())
486 {
487 // Do nothing.
488 }
489 }
490
491 //*************************************************************************
493 //*************************************************************************
494 void clear()
495 {
496 lock();
497
498 while (pop_implementation())
499 {
500 // Do nothing.
501 }
502
503 unlock();
504 }
505
506 //*************************************************************************
508 //*************************************************************************
510 {
511 lock();
512
513 size_type result = this->available_implementation();
514
515 unlock();
516
517 return result;
518 }
519
520 //*************************************************************************
522 //*************************************************************************
523 bool full() const
524 {
525 lock();
526
527 size_type result = this->full_implementation();
528
529 unlock();
530
531 return result;
532 }
533
534 //*************************************************************************
536 //*************************************************************************
538 {
539 lock();
540
541 size_type result = this->size_implementation();
542
543 unlock();
544
545 return result;
546 }
547
548 //*************************************************************************
550 //*************************************************************************
551 bool empty() const
552 {
553 lock();
554
555 bool result = this->empty_implementation();
556
557 unlock();
558
559 return result;
560 }
561
562 protected:
563
564 //*************************************************************************
566 //*************************************************************************
567 iqueue_spsc_locked(T* p_buffer_, size_type max_size_, const etl::ifunction<void>& lock_, const etl::ifunction<void>& unlock_)
568 : base_t(max_size_)
569 , p_buffer(p_buffer_)
570 , lock(lock_)
571 , unlock(unlock_)
572 {
573 }
574
575 private:
576
577 //*************************************************************************
579 //*************************************************************************
580 bool push_implementation(const_reference value)
581 {
582 if (this->current_size != this->MAX_SIZE)
583 {
584 ::new (&p_buffer[this->write_index]) T(value);
585
586 this->write_index = this->get_next_index(this->write_index, this->MAX_SIZE);
587
588 ++this->current_size;
589
590 return true;
591 }
592
593 // Queue is full.
594 return false;
595 }
596
597#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_LOCKED_FORCE_CPP03_IMPLEMENTATION)
598 //*************************************************************************
601 //*************************************************************************
602 bool push_implementation(rvalue_reference value)
603 {
604 if (this->current_size != this->MAX_SIZE)
605 {
606 ::new (&p_buffer[this->write_index]) T(etl::move(value));
607
608 this->write_index = this->get_next_index(this->write_index, this->MAX_SIZE);
609
610 ++this->current_size;
611
612 return true;
613 }
614
615 // Queue is full.
616 return false;
617 }
618#endif
619
620#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_LOCKED_FORCE_CPP03_IMPLEMENTATION)
621 //*************************************************************************
624 //*************************************************************************
625 template <typename ... Args>
626 bool emplace_implementation(Args&&... args)
627 {
628 if (this->current_size != this->MAX_SIZE)
629 {
630 ::new (&p_buffer[this->write_index]) T(etl::forward<Args>(args)...);
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#else
643 //*************************************************************************
645 //*************************************************************************
646 template <typename T1>
647 bool emplace_implementation(const T1& value1)
648 {
649 if (this->current_size != this->MAX_SIZE)
650 {
651 ::new (&p_buffer[this->write_index]) T(value1);
652
653 this->write_index = this->get_next_index(this->write_index, this->MAX_SIZE);
654
655 ++this->current_size;
656
657 return true;
658 }
659
660 // Queue is full.
661 return false;
662 }
663
664 //*************************************************************************
666 //*************************************************************************
667 template <typename T1, typename T2>
668 bool emplace_implementation(const T1& value1, const T2& value2)
669 {
670 if (this->current_size != this->MAX_SIZE)
671 {
672 ::new (&p_buffer[this->write_index]) T(value1, value2);
673
674 this->write_index = this->get_next_index(this->write_index, this->MAX_SIZE);
675
676 ++this->current_size;
677
678 return true;
679 }
680
681 // Queue is full.
682 return false;
683 }
684
685 //*************************************************************************
687 //*************************************************************************
688 template <typename T1, typename T2, typename T3>
689 bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3)
690 {
691 if (this->current_size != this->MAX_SIZE)
692 {
693 ::new (&p_buffer[this->write_index]) T(value1, value2, value3);
694
695 this->write_index = this->get_next_index(this->write_index, this->MAX_SIZE);
696
697 ++this->current_size;
698
699 return true;
700 }
701
702 // Queue is full.
703 return false;
704 }
705
706 //*************************************************************************
708 //*************************************************************************
709 template <typename T1, typename T2, typename T3, typename T4>
710 bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
711 {
712 if (this->current_size != this->MAX_SIZE)
713 {
714 ::new (&p_buffer[this->write_index]) T(value1, value2, value3, value4);
715
716 this->write_index = this->get_next_index(this->write_index, this->MAX_SIZE);
717
718 ++this->current_size;
719
720 return true;
721 }
722
723 // Queue is full.
724 return false;
725 }
726#endif
727
728 //*************************************************************************
731 //*************************************************************************
732 bool pop_implementation(reference value)
733 {
734 if (this->current_size == 0)
735 {
736 // Queue is empty
737 return false;
738 }
739
740#if ETL_USING_CPP11 && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_LOCKABLE_FORCE_CPP03_IMPLEMENTATION)
741 value = etl::move(p_buffer[this->read_index]);
742#else
743 value = p_buffer[this->read_index];
744#endif
745
746 p_buffer[this->read_index].~T();
747
748 this->read_index = this->get_next_index(this->read_index, this->MAX_SIZE);
749
750 --this->current_size;
751
752 return true;
753 }
754
755 //*************************************************************************
758 //*************************************************************************
759 reference front_implementation()
760 {
761 return p_buffer[this->read_index];
762 }
763
764 //*************************************************************************
767 //*************************************************************************
768 const_reference front_implementation() const
769 {
770 return p_buffer[this->read_index];
771 }
772
773 //*************************************************************************
776 //*************************************************************************
777 bool pop_implementation()
778 {
779 if (this->current_size == 0)
780 {
781 // Queue is empty
782 return false;
783 }
784
785 p_buffer[this->read_index].~T();
786
787 this->read_index = this->get_next_index(this->read_index, this->MAX_SIZE);
788
789 --this->current_size;
790
791 return true;
792 }
793
794 // Disable copy construction and assignment.
795 iqueue_spsc_locked(const iqueue_spsc_locked&) ETL_DELETE;
796 iqueue_spsc_locked& operator =(const iqueue_spsc_locked&) ETL_DELETE;
797
798#if ETL_USING_CPP11
800 iqueue_spsc_locked& operator =(iqueue_spsc_locked&&) = delete;
801#endif
802
803 T* p_buffer;
804
805 const etl::ifunction<void>& lock;
806 const etl::ifunction<void>& unlock;
807 };
808
809 //***************************************************************************
816 //***************************************************************************
817 template <typename T, size_t SIZE, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
818 class queue_spsc_locked : public etl::iqueue_spsc_locked<T, MEMORY_MODEL>
819 {
820 private:
821
823
824 public:
825
826 typedef typename base_t::size_type size_type;
827
828 ETL_STATIC_ASSERT((SIZE <= etl::integral_limits<size_type>::max), "Size too large for memory model");
829
830 static ETL_CONSTANT size_type MAX_SIZE = size_type(SIZE);
831
832 //*************************************************************************
834 //*************************************************************************
835
837 const etl::ifunction<void>& unlock)
838 : base_t(reinterpret_cast<T*>(buffer.raw), MAX_SIZE, lock, unlock)
839 {
840 }
841
842 //*************************************************************************
844 //*************************************************************************
846 {
848 }
849
850 private:
851
852 queue_spsc_locked(const queue_spsc_locked&) ETL_DELETE;
853 queue_spsc_locked& operator = (const queue_spsc_locked&) ETL_DELETE;
854
855#if ETL_USING_CPP11
857 queue_spsc_locked& operator =(queue_spsc_locked&&) = delete;
858#endif
859
862 };
863
864 template <typename T, size_t SIZE, const size_t MEMORY_MODEL>
865 ETL_CONSTANT typename queue_spsc_locked<T, SIZE, MEMORY_MODEL>::size_type queue_spsc_locked<T, SIZE, MEMORY_MODEL>::MAX_SIZE;
866}
867
868#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:376
bool emplace(const T1 &value1)
Definition: queue_spsc_locked.h:328
bool pop_from_unlocked()
Definition: queue_spsc_locked.h:415
bool emplace_from_unlocked(const T1 &value1)
Definition: queue_spsc_locked.h:288
reference front_from_unlocked()
Definition: queue_spsc_locked.h:438
bool emplace(const T1 &value1, const T2 &value2, const T3 &value3)
Definition: queue_spsc_locked.h:360
bool emplace(const T1 &value1, const T2 &value2)
Definition: queue_spsc_locked.h:344
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:567
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:423
bool pop(reference value)
Pop a value from the queue.
Definition: queue_spsc_locked.h:400
void clear()
Clear the queue.
Definition: queue_spsc_locked.h:494
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:455
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:447
bool empty() const
Is the queue empty?
Definition: queue_spsc_locked.h:551
size_type size() const
How many items in the queue?
Definition: queue_spsc_locked.h:537
bool push_from_unlocked(const_reference value)
Push a value to the queue.
Definition: queue_spsc_locked.h:211
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:469
bool full() const
Is the queue full?
Definition: queue_spsc_locked.h:523
void clear_from_unlocked()
Clear the queue from the ISR.
Definition: queue_spsc_locked.h:483
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:509
bool pop_from_unlocked(reference value)
Definition: queue_spsc_locked.h:392
Definition: queue_spsc_locked.h:819
~queue_spsc_locked()
Destructor.
Definition: queue_spsc_locked.h:845
queue_spsc_locked(const etl::ifunction< void > &lock, const etl::ifunction< void > &unlock)
Default constructor.
Definition: queue_spsc_locked.h:836
Definition: function.h:73
Definition: integral_limits.h:468
bitset_ext
Definition: absolute.h:38
Definition: memory_model.h:50