Skip to content

Commit

Permalink
adding shared_context to easily operate bus and loop pair.
Browse files Browse the repository at this point in the history
* adding context example.
* updating readme.
  • Loading branch information
alkavan committed Aug 31, 2024
1 parent 308c686 commit 09d981e
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 6 deletions.
38 changes: 32 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

The `microbus` namespace provides a simple yet efficient event-bus and event-loop implementation in C++17.
This library includes classes to manage subscriptions, event notifications, and asynchronous event processing.
The bus component can be used in a simple subscribe/trigger scenario, or, in a complex multi-threading scenario.

## Key Features

- **Thread-Safe**: Both `event_bus` and `event_loop` classes use mutexes to ensure thread-safety.
- **Type Erasure**: Handlers are type-erased, allowing storage of various callable objects in a unified manner.
- **Asynchronous Processing**: Events can be processed asynchronously using the `event_loop` class.
- **Automatic Cleanup**: Event handlers are automatically cleaned up when unsubscribed or when the event bus is cleared.
- **Flexible Subscription Management**: Supports multiple subscribers per event and manages them using unique subscription IDs.
- **Context Helper Class**: Helps operate the bus and loop pair in common application use-cases.

## Overview

Expand Down Expand Up @@ -39,13 +49,29 @@ This class manages the processing of asynchronous events. It runs an internal th
- **wait_until_finished**: Blocks until all events in the queue are processed.
- **stop**: Stops the event loop and joins the internal thread.

## Key Features
### `shared_context`

- **Thread-Safe**: Both `event_bus` and `event_loop` classes use mutexes to ensure thread-safety.
- **Type Erasure**: Handlers are type-erased, allowing storage of various callable objects in a unified manner.
- **Asynchronous Processing**: Events can be processed asynchronously using the `event_loop` class.
- **Automatic Cleanup**: Event handlers are automatically cleaned up when unsubscribed or when the event bus is cleared.
- **Flexible Subscription Management**: Supports multiple subscribers per event and manages them using unique subscription IDs.
This class is optional, it helps to operate the bus nad loop pair
in common development scenarios.
It allows subscribing and queuing event as well as operating the loop.

```cpp
#include "microbus.hpp"
#include <iostream>

using my_event_handler = microbus::event_bus::event_handler<int>;
auto context = microbus::shared_context();

int on_number_id = context.subscribe("OnNumber", (my_event_handler)[](int number) {
auto result = factorial(number);
std::cout << "Number " << number << " was passed to event." << std::endl;
});
context.enqueue_event("OnNumber", 69);

context.wait_until_finished();
context.unsubscribe("OnNumber", on_number_id);
context.stop();
```

## Example Usage

Expand Down
15 changes: 15 additions & 0 deletions src/examples.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,21 @@ int main() {
event_loop.stop();

shared_event_bus->clear();

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Shared event bus and event loop context example
using my_event_handler = microbus::event_bus::event_handler<int>;
auto context = microbus::shared_context();

int on_number_id = context.subscribe("OnNumber", (my_event_handler)[](int number) {
auto result = factorial(number);
std::cout << "Number " << number << " was passed to event." << std::endl;
});
context.enqueue_event("OnNumber", 69);

context.wait_until_finished();
context.unsubscribe("OnNumber", on_number_id);
context.stop();
}

static int64_t factorial(int n) {
Expand Down
82 changes: 82 additions & 0 deletions src/microbus.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,88 @@ namespace microbus {
}
}
};

/**
* @class shared_context
* @brief A context that wraps around an event bus and event loop for managing event-based communication.
*/
class shared_context
{
private:
std::shared_ptr<microbus::event_bus> bus_; ///< Shared pointer to the event bus
microbus::event_loop loop_; ///< Event loop instance

template <typename... Args>
using event_handler = std::function<void(Args...)>;

public:
/**
* @brief Constructs a shared_context with an optional event bus.
*
* @param bus Shared pointer to an event bus. If nullptr, a new event bus is created.
*/
explicit shared_context(const std::shared_ptr<microbus::event_bus>& bus = nullptr)
: bus_(bus ? bus : std::make_shared<microbus::event_bus>()) {
}

/**
* @brief Gets the current event bus.
*
* @return Shared pointer to the event bus.
*/
[[nodiscard]] std::shared_ptr<microbus::event_bus> get_bus() const {
return bus_;
}

/**
* @brief Subscribes to an event with a specified handler.
*
* @tparam Args Types of arguments that the event handler takes.
* @param event_name Name of the event to subscribe to.
* @param handler Function to handle the event.
* @return Subscription ID.
*/
template <typename... Args>
int subscribe(const std::string& event_name, event_handler<Args...> handler) {
return bus_->subscribe(event_name, handler);
}

/**
* @brief Unsubscribes from an event.
* @param event_name The name of the event.
* @param id The subscription ID.
*/
void unsubscribe(const std::string& event_name, int id) {
bus_->unsubscribe(event_name, id);
}

/**
* @brief Enqueues an event to be processed by the event loop.
*
* @tparam Args Types of arguments that the event handler takes.
* @param event_name Name of the event.
* @param params Parameters to pass to the event handler.
*/
template <typename... Args>
void enqueue_event(const std::string& event_name, Args&&... params)
{
loop_.enqueue_event(bus_, event_name, std::forward<Args>(params)...);
}

/**
* @brief Waits until the event loop has finished processing all events.
*/
void wait_until_finished() {
loop_.wait_until_finished();
}

/**
* @brief Stops the internal event loop.
*/
void stop() {
loop_.stop();
}
};
}

#endif //MICROBUS_MICROBUS_HPP

0 comments on commit 09d981e

Please sign in to comment.