Any Collection Serialization

The first disclaimer of this article is that templatious doesn't have and probably will never have to do anything with serialization. However, we will use serialization framework to serialize any collection (as long as it specializes collection adapter) since we can treat collections uniformly.

So first of all, how much data do we need to serialize any collection?

  • It's size (for reading it back)
  • It's elements

We will be using cereal C++11 library for serialization.

So, this is how our serialization class will look like:

template <class T>
struct AnyCollectionSerializer {

    AnyCollectionSerializer(T&& t) : _t(std::move(t)) {}
    AnyCollectionSerializer() {}

    template <class Archive>
    void save(Archive & archive) const {
        long size = SA::size(_t);
        archive & size;
        TEMPLATIOUS_FOREACH(auto& i,_t) {
            archive & i;
        }
    }

    template <class Archive>
    void load(Archive & archive) {
        long size;
        archive & size;
        SA::clear(_t);
        typedef templatious::adapters::
            CollectionAdapter<T> Ad;
        // find out collection value type
        // from adapter
        typedef typename Ad::ValueType ValType;
        ValType inp;
        TEMPLATIOUS_REPEAT( size ) {
            archive & inp;
            SA::add(_t,inp);
        }
    }

    T _t;
};

We simply have one member variable that is our collection. We can instantiate it with current collection or we can instantiate it empty for loading. We simply specify save and load functions that framework asks us and we should be good to go.

In the following example we will use this class to serialize std::vector and when deserializing receive std::list.

int main(int argc,char* argv[]) {
    typedef std::vector<double> InColType;
    typedef std::list<double> OutColType;

    InColType inVect;
    SA::add(inVect,0.7,1.7,2.7,3.7,4.7,5.7,6.7);

    double prevSum = SM::sum(inVect);

    {
    std::ofstream outFile("myser.bin");
    cereal::BinaryOutputArchive outArch(outFile);
    AnyCollectionSerializer< InColType >
        ser(std::move(inVect));
    outArch( ser );
    }

    OutColType outList;
    {
    std::ifstream inFile("myser.bin");
    cereal::BinaryInputArchive inArch(inFile);
    AnyCollectionSerializer< OutColType > ser;
    inArch( ser );
    outList = std::move(ser._t);
    }

    double afterSum = SM::sum(outList);

    assert( prevSum == afterSum );
}

Since we don't have to commit ourselves to any specific collection like std::vector or std::list when serializing/deserializing this is quite generic and flexible.

Expected longer article? Well, sorry to disappoint.