From 0e05c8b2d291ff98571d9bddf146d138855e8ef7 Mon Sep 17 00:00:00 2001
From: Joseph Mirabel <jmirabel@laas.fr>
Date: Mon, 14 Dec 2020 18:38:55 +0100
Subject: [PATCH] Update serialization functions.

---
 include/hpp/manipulation/device.hh        |  2 +
 include/hpp/manipulation/graph/graph.hh   |  4 +
 include/hpp/manipulation/serialization.hh | 98 +++++++++++------------
 src/device.cc                             | 11 ++-
 src/steering-method/graph.cc              |  2 +-
 5 files changed, 59 insertions(+), 58 deletions(-)

diff --git a/include/hpp/manipulation/device.hh b/include/hpp/manipulation/device.hh
index 1841997..2586170 100644
--- a/include/hpp/manipulation/device.hh
+++ b/include/hpp/manipulation/device.hh
@@ -50,6 +50,8 @@ namespace hpp {
           return shPtr;
         }
 
+        DevicePtr_t self () const { return self_.lock(); }
+
         /// Print object in a stream
         virtual std::ostream& print (std::ostream& os) const;
 
diff --git a/include/hpp/manipulation/graph/graph.hh b/include/hpp/manipulation/graph/graph.hh
index 0cef13e..ade3266 100644
--- a/include/hpp/manipulation/graph/graph.hh
+++ b/include/hpp/manipulation/graph/graph.hh
@@ -52,6 +52,8 @@ namespace hpp {
 	  static GraphPtr_t create(const std::string& name, DevicePtr_t robot,
 				   const ProblemPtr_t& problem);
 
+          GraphPtr_t self () const { return wkPtr_.lock(); }
+
           /// Create and insert a state selector inside the graph.
           StateSelectorPtr_t createStateSelector (const std::string& name);
 
@@ -301,4 +303,6 @@ namespace hpp {
 
 } // namespace hpp
 
+BOOST_CLASS_EXPORT_KEY(hpp::manipulation::graph::Graph)
+
 #endif // HPP_MANIPULATION_GRAPH_GRAPH_HH
diff --git a/include/hpp/manipulation/serialization.hh b/include/hpp/manipulation/serialization.hh
index 0711fc4..cfb1835 100644
--- a/include/hpp/manipulation/serialization.hh
+++ b/include/hpp/manipulation/serialization.hh
@@ -34,10 +34,33 @@
 
 namespace hpp {
 namespace serialization {
-struct archive_graph_wrapper {
-  manipulation::graph::GraphPtr_t graph;
-  virtual ~archive_graph_wrapper() {}
-};
+template<typename Archive>
+manipulation::graph::GraphPtr_t getGraphFromArchive(Archive& ar, const std::string& name)
+{
+  auto* har = hpp::serialization::cast(&ar);
+  if (!har || !har->contains(name))
+    throw std::runtime_error("Cannot deserialize edges with a provided graph with correct name.");
+  return har->template get<manipulation::graph::Graph>(name, true)->self();
+}
+
+template<class Archive, class GraphCompT>
+inline void serializeGraphComponent(Archive & ar, boost::shared_ptr<GraphCompT>& c, const unsigned int version)
+{
+  (void) version;
+
+  std::size_t id;
+  std::string name;
+  if (Archive::is_saving::value) {
+    id = (c ? c->id() : -1);
+    if (c && c->parentGraph()) name = c->parentGraph()->name();
+  }
+  ar & BOOST_SERIALIZATION_NVP(id);
+  ar & BOOST_SERIALIZATION_NVP(name);
+  if (!Archive::is_saving::value) {
+    auto graph = getGraphFromArchive(ar, name);
+    c = HPP_DYNAMIC_PTR_CAST(GraphCompT, graph->get(id).lock());
+  }
+}
 } // namespace manipulation
 } // namespace hpp
 
@@ -51,64 +74,32 @@ namespace serialization {
 template<class Archive>
 inline void serialize(Archive & ar, hpp::manipulation::graph::GraphPtr_t& g, const unsigned int version)
 {
-  using hpp::serialization::archive_graph_wrapper;
-  using namespace hpp::manipulation::graph;
+  using hpp::serialization::getGraphFromArchive;
   (void) version;
 
-  std::size_t id;
-  if (Archive::is_saving::value) id = g->id();
-  ar & BOOST_SERIALIZATION_NVP(id);
-  if (!Archive::is_saving::value) {
-    archive_graph_wrapper* agw = dynamic_cast<archive_graph_wrapper*>(&ar);
-    if (agw == NULL)
-      throw std::runtime_error("Cannot deserialize edges with a archive_graph_wrapper");
-    g = agw->graph;
-  }
+  std::string name;
+  if (Archive::is_saving::value) name = g->name();
+  ar & BOOST_SERIALIZATION_NVP(name);
+  if (!Archive::is_saving::value)
+    g = getGraphFromArchive(ar, name);
 }
 
 template<class Archive>
 inline void serialize(Archive & ar, hpp::manipulation::graph::EdgePtr_t& e, const unsigned int version)
 {
-  using hpp::serialization::archive_graph_wrapper;
-  using namespace hpp::manipulation::graph;
-  (void) version;
-
-  std::size_t id;
-  if (Archive::is_saving::value) id = (e ? e->id() : -1);
-  ar & BOOST_SERIALIZATION_NVP(id);
-  if (!Archive::is_saving::value) {
-    archive_graph_wrapper* agw = dynamic_cast<archive_graph_wrapper*>(&ar);
-    if (agw == NULL)
-      throw std::runtime_error("Cannot deserialize edges with a archive_graph_wrapper");
-    GraphComponentPtr_t gc = agw->graph->get(id).lock();
-    e = HPP_DYNAMIC_PTR_CAST(Edge, gc);
-  }
+  hpp::serialization::serializeGraphComponent (ar, e, version);
 }
 
 template<class Archive>
 inline void serialize(Archive & ar, hpp::manipulation::graph::StatePtr_t& s, const unsigned int version)
 {
-  using hpp::serialization::archive_graph_wrapper;
-  using namespace hpp::manipulation::graph;
-  (void) version;
-
-  std::size_t id;
-  if (Archive::is_saving::value) id = (s ? s->id() : -1);
-  ar & BOOST_SERIALIZATION_NVP(id);
-  if (!Archive::is_saving::value) {
-    archive_graph_wrapper* agw = dynamic_cast<archive_graph_wrapper*>(&ar);
-    if (agw == NULL)
-      throw std::runtime_error("Cannot deserialize edges with a archive_graph_wrapper");
-    GraphComponentPtr_t gc = agw->graph->get(id).lock();
-    s = HPP_DYNAMIC_PTR_CAST(State, gc);
-  }
+  hpp::serialization::serializeGraphComponent (ar, s, version);
 }
 
 template<class Archive>
 inline void serialize(Archive & ar, hpp::manipulation::graph::EdgeWkPtr_t& e, const unsigned int version)
 {
-  using namespace hpp::manipulation::graph;
-  EdgePtr_t e_ = e.lock();
+  auto e_ = e.lock();
   serialize(ar, e_, version);
   e = e_;
 }
@@ -116,8 +107,7 @@ inline void serialize(Archive & ar, hpp::manipulation::graph::EdgeWkPtr_t& e, co
 template<class Archive>
 inline void serialize(Archive & ar, hpp::manipulation::graph::StateWkPtr_t& s, const unsigned int version)
 {
-  using namespace hpp::manipulation::graph;
-  StatePtr_t s_ = s.lock();
+  auto s_ = s.lock();
   serialize(ar, s_, version);
   s = s_;
 }
@@ -126,18 +116,20 @@ template<class Archive>
 inline void load (Archive& ar, hpp::manipulation::DevicePtr_t& d, const unsigned int version)
 {
   load<Archive, hpp::manipulation::Device> (ar, d, version);
-  using hpp::serialization::archive_device_wrapper;
-  archive_device_wrapper* adw = dynamic_cast<archive_device_wrapper*>(&ar);
-  if (adw) d = boost::dynamic_pointer_cast<hpp::manipulation::Device>(adw->device);
+  auto* har = hpp::serialization::cast(&ar);
+  if (d && har && har->contains(d->name()))
+    d = har->template getChildClass<hpp::pinocchio::Device, hpp::manipulation::Device>(d->name(), true)->self();
 }
 
 template<class Archive>
 inline void load (Archive& ar, hpp::manipulation::DeviceWkPtr_t& d, const unsigned int version)
 {
   load<Archive, hpp::manipulation::Device> (ar, d, version);
-  using hpp::serialization::archive_device_wrapper;
-  archive_device_wrapper* adw = dynamic_cast<archive_device_wrapper*>(&ar);
-  if (adw) d = boost::dynamic_pointer_cast<hpp::manipulation::Device>(adw->device);
+  auto* har = hpp::serialization::cast(&ar);
+  auto dd = d.lock();
+  if (!dd) return;
+  if (har && har->contains(dd->name()))
+    d = har->template getChildClass<hpp::pinocchio::Device, hpp::manipulation::Device>(dd->name(), true)->self();
 }
 } // namespace serialization
 } // namespace boost
diff --git a/src/device.cc b/src/device.cc
index 665301d..09b8b4a 100644
--- a/src/device.cc
+++ b/src/device.cc
@@ -139,13 +139,16 @@ namespace hpp {
     template<class Archive>
     void Device::serialize(Archive & ar, const unsigned int version)
     {
-      using hpp::serialization::archive_device_wrapper;
       using namespace boost::serialization;
-
       (void) version;
+      auto* har = hpp::serialization::cast(&ar);
+
       ar & make_nvp("base", base_object<pinocchio::HumanoidRobot>(*this));
-      archive_device_wrapper* adw = dynamic_cast<archive_device_wrapper*>(&ar);
-      bool written = (adw == NULL);
+
+      // TODO we should throw if a pinocchio::Device instance with name name_
+      // and not of type manipulation::Device is found.
+      bool written = (!har ||
+          har->template getChildClass<pinocchio::Device, Device>(name_, false) != this);
       ar & BOOST_SERIALIZATION_NVP(written);
       if (written) {
         ar & BOOST_SERIALIZATION_NVP(self_);
diff --git a/src/steering-method/graph.cc b/src/steering-method/graph.cc
index 0e47f49..f7d778c 100644
--- a/src/steering-method/graph.cc
+++ b/src/steering-method/graph.cc
@@ -44,7 +44,7 @@ namespace hpp {
       GraphPtr_t Graph::create
         (const core::ProblemConstPtr_t& problem)
         {
-          assert(HPP_DYNAMIC_PTR_CASE (const Problem, problem));
+          assert(HPP_DYNAMIC_PTR_CAST (const Problem, problem));
           ProblemConstPtr_t p = HPP_STATIC_PTR_CAST(const Problem, problem);
           Graph* ptr = new Graph (p);
           GraphPtr_t shPtr (ptr);
-- 
GitLab