Commit 89bf26d1 authored by Dominik Charousset's avatar Dominik Charousset

Remove giant switch-case in serializer code

parent e9946674
...@@ -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);
} }
......
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