ArchiveCollection.h

// ArchiveCollection.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2019

#pragma once
#include "CedaAssert.h"
#include "VariableLengthSerialise.h"
#include "Archive.h"
#include "xdeque.h"
#include "xvector.h"
#include <array>
#include <deque>
#include <forward_list>
#include <list>
#include <vector>
#include <map>
#include <set>
#include <unordered_set>
#include <unordered_map>
#include <string.h>

namespace ceda
{
template<typename T, typename Archive>
void ScanOverVariable(Archive& ar)
{
    T v;
    ar >> v;
}

template<typename T, typename Archive>
void ScanOverArray(Archive& ar, ssize_t count)
{
    T v;
    for (ssize_t i=0 ; i < count ; ++i)
    {
        ar >> v;
    }
}

template<typename T, typename Archive> 
void ScanOverVector(Archive& ar)
{
    ssize_t n;
    DeserialiseVariableLengthUint(ar,n);
    cxAssert(0 <= n);
    T x;
    for (ssize_t i = 0 ; i != n ; ++i)
    {
        ar >> x;
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// Deserialise

template<typename Archive, typename T>
inline void DeserialiseArray(Archive& ar, T* data, ssize_t count)
{
    for (ssize_t i=0 ; i < count ; ++i)
    {
        ar >> data[i];
    }
}

template <typename Archive, typename It> 
inline void DeserialiseRange(Archive& ar, It begin, It end)
{
    while(begin != end)
    {
        ar >> *begin++;
    }
}

template <typename Archive, typename T> 
inline void DeserialiseCollectionWithResize(Archive& ar, T& c)
{
    CompressedInt<ssize_t> n;
    ar >> n;
    cxAssert(0 <= n.val);
    c.resize(n.val);
    for (auto& e : c)
    {
        ar >> e;
    }
}

template <typename V, typename Archive, typename T> 
inline void DeserialiseCollectionWithAppend(Archive& ar, T& c)
{
    CompressedInt<ssize_t> n;
    ar >> n;
    cxAssert(0 <= n.val);
    c.clear();
    for (ssize_t i=0 ; i < n.val ; ++i)
    {
        V v;
        ar >> v;
        c.insert(c.end(), v);
    }
}

template <typename Archive, typename U, typename V, std::enable_if_t<IsSerialisable<U>::value && IsSerialisable<V>::value, int> = 0> 
inline void Deserialise(Archive& ar, std::pair<U,V>& x)
{
    ar >> x.first >> x.second;
}

template <typename Archive, typename T, size_t N, std::enable_if_t<IsSerialisable<T>::value, int> = 0>
inline void Deserialise(Archive& ar, std::array<T,N>& x)
{
    DeserialiseRange(ar, x.begin(), x.end());
}

template <typename Archive, typename Char, typename Traits, typename Alloc>
inline void Deserialise(Archive& ar, std::basic_string<Char,Traits,Alloc>& x)
{
    CompressedInt<ssize_t> n;
    ar >> n;
    cxAssert(0 <= n.val);
    x.resize(n.val);
    if (n.val > 0)
    {
        memcpy(&x[0], ar, n.val * sizeof(Char));
        ar += n.val * sizeof(Char);
    }
}

template <typename Archive, typename T, typename Alloc, std::enable_if_t<IsSerialisable<T>::value, int> = 0>
inline void Deserialise(Archive& ar, std::vector<T,Alloc>& x)
{
    DeserialiseCollectionWithResize(ar, x);
}

template <typename Archive> 
inline void Deserialise(Archive& ar, std::vector<bool>& c)
{
    CompressedInt<ssize_t> n;
    ar >> n;
    cxAssert(0 <= n.val);
    c.resize(n.val);
    for (auto i = c.begin() ; i != c.end() ; ++i)
    {
        bool v;
        ar >> v;
        *i = v;
    }
}

template <typename Archive, typename T, typename Alloc, std::enable_if_t<IsSerialisable<T>::value, int> = 0> 
inline void Deserialise(Archive& ar, std::deque<T,Alloc>& x)
{
    DeserialiseCollectionWithResize(ar, x);
}

template <typename Archive, typename T, typename Alloc, std::enable_if_t<IsSerialisable<T>::value, int> = 0> 
inline void Deserialise(Archive& ar, std::forward_list<T,Alloc>& c)
{
    CompressedInt<ssize_t> n;
    ar >> n;
    cxAssert(0 <= n.val);
    c.clear();
    auto p = c.before_begin();
    for (ssize_t i=0 ; i < n.val ; ++i)
    {
        T v;
        ar >> v;
        p = c.insert_after(p,v);
    }
}

template <typename Archive, typename T, typename A, std::enable_if_t<IsSerialisable<T>::value, int> = 0>
inline void Deserialise(Archive& ar, std::list<T,A>& x)
{
    DeserialiseCollectionWithAppend<T>(ar, x);
}

template <typename Archive, typename T, ssize_t pageSize, std::enable_if_t<IsSerialisable<T>::value, int> = 0> 
inline void Deserialise(Archive& ar, xdeque<T,pageSize>& x)
{
    DeserialiseCollectionWithResize(ar, x);
}

template <typename Archive> 
inline void Deserialise(Archive& ar, VectorOfByte& x)
{
    DeserialiseCollectionWithResize(ar, x);
}

template <typename Archive, typename T, std::enable_if_t<IsSerialisable<T>::value, int> = 0> 
inline void Deserialise(Archive& ar, xvector<T>& x)
{
    DeserialiseCollectionWithResize(ar, x);
}

template <typename Archive, typename Key,typename T,typename Compare,typename Alloc, std::enable_if_t<IsSerialisable<Key>::value && IsSerialisable<T>::value, int> = 0>
inline void Deserialise(Archive& ar, std::map<Key,T,Compare,Alloc>& x)
{
    DeserialiseCollectionWithAppend<std::pair<Key,T>> (ar, x);
}

template <typename Archive, typename Key,typename T,typename Compare,typename Alloc, std::enable_if_t<IsSerialisable<Key>::value && IsSerialisable<T>::value, int> = 0>
inline void Deserialise(Archive& ar, std::multimap<Key,T,Compare,Alloc>& x)
{
    DeserialiseCollectionWithAppend<std::pair<Key,T>>(ar, x);
}

template <typename Archive, typename T,typename Compare,typename Alloc, std::enable_if_t<IsSerialisable<T>::value, int> = 0>
inline void Deserialise(Archive& ar, std::set<T,Compare,Alloc>& x)
{
    DeserialiseCollectionWithAppend<T>(ar, x);
}

template <typename Archive, typename T,typename Compare,typename Alloc, std::enable_if_t<IsSerialisable<T>::value, int> = 0>
inline void Deserialise(Archive& ar, std::multiset<T,Compare,Alloc>& x)
{
    DeserialiseCollectionWithAppend<T>(ar, x);
}

template <typename Archive, typename Key, typename Hash, typename KeyEqual, typename Alloc, std::enable_if_t<IsSerialisable<Key>::value, int> = 0>
inline void Deserialise(Archive& ar, std::unordered_set<Key,Hash,KeyEqual,Alloc>& x)
{
    DeserialiseCollectionWithAppend<Key>(ar, x);
}

template <typename Archive, typename Key, typename Hash, typename KeyEqual, typename Alloc, std::enable_if_t<IsSerialisable<Key>::value, int> = 0>
inline void Deserialise(Archive& ar, std::unordered_multiset<Key,Hash,KeyEqual,Alloc>& x)
{
    DeserialiseCollectionWithAppend<Key>(ar, x);
}

template <typename Archive, typename Key, typename T, typename Hash, typename KeyEqual, typename Alloc, std::enable_if_t<IsSerialisable<Key>::value && IsSerialisable<T>::value, int> = 0>
inline void Deserialise(Archive& ar, std::unordered_map<Key,T,Hash,KeyEqual,Alloc>& x)
{
    DeserialiseCollectionWithAppend<std::pair<Key,T>>(ar, x);
}

template <typename Archive, typename Key, typename T, typename Hash, typename KeyEqual, typename Alloc, std::enable_if_t<IsSerialisable<Key>::value && IsSerialisable<T>::value, int> = 0>
inline void Deserialise(Archive& ar, std::unordered_multimap<Key,T,Hash,KeyEqual,Alloc>& x)
{
    DeserialiseCollectionWithAppend<std::pair<Key,T>>(ar, x);
}

///////////////////////////////////////////////////////////////////////////////////////////////////
// Serialise

template<typename Archive, typename T>
inline void SerialiseArray(Archive& ar, const T* data, ssize_t count)
{
    for (ssize_t i=0 ; i < count ; ++i)
    {
        ar << data[i];
    }
}

template <typename Archive, typename It> 
inline void SerialiseRange(Archive& ar, It begin, It end)
{
    while(begin != end)
    {
        ar << *begin++;
    }
}

template <typename Archive, typename T> 
inline void SerialiseCollection(Archive& ar, const T& c)
{
    ar << AsCompressedInt(c.size());
    for (auto& e : c)
    {
        ar << e;
    }
}

template <typename Archive, typename T, size_t N> 
inline void SerialiseCollection(Archive& ar, const std::array<T,N>& c)
{
    for (auto& e : c)
    {
        ar << e;
    }
}

template <typename Archive, typename U, typename V> 
inline void Serialise(Archive& ar, const std::pair<U,V>& x)
{
    ar << x.first << x.second;
}

template <typename Archive, typename T, size_t N>
inline void Serialise(Archive& ar, const std::array<T,N>& x)
{
    SerialiseRange(ar, x.begin(), x.end());
}

template <typename Archive, typename Char, typename Traits, typename Alloc>
inline void Serialise(Archive& ar, const std::basic_string<Char,Traits,Alloc>& x)
{
    SerialiseCollection(ar, x);
}

template <typename Archive, typename T,typename Alloc> 
inline void Serialise(Archive& ar, const std::vector<T,Alloc>& x)
{
    SerialiseCollection(ar, x);
}

template <typename Archive> 
inline void Serialise(Archive& ar, const std::vector<bool>& x)
{
    ar << AsCompressedInt(x.size());
    for (auto i = x.begin() ; i != x.end() ; ++i)
    {
        ar << (bool)*i;
    }
}

template <typename Archive, typename T, typename Alloc> 
inline void Serialise(Archive& ar, const std::deque<T,Alloc>& x)
{
    SerialiseCollection(ar, x);
}

template <typename Archive, typename T, typename Alloc> 
inline void Serialise(Archive& ar, const std::forward_list<T,Alloc>& x)
{
    ar << AsCompressedInt(std::distance(x.begin(), x.end()));
    for (auto& e : x)
    {
        ar << e;
    }
}

template <typename Archive, typename T, typename Alloc> 
inline void Serialise(Archive& ar, const std::list<T,Alloc>& x)
{
    SerialiseCollection(ar, x);
}

template <typename Archive>
inline void Serialise(Archive& ar, const VectorOfByte& x)
{
    SerialiseCollection(ar, x);
}

template <typename Archive, typename T> 
inline void Serialise(Archive& ar, const xvector<T>& x)
{
    SerialiseCollection(ar, x);
}

template <typename Archive, typename T,ssize_t pageSize> 
inline void Serialise(Archive& ar, const xdeque<T,pageSize>& x)
{
    SerialiseCollection(ar, x);
}

template <typename Archive, typename Key,typename T,typename Compare,typename Alloc> 
inline void Serialise(Archive& ar, const std::map<Key,T,Compare,Alloc>& x)
{
    SerialiseCollection(ar, x);
}

template <typename Archive, typename Key,typename T,typename Compare,typename Alloc> 
inline void Serialise(Archive& ar, const std::multimap<Key,T,Compare,Alloc>& x)
{
    SerialiseCollection(ar, x);
}

template <typename Archive, typename T,typename Compare,typename Alloc> 
inline void Serialise(Archive& ar, const std::set<T,Compare,Alloc>& x)
{
    SerialiseCollection(ar, x);
}

template <typename Archive, typename T,typename Compare,typename Alloc> 
inline void Serialise(Archive& ar, const std::multiset<T,Compare,Alloc>& x)
{
    SerialiseCollection(ar, x);
}

template <typename Archive, typename Key, typename Hash, typename KeyEqual, typename Alloc> 
inline void Serialise(Archive& ar, const std::unordered_set<Key,Hash,KeyEqual,Alloc>& x)
{
    SerialiseCollection(ar, x);
}

template <typename Archive, typename Key, typename Hash, typename KeyEqual, typename Alloc> 
inline void Serialise(Archive& ar, const std::unordered_multiset<Key,Hash,KeyEqual,Alloc>& x)
{
    SerialiseCollection(ar, x);
}

template <typename Archive, typename Key, typename T, typename Hash, typename KeyEqual, typename Alloc> 
inline void Serialise(Archive& ar, const std::unordered_map<Key,T,Hash,KeyEqual,Alloc>& x)
{
    SerialiseCollection(ar, x);
}

template <typename Archive, typename Key, typename T, typename Hash, typename KeyEqual, typename Alloc> 
inline void Serialise(Archive& ar, const std::unordered_multimap<Key,T,Hash,KeyEqual,Alloc>& x)
{
    SerialiseCollection(ar, x);
}

#if 0
///////////////////////////////////////////////////////////////////////////////////////////////////
/*
For efficiency provide fast implementations for certain specialisations
such as xvector<int>, xvector<float>, xvector<double>
*/

template <typename Archive, typename T> 
void WritePodVector(Archive& ar, const xvector<T>& x)
{
    SerialiseVariableLengthUint(ar, x.size());
    ar.WriteBuffer(x.data(),x.size() * sizeof(T));
}

template <typename Archive> 
void Serialise(Archive& ar, const xvector<char>& x)
{
    WritePodVector(ar,x);
}

template <typename Archive> 
void Serialise(Archive& ar, const xvector<signed char>& x)
{
    WritePodVector(ar,x);
}

template <typename Archive> 
void Serialise(Archive& ar, const xvector<unsigned char>& x)
{
    WritePodVector(ar,x);
}

template <typename Archive> 
void Serialise(Archive& ar, const xvector<short>& x)
{
    WritePodVector(ar,x);
}

template <typename Archive> 
void Serialise(Archive& ar, const xvector<unsigned short>& x)
{
    WritePodVector(ar,x);
}

template <typename Archive> 
void Serialise(Archive& ar, const xvector<int>& x)
{
    WritePodVector(ar,x);
}

template <typename Archive> 
void Serialise(Archive& ar, const xvector<unsigned int>& x)
{
    WritePodVector(ar,x);
}

template <typename Archive> 
void Serialise(Archive& ar, const xvector<long>& x)
{
    WritePodVector(ar,x);
}

template <typename Archive> 
void Serialise(Archive& ar, const xvector<unsigned long>& x)
{
    WritePodVector(ar,x);
}

template <typename Archive> 
void Serialise(Archive& ar, const xvector<long long>& x)
{
    WritePodVector(ar,x);
}

template <typename Archive> 
void Serialise(Archive& ar, const xvector<unsigned long long>& x)
{
    WritePodVector(ar,x);
}

template <typename Archive> 
void Serialise(Archive& ar, const xvector<float>& x)
{
    WritePodVector(ar,x);
}

template <typename Archive> 
void Serialise(Archive& ar, const xvector<double>& x)
{
    WritePodVector(ar,x);
}

template <typename Archive> 
void Serialise(Archive& ar, const xvector<long double>& x)
{
    WritePodVector(ar,x);
}
#endif

} // namespace ceda