Unverified Commit afb884bb authored by Joseph Noir's avatar Joseph Noir Committed by GitHub

Merge pull request #818

Re-implement container-based binary serializers
parents d208f93c d04f510a
...@@ -30,6 +30,8 @@ set(LIBCAF_CORE_SRCS ...@@ -30,6 +30,8 @@ set(LIBCAF_CORE_SRCS
src/behavior.cpp src/behavior.cpp
src/behavior_impl.cpp src/behavior_impl.cpp
src/behavior_stack.cpp src/behavior_stack.cpp
src/binary_deserializer.cpp
src/binary_serializer.cpp
src/blocking_actor.cpp src/blocking_actor.cpp
src/blocking_behavior.cpp src/blocking_behavior.cpp
src/chars.cpp src/chars.cpp
......
...@@ -93,12 +93,14 @@ ...@@ -93,12 +93,14 @@
#include "caf/composed_behavior.hpp" #include "caf/composed_behavior.hpp"
#include "caf/event_based_actor.hpp" #include "caf/event_based_actor.hpp"
#include "caf/primitive_variant.hpp" #include "caf/primitive_variant.hpp"
#include "caf/stream_serializer.hpp"
#include "caf/make_config_option.hpp" #include "caf/make_config_option.hpp"
#include "caf/timeout_definition.hpp" #include "caf/timeout_definition.hpp"
#include "caf/actor_system_config.hpp" #include "caf/actor_system_config.hpp"
#include "caf/binary_deserializer.hpp" #include "caf/binary_deserializer.hpp"
#include "caf/composable_behavior.hpp" #include "caf/composable_behavior.hpp"
#include "caf/config_option_adder.hpp" #include "caf/config_option_adder.hpp"
#include "caf/stream_deserializer.hpp"
#include "caf/typed_actor_pointer.hpp" #include "caf/typed_actor_pointer.hpp"
#include "caf/scoped_execution_unit.hpp" #include "caf/scoped_execution_unit.hpp"
#include "caf/typed_response_promise.hpp" #include "caf/typed_response_promise.hpp"
......
...@@ -18,14 +18,81 @@ ...@@ -18,14 +18,81 @@
#pragma once #pragma once
#include "caf/stream_deserializer.hpp" #include <cstddef>
#include "caf/streambuf.hpp" #include <cstdint>
#include <vector>
#include "caf/deserializer.hpp"
namespace caf { namespace caf {
/// A stream serializer that writes into an unbounded contiguous character /// Implements the deserializer interface with a binary serialization protocol.
/// sequence. class binary_deserializer final : public deserializer {
using binary_deserializer = stream_deserializer<charbuf>; public:
// -- member types -----------------------------------------------------------
} // namespace caf using super = deserializer;
using buffer = std::vector<char>;
// -- constructors, destructors, and assignment operators --------------------
binary_deserializer(actor_system& sys, const char* buf, size_t buf_size);
binary_deserializer(execution_unit* ctx, const char* buf, size_t buf_size);
binary_deserializer(actor_system& sys, const buffer& buf);
binary_deserializer(execution_unit* ctx, const buffer& buf);
// -- overridden member functions --------------------------------------------
error begin_object(uint16_t& typenr, std::string& name) override;
error end_object() override;
error begin_sequence(size_t& list_size) override;
error end_sequence() override;
error apply_raw(size_t num_bytes, void* data) override;
protected:
error apply_impl(int8_t&) override;
error apply_impl(uint8_t&) override;
error apply_impl(int16_t&) override;
error apply_impl(uint16_t&) override;
error apply_impl(int32_t&) override;
error apply_impl(uint32_t&) override;
error apply_impl(int64_t&) override;
error apply_impl(uint64_t&) override;
error apply_impl(float&) override;
error apply_impl(double&) override;
error apply_impl(long double&) override;
error apply_impl(std::string&) override;
error apply_impl(std::u16string&) override;
error apply_impl(std::u32string&) override;
private:
bool range_check(size_t read_size) {
return pos_ + read_size <= end_;
}
const char* pos_;
const char* end_;
};
} // namespace caf
...@@ -18,14 +18,93 @@ ...@@ -18,14 +18,93 @@
#pragma once #pragma once
#include "caf/stream_serializer.hpp" #include <cstddef>
#include "caf/streambuf.hpp" #include <cstdint>
#include <vector>
#include "caf/serializer.hpp"
namespace caf { namespace caf {
/// A stream serializer that writes into an unbounded contiguous character /// Implements the serializer interface with a binary serialization protocol.
/// sequence. class binary_serializer final : public serializer {
using binary_serializer = stream_serializer<vectorbuf>; public:
// -- member types -----------------------------------------------------------
} // namespace caf using super = serializer;
using buffer = std::vector<char>;
// -- constructors, destructors, and assignment operators --------------------
binary_serializer(actor_system& sys, buffer& buf);
binary_serializer(execution_unit* ctx, buffer& buf);
// -- position management ----------------------------------------------------
/// Sets the write position to given offset.
/// @pre `offset <= buf.size()`
void seek(size_t offset);
/// Jumps `num_bytes` forward. Resizes the buffer (filling it with zeros)
/// when skipping past the end.
void skip(size_t num_bytes);
// -- overridden member functions --------------------------------------------
error begin_object(uint16_t& typenr, std::string& name) override;
error end_object() override;
error begin_sequence(size_t& list_size) override;
error end_sequence() override;
error apply_raw(size_t num_bytes, void* data) override;
// -- properties -------------------------------------------------------------
buffer& buf() {
return buf_;
}
const buffer& buf() const {
return buf_;
}
protected:
error apply_impl(int8_t&) override;
error apply_impl(uint8_t&) override;
error apply_impl(int16_t&) override;
error apply_impl(uint16_t&) override;
error apply_impl(int32_t&) override;
error apply_impl(uint32_t&) override;
error apply_impl(int64_t&) override;
error apply_impl(uint64_t&) override;
error apply_impl(float&) override;
error apply_impl(double&) override;
error apply_impl(long double&) override;
error apply_impl(std::string&) override;
error apply_impl(std::u16string&) override;
error apply_impl(std::u32string&) override;
private:
buffer& buf_;
buffer::iterator write_pos_;
};
} // namespace caf
...@@ -73,24 +73,6 @@ public: ...@@ -73,24 +73,6 @@ public:
std::u32string std::u32string
>; >;
/// List of builtin types for data processors as enum.
enum builtin {
i8_v,
u8_v,
i16_v,
u16_v,
i32_v,
u32_v,
i64_v,
u64_v,
float_v,
double_v,
ldouble_v,
string8_v,
string16_v,
string32_v
};
// -- constructors, destructors, and assignment operators -------------------- // -- constructors, destructors, and assignment operators --------------------
data_processor(const data_processor&) = delete; data_processor(const data_processor&) = delete;
...@@ -137,7 +119,7 @@ public: ...@@ -137,7 +119,7 @@ public:
apply(T& x) { apply(T& x) {
static constexpr auto tlindex = detail::tl_index_of<builtin_t, T>::value; static constexpr auto tlindex = detail::tl_index_of<builtin_t, T>::value;
static_assert(tlindex >= 0, "T not recognized as builtin type"); static_assert(tlindex >= 0, "T not recognized as builtin type");
return apply_builtin(static_cast<builtin>(tlindex), &x); return apply_impl(x);
} }
template <class T> template <class T>
...@@ -147,25 +129,21 @@ public: ...@@ -147,25 +129,21 @@ public:
error error
>::type >::type
apply(T& x) { apply(T& x) {
using type = using type = detail::select_integer_type_t<sizeof(T),
typename detail::select_integer_type< std::is_signed<T>::value>;
static_cast<int>(sizeof(T)) * (std::is_signed<T>::value ? -1 : 1) return apply_impl(reinterpret_cast<type&>(x));
>::type;
static constexpr auto tlindex = detail::tl_index_of<builtin_t, type>::value;
static_assert(tlindex >= 0, "T not recognized as builtin type");
return apply_builtin(static_cast<builtin>(tlindex), &x);
} }
error apply(std::string& x) { error apply(std::string& x) {
return apply_builtin(string8_v, &x); return apply_impl(x);
} }
error apply(std::u16string& x) { error apply(std::u16string& x) {
return apply_builtin(string16_v, &x); return apply_impl(x);
} }
error apply(std::u32string& x) { error apply(std::u32string& x) {
return apply_builtin(string32_v, &x); return apply_impl(x);
} }
template <class D, atom_value V> template <class D, atom_value V>
...@@ -549,8 +527,33 @@ public: ...@@ -549,8 +527,33 @@ public:
} }
protected: protected:
/// Applies this processor to a single builtin value. virtual error apply_impl(int8_t&) = 0;
virtual error apply_builtin(builtin in_out_type, void* in_out) = 0;
virtual error apply_impl(uint8_t&) = 0;
virtual error apply_impl(int16_t&) = 0;
virtual error apply_impl(uint16_t&) = 0;
virtual error apply_impl(int32_t&) = 0;
virtual error apply_impl(uint32_t&) = 0;
virtual error apply_impl(int64_t&) = 0;
virtual error apply_impl(uint64_t&) = 0;
virtual error apply_impl(float&) = 0;
virtual error apply_impl(double&) = 0;
virtual error apply_impl(long double&) = 0;
virtual error apply_impl(std::string&) = 0;
virtual error apply_impl(std::u16string&) = 0;
virtual error apply_impl(std::u32string&) = 0;
private: private:
template <class T> template <class T>
......
...@@ -23,49 +23,52 @@ ...@@ -23,49 +23,52 @@
namespace caf { namespace caf {
namespace detail { namespace detail {
template <int> template <int, bool>
struct select_integer_type; struct select_integer_type;
template <> template <>
struct select_integer_type<-1> { struct select_integer_type<1, true> {
using type = int8_t; using type = int8_t;
}; };
template <> template <>
struct select_integer_type<1> { struct select_integer_type<1, false> {
using type = uint8_t; using type = uint8_t;
}; };
template <> template <>
struct select_integer_type<-2> { struct select_integer_type<2, true> {
using type = int16_t; using type = int16_t;
}; };
template <> template <>
struct select_integer_type<2> { struct select_integer_type<2, false> {
using type = uint16_t; using type = uint16_t;
}; };
template <> template <>
struct select_integer_type<-4> { struct select_integer_type<4, true> {
using type = int32_t; using type = int32_t;
}; };
template <> template <>
struct select_integer_type<4> { struct select_integer_type<4, false> {
using type = uint32_t; using type = uint32_t;
}; };
template <> template <>
struct select_integer_type<-8> { struct select_integer_type<8, true> {
using type = int64_t; using type = int64_t;
}; };
template <> template <>
struct select_integer_type<8> { struct select_integer_type<8, false> {
using type = uint64_t; using type = uint64_t;
}; };
template <int Size, bool IsSigned>
using select_integer_type_t = typename select_integer_type<Size,
IsSigned>::type;
} // namespace detail } // namespace detail
} // namespace caf } // namespace caf
...@@ -18,22 +18,21 @@ ...@@ -18,22 +18,21 @@
#pragma once #pragma once
#include <limits>
#include <string>
#include <sstream>
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include <iomanip> #include <iomanip>
#include <limits>
#include <sstream>
#include <stdexcept> #include <stdexcept>
#include <string>
#include <type_traits> #include <type_traits>
#include "caf/sec.hpp"
#include "caf/logger.hpp"
#include "caf/deserializer.hpp" #include "caf/deserializer.hpp"
#include "caf/detail/ieee_754.hpp" #include "caf/detail/ieee_754.hpp"
#include "caf/detail/network_order.hpp" #include "caf/detail/network_order.hpp"
#include "caf/logger.hpp"
#include "caf/sec.hpp"
namespace caf { namespace caf {
...@@ -127,66 +126,82 @@ protected: ...@@ -127,66 +126,82 @@ protected:
return none; return none;
} }
error apply_builtin(builtin type, void* val) override { error apply_impl(int8_t& x) override {
CAF_ASSERT(val != nullptr); return apply_raw(sizeof(int8_t), &x);
switch (type) { }
default: // i8_v or u8_v
CAF_ASSERT(type == i8_v || type == u8_v); error apply_impl(uint8_t& x) override {
return apply_raw(sizeof(uint8_t), val); return apply_raw(sizeof(uint8_t), &x);
case i16_v: }
case u16_v:
return apply_int(*reinterpret_cast<uint16_t*>(val)); error apply_impl(int16_t& x) override {
case i32_v: return apply_int(x);
case u32_v: }
return apply_int(*reinterpret_cast<uint32_t*>(val));
case i64_v: error apply_impl(uint16_t& x) override {
case u64_v: return apply_int(x);
return apply_int(*reinterpret_cast<uint64_t*>(val)); }
case float_v:
return apply_float(*reinterpret_cast<float*>(val)); error apply_impl(int32_t& x) override {
case double_v: return apply_int(x);
return apply_float(*reinterpret_cast<double*>(val)); }
case ldouble_v: {
// the IEEE-754 conversion does not work for long double error apply_impl(uint32_t& x) override {
// => fall back to string serialization (even though it sucks) return apply_int(x);
}
error apply_impl(int64_t& x) override {
return apply_int(x);
}
error apply_impl(uint64_t& x) override {
return apply_int(x);
}
error apply_impl(float& x) override {
return apply_float(x);
}
error apply_impl(double& x) override {
return apply_float(x);
}
error apply_impl(long double& x) override {
// The IEEE-754 conversion does not work for long double
// => fall back to string serialization (even though it sucks).
std::string tmp; std::string tmp;
auto e = apply(tmp); if (auto err = apply(tmp))
if (e) return err;
return e;
std::istringstream iss{std::move(tmp)}; std::istringstream iss{std::move(tmp)};
iss >> *reinterpret_cast<long double*>(val); iss >> x;
return none; return none;
} }
case string8_v: {
auto& str = *reinterpret_cast<std::string*>(val); error apply_impl(std::string& x) override {
size_t str_size; size_t str_size;
return error::eval([&] { return begin_sequence(str_size); }, if (auto err = begin_sequence(str_size))
[&] { str.resize(str_size); return err;
auto p = &str[0]; x.resize(str_size);
auto data = reinterpret_cast<char_type*>(p);
auto s = static_cast<streamsize>(str_size); auto s = static_cast<streamsize>(str_size);
return range_check(streambuf_.sgetn(data, s), auto data = reinterpret_cast<char_type*>(&x[0]);
str_size); }, if (auto err = range_check(streambuf_.sgetn(data, s), str_size))
[&] { return end_sequence(); }); return err;
return end_sequence();
} }
case string16_v: {
auto& str = *reinterpret_cast<std::u16string*>(val); error apply_impl(std::u16string& x) override {
str.clear(); size_t str_size;
size_t ns; return error::eval([&] { return begin_sequence(str_size); },
return error::eval([&] { return begin_sequence(ns); }, [&] { return fill_range_c<uint16_t>(x, str_size); },
[&] { return fill_range_c<uint16_t>(str, ns); },
[&] { return end_sequence(); }); [&] { return end_sequence(); });
} }
case string32_v: {
auto& str = *reinterpret_cast<std::u32string*>(val); error apply_impl(std::u32string& x) override {
str.clear(); size_t str_size;
size_t ns; return error::eval([&] { return begin_sequence(str_size); },
return error::eval([&] { return begin_sequence(ns); }, [&] { return fill_range_c<uint32_t>(x, str_size); },
[&] { return fill_range_c<uint32_t>(str, ns); },
[&] { return end_sequence(); }); [&] { return end_sequence(); });
} }
}
}
error range_check(std::streamsize got, size_t need) { error range_check(std::streamsize got, size_t need) {
if (got >= 0 && static_cast<size_t>(got) == need) if (got >= 0 && static_cast<size_t>(got) == need)
...@@ -197,20 +212,18 @@ protected: ...@@ -197,20 +212,18 @@ protected:
template <class T> template <class T>
error apply_int(T& x) { error apply_int(T& x) {
T tmp; typename std::make_unsigned<T>::type tmp = 0;
auto e = apply_raw(sizeof(T), &tmp); if (auto err = apply_raw(sizeof(T), &tmp))
if (e) return err;
return e; x = static_cast<T>(detail::from_network_order(tmp));
x = detail::from_network_order(tmp);
return none; return none;
} }
template <class T> template <class T>
error apply_float(T& x) { error apply_float(T& x) {
typename detail::ieee_754_trait<T>::packed_type tmp = 0; typename detail::ieee_754_trait<T>::packed_type tmp = 0;
auto e = apply_int(tmp); if (auto err = apply_int(tmp))
if (e) return err;
return e;
x = detail::unpack754(tmp); x = detail::unpack754(tmp);
return none; return none;
} }
......
...@@ -125,65 +125,81 @@ protected: ...@@ -125,65 +125,81 @@ protected:
return none; return none;
} }
error apply_builtin(builtin type, void* val) override { error apply_impl(int8_t& x) override {
CAF_ASSERT(val != nullptr); return apply_raw(sizeof(int8_t), &x);
switch (type) { }
default: // i8_v or u8_v
CAF_ASSERT(type == i8_v || type == u8_v); error apply_impl(uint8_t& x) override {
return apply_raw(sizeof(uint8_t), val); return apply_raw(sizeof(uint8_t), &x);
case i16_v: }
case u16_v:
return apply_int(*reinterpret_cast<uint16_t*>(val)); error apply_impl(int16_t& x) override {
case i32_v: return apply_int(x);
case u32_v: }
return apply_int(*reinterpret_cast<uint32_t*>(val));
case i64_v: error apply_impl(uint16_t& x) override {
case u64_v: return apply_int(x);
return apply_int(*reinterpret_cast<uint64_t*>(val)); }
case float_v:
return apply_int(detail::pack754(*reinterpret_cast<float*>(val))); error apply_impl(int32_t& x) override {
case double_v: return apply_int(x);
return apply_int(detail::pack754(*reinterpret_cast<double*>(val))); }
case ldouble_v: {
// the IEEE-754 conversion does not work for long double error apply_impl(uint32_t& x) override {
// => fall back to string serialization (event though it sucks) return apply_int(x);
}
error apply_impl(int64_t& x) override {
return apply_int(x);
}
error apply_impl(uint64_t& x) override {
return apply_int(x);
}
error apply_impl(float& x) override {
return apply_int(detail::pack754(x));
}
error apply_impl(double& x) override {
return apply_int(detail::pack754(x));
}
error apply_impl(long double& x) override {
// The IEEE-754 conversion does not work for long double
// => fall back to string serialization (event though it sucks).
std::ostringstream oss; std::ostringstream oss;
oss << std::setprecision(std::numeric_limits<long double>::digits) oss << std::setprecision(std::numeric_limits<long double>::digits) << x;
<< *reinterpret_cast<long double*>(val);
auto tmp = oss.str(); auto tmp = oss.str();
return apply(tmp); return apply_impl(tmp);
}
case string8_v: {
auto str = reinterpret_cast<std::string*>(val);
auto s = str->size();
auto data = reinterpret_cast<char_type*>(
const_cast<std::string::value_type*>(str->data()));
return error::eval([&] { return begin_sequence(s); },
[&] { return apply_raw(str->size(), data); },
[&] { return end_sequence(); });
} }
case string16_v: {
auto str = reinterpret_cast<std::u16string*>(val); error apply_impl(std::string& x) override {
auto s = str->size(); auto str_size = x.size();
// the standard does not guarantee that char16_t is exactly 16 bits... auto data = const_cast<char*>(x.c_str());
return error::eval([&] { return begin_sequence(s); }, return error::eval([&] { return begin_sequence(str_size); },
[&] { return consume_range_c<uint16_t>(*str); }, [&] { return apply_raw(x.size(), data); },
[&] { return end_sequence(); }); [&] { return end_sequence(); });
} }
case string32_v: {
auto str = reinterpret_cast<std::u32string*>(val); error apply_impl(std::u16string& x) override {
auto s = str->size(); auto str_size = x.size();
// the standard does not guarantee that char32_t is exactly 32 bits... return error::eval([&] { return begin_sequence(str_size); },
return error::eval([&] { return begin_sequence(s); }, [&] { return consume_range_c<uint16_t>(x); },
[&] { return consume_range_c<uint32_t>(*str); },
[&] { return end_sequence(); }); [&] { return end_sequence(); });
} }
}
error apply_impl(std::u32string& x) override {
auto str_size = x.size();
return error::eval([&] { return begin_sequence(str_size); },
[&] { return consume_range_c<uint32_t>(x); },
[&] { return end_sequence(); });
} }
template <class T> template <class T>
error apply_int(T x) { error apply_int(T x) {
auto y = detail::to_network_order(x); using unsigned_type = typename std::make_unsigned<T>::type;
auto y = detail::to_network_order(static_cast<unsigned_type>(x));
return apply_raw(sizeof(T), &y); return apply_raw(sizeof(T), &y);
} }
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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. *
******************************************************************************/
#include "caf/binary_deserializer.hpp"
#include <iomanip>
#include <sstream>
#include <type_traits>
#include "caf/detail/ieee_754.hpp"
#include "caf/detail/network_order.hpp"
#include "caf/sec.hpp"
namespace caf {
namespace {
template <class T>
error apply_int(binary_deserializer& bs, T& x) {
typename std::make_unsigned<T>::type tmp;
if (auto err = bs.apply_raw(sizeof(T), &tmp))
return err;
x = static_cast<T>(detail::from_network_order(tmp));
return none;
}
template <class T>
error apply_float(binary_deserializer& bs, T& x) {
typename detail::ieee_754_trait<T>::packed_type tmp;
if (auto err = apply_int(bs, tmp))
return err;
x = detail::unpack754(tmp);
return none;
}
} // namespace <anonmyous>
binary_deserializer::binary_deserializer(actor_system& sys, const char* buf,
size_t buf_size)
: super(sys), pos_(buf), end_(buf + buf_size) {
// nop
}
binary_deserializer::binary_deserializer(execution_unit* ctx, const char* buf,
size_t buf_size)
: super(ctx), pos_(buf), end_(buf + buf_size) {
// nop
}
binary_deserializer::binary_deserializer(actor_system& sys, const buffer& buf)
: binary_deserializer(sys, buf.data(), buf.size()) {
// nop
}
binary_deserializer::binary_deserializer(execution_unit* ctx, const buffer& buf)
: binary_deserializer(ctx, buf.data(), buf.size()) {
// nop
}
error binary_deserializer::begin_object(uint16_t& nr, std::string& name) {
if (auto err = apply(nr))
return err;
if (nr != 0)
return none;
return apply(name);
}
error binary_deserializer::end_object() {
return none;
}
error binary_deserializer::begin_sequence(size_t& list_size) {
auto s = static_cast<uint32_t>(list_size);
if (auto err = apply(s))
return err;
list_size = s;
return none;
}
error binary_deserializer::end_sequence() {
return none;
}
error binary_deserializer::apply_raw(size_t num_bytes, void* storage) {
if (!range_check(num_bytes))
return sec::end_of_stream;
memcpy(storage, pos_, num_bytes);
pos_ += num_bytes;
return none;
}
error binary_deserializer::apply_impl(int8_t& x) {
return apply_raw(sizeof(int8_t), &x);
}
error binary_deserializer::apply_impl(uint8_t& x) {
return apply_raw(sizeof(uint8_t), &x);
}
error binary_deserializer::apply_impl(int16_t& x) {
return apply_int(*this, x);
}
error binary_deserializer::apply_impl(uint16_t& x) {
return apply_int(*this, x);
}
error binary_deserializer::apply_impl(int32_t& x) {
return apply_int(*this, x);
}
error binary_deserializer::apply_impl(uint32_t& x) {
return apply_int(*this, x);
}
error binary_deserializer::apply_impl(int64_t& x) {
return apply_int(*this, x);
}
error binary_deserializer::apply_impl(uint64_t& x) {
return apply_int(*this, x);
}
error binary_deserializer::apply_impl(float& x) {
return apply_float(*this, x);
}
error binary_deserializer::apply_impl(double& x) {
return apply_float(*this, x);
}
error binary_deserializer::apply_impl(long double& x) {
// The IEEE-754 conversion does not work for long double
// => fall back to string serialization (even though it sucks).
std::string tmp;
if (auto err = apply(tmp))
return err;
std::istringstream iss{std::move(tmp)};
iss >> x;
return none;
}
error binary_deserializer::apply_impl(std::string& x) {
size_t str_size;
if (auto err = begin_sequence(str_size))
return err;
if (!range_check(str_size))
return sec::end_of_stream;
x.assign(pos_, pos_ + str_size);
pos_ += str_size;
return end_sequence();
}
error binary_deserializer::apply_impl(std::u16string& x) {
auto str_size = x.size();
if (auto err = begin_sequence(str_size))
return err;
for (size_t i = 0; i < str_size; ++i) {
// The standard does not guarantee that char16_t is exactly 16 bits.
uint16_t tmp;
if (auto err = apply_int(*this, tmp))
return err;
x.push_back(static_cast<char16_t>(tmp));
}
return none;
}
error binary_deserializer::apply_impl(std::u32string& x) {
auto str_size = x.size();
if (auto err = begin_sequence(str_size))
return err;
for (size_t i = 0; i < str_size; ++i) {
// The standard does not guarantee that char32_t is exactly 32 bits.
uint32_t tmp;
if (auto err = apply_int(*this, tmp))
return err;
x.push_back(static_cast<char32_t>(tmp));
}
return none;
}
} // 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. *
******************************************************************************/
#include "caf/binary_serializer.hpp"
#include <cstring>
#include <iomanip>
#include <sstream>
#include "caf/detail/ieee_754.hpp"
#include "caf/detail/network_order.hpp"
namespace caf {
namespace {
template <class T>
error apply_int(binary_serializer& bs, T x) {
auto y = detail::to_network_order(x);
return bs.apply_raw(sizeof(T), &y);
}
} // namespace <anonmyous>
binary_serializer::binary_serializer(actor_system& sys, buffer& buf)
: super(sys), buf_(buf), write_pos_(buf.end()) {
// nop
}
binary_serializer::binary_serializer(execution_unit* ctx, buffer& buf)
: super(ctx), buf_(buf), write_pos_(buf.end()) {
// nop
}
void binary_serializer::seek(size_t offset) {
write_pos_ = buf_.begin() + offset;
}
void binary_serializer::skip(size_t num_bytes) {
auto last = buf_.end();
auto remaining = static_cast<size_t>(std::distance(write_pos_, last));
if (remaining >= num_bytes) {
write_pos_ += num_bytes;
} else {
buf_.insert(last, num_bytes - remaining, 0);
write_pos_ = buf_.end();
}
}
error binary_serializer::begin_object(uint16_t& nr, std::string& name) {
if (nr != 0)
return apply(nr);
if (auto err = apply(nr))
return err;
return apply(name);
}
error binary_serializer::end_object() {
return none;
}
error binary_serializer::begin_sequence(size_t& list_size) {
auto s = static_cast<uint32_t>(list_size);
return apply(s);
}
error binary_serializer::end_sequence() {
return none;
}
error binary_serializer::apply_raw(size_t num_bytes, void* data) {
auto ptr = reinterpret_cast<char*>(data);
auto last = buf_.end();
if (write_pos_ == last) {
buf_.insert(last, ptr, ptr + num_bytes);
write_pos_ = buf_.end();
} else if (write_pos_ + num_bytes < last) {
memcpy(&(*write_pos_), ptr, num_bytes);
write_pos_ += num_bytes;
} else {
auto remaining = static_cast<size_t>(last - write_pos_);
memcpy(&(*write_pos_), ptr, remaining);
buf_.insert(last, ptr + remaining, ptr + num_bytes);
write_pos_ = buf_.end();
}
return none;
}
error binary_serializer::apply_impl(int8_t& x) {
return apply_raw(sizeof(int8_t), &x);
}
error binary_serializer::apply_impl(uint8_t& x) {
return apply_raw(sizeof(uint8_t), &x);
}
error binary_serializer::apply_impl(int16_t& x) {
return apply_int(*this, static_cast<uint16_t>(x));
}
error binary_serializer::apply_impl(uint16_t& x) {
return apply_int(*this, x);
}
error binary_serializer::apply_impl(int32_t& x) {
return apply_int(*this, static_cast<uint32_t>(x));
}
error binary_serializer::apply_impl(uint32_t& x) {
return apply_int(*this, x);
}
error binary_serializer::apply_impl(int64_t& x) {
return apply_int(*this, static_cast<uint64_t>(x));
}
error binary_serializer::apply_impl(uint64_t& x) {
return apply_int(*this, x);
}
error binary_serializer::apply_impl(float& x) {
return apply_int(*this, detail::pack754(x));
}
error binary_serializer::apply_impl(double& x) {
return apply_int(*this, detail::pack754(x));
}
error binary_serializer::apply_impl(long double& x) {
// The IEEE-754 conversion does not work for long double
// => fall back to string serialization (event though it sucks).
std::ostringstream oss;
oss << std::setprecision(std::numeric_limits<long double>::digits) << x;
auto tmp = oss.str();
return apply_impl(tmp);
}
error binary_serializer::apply_impl(std::string& x) {
auto str_size = x.size();
if (str_size == 0)
return error::eval([&] { return begin_sequence(str_size); },
[&] { return end_sequence(); });
auto data = const_cast<char*>(x.c_str());
return error::eval([&] { return begin_sequence(str_size); },
[&] { return apply_raw(str_size, data); },
[&] { return end_sequence(); });
}
error binary_serializer::apply_impl(std::u16string& x) {
auto str_size = x.size();
if (auto err = begin_sequence(str_size))
return err;
for (auto c : x) {
// The standard does not guarantee that char16_t is exactly 16 bits.
if (auto err = apply_int(*this, static_cast<uint16_t>(c)))
return err;
}
return none;
}
error binary_serializer::apply_impl(std::u32string& x) {
auto str_size = x.size();
if (auto err = begin_sequence(str_size))
return err;
for (auto c : x) {
// The standard does not guarantee that char16_t is exactly 16 bits.
if (auto err = apply_int(*this, static_cast<uint32_t>(c)))
return err;
}
return none;
}
} // namespace caf
...@@ -21,51 +21,52 @@ ...@@ -21,51 +21,52 @@
#define CAF_SUITE serialization #define CAF_SUITE serialization
#include "caf/test/unit_test.hpp" #include "caf/test/unit_test.hpp"
#include <new> #include <algorithm>
#include <set> #include <cassert>
#include <cstdint>
#include <cstring>
#include <functional>
#include <iostream>
#include <iterator>
#include <limits>
#include <list> #include <list>
#include <stack>
#include <tuple>
#include <locale> #include <locale>
#include <memory> #include <memory>
#include <string> #include <new>
#include <limits> #include <set>
#include <vector>
#include <cstring>
#include <sstream> #include <sstream>
#include <cstdint> #include <stack>
#include <cstring>
#include <cassert>
#include <iterator>
#include <typeinfo>
#include <iostream>
#include <stdexcept> #include <stdexcept>
#include <algorithm> #include <string>
#include <functional> #include <tuple>
#include <type_traits> #include <type_traits>
#include <typeinfo>
#include <vector>
#include "caf/message.hpp"
#include "caf/streambuf.hpp"
#include "caf/serializer.hpp"
#include "caf/ref_counted.hpp"
#include "caf/deserializer.hpp"
#include "caf/actor_system.hpp" #include "caf/actor_system.hpp"
#include "caf/proxy_registry.hpp"
#include "caf/message_handler.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/primitive_variant.hpp"
#include "caf/binary_serializer.hpp"
#include "caf/binary_deserializer.hpp"
#include "caf/actor_system_config.hpp" #include "caf/actor_system_config.hpp"
#include "caf/make_type_erased_view.hpp" #include "caf/binary_deserializer.hpp"
#include "caf/binary_serializer.hpp"
#include "caf/deserializer.hpp"
#include "caf/event_based_actor.hpp"
#include "caf/make_type_erased_tuple_view.hpp" #include "caf/make_type_erased_tuple_view.hpp"
#include "caf/make_type_erased_view.hpp"
#include "caf/message.hpp"
#include "caf/message_handler.hpp"
#include "caf/primitive_variant.hpp"
#include "caf/proxy_registry.hpp"
#include "caf/ref_counted.hpp"
#include "caf/serializer.hpp"
#include "caf/stream_deserializer.hpp"
#include "caf/stream_serializer.hpp"
#include "caf/streambuf.hpp"
#include "caf/detail/enum_to_string.hpp"
#include "caf/detail/get_mac_addresses.hpp"
#include "caf/detail/ieee_754.hpp" #include "caf/detail/ieee_754.hpp"
#include "caf/detail/int_list.hpp" #include "caf/detail/int_list.hpp"
#include "caf/detail/safe_equal.hpp" #include "caf/detail/safe_equal.hpp"
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
#include "caf/detail/enum_to_string.hpp"
#include "caf/detail/get_mac_addresses.hpp"
using namespace std; using namespace std;
using namespace caf; using namespace caf;
...@@ -138,6 +139,7 @@ public: ...@@ -138,6 +139,7 @@ public:
} }
}; };
template <class Serializer, class Deserializer>
struct fixture { struct fixture {
int32_t i32 = -345; int32_t i32 = -345;
int64_t i64 = -1234567890123456789ll; int64_t i64 = -1234567890123456789ll;
...@@ -159,21 +161,25 @@ struct fixture { ...@@ -159,21 +161,25 @@ struct fixture {
config cfg; config cfg;
actor_system system; actor_system system;
scoped_execution_unit context;
message msg; message msg;
message recursive;
template <class T, class... Ts> template <class T, class... Ts>
vector<char> serialize(T& x, Ts&... xs) { vector<char> serialize(T& x, Ts&... xs) {
vector<char> buf; vector<char> buf;
binary_serializer bs{&context, buf}; binary_serializer sink{system, buf};
bs(x, xs...); if (auto err = sink(x, xs...))
CAF_FAIL("serialization failed: "
<< system.render(err) << ", data: "
<< deep_to_string(std::forward_as_tuple(x, xs...)));
return buf; return buf;
} }
template <class T, class... Ts> template <class T, class... Ts>
void deserialize(const vector<char>& buf, T& x, Ts&... xs) { void deserialize(const vector<char>& buf, T& x, Ts&... xs) {
binary_deserializer bd{&context, buf}; binary_deserializer source{system, buf};
bd(x, xs...); if (auto err = source(x, xs...))
CAF_FAIL("deserialization failed: " << system.render(err));
} }
// serializes `x` and then deserializes and returns the serialized value // serializes `x` and then deserializes and returns the serialized value
...@@ -191,15 +197,20 @@ struct fixture { ...@@ -191,15 +197,20 @@ struct fixture {
message result; message result;
auto tmp = make_message(x); auto tmp = make_message(x);
deserialize(serialize(tmp), result); deserialize(serialize(tmp), result);
CAF_REQUIRE(result.match_elements<T>()); if (!result.match_elements<T>())
CAF_FAIL("expected: " << x << ", got: " << result);
return result.get_as<T>(0); return result.get_as<T>(0);
} }
fixture() fixture() : system(cfg) {
: system(cfg),
context(&system) {
rs.str.assign(string(str.rbegin(), str.rend())); rs.str.assign(string(str.rbegin(), str.rend()));
msg = make_message(i32, i64, dur, ts, te, str, rs); msg = make_message(i32, i64, dur, ts, te, str, rs);
config_value::dictionary dict;
put(dict, "scheduler.policy", atom("none"));
put(dict, "scheduler.max-threads", 42);
put(dict, "nodes.preload",
make_config_value_list("sun", "venus", "mercury", "earth", "mars"));
recursive = make_message(config_value{std::move(dict)});
} }
}; };
...@@ -227,9 +238,43 @@ struct is_message { ...@@ -227,9 +238,43 @@ struct is_message {
} // namespace <anonymous> } // namespace <anonymous>
CAF_TEST_FIXTURE_SCOPE(serialization_tests, fixture) #define SERIALIZATION_TEST(name) \
template <class Serializer, class Deserializer> \
CAF_TEST(ieee_754_conversion) { struct name##_tpl : fixture<Serializer, Deserializer> { \
using super = fixture<Serializer, Deserializer>; \
using super::i32; \
using super::i64; \
using super::f32; \
using super::f64; \
using super::dur; \
using super::ts; \
using super::te; \
using super::str; \
using super::rs; \
using super::ta; \
using super::ra; \
using super::system; \
using super::msg; \
using super::recursive; \
using super::serialize; \
using super::deserialize; \
using super::roundtrip; \
using super::msg_roundtrip; \
void run_test_impl(); \
}; \
namespace { \
using name##_binary = name##_tpl<binary_serializer, binary_deserializer>; \
using name##_stream = name##_tpl<stream_serializer<vectorbuf>, \
stream_deserializer<charbuf>>; \
::caf::test::detail::adder<::caf::test::test_impl<name##_binary>> \
CAF_UNIQUE(a_binary){CAF_XSTR(CAF_SUITE), CAF_XSTR(name##_binary), false}; \
::caf::test::detail::adder<::caf::test::test_impl<name##_stream>> \
CAF_UNIQUE(a_stream){CAF_XSTR(CAF_SUITE), CAF_XSTR(name##_stream), false}; \
} \
template <class Serializer, class Deserializer> \
void name##_tpl<Serializer, Deserializer>::run_test_impl()
SERIALIZATION_TEST(ieee_754_conversion) {
// check conversion of float // check conversion of float
float f1 = 3.1415925f; // float value float f1 = 3.1415925f; // float value
auto p1 = caf::detail::pack754(f1); // packet value auto p1 = caf::detail::pack754(f1); // packet value
...@@ -244,70 +289,70 @@ CAF_TEST(ieee_754_conversion) { ...@@ -244,70 +289,70 @@ CAF_TEST(ieee_754_conversion) {
CAF_CHECK_EQUAL(f2, u2); CAF_CHECK_EQUAL(f2, u2);
} }
CAF_TEST(i32_values) { SERIALIZATION_TEST(i32_values) {
auto buf = serialize(i32); auto buf = serialize(i32);
int32_t x; int32_t x;
deserialize(buf, x); deserialize(buf, x);
CAF_CHECK_EQUAL(i32, x); CAF_CHECK_EQUAL(i32, x);
} }
CAF_TEST(i64_values) { SERIALIZATION_TEST(i64_values) {
auto buf = serialize(i64); auto buf = serialize(i64);
int64_t x; int64_t x;
deserialize(buf, x); deserialize(buf, x);
CAF_CHECK_EQUAL(i64, x); CAF_CHECK_EQUAL(i64, x);
} }
CAF_TEST(float_values) { SERIALIZATION_TEST(float_values) {
auto buf = serialize(f32); auto buf = serialize(f32);
float x; float x;
deserialize(buf, x); deserialize(buf, x);
CAF_CHECK_EQUAL(f32, x); CAF_CHECK_EQUAL(f32, x);
} }
CAF_TEST(double_values) { SERIALIZATION_TEST(double_values) {
auto buf = serialize(f64); auto buf = serialize(f64);
double x; double x;
deserialize(buf, x); deserialize(buf, x);
CAF_CHECK_EQUAL(f64, x); CAF_CHECK_EQUAL(f64, x);
} }
CAF_TEST(duration_values) { SERIALIZATION_TEST(duration_values) {
auto buf = serialize(dur); auto buf = serialize(dur);
duration x; duration x;
deserialize(buf, x); deserialize(buf, x);
CAF_CHECK_EQUAL(dur, x); CAF_CHECK_EQUAL(dur, x);
} }
CAF_TEST(timestamp_values) { SERIALIZATION_TEST(timestamp_values) {
auto buf = serialize(ts); auto buf = serialize(ts);
timestamp x; timestamp x;
deserialize(buf, x); deserialize(buf, x);
CAF_CHECK_EQUAL(ts, x); CAF_CHECK_EQUAL(ts, x);
} }
CAF_TEST(enum_classes) { SERIALIZATION_TEST(enum_classes) {
auto buf = serialize(te); auto buf = serialize(te);
test_enum x; test_enum x;
deserialize(buf, x); deserialize(buf, x);
CAF_CHECK_EQUAL(te, x); CAF_CHECK_EQUAL(te, x);
} }
CAF_TEST(strings) { SERIALIZATION_TEST(strings) {
auto buf = serialize(str); auto buf = serialize(str);
string x; string x;
deserialize(buf, x); deserialize(buf, x);
CAF_CHECK_EQUAL(str, x); CAF_CHECK_EQUAL(str, x);
} }
CAF_TEST(custom_struct) { SERIALIZATION_TEST(custom_struct) {
auto buf = serialize(rs); auto buf = serialize(rs);
raw_struct x; raw_struct x;
deserialize(buf, x); deserialize(buf, x);
CAF_CHECK_EQUAL(rs, x); CAF_CHECK_EQUAL(rs, x);
} }
CAF_TEST(atoms) { SERIALIZATION_TEST(atoms) {
auto foo = atom("foo"); auto foo = atom("foo");
CAF_CHECK_EQUAL(foo, roundtrip(foo)); CAF_CHECK_EQUAL(foo, roundtrip(foo));
CAF_CHECK_EQUAL(foo, msg_roundtrip(foo)); CAF_CHECK_EQUAL(foo, msg_roundtrip(foo));
...@@ -316,7 +361,7 @@ CAF_TEST(atoms) { ...@@ -316,7 +361,7 @@ CAF_TEST(atoms) {
CAF_CHECK_EQUAL(bar_atom::value, msg_roundtrip(atom("bar"))); CAF_CHECK_EQUAL(bar_atom::value, msg_roundtrip(atom("bar")));
} }
CAF_TEST(raw_arrays) { SERIALIZATION_TEST(raw_arrays) {
auto buf = serialize(ra); auto buf = serialize(ra);
int x[3]; int x[3];
deserialize(buf, x); deserialize(buf, x);
...@@ -324,7 +369,7 @@ CAF_TEST(raw_arrays) { ...@@ -324,7 +369,7 @@ CAF_TEST(raw_arrays) {
CAF_CHECK_EQUAL(ra[i], x[i]); CAF_CHECK_EQUAL(ra[i], x[i]);
} }
CAF_TEST(arrays) { SERIALIZATION_TEST(arrays) {
auto buf = serialize(ta); auto buf = serialize(ta);
test_array x; test_array x;
deserialize(buf, x); deserialize(buf, x);
...@@ -335,7 +380,7 @@ CAF_TEST(arrays) { ...@@ -335,7 +380,7 @@ CAF_TEST(arrays) {
CAF_CHECK_EQUAL(ta.value2[i][j], x.value2[i][j]); CAF_CHECK_EQUAL(ta.value2[i][j], x.value2[i][j]);
} }
CAF_TEST(empty_non_pods) { SERIALIZATION_TEST(empty_non_pods) {
test_empty_non_pod x; test_empty_non_pod x;
auto buf = serialize(x); auto buf = serialize(x);
CAF_REQUIRE(buf.empty()); CAF_REQUIRE(buf.empty());
...@@ -354,7 +399,7 @@ std::string hexstr(const std::vector<char>& buf) { ...@@ -354,7 +399,7 @@ std::string hexstr(const std::vector<char>& buf) {
return oss.str(); return oss.str();
} }
CAF_TEST(messages) { SERIALIZATION_TEST(messages) {
// serialize original message which uses tuple_vals internally and // serialize original message which uses tuple_vals internally and
// deserialize into a message which uses type_erased_value pointers // deserialize into a message which uses type_erased_value pointers
message x; message x;
...@@ -369,9 +414,10 @@ CAF_TEST(messages) { ...@@ -369,9 +414,10 @@ CAF_TEST(messages) {
deserialize(buf2, y); deserialize(buf2, y);
CAF_CHECK_EQUAL(to_string(msg), to_string(y)); CAF_CHECK_EQUAL(to_string(msg), to_string(y));
CAF_CHECK(is_message(y).equal(i32, i64, dur, ts, te, str, rs)); CAF_CHECK(is_message(y).equal(i32, i64, dur, ts, te, str, rs));
CAF_CHECK_EQUAL(to_string(recursive), to_string(roundtrip(recursive)));
} }
CAF_TEST(multiple_messages) { SERIALIZATION_TEST(multiple_messages) {
auto m = make_message(rs, te); auto m = make_message(rs, te);
auto buf = serialize(te, m, msg); auto buf = serialize(te, m, msg);
test_enum t; test_enum t;
...@@ -385,15 +431,15 @@ CAF_TEST(multiple_messages) { ...@@ -385,15 +431,15 @@ CAF_TEST(multiple_messages) {
} }
CAF_TEST(type_erased_value) { SERIALIZATION_TEST(type_erased_value) {
auto buf = serialize(str); auto buf = serialize(str);
type_erased_value_ptr ptr{new type_erased_value_impl<std::string>}; type_erased_value_ptr ptr{new type_erased_value_impl<std::string>};
binary_deserializer bd{&context, buf.data(), buf.size()}; binary_deserializer source{system, buf};
ptr->load(bd); ptr->load(source);
CAF_CHECK_EQUAL(str, *reinterpret_cast<const std::string*>(ptr->get())); CAF_CHECK_EQUAL(str, *reinterpret_cast<const std::string*>(ptr->get()));
} }
CAF_TEST(type_erased_view) { SERIALIZATION_TEST(type_erased_view) {
auto str_view = make_type_erased_view(str); auto str_view = make_type_erased_view(str);
auto buf = serialize(str_view); auto buf = serialize(str_view);
std::string res; std::string res;
...@@ -401,7 +447,7 @@ CAF_TEST(type_erased_view) { ...@@ -401,7 +447,7 @@ CAF_TEST(type_erased_view) {
CAF_CHECK_EQUAL(str, res); CAF_CHECK_EQUAL(str, res);
} }
CAF_TEST(type_erased_tuple) { SERIALIZATION_TEST(type_erased_tuple) {
auto tview = make_type_erased_tuple_view(str, i32); auto tview = make_type_erased_tuple_view(str, i32);
CAF_CHECK_EQUAL(to_string(tview), deep_to_string(std::make_tuple(str, i32))); CAF_CHECK_EQUAL(to_string(tview), deep_to_string(std::make_tuple(str, i32)));
auto buf = serialize(tview); auto buf = serialize(tview);
...@@ -415,7 +461,7 @@ CAF_TEST(type_erased_tuple) { ...@@ -415,7 +461,7 @@ CAF_TEST(type_erased_tuple) {
CAF_CHECK_EQUAL(to_string(tview), deep_to_string(std::make_tuple(str, i32))); CAF_CHECK_EQUAL(to_string(tview), deep_to_string(std::make_tuple(str, i32)));
} }
CAF_TEST(streambuf_serialization) { SERIALIZATION_TEST(streambuf_serialization) {
auto data = std::string{"The quick brown fox jumps over the lazy dog"}; auto data = std::string{"The quick brown fox jumps over the lazy dog"};
std::vector<char> buf; std::vector<char> buf;
// First, we check the standard use case in CAF where stream serializers own // First, we check the standard use case in CAF where stream serializers own
...@@ -443,7 +489,7 @@ CAF_TEST(streambuf_serialization) { ...@@ -443,7 +489,7 @@ CAF_TEST(streambuf_serialization) {
CAF_CHECK(data == target); CAF_CHECK(data == target);
} }
CAF_TEST(byte_sequence_optimization) { SERIALIZATION_TEST(byte_sequence_optimization) {
std::vector<uint8_t> data(42); std::vector<uint8_t> data(42);
std::fill(data.begin(), data.end(), 0x2a); std::fill(data.begin(), data.end(), 0x2a);
std::vector<uint8_t> buf; std::vector<uint8_t> buf;
...@@ -462,7 +508,7 @@ CAF_TEST(byte_sequence_optimization) { ...@@ -462,7 +508,7 @@ CAF_TEST(byte_sequence_optimization) {
[](uint8_t c) { return c == 0x2a; })); [](uint8_t c) { return c == 0x2a; }));
} }
CAF_TEST(long_sequences) { SERIALIZATION_TEST(long_sequences) {
std::vector<char> data; std::vector<char> data;
binary_serializer sink{nullptr, data}; binary_serializer sink{nullptr, data};
size_t n = std::numeric_limits<uint32_t>::max(); size_t n = std::numeric_limits<uint32_t>::max();
...@@ -475,7 +521,7 @@ CAF_TEST(long_sequences) { ...@@ -475,7 +521,7 @@ CAF_TEST(long_sequences) {
CAF_CHECK_EQUAL(n, m); CAF_CHECK_EQUAL(n, m);
} }
CAF_TEST(non-empty vector) { SERIALIZATION_TEST(non_empty_vector) {
CAF_MESSAGE("deserializing into a non-empty vector overrides any content"); CAF_MESSAGE("deserializing into a non-empty vector overrides any content");
std::vector<int> foo{1, 2, 3}; std::vector<int> foo{1, 2, 3};
std::vector<int> bar{0}; std::vector<int> bar{0};
...@@ -487,21 +533,21 @@ CAF_TEST(non-empty vector) { ...@@ -487,21 +533,21 @@ CAF_TEST(non-empty vector) {
// -- our vector<bool> serialization packs into an uint64_t. Hence, the // -- our vector<bool> serialization packs into an uint64_t. Hence, the
// critical sizes to test are 0, 1, 63, 64, and 65. // critical sizes to test are 0, 1, 63, 64, and 65.
CAF_TEST(bool_vector_size_0) { SERIALIZATION_TEST(bool_vector_size_0) {
std::vector<bool> xs; std::vector<bool> xs;
CAF_CHECK_EQUAL(deep_to_string(xs), "[]"); CAF_CHECK_EQUAL(deep_to_string(xs), "[]");
CAF_CHECK_EQUAL(xs, roundtrip(xs)); CAF_CHECK_EQUAL(xs, roundtrip(xs));
CAF_CHECK_EQUAL(xs, msg_roundtrip(xs)); CAF_CHECK_EQUAL(xs, msg_roundtrip(xs));
} }
CAF_TEST(bool_vector_size_1) { SERIALIZATION_TEST(bool_vector_size_1) {
std::vector<bool> xs{true}; std::vector<bool> xs{true};
CAF_CHECK_EQUAL(deep_to_string(xs), "[1]"); CAF_CHECK_EQUAL(deep_to_string(xs), "[1]");
CAF_CHECK_EQUAL(xs, roundtrip(xs)); CAF_CHECK_EQUAL(xs, roundtrip(xs));
CAF_CHECK_EQUAL(xs, msg_roundtrip(xs)); CAF_CHECK_EQUAL(xs, msg_roundtrip(xs));
} }
CAF_TEST(bool_vector_size_63) { SERIALIZATION_TEST(bool_vector_size_63) {
std::vector<bool> xs; std::vector<bool> xs;
for (int i = 0; i < 63; ++i) for (int i = 0; i < 63; ++i)
xs.push_back(i % 3 == 0); xs.push_back(i % 3 == 0);
...@@ -514,7 +560,7 @@ CAF_TEST(bool_vector_size_63) { ...@@ -514,7 +560,7 @@ CAF_TEST(bool_vector_size_63) {
CAF_CHECK_EQUAL(xs, msg_roundtrip(xs)); CAF_CHECK_EQUAL(xs, msg_roundtrip(xs));
} }
CAF_TEST(bool_vector_size_64) { SERIALIZATION_TEST(bool_vector_size_64) {
std::vector<bool> xs; std::vector<bool> xs;
for (int i = 0; i < 64; ++i) for (int i = 0; i < 64; ++i)
xs.push_back(i % 5 == 0); xs.push_back(i % 5 == 0);
...@@ -527,7 +573,7 @@ CAF_TEST(bool_vector_size_64) { ...@@ -527,7 +573,7 @@ CAF_TEST(bool_vector_size_64) {
CAF_CHECK_EQUAL(xs, msg_roundtrip(xs)); CAF_CHECK_EQUAL(xs, msg_roundtrip(xs));
} }
CAF_TEST(bool_vector_size_65) { SERIALIZATION_TEST(bool_vector_size_65) {
std::vector<bool> xs; std::vector<bool> xs;
for (int i = 0; i < 65; ++i) for (int i = 0; i < 65; ++i)
xs.push_back(!(i % 7 == 0)); xs.push_back(!(i % 7 == 0));
...@@ -539,5 +585,3 @@ CAF_TEST(bool_vector_size_65) { ...@@ -539,5 +585,3 @@ CAF_TEST(bool_vector_size_65) {
CAF_CHECK_EQUAL(xs, roundtrip(xs)); CAF_CHECK_EQUAL(xs, roundtrip(xs));
CAF_CHECK_EQUAL(xs, msg_roundtrip(xs)); CAF_CHECK_EQUAL(xs, msg_roundtrip(xs));
} }
CAF_TEST_FIXTURE_SCOPE_END()
...@@ -198,24 +198,18 @@ bool instance::dispatch(execution_unit* ctx, const strong_actor_ptr& sender, ...@@ -198,24 +198,18 @@ bool instance::dispatch(execution_unit* ctx, const strong_actor_ptr& sender,
void instance::write(execution_unit* ctx, buffer_type& buf, void instance::write(execution_unit* ctx, buffer_type& buf,
header& hdr, payload_writer* pw) { header& hdr, payload_writer* pw) {
CAF_LOG_TRACE(CAF_ARG(hdr)); CAF_LOG_TRACE(CAF_ARG(hdr));
error err; binary_serializer sink{ctx, buf};
if (pw != nullptr) { if (pw != nullptr) {
auto pos = buf.size(); // Write the BASP header after the payload.
// write payload first (skip first 72 bytes and write header later) auto header_offset = buf.size();
char placeholder[basp::header_size]; sink.skip(header_size);
buf.insert(buf.end(), std::begin(placeholder), std::end(placeholder)); if (auto err = (*pw)(sink))
binary_serializer bs{ctx, buf}; CAF_LOG_ERROR(CAF_ARG(err));
(*pw)(bs); sink.seek(header_offset);
auto plen = buf.size() - pos - basp::header_size; auto payload_len = buf.size() - (header_offset + basp::header_size);
CAF_ASSERT(plen <= std::numeric_limits<uint32_t>::max()); hdr.payload_len = static_cast<uint32_t>(payload_len);
hdr.payload_len = static_cast<uint32_t>(plen);
stream_serializer<charbuf> out{ctx, buf.data() + pos, basp::header_size};
err = out(hdr);
} else {
binary_serializer bs{ctx, buf};
err = bs(hdr);
} }
if (err) if (auto err = sink(hdr))
CAF_LOG_ERROR(CAF_ARG(err)); CAF_LOG_ERROR(CAF_ARG(err));
} }
......
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