/*
    libmaus2
    Copyright (C) 2009-2013 German Tischler
    Copyright (C) 2011-2013 Genome Research Limited

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#if ! defined(SERIALIZE_HPP)
#define SERIALIZE_HPP

#include <ostream>
#include <istream>
#include <map>

#include <libmaus2/types/types.hpp>
#include <stdexcept>
#include <sstream>
#include <libmaus2/demangle/Demangle.hpp>

namespace libmaus2
{
	namespace serialize
	{
		template<typename N>
		struct Serialize
		{
			private:
			static uint64_t serialize(std::ostream & out, N const & c);
			static uint64_t serializeArray(std::ostream & out, N const * A, uint64_t const n);

			static uint64_t deserialize(std::istream & in, N * p);
			static uint64_t deserializeChecked(std::istream & in, N * p);
			static uint64_t deserializeArray(std::istream & in, N * p, uint64_t const n);

			static uint64_t ignore(std::istream & in);
			static uint64_t ignoreArray(std::istream & in, uint64_t const n);

			static uint64_t skip(std::istream & in);
			static uint64_t skipArray(std::istream & in, uint64_t const n);
		};

		template<typename _N>
		struct BuiltinLocalSerializer
		{
			typedef _N N;

			static uint64_t serialize(std::ostream & out, N const & c)
			{
				out.write( reinterpret_cast<char const *>(&c) , sizeof(N) );
				return sizeof(N);
			}
			static uint64_t serializeChecked(std::ostream & out, N const & c)
			{
				out.write( reinterpret_cast<char const *>(&c) , sizeof(N) );
				if ( ! out )
				{
					std::ostringstream ostr;
					ostr
						<< "BuiltinLocalSerializer<"
						<< libmaus2::demangle::Demangle::demangle<N>()
						<< ">::serializeChecked(): failed to write " << sizeof(N) << " bytes.";
					throw std::runtime_error(ostr.str());
				}
				return sizeof(N);
			}
			static uint64_t serializeArray(std::ostream & out, N const * A, uint64_t const n)
			{
				out.write( reinterpret_cast<char const *>(A) , n * sizeof(N) );
				return n * sizeof(N);
			}
			static uint64_t serializeArrayChecked(std::ostream & out, N const * A, uint64_t const n)
			{
				out.write( reinterpret_cast<char const *>(A) , n * sizeof(N) );
				if ( ! out )
				{
					std::ostringstream ostr;
					ostr
						<< "BuiltinLocalSerializer<"
						<< libmaus2::demangle::Demangle::demangle<N>()
						<< ">::serializeArrayChecked(): failed to write " << (n*sizeof(N)) << " bytes.";
					throw std::runtime_error(ostr.str());
				}
				return n * sizeof(N);
			}
			static uint64_t deserialize(std::istream & in, N * p)
			{
				in.read ( reinterpret_cast<char *>(p) , sizeof(N) ); return sizeof(N);
			}
			static uint64_t deserializeChecked(std::istream & in, N * p)
			{
				in.read ( reinterpret_cast<char *>(p) , sizeof(N) );
				if ( in.gcount() != sizeof(N) )
				{
					std::ostringstream ostr;
					ostr
						<< "BuiltinLocalSerializer<"
						<< libmaus2::demangle::Demangle::demangle<N>()
						<< ">::deserializeChecked(): failed to read " << sizeof(N) << " bytes.";
					throw std::runtime_error(ostr.str());
				}
				return sizeof(N);
			}
			static N deserializeChecked(std::istream & in)
			{
				N v;
				deserializeChecked(in,&v);
				return v;
			}
			static uint64_t deserializeArray(
				std::istream & in, N * p, uint64_t const n
			)
			{
				static uint64_t const bsavail = 64*1024;
				static uint64_t const bsunits = (bsavail + sizeof(N) - 1) / sizeof(N);
				static uint64_t const bsbytes = bsunits * sizeof(N);

				// number of full blocks
				uint64_t const full = n / bsunits;
				// rest
				uint64_t const rest = n - full*bsunits;
				// rest in bytes
				uint64_t const restbytes = rest * sizeof(N);

				for ( uint64_t i = 0; i < full; ++i )
				{
					in.read ( reinterpret_cast<char *>(p+   i*bsunits), bsbytes );
				}
				if ( rest )
				{
					in.read ( reinterpret_cast<char *>(p+full*bsunits), restbytes );
				}

				return n*sizeof(N);
			}
			static uint64_t deserializeArrayChecked(
				std::istream & in, N * p, uint64_t const n
			)
			{
				static uint64_t const bsavail = 64*1024;
				static uint64_t const bsunits = (bsavail + sizeof(N) - 1) / sizeof(N);
				static uint64_t const bsbytes = bsunits * sizeof(N);

				// number of full blocks
				uint64_t const full = n / bsunits;
				// rest
				uint64_t const rest = n - full*bsunits;
				// rest in bytes
				uint64_t const restbytes = rest * sizeof(N);

				for ( uint64_t i = 0; i < full; ++i )
				{
					in.read ( reinterpret_cast<char *>(p+   i*bsunits), bsbytes );
					if ( in.gcount() != static_cast<int64_t>(bsbytes) )
					{
						std::ostringstream ostr;
						ostr
							<< "BuiltinLocalSerializer<"
							<< libmaus2::demangle::Demangle::demangle<N>()
							<< ">::deserializeArrayChecked(): failed to read " << bsbytes << " bytes at offset " << (i*bsbytes);
						throw std::runtime_error(ostr.str());
					}
				}
				if ( rest )
				{
					in.read ( reinterpret_cast<char *>(p+full*bsunits), restbytes );
					if ( in.gcount() != static_cast<int64_t>(restbytes) )
					{
						std::ostringstream ostr;
						ostr
							<< "BuiltinLocalSerializer<"
							<< libmaus2::demangle::Demangle::demangle<N>()
							<< ">::deserializeArrayChecked(): failed to read " << restbytes << " bytes at offset" << (full*bsbytes);
						throw std::runtime_error(ostr.str());
					}
				}

				return n*sizeof(N);
			}
			static uint64_t ignore(std::istream & in)
			{
				in.ignore ( sizeof(N) ); return sizeof(N);
			}
			static uint64_t ignoreArray(std::istream & in, uint64_t const n)
			{
				in.ignore ( n * sizeof(N) ); return n*sizeof(N);
			}
			static uint64_t skip(std::istream & in)
			{
				in.seekg(sizeof(N),std::ios::cur); return sizeof(N);
			}
			static uint64_t skipArray(std::istream & in, uint64_t const n)
			{
				in.seekg (n * sizeof(N), std::ios::cur ); return n*sizeof(N);
			}
		};

		template<>
		struct Serialize<unsigned char>
		{
			typedef unsigned char N;
			static uint64_t serialize(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArray(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t serializeChecked(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArrayChecked(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t deserialize(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserialize(in,p); }
			static uint64_t deserializeChecked(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserializeChecked(in,p); }
			static uint64_t deserializeArray(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArray(in,p,n); }
			static uint64_t deserializeArrayChecked(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArrayChecked(in,p,n); }
			static uint64_t ignore(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t ignoreArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
			static uint64_t skip(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t skipArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
		};

		template<>
		struct Serialize<unsigned short>
		{
			typedef unsigned short N;
			static uint64_t serialize(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArray(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t serializeChecked(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArrayChecked(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t deserialize(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserialize(in,p); }
			static uint64_t deserializeChecked(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserializeChecked(in,p); }
			static uint64_t deserializeArray(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArray(in,p,n); }
			static uint64_t deserializeArrayChecked(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArrayChecked(in,p,n); }
			static uint64_t ignore(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t ignoreArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
			static uint64_t skip(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t skipArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
		};

		template<>
		struct Serialize<unsigned int>
		{
			typedef unsigned int N;
			static uint64_t serialize(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArray(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t serializeChecked(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArrayChecked(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t deserialize(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserialize(in,p); }
			static uint64_t deserializeChecked(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserializeChecked(in,p); }
			static uint64_t deserializeArray(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArray(in,p,n); }
			static uint64_t deserializeArrayChecked(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArrayChecked(in,p,n); }
			static uint64_t ignore(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t ignoreArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
			static uint64_t skip(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t skipArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
		};

		template<>
		struct Serialize<unsigned long>
		{
			typedef unsigned long N;
			static uint64_t serialize(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArray(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t serializeChecked(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArrayChecked(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t deserialize(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserialize(in,p); }
			static uint64_t deserializeChecked(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserializeChecked(in,p); }
			static uint64_t deserializeArray(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArray(in,p,n); }
			static uint64_t deserializeArrayChecked(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArrayChecked(in,p,n); }
			static uint64_t ignore(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t ignoreArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
			static uint64_t skip(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t skipArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
		};

		template<>
		struct Serialize<unsigned long long>
		{
			typedef unsigned long long N;
			static uint64_t serialize(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArray(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t serializeChecked(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArrayChecked(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t deserialize(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserialize(in,p); }
			static uint64_t deserializeChecked(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserializeChecked(in,p); }
			static uint64_t deserializeArray(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArray(in,p,n); }
			static uint64_t deserializeArrayChecked(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArrayChecked(in,p,n); }
			static uint64_t ignore(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t ignoreArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
			static uint64_t skip(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t skipArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
		};

		template<>
		struct Serialize<char>
		{
			typedef char N;
			static uint64_t serialize(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArray(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t serializeChecked(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArrayChecked(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t deserialize(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserialize(in,p); }
			static uint64_t deserializeChecked(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserializeChecked(in,p); }
			static uint64_t deserializeArray(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArray(in,p,n); }
			static uint64_t deserializeArrayChecked(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArrayChecked(in,p,n); }
			static uint64_t ignore(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t ignoreArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
			static uint64_t skip(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t skipArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
		};

		template<>
		struct Serialize<short>
		{
			typedef short N;
			static uint64_t serialize(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArray(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t serializeChecked(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArrayChecked(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t deserialize(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserialize(in,p); }
			static uint64_t deserializeChecked(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserializeChecked(in,p); }
			static uint64_t deserializeArray(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArray(in,p,n); }
			static uint64_t deserializeArrayChecked(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArrayChecked(in,p,n); }
			static uint64_t ignore(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t ignoreArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
			static uint64_t skip(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t skipArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
		};

		template<>
		struct Serialize<int>
		{
			typedef int N;
			static uint64_t serialize(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArray(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t serializeChecked(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArrayChecked(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t deserialize(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserialize(in,p); }
			static uint64_t deserializeChecked(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserializeChecked(in,p); }
			static uint64_t deserializeArray(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArray(in,p,n); }
			static uint64_t deserializeArrayChecked(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArrayChecked(in,p,n); }
			static uint64_t ignore(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t ignoreArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
			static uint64_t skip(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t skipArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
		};

		template<>
		struct Serialize<long>
		{
			typedef long N;
			static uint64_t serialize(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArray(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t serializeChecked(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArrayChecked(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t deserialize(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserialize(in,p); }
			static uint64_t deserializeChecked(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserializeChecked(in,p); }
			static uint64_t deserializeArray(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArray(in,p,n); }
			static uint64_t deserializeArrayChecked(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArrayChecked(in,p,n); }
			static uint64_t ignore(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t ignoreArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
			static uint64_t skip(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t skipArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
		};

		template<>
		struct Serialize<long long>
		{
			typedef long long N;
			static uint64_t serialize(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArray(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t serializeChecked(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArrayChecked(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t deserialize(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserialize(in,p); }
			static uint64_t deserializeChecked(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserializeChecked(in,p); }
			static uint64_t deserializeArray(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArray(in,p,n); }
			static uint64_t deserializeArrayChecked(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArrayChecked(in,p,n); }
			static uint64_t ignore(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t ignoreArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
			static uint64_t skip(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t skipArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
		};

		#if 0
		template<>
		struct Serialize<size_t>
		{
			typedef size_t N;
			static uint64_t serialize(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArray(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t serializeChecked(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArrayChecked(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t deserialize(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserialize(in,p); }
			static uint64_t deserializeChecked(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserializeChecked(in,p); }
			static uint64_t deserializeArray(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArray(in,p,n); }
			static uint64_t deserializeArrayChecked(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArrayChecked(in,p,n); }
			static uint64_t ignore(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t ignoreArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
			static uint64_t skip(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t skipArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
		};
		#endif

		template<>
		struct Serialize< std::pair <uint32_t,uint32_t> >
		{
			typedef std::pair <uint32_t,uint32_t> N;
			static uint64_t serialize(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArray(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t serializeChecked(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArrayChecked(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t deserialize(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserialize(in,p); }
			static uint64_t deserializeChecked(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserializeChecked(in,p); }
			static uint64_t deserializeArray(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArray(in,p,n); }
			static uint64_t deserializeArrayChecked(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArrayChecked(in,p,n); }
			static uint64_t ignore(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t ignoreArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
			static uint64_t skip(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t skipArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
		};

		template<>
		struct Serialize< std::pair <uint64_t,uint64_t> >
		{
			typedef std::pair <uint64_t,uint64_t> N;
			static uint64_t serialize(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArray(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t serializeChecked(std::ostream & out, N const & c) { return BuiltinLocalSerializer<N>::serialize(out,c); }
			static uint64_t serializeArrayChecked(std::ostream & out, N const * A, uint64_t const n) { return BuiltinLocalSerializer<N>::serializeArray(out,A,n); }
			static uint64_t deserialize(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserialize(in,p); }
			static uint64_t deserializeArray(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArray(in,p,n); }
			static uint64_t deserializeArrayChecked(std::istream & in, N * p, uint64_t const n) { return BuiltinLocalSerializer<N>::deserializeArrayChecked(in,p,n); }
			static uint64_t deserializeChecked(std::istream & in, N * p) { return BuiltinLocalSerializer<N>::deserializeChecked(in,p); }
			static uint64_t ignore(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t ignoreArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
			static uint64_t skip(std::istream & in) { return BuiltinLocalSerializer<N>::ignore(in); }
			static uint64_t skipArray(std::istream & in, uint64_t const n) { return BuiltinLocalSerializer<N>::ignoreArray(in,n); }
		};
	}
}
#endif
