FTXUI  5.0.0
C++ functional terminal UI.
receiver.hpp
Go to the documentation of this file.
1// Copyright 2020 Arthur Sonzogni. All rights reserved.
2// Use of this source code is governed by the MIT license that can be found in
3// the LICENSE file.
4#ifndef FTXUI_COMPONENT_RECEIVER_HPP_
5#define FTXUI_COMPONENT_RECEIVER_HPP_
6
7#include <algorithm> // for copy, max
8#include <atomic> // for atomic, __atomic_base
9#include <condition_variable> // for condition_variable
10#include <functional>
11#include <iostream>
12#include <memory> // for unique_ptr, make_unique
13#include <mutex> // for mutex, unique_lock
14#include <queue> // for queue
15#include <utility> // for move
16
17namespace ftxui {
18
19// Usage:
20//
21// Initialization:
22// ---------------
23//
24// auto receiver = MakeReceiver<std:string>();
25// auto sender_1= receiver->MakeSender();
26// auto sender_2 = receiver->MakeSender();
27//
28// Then move the senders elsewhere, potentially in a different thread.
29//
30// On the producer side:
31// ----------------------
32// [thread 1] sender_1->Send("hello");
33// [thread 2] sender_2->Send("world");
34//
35// On the consumer side:
36// ---------------------
37// char c;
38// while(receiver->Receive(&c)) // Return true as long as there is a producer.
39// print(c)
40//
41// Receiver::Receive() returns true when there are no more senders.
42
43// clang-format off
44template<class T> class SenderImpl;
45template<class T> class ReceiverImpl;
46
47template<class T> using Sender = std::unique_ptr<SenderImpl<T>>;
48template<class T> using Receiver = std::unique_ptr<ReceiverImpl<T>>;
49template<class T> Receiver<T> MakeReceiver();
50// clang-format on
51
52// ---- Implementation part ----
53
54template <class T>
56 public:
57 void Send(T t) { receiver_->Receive(std::move(t)); }
58 ~SenderImpl() { receiver_->ReleaseSender(); }
59
60 Sender<T> Clone() { return receiver_->MakeSender(); }
61
62 private:
63 friend class ReceiverImpl<T>;
64 SenderImpl(ReceiverImpl<T>* consumer) : receiver_(consumer) {}
65 ReceiverImpl<T>* receiver_;
66};
67
68template <class T>
70 public:
72 std::unique_lock<std::mutex> lock(mutex_);
73 senders_++;
74 return std::unique_ptr<SenderImpl<T>>(new SenderImpl<T>(this));
75 }
76 ReceiverImpl() { senders_ = 0; }
77
78 bool Receive(T* t) {
79 while (senders_ || !queue_.empty()) {
80 std::unique_lock<std::mutex> lock(mutex_);
81 if (queue_.empty())
82 notifier_.wait(lock);
83 if (queue_.empty())
84 continue;
85 *t = std::move(queue_.front());
86 queue_.pop();
87 return true;
88 }
89 return false;
90 }
91
92 bool ReceiveNonBlocking(T* t) {
93 std::unique_lock<std::mutex> lock(mutex_);
94 if (queue_.empty())
95 return false;
96 *t = queue_.front();
97 queue_.pop();
98 return true;
99 }
100
101 bool HasPending() {
102 std::unique_lock<std::mutex> lock(mutex_);
103 return !queue_.empty();
104 }
105
106 bool HasQuitted() {
107 std::unique_lock<std::mutex> lock(mutex_);
108 return queue_.empty() && !senders_;
109 }
110
111 private:
112 friend class SenderImpl<T>;
113
114 void Receive(T t) {
115 {
116 std::unique_lock<std::mutex> lock(mutex_);
117 queue_.push(std::move(t));
118 }
119 notifier_.notify_one();
120 }
121
122 void ReleaseSender() {
123 senders_--;
124 notifier_.notify_one();
125 }
126
127 std::mutex mutex_;
128 std::queue<T> queue_;
129 std::condition_variable notifier_;
130 std::atomic<int> senders_;
131};
132
133template <class T>
135 return std::make_unique<ReceiverImpl<T>>();
136}
137
138} // namespace ftxui
139
140#endif // FTXUI_COMPONENT_RECEIVER_HPP_
bool Receive(T *t)
Definition: receiver.hpp:78
bool ReceiveNonBlocking(T *t)
Definition: receiver.hpp:92
friend class SenderImpl< T >
Definition: receiver.hpp:112
Sender< T > MakeSender()
Definition: receiver.hpp:71
friend class ReceiverImpl< T >
Definition: receiver.hpp:63
Sender< T > Clone()
Definition: receiver.hpp:60
void Send(T t)
Definition: receiver.hpp:57
Receiver< T > MakeReceiver()
Definition: receiver.hpp:134
std::unique_ptr< ReceiverImpl< T > > Receiver
Definition: receiver.hpp:48
std::unique_ptr< SenderImpl< T > > Sender
Definition: receiver.hpp:47