blob: 30e629ba5c121da3141257abe4111dcdd78398d0 [file] [log] [blame]
anjana_sreekumar@infosys.com991c2062020-01-08 11:42:57 +05301/*
2 * This code is in public domain.
3 * Implementation and its platform dependent issues discussed in
4 * https://kjellkod.wordpress.com/2012/11/28/c-debt-paid-in-full-wait-free-lock-free-queue/
5 */
6
7#ifndef INCLUDE_CMN_CIRCULARFIFO_H_
8#define INCLUDE_CMN_CIRCULARFIFO_H_
9
10#include <atomic>
11#include <cstddef>
12
13namespace cmn {
14 namespace utils {
15 template<typename Element, size_t Size>
16 class CircularFifo
17 {
18 public:
19 enum { Capacity = Size + 1 };
20
21 CircularFifo() : _tail(0), _head(0){}
22 virtual ~CircularFifo() {}
23
24 bool push(Element* item);
25 bool pop(Element*& item);
26
27 bool wasEmpty() const;
28 bool wasFull() const;
29 bool isLockFree() const;
30
31 private:
32 size_t increment(size_t idx) const;
33
34 std::atomic <size_t> _tail;
35 Element* _array[Capacity];
36 std::atomic<size_t> _head;
37 };
38
39 template<typename Element, size_t Size>
40 bool CircularFifo<Element, Size>::push(Element* item)
41 {
42 const auto current_tail = _tail.load(std::memory_order_relaxed);
43 const auto next_tail = increment(current_tail);
44 if(next_tail != _head.load(std::memory_order_acquire))
45 {
46 _array[current_tail] = item;
47 _tail.store(next_tail, std::memory_order_release);
48 return true;
49 }
50
51 return false;
52 }
53
54 template<typename Element, size_t Size>
55 bool CircularFifo<Element, Size>::pop(Element*& item)
56 {
57 const auto current_head = _head.load(std::memory_order_relaxed);
58 if(current_head == _tail.load(std::memory_order_acquire))
59 return false;
60
61 item = _array[current_head];
62 _head.store(increment(current_head), std::memory_order_release);
63 return true;
64 }
65
66 template<typename Element, size_t Size>
67 bool CircularFifo<Element, Size>::wasEmpty() const
68 {
69 return (_head.load() == _tail.load());
70 }
71
72 template<typename Element, size_t Size>
73 bool CircularFifo<Element, Size>::wasFull() const
74 {
75 const auto next_tail = increment(_tail.load());
76 return (next_tail == _head.load());
77 }
78
79 template<typename Element, size_t Size>
80 bool CircularFifo<Element, Size>::isLockFree() const
81 {
82 return (_tail.is_lock_free() && _head.is_lock_free());
83 }
84
85 template<typename Element, size_t Size>
86 size_t CircularFifo<Element, Size>::increment(size_t idx) const
87 {
88 return (idx + 1) % Capacity;
89 }
90 }
91}
92
93
94#endif /* INCLUDE_CMN_CIRCULARFIFO_H_ */