| 
									
										
										
										
											2023-08-19 13:56:36 +02:00
										 |  |  | // Copyright 2020 Arthur Sonzogni. All rights reserved.
 | 
					
						
							|  |  |  | // Use of this source code is governed by the MIT license that can be found in
 | 
					
						
							|  |  |  | // the LICENSE file.
 | 
					
						
							| 
									
										
										
										
											2020-03-25 00:07:41 +01:00
										 |  |  | #ifndef FTXUI_COMPONENT_RECEIVER_HPP_
 | 
					
						
							|  |  |  | #define FTXUI_COMPONENT_RECEIVER_HPP_
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-17 21:08:36 +02:00
										 |  |  | #include <ftxui/util/warn_windows_macro.hpp>
 | 
					
						
							| 
									
										
										
										
											2023-05-02 13:32:37 +02:00
										 |  |  | #include <algorithm>           // for copy, max
 | 
					
						
							| 
									
										
										
										
											2021-05-14 22:00:49 +02:00
										 |  |  | #include <atomic>              // for atomic, __atomic_base
 | 
					
						
							| 
									
										
										
										
											2021-05-01 20:40:35 +02:00
										 |  |  | #include <condition_variable>  // for condition_variable
 | 
					
						
							| 
									
										
										
										
											2024-05-01 11:40:49 +02:00
										 |  |  | #include <memory>              // for unique_ptr, make_unique
 | 
					
						
							|  |  |  | #include <mutex>               // for mutex, unique_lock
 | 
					
						
							|  |  |  | #include <queue>               // for queue
 | 
					
						
							|  |  |  | #include <utility>             // for move
 | 
					
						
							| 
									
										
										
										
											2020-03-25 00:07:41 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace ftxui { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-16 18:40:50 +02:00
										 |  |  | // Deprecated
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2020-03-25 00:07:41 +01:00
										 |  |  | // Usage:
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Initialization:
 | 
					
						
							|  |  |  | // ---------------
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // auto receiver = MakeReceiver<std:string>();
 | 
					
						
							| 
									
										
										
										
											2020-05-25 02:36:32 +02:00
										 |  |  | // auto sender_1= receiver->MakeSender();
 | 
					
						
							|  |  |  | // auto sender_2 = receiver->MakeSender();
 | 
					
						
							| 
									
										
										
										
											2020-03-25 00:07:41 +01:00
										 |  |  | //
 | 
					
						
							|  |  |  | // Then move the senders elsewhere, potentially in a different thread.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // On the producer side:
 | 
					
						
							|  |  |  | // ----------------------
 | 
					
						
							|  |  |  | // [thread 1] sender_1->Send("hello");
 | 
					
						
							|  |  |  | // [thread 2] sender_2->Send("world");
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // On the consumer side:
 | 
					
						
							|  |  |  | // ---------------------
 | 
					
						
							|  |  |  | // char c;
 | 
					
						
							|  |  |  | // while(receiver->Receive(&c)) // Return true as long as there is a producer.
 | 
					
						
							|  |  |  | //   print(c)
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Receiver::Receive() returns true when there are no more senders.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // clang-format off
 | 
					
						
							| 
									
										
										
										
											2025-08-16 18:40:50 +02:00
										 |  |  | // Deprecated:
 | 
					
						
							| 
									
										
										
										
											2020-03-25 00:07:41 +01:00
										 |  |  | template<class T> class SenderImpl; | 
					
						
							| 
									
										
										
										
											2025-08-16 18:40:50 +02:00
										 |  |  | // Deprecated:
 | 
					
						
							| 
									
										
										
										
											2020-03-25 00:07:41 +01:00
										 |  |  | template<class T> class ReceiverImpl; | 
					
						
							| 
									
										
										
										
											2025-08-16 18:40:50 +02:00
										 |  |  | // Deprecated:
 | 
					
						
							| 
									
										
										
										
											2021-05-01 20:40:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-16 18:40:50 +02:00
										 |  |  | // Deprecated:
 | 
					
						
							| 
									
										
										
										
											2020-03-25 00:07:41 +01:00
										 |  |  | template<class T> using Sender = std::unique_ptr<SenderImpl<T>>; | 
					
						
							| 
									
										
										
										
											2025-08-16 18:40:50 +02:00
										 |  |  | // Deprecated:
 | 
					
						
							| 
									
										
										
										
											2020-03-25 00:07:41 +01:00
										 |  |  | template<class T> using Receiver = std::unique_ptr<ReceiverImpl<T>>; | 
					
						
							| 
									
										
										
										
											2025-08-16 18:40:50 +02:00
										 |  |  | // Deprecated:
 | 
					
						
							| 
									
										
										
										
											2020-03-25 00:07:41 +01:00
										 |  |  | template<class T> Receiver<T> MakeReceiver(); | 
					
						
							|  |  |  | // clang-format on
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ---- Implementation part ----
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <class T> | 
					
						
							| 
									
										
										
										
											2025-08-16 18:40:50 +02:00
										 |  |  | // Deprecated:
 | 
					
						
							| 
									
										
										
										
											2020-03-25 00:07:41 +01:00
										 |  |  | class SenderImpl { | 
					
						
							|  |  |  |  public: | 
					
						
							| 
									
										
										
										
											2024-05-01 11:40:49 +02:00
										 |  |  |   SenderImpl(const SenderImpl&) = delete; | 
					
						
							|  |  |  |   SenderImpl(SenderImpl&&) = delete; | 
					
						
							|  |  |  |   SenderImpl& operator=(const SenderImpl&) = delete; | 
					
						
							|  |  |  |   SenderImpl& operator=(SenderImpl&&) = delete; | 
					
						
							| 
									
										
										
										
											2020-03-27 00:22:04 +01:00
										 |  |  |   void Send(T t) { receiver_->Receive(std::move(t)); } | 
					
						
							| 
									
										
										
										
											2020-03-27 01:42:46 +01:00
										 |  |  |   ~SenderImpl() { receiver_->ReleaseSender(); } | 
					
						
							| 
									
										
										
										
											2020-03-25 00:07:41 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-25 01:57:56 +02:00
										 |  |  |   Sender<T> Clone() { return receiver_->MakeSender(); } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-25 00:07:41 +01:00
										 |  |  |  private: | 
					
						
							|  |  |  |   friend class ReceiverImpl<T>; | 
					
						
							| 
									
										
										
										
											2024-05-01 11:40:49 +02:00
										 |  |  |   explicit SenderImpl(ReceiverImpl<T>* consumer) : receiver_(consumer) {} | 
					
						
							| 
									
										
										
										
											2020-03-27 00:22:04 +01:00
										 |  |  |   ReceiverImpl<T>* receiver_; | 
					
						
							| 
									
										
										
										
											2020-03-25 00:07:41 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <class T> | 
					
						
							|  |  |  | class ReceiverImpl { | 
					
						
							|  |  |  |  public: | 
					
						
							|  |  |  |   Sender<T> MakeSender() { | 
					
						
							| 
									
										
										
										
											2020-10-25 01:57:56 +02:00
										 |  |  |     std::unique_lock<std::mutex> lock(mutex_); | 
					
						
							| 
									
										
										
										
											2020-03-25 00:07:41 +01:00
										 |  |  |     senders_++; | 
					
						
							|  |  |  |     return std::unique_ptr<SenderImpl<T>>(new SenderImpl<T>(this)); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2024-05-01 11:40:49 +02:00
										 |  |  |   ReceiverImpl() = default; | 
					
						
							| 
									
										
										
										
											2020-03-25 00:07:41 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |   bool Receive(T* t) { | 
					
						
							| 
									
										
										
										
											2020-03-27 00:22:04 +01:00
										 |  |  |     while (senders_ || !queue_.empty()) { | 
					
						
							| 
									
										
										
										
											2020-03-25 00:07:41 +01:00
										 |  |  |       std::unique_lock<std::mutex> lock(mutex_); | 
					
						
							| 
									
										
										
										
											2024-05-01 11:40:49 +02:00
										 |  |  |       if (queue_.empty()) { | 
					
						
							| 
									
										
										
										
											2020-03-25 00:07:41 +01:00
										 |  |  |         notifier_.wait(lock); | 
					
						
							| 
									
										
										
										
											2024-05-01 11:40:49 +02:00
										 |  |  |       } | 
					
						
							|  |  |  |       if (queue_.empty()) { | 
					
						
							| 
									
										
										
										
											2020-03-25 00:07:41 +01:00
										 |  |  |         continue; | 
					
						
							| 
									
										
										
										
											2024-05-01 11:40:49 +02:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2020-03-25 00:07:41 +01:00
										 |  |  |       *t = std::move(queue_.front()); | 
					
						
							|  |  |  |       queue_.pop(); | 
					
						
							|  |  |  |       return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-18 21:29:27 +02:00
										 |  |  |   bool ReceiveNonBlocking(T* t) { | 
					
						
							|  |  |  |     std::unique_lock<std::mutex> lock(mutex_); | 
					
						
							| 
									
										
										
										
											2024-05-01 11:40:49 +02:00
										 |  |  |     if (queue_.empty()) { | 
					
						
							| 
									
										
										
										
											2022-10-18 21:29:27 +02:00
										 |  |  |       return false; | 
					
						
							| 
									
										
										
										
											2024-05-01 11:40:49 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-10-18 21:29:27 +02:00
										 |  |  |     *t = queue_.front(); | 
					
						
							|  |  |  |     queue_.pop(); | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-25 02:36:32 +02:00
										 |  |  |   bool HasPending() { | 
					
						
							|  |  |  |     std::unique_lock<std::mutex> lock(mutex_); | 
					
						
							|  |  |  |     return !queue_.empty(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-18 21:29:27 +02:00
										 |  |  |   bool HasQuitted() { | 
					
						
							|  |  |  |     std::unique_lock<std::mutex> lock(mutex_); | 
					
						
							|  |  |  |     return queue_.empty() && !senders_; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-25 00:07:41 +01:00
										 |  |  |  private: | 
					
						
							|  |  |  |   friend class SenderImpl<T>; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void Receive(T t) { | 
					
						
							| 
									
										
										
										
											2020-03-27 00:22:04 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |       std::unique_lock<std::mutex> lock(mutex_); | 
					
						
							|  |  |  |       queue_.push(std::move(t)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     notifier_.notify_one(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void ReleaseSender() { | 
					
						
							|  |  |  |     senders_--; | 
					
						
							| 
									
										
										
										
											2020-03-25 00:07:41 +01:00
										 |  |  |     notifier_.notify_one(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   std::mutex mutex_; | 
					
						
							|  |  |  |   std::queue<T> queue_; | 
					
						
							|  |  |  |   std::condition_variable notifier_; | 
					
						
							| 
									
										
										
										
											2024-05-01 11:40:49 +02:00
										 |  |  |   std::atomic<int> senders_{0}; | 
					
						
							| 
									
										
										
										
											2020-03-25 00:07:41 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template <class T> | 
					
						
							|  |  |  | Receiver<T> MakeReceiver() { | 
					
						
							|  |  |  |   return std::make_unique<ReceiverImpl<T>>(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }  // namespace ftxui
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #endif  // FTXUI_COMPONENT_RECEIVER_HPP_
 |