FTXUI  5.0.0
C++ functional terminal UI.
Loading...
Searching...
No Matches
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
15namespace 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
42template<class T> class SenderImpl;
43template<class T> class ReceiverImpl;
44
45template<class T> using Sender = std::unique_ptr<SenderImpl<T>>;
46template<class T> using Receiver = std::unique_ptr<ReceiverImpl<T>>;
47template<class T> Receiver<T> MakeReceiver();
48// clang-format on
49
50// ---- Implementation part ----
51
52template <class T>
54 public:
55 SenderImpl(const 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
70template <class T>
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
138template <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
friend class SenderImpl< T >
Definition receiver.hpp:117
Sender< T > MakeSender()
Definition receiver.hpp:73
friend class ReceiverImpl< T >
Definition receiver.hpp:65
SenderImpl & operator=(const SenderImpl &)=delete
Sender< T > Clone()
Definition receiver.hpp:62
SenderImpl(SenderImpl &&)=delete
SenderImpl(const SenderImpl &)=delete
SenderImpl & operator=(SenderImpl &&)=delete
std::shared_ptr< T > Make(Args &&... args)
Definition component.hpp:26
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