The solution to my problem is a combination of boost::serialization and 
boost::shared_ptr.

Rather than holding refs to the contained shared objects, if the objects are 
share_ptr, then serialization will do the correct thing.

For example, I have

struct boost_uniform_int_wrap {
  boost::shared_ptr<rng_t> rng_obj;
  boost::uniform_int<> gen;

  boost_uniform_int_wrap (boost::shared_ptr<rng_t> _rng_obj, int min, int max) :
    rng_obj (_rng_obj),
    gen (min, max) {}
...

struct uniform_int_pickle_suite : bp::pickle_suite {
  static bp::tuple getinitargs (boost_uniform_int_wrap const& gen) {
    return bp::make_tuple (gen.rng_obj, gen.gen.min(), gen.gen.max());
  }
};

Also, I have modified mersenne_twister to make it serializable (very simple to 
add).

Then to make mersenne_twister pickleable:

typedef boost::mt19937 rng_t;

struct mt_pickle_suite : bp::pickle_suite {
    
  static bp::object getstate (const rng_t& rng) {
    std::ostringstream os;
    boost::archive::binary_oarchive oa(os);
    oa << rng;
    return bp::str (os.str());
  }

  static void
  setstate(rng_t& rng, bp::object entries) {
    bp::str s = bp::extract<bp::str> (entries)();
    std::string st = bp::extract<std::string> (s)();
    std::istringstream is (st);
    
    boost::archive::binary_iarchive ia (is);
    ia >> rng;
  }
};

Now:
from boost_rand import rng, normal
from sys import getrefcount

rng1 = rng()
print getrefcount(rng1)
n1 = normal (rng1, 1, 0)
print getrefcount(rng1)
n2 = normal (rng1, 1, 0)
print getrefcount(rng1)

from cPickle import dumps, loads
rng2, n3, n4 = loads (dumps ((rng1, n1, n2), -1))

In [10]: ## working on region in file /usr/tmp/python-18983NT.py...
2
3
4

In [11]: rng2
Out[11]: <boost_rand.rng at 0x307c838>

In [12]: n3.rng
Out[12]: <boost_rand.rng at 0x307c838>

In [13]: n4.rng
Out[13]: <boost_rand.rng at 0x307c838>

_______________________________________________
Cplusplus-sig mailing list
Cplusplus-sig@python.org
http://mail.python.org/mailman/listinfo/cplusplus-sig

Reply via email to