Ok I've spent a good chunk of my day making a set of custom archive class,
based on the portable_binary_iarchive and portable_binary_oarchive.
I have a non-virtual class hierarchy named Asset, in memory this is a cyclic
graph, but my requirements are that this structure cannot be serialized all
at once, it has to be broken up at boundaries. So the archiver serializes
the first Asset* (which is always the root object passed into operator&).
This object serializes as normally as per the boost serialization code,
except except that when subsequent Asset*'s are encountered I send the
pointer into an AssetManager class and translate the Asset* into a
ResourceID, and serialize the ResourceID instead of the object. This is
done by directly calling operator& inside save_override.
So far all of this works:
The reverse case of loading, by hooking load_override almost works. Almost,
because I have to apply a hack of skipping 4 bytes inside load_override,
before trying to read the ResourceID structure with operator&. I can't
figure out how to make it 'proper', without simply hard coding the 4 byte
read. As far as I can tell before save_override some bookkeeping
information is written, but the reverse operation in load_override has not
yet stripped this bookkeeping information from the stream, so these
functions aren't quite mirror operations. As best as I can tell the
function guilty of reading the bookkeeping information is load_pointer.
What I need is another function in the boost archive API that pulls the
bookkeeping information out of the stream safely, that I can call from
within load_override, since I have no intention of calling load_pointer
through any means.
Aside from the hack, it technically works, but even then I still have a few
aching problems:
I also have to hard-code the full list of derived Asset types and manually
provide specializations for all of them in save_override and load_override.
If I use the base class, I end up slicing my class down to its base, and
cannot serialize it. I can't make serialize virtual, since the intrusive
serialize methods are templates, but it certainly would solve the problem if
it were possible. In addition the bodies of all of my overrides are
completely identical except for the classname (AssetModel, AssetTexture,
etc). Which means I'll be wrapping the bodies of a generic save_override
and load_override in a macro, and have to manually add all Asset derived
classes to a list of classes inside my archive class. Which means that my
archiver cannot be generic, even though I have managed to make it a template
in the sense that the passed in asset manager and base asset types are
template parameters.
the type ResourceID is a std::string
saving...
class asset_oarchive : ...
void save_override(const AssetModel& t, int i)
{
if (!RootAssetSaved)
{
RootAssetSaved = true;
binary_oarchive_impl::save_override(t, i);
}
else
{
AssetManagerType::ResourceID ResourceId =
TheAssetManager->ResourceIdForAsset(&t);
operator&(ResourceId);
}
}
loading ...
class asset_iarchive : ...
void load_override(AssetModel*& t, int i)
{
if (!RootAssetLoaded)
{
RootAssetLoaded = true;
binary_iarchive_impl::load_override(t, i);
}
else
{
unsigned char c[10];
for (INT x=0; x<10; ++x)
{
c[x] = 0xFF;
}
for (INT x=0; x<4; ++x)
{
operator&(c[x]); //hackhack
}
AssetManagerType::ResourceID ResourceId;
operator&(ResourceId);
AssetType* a = TheAssetManager->FindAsset(ResourceId);
if (!a)
{
a = TheAssetManager->LoadAsset(ResourceId);
}
// TODO: throw on missing resources, potentially query asset
manager for substitutes
t = static_cast