From 1a888dbe66fe02d0ba5c09dcc264545b4f0d5d70 Mon Sep 17 00:00:00 2001
From: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com>
Date: Fri, 18 Dec 2015 20:56:34 -0500
Subject: [PATCH] Fix RCTP multi-inheriting in Serialized and derived classes

This patch fixes Serialized derived classes, using CRTP idom,
by fixing the "constructor forwarding problem".

A derived class has no to use dht::Value::Serialized<Derived, Base>
as super class, by replacing itself in "Derived" and use the
right "Base" class. Ex:

class MyImMessage : public dht::Value::Serializable<MyImMessage, dht::ImMessage>
{
  ...
}

No more needed to overload getType and define TYPE static.
---
 include/opendht/default_types.h | 90 +++++++++++++++++++--------------
 include/opendht/value.h         | 44 ++++++++++------
 2 files changed, 81 insertions(+), 53 deletions(-)

diff --git a/include/opendht/default_types.h b/include/opendht/default_types.h
index db8f4395..33a2a302 100644
--- a/include/opendht/default_types.h
+++ b/include/opendht/default_types.h
@@ -23,18 +23,17 @@
 
 namespace dht {
 
-struct DhtMessage : public Value::Serializable<DhtMessage>
+class DhtMessage : public Value::Serializable<DhtMessage>
 {
+public:
+    static const ValueType TYPE;
+
     DhtMessage(std::string s = {}, Blob msg = {}) : service(s), data(msg) {}
 
     std::string getService() const {
         return service;
     }
 
-    static const ValueType TYPE;
-    virtual const ValueType& getType() const override {
-        return TYPE;
-    }
     static Value::Filter getFilter() { return {}; }
 
     static bool storePolicy(InfoHash key, std::shared_ptr<Value>& value, InfoHash from, const sockaddr* from_addr, socklen_t from_len);
@@ -44,57 +43,64 @@ struct DhtMessage : public Value::Serializable<DhtMessage>
     /** print value for debugging */
     friend std::ostream& operator<< (std::ostream&, const DhtMessage&);
 
-public:
     std::string service;
     Blob data;
     MSGPACK_DEFINE(service, data);
 };
 
-template <typename Type>
-struct SignedValue : public Value::Serializable<Type>
+template <typename T>
+class SignedValue : public Value::Serializable<T>
 {
+private:
+    using BaseClass = Value::Serializable<T>;
+
+public:
     virtual void unpackValue(const Value& v) override {
         from = v.owner.getId();
-        Value::Serializable<Type>::unpackValue(v);
+        BaseClass::unpackValue(v);
     }
+
     static Value::Filter getFilter() {
         return [](const Value& v){ return v.isSigned(); };
     }
-public:
+
     dht::InfoHash from;
 };
 
-template <typename Type>
-struct EncryptedValue : public SignedValue<Type>
+template <typename T>
+class EncryptedValue : public SignedValue<T>
 {
+public:
+    using BaseClass = SignedValue<T>;
+
+public:
     virtual void unpackValue(const Value& v) override {
         to = v.recipient;
-        SignedValue<Type>::unpackValue(v);
+        BaseClass::unpackValue(v);
     }
+
     static Value::Filter getFilter() {
         return Value::Filter::chain(
-            SignedValue<Type>::getFilter(),
+            BaseClass::getFilter(),
             [](const Value& v){ return v.recipient != InfoHash(); }
         );
     }
 
-public:
     dht::InfoHash to;
 };
 
-struct ImMessage : public SignedValue<ImMessage>
+class ImMessage : public SignedValue<ImMessage>
 {
+private:
+    using BaseClass = SignedValue<ImMessage>;
+
+public:
+    static const ValueType TYPE;
+
     ImMessage() {}
     ImMessage(dht::Value::Id id, std::string&& m, long d = 0)
-      : id(id), msg(std::move(m)), date(d) {}
+        : id(id), msg(std::move(m)), date(d) {}
 
-    static const ValueType TYPE;
-    virtual const ValueType& getType() const override {
-        return TYPE;
-    }
-    static Value::Filter getFilter() {
-        return SignedValue::getFilter();
-    }
     virtual void unpackValue(const Value& v) override {
         to = v.recipient;
         SignedValue::unpackValue(v);
@@ -103,20 +109,22 @@ struct ImMessage : public SignedValue<ImMessage>
     dht::InfoHash to;
     dht::Value::Id id;
     std::string msg;
-    long date;
+    long date {0};
     MSGPACK_DEFINE_MAP(id, msg, date);
 };
 
-struct TrustRequest : public EncryptedValue<TrustRequest>
+class TrustRequest : public EncryptedValue<TrustRequest>
 {
+private:
+    using BaseClass = EncryptedValue<TrustRequest>;
+
+public:
+    static const ValueType TYPE;
+
     TrustRequest() {}
     TrustRequest(std::string s) : service(s) {}
     TrustRequest(std::string s, const Blob& d) : service(s), payload(d) {}
 
-    static const ValueType TYPE;
-    virtual const ValueType& getType() const override {
-        return TYPE;
-    }
     static Value::Filter getFilter() {
         return EncryptedValue::getFilter();
     }
@@ -126,15 +134,17 @@ struct TrustRequest : public EncryptedValue<TrustRequest>
     MSGPACK_DEFINE(service, payload);
 };
 
-struct IceCandidates : public EncryptedValue<IceCandidates>
+class IceCandidates : public EncryptedValue<IceCandidates>
 {
+private:
+    using BaseClass = EncryptedValue<IceCandidates>;
+
+public:
+    static const ValueType TYPE;
+
     IceCandidates() {}
     IceCandidates(Value::Id msg_id, Blob ice) : id(msg_id), ice_data(ice) {}
 
-    static const ValueType TYPE;
-    virtual const ValueType& getType() const override {
-        return TYPE;
-    }
     static Value::Filter getFilter() {
         return EncryptedValue::getFilter();
     }
@@ -168,11 +178,16 @@ struct IceCandidates : public EncryptedValue<IceCandidates>
     Blob ice_data;
 };
 
-
 /* "Peer" announcement
  */
-struct IpServiceAnnouncement : public Value::Serializable<IpServiceAnnouncement>
+class IpServiceAnnouncement : public Value::Serializable<IpServiceAnnouncement>
 {
+private:
+    using BaseClass = Value::Serializable<IpServiceAnnouncement>;
+
+public:
+    static const ValueType TYPE;
+
     IpServiceAnnouncement(in_port_t p = 0) {
         ss.ss_family = 0;
         setPort(p);
@@ -226,7 +241,6 @@ struct IpServiceAnnouncement : public Value::Serializable<IpServiceAnnouncement>
         return ss;
     }
 
-    static const ValueType TYPE;
     virtual const ValueType& getType() const {
         return TYPE;
     }
diff --git a/include/opendht/value.h b/include/opendht/value.h
index 4be12f17..693014bc 100644
--- a/include/opendht/value.h
+++ b/include/opendht/value.h
@@ -175,38 +175,52 @@ struct Value
         };
     }
 
-    template <typename T>
-    struct Serializable
+    class SerializableBase
     {
+    public:
+        SerializableBase() {}
+        virtual ~SerializableBase() {};
         virtual const ValueType& getType() const = 0;
+        virtual void unpackValue(const Value& v) = 0;
+        virtual Value packValue() const = 0;
+    };
+
+    template <typename Derived, typename Base=SerializableBase>
+	class Serializable : public Base
+	{
+	public:
+		using Base::Base;
+
+        virtual const ValueType& getType() const {
+            return Derived::TYPE;
+        }
+
         virtual void unpackValue(const Value& v) {
             auto msg = msgpack::unpack((const char*)v.data.data(), v.data.size());
-            msgpack::object obj = msg.get();
-            obj.convert(static_cast<T*>(this));
+            msg.get().convert(static_cast<Derived*>(this));
         }
 
         virtual Value packValue() const {
-            return Value {getType(), static_cast<const T&>(*this)};
+            return Value {getType(), static_cast<const Derived&>(*this)};
         }
-        virtual ~Serializable() = default;
     };
 
     template <typename T,
-              typename std::enable_if<std::is_base_of<Serializable<T>, T>::value, T>::type* = nullptr>
+              typename std::enable_if<std::is_base_of<SerializableBase, T>::value, T>::type* = nullptr>
     static Value pack(const T& obj)
     {
         return obj.packValue();
     }
 
     template <typename T,
-              typename std::enable_if<!std::is_base_of<Serializable<T>, T>::value, T>::type* = nullptr>
+              typename std::enable_if<!std::is_base_of<SerializableBase, T>::value, T>::type* = nullptr>
     static Value pack(const T& obj)
     {
         return {ValueType::USER_DATA.id, packMsg<T>(obj)};
     }
 
     template <typename T,
-              typename std::enable_if<std::is_base_of<Serializable<T>, T>::value, T>::type* = nullptr>
+              typename std::enable_if<std::is_base_of<SerializableBase, T>::value, T>::type* = nullptr>
     static T unpack(const Value& v)
     {
         T msg;
@@ -215,7 +229,7 @@ struct Value
     }
 
     template <typename T,
-              typename std::enable_if<!std::is_base_of<Serializable<T>, T>::value, T>::type* = nullptr>
+              typename std::enable_if<!std::is_base_of<SerializableBase, T>::value, T>::type* = nullptr>
     static T unpack(const Value& v)
     {
         return unpackMsg<T>(v.data);
@@ -245,7 +259,7 @@ struct Value
      : id(id), type(t), data(std::move(data)) {}
     Value(ValueType::Id t, const uint8_t* dat_ptr, size_t dat_len, Id id = INVALID_ID)
      : id(id), type(t), data(dat_ptr, dat_ptr+dat_len) {}
-    
+
     template <typename Type>
     Value(ValueType::Id t, const Type& d, Id id = INVALID_ID)
      : id(id), type(t), data(packMsg(d)) {}
@@ -405,7 +419,7 @@ struct Value
 };
 
 template <typename T,
-          typename std::enable_if<std::is_base_of<Value::Serializable<T>, T>::value, T>::type* = nullptr>
+          typename std::enable_if<std::is_base_of<Value::SerializableBase, T>::value, T>::type* = nullptr>
 Value::Filter
 getFilterSet(Value::Filter f)
 {
@@ -417,7 +431,7 @@ getFilterSet(Value::Filter f)
 }
 
 template <typename T,
-          typename std::enable_if<!std::is_base_of<Value::Serializable<T>, T>::value, T>::type* = nullptr>
+          typename std::enable_if<!std::is_base_of<Value::SerializableBase, T>::value, T>::type* = nullptr>
 Value::Filter
 getFilterSet(Value::Filter f)
 {
@@ -425,7 +439,7 @@ getFilterSet(Value::Filter f)
 }
 
 template <typename T,
-          typename std::enable_if<std::is_base_of<Value::Serializable<T>, T>::value, T>::type* = nullptr>
+          typename std::enable_if<std::is_base_of<Value::SerializableBase, T>::value, T>::type* = nullptr>
 Value::Filter
 getFilterSet()
 {
@@ -436,7 +450,7 @@ getFilterSet()
 }
 
 template <typename T,
-          typename std::enable_if<!std::is_base_of<Value::Serializable<T>, T>::value, T>::type* = nullptr>
+          typename std::enable_if<!std::is_base_of<Value::SerializableBase, T>::value, T>::type* = nullptr>
 Value::Filter
 getFilterSet()
 {
-- 
GitLab