Commit e74fd805 authored by Dominik Charousset's avatar Dominik Charousset

Merge pull request #1085

parents 65f2dc01 7e38a24f
...@@ -276,6 +276,7 @@ caf_add_test_suites(caf-core-test ...@@ -276,6 +276,7 @@ caf_add_test_suites(caf-core-test
mailbox_element mailbox_element
make_config_value_field make_config_value_field
message message
message_builder
message_id message_id
message_lifetime message_lifetime
metaprogramming metaprogramming
......
...@@ -45,12 +45,10 @@ public: ...@@ -45,12 +45,10 @@ public:
type_id_t operator[](size_t index) const noexcept; type_id_t operator[](size_t index) const noexcept;
/// Convertes the internal buffer to a ::type_id_list and returns it. /// Convertes the internal buffer to a ::type_id_list and returns it.
/// @pre `push_back` was called at least once type_id_list move_to_list() noexcept;
type_id_list move_to_list();
/// Convertes the internal buffer to a ::type_id_list and returns it. /// Convertes the internal buffer to a ::type_id_list and returns it.
/// @pre `push_back` was called at least once type_id_list copy_to_list() const;
type_id_list copy_to_list();
void clear() noexcept { void clear() noexcept {
if (storage_) if (storage_)
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "caf/detail/core_export.hpp" #include "caf/detail/core_export.hpp"
#include "caf/detail/implicit_conversions.hpp" #include "caf/detail/implicit_conversions.hpp"
#include "caf/detail/message_builder_element.hpp" #include "caf/detail/message_builder_element.hpp"
#include "caf/detail/padded_size.hpp"
#include "caf/detail/type_id_list_builder.hpp" #include "caf/detail/type_id_list_builder.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/message.hpp" #include "caf/message.hpp"
...@@ -61,6 +62,7 @@ public: ...@@ -61,6 +62,7 @@ public:
using namespace detail; using namespace detail;
using value_type = strip_and_convert_t<T>; using value_type = strip_and_convert_t<T>;
static_assert(sendable<value_type>); static_assert(sendable<value_type>);
storage_size_ += padded_size_v<value_type>;
types_.push_back(type_id_v<value_type>); types_.push_back(type_id_v<value_type>);
elements_.emplace_back(make_message_builder_element(std::forward<T>(x))); elements_.emplace_back(make_message_builder_element(std::forward<T>(x)));
return *this; return *this;
...@@ -91,7 +93,7 @@ public: ...@@ -91,7 +93,7 @@ public:
/// Converts the buffer to an actual message object and transfers /// Converts the buffer to an actual message object and transfers
/// ownership of the data to it, leaving this object in an invalid state. /// ownership of the data to it, leaving this object in an invalid state.
/// @warning Calling *any* member function on this object afterwards /// @warning Calling *any* member function on this object afterwards
/// is undefined behavior (dereferencing a `nullptr`) /// is undefined behavior.
message move_to_message(); message move_to_message();
/// Removes all elements from the buffer. /// Removes all elements from the buffer.
...@@ -108,6 +110,7 @@ public: ...@@ -108,6 +110,7 @@ public:
} }
private: private:
size_t storage_size_ = 0;
detail::type_id_list_builder types_; detail::type_id_list_builder types_;
std::vector<detail::message_builder_element_ptr> elements_; std::vector<detail::message_builder_element_ptr> elements_;
}; };
......
...@@ -69,7 +69,13 @@ public: ...@@ -69,7 +69,13 @@ public:
/// Compares this list to `other`. /// Compares this list to `other`.
int compare(type_id_list other) const noexcept { int compare(type_id_list other) const noexcept {
return memcmp(data_, other.data_, (size() + 1) * sizeof(type_id_t)); // These conversions are safe, because the size is stored in 16 bits.
int s1 = data_[0];
int s2 = other.data_[0];
int diff = s1 - s2;
if (diff == 0)
return memcmp(begin(), other.begin(), s1 * sizeof(type_id_t));
return diff;
} }
/// Returns an iterator to the first type ID. /// Returns an iterator to the first type ID.
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "caf/detail/type_id_list_builder.hpp" #include "caf/detail/type_id_list_builder.hpp"
#include <cstdint> #include <cstdint>
#include <cstdlib>
#include <mutex> #include <mutex>
#include <unordered_set> #include <unordered_set>
...@@ -30,15 +31,17 @@ namespace caf::detail { ...@@ -30,15 +31,17 @@ namespace caf::detail {
namespace { namespace {
struct dyn_type_id_list { struct dyn_type_id_list {
dyn_type_id_list(type_id_t* storage) : storage(storage) { explicit dyn_type_id_list(type_id_t* storage) noexcept : storage(storage) {
CAF_ASSERT(storage != nullptr);
auto first = reinterpret_cast<const uint8_t*>(storage); auto first = reinterpret_cast<const uint8_t*>(storage);
auto last = first + ((storage[0] + 1) * sizeof(type_id_t)); auto last = first + ((storage[0] + 1) * sizeof(type_id_t));
hash = caf::hash::fnv<size_t>::compute(make_span(first, last)); hash = caf::hash::fnv<size_t>::compute(make_span(first, last));
} }
dyn_type_id_list(dyn_type_id_list&& other) dyn_type_id_list(dyn_type_id_list&& other) noexcept
: storage(other.storage), hash(other.hash) { : storage(other.storage), hash(other.hash) {
other.storage = nullptr; other.storage = nullptr;
other.hash = 0;
} }
~dyn_type_id_list() { ~dyn_type_id_list() {
...@@ -49,7 +52,7 @@ struct dyn_type_id_list { ...@@ -49,7 +52,7 @@ struct dyn_type_id_list {
size_t hash; size_t hash;
}; };
bool operator==(const dyn_type_id_list& x, const dyn_type_id_list& y) { bool operator==(const dyn_type_id_list& x, const dyn_type_id_list& y) noexcept {
return type_id_list{x.storage} == type_id_list{y.storage}; return type_id_list{x.storage} == type_id_list{y.storage};
} }
...@@ -122,10 +125,11 @@ type_id_t type_id_list_builder::operator[](size_t index) const noexcept { ...@@ -122,10 +125,11 @@ type_id_t type_id_list_builder::operator[](size_t index) const noexcept {
return storage_[index + 1]; return storage_[index + 1];
} }
type_id_list type_id_list_builder::move_to_list() { type_id_list type_id_list_builder::move_to_list() noexcept {
if (size_ == 0) auto list_size = size();
if (list_size == 0)
return make_type_id_list(); return make_type_id_list();
storage_[0] = static_cast<type_id_t>(size()); storage_[0] = static_cast<type_id_t>(list_size);
// Transfer ownership of buffer into the global cache. If an equivalent list // Transfer ownership of buffer into the global cache. If an equivalent list
// already exists, get_or_set_type_id_buf releases `ptr` and returns the old // already exists, get_or_set_type_id_buf releases `ptr` and returns the old
// buffer. // buffer.
...@@ -134,15 +138,16 @@ type_id_list type_id_list_builder::move_to_list() { ...@@ -134,15 +138,16 @@ type_id_list type_id_list_builder::move_to_list() {
return type_id_list{get_or_set_type_id_buf(ptr)}; return type_id_list{get_or_set_type_id_buf(ptr)};
} }
type_id_list type_id_list_builder::copy_to_list() { type_id_list type_id_list_builder::copy_to_list() const {
if (size_ == 0) auto list_size = size();
if (list_size == 0)
return make_type_id_list(); return make_type_id_list();
storage_[0] = static_cast<type_id_t>(size());
auto vptr = malloc(size_ * sizeof(type_id_t)); auto vptr = malloc(size_ * sizeof(type_id_t));
if (vptr == nullptr) if (vptr == nullptr)
throw std::bad_alloc(); throw std::bad_alloc();
auto copy = reinterpret_cast<type_id_t*>(vptr); auto copy = reinterpret_cast<type_id_t*>(vptr);
memcpy(copy, storage_, size_ * sizeof(type_id_t)); copy[0] = static_cast<type_id_t>(list_size);
memcpy(copy + 1, storage_ + 1, list_size * sizeof(type_id_t));
return type_id_list{get_or_set_type_id_buf(copy)}; return type_id_list{get_or_set_type_id_buf(copy)};
} }
......
...@@ -20,19 +20,52 @@ ...@@ -20,19 +20,52 @@
namespace caf { namespace caf {
namespace {
using namespace detail;
enum to_msg_policy {
move_msg,
copy_msg,
};
template <to_msg_policy Policy, class TypeListBuilder, class ElementVector>
message to_message_impl(size_t storage_size, TypeListBuilder& types,
ElementVector& elements) {
if (storage_size == 0)
return message{};
auto vptr = malloc(sizeof(message_data) + storage_size);
if (vptr == nullptr)
throw std::bad_alloc();
message_data* raw_ptr;
if constexpr (Policy == move_msg)
raw_ptr = new (vptr) message_data(types.move_to_list());
else
raw_ptr = new (vptr) message_data(types.copy_to_list());
intrusive_cow_ptr<message_data> ptr{raw_ptr, false};
auto storage = raw_ptr->storage();
for (auto& element : elements)
if constexpr (Policy == move_msg)
storage = element->move_init(storage);
else
storage = element->copy_init(storage);
return message{std::move(ptr)};
}
} // namespace
void message_builder::clear() noexcept { void message_builder::clear() noexcept {
storage_size_ = 0;
types_.clear(); types_.clear();
elements_.clear(); elements_.clear();
} }
message message_builder::to_message() const { message message_builder::to_message() const {
// TODO: implement me return to_message_impl<copy_msg>(storage_size_, types_, elements_);
return {};
} }
message message_builder::move_to_message() { message message_builder::move_to_message() {
// TODO: implement me return to_message_impl<move_msg>(storage_size_, types_, elements_);
return {};
} }
} // namespace caf } // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#define CAF_SUITE message_builder
#include "caf/message_builder.hpp"
#include "core-test.hpp"
#include <map>
#include <numeric>
#include <string>
#include <vector>
#include "caf/message.hpp"
#include "caf/type_id_list.hpp"
using namespace caf;
#define STEP(message) \
CAF_MESSAGE(message); \
if (true)
CAF_TEST(message builder can build messages incrermenetally) {
message_builder builder;
CAF_CHECK(builder.empty());
CAF_CHECK(builder.to_message().empty());
CAF_CHECK_EQUAL(builder.size(), 0u);
STEP("after adding 1, the message is (1)") {
builder.append(int32_t{1});
auto msg = builder.to_message();
CAF_CHECK_EQUAL(builder.size(), 1u);
CAF_CHECK_EQUAL(msg.types(), make_type_id_list<int32_t>());
CAF_CHECK_EQUAL(to_string(msg.types()), "[int32_t]");
CAF_CHECK_EQUAL(to_string(msg), "(1)");
}
STEP("after adding [2, 3], the message is (1, 2, 3)") {
std::vector<int32_t> xs{2, 3};
builder.append(xs.begin(), xs.end());
CAF_CHECK_EQUAL(builder.size(), 3u);
auto msg = builder.to_message();
CAF_CHECK_EQUAL(msg.types(),
(make_type_id_list<int32_t, int32_t, int32_t>()));
CAF_CHECK_EQUAL(to_string(msg.types()), "[int32_t, int32_t, int32_t]");
CAF_CHECK_EQUAL(to_string(msg), "(1, 2, 3)");
}
STEP("moving the content to a message produces the same message again") {
auto msg = builder.move_to_message();
CAF_CHECK_EQUAL(msg.types(),
(make_type_id_list<int32_t, int32_t, int32_t>()));
CAF_CHECK_EQUAL(to_string(msg.types()), "[int32_t, int32_t, int32_t]");
CAF_CHECK_EQUAL(to_string(msg), "(1, 2, 3)");
}
}
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