Hotfix/documentation updates (#1456)

* message_router and fsm documentation corrections

* message_router and fsm documentation corrections

* message_router and fsm documentation corrections

* Delete docs/Messaging/message-router.md

The folder is no longer valid.

---------

Co-authored-by: John Wellbelove <john.wellbelove@etlcpp.com>
This commit is contained in:
John Wellbelove 2026-06-08 08:58:47 +01:00 committed by GitHub
parent 4a88884b39
commit eed3d0b7b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 1332 additions and 24 deletions

23
docs/messaging/_index.md Normal file
View File

@ -0,0 +1,23 @@
---
title: "Messaging"
weight: 100
---
## Headers
- `message.h`
Defines the core message model. etl::imessage is the base interface (virtual or non-virtual, depending on `ETL_HAS_VIRTUAL_MESSAGES`). `etl::message<ID>` provides typed messages with static IDs. Type traits (`is_message`, `is_message_type`, etc.) and ID comparison utilities support compile-time validation.
- `message_router.h`
Defines `etl::imessage_router`, the central routing interface with receive, accepts, and router identity. Provides message_router<TDerived, ...> that statically dispatches by message ID (contiguous IDs optimized). Includes null_message_router and message_producer helpers, plus send_message utilities.
- `message_bus.h`
Implements `etl::imessage_bus`, a router that manages a sorted list of subscribed routers and forwards messages based on destination ID (broadcast or addressed). Supports subscription limits and forwards to successors.
- `message_broker.h`
Implements etl::message_broker, a router with explicit subscription objects mapping routers to message ID lists (span). It routes only to subscribers that match both message ID and destination ID, then forwards to any successor.
- `message_packet.h`
A type-erased, in-place container for a fixed set of message types. Validates message ID acceptance, supports copy/move, and exposes `get()` as `etl::imessage&`. Uses aligned storage sized to the largest message type.
- `shared_message.h`
Reference-counted wrapper around pooled messages (`ireference_counted_message_pool`). Supports copy/move semantics with automatic release when the last reference drops.
## Basic architecture
![message-framework](images/message-framework.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@ -0,0 +1,217 @@
---
title: "message_broker"
weight: 6
---
{{< callout type="info">}}
Header: `message_broker.h`
{{< /callout >}}
Message Broker
A variant of the observer pattern in that message routers and derived types are be able to subscribe to selected sets of messages. The message_broker is similar to the message_bus, but it provides more control over the routing of messages. While the message_bus simply broadcasts every message to all subscribers, the message_broker allows you to specify which subscribers should receive each message.
Derived from `imessage_router`.
## Types
```cpp
message_id_span_t etl::span<const etl::message_id_t>
```
## subscription
A nested class of `etl::message_broker`.
The base for broker subscription information.
Derive from this to define your subscription class.
See Example.
---
```cpp
subscription(etl::imessage_router& router)
```
Constructor.
---
```cpp
virtual message_id_span_t message_id_list() const = 0;
```
Override this to return a span of message ids.
## message_broker
```cpp
message_broker()
```
The broker is constructed with an id of `etl::imessage_router::MESSAGE_BROKER`.
---
```cpp
message_broker(etl::imessage_router& successor)
```
The broker is constructed with an id of `etl::imessage_router::MESSAGE_BROKER`.
Sets the successor.
---
```cpp
message_broker(etl::message_router_id_t id)
```
The broker is constructed with the specified id.
---
```cpp
message_broker(etl::message_router_id_t id, etl::imessage_router& successor)
```
The broker is constructed with the specified id.
Sets the successor.
---
```cpp
void subscribe(etl::imessage_router& router)
```
Subscribes an `etl::imessage_router` derived class to the broker.
A subscription object must have a lifetime of at least the same as the broker.
A subscription cannot be shared with another broker.
---
```cpp
void unsubscribe(etl::imessage_router& router)
```
Unsubscribes the specified `etl::imessage_router` derived class from the bus.
Does not unsubscribe from nested buses.
---
```cpp
void receive(const etl::imessage& message)
void receive(etl::shared_message message)
```
Receives a message and distributes it to all subscribers that have registered to receive the message type.
Forwards the message to any successor.
Override this in a derived class if you wish to capture messages sent to the broker.
Call the base receive function from here to allow normal operation to continue.
---
```cpp
bool accepts(etl::message_id_t id) const
```
Always returns `true`.
---
```cpp
void clear()
```
Clears the broker of all subscribers.
---
```cpp
ETL_DEPRECATED bool is_null_router() const ETL_OVERRIDE
```
Always returns `false`.
---
```cpp
bool is_producer() const ETL_OVERRIDE
```
Always returns `true`.
---
```cpp
bool is_consumer() const ETL_OVERRIDE
```
Always returns `true`.
---
```cpp
bool empty() const
```
Returns `true` is the are are no subscribers.
## Example
```cpp
// Some router ids.
enum
{
ROUTER_ID_1,
ROUTER_ID_2,
};
// Custom subscription type.
class Subscription : public etl::message_broker::subscription
{
public:
Subscription(etl::imessage_router& router, std::initializer_list<etl::message_id_t> id_list_)
: etl::message_broker::subscription(router)
, id_list(id_list_)
{
}
etl::message_broker::message_id_span_t message_id_list() const override
{
return etl::message_broker::message_id_span_t(id_list.begin(), id_list.end());
}
std::vector<etl::message_id_t> id_list;
};
// Instances of messages.
Message1 message1;
Message2 message2;
Message3 message3;
Message4 message4;
// Custom broker.
class Broker : public etl::message_broker
{
public:
using etl::message_broker::receive;
// Hook incoming messages and translate Message4 to Message3.
void receive(const etl::imessage& msg) override
{
if (msg.get_message_id() == Message4::ID)
{
etl::message_broker::receive(Message3());
}
else
{
etl::message_broker::receive(msg);
}
}
};
// Instances of message routers.
Router1 router1;
Router2 router2;
// The subscriptions.
Subscription subscription1{ router1, { Message1::ID, Message2::ID } };
Subscription subscription2{ router2, { Message2::ID, Message3::ID } };
// Instance of message broker.
etl::message_broker broker;
// Subscribe router1 and router1 to the broker.
broker.subscribe(subscription1);
broker.subscribe(subscription2);
broker.receive(message1); // Received by router1
broker.receive(message2); // Received by router1 and router2
broker.receive(message3); // Received by router2
broker.receive(message4); // Received by router2 as a Message3
```

View File

@ -0,0 +1,207 @@
---
title: "message_bus"
weight: 5
---
{{< callout type="info">}}
Header: `message_broker.h`
From: `20.33.0`
{{< /callout >}}
Message Bus
This page documents version `20.0.0` and above.
A variant of the observer pattern in that message routers and derived types are be able to subscribe to messages on a bus. The messages can be either broadcast, to be automatically picked up by any router that has a handler, or addressed to a particular router or router id. Message buses may be nested by setting a successor.
## imessage_bus
Derived from imessage_router.
The base for all message buses.
Inherits publicly from `etl::imessage_router`.
Message buses are therefore also a type of router.
Objects of type `etl::imessage_bus` cannot be directly constructed.
## Member functions
```cpp
bool subscribe(etl::imessage_router& router)
```
Subscribes an `etl::imessage_router` derived class to the bus.
Returns `true` on success.
---
```cpp
void unsubscribe(etl::imessage_router& router)
```
Unsubscribes the specified `etl::imessage_router` derived class from the bus.
Does not unsubscribe from nested buses.
---
```cpp
void unsubscribe(etl::message_router_id_t id)
```
Unsubscribes routers with the specified id from the bus.
Does not unsubscribe from nested buses.
`etl::imessage::MESSAGE_BUS` will unsubscribe all message buses.
`etl::imessage::ALL_MESSAGE_ROUTERS` will unsubscribe all routers and buses. Equivalent to calling `clear()`.
---
```cpp
void receive(const etl::imessage& message)
void receive(etl::shared_message message)
```
Receives a message and distributes it to all subscribers.
Forwards the message to any successor.
The routers are called first, in order of ascending router id.
Routers with the duplicate ids will be called in subscribe order.
Any nested message buses are called in subscribe order.
---
```cpp
void receive(etl::message_router_id_t destination_router_id,
const etl::imessage& message);
void receive(etl::message_router_id_t destination_router_id,
etl::shared_message message)
```
Receives a message and distributes it to all subscribers that have the specified router id.
Forwards the message to any successor.
Routers with the duplicate ids will be called in subscribe order.
Any nested message buses are called in subscribe order.
Override this in a derived class if you wish to capture messages sent to the bus.
Call the base receive function from here to allow normal operation to continue.
---
```cpp
bool accepts(etl::message_id_t id) const
```
Always returns `true`.
---
```cpp
size_t size() const
```
Returns the number of subscribers.
---
```cpp
void clear()
```
Clears the bus of all subscribers.
Message buses inherit all of the public functions of `etl::imessage_router`.
## Errors
```cpp
message_bus_exception
```
Base error class for `etl::message_bus`. Inherits from `etl::exception`.
---
```cpp
message_bus_too_many_subscribers
```
Emitted when the number of subscribers exceeds the capacity. Inherits from `etl::message_bus_exception`.
## message_bus
Derived from `imessage_bus`.
```cpp
template <const uint_least8_t MAX_ROUTERS>
class message_bus
```
`MAX_ROUTERS` The maximum number of routers that can be subscribed.
## Member functions
```cpp
message_bus()
```
Constructs a message bus.
Message buses always have a router id of `etl::imessage::MESSAGE_BUS`.
```cpp
message_bus(etl::imessage_router& successor)
```
Constructs a message bus and sets the successor.
Message buses always have a router id of `etl::imessage::MESSAGE_BUS`.
## Example
```cpp
// Some router ids.
enum
{
ROUTER_ID_1,
ROUTER_ID_2,
ROUTER_ID_3
};
// Instances of messages.
MessageA messageA;
// Instances of message routers.
RouterA routerA(ROUTER_ID_1);
RouterB routerB(ROUTER_ID_1);
RouterC routerC(ROUTER_ID_2);
RouterD routerD(ROUTER_ID_3);
RouterE routerE(ROUTER_ID_1);
// Instances of message buses.
etl::message_bus<4> bus1;
etl::message_bus<2> bus2;
etl::message_bus<1> bus3;
// Subscribe bus2 & bus3 to bus1.
bus1.subscribe(bus3);
bus1.subscribe(bus2);
// Subscribe routerB & routerA to bus1.
bus1.subscribe(routerB);
bus1.subscribe(routerA);
// Subscribe routerD & routerC to bus2.
bus2.subscribe(routerD);
bus2.subscribe(routerC);
// Subscribe routerE to bus3.
bus3.subscibe(routerE);
// Assume all routers accept the same messages.
// Broadcast messageA to everyone.
bus1.receive(messageA);
// The call order will be...
// routerB
// routerA
// routerE
// routerC
// routerD
// Address messageA to routers with id ROUTER_ID_1.
bus1.receive(ROUTER_ID_1, messageA);
// The call order will be...
// routerB
// routerA
// routerE
// Address messageA to routers with id ROUTER_ID_3.
bus1.receive(ROUTER_ID_3, messageA);
// The call order will be...
// routerD
```

View File

@ -0,0 +1,155 @@
---
title: "message_packet"
---
{{< callout type="info">}}
Header: `message_packet.h`
{{< /callout >}}
A container for more than one type of message.
The messages must have been derived from `etl::imessage`.
The messages types that the packet may contain are listed as template parameters.
e.g. `etl::message_packet<Message1, Message2, Message3>`
From `20.40.0` message types are not required to have a virtual destructor.
---
```cpp
message_packet()
```
Default constructs a message packet.
`is_valid()` returns `false`.
---
```cpp
explicit message_packet(const etl::imessage&)
```
Constructs a message packet from an `etl::imessage` reference.
Asserts an `etl::unhandled_message_exception` error if the parameter is not one listed in the template parameter list.
---
```cpp
explicit message_packet(etl::imessage&&) C++11
```
Move constructs a message packet from an `etl::imessage` rvalue reference.
Emits an `etl::unhandled_message_exception` error if the parameter is not one listed in the template parameter list.
---
```cpp
template <typename TMessage>
explicit message_packet(const TMessage&)
```
Constructs a message packet from a `TMessage` reference.
Emits a compile time static assert if the parameter is not one listed in the template parameter list.
From: `20.22.0`
---
```cpp
template <typename TMessage>
explicit message_packet(TMessage&&)
```
Move constructs a message packet from a `TMessage` rvalue reference.
Emits a compile time static assert if the parameter is not one listed in the template parameter list.
From: `20.22.0`
---
```cpp
message_packet(const message_packet&)
```
Constructs a message packet from an `message_packet` reference.
Emits an `etl::unhandled_message_exception` error if the parameter is not one listed in the template parameter list.
---
```cpp
message_packet(message_packet&&)
```
Move constructs a message packet from an `message_packet` rvalue reference.
Emits an `etl::unhandled_message_exception` if the parameter is not one listed in the template parameter list.
---
```cpp
message_packet& operator =(const message_packet&)
```
Assigns a message packet from an `message_packet` reference.
Emits an `etl::unhandled_message_exception` error if the parameter is not one listed in the template parameter list.
---
```cpp
message_packet& operator =(message_packet&&)
```
Move assigns a message packet from an `message_packet` rvalue reference.
Emits an `etl::unhandled_message_exception` error if the parameter is not one listed in the template parameter list.
---
```cpp
etl::imessage& get()
const etl::imessage& get() const
```
Returns a reference to an `etl::imessage`.
---
```cpp
bool is_valid() const
```
Returns `true` if the packet contains a valid message, otherwise `false`.
---
## Constants
`SIZE` The size of the largest message.
`ALIGNMENT` The largest message alignment.
---
## Example
```cpp
enum
{
MESSAGE1,
MESSAGE2,
MESSAGE3
};
struct Message1 : public etl::message<MESSAGE1>
{
};
struct Message2 : public etl::message<MESSAGE2>
{
};
struct Message3 : public etl::message<MESSAGE3>
{
};
using Packet = etl::message_packet<Message1, Message2>
Message1 message1;
Message2 message2;
Message3 message3;
Packet packet1(message1);
Packet packet2(message2);
Packet packet3(message3); // Runtime time error! Packet does not support Message3 type.
etl::imessage& m1 = message1;
Packet packet4(m1); // Construct from an etl::imessage reference.
etl::imessage& m3 = message3;
Packet packet4(m3); // Asserts etl::unhandled_message_exception! Packet does not support Message3 type.
etl::imessage& m = packet2.get(); // Get a reference to an etl::imessage from the packet.
```

View File

@ -0,0 +1,180 @@
---
title: "message_router_registry"
weight: 4
---
{{< callout type="info">}}
Header: `message_router_registry`
From: `20.6.0`
{{< /callout >}}
A class that will act as a registry for all message router types.
When iterating through the registry, routers with identical IDs are ordered by insertion.
**Defines the following classes**
```cpp
etl::imessage_router_registry
etl::message_router_registry
```
## imessage_router_registry
The base class for all router registries.
### Iterators
```cpp
iterator
const_iterator
```
### Member functions
```cpp
iterator begin()
const_iterator begin() const
const_iterator cbegin() const
```
Get the beginning of the registry.
---
```cpp
iterator end()
const_iterator end() const
const_iterator cend() const
```
Get the end of the registry.
---
```cpp
iterator lower_bound(etl::message_router_id_t id)
const_iterator lower_bound(etl::message_router_id_t id) const
```
Get the lower bound in the registry of the router with the specified ID.
---
```cpp
iterator upper_bound(etl::message_router_id_t id)
const_iterator upper_bound(etl::message_router_id_t id) const
```
Get the upper bound in the registry of the router with the specified ID.
---
```cpp
etl::imessage_router* find(etl::message_router_id_t id)
const etl::imessage_router* find(etl::message_router_id_t id) const
```
Returns a pointer to the first router with the specified ID, or `ETL_NULLPTR` if it cannot be found.
---
```cpp
void add(etl::imessage_router& router)
void add(etl::imessage_router* p_router)
```
Registers a router.
If the registry is full then an ETL assert is emitted (`etl::message_router_registry_full`).
Duplicate routers will be ignored.
---
```cpp
template <typename TIterator>
void add(TIterator first, const TIterator& last)
```
Registers a collection of routers.
If the registry becomes full then an ETL assert is emitted (`etl::message_router_registry_full`).
Duplicate routers will be ignored.
---
```cpp
void remove(etl::message_router_id_t id)
```
Unregisters a router.
---
```cpp
bool contains(const etl::message_router_id_t id) const
bool contains(const etl::imessage_router* const p_router) const
bool contains(const etl::imessage_router& router) const
```
Returns `true` if the registry contains a router that has the specified ID or object.
---
```cpp
bool empty() const
```
Returns `true` if the registry is empty, otherwise `false`.
---
```cpp
bool full() const
```
Returns `true` if the registry is full, otherwise `false`.
---
```cpp
size_t size() const
```
Returns the size of the registry.
---
```cpp
size_t available() const
```
Returns the available size of the registry.
---
```cpp
size_t max_size() const
```
Returns the maximum size of the registry.
---
## message_router_registry
```cpp
message_router_registry()
```
Default constructor.
---
```cpp
template <typename TIterator>
message_router_registry(TIterator first, const TIterator& last)
```
Constructs from an iterator range.
---
```cpp
message_router_registry(std::initializer_list<etl::imessage_router*> init)
```
Initializer_list constructor.
Enabled for C++11 or above.
---
```cpp
message_router_registry(const message_router_registry& rhs)
```
Copy constructor.
---
```cpp
message_router_registry& operator =(const message_router_registry& rhs)
```
Assignment operator.

View File

@ -3,7 +3,7 @@ title: message_router
weight: 3
---
A class that will automatically route incoming messages to specific handlers based on the message types declared in the template parameter list. Messages are passed to the receive member function which will static cast it to its real type and call the matching on_receive function in the derived class. A compilation error will occur if the matching on_receive does not exist.
A class that will automatically route incoming messages to specific handlers based on the message types declared in the template parameter list. Messages are passed to the receive member function which will static cast it to its real type and call the matching `on_receive` function in the derived class. A compilation error will occur if the matching `on_receive` does not exist.
The `on_receive` functions are not virtual. The template base class uses `CRTP` to directly call the derived class's functions.
@ -26,25 +26,25 @@ Note: A message router 'group' is deemed to be a set of routers with identical I
The default router id is `etl::imessage_router::MESSAGE_ROUTER`.
### Scenario 1
You never send a message to a router using it's ID.
You never use the ID to uniquely identify a router.
You do not require the router ID to act as a priority level when subscribing to a message bus.
You do not require that messages can be sent to a group.
- You never send a message to a router using it's ID.
- You never use the ID to uniquely identify a router.
- You do not require the router ID to act as a priority level when subscribing to a message bus.
- You do not require that messages can be sent to a group.
All message router IDs can be identical.
### Scenario 2
You never use the ID to uniquely identify a router.
You may use the router ID to send to a particular router group.
You require the router ID to act as a priority level when subscribing to a message bus.
- You never use the ID to uniquely identify a router.
- You may use the router ID to send to a particular router group.
- You require the router ID to act as a priority level when subscribing to a message bus.
Router IDs will be assigned in groups. i.e. Some routers may share IDs.
### Scenario 3
You use the ID to uniquely identify a router.
You use the router ID to send to a particular router.
You require the router ID to act as a priority level when subscribing to a message bus.
You require all priority levels to be unique.
- You use the ID to uniquely identify a router.
- You use the router ID to send to a particular router.
- You require the router ID to act as a priority level when subscribing to a message bus.
- You require all priority levels to be unique.
All router IDs are unique
@ -117,7 +117,7 @@ Returns the router id.
```cpp
virtual bool is_null_router() const = 0;
```
Returns `true` if the router is a null message router, otherwise `false`.
Returns `true` if the router is a null message router, otherwise `false`.
**Deprecated. **
---
@ -154,7 +154,7 @@ MAX_MESSAGE_ROUTER
## message_router
User defined message routers are derived from this class.
Derived from `## imessage_router`.
Derived from `imessage_router`.
---
@ -168,11 +168,12 @@ template <typename TDerived,
class message_router
```
**Template parameters**
`TDerived` The derived class.
`T1` The first message type.
`T2...` The additional message types.
The maximum number of types can be set by running the generator for this file.
The default is 16.This may be changed by running a modified version of generate_message_router.bat.
`TDerived` The derived class.
`T1` The first message type.
`T2...` The additional message types.
The maximum number of types can be set by running the generator for this file.
The default is 16.This may be changed by running a modified version of generate_message_router.bat.
See [Generators](../tutorials/generators-tutorial)
---
@ -191,12 +192,10 @@ This definition will automatically be selected if the compiler supports C++17 or
To use the older C++03 compatible definition, define `ETL_MESSAGE_ROUTER_FORCE_CPP03` as a project setting or in the optional `etl_profile.h`.
**Since: 20.47.0**
This definition will automatically be selected if the compiler supports C++11 or above. It uses either an O(1) or O(N) mechanism to resolve `on_receive()` calls.
This definition will automatically be selected if the compiler supports C++11 or above. It uses either an O(1) or O(logN) mechanism to resolve `on_receive()` calls.
To use the older C++03 compatible definition, define `ETL_MESSAGE_ROUTER_FORCE_CPP03` as a project setting or in the optional `etl_profile.h`.
---
The derived class must define the following member functions.
### The derived class must define the following member functions.
```cpp
void on_receive(const Type& msg);

112
docs/messaging/message.md Normal file
View File

@ -0,0 +1,112 @@
---
title: "message"
weight: 1
---
{{< callout type="info">}}
Header: `message.h`
{{< /callout >}}
Message types used for many of the framework classes.
---
```cpp
etl::message_id_t
```
The type used for message ids.
By default can hold a value between 0 and 255.
If `ETL_MESSAGE_ID_TYPE` is defined then this type will be used instead.
---
```cpp
etl::message_router_id_t
```
The type used for message router ids.
Can hold a value between 0 and 255.
---
The message classes are the common communication method across all of the message capable frameworks.
They are identified by a unique id number that specialises the base class.
## imessage
The base class for messages.
It is this class that is passed around, usually by const reference.
The class is abstract.
---
```cpp
etl::message_id_t get_message_id() const ETL_NOEXCEPT = 0;
```
Returns the id of the message.
---
## message
```cpp
message<size_t ID, typename TParent = etl::imessage>
```
Requires an integral id as the template parameter.
Inherits from `TParent`, which defaults to `etl::imessage`.
`TParent` allows additional base interfaces or functionality to be included.
static asserts if `TParent` is not a base of `etl::imessage`.
---
```cpp
ID
```
The id of the message as an enum.
Can be accessed by `etl::message` instances.
---
```cpp
TParent
```
The class that it inherits from. It must ultimately derive from `etl::imessage`.
The default is `etl::imessage`.
---
## Example
```cpp
enum
{
START,
STOP,
SET_SPEED
};
struct MyInterface : public etl::imessage
{
virtual void DoStuff() = 0;
};
// Start implements MyIterface
struct Start : public etl::message<START, MyInterface>
{
void DoStuff() override
{
// Do stuff here.
}
};
struct Stop : public etl::message<STOP>
{
bool isEmergencyStop;
};
struct SetSpeed : public etl::message<SET_SPEED>
{
uint32_t speed;
};
void Receive(const etl::imessage& msg);
```

View File

@ -0,0 +1,139 @@
---
title: "reference_counted_message_pool"
---
{{< callout type="info">}}
Header: `reference_counted_message_pool.h`
Header: `ireference_counted_message_pool.h`
{{< /callout >}}
Allocates `etl::ireference_counted_message` types that are used by `etl::shared_message`.
Uses a supplied `memory_block allocator` derived from `etl::imemory_block_allocator`.
## ireference_counted_message_pool.h
Defines the following class.
`etl::ireference_counted_message_pool`
## reference_counted_message_pool.h
Defines the following classes.
`etl::reference_counted_message_pool_exception`
`etl::reference_counted_message_pool_allocation_failure`
`etl::reference_counted_message_pool_release_failure`
## ireference_counted_message_pool
```cpp
etl::ireference_counted_message_pool
```
The interface for reference counted message pools.
```cpp
virtual ~ireference_counted_message_pool() {}
```
```cpp
virtual void release(const etl::ipool_message& msg) = 0;
```
Virtual `lock()` and `unlock()` functions are defined. The default action is to do nothing.
A derived class may override these functions to provide a thread or interrupt safe pool.
`virtual void lock()`
`virtual void unlock()`
## reference_counted_message_pool
```cpp
etl::reference_counted_message_pool<TCounter>
```
The concrete reference counted message pool.
```cpp
reference_counted_message_pool(imemory_block_allocator& memory_block_allocator)
```
Constructs the pool and assigns the memory block allocator to it.
---
```cpp
template <typename TMessage>
etl::reference_counted_message<TMessage, TCounter>* allocate()
```
Returns a pointer to a pool message that holds a `TMessage`.
The message is default constructed.
ETL_ASSERT if one cannot be allocated and returns `ETL_NULLPTR`.
---
```cpp
template <typename TMessage>
etl::reference_counted_message<TMessage, TCounter>* allocate(const TMessage& message)
```
Returns a pointer to a pool message that holds a `TMessage`.
ETL_ASSERT if one cannot be allocated and returns `ETL_NULLPTR`.
---
```cpp
void release(const etl::ireference_counted_message& rcmessage)
```
Returns the reference counted to a pool message that holds a `TMessage`.
`ETL_ASSERT` if it cannot be released. Reasons can include the message not belonging to the pool.
## pool_message_parameters
**C++03**
The C++03 version defines the largest size and alignment of up to 8 types at a time.
```cpp
template <typename TMessage1, typename TMessage2 = TMessage1,
typename TMessage3 = TMessage1, typename TMessage4 = TMessage1,
typename TMessage5 = TMessage1, typename TMessage6 = TMessage1,
typename TMessage7 = TMessage1, typename TMessage8 = TMessage1>
struct pool_message_parameters
```
---
```cpp
static const size_t max_size;
```
The maximum size.
---
```cpp
static const size_t max_alignment;
```
The maximum alignment.
**C++11 or above**
The C++11 version defines the largest size and alignment of a set of message types.
```cpp
template <typename TMessage1, typename... TMessages>
struct pool_message_parameters
```
---
```cpp
static constexpr size_t max_size
```
The maximum size.
---
```cpp
static constexpr size_t max_alignment;
```
The maximum alignment.
---
**For C++11, with atomic support.**
```cpp
template <typename TObject>
using atomic_counted_message_pool = etl::reference_counted_message_pool<etl::atomic_int32_t>;
```
Defines an alias to a reference counted message pool that uses an atomic.

View File

@ -0,0 +1,197 @@
---
title: "reference_counted_message"
---
{{< callout type="info">}}
Header: `reference_counted_message.h`
{{< /callout >}}
Reference counted message types that are used by `etl::shared_message`.
**Defines the following classes**
```cpp
etl::ireference_counted_message
```
The interface of all reference counted message types.
---
```cpp
etl::reference_counted_message<typename TMessage, typename TCounter>
```
Derived from `etl::ireference_counted_message`.
```cpp
etl::persistent_message<typename TMessage>
```
Derived from `etl::ireference_counted_message`.
## ireference_counted_message
```cpp
etl::ireference_counted_message
```
The interface of all reference counted message types.
---
```cpp
virtual ~ireference_counted_message()
```
---
```cpp
ETL_NODISCARD virtual etl::imessage& get_message() = 0;
```
Get a reference to the message.
---
```cpp
ETL_NODISCARD virtual const etl::imessage& get_message() const = 0;
```
Get a const reference to the message.
---
```cpp
ETL_NODISCARD virtual etl::ireference_counter& get_reference_counter() = 0;
```
Get a reference to the reference counter.
---
```cpp
ETL_NODISCARD virtual const etl::ireference_counter& get_reference_counter() const = 0;
```
Get a const reference to the reference counter.
---
```cpp
virtual void release() = 0;
```
Release back to the owner.
## reference_counted_message
```cpp
etl::reference_counted_message<typename TMessage, typename TCounter>
```
The implementation of reference counted messages owned by a pool.
Will static assert if TMessage is no derived from etl::imessage.
---
```cpp
reference_counted_message(const TMessage& message, etl::ireference_counted_message_pool& owner)
```
Constructs from a message and the pool from which the reference counted message is allocated.
The message is copied.
---
```cpp
reference_counted_message(etl::ireference_counted_message_pool& owner)
```
Constructs from a message and the pool from which the reference counted message is allocated.
The message is default constructed.
---
```cpp
ETL_NODISCARD TMessage& get_message() ETL_OVERRIDE
```
Get a reference to the message.
---
```cpp
ETL_NODISCARD const TMessage& get_message() const ETL_OVERRIDE
```
Get a const reference to the message.
---
```cpp
ETL_NODISCARD etl::ireference_counter& get_reference_counter() ETL_OVERRIDE
```
Get a reference to the reference counter.
---
```cpp
ETL_NODISCARD const etl::ireference_counter& get_reference_counter() const ETL_OVERRIDE
```
Get a const reference to the reference counter.
---
```cpp
void release() ETL_OVERRIDE
```
Release back to the owner pool.
## persistent_message
```cpp
etl::persistent_message<typename TMessage>
```
The implementation of reference counted messages not owned by a pool.
It's counter type is `void`.
Will static assert if `TMessage` is not derived from `etl::imessage`.
---
```cpp
persistent_message(const TMessage& message)
```
Constructs from a message.
The message is copied.
---
```cpp
ETL_NODISCARD TMessage& get_message() ETL_OVERRIDE
```
Get a reference to the message.
---
```cpp
ETL_NODISCARD const TMessage& get_message() const ETL_OVERRIDE
```
Get a const reference to the message.
---
```cpp
ETL_NODISCARD etl::ireference_counter& get_reference_counter() ETL_OVERRIDE
```
Get a reference to the reference counter.
---
```cpp
ETL_NODISCARD const etl::ireference_counter& get_reference_counter() const ETL_OVERRIDE
```
Get a const reference to the reference counter.
---
```cpp
void release() ETL_OVERRIDE
```
Does nothing for a persistent message.
## For C++11, with atomic support.
```cpp
template <typename TMessage>
using atomic_counted_message = etl::reference_counted_message<TMessage, etl::atomic_int32_t>;
```
Defines an alias to a reference counted message that uses an atomic.

View File

@ -0,0 +1,79 @@
---
title: "shared_message"
weight: 2
---
{{< callout type="info">}}
Header: `shared_message.h`
{{< /callout >}}
Shared Messages
The type used to encapsulate reference counted messages.
Shared messages are usually passed by value.
See the Shared Message Tutorial
---
```cpp
template <typename TPool, typename TMessage>
shared_message(TPool& owner, const TMessage& message)
```
Static asserts if `TPool` is not derived from `etl::ireference_counted_message_pool`
Static asserts if `TMessage` not derived from `etl::imessage`.
Requires that `TPool` implements the following member function to allocate from the pool.
```cpp
template <typename TMessage>
etl::ireference_counted_message* allocate(const TMessage& message)
```
---
```cpp
explicit shared_message(etl::ireference_coutnted_message& message)
```
Construct from a reference counted message.
---
```cpp
shared_message(const etl::shared_message& other)
```
Copy constructor.
---
```cpp
shared_message& operator =(const etl::shared_message& other)
```
Assignment operator.
---
```cpp
~shared_message()
```
Destructor.
---
```cpp
ETL_NODISCARD etl::imessage& get_message()
```
Gets a reference to the contained message.
---
```cpp
ETL_NODISCARD const etl::imessage& get_message() const
```
Gets a const reference to the contained message.
---
```cpp
ETL_NODISCARD uint32_t get_reference_count() const
```
Gets the current reference count for this shared message.

View File

@ -10,7 +10,7 @@ This page documents version `20.0.0` and above.
A finite state machine driven by the reception of events (messages) . The incoming messages will be automatically routed to specific handlers based on the message list defined in the template parameters. Optional on_entry and on_exit handlers are available.
This FSM is slightly more involved to set up than the traditional simple table driven method, but provides great flexibility in implementation. It may also be faster due to the fact that all messages are routed with either O(1) or O(N) rather than scanning a lookup table and calling indirectly through function pointers.
This FSM is slightly more involved to set up than the traditional simple table driven method, but provides great flexibility in implementation. It may also be faster due to the fact that all messages are routed with either O(1) or O(logN). O(1) is selected if the event IDs are contiguous.
The `on_event` functions are not virtual. The template class uses [CRTP](https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern) to directly call the derived class's functions.