Commit b97717bc authored by Dominik Charousset's avatar Dominik Charousset

Add message::concat

parent a7d8a39c
......@@ -20,6 +20,7 @@
#include <atomic>
#include <cstdlib>
#include <new>
#include "caf/byte.hpp"
#include "caf/config.hpp"
......@@ -60,6 +61,8 @@ public:
message_data* copy() const;
static intrusive_ptr<message_data> make_uninitialized(type_id_list types);
// -- reference counting -----------------------------------------------------
/// Increases reference count by one.
......@@ -124,9 +127,53 @@ public:
init_impl(storage(), std::forward<Ts>(xs)...);
}
byte* stepwise_init(byte* pos) {
return pos;
}
template <class T, class... Ts>
byte* stepwise_init(byte* pos, T&& x, Ts&&... xs) {
using type = strip_and_convert_t<T>;
new (pos) type(std::forward<T>(x));
++constructed_elements_;
return stepwise_init(pos + padded_size_v<type>, std::forward<Ts>(xs)...);
}
byte* stepwise_init_from(byte* pos, const message& msg);
byte* stepwise_init_from(byte* pos, const message_data* other);
template <class Tuple, size_t... Is>
byte* stepwise_init_from(byte* pos, Tuple&& tup, std::index_sequence<Is...>) {
return stepwise_init(pos, std::get<Is>(std::forward<Tuple>(tup))...);
}
template <class... Ts>
byte* stepwise_init_from(byte* pos, std::tuple<Ts...>&& tup) {
return stepwise_init_from(pos, std::move(tup),
std::make_index_sequence<sizeof...(Ts)>{});
}
template <class... Ts>
byte* stepwise_init_from(byte* pos, std::tuple<Ts...>& tup) {
return stepwise_init_from(pos, tup,
std::make_index_sequence<sizeof...(Ts)>{});
}
template <class... Ts>
byte* stepwise_init_from(byte* pos, const std::tuple<Ts...>& tup) {
return stepwise_init_from(pos, tup,
std::make_index_sequence<sizeof...(Ts)>{});
}
template <class... Ts>
void init_from(Ts&&... xs) {
init_from_impl(storage(), std::forward<Ts>(xs)...);
}
private:
void init_impl(byte*) {
// nop
// End of recursion.
}
template <class T, class... Ts>
......@@ -137,6 +184,16 @@ private:
init_impl(storage + padded_size_v<type>, std::forward<Ts>(xs)...);
}
void init_from_impl(byte*) {
// End of recursion.
}
template <class T, class... Ts>
void init_from_impl(byte* pos, T&& x, Ts&&... xs) {
init_from_impl(stepwise_init_from(pos, std::forward<T>(x)),
std::forward<Ts>(xs)...);
}
mutable std::atomic<size_t> rc_;
type_id_list types_;
size_t constructed_elements_;
......
......@@ -57,6 +57,17 @@ public:
message& operator=(const message&) noexcept = default;
// -- concatenation ----------------------------------------------------------
template <class... Ts>
static message concat(Ts&&... xs) {
static_assert(sizeof...(Ts) >= 2);
auto types = type_id_list::concat(types_of(xs)...);
auto ptr = detail::message_data::make_uninitialized(types);
ptr->init_from(std::forward<Ts>(xs)...);
return message{data_ptr{ptr.release(), false}};
}
// -- properties -------------------------------------------------------------
auto types() const noexcept {
......
......@@ -25,6 +25,7 @@
#include "caf/detail/comparable.hpp"
#include "caf/detail/core_export.hpp"
#include "caf/detail/implicit_conversions.hpp"
#include "caf/span.hpp"
#include "caf/type_id.hpp"
......@@ -125,6 +126,14 @@ constexpr type_id_list make_type_id_list() {
/// @relates type_id_list
CAF_CORE_EXPORT std::string to_string(type_id_list xs);
/// @relates type_id_list
CAF_CORE_EXPORT type_id_list types_of(const message& msg);
template <class... Ts>
type_id_list types_of(const std::tuple<Ts...>&) {
return make_type_id_list<detail::strip_and_convert_t<Ts>...>();
}
} // namespace caf
namespace caf::detail {
......
......@@ -24,6 +24,7 @@
#include "caf/detail/meta_object.hpp"
#include "caf/error.hpp"
#include "caf/error_code.hpp"
#include "caf/message.hpp"
#include "caf/raise_error.hpp"
#include "caf/sec.hpp"
#include "caf/span.hpp"
......@@ -75,6 +76,19 @@ message_data* message_data::copy() const {
return ptr.release();
}
intrusive_ptr<message_data>
message_data::make_uninitialized(type_id_list types) {
auto gmos = global_meta_objects();
size_t storage_size = 0;
for (auto id : types)
storage_size += gmos[id].padded_size;
auto total_size = sizeof(message_data) + storage_size;
auto vptr = malloc(total_size);
if (vptr == nullptr)
CAF_RAISE_ERROR(std::bad_alloc, "bad_alloc");
return {new (vptr) message_data(types), false};
}
byte* message_data::at(size_t index) noexcept {
if (index == 0)
return storage();
......@@ -95,4 +109,23 @@ const byte* message_data::at(size_t index) const noexcept {
return ptr;
}
byte* message_data::stepwise_init_from(byte* pos, const message& msg) {
return stepwise_init_from(pos, msg.cptr());
}
byte* message_data::stepwise_init_from(byte* pos, const message_data* other) {
CAF_ASSERT(other != nullptr);
CAF_ASSERT(other != this);
auto gmos = global_meta_objects();
auto src = other->storage();
for (auto id : other->types()) {
auto& meta = gmos[id];
meta.copy_construct(pos, src);
++constructed_elements_;
src += meta.padded_size;
pos += meta.padded_size;
}
return pos;
}
} // namespace caf::detail
......@@ -20,6 +20,7 @@
#include "caf/detail/meta_object.hpp"
#include "caf/detail/type_id_list_builder.hpp"
#include "caf/message.hpp"
namespace caf {
......@@ -62,4 +63,8 @@ type_id_list type_id_list::concat(span<type_id_list> lists) {
return builder.move_to_list();
}
type_id_list types_of(const message& msg) {
return msg.types();
}
} // namespace caf
......@@ -135,3 +135,15 @@ CAF_TEST(match_elements exposes element types) {
CAF_CHECK((msg.match_element<int64_t>(2)));
CAF_CHECK((msg.match_elements<put_atom, string, int64_t>()));
}
CAF_TEST(messages are concatenable) {
using std::make_tuple;
CHECK(message::concat(make_tuple(int16_t{1}), make_tuple(uint8_t{2}))
.matches(int16_t{1}, uint8_t{2}));
CHECK(message::concat(make_message(int16_t{1}), make_message(uint8_t{2}))
.matches(int16_t{1}, uint8_t{2}));
CHECK(message::concat(make_message(int16_t{1}), make_tuple(uint8_t{2}))
.matches(int16_t{1}, uint8_t{2}));
CHECK(message::concat(make_tuple(int16_t{1}), make_message(uint8_t{2}))
.matches(int16_t{1}, uint8_t{2}));
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment