Embedded Template Library  1.0
queue_spsc_locked.h
Go to the documentation of this file.
1 
3 /******************************************************************************
4 The MIT License(MIT)
5 
6 Embedded Template Library.
7 https://github.com/ETLCPP/etl
8 https://www.etlcpp.com
9 
10 Copyright(c) 2019 jwellbelove
11 
12 Permission is hereby granted, free of charge, to any person obtaining a copy
13 of this software and associated documentation files(the "Software"), to deal
14 in the Software without restriction, including without limitation the rights
15 to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
16 copies of the Software, and to permit persons to whom the Software is
17 furnished to do so, subject to the following conditions :
18 
19 The above copyright notice and this permission notice shall be included in all
20 copies or substantial portions of the Software.
21 
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
25 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
28 SOFTWARE.
29 ******************************************************************************/
30 
31 #ifndef ETL_SPSC_QUEUE_LOCKED_INCLUDED
32 #define ETL_SPSC_QUEUE_LOCKED_INCLUDED
33 
34 #include <stddef.h>
35 #include <stdint.h>
36 
37 #include "platform.h"
38 #include "alignment.h"
39 #include "parameter_type.h"
40 #include "memory_model.h"
41 #include "integral_limits.h"
42 #include "function.h"
43 #include "utility.h"
44 #include "placement_new.h"
45 
46 #undef ETL_FILE
47 #define ETL_FILE "54"
48 
49 namespace etl
50 {
51  template <typename T, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
53  {
54  public:
55 
58 
59  typedef T value_type;
60  typedef T& reference;
61  typedef const T& const_reference;
62 #if ETL_CPP11_SUPPORTED
63  typedef T&& rvalue_reference;
64 #endif
65 
66  //*************************************************************************
68  //*************************************************************************
70  {
71  return push_implementation(value);
72  }
73 
74 #if ETL_CPP11_SUPPORTED
75  //*************************************************************************
77  //*************************************************************************
78  bool push_from_unlocked(rvalue_reference value)
79  {
80  return push_implementation(etl::move(value));
81  }
82 #endif
83 
84  //*************************************************************************
88  //*************************************************************************
89 #if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_LOCKED_FORCE_CPP03)
90  template <typename ... Args>
91  bool emplace_from_unlocked(Args&&... args)
92  {
93  return emplace_implementation(etl::forward<Args>(args)...);
94  }
95 #endif
96 
97  //*************************************************************************
99  //*************************************************************************
101  {
102  return pop_implementation(value);
103  }
104 
105 #if ETL_CPP11_SUPPORTED
106  //*************************************************************************
108  //*************************************************************************
109  bool pop_from_unlocked(rvalue_reference value)
110  {
111  return pop_implementation(etl::move(value));
112  }
113 #endif
114 
115  //*************************************************************************
117  //*************************************************************************
119  {
120  return pop_implementation();
121  }
122 
123  //*************************************************************************
126  //*************************************************************************
128  {
129  return MAX_SIZE - current_size;
130  }
131 
132  //*************************************************************************
134  //*************************************************************************
136  {
137  while (pop_implementation())
138  {
139  // Do nothing.
140  }
141  }
142 
143  //*************************************************************************
146  //*************************************************************************
147  bool empty_from_unlocked() const
148  {
149  return (current_size == 0);
150  }
151 
152  //*************************************************************************
155  //*************************************************************************
156  bool full_from_unlocked() const
157  {
158  return (current_size == MAX_SIZE);
159  }
160 
161  //*************************************************************************
164  //*************************************************************************
166  {
167  return current_size;
168  }
169 
170  //*************************************************************************
172  //*************************************************************************
174  {
175  return MAX_SIZE;
176  }
177 
178  //*************************************************************************
180  //*************************************************************************
182  {
183  return MAX_SIZE;
184  }
185 
186  protected:
187 
188  iqueue_spsc_locked_base(T* p_buffer_, size_type max_size_)
189  : p_buffer(p_buffer_),
190  write_index(0),
191  read_index(0),
192  current_size(0),
193  MAX_SIZE(max_size_)
194  {
195  }
196 
197  //*************************************************************************
199  //*************************************************************************
201  {
202  if (current_size != MAX_SIZE)
203  {
204  ::new (&p_buffer[write_index]) T(value);
205 
207 
208  ++current_size;
209 
210  return true;
211  }
212 
213  // Queue is full.
214  return false;
215  }
216 
217 #if ETL_CPP11_SUPPORTED
218  //*************************************************************************
220  //*************************************************************************
221  bool push_implementation(rvalue_reference value)
222  {
223  if (current_size != MAX_SIZE)
224  {
225  ::new (&p_buffer[write_index]) T(etl::move(value));
226 
228 
229  ++current_size;
230 
231  return true;
232  }
233 
234  // Queue is full.
235  return false;
236  }
237 #endif
238 
239 #if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_LOCKED_FORCE_CPP03)
240  //*************************************************************************
244  //*************************************************************************
245  template <typename ... Args>
246  bool emplace_implementation(Args&&... args)
247  {
248  if (current_size != MAX_SIZE)
249  {
250  ::new (&p_buffer[write_index]) T(etl::forward<Args>(args)...);
251 
253 
254  ++current_size;
255 
256  return true;
257  }
258 
259  // Queue is full.
260  return false;
261  }
262 #else
263  //*************************************************************************
266  //*************************************************************************
267  template <typename T1>
268  bool emplace_implementation(const T1& value1)
269  {
270  if (current_size != MAX_SIZE)
271  {
272  ::new (&p_buffer[write_index]) T(value1);
273 
275 
276  ++current_size;
277 
278  return true;
279  }
280 
281  // Queue is full.
282  return false;
283  }
284 
285  //*************************************************************************
288  //*************************************************************************
289  template <typename T1, typename T2>
290  bool emplace_implementation(const T1& value1, const T2& value2)
291  {
292  if (current_size != MAX_SIZE)
293  {
294  ::new (&p_buffer[write_index]) T(value1, value2);
295 
297 
298  ++current_size;
299 
300  return true;
301  }
302 
303  // Queue is full.
304  return false;
305  }
306 
307  //*************************************************************************
310  //*************************************************************************
311  template <typename T1, typename T2, typename T3>
312  bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3)
313  {
314  if (current_size != MAX_SIZE)
315  {
316  ::new (&p_buffer[write_index]) T(value1, value2, value3);
317 
319 
320  ++current_size;
321 
322  return true;
323  }
324 
325  // Queue is full.
326  return false;
327  }
328 
329  //*************************************************************************
332  //*************************************************************************
333  template <typename T1, typename T2, typename T3, typename T4>
334  bool emplace_implementation(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
335  {
336  if (current_size != MAX_SIZE)
337  {
338  ::new (&p_buffer[write_index]) T(value1, value2, value3, value4);
339 
341 
342  ++current_size;
343 
344  return true;
345  }
346 
347  // Queue is full.
348  return false;
349  }
350 
351 #endif
352 
353  //*************************************************************************
355  //*************************************************************************
357  {
358  if (current_size == 0)
359  {
360  // Queue is empty
361  return false;
362  }
363 
364  value = p_buffer[read_index];
365  p_buffer[read_index].~T();
366 
368 
369  --current_size;
370 
371  return true;
372  }
373 
374 #if ETL_CPP11_SUPPORTED
375  //*************************************************************************
377  //*************************************************************************
378  bool pop_implementation(rvalue_reference value)
379  {
380  if (current_size == 0)
381  {
382  // Queue is empty
383  return false;
384  }
385 
386  value = etl::move(p_buffer[read_index]);
387  p_buffer[read_index].~T();
388 
390 
391  --current_size;
392 
393  return true;
394  }
395 #endif
396 
397  //*************************************************************************
399  //*************************************************************************
401  {
402  if (current_size == 0)
403  {
404  // Queue is empty
405  return false;
406  }
407 
408  p_buffer[read_index].~T();
409 
411 
412  --current_size;
413 
414  return true;
415  }
416 
417  //*************************************************************************
419  //*************************************************************************
421  {
422  ++index;
423 
424  if (index == maximum)
425  {
426  index = 0;
427  }
428 
429  return index;
430  }
431 
432  T* p_buffer;
437 
438  private:
439 
440  //*************************************************************************
442  //*************************************************************************
443 #if defined(ETL_POLYMORPHIC_SPSC_QUEUE_ISR) || defined(ETL_POLYMORPHIC_CONTAINERS)
444  public:
445  virtual ~iqueue_spsc_locked_base()
446  {
447  }
448 #else
449  protected:
451  {
452  }
453 #endif
454  };
455 
456  //***************************************************************************
462  //***************************************************************************
463  template <typename T, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
464  class iqueue_spsc_locked : public iqueue_spsc_locked_base<T, MEMORY_MODEL>
465  {
466  private:
467 
469 
470  public:
471 
472  typedef typename base_t::value_type value_type;
473  typedef typename base_t::reference reference;
475 #if ETL_CPP11_SUPPORTED
476  typedef typename base_t::rvalue_reference rvalue_reference;
477 #endif
478  typedef typename base_t::size_type size_type;
479 
480  //*************************************************************************
482  //*************************************************************************
483  bool push(const_reference value)
484  {
485  lock();
486 
487  bool result = this->push_implementation(value);
488 
489  unlock();
490 
491  return result;
492  }
493 
494 #if ETL_CPP11_SUPPORTED
495  //*************************************************************************
497  //*************************************************************************
498  bool push(rvalue_reference value)
499  {
500  lock();
501 
502  bool result = this->push_implementation(etl::move(value));
503 
504  unlock();
505 
506  return result;
507  }
508 #endif
509 
510  //*************************************************************************
513  //*************************************************************************
514 #if ETL_CPP11_SUPPORTED && ETL_NOT_USING_STLPORT && !defined(ETL_QUEUE_LOCKED_FORCE_CPP03)
515  template <typename ... Args>
516  bool emplace(Args&&... args)
517  {
518  lock();
519 
520  bool result = this->emplace_implementation(etl::forward<Args>(args)...);
521 
522  unlock();
523 
524  return result;
525  }
526 #else
527  //*************************************************************************
530  //*************************************************************************
531  template <typename T1>
532  bool emplace(const T1& value1)
533  {
534  lock();
535 
536  bool result = this->emplace_implementation(value1);
537 
538  unlock();
539 
540  return result;
541  }
542 
543  //*************************************************************************
546  //*************************************************************************
547  template <typename T1, typename T2>
548  bool emplace(const T1& value1, const T2& value2)
549  {
550  lock();
551 
552  bool result = this->emplace_implementation(value1, value2);
553 
554  unlock();
555 
556  return result;
557  }
558 
559  //*************************************************************************
562  //*************************************************************************
563  template <typename T1, typename T2, typename T3>
564  bool emplace(const T1& value1, const T2& value2, const T3& value3)
565  {
566  lock();
567 
568  bool result = this->emplace_implementation(value1, value2, value3);
569 
570  unlock();
571 
572  return result;
573  }
574 
575  //*************************************************************************
578  //*************************************************************************
579  template <typename T1, typename T2, typename T3, typename T4>
580  bool emplace(const T1& value1, const T2& value2, const T3& value3, const T4& value4)
581  {
582  lock();
583 
584  bool result = this->emplace_implementation(value1, value2, value3, value4);
585 
586  unlock();
587 
588  return result;
589  }
590 #endif
591 
592  //*************************************************************************
594  //*************************************************************************
595  bool pop(reference value)
596  {
597  lock();
598 
599  bool result = this->pop_implementation(value);
600 
601  unlock();
602 
603  return result;
604  }
605 
606 #if ETL_CPP11_SUPPORTED
607  //*************************************************************************
609  //*************************************************************************
610  bool pop(rvalue_reference value)
611  {
612  lock();
613 
614  bool result = this->pop_implementation(etl::move(value));
615 
616  unlock();
617 
618  return result;
619  }
620 #endif
621 
622  //*************************************************************************
624  //*************************************************************************
625  bool pop()
626  {
627  lock();
628 
629  bool result = this->pop_implementation();
630 
631  unlock();
632 
633  return result;
634  }
635 
636  //*************************************************************************
638  //*************************************************************************
639  void clear()
640  {
641  lock();
642 
643  while (this->pop_implementation())
644  {
645  // Do nothing.
646  }
647 
648  unlock();
649  }
650 
651  //*************************************************************************
653  //*************************************************************************
654  bool empty() const
655  {
656  lock();
657 
658  size_type result = (this->current_size == 0);
659 
660  unlock();
661 
662  return result;
663  }
664 
665  //*************************************************************************
667  //*************************************************************************
668  bool full() const
669  {
670  lock();
671 
672  size_type result = (this->current_size == this->MAX_SIZE);
673 
674  unlock();
675 
676  return result;
677  }
678 
679  //*************************************************************************
681  //*************************************************************************
682  size_type size() const
683  {
684  lock();
685 
686  size_type result = this->current_size;
687 
688  unlock();
689 
690  return result;
691  }
692 
693  //*************************************************************************
695  //*************************************************************************
697  {
698  lock();
699 
700  size_type result = this->MAX_SIZE - this->current_size;
701 
702  unlock();
703 
704  return result;
705  }
706 
707  protected:
708 
709  //*************************************************************************
711  //*************************************************************************
712  iqueue_spsc_locked(T* p_buffer_, size_type max_size_, const etl::ifunction<void>& lock_, const etl::ifunction<void>& unlock_)
713  : base_t(p_buffer_, max_size_)
714  , lock(lock_)
715  , unlock(unlock_)
716  {
717  }
718 
719  private:
720 
721  // Disable copy construction and assignment.
722  iqueue_spsc_locked(const iqueue_spsc_locked&) ETL_DELETE;
723  iqueue_spsc_locked& operator =(const iqueue_spsc_locked&) ETL_DELETE;
724 
725 #if ETL_CPP11_SUPPORTED
727  iqueue_spsc_locked& operator =(iqueue_spsc_locked&&) = delete;
728 #endif
729 
730  const etl::ifunction<void>& lock;
731  const etl::ifunction<void>& unlock;
732  };
733 
734  //***************************************************************************
741  //***************************************************************************
742  template <typename T, size_t SIZE, const size_t MEMORY_MODEL = etl::memory_model::MEMORY_MODEL_LARGE>
743  class queue_spsc_locked : public etl::iqueue_spsc_locked<T, MEMORY_MODEL>
744  {
745  private:
746 
748 
749  public:
750 
751  typedef typename base_t::size_type size_type;
752 
753  ETL_STATIC_ASSERT((SIZE <= etl::integral_limits<size_type>::max), "Size too large for memory model");
754 
755  static const size_type MAX_SIZE = size_type(SIZE);
756 
757  //*************************************************************************
759  //*************************************************************************
760 
762  const etl::ifunction<void>& unlock)
763  : base_t(reinterpret_cast<T*>(&buffer[0]), MAX_SIZE, lock, unlock)
764  {
765  }
766 
767  //*************************************************************************
769  //*************************************************************************
771  {
772  base_t::clear();
773  }
774 
775  private:
776 
777  queue_spsc_locked(const queue_spsc_locked&) ETL_DELETE;
778  queue_spsc_locked& operator = (const queue_spsc_locked&) ETL_DELETE;
779 
780 #if ETL_CPP11_SUPPORTED
782  queue_spsc_locked& operator =(queue_spsc_locked&&) = delete;
783 #endif
784 
786  typename etl::aligned_storage<sizeof(T), etl::alignment_of<T>::value>::type buffer[MAX_SIZE];
787  };
788 }
789 
790 #undef ETL_FILE
791 
792 #endif
Definition: queue_spsc_locked.h:53
bool pop_from_unlocked()
Pop a value from the queue from an ISR, and discard.
Definition: queue_spsc_locked.h:118
size_type available_from_unlocked() const
Definition: queue_spsc_locked.h:127
bool emplace_implementation(const T1 &value1)
Definition: queue_spsc_locked.h:268
size_type read_index
Where to get the oldest data.
Definition: queue_spsc_locked.h:434
size_type max_size() const
How many items can the queue hold.
Definition: queue_spsc_locked.h:181
const size_type MAX_SIZE
The maximum number of items in the queue.
Definition: queue_spsc_locked.h:436
bool pop_implementation(reference value)
Pop a value from the queue.
Definition: queue_spsc_locked.h:356
bool push_implementation(const_reference value)
Push a value to the queue.
Definition: queue_spsc_locked.h:200
bool emplace_implementation(const T1 &value1, const T2 &value2, const T3 &value3)
Definition: queue_spsc_locked.h:312
size_type write_index
Where to input new data.
Definition: queue_spsc_locked.h:433
const T & const_reference
A const reference to the type used in the queue.
Definition: queue_spsc_locked.h:61
T & reference
A reference to the type used in the queue.
Definition: queue_spsc_locked.h:60
size_type current_size
The current size of the queue.
Definition: queue_spsc_locked.h:435
bool push_from_unlocked(const_reference value)
Push a value to the queue from an ISR.
Definition: queue_spsc_locked.h:69
void clear_from_unlocked()
Clear the queue from the ISR.
Definition: queue_spsc_locked.h:135
bool empty_from_unlocked() const
Definition: queue_spsc_locked.h:147
T value_type
The type stored in the queue.
Definition: queue_spsc_locked.h:59
~iqueue_spsc_locked_base()
Destructor.
Definition: queue_spsc_locked.h:450
T * p_buffer
The internal buffer.
Definition: queue_spsc_locked.h:432
size_type size_from_unlocked() const
Definition: queue_spsc_locked.h:165
etl::size_type_lookup< MEMORY_MODEL >::type size_type
The type used for determining the size of queue.
Definition: queue_spsc_locked.h:57
bool emplace_implementation(const T1 &value1, const T2 &value2)
Definition: queue_spsc_locked.h:290
bool emplace_implementation(const T1 &value1, const T2 &value2, const T3 &value3, const T4 &value4)
Definition: queue_spsc_locked.h:334
static size_type get_next_index(size_type index, size_type maximum)
Calculate the next index.
Definition: queue_spsc_locked.h:420
bool pop_implementation()
Pop a value from the queue and discard.
Definition: queue_spsc_locked.h:400
bool full_from_unlocked() const
Definition: queue_spsc_locked.h:156
bool pop_from_unlocked(reference value)
Pop a value from the queue from an ISR.
Definition: queue_spsc_locked.h:100
size_type capacity() const
How many items can the queue hold.
Definition: queue_spsc_locked.h:173
This is the base for all queue_spsc_isrs that contain a particular type.
Definition: queue_spsc_locked.h:465
bool emplace(const T1 &value1, const T2 &value2, const T3 &value3, const T4 &value4)
Definition: queue_spsc_locked.h:580
bool emplace(const T1 &value1)
Definition: queue_spsc_locked.h:532
bool emplace(const T1 &value1, const T2 &value2, const T3 &value3)
Definition: queue_spsc_locked.h:564
bool emplace(const T1 &value1, const T2 &value2)
Definition: queue_spsc_locked.h:548
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:712
bool pop()
Pop a value from the queue and discard.
Definition: queue_spsc_locked.h:625
bool pop(reference value)
Pop a value from the queue.
Definition: queue_spsc_locked.h:595
void clear()
Clear the queue.
Definition: queue_spsc_locked.h:639
base_t::const_reference const_reference
A const reference to the type used in the queue.
Definition: queue_spsc_locked.h:474
base_t::reference reference
A reference to the type used in the queue.
Definition: queue_spsc_locked.h:473
base_t::value_type value_type
The type stored in the queue.
Definition: queue_spsc_locked.h:472
bool empty() const
Is the queue empty?
Definition: queue_spsc_locked.h:654
size_type size() const
How many items in the queue?
Definition: queue_spsc_locked.h:682
base_t::size_type size_type
The type used for determining the size of the queue.
Definition: queue_spsc_locked.h:478
bool full() const
Is the queue full?
Definition: queue_spsc_locked.h:668
bool push(const_reference value)
Push a value to the queue.
Definition: queue_spsc_locked.h:483
size_type available() const
How much free space available in the queue.
Definition: queue_spsc_locked.h:696
Definition: queue_spsc_locked.h:744
~queue_spsc_locked()
Destructor.
Definition: queue_spsc_locked.h:770
queue_spsc_locked(const etl::ifunction< void > &lock, const etl::ifunction< void > &unlock)
Default constructor.
Definition: queue_spsc_locked.h:761
Definition: alignment.h:116
Definition: function.h:73
Definition: integral_limits.h:54
add_rvalue_reference
Definition: type_traits_generator.h:1348
Definition: absolute.h:37
Definition: memory_model.h:48