[mlpack-git] master: Add wrapper for boost::serialization. This means we can write Serialize() not serialize(). (And thus we stay in accordance with the style guidelines.) (2fecd93)
gitdub at big.cc.gt.atl.ga.us
gitdub at big.cc.gt.atl.ga.us
Fri Jul 10 18:58:59 EDT 2015
Repository : https://github.com/mlpack/mlpack
On branch : master
Link : https://github.com/mlpack/mlpack/compare/4a97187bbba7ce8a6191b714949dd818ef0f37d2...e5905e62c15d1bcff21e6359b11efcd7ab6d7ca0
>---------------------------------------------------------------
commit 2fecd93a05d682610359763624a1c9d0394a5e6f
Author: ryan <ryan at ratml.org>
Date: Tue Apr 14 09:42:34 2015 -0400
Add wrapper for boost::serialization.
This means we can write Serialize() not serialize(). (And thus we stay in accordance with the style guidelines.)
>---------------------------------------------------------------
2fecd93a05d682610359763624a1c9d0394a5e6f
src/mlpack/core/util/serialization_shim.hpp | 212 ++++++++++++++++++++++++++++
1 file changed, 212 insertions(+)
diff --git a/src/mlpack/core/util/serialization_shim.hpp b/src/mlpack/core/util/serialization_shim.hpp
new file mode 100644
index 0000000..7f5904a
--- /dev/null
+++ b/src/mlpack/core/util/serialization_shim.hpp
@@ -0,0 +1,212 @@
+/**
+ * @file serialization_shim.hpp
+ * @author Ryan Curtin
+ *
+ * This file contains the necessary shims to make boost.serialization work with
+ * classes that have a Serialize() method (instead of a serialize() method).
+ *
+ * This allows our mlpack naming conventions to remain intact, and only costs a
+ * small amount of ridiculous template metaprogramming.
+ */
+#ifndef __MLPACK_CORE_UTIL_SERIALIZATION_SHIM_HPP
+#define __MLPACK_CORE_UTIL_SERIALIZATION_SHIM_HPP
+
+#include <mlpack/prereqs.hpp>
+#include <boost/serialization/serialization.hpp>
+#include "sfinae_utility.hpp"
+
+namespace mlpack {
+namespace util {
+
+// This gives us a HasSerialize<T, U> type (where U is a function pointer) we
+// can use with SFINAE to catch when a type has a Serialize() function.
+HAS_MEM_FUNC(Serialize, HasSerialize);
+
+// Declare the shims we need.
+template<typename T> class FirstShim;
+template<typename T> class SecondShim;
+
+/**
+ * Call this function to produce a name-value pair; this is similar to
+ * BOOST_SERIALIZATION_NVP(), but should be used for types that have a
+ * Serialize() function (or contain a type that has a Serialize() function)
+ * instead of a serialize() function. The template type should be automatically
+ * deduced, and the two boost::enable_if<> parameters are automatically deduced
+ * too. So usage looks like
+ *
+ * @code
+ * MyType t;
+ * CreateNVP(t, "my_name_for_t");
+ * @endcode
+ *
+ * Note that the second parameter, 'name', must be a valid XML identifier.
+ *
+ * This function does not return a boost::serialization::nvp<T> object, but
+ * instead a shim type (FirstShim<T>).
+ *
+ * This particular overload is used by classes that have a Serialize() function.
+ *
+ * @param t Object to create NVP (name-value pair) with.
+ * @param name Name of object (must be a valid XML identifier).
+ */
+template<typename T>
+inline FirstShim<T> CreateNVP(
+ T& t,
+ const char* name,
+ typename boost::enable_if<boost::is_class<T>>::type* = 0,
+ typename boost::enable_if<HasSerialize<T,
+ void(T::*)(boost::archive::xml_oarchive& const unsigned int)>>::
+ type* = 0)
+{
+ return FirstShim<T>(t, name);
+}
+
+/**
+ * Call this function to produce a name-value pair; this is similar to
+ * BOOST_SERIALIZATION_NVP(), but should be used for types that have a
+ * Serialize() function (or contain a type that has a Serialize() function)
+ * instead of a serialize() function. The template type should be automatically
+ * deduced, and the two boost::enable_if<> parameters are automatically deduced
+ * too. So usage looks like
+ *
+ * @code
+ * MyType t;
+ * CreateNVP(t, "my_name_for_t");
+ * @endcode
+ *
+ * Note that the second parameter, 'name', must be a valid XML identifier.
+ *
+ * This particular overload is used by classes that do not have a Serialize()
+ * function (so, no shim is necessary).
+ *
+ * @param t Object to create NVP (name-value pair) with.
+ * @param name Name of object (must be a valid XML identifier).
+ */
+template<typename T>
+inline
+#ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
+const // Imitate the boost::serialization make_nvp() function.
+#endif
+boost::serialization::nvp<T> CreateNVP(
+ T& t,
+ const char* name,
+ typename boost::enable_if<boost::is_class<T>>::type* = 0,
+ typename boost::disable_if<HasSerialize<T,
+void(T::*)(boost::archive::xml_oarchive&, const unsigned int)>>::type* = 0)
+{
+ return boost::serialization::make_nvp(name, t);
+}
+
+/**
+ * Call this function to produce a name-value pair; this is similar to
+ * BOOST_SERIALIZATION_NVP(), but should be used for types that have a
+ * Serialize() function (or contain a type that has a Serialize() function)
+ * instead of a serialize() function. The template type should be automatically
+ * deduced, and the two boost::enable_if<> parameters are automatically deduced
+ * too. So usage looks like
+ *
+ * @code
+ * MyType t;
+ * CreateNVP(t, "my_name_for_t");
+ * @endcode
+ *
+ * Note that the second parameter, 'name', must be a valid XML identifier.
+ *
+ * This particular overload is used by primitive types.
+ *
+ * @param t Object to create NVP (name-value pair) with.
+ * @param name Name of object (must be a valid XML identifier).
+ */
+template<typename T>
+inline
+#ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING
+const // Imitate the boost::serialization make_nvp() function.
+#endif
+boost::serialization::nvp<T> CreateNVP(
+ T& t,
+ const char* name,
+ typename boost::disable_if<boost::is_class<T>>::type* = 0)
+{
+ return boost::serialization::make_nvp(name, t);
+}
+
+/**
+ * The first shim: simply holds the object and its name. This shim's purpose is
+ * to be caught by our overloads of operator<<, operator&, and operator>>, which
+ * then creates a second shim.
+ */
+template<typename T>
+struct FirstShim
+{
+ //! Construct the first shim with the given object and name.
+ FirstShim(T& t, const char* name) : t(t), name(name) { }
+
+ T& t;
+ const char* name;
+};
+
+/**
+ * The second shim: wrap the call to Serialize() inside of a serialize()
+ * function, so that an archive type can call serialize() on a SecondShim object
+ * and this gets forwarded correctly to our object's Serialize() function.
+ */
+template<typename T>
+struct SecondShim
+{
+ //! Construct the second shim. The name isn't necessary for this shim.
+ SecondShim(T& t) : t(t) { }
+
+ //! A wrapper for t.Serialize().
+ template<typename Archive>
+ void serialize(Archive& ar, const unsigned int version)
+ {
+ t.Serialize(ar, version);
+ }
+};
+
+/**
+ * Catch when we call operator<< with a FirstShim object. In this case, we make
+ * the second-level shim and use it. Note that this second-level shim can be
+ * used as an lvalue, which is what's necessary for this whole thing to work.
+ * The first-level shim can't be an lvalue (this is why we need two levels of
+ * shims).
+ */
+template<typename Archive, typename T>
+Archive& operator<<(Archive& ar, FirstShim<T> t)
+{
+ SecondShim<T> sh(t.t);
+ return (ar << boost::serialization::make_nvp(t.name, sh));
+}
+
+/**
+ * Catch when we call operator& with a FirstShim object. In this case, we make
+ * the second-level shim and use it. Note that this second-level shim can be
+ * used as an lvalue, which is what's necessary for this whole thing to work.
+ * The first-level shim can't be an lvalue (this is why we need two levels of
+ * shims).
+ */
+template<typename Archive, typename T>
+Archive& operator&(Archive& ar, FirstShim<T> t)
+{
+ SecondShim<T> sh(t.t);
+ return (ar & boost::serialization::make_nvp(t.name, sh));
+}
+
+/**
+ * Catch when we call operator<< with a FirstShim object. In this case, we make
+ * the second-level shim and use it. Note that this second-level shim can be
+ * used as an lvalue, which is what's necessary for this whole thing to work.
+ * The first-level shim can't be an lvalue (this is why we need two levels of
+ * shims).
+ */
+template<typename Archive, typename T>
+Archive& operator>>(Archive& ar, FirstShim<T> t)
+{
+ SecondShim<T> sh(t.t);
+ return (ar >> boost::serialization::make_nvp(t.name, sh));
+}
+
+} // namespace util
+} // namespace mlpack
+
+#endif
More information about the mlpack-git
mailing list