Fix serialization of boost::variant

This commit is contained in:
nsubiron 2019-01-25 16:21:56 +01:00
parent 5f7c8b797b
commit 8296b50aec
5 changed files with 123 additions and 76 deletions

View File

@ -0,0 +1,96 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "carla/MsgPack.h"
#include <boost/variant.hpp>
#include <tuple>
namespace clmdep_msgpack {
MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS) {
namespace adaptor {
// ===========================================================================
// -- Adaptors for boost::variant --------------------------------------------
// ===========================================================================
template<typename... Ts>
struct convert<boost::variant<Ts...>> {
const clmdep_msgpack::object &operator()(
const clmdep_msgpack::object &o,
boost::variant<Ts...> &v) const {
if (o.type != clmdep_msgpack::type::ARRAY) {
throw clmdep_msgpack::type_error();
}
if (o.via.array.size != 2) {
throw clmdep_msgpack::type_error();
}
const auto index = o.via.array.ptr[0].as<int>();
copy_to_variant(index, o, v, std::make_index_sequence<sizeof...(Ts)>());
return o;
}
private:
template <size_t I>
static void copy_to_variant_impl(
const clmdep_msgpack::object &o,
boost::variant<Ts...> &v) {
/// @todo Workaround for finding the type.
auto dummy = std::get<I>(std::tuple<Ts...>{});
using T = decltype(dummy);
v = o.via.array.ptr[1].as<T>();
}
template <size_t... Is>
static void copy_to_variant(
const size_t index,
const clmdep_msgpack::object &o,
boost::variant<Ts...> &v,
std::index_sequence<Is...>) {
std::initializer_list<int> ({
(index == Is ? copy_to_variant_impl<Is>(o, v), 0 : 0)...
});
}
};
template<typename... Ts>
struct pack<boost::variant<Ts...>> {
template <typename Stream>
packer<Stream> &operator()(
clmdep_msgpack::packer<Stream> &o,
const boost::variant<Ts...> &v) const {
o.pack_array(2);
o.pack(static_cast<int>(v.which()));
boost::apply_visitor([&](const auto &value) { o.pack(value); }, v);
return o;
}
};
template<typename... Ts>
struct object_with_zone<boost::variant<Ts...>> {
void operator()(
clmdep_msgpack::object::with_zone &o,
const boost::variant<Ts...> &v) const {
o.type = type::ARRAY;
o.via.array.size = 2;
o.via.array.ptr = static_cast<clmdep_msgpack::object*>(o.zone.allocate_align(
sizeof(clmdep_msgpack::object) * o.via.array.size,
MSGPACK_ZONE_ALIGNOF(clmdep_msgpack::object)));
o.via.array.ptr[0] = clmdep_msgpack::object(static_cast<int>(v.which()), o.zone);
boost::apply_visitor([&](const auto &value) {
o.via.array.ptr[1] = clmdep_msgpack::object(value, o.zone);
}, v);
}
};
} // namespace adaptor
} // MSGPACK_API_VERSION_NAMESPACE(MSGPACK_DEFAULT_API_NS)
} // namespace msgpack

View File

@ -6,15 +6,14 @@
#pragma once #pragma once
#include "carla/MsgPack.h"
#include "carla/MsgPackAdaptors.h"
#include "carla/geom/BoundingBox.h" #include "carla/geom/BoundingBox.h"
#include "carla/geom/Location.h" #include "carla/geom/Location.h"
#include "carla/geom/Rotation.h" #include "carla/geom/Rotation.h"
#include "carla/rpc/Color.h" #include "carla/rpc/Color.h"
#include "carla/rpc/Variant.h"
// #include <rpc/msgpack/adaptor/boost/msgpack_variant.hpp> #include <boost/variant.hpp>
// #include <boost/variant.hpp>
namespace carla { namespace carla {
namespace rpc { namespace rpc {
@ -55,7 +54,7 @@ namespace rpc {
MSGPACK_DEFINE_ARRAY(location, text, draw_shadow); MSGPACK_DEFINE_ARRAY(location, text, draw_shadow);
}; };
Variant<Point, Line, Arrow, Box, String> primitive; boost::variant<Point, Line, Arrow, Box, String> primitive;
Color color = {255u, 0u, 0u}; Color color = {255u, 0u, 0u};

View File

@ -1,70 +0,0 @@
// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "carla/MsgPack.h"
#include <tuple>
namespace carla {
namespace rpc {
/// @todo Workaround for packing boost::variant; it uses tuple instead so it's
/// quite inefficient memory-wise.
template <typename... Ts>
class Variant {
private:
size_t _index = 0u;
std::tuple<Ts...> _tuple;
template <typename T, typename Tuple>
struct IndexFromType;
template <typename T, typename... Types>
struct IndexFromType<T, std::tuple<T, Types...>> {
static constexpr size_t value = 0u;
};
template <typename T, typename U, typename... Types>
struct IndexFromType<T, std::tuple<U, Types...>> {
static constexpr size_t value = 1u + IndexFromType<T, std::tuple<Types...>>::value;
};
template <typename VisitorT, size_t... Is>
void ApplyVisitorImpl(VisitorT &visitor, std::index_sequence<Is...>) const {
std::initializer_list<int> ({ (_index == Is ? visitor(std::get<Is>(_tuple)), 0 : 0)... });
}
public:
Variant() = default;
template <typename ObjT>
Variant(ObjT &&rhs) {
(*this) = std::forward<ObjT>(rhs);
}
template <typename ObjT>
Variant &operator=(ObjT &&rhs) {
constexpr auto index = IndexFromType<typename std::decay<ObjT>::type, decltype(_tuple)>::value;
_index = index;
std::get<index>(_tuple) = std::forward<ObjT>(rhs);
return *this;
}
template <typename VisitorT>
void ApplyVisitor(VisitorT visitor) const {
return ApplyVisitorImpl(visitor, std::make_index_sequence<sizeof...(Ts)>());
}
MSGPACK_DEFINE_ARRAY(_index, _tuple);
};
} // namespace rpc
} // namespace carla

View File

@ -6,6 +6,7 @@
#include "test.h" #include "test.h"
#include <carla/MsgPackAdaptors.h>
#include <carla/ThreadGroup.h> #include <carla/ThreadGroup.h>
#include <carla/rpc/Actor.h> #include <carla/rpc/Actor.h>
#include <carla/rpc/Client.h> #include <carla/rpc/Client.h>
@ -75,3 +76,24 @@ TEST(rpc, msgpack) {
ASSERT_EQ(result.description.id, actor.description.id); ASSERT_EQ(result.description.id, actor.description.id);
ASSERT_EQ(result.bounding_box, actor.bounding_box); ASSERT_EQ(result.bounding_box, actor.bounding_box);
} }
TEST(rpc, msgpack_variant) {
using mp = carla::MsgPack;
boost::variant<bool, float, std::string> var;
var = true;
auto result = mp::UnPack<decltype(var)>(mp::Pack(var));
ASSERT_EQ(result.which(), 0);
ASSERT_EQ(boost::get<bool>(result), true);
var = 42.0f;
result = mp::UnPack<decltype(var)>(mp::Pack(var));
ASSERT_EQ(result.which(), 1);
ASSERT_EQ(boost::get<float>(result), 42.0f);
var = std::string("hola!");
result = mp::UnPack<decltype(var)>(mp::Pack(var));
ASSERT_EQ(result.which(), 2);
ASSERT_EQ(boost::get<std::string>(result), "hola!");
}

View File

@ -106,5 +106,5 @@ private:
void FDebugShapeDrawer::Draw(const carla::rpc::DebugShape &Shape) void FDebugShapeDrawer::Draw(const carla::rpc::DebugShape &Shape)
{ {
auto Visitor = FShapeVisitor(World, Shape.color, Shape.life_time, Shape.persistent_lines); auto Visitor = FShapeVisitor(World, Shape.color, Shape.life_time, Shape.persistent_lines);
Shape.primitive.ApplyVisitor(Visitor); boost::apply_visitor(Visitor, Shape.primitive);
} }