Commit b97717bc authored by Dominik Charousset's avatar Dominik Charousset

Add message::concat

parent a7d8a39c
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <atomic> #include <atomic>
#include <cstdlib> #include <cstdlib>
#include <new>
#include "caf/byte.hpp" #include "caf/byte.hpp"
#include "caf/config.hpp" #include "caf/config.hpp"
...@@ -60,6 +61,8 @@ public: ...@@ -60,6 +61,8 @@ public:
message_data* copy() const; message_data* copy() const;
static intrusive_ptr<message_data> make_uninitialized(type_id_list types);
// -- reference counting ----------------------------------------------------- // -- reference counting -----------------------------------------------------
/// Increases reference count by one. /// Increases reference count by one.
...@@ -124,9 +127,53 @@ public: ...@@ -124,9 +127,53 @@ public:
init_impl(storage(), std::forward<Ts>(xs)...); 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: private:
void init_impl(byte*) { void init_impl(byte*) {
// nop // End of recursion.
} }
template <class T, class... Ts> template <class T, class... Ts>
...@@ -137,6 +184,16 @@ private: ...@@ -137,6 +184,16 @@ private:
init_impl(storage + padded_size_v<type>, std::forward<Ts>(xs)...); 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_; mutable std::atomic<size_t> rc_;
type_id_list types_; type_id_list types_;
size_t constructed_elements_; size_t constructed_elements_;
......
...@@ -57,6 +57,17 @@ public: ...@@ -57,6 +57,17 @@ public:
message& operator=(const message&) noexcept = default; 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 ------------------------------------------------------------- // -- properties -------------------------------------------------------------
auto types() const noexcept { auto types() const noexcept {
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "caf/detail/comparable.hpp" #include "caf/detail/comparable.hpp"
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/detail/implicit_conversions.hpp"
#include "caf/span.hpp" #include "caf/span.hpp"
#include "caf/type_id.hpp" #include "caf/type_id.hpp"
...@@ -125,6 +126,14 @@ constexpr type_id_list make_type_id_list() { ...@@ -125,6 +126,14 @@ constexpr type_id_list make_type_id_list() {
/// @relates type_id_list /// @relates type_id_list
CAF_CORE_EXPORT std::string to_string(type_id_list xs); 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
namespace caf::detail { namespace caf::detail {
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "caf/detail/meta_object.hpp" #include "caf/detail/meta_object.hpp"
#include "caf/error.hpp" #include "caf/error.hpp"
#include "caf/error_code.hpp" #include "caf/error_code.hpp"
#include "caf/message.hpp"
#include "caf/raise_error.hpp" #include "caf/raise_error.hpp"
#include "caf/sec.hpp" #include "caf/sec.hpp"
#include "caf/span.hpp" #include "caf/span.hpp"
...@@ -75,6 +76,19 @@ message_data* message_data::copy() const { ...@@ -75,6 +76,19 @@ message_data* message_data::copy() const {
return ptr.release(); 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 { byte* message_data::at(size_t index) noexcept {
if (index == 0) if (index == 0)
return storage(); return storage();
...@@ -95,4 +109,23 @@ const byte* message_data::at(size_t index) const noexcept { ...@@ -95,4 +109,23 @@ const byte* message_data::at(size_t index) const noexcept {
return ptr; 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 } // namespace caf::detail
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "caf/detail/meta_object.hpp" #include "caf/detail/meta_object.hpp"
#include "caf/detail/type_id_list_builder.hpp" #include "caf/detail/type_id_list_builder.hpp"
#include "caf/message.hpp"
namespace caf { namespace caf {
...@@ -62,4 +63,8 @@ type_id_list type_id_list::concat(span<type_id_list> lists) { ...@@ -62,4 +63,8 @@ type_id_list type_id_list::concat(span<type_id_list> lists) {
return builder.move_to_list(); return builder.move_to_list();
} }
type_id_list types_of(const message& msg) {
return msg.types();
}
} // namespace caf } // namespace caf
...@@ -135,3 +135,15 @@ CAF_TEST(match_elements exposes element types) { ...@@ -135,3 +135,15 @@ CAF_TEST(match_elements exposes element types) {
CAF_CHECK((msg.match_element<int64_t>(2))); CAF_CHECK((msg.match_element<int64_t>(2)));
CAF_CHECK((msg.match_elements<put_atom, string, int64_t>())); 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