SObjectizer 5.8
Loading...
Searching...
No Matches
so_5::message_holder_t< Msg, Ownership > Class Template Reference

A class for holding an instance of a message. More...

#include <message_holder.hpp>

Inheritance diagram for so_5::message_holder_t< Msg, Ownership >:

Public Types

using payload_type = typename base_type::payload_type
 
using envelope_type = typename base_type::envelope_type
 

Public Member Functions

template<typename... Args>
 message_holder_t (std::piecewise_construct_t, Args &&...args)
 

Static Public Member Functions

template<typename... Args>
static message_holder_t make (Args &&...args)
 Create a new instance of message_holder with a new message inside.
 

Private Types

using base_type
 

Static Private Member Functions

template<typename... Args>
static intrusive_ptr_t< envelope_typemake_msg_instance (Args &&...args)
 Create a new instance of message.
 

Friends

void swap (message_holder_t &a, message_holder_t &b) noexcept
 

Detailed Description

template<typename Msg, message_ownership_t Ownership = message_ownership_t::autodetected>
class so_5::message_holder_t< Msg, Ownership >

A class for holding an instance of a message.

Attention
This class should be used with messages only. Signals are not supported by that class.

This class is intended for simplification of holding message instances for some time and resending them later. For example:

class my_actor final : public so_5::agent_t {
// A stored message.
...
void on_message(mhood_t<my_message> cmd) {
// Store message inside the agent.
stored_ = cmd.make_holder();
...
// Initiate a delayed message to resend the stored message later.
}
...
void on_resend_message(mhood_t<resend_message>) {
// Resend the stored message.
so_5::send(some_target, stored_);
// The stored message is no more needed.
stored_.reset();
// Or we can write:
// so_5::send(some_target, std::move(stored_));
}
};
A base class for agents.
Definition agent.hpp:673
A class for holding an instance of a message.
A message wrapped to be used as type of argument for event handlers.
Definition mhood.hpp:570
void send(Target &&to, Args &&... args)
A utility function for creating and delivering a message or a signal.
void send_delayed(Target &&target, std::chrono::steady_clock::duration pause, Args &&... args)
A utility function for creating and delivering a delayed message to the specified destination.

This class is also intended to be used with preallocated messages:

class prealloc_msg_demo final : public so_5::agent_t {
...
prealloc_msg_demo(
context_t ctx,
... // Some other params.
) : request_{std::piecewise_construct, ...} // Preallocation of message.
{}
void on_some_event(...) {
...
// It is time to send preallocated message.
so_5::send(some_target, request_);
...
}
};
so_5::agent_context_t context_t
Short alias for agent_context.
Definition agent.hpp:692

The main benefit of that class is the ability to correctly handle messages of arbitrary user types (e.g. messages not derived from so_5::message_t class) and mutability flags. For example, the following cases are correctly handled by message_holder_t:

struct status_data { // This is message that is not derived from so_5::message_t.
... // Some fields.
};

This is an example of how immutable and mutable preallocated messages can be used with message_holder_t:

class preallocated_messages_owner final : public so_5::agent_t {
...
void on_some_event(mhood_t<some_event>) {
// It is time to send preallocated messages.
// This message will be sent as immutable message.
so_5::send(dest, first_);
// This message will be sent as mutable message.
so_5::send(dest, std::move(second_));
}
};
Methods of message_holder_t class

Class message_holder_t provides the following methods:

// Default constructor. Creates an empty holder.
// Constructs holder for holding the specified message instance.
message_holder_t(so_5::intrusive_ptr<envelope_type> msg);
// Creates a new instance of message from 'args' and constructs holder for it.
template<typename... Args>
message_holder_t(std::piecewise_construct_t, Args && ...args);
// Creates a new instance of message from 'args' and constructs holder for it.
template<typename... Args>
static message_holder_t make(Args && ...args);
// Returns true if message_holder is empty.
bool empty() const noexcept;
bool operator!() const noexcept;
// Returns true if message_holder is not empty.
operator bool() const noexcept;
// Drops the content of message_holder.
void reset() noexcept;
static message_holder_t make(Args &&...args)
Create a new instance of message_holder with a new message inside.
message_holder_t(std::piecewise_construct_t, Args &&...args)

There are also some more methods which are depend on mutability of message and the type of ownership. They are described below.

Getters are depend on mutability of message

If a message_holder holds an immutable message then there are the following getter methods:

const payload_type * get() const noexcept;
const payload_type & operator*() const noexcept;
const payload_type * operator->() const noexcept;
typename base_type::payload_type payload_type

But if message_holder holds a mutable message those getters are still here but they have non-const return type:

payload_type * get() const noexcept;
payload_type & operator*() const noexcept;
payload_type * operator->() const noexcept;
Shared and unique ownership

A message_holder works like a smart pointer. But what kind of smart pointer?

It depends on Ownership template parameters.

But default Ownership is so_5::message_ownership_t::autodetected. In this case the behavior of a message_holder depends of the mutability of message. If message is immutable then message_holders is like std::shared_ptr: several message_holders can hold pointers to the same message instances.

If message is mutable then message_holder is like std::unique_ptr: only one message_holder can hold a pointer to a message instance.

For example:

// Immutable message.
so_5::message_holder_t<my_msg> msg1{std::piecewise_construct, ...};
assert(msg1.get() == msg2.get()); // Now msg1 and msg2 refer to the same msg.
// Mutable message.
so_5::message_holder_t<so_5::mutable_msg<my_msg>> msg4{ msg3 }; // WON'T COMPILE!
assert(msg3.empty()); // Now msg3 is empty.
assert(!msg5.empty()); // And only msg5 holds the message.

The value of Ownership parameter can be specified manually. In that case we can have an unique-holder for an immutable message:

There can also be a shared-holder for a mutable message:

But this approach should be taken with an additional care because it allows to make several sends of the same mutable message instances at the same time.

If a message_holder works as std::shared_ptr then there is the following methods:

// Copy constructor and operator.
message_holder_t & operator=(const message_holder_t &) noexcept;
// Move constructor and operator.
message_holder_t & operator=(message_holder_t &&) noexcept;
// Getter for the underlying smart pointer.
intrusive_ptr_t<envelope_type> make_reference() const noexcept;
Template class for smart reference wrapper on the atomic_refcounted_t.
typename base_type::envelope_type envelope_type

If a message_holder works as std::unique_ptr then copy operator/constructors are disabled and make_reference() leaves the message_holder object empty:

// Move constructor and operator.
message_holder_t & operator=(message_holder_t &&) noexcept;
// Extracts the underlying smart pointer.
// Leaves the message_holder object empty.
intrusive_ptr_t<envelope_type> make_reference() noexcept;
Creation of an instance of message to be stored inside a message_holder

There are several ways of creation of a message to be stored inside a message_holder object.

The recommended way is to use the constructor of message_holder with std::piecewise_construct_t argument. This constructor automatically creates an underlying message instance:

struct my_msg {
int a_;
std::string b_;
};
so_5::message_holder_t<my_msg> msg{std::piecewise_construct,
0, // value for my_msg's a_ field.
"hello" // value for my_msg's b_ field.
};

Sometimes a static method make() can be used for similar purpose:

auto make_message() {
}

But sometimes an instance of message is present as raw pointer, std::unique_ptr or so_5::intrusive_ptr_t objects. In that case the constructor that accepts intrusive_ptr_t can be used:

// Somewhere in 3rd-party library.
std::unique_ptr<some_message> make_message() {
return std::make_unique<some_message>(...);
}
// Somewhere in your code.
Since
v.5.6.0
Examples
so_5/chameneos_prealloc_msgs/main.cpp, so_5/make_pipeline/main.cpp, so_5/mchain_fibonacci/main.cpp, so_5/prio_work_stealing/main.cpp, and so_5/simple_message_deadline/main.cpp.

Definition at line 599 of file message_holder.hpp.

Member Typedef Documentation

◆ base_type

template<typename Msg , message_ownership_t Ownership = message_ownership_t::autodetected>
using so_5::message_holder_t< Msg, Ownership >::base_type
private
Initial value:
details::message_holder_details::accessor_selector_t<
typename impl_selector< Msg, Ownership >::type impl_selector_t
Just a shortcut for impl_selector meta-function.
static const constexpr message_mutability_t mutability
Definition message.hpp:403

Definition at line 604 of file message_holder.hpp.

◆ envelope_type

template<typename Msg , message_ownership_t Ownership = message_ownership_t::autodetected>
using so_5::message_holder_t< Msg, Ownership >::envelope_type = typename base_type::envelope_type

Definition at line 613 of file message_holder.hpp.

◆ payload_type

template<typename Msg , message_ownership_t Ownership = message_ownership_t::autodetected>
using so_5::message_holder_t< Msg, Ownership >::payload_type = typename base_type::payload_type

Definition at line 612 of file message_holder.hpp.

Constructor & Destructor Documentation

◆ message_holder_t()

template<typename Msg , message_ownership_t Ownership = message_ownership_t::autodetected>
template<typename... Args>
so_5::message_holder_t< Msg, Ownership >::message_holder_t ( std::piecewise_construct_t ,
Args &&... args )
inline

Special constructor for constructing message_holder with a new message instance inside.

Usage example:

struct my_message {
int a_;
std::string b_;
std::chrono::millisecons c_;
};
so_5::message_holder_t<my_message> msg{ std::piecewise_construct,
0, // value for my_message's a_ field.
"hello", // value for my_message's b_ field.
15s // value for my_message's c_ field.
};

Definition at line 636 of file message_holder.hpp.

Member Function Documentation

◆ make()

template<typename Msg , message_ownership_t Ownership = message_ownership_t::autodetected>
template<typename... Args>
static message_holder_t so_5::message_holder_t< Msg, Ownership >::make ( Args &&... args)
inlinestaticnodiscard

Create a new instance of message_holder with a new message inside.

Usage example:

struct my_message {
int a_;
std::string b_;
std::chrono::millisecons c_;
};
auto make_message() {
0, // value for my_message's a_ field.
"hello", // value for my_message's b_ field.
15s ); // value for my_message's c_ field.
}

Definition at line 670 of file message_holder.hpp.

◆ make_msg_instance()

template<typename Msg , message_ownership_t Ownership = message_ownership_t::autodetected>
template<typename... Args>
static intrusive_ptr_t< envelope_type > so_5::message_holder_t< Msg, Ownership >::make_msg_instance ( Args &&... args)
inlinestaticnodiscardprivate

Create a new instance of message.

Definition at line 680 of file message_holder.hpp.

Friends And Related Symbol Documentation

◆ swap

template<typename Msg , message_ownership_t Ownership = message_ownership_t::autodetected>
void swap ( message_holder_t< Msg, Ownership > & a,
message_holder_t< Msg, Ownership > & b )
friend

Definition at line 643 of file message_holder.hpp.


The documentation for this class was generated from the following file: