11#pragma once
2- #include " util/math.hh"
32#include < atomic>
43#include < optional>
54#include < vector>
98// For cheaply copied types
109// Will not overwrite -- put() returns false if buffer is full, and get() returns nullopt if buffer is empty.
1110// Provide the buffer size in the constructor.
12- // max_size_ MUST be a power of 2. If it's not, the next-highest power of 2 will be used for the size.
1311//
1412// Edge-case: max_size cannot be more than half the largest integer representable by size_t
1513template <class T >
1614class LockFreeFifoSpscDyn {
1715public:
18- size_t max_size_;
19- size_t SIZE_MASK;
20-
2116 LockFreeFifoSpscDyn (size_t max_size)
22- : max_size_{MathTools::next_power_of_2 (max_size)}
23- , SIZE_MASK{max_size_ - 1 }
17+ : max_size_{max_size}
2418 , head_{0 }
2519 , tail_{0 }
2620 , buf_(max_size_) {
@@ -30,19 +24,15 @@ public:
3024 // Useful, for example, if get() and put() happen at the same rates
3125 // and you want to provide a fixed delay
3226 LockFreeFifoSpscDyn (size_t max_size, size_t head)
33- : max_size_{MathTools::next_power_of_2 (max_size)}
34- , SIZE_MASK{max_size_ - 1 }
27+ : max_size_{max_size}
3528 , head_{head}
3629 , tail_{0 }
3730 , buf_(max_size_) {
3831 }
3932
4033 // Resets and resizes the vector. All contents are lost.
41- // max_size must be a power of 2 or else the next highest power of 2 will be used.
4234 // If max_size does not change, do nothing.
43- // Edge-case: max_size cannot be more than half the largest integer representable by size_t
4435 void resize (size_t new_max_size) {
45- new_max_size = MathTools::next_power_of_2 (new_max_size);
4636 if (new_max_size != max_size_) {
4737 reset ();
4838
@@ -54,7 +44,6 @@ public:
5444 buf_.resize (new_max_size);
5545
5646 max_size_ = new_max_size;
57- SIZE_MASK = max_size_ - 1 ;
5847 }
5948 }
6049
@@ -67,7 +56,7 @@ public:
6756 if ((tmp_head - tail_.load (std::memory_order_acquire)) == max_size_)
6857 return false ;
6958
70- buf_[tmp_head & SIZE_MASK ] = item;
59+ buf_[tmp_head % max_size_ ] = item;
7160 tmp_head++;
7261 std::atomic_signal_fence (std::memory_order_release);
7362 head_.store (tmp_head, std::memory_order_release);
@@ -101,7 +90,7 @@ public:
10190 return std::nullopt ;
10291 }
10392
104- auto item = buf_[tmp_tail & SIZE_MASK ];
93+ auto item = buf_[tmp_tail % max_size_ ];
10594 tmp_tail++;
10695 std::atomic_signal_fence (std::memory_order_release);
10796 tail_.store (tmp_tail, std::memory_order_release);
@@ -115,7 +104,7 @@ public:
115104 return false ;
116105 }
117106
118- t = std::move (buf_[tmp_tail & SIZE_MASK ]);
107+ t = std::move (buf_[tmp_tail % max_size_ ]);
119108 tmp_tail++;
120109 std::atomic_signal_fence (std::memory_order_release);
121110 tail_.store (tmp_tail, std::memory_order_release);
@@ -168,6 +157,7 @@ public:
168157 }
169158
170159private:
160+ size_t max_size_;
171161 std::atomic<size_t > head_ = 0 ;
172162 std::atomic<size_t > tail_ = 0 ;
173163 std::vector<T> buf_;
0 commit comments