sharedObject
This commit is contained in:
8
CMakeLists.txt
Normal file
8
CMakeLists.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(archive)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
file(GLOB_RECURSE HEADERS "include/*.h" "include/*.hpp")
|
||||
include_directories("include")
|
||||
add_library(archive SHARED ${HEADERS})
|
||||
set_target_properties(archive PROPERTIES LINKER_LANGUAGE CXX)
|
385
archive.h
385
archive.h
@@ -1,385 +0,0 @@
|
||||
/*
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <https://unlicense.org>
|
||||
*/
|
||||
|
||||
#ifndef ARCHIVE_H__
|
||||
#define ARCHIVE_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace EndianSwapper
|
||||
{
|
||||
class SwapByteBase
|
||||
{
|
||||
public:
|
||||
static bool ShouldSwap()
|
||||
{
|
||||
static const uint16_t swapTest = 1;
|
||||
return (*((char*)&swapTest) == 1);
|
||||
}
|
||||
|
||||
static void SwapBytes(uint8_t& v1, uint8_t& v2)
|
||||
{
|
||||
uint8_t tmp = v1;
|
||||
v1 = v2;
|
||||
v2 = tmp;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, int S>
|
||||
class SwapByte : public SwapByteBase
|
||||
{
|
||||
public:
|
||||
static T Swap(T v)
|
||||
{
|
||||
assert(false); // Shoud not be here...
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class SwapByte<T, 1> : public SwapByteBase
|
||||
{
|
||||
public:
|
||||
static T Swap(T v)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class SwapByte<T, 2> : public SwapByteBase
|
||||
{
|
||||
public:
|
||||
static T Swap(T v)
|
||||
{
|
||||
if(ShouldSwap())
|
||||
return ((uint16_t)v >> 8) | ((uint16_t)v << 8);
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class SwapByte<T, 4> : public SwapByteBase
|
||||
{
|
||||
public:
|
||||
static T Swap(T v)
|
||||
{
|
||||
if(ShouldSwap())
|
||||
{
|
||||
return (SwapByte<uint16_t, 2>::Swap((uint32_t)v & 0xffff) << 16) | (SwapByte<uint16_t, 2>::Swap(((uint32_t)v & 0xffff0000) >> 16));
|
||||
}
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class SwapByte<T, 8> : public SwapByteBase
|
||||
{
|
||||
public:
|
||||
static T Swap(T v)
|
||||
{
|
||||
if(ShouldSwap())
|
||||
return (((uint64_t)SwapByte<uint32_t, 4>::Swap((uint32_t)(v & 0xffffffffull))) << 32) | (SwapByte<uint32_t, 4>::Swap((uint32_t)(v >> 32)));
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class SwapByte<float, 4> : public SwapByteBase
|
||||
{
|
||||
public:
|
||||
static float Swap(float v)
|
||||
{
|
||||
union { float f; uint8_t c[4]; };
|
||||
f = v;
|
||||
if(ShouldSwap())
|
||||
{
|
||||
SwapBytes(c[0], c[3]);
|
||||
SwapBytes(c[1], c[2]);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class SwapByte<double, 8> : public SwapByteBase
|
||||
{
|
||||
public:
|
||||
static double Swap(double v)
|
||||
{
|
||||
union { double f; uint8_t c[8]; };
|
||||
f = v;
|
||||
if(ShouldSwap())
|
||||
{
|
||||
SwapBytes(c[0], c[7]);
|
||||
SwapBytes(c[1], c[6]);
|
||||
SwapBytes(c[2], c[5]);
|
||||
SwapBytes(c[3], c[4]);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <class STREAM_TYPE>
|
||||
class Archive
|
||||
{
|
||||
public:
|
||||
Archive(STREAM_TYPE& stream) : m_stream(stream)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
template <class T>
|
||||
const Archive& operator<<(const T& v) const
|
||||
{
|
||||
*this & v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Archive& operator>>(T& v)
|
||||
{
|
||||
*this & v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
template <class T>
|
||||
Archive& operator&(T& v)
|
||||
{
|
||||
v.Serialize(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const Archive& operator&(const T& v) const
|
||||
{
|
||||
((T&)v).Serialize(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T, size_t N>
|
||||
Archive& operator&(T (&v)[N])
|
||||
{
|
||||
uint32_t len;
|
||||
*this & len;
|
||||
for(size_t i = 0; i < N; ++i)
|
||||
*this & v[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T, size_t N>
|
||||
const Archive& operator&(const T (&v)[N]) const
|
||||
{
|
||||
uint32_t len = N;
|
||||
*this & len;
|
||||
for(size_t i = 0; i < N; ++i)
|
||||
*this & v[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
#define SERIALIZER_FOR_POD(type) \
|
||||
Archive& operator&(type& v) \
|
||||
{ \
|
||||
m_stream.read((char*)&v, sizeof(type)); \
|
||||
if(!m_stream) { throw std::runtime_error("malformed data"); } \
|
||||
v = Swap(v); \
|
||||
return *this; \
|
||||
} \
|
||||
const Archive& operator&(type v) const \
|
||||
{ \
|
||||
v = Swap(v); \
|
||||
m_stream.write((const char*)&v, sizeof(type)); \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
// Special serializer for floating point values, can't directly swap on floating point variable
|
||||
// because it might cause a NaN and the wrong value is read back (the problem occurs on vstudio)
|
||||
#define SERIALIZER_FOR_POD_FLOATINGPOINT(type) \
|
||||
Archive& operator&(type& v) \
|
||||
{ \
|
||||
union { type f; uint8_t c[sizeof(type)];}; \
|
||||
m_stream.read((char*)&c[0], sizeof(type)); \
|
||||
if (!m_stream) { throw std::runtime_error("malformed data"); } \
|
||||
if (EndianSwapper::SwapByteBase::ShouldSwap()) \
|
||||
{ \
|
||||
for (int i = 0; i < sizeof(type) / 2; ++i) \
|
||||
EndianSwapper::SwapByteBase::SwapBytes(c[i], c[sizeof(type) - 1 - i]); \
|
||||
} \
|
||||
v = f; \
|
||||
return *this; \
|
||||
} \
|
||||
const Archive& operator&(type v) const \
|
||||
{ \
|
||||
union { type f; uint8_t c[sizeof(type)];}; \
|
||||
f = v; \
|
||||
if (EndianSwapper::SwapByteBase::ShouldSwap()) \
|
||||
{ \
|
||||
for (int i = 0; i < sizeof(type) / 2; ++i) \
|
||||
EndianSwapper::SwapByteBase::SwapBytes(c[i], c[sizeof(type) - 1 - i]); \
|
||||
} \
|
||||
m_stream.write((const char*)&c[0], sizeof(type)); \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
SERIALIZER_FOR_POD(bool)
|
||||
SERIALIZER_FOR_POD(char)
|
||||
SERIALIZER_FOR_POD(unsigned char)
|
||||
SERIALIZER_FOR_POD(short)
|
||||
SERIALIZER_FOR_POD(unsigned short)
|
||||
SERIALIZER_FOR_POD(int)
|
||||
SERIALIZER_FOR_POD(unsigned int)
|
||||
SERIALIZER_FOR_POD(long)
|
||||
SERIALIZER_FOR_POD(unsigned long)
|
||||
SERIALIZER_FOR_POD(long long)
|
||||
SERIALIZER_FOR_POD(unsigned long long)
|
||||
SERIALIZER_FOR_POD_FLOATINGPOINT(float)
|
||||
SERIALIZER_FOR_POD_FLOATINGPOINT(double)
|
||||
|
||||
|
||||
#define SERIALIZER_FOR_STL(type) \
|
||||
template <class T> \
|
||||
Archive& operator&(type<T>& v) \
|
||||
{ \
|
||||
uint32_t len; \
|
||||
*this & len; \
|
||||
for(uint32_t i = 0; i < len; ++i) \
|
||||
{ \
|
||||
T value; \
|
||||
*this & value; \
|
||||
v.insert(v.end(), value); \
|
||||
} \
|
||||
return *this; \
|
||||
} \
|
||||
template <class T> \
|
||||
const Archive& operator&(const type<T>& v) const \
|
||||
{ \
|
||||
uint32_t len = v.size(); \
|
||||
*this & len; \
|
||||
for(typename type<T>::const_iterator it = v.begin(); it != v.end(); ++it) \
|
||||
*this & *it; \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
#define SERIALIZER_FOR_STL2(type) \
|
||||
template <class T1, class T2> \
|
||||
Archive& operator&(type<T1, T2>& v) \
|
||||
{ \
|
||||
uint32_t len; \
|
||||
*this & len; \
|
||||
for(uint32_t i = 0; i < len; ++i) \
|
||||
{ \
|
||||
std::pair<T1, T2> value; \
|
||||
*this & value; \
|
||||
v.insert(v.end(), value); \
|
||||
} \
|
||||
return *this; \
|
||||
} \
|
||||
template <class T1, class T2> \
|
||||
const Archive& operator&(const type<T1, T2>& v) const \
|
||||
{ \
|
||||
uint32_t len = v.size(); \
|
||||
*this & len; \
|
||||
for(typename type<T1, T2>::const_iterator it = v.begin(); it != v.end(); ++it) \
|
||||
*this & *it; \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
SERIALIZER_FOR_STL(std::vector)
|
||||
SERIALIZER_FOR_STL(std::deque)
|
||||
SERIALIZER_FOR_STL(std::list)
|
||||
SERIALIZER_FOR_STL(std::set)
|
||||
SERIALIZER_FOR_STL(std::multiset)
|
||||
SERIALIZER_FOR_STL2(std::map)
|
||||
SERIALIZER_FOR_STL2(std::multimap)
|
||||
|
||||
template <class T1, class T2>
|
||||
Archive& operator&(std::pair<T1, T2>& v)
|
||||
{
|
||||
*this & v.first & v.second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
const Archive& operator&(const std::pair<T1, T2>& v) const
|
||||
{
|
||||
*this & v.first & v.second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Archive& operator&(std::string& v)
|
||||
{
|
||||
uint32_t len;
|
||||
*this & len;
|
||||
v.clear();
|
||||
char buffer[4096];
|
||||
uint32_t toRead = len;
|
||||
while(toRead != 0)
|
||||
{
|
||||
uint32_t l = std::min(toRead, (uint32_t)sizeof(buffer));
|
||||
m_stream.read(buffer, l);
|
||||
if(!m_stream)
|
||||
throw std::runtime_error("malformed data");
|
||||
v += std::string(buffer, l);
|
||||
toRead -= l;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Archive& operator&(const std::string& v) const
|
||||
{
|
||||
uint32_t len = v.length();
|
||||
*this & len;
|
||||
m_stream.write(v.c_str(), len);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
template <class T>
|
||||
T Swap(const T& v) const
|
||||
{
|
||||
return EndianSwapper::SwapByte<T, sizeof(T)>::Swap(v);
|
||||
}
|
||||
|
||||
private:
|
||||
STREAM_TYPE& m_stream;
|
||||
};
|
||||
|
||||
#endif // ARCHIVE_H__
|
385
include/archive.h
Normal file
385
include/archive.h
Normal file
@@ -0,0 +1,385 @@
|
||||
/*
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <https://unlicense.org>
|
||||
*/
|
||||
|
||||
#ifndef ARCHIVE_H__
|
||||
#define ARCHIVE_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
#include <exception>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace EndianSwapper
|
||||
{
|
||||
class SwapByteBase
|
||||
{
|
||||
public:
|
||||
static bool ShouldSwap()
|
||||
{
|
||||
static const uint16_t swapTest = 1;
|
||||
return (*((char*)&swapTest) == 1);
|
||||
}
|
||||
|
||||
static void SwapBytes(uint8_t& v1, uint8_t& v2)
|
||||
{
|
||||
uint8_t tmp = v1;
|
||||
v1 = v2;
|
||||
v2 = tmp;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, int S>
|
||||
class SwapByte : public SwapByteBase
|
||||
{
|
||||
public:
|
||||
static T Swap(T v)
|
||||
{
|
||||
assert(false); // Shoud not be here...
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class SwapByte<T, 1> : public SwapByteBase
|
||||
{
|
||||
public:
|
||||
static T Swap(T v)
|
||||
{
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class SwapByte<T, 2> : public SwapByteBase
|
||||
{
|
||||
public:
|
||||
static T Swap(T v)
|
||||
{
|
||||
if(ShouldSwap())
|
||||
return ((uint16_t)v >> 8) | ((uint16_t)v << 8);
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class SwapByte<T, 4> : public SwapByteBase
|
||||
{
|
||||
public:
|
||||
static T Swap(T v)
|
||||
{
|
||||
if(ShouldSwap())
|
||||
{
|
||||
return (SwapByte<uint16_t, 2>::Swap((uint32_t)v & 0xffff) << 16) | (SwapByte<uint16_t, 2>::Swap(((uint32_t)v & 0xffff0000) >> 16));
|
||||
}
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class SwapByte<T, 8> : public SwapByteBase
|
||||
{
|
||||
public:
|
||||
static T Swap(T v)
|
||||
{
|
||||
if(ShouldSwap())
|
||||
return (((uint64_t)SwapByte<uint32_t, 4>::Swap((uint32_t)(v & 0xffffffffull))) << 32) | (SwapByte<uint32_t, 4>::Swap((uint32_t)(v >> 32)));
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class SwapByte<float, 4> : public SwapByteBase
|
||||
{
|
||||
public:
|
||||
static float Swap(float v)
|
||||
{
|
||||
union { float f; uint8_t c[4]; };
|
||||
f = v;
|
||||
if(ShouldSwap())
|
||||
{
|
||||
SwapBytes(c[0], c[3]);
|
||||
SwapBytes(c[1], c[2]);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
class SwapByte<double, 8> : public SwapByteBase
|
||||
{
|
||||
public:
|
||||
static double Swap(double v)
|
||||
{
|
||||
union { double f; uint8_t c[8]; };
|
||||
f = v;
|
||||
if(ShouldSwap())
|
||||
{
|
||||
SwapBytes(c[0], c[7]);
|
||||
SwapBytes(c[1], c[6]);
|
||||
SwapBytes(c[2], c[5]);
|
||||
SwapBytes(c[3], c[4]);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
template <class STREAM_TYPE>
|
||||
class Archive
|
||||
{
|
||||
public:
|
||||
Archive(STREAM_TYPE& stream) : m_stream(stream)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
template <class T>
|
||||
const Archive& operator<<(const T& v) const
|
||||
{
|
||||
*this & v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
Archive& operator>>(T& v)
|
||||
{
|
||||
*this & v;
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
template <class T>
|
||||
Archive& operator&(T& v)
|
||||
{
|
||||
v.Serialize(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
const Archive& operator&(const T& v) const
|
||||
{
|
||||
((T&)v).Serialize(*this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T, size_t N>
|
||||
Archive& operator&(T (&v)[N])
|
||||
{
|
||||
uint32_t len;
|
||||
*this & len;
|
||||
for(size_t i = 0; i < N; ++i)
|
||||
*this & v[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T, size_t N>
|
||||
const Archive& operator&(const T (&v)[N]) const
|
||||
{
|
||||
uint32_t len = N;
|
||||
*this & len;
|
||||
for(size_t i = 0; i < N; ++i)
|
||||
*this & v[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
#define SERIALIZER_FOR_POD(type) \
|
||||
Archive& operator&(type& v) \
|
||||
{ \
|
||||
m_stream.read((char*)&v, sizeof(type)); \
|
||||
if(!m_stream) { throw std::runtime_error("malformed data"); } \
|
||||
v = Swap(v); \
|
||||
return *this; \
|
||||
} \
|
||||
const Archive& operator&(type v) const \
|
||||
{ \
|
||||
v = Swap(v); \
|
||||
m_stream.write((const char*)&v, sizeof(type)); \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
// Special serializer for floating point values, can't directly swap on floating point variable
|
||||
// because it might cause a NaN and the wrong value is read back (the problem occurs on vstudio)
|
||||
#define SERIALIZER_FOR_POD_FLOATINGPOINT(type) \
|
||||
Archive& operator&(type& v) \
|
||||
{ \
|
||||
union { type f; uint8_t c[sizeof(type)];}; \
|
||||
m_stream.read((char*)&c[0], sizeof(type)); \
|
||||
if (!m_stream) { throw std::runtime_error("malformed data"); } \
|
||||
if (EndianSwapper::SwapByteBase::ShouldSwap()) \
|
||||
{ \
|
||||
for (int i = 0; i < sizeof(type) / 2; ++i) \
|
||||
EndianSwapper::SwapByteBase::SwapBytes(c[i], c[sizeof(type) - 1 - i]); \
|
||||
} \
|
||||
v = f; \
|
||||
return *this; \
|
||||
} \
|
||||
const Archive& operator&(type v) const \
|
||||
{ \
|
||||
union { type f; uint8_t c[sizeof(type)];}; \
|
||||
f = v; \
|
||||
if (EndianSwapper::SwapByteBase::ShouldSwap()) \
|
||||
{ \
|
||||
for (int i = 0; i < sizeof(type) / 2; ++i) \
|
||||
EndianSwapper::SwapByteBase::SwapBytes(c[i], c[sizeof(type) - 1 - i]); \
|
||||
} \
|
||||
m_stream.write((const char*)&c[0], sizeof(type)); \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
SERIALIZER_FOR_POD(bool)
|
||||
SERIALIZER_FOR_POD(char)
|
||||
SERIALIZER_FOR_POD(unsigned char)
|
||||
SERIALIZER_FOR_POD(short)
|
||||
SERIALIZER_FOR_POD(unsigned short)
|
||||
SERIALIZER_FOR_POD(int)
|
||||
SERIALIZER_FOR_POD(unsigned int)
|
||||
SERIALIZER_FOR_POD(long)
|
||||
SERIALIZER_FOR_POD(unsigned long)
|
||||
SERIALIZER_FOR_POD(long long)
|
||||
SERIALIZER_FOR_POD(unsigned long long)
|
||||
SERIALIZER_FOR_POD_FLOATINGPOINT(float)
|
||||
SERIALIZER_FOR_POD_FLOATINGPOINT(double)
|
||||
|
||||
|
||||
#define SERIALIZER_FOR_STL(type) \
|
||||
template <class T> \
|
||||
Archive& operator&(type<T>& v) \
|
||||
{ \
|
||||
uint32_t len; \
|
||||
*this & len; \
|
||||
for(uint32_t i = 0; i < len; ++i) \
|
||||
{ \
|
||||
T value; \
|
||||
*this & value; \
|
||||
v.insert(v.end(), value); \
|
||||
} \
|
||||
return *this; \
|
||||
} \
|
||||
template <class T> \
|
||||
const Archive& operator&(const type<T>& v) const \
|
||||
{ \
|
||||
uint32_t len = v.size(); \
|
||||
*this & len; \
|
||||
for(typename type<T>::const_iterator it = v.begin(); it != v.end(); ++it) \
|
||||
*this & *it; \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
#define SERIALIZER_FOR_STL2(type) \
|
||||
template <class T1, class T2> \
|
||||
Archive& operator&(type<T1, T2>& v) \
|
||||
{ \
|
||||
uint32_t len; \
|
||||
*this & len; \
|
||||
for(uint32_t i = 0; i < len; ++i) \
|
||||
{ \
|
||||
std::pair<T1, T2> value; \
|
||||
*this & value; \
|
||||
v.insert(v.end(), value); \
|
||||
} \
|
||||
return *this; \
|
||||
} \
|
||||
template <class T1, class T2> \
|
||||
const Archive& operator&(const type<T1, T2>& v) const \
|
||||
{ \
|
||||
uint32_t len = v.size(); \
|
||||
*this & len; \
|
||||
for(typename type<T1, T2>::const_iterator it = v.begin(); it != v.end(); ++it) \
|
||||
*this & *it; \
|
||||
return *this; \
|
||||
}
|
||||
|
||||
SERIALIZER_FOR_STL(std::vector)
|
||||
SERIALIZER_FOR_STL(std::deque)
|
||||
SERIALIZER_FOR_STL(std::list)
|
||||
SERIALIZER_FOR_STL(std::set)
|
||||
SERIALIZER_FOR_STL(std::multiset)
|
||||
SERIALIZER_FOR_STL2(std::map)
|
||||
SERIALIZER_FOR_STL2(std::multimap)
|
||||
|
||||
template <class T1, class T2>
|
||||
Archive& operator&(std::pair<T1, T2>& v)
|
||||
{
|
||||
*this & v.first & v.second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T1, class T2>
|
||||
const Archive& operator&(const std::pair<T1, T2>& v) const
|
||||
{
|
||||
*this & v.first & v.second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Archive& operator&(std::string& v)
|
||||
{
|
||||
uint32_t len;
|
||||
*this & len;
|
||||
v.clear();
|
||||
char buffer[4096];
|
||||
uint32_t toRead = len;
|
||||
while(toRead != 0)
|
||||
{
|
||||
uint32_t l = std::min(toRead, (uint32_t)sizeof(buffer));
|
||||
m_stream.read(buffer, l);
|
||||
if(!m_stream)
|
||||
throw std::runtime_error("malformed data");
|
||||
v += std::string(buffer, l);
|
||||
toRead -= l;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Archive& operator&(const std::string& v) const
|
||||
{
|
||||
uint32_t len = v.length();
|
||||
*this & len;
|
||||
m_stream.write(v.c_str(), len);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
template <class T>
|
||||
T Swap(const T& v) const
|
||||
{
|
||||
return EndianSwapper::SwapByte<T, sizeof(T)>::Swap(v);
|
||||
}
|
||||
|
||||
private:
|
||||
STREAM_TYPE& m_stream;
|
||||
};
|
||||
|
||||
#endif // ARCHIVE_H__
|
254
main.cpp
254
main.cpp
@@ -1,254 +0,0 @@
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <limits.h>
|
||||
#include "archive.h"
|
||||
|
||||
////////////////////////////////////////////////////
|
||||
// Test/usage examples for archive
|
||||
////////////////////////////////////////////////////
|
||||
|
||||
|
||||
struct Message
|
||||
{
|
||||
int id;
|
||||
std::string name;
|
||||
std::vector<std::string> groups;
|
||||
float coolNumbers[3];
|
||||
|
||||
|
||||
Message(int nid = 1, const std::string& nname = "unknown") : id(nid), name(nname)
|
||||
{
|
||||
coolNumbers[0] = 3.1416f;
|
||||
coolNumbers[1] = 2.7182f;
|
||||
coolNumbers[2] = 1.6180f;
|
||||
|
||||
groups.push_back("wheel");
|
||||
groups.push_back("lp");
|
||||
groups.push_back("root");
|
||||
groups.push_back("sudo");
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void Serialize(T& archive)
|
||||
{
|
||||
archive & id & name & groups & coolNumbers;
|
||||
}
|
||||
|
||||
// equality operator for the tests
|
||||
bool operator==(const Message& m) const
|
||||
{
|
||||
if(id != m.id)
|
||||
return false;
|
||||
if(name != m.name)
|
||||
return false;
|
||||
for(int i = 0; i < 3; ++i)
|
||||
if(coolNumbers[i] != m.coolNumbers[i])
|
||||
return false;
|
||||
for(unsigned int i = 0; i < groups.size(); ++i)
|
||||
if(groups[i] != m.groups[i])
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool operator!=(const Message& m) const
|
||||
{
|
||||
return !(*this == m);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void Test(const T& testValue)
|
||||
{
|
||||
std::stringstream s;
|
||||
Archive<std::stringstream> a(s);
|
||||
T value(testValue);
|
||||
|
||||
a << value;
|
||||
assert(testValue == value);
|
||||
|
||||
value = T();
|
||||
assert(testValue != value);
|
||||
|
||||
a >> value;
|
||||
assert(testValue == value);
|
||||
}
|
||||
|
||||
template <class T, size_t N>
|
||||
void TestArray(T (&value)[N])
|
||||
{
|
||||
std::stringstream s;
|
||||
Archive<std::stringstream> a(s);
|
||||
|
||||
a << value;
|
||||
a >> value;
|
||||
}
|
||||
|
||||
void TestFile()
|
||||
{
|
||||
// Serialize to file
|
||||
std::ofstream ofile("test.bin", std::ios::binary);
|
||||
Archive<std::ofstream> a(ofile);
|
||||
int i = 123;
|
||||
std::string name = "mouton";
|
||||
float pi = 3.1416f;
|
||||
Message m(666, "the beast");
|
||||
|
||||
a << i << name << pi << m;
|
||||
ofile.close();
|
||||
|
||||
|
||||
// Unserialize from file:
|
||||
int i2;
|
||||
std::string name2;
|
||||
float pi2;
|
||||
Message m2;
|
||||
|
||||
std::ifstream ifile("test.bin", std::ios::binary);
|
||||
if(!ifile.is_open())
|
||||
{
|
||||
std::cout << "ERROR file doesn't exist.." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
Archive<std::ifstream> a2(ifile);
|
||||
a2 >> i2 >> name2 >> pi2 >> m2;
|
||||
ifile.close();
|
||||
|
||||
assert(i == i2);
|
||||
assert(name == name2);
|
||||
assert(pi == pi2);
|
||||
assert(m == m2);
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
// POD
|
||||
std::cout << "POD..." << std::endl;
|
||||
Test(true);
|
||||
|
||||
Test((char)123);
|
||||
Test((char)-123);
|
||||
Test((char)SCHAR_MIN);
|
||||
Test((char)SCHAR_MAX);
|
||||
Test((unsigned char)123);
|
||||
Test((unsigned char)UCHAR_MAX);
|
||||
|
||||
Test((short)123);
|
||||
Test((short)-123);
|
||||
Test((short)SHRT_MIN);
|
||||
Test((short)SHRT_MAX);
|
||||
Test((unsigned short)123);
|
||||
|
||||
Test((int)123);
|
||||
Test((int)-123);
|
||||
Test((int)INT_MIN);
|
||||
Test((int)INT_MAX);
|
||||
Test((unsigned int)123);
|
||||
Test((unsigned int)UINT_MAX);
|
||||
|
||||
Test((long)123);
|
||||
Test((long)-123);
|
||||
Test((long)LONG_MIN);
|
||||
Test((long)LONG_MAX);
|
||||
Test((unsigned long)123);
|
||||
Test((unsigned long)ULONG_MAX);
|
||||
|
||||
Test((long long)123);
|
||||
Test((long long)-123);
|
||||
Test((long long)LLONG_MIN);
|
||||
Test((long long)LLONG_MAX);
|
||||
Test((unsigned long long)123);
|
||||
Test((unsigned long long)ULLONG_MAX);
|
||||
|
||||
Test(std::string("salut"));
|
||||
Test(123.456f);
|
||||
Test(-123.456f);
|
||||
Test(123.456);
|
||||
Test(-123.456);
|
||||
|
||||
// Test problem with NaN (reported by @NikishinRoman on vstudio: https://github.com/voidah/archive/issues/10)
|
||||
Test(-0.348907441f);
|
||||
|
||||
// Array
|
||||
std::cout << "Array..." << std::endl;
|
||||
int ii[] = {1, 2, 3, 4, 5, 6};
|
||||
TestArray(ii);
|
||||
|
||||
// STL
|
||||
std::cout << "STL..." << std::endl;
|
||||
Test(std::vector<int>({1, 2, 3, 4, 5}));
|
||||
Test(std::vector<std::string>({"a", "bb", "ccc", "dddd"}));
|
||||
Test(std::deque<int>({1, 2, 3, 4, 5}));
|
||||
Test(std::deque<std::string>({"a", "bb", "ccc", "dddd"}));
|
||||
Test(std::list<int>({1, 2, 3, 4, 5}));
|
||||
Test(std::list<std::string>({"a", "bb", "ccc", "dddd"}));
|
||||
Test(std::set<int>({1, 2, 3, 4, 5}));
|
||||
Test(std::set<std::string>({"a", "bb", "ccc", "dddd"}));
|
||||
Test(std::multiset<int>({1, 2, 3, 4, 5}));
|
||||
Test(std::multiset<std::string>({"a", "bb", "ccc", "dddd"}));
|
||||
Test(std::map<int, std::string>({std::make_pair(1, "a"), std::make_pair(2, "bb")}));
|
||||
Test(std::multimap<int, std::string>({std::make_pair(1, "a"), std::make_pair(2, "bb")}));
|
||||
|
||||
// User type
|
||||
std::cout << "User type..." << std::endl;
|
||||
Test(Message(666, "the beast"));
|
||||
|
||||
// Serialize to/from file
|
||||
std::cout << "In/Out from file..." << std::endl;
|
||||
TestFile();
|
||||
|
||||
// invalid data, invalid string length
|
||||
{
|
||||
std::cout << "Testing invalid data (invalid string length), should throw an exception" << std::endl;
|
||||
std::stringstream s1;
|
||||
Archive<std::stringstream> a1(s1);
|
||||
a1 << std::string("salut");
|
||||
|
||||
std::string data = s1.str();
|
||||
|
||||
// Corrupt string length:
|
||||
data[0] = (char)255; // the first 4 bytes are the string length
|
||||
data[1] = (char)255; // the first 4 bytes are the string length
|
||||
data[2] = (char)255; // the first 4 bytes are the string length
|
||||
data[3] = (char)255; // the first 4 bytes are the string length
|
||||
|
||||
// Try to read back the data:
|
||||
try
|
||||
{
|
||||
std::istringstream s2(data);
|
||||
Archive<std::istringstream> a2(s2);
|
||||
std::string value;
|
||||
a2 >> value;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
std::cout << " GOOD! exception catched" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// invalid data, not enough data
|
||||
{
|
||||
std::cout << "Testing invalid data (not enough data), should throw an exception" << std::endl;
|
||||
std::stringstream s1;
|
||||
Archive<std::stringstream> a1(s1);
|
||||
a1 << 'a';
|
||||
|
||||
std::string data = s1.str();
|
||||
std::cout << data << std::endl;
|
||||
|
||||
// Try to read back the data:
|
||||
try
|
||||
{
|
||||
std::istringstream s2(data);
|
||||
Archive<std::istringstream> a2(s2);
|
||||
int value;
|
||||
a2 >> value;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
std::cout << " GOOD! exception catched" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user