Unverified Commit c6815ed0 authored by Noir's avatar Noir Committed by GitHub

Merge pull request #1191

Add message::concat function
parents f259fbb6 b97717bc
...@@ -5,8 +5,6 @@ ...@@ -5,8 +5,6 @@
#include <cstdint> #include <cstdint>
#include <type_traits> #include <type_traits>
#include "caf/detail/type_traits.hpp"
#pragma once #pragma once
namespace caf { namespace caf {
...@@ -15,31 +13,31 @@ namespace caf { ...@@ -15,31 +13,31 @@ namespace caf {
enum class byte : uint8_t {}; enum class byte : uint8_t {};
template <class IntegerType, template <class IntegerType,
class = detail::enable_if_tt<std::is_integral<IntegerType>>> class = std::enable_if_t<std::is_integral<IntegerType>::value>>
constexpr IntegerType to_integer(byte x) noexcept { constexpr IntegerType to_integer(byte x) noexcept {
return static_cast<IntegerType>(x); return static_cast<IntegerType>(x);
} }
template <class IntegerType, template <class IntegerType,
class E = detail::enable_if_tt<std::is_integral<IntegerType>>> class E = std::enable_if_t<std::is_integral<IntegerType>::value>>
constexpr byte& operator<<=(byte& x, IntegerType shift) noexcept { constexpr byte& operator<<=(byte& x, IntegerType shift) noexcept {
return x = static_cast<byte>(to_integer<uint8_t>(x) << shift); return x = static_cast<byte>(to_integer<uint8_t>(x) << shift);
} }
template <class IntegerType, template <class IntegerType,
class E = detail::enable_if_tt<std::is_integral<IntegerType>>> class E = std::enable_if_t<std::is_integral<IntegerType>::value>>
constexpr byte operator<<(byte x, IntegerType shift) noexcept { constexpr byte operator<<(byte x, IntegerType shift) noexcept {
return static_cast<byte>(to_integer<uint8_t>(x) << shift); return static_cast<byte>(to_integer<uint8_t>(x) << shift);
} }
template <class IntegerType, template <class IntegerType,
class E = detail::enable_if_tt<std::is_integral<IntegerType>>> class E = std::enable_if_t<std::is_integral<IntegerType>::value>>
constexpr byte& operator>>=(byte& x, IntegerType shift) noexcept { constexpr byte& operator>>=(byte& x, IntegerType shift) noexcept {
return x = static_cast<byte>(to_integer<uint8_t>(x) >> shift); return x = static_cast<byte>(to_integer<uint8_t>(x) >> shift);
} }
template <class IntegerType, template <class IntegerType,
class E = detail::enable_if_tt<std::is_integral<IntegerType>>> class E = std::enable_if_t<std::is_integral<IntegerType>::value>>
constexpr byte operator>>(byte x, IntegerType shift) noexcept { constexpr byte operator>>(byte x, IntegerType shift) noexcept {
return static_cast<byte>(static_cast<unsigned char>(x) >> shift); return static_cast<byte>(static_cast<unsigned char>(x) >> shift);
} }
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,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"
...@@ -46,6 +47,8 @@ public: ...@@ -46,6 +47,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.
...@@ -110,9 +113,53 @@ public: ...@@ -110,9 +113,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>
...@@ -123,6 +170,16 @@ private: ...@@ -123,6 +170,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_;
......
...@@ -12,8 +12,6 @@ ...@@ -12,8 +12,6 @@
#include "caf/detail/type_pair.hpp" #include "caf/detail/type_pair.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/none.hpp" #include "caf/none.hpp"
#include "caf/type_id.hpp"
#include "caf/type_id_list.hpp"
#include "caf/unit.hpp" #include "caf/unit.hpp"
namespace caf::detail { namespace caf::detail {
...@@ -36,21 +34,6 @@ struct strip_param<param<T>> { ...@@ -36,21 +34,6 @@ struct strip_param<param<T>> {
using type = T; using type = T;
}; };
template <class List>
struct to_type_id_list_helper;
template <class... Ts>
struct to_type_id_list_helper<type_list<Ts...>> {
static constexpr type_id_list get() {
return make_type_id_list<typename strip_param<Ts>::type...>();
}
};
template <class List>
constexpr type_id_list to_type_id_list() {
return to_type_id_list_helper<List>::get();
}
/// Denotes the empty list. /// Denotes the empty list.
using empty_type_list = type_list<>; using empty_type_list = type_list<>;
......
...@@ -130,7 +130,6 @@ class string_view; ...@@ -130,7 +130,6 @@ class string_view;
class tracing_data; class tracing_data;
class tracing_data_factory; class tracing_data_factory;
class type_id_list; class type_id_list;
class type_id_list_builder;
class uri; class uri;
class uri_builder; class uri_builder;
class uuid; class uuid;
......
...@@ -43,6 +43,17 @@ public: ...@@ -43,6 +43,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 {
......
...@@ -11,6 +11,8 @@ ...@@ -11,6 +11,8 @@
#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/type_id.hpp" #include "caf/type_id.hpp"
namespace caf { namespace caf {
...@@ -78,6 +80,17 @@ public: ...@@ -78,6 +80,17 @@ public:
/// type-erased tuple for the element types stored in this list. /// type-erased tuple for the element types stored in this list.
size_t data_size() const noexcept; size_t data_size() const noexcept;
/// Concatenates all `lists` into a single type ID list.
static type_id_list concat(span<type_id_list> lists);
/// Concatenates all `lists` into a single type ID list.
template <class... Ts>
static type_id_list
concat(type_id_list list1, type_id_list list2, Ts... lists) {
type_id_list arr[] = {list1, list2, lists...};
return concat(arr);
}
private: private:
pointer data_; pointer data_;
}; };
...@@ -99,6 +112,14 @@ constexpr type_id_list make_type_id_list() { ...@@ -99,6 +112,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 {
...@@ -118,4 +139,19 @@ type_id_list make_argument_type_id_list() { ...@@ -118,4 +139,19 @@ type_id_list make_argument_type_id_list() {
return argument_type_id_list_factory<F>::make(); return argument_type_id_list_factory<F>::make();
} }
template <class List>
struct to_type_id_list_helper;
template <class... Ts>
struct to_type_id_list_helper<type_list<Ts...>> {
static constexpr type_id_list get() {
return make_type_id_list<typename strip_param<Ts>::type...>();
}
};
template <class List>
constexpr type_id_list to_type_id_list() {
return to_type_id_list_helper<List>::get();
}
} // namespace caf::detail } // namespace caf::detail
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,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"
...@@ -48,18 +49,30 @@ message_data* message_data::copy() const { ...@@ -48,18 +49,30 @@ message_data* message_data::copy() const {
auto vptr = malloc(total_size); auto vptr = malloc(total_size);
if (vptr == nullptr) if (vptr == nullptr)
CAF_RAISE_ERROR(std::bad_alloc, "bad_alloc"); CAF_RAISE_ERROR(std::bad_alloc, "bad_alloc");
auto ptr = new (vptr) message_data(types_); intrusive_ptr<message_data> ptr{new (vptr) message_data(types_), false};
auto src = storage(); auto src = storage();
auto dst = ptr->storage(); auto dst = ptr->storage();
for (auto id : types_) { for (auto id : types_) {
auto& meta = gmos[id]; auto& meta = gmos[id];
// TODO: exception handling.
meta.copy_construct(dst, src); meta.copy_construct(dst, src);
++ptr->constructed_elements_; ++ptr->constructed_elements_;
src += meta.padded_size; src += meta.padded_size;
dst += meta.padded_size; dst += meta.padded_size;
} }
return ptr; 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 {
...@@ -82,4 +95,23 @@ const byte* message_data::at(size_t index) const noexcept { ...@@ -82,4 +95,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
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#include "caf/type_id_list.hpp" #include "caf/type_id_list.hpp"
#include "caf/detail/meta_object.hpp" #include "caf/detail/meta_object.hpp"
#include "caf/detail/type_id_list_builder.hpp"
#include "caf/message.hpp"
namespace caf { namespace caf {
...@@ -35,4 +37,20 @@ std::string to_string(type_id_list xs) { ...@@ -35,4 +37,20 @@ std::string to_string(type_id_list xs) {
return result; return result;
} }
type_id_list type_id_list::concat(span<type_id_list> lists) {
auto total_size = size_t{0};
for (auto ls : lists)
total_size += ls.size();
detail::type_id_list_builder builder;
builder.reserve(total_size);
for (auto ls : lists)
for (auto id : ls)
builder.push_back(id);
return builder.move_to_list();
}
type_id_list types_of(const message& msg) {
return msg.types();
}
} // namespace caf } // namespace caf
...@@ -121,3 +121,15 @@ CAF_TEST(match_elements exposes element types) { ...@@ -121,3 +121,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}));
}
...@@ -45,3 +45,35 @@ CAF_TEST(type ID lists are convertible to strings) { ...@@ -45,3 +45,35 @@ CAF_TEST(type ID lists are convertible to strings) {
auto xs = make_type_id_list<uint16_t, bool, float, long double>(); auto xs = make_type_id_list<uint16_t, bool, float, long double>();
CAF_CHECK_EQUAL(to_string(xs), "[uint16_t, bool, float, ldouble]"); CAF_CHECK_EQUAL(to_string(xs), "[uint16_t, bool, float, ldouble]");
} }
CAF_TEST(type ID lists are concatenable) {
// 1 + 0
CHECK_EQ((make_type_id_list<int8_t>()),
type_id_list::concat(make_type_id_list<int8_t>(),
make_type_id_list<>()));
CHECK_EQ((make_type_id_list<int8_t>()),
type_id_list::concat(make_type_id_list<>(),
make_type_id_list<int8_t>()));
// 1 + 1
CHECK_EQ((make_type_id_list<int8_t, int16_t>()),
type_id_list::concat(make_type_id_list<int8_t>(),
make_type_id_list<int16_t>()));
// 2 + 0
CHECK_EQ((make_type_id_list<int8_t, int16_t>()),
type_id_list::concat(make_type_id_list<int8_t, int16_t>(),
make_type_id_list<>()));
CHECK_EQ((make_type_id_list<int8_t, int16_t>()),
type_id_list::concat(make_type_id_list<>(),
make_type_id_list<int8_t, int16_t>()));
// 2 + 1
CHECK_EQ((make_type_id_list<int8_t, int16_t, int32_t>()),
type_id_list::concat(make_type_id_list<int8_t, int16_t>(),
make_type_id_list<int32_t>()));
CHECK_EQ((make_type_id_list<int8_t, int16_t, int32_t>()),
type_id_list::concat(make_type_id_list<int8_t>(),
make_type_id_list<int16_t, int32_t>()));
// 2 + 2
CHECK_EQ((make_type_id_list<int8_t, int16_t, int32_t, int64_t>()),
type_id_list::concat(make_type_id_list<int8_t, int16_t>(),
make_type_id_list<int32_t, int64_t>()));
}
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