Boost logo

Boost :

From: troy d. straszheim (troy_at_[hidden])
Date: 2005-02-08 23:39:23


troy d. straszheim wrote:

> // the variant. Is there a better idiom for this than
> // preprocessor metaprogramming inside a switch statement?

There is a better idiom, Richard Crossley sent me a very cool mpl::fold
trick. (Thanks Richard!) Improved serialization/variant.hpp attached.

troy d. straszheim


#ifndef BOOST_SERIALIZATION_VARIANT_HPP
#define BOOST_SERIALIZATION_VARIANT_HPP

//
// boost/seriaization/variant.hpp
// non-intrusive serialization of variant types
//
// copyright (c) 2005
// troy d. straszheim <troy_at_[hidden]>
// http://www.resophonic.com
//
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org for updates, documentation, and revision history.
//
// thanks to Robert Ramey, Peter Dimov, and Richard Crossley.
//

#include <boost/serialization/serialization.hpp>
#include <boost/serialization/split_free.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/bind.hpp>
#include <boost/ref.hpp>
#include <boost/variant.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/mpl/at.hpp>
#include <boost/mpl/int.hpp>
#include <boost/mpl/size.hpp>
#include <boost/mpl/greater_equal.hpp>
#include <boost/mpl/eval_if.hpp>
#include <boost/mpl/identity.hpp>
#include <boost/throw_exception.hpp>
#include <boost/archive/archive_exception.hpp>
#include <boost/preprocessor/repetition/repeat.hpp>
#include <boost/serialization/split_free.hpp>
#include <boost/mpl/fold.hpp>
#include <boost/mpl/int.hpp>

namespace boost {
  namespace serialization {
    namespace variant {

      struct stop_tag { };

      template <typename Value = mpl::void_,
                typename Base = stop_tag>
      struct variant_in : Base
      {
        enum { index = 1 + Base::index };

        template <typename Archive, typename Variant>
        static void exec(Archive& ar, int discriminator, Variant& var)
        {
          if (discriminator == index) {
            Value value;
            ar >> BOOST_SERIALIZATION_NVP(value);
            var = value;
            return;
          }
          Base::exec(ar,discriminator,var);
        }
      };

      using boost::archive::archive_exception;
      template <>
      struct variant_in<mpl::void_, stop_tag>
      {
        enum { index = -1 };

        template <typename Archive,typename V>
        static void exec(Archive& ar,int discriminator,V& v)
        {
          boost::throw_exception(archive_exception(archive_exception::stream_error));
        }
      };

      struct save_visitor : boost::static_visitor<>
      {
        template<class Archive, class T>
        void operator()(Archive & ar, T const & value ) const
        {
          ar << BOOST_SERIALIZATION_NVP(value);
        }
      };

    } // namespace boost::serialization::variant

    template<class Archive,BOOST_VARIANT_ENUM_PARAMS(typename T)>
    void load(Archive & ar,
              boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& v,
              unsigned int version)
    {
      typedef typename boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>::types types;
      int which;
      ar >> BOOST_SERIALIZATION_NVP(which);
   
      // fold<> from Richard Crossley. Wicked. The call to exec
      // starts in the most-derived part of the composite class
      // generated by fold and recursively works its way down.
      mpl::fold<
        types, variant::variant_in<>, variant::variant_in<mpl::_2,mpl::_1>
>::type::exec(ar,which,v);
    }

    template<class Archive,BOOST_VARIANT_ENUM_PARAMS(typename T)>
    void save(Archive & ar,
              boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const & v,
              unsigned int version)
    {
      int which = v.which();
      ar << BOOST_SERIALIZATION_NVP(which);
      // thx Peter Dimov
      apply_visitor( bind( variant::save_visitor(), boost::ref(ar), _1 ), v );
    }

    template<class Archive,BOOST_VARIANT_ENUM_PARAMS(typename T)>
    inline void serialize(Archive & ar,
                          boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> & v,
                          unsigned int file_version)
    {
      split_free(ar,v,file_version);
    }
  }
}

#endif //BOOST_SERIALIZATION_VARIANT_HPP


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk