mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2025-09-15 23:48:15 +08:00
Add a Producer/Consumer system.
It allow you to create the two end of a pipe: A producer and consumer. The producer can be moved into another thread. Several producer can be created if necessary. This will ease merging: https://github.com/ArthurSonzogni/FTXUI/pull/11
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <ftxui/component/producer_consumer.hpp>
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
@@ -20,7 +21,7 @@ struct Event {
|
||||
static Event Character(const std::string&);
|
||||
static Event Special(const std::string&);
|
||||
|
||||
static Event GetEvent(std::function<char()> getchar);
|
||||
static void Convert(Consumer<char>& in, Producer<Event>& out, char c);
|
||||
|
||||
// --- Arrow ---
|
||||
static Event ArrowLeft;
|
||||
|
101
include/ftxui/component/producer_consumer.hpp
Normal file
101
include/ftxui/component/producer_consumer.hpp
Normal file
@@ -0,0 +1,101 @@
|
||||
#ifndef FTXUI_COMPONENTS_CONSUMER_PRODUCER_H_
|
||||
#define FTXUI_COMPONENTS_CONSUMER_PRODUCER_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
// Usage:
|
||||
//
|
||||
// Initialization:
|
||||
// ---------------
|
||||
//
|
||||
// auto consumer = MakeConsumer<std:string>();
|
||||
// auto producer_1 = consumer.MakeProducer();
|
||||
// auto producer_2 = consumer.MakeProducer();
|
||||
//
|
||||
// Then move one producers elsewhere, potentially in a different thread.
|
||||
// ----------------------
|
||||
// [thread 1] producer_1->Send("hello");
|
||||
// [thread 2] producer_2->Send("world");
|
||||
//
|
||||
// On the consumer side:
|
||||
// ---------------------
|
||||
// char c;
|
||||
// while(consumer_->Receive(&c)) // Return true as long as there is a producer.
|
||||
// print(c)
|
||||
//
|
||||
// Consumer::Receive returns true when the last Producer is released.
|
||||
|
||||
// clang-format off
|
||||
template<class T> class ProducerImpl;
|
||||
template<class T> class ConsumerImpl;
|
||||
template<class T> using Producer = std::unique_ptr<ProducerImpl<T>>;
|
||||
template<class T> using Consumer = std::unique_ptr<ConsumerImpl<T>>;
|
||||
template<class T> Consumer<T> MakeConsumer();
|
||||
// clang-format on
|
||||
|
||||
// ---- Implementation part ----
|
||||
|
||||
template <class T>
|
||||
class ProducerImpl {
|
||||
public:
|
||||
void Send(T t) { consumer_->Receive(std::move(t)); }
|
||||
~ProducerImpl() { consumer_->producers_--; }
|
||||
|
||||
private:
|
||||
friend class ConsumerImpl<T>;
|
||||
ProducerImpl(ConsumerImpl<T>* consumer) : consumer_(consumer) {}
|
||||
ConsumerImpl<T>* consumer_;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class ConsumerImpl {
|
||||
public:
|
||||
Producer<T> MakeProducer() {
|
||||
producers_++;
|
||||
return std::unique_ptr<ProducerImpl<T>>(new ProducerImpl<T>(this));
|
||||
}
|
||||
|
||||
bool Receive(T* t) {
|
||||
while (producers_) {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
while (queue_.empty())
|
||||
notifier_.wait(lock);
|
||||
if (queue_.empty())
|
||||
continue;
|
||||
*t = std::move(queue_.front());
|
||||
queue_.pop();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ProducerImpl<T>;
|
||||
|
||||
void Receive(T t) {
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
queue_.push(std::move(t));
|
||||
notifier_.notify_one();
|
||||
}
|
||||
|
||||
std::mutex mutex_;
|
||||
std::queue<T> queue_;
|
||||
std::condition_variable notifier_;
|
||||
std::atomic<int> producers_ = 0;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
Consumer<T> MakeConsumer() {
|
||||
return std::make_unique<ConsumerImpl<T>>();
|
||||
}
|
||||
|
||||
} // namespace ftxui
|
||||
|
||||
#endif // FTXUI_COMPONENTS_CONSUMER_PRODUCER_H_
|
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "ftxui/component/event.hpp"
|
||||
#include "ftxui/screen/screen.hpp"
|
||||
#include <ftxui/component/producer_consumer.hpp>
|
||||
|
||||
namespace ftxui {
|
||||
class Component;
|
||||
@@ -40,13 +41,13 @@ class ScreenInteractive : public Screen {
|
||||
Dimension dimension_ = Dimension::Fixed;
|
||||
ScreenInteractive(int dimx, int dimy, Dimension dimension);
|
||||
|
||||
std::condition_variable events_queue_cv;
|
||||
std::mutex events_queue_mutex;
|
||||
std::queue<Event> events_queue;
|
||||
std::atomic<bool> quit_ = false;
|
||||
Producer<Event> event_producer_;
|
||||
Consumer<Event> event_consumer_;
|
||||
|
||||
std::string set_cursor_position;
|
||||
std::string reset_cursor_position;
|
||||
|
||||
std::atomic<bool>quit_ = false;
|
||||
};
|
||||
|
||||
} // namespace ftxui
|
||||
|
Reference in New Issue
Block a user