Boost logo

Boost :

From: JOAQUIN LOPEZ MU?Z (joaquin_at_[hidden])
Date: 2007-09-26 17:21:47


Reviewing the discussion in the thread entitled
"[serialization][trunk] please bring us archive helpers back" at
http://lists.boost.org/Archives/boost/2007/09/127065.php , I've
been thinking about the design issues raised there and I'd
like to make a proposal for a seamless extension API that
I think can solve the practical concerns originating the
discussion while addressing Robert's policy of keeping the
Archive concept simple.

The last proposal Robert made regarding the helper API
and special support for shared_ptr can be summarized in
the following points:

1. The Archive concept does not include any extra requirement
concerning special support for shared_ptr and/or a helper API.
2. There are naked_* archive implementations which conform
to the bare requirements of the Archive concept.
3. The traditional archive implementations (without the
"naked_" prefix) inherit from naked_ as well as from a class
shared_ptr_helper and a class named, say, helper_api so that
special support for shared_ptr and a helper API are provided.

This approach has pros and cons:

pros: the Archive concept is not polluted by impure
considerations such as those accomodating shared_ptr and
helpers, thus helping keep the conceptual design and
the work of archive implementers simple.
cons: A naked archive implementation, while conforming
with the concept requirements, will fail to handle shared_ptr
and any type relying on the helper API.

My point of view is that this solution is just a half-baked
one: having a conformant archive which fails to handle
shared_ptrs would come as a surprising (and annoying) fact
to users of B.S.

So, how to make B.S provide shared_ptr and helper support
whitout polluting the archive concept with too specific
provisions? My proposal is to add a single "hook" to the
Archive concept which is as agnostic as possible and
can be leveraged in the future for unforeseen necessities
beyond shared_ptr and helper support. Add the following
requirement to the Archive concept (both Saving and Loading):

  a.get_extension_obj(p);
  a.set_extension_obj(p);

  Returns and sets, respectively, an internal object of type
  shared_ptr<void>. This object is default initialized
  upon archive construction and is destroyed along with
  destruction of the archive. These expressions are reserved
  for the internal usage of Boost.Serialization and thus must
  not be called by user code.

>From the point of view of the implementer of an Archive,
satisfying this new requirement is as simple as having an
internal member of type shared_ptr<void> and granting access
to it through member functions as described above. That's
all the extra burden put on the Archive concept. So far,
the concept is not polluted with considerations on shared_ptrs,
helpers or anything.

How can Boost.Serialization leverage this extension API to
*universally* provide helper and shared_ptr support for
any Archive type? The following is an skectch of the procedure:
B.S can define an internal type resembling this:

  class extension:
    public shared_ptr_helper,
    public helper_api
  {};

where shared_ptr_helper is more or less like the currently
existing class and helper_api will package the helper
API functions formerly present in Boost 1.34 (lookup_helper,
insert_helper, etc.) Now, B.S can publicly provide the
following helper API to user code:

  namespace boost{
  namespace serialization{

    template<typename Archive>
    void lookup_helper(
      Archive& ar,
      const extended_type_info* eti,
      shared_ptr<void> & sph);
    // rest of the helper API
    ...
  }
  }

which is implemented along the following lines:

  template<typename Archive>
  void lookup_helper(
    Archive& ar,
    const extended_type_info* eti,
    shared_ptr<void> & sph)
  {
    // get the extension object or create a new one if this
    // is the first time

    shared_ptr<void> ext_obj=ar.get_extension_obj();
    if(!ext_obj){
      ext_obj.reset(new extension);
      ar.set_extension_obj(ext_obj);
    }
    extension& ext=*ext_obj;

    // forward to the extension object
    ext.lookup_helper(eti,sph);
  }

and similarly for the other helper API and shared_ptr support
functions.

What do we gain with this?

1. The Archive concept is kept almost intact, and the required
extension is both trivial to implement and totally agnostic.
2. We can provide support for shared_ptr and helpers *universally*,
without putting the burden of its implementation to the writers
of Archive classes. This extra functionality will be called
using a notation

  boost::serialization::foo(ar,...);

instead of

  ar.foo(...);

but this is the only drawback (if it can be considered a drawback.)
3. Future functionality can be added by Boost.Serialization
to Archives by adjoining it to the internal extension class without
the Archive concept or its implementation needing any revision
at all.

How do you like it? Your feedback is greatly appreciated.

Joaquín M López Muñoz
Telefónica, Investigación y Desarrollo


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