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
mailbox_element
make_config_value_field
message
message_builder
message_id
message_lifetime
metaprogramming
......
......@@ -45,12 +45,10 @@ public:
type_id_t operator[](size_t index) const noexcept;
/// 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();
type_id_list move_to_list() noexcept;
/// 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();
type_id_list copy_to_list() const;
void clear() noexcept {
if (storage_)
......
......@@ -23,6 +23,7 @@
#include "caf/detail/core_export.hpp"
#include "caf/detail/implicit_conversions.hpp"
#include "caf/detail/message_builder_element.hpp"
#include "caf/detail/padded_size.hpp"
#include "caf/detail/type_id_list_builder.hpp"
#include "caf/fwd.hpp"
#include "caf/message.hpp"
......@@ -61,6 +62,7 @@ public:
using namespace detail;
using value_type = strip_and_convert_t<T>;
static_assert(sendable<value_type>);
storage_size_ += padded_size_v<value_type>;
types_.push_back(type_id_v<value_type>);
elements_.emplace_back(make_message_builder_element(std::forward<T>(x)));
return *this;
......@@ -91,7 +93,7 @@ public:
/// Converts the buffer to an actual message object and transfers
/// ownership of the data to it, leaving this object in an invalid state.
/// @warning Calling *any* member function on this object afterwards
/// is undefined behavior (dereferencing a `nullptr`)
/// is undefined behavior.
message move_to_message();
/// Removes all elements from the buffer.
......@@ -108,6 +110,7 @@ public:
}
private:
size_t storage_size_ = 0;
detail::type_id_list_builder types_;
std::vector<detail::message_builder_element_ptr> elements_;
};
......
......@@ -69,7 +69,13 @@ public:
/// Compares this list to `other`.
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.
......
......@@ -19,6 +19,7 @@
#include "caf/detail/type_id_list_builder.hpp"
#include <cstdint>
#include <cstdlib>
#include <mutex>
#include <unordered_set>
......@@ -30,15 +31,17 @@ namespace caf::detail {
namespace {
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 last = first + ((storage[0] + 1) * sizeof(type_id_t));
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) {
other.storage = nullptr;
other.hash = 0;
}
~dyn_type_id_list() {
......@@ -49,7 +52,7 @@ struct dyn_type_id_list {
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};
}
......@@ -122,10 +125,11 @@ type_id_t type_id_list_builder::operator[](size_t index) const noexcept {
return storage_[index + 1];
}
type_id_list type_id_list_builder::move_to_list() {
if (size_ == 0)
type_id_list type_id_list_builder::move_to_list() noexcept {
auto list_size = size();
if (list_size == 0)
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
// already exists, get_or_set_type_id_buf releases `ptr` and returns the old
// buffer.
......@@ -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)};
}
type_id_list type_id_list_builder::copy_to_list() {
if (size_ == 0)
type_id_list type_id_list_builder::copy_to_list() const {
auto list_size = size();
if (list_size == 0)
return make_type_id_list();
storage_[0] = static_cast<type_id_t>(size());
auto vptr = malloc(size_ * sizeof(type_id_t));
if (vptr == nullptr)
throw std::bad_alloc();
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)};
}
......
......@@ -20,19 +20,52 @@
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 {
storage_size_ = 0;
types_.clear();
elements_.clear();
}
message message_builder::to_message() const {
// TODO: implement me
return {};
return to_message_impl<copy_msg>(storage_size_, types_, elements_);
}
message message_builder::move_to_message() {
// TODO: implement me
return {};
return to_message_impl<move_msg>(storage_size_, types_, elements_);
}
} // 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