48 right(std::move(source))
60 left(std::move(left)),
61 right(std::move(right))
82 template<
typename Func>
83 auto read(Func&& func)
const {
84 read_guard guard(*
this);
86 const T& inst = lr_indicator.load(std::memory_order_seq_cst) == READ_LEFT ? left : right;
99 template<
typename Func>
101 std::lock_guard<std::mutex> lock(writer_mutex);
102 assert(lr_indicator.load() == version_index.load());
103 if (lr_indicator.load(std::memory_order_relaxed) == READ_LEFT) {
106 lr_indicator.store(READ_RIGHT, std::memory_order_seq_cst);
107 toggle_version_and_wait();
112 lr_indicator.store(READ_LEFT, std::memory_order_seq_cst);
113 toggle_version_and_wait();
118 struct alignas(64) read_indicator {
121 counter.fetch_add(1, std::memory_order_seq_cst);
125 counter.fetch_sub(1, std::memory_order_release);
134 return counter.load(std::memory_order_seq_cst) == 0;
137 std::atomic<uint64_t> counter{0};
142 indicator(inst.get_read_indicator(inst.version_index.load(std::memory_order_relaxed)))
146 ~read_guard() { indicator.depart(); }
148 read_indicator& indicator;
150 friend struct read_guard;
152 void toggle_version_and_wait(
void) {
153 const int current_version = version_index.load(std::memory_order_relaxed);
154 const int current_idx = current_version & 0x1;
155 const int next_idx = (current_version + 1) & 0x1;
157 wait_for_readers(next_idx);
158 version_index.store(next_idx, std::memory_order_relaxed);
159 wait_for_readers(current_idx);
162 void wait_for_readers(
int idx) {
163 auto& indicator = get_read_indicator(idx);
164 while (!indicator.empty())
165 std::this_thread::yield();
168 read_indicator& get_read_indicator(
int idx)
const {
169 assert(idx == 0 || idx == 1);
171 return read_indicator1;
172 return read_indicator2;
175 static constexpr int READ_LEFT = 0;
176 static constexpr int READ_RIGHT = 1;
179 std::mutex writer_mutex;
180 std::atomic<int> version_index{0} ;
181 std::atomic<int> lr_indicator { READ_LEFT };
183 mutable read_indicator read_indicator1;
186 mutable read_indicator read_indicator2;
auto read(Func &&func) const
Performs a read operation on the active instance using the specified functor.
Definition left_right.hpp:83
left_right(T left, T right)
Initializes the two underlying instances withe the specified sources.
Definition left_right.hpp:59