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