├── Makefile ├── bin └── serialize_test ├── deps ├── Makefile ├── lib │ └── liblut.a └── testlib │ ├── Makefile │ ├── lut.cpp │ └── lut.h ├── readme.md └── src ├── serialize.h └── test.cpp /Makefile: -------------------------------------------------------------------------------- 1 | ## 2 | ## 3 | ## 4 | BINDIR=bin 5 | EXES = $(BINDIR)/serialize_test 6 | SRCS=$(wildcard src/*.cpp ) 7 | OBJS=$(patsubst %.cpp,%.o,$(SRCS) ) 8 | RM :=rm -f 9 | 10 | CFLAGS= -g -Wall -rdynamic -O2 11 | CXXFLAGS = -g -Wall -rdynamic -O2 12 | CPPFLAGS = -I./deps -I./deps/testlib 13 | LIBS = -L./lib -L./deps/lib -llut 14 | 15 | all: dir $(OBJ) $(EXES) 16 | 17 | show: 18 | @echo "EXES=$(EXES)" 19 | @echo "SRCS=$(SRCS)" 20 | @echo "OBJS=$(OBJS)" 21 | 22 | dir: 23 | if [ ! -d $(BINDIR) ]; then mkdir $(BINDIR) ; fi; 24 | 25 | $(EXES): $(OBJS) 26 | g++ -o $@ $^ $(CXXFLAGS) $(CPPFLAGS) $(LIBS) 27 | 28 | clean: 29 | $(RM) $(EXES) $(OBJS) 30 | 31 | .c: 32 | $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $< 33 | 34 | .cpp: 35 | $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $@ $< 36 | 37 | # 38 | # 39 | 40 | -------------------------------------------------------------------------------- /bin/serialize_test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangyibo/serialize/1ccf4b23b232520bdf40ce187164add23839a2c7/bin/serialize_test -------------------------------------------------------------------------------- /deps/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # 3 | dirs = testlib 4 | 5 | all: 6 | for x in $(dirs); do (cd $$x; make); done 7 | cp testlib/liblut.a lib/ 8 | 9 | clean: 10 | for x in $(dirs); do (cd $$x; make clean); done 11 | 12 | cleanall: 13 | make clean 14 | rm -f lib/* 15 | # 16 | # 17 | -------------------------------------------------------------------------------- /deps/lib/liblut.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tangyibo/serialize/1ccf4b23b232520bdf40ce187164add23839a2c7/deps/lib/liblut.a -------------------------------------------------------------------------------- /deps/testlib/Makefile: -------------------------------------------------------------------------------- 1 | ## 2 | ## 3 | ## 4 | LIBS = liblut.a 5 | 6 | SRC=$(wildcard ./*.cpp) 7 | 8 | OBJ=$(patsubst %.cpp,%.o,$(SRC) ) 9 | 10 | RM :=rm -f 11 | 12 | 13 | 14 | CFLAGS= -g -Wall -fPIC -rdynamic -O2 15 | 16 | CXXFLAGS = -g -Wall -fPIC -rdynamic -O2 17 | 18 | CPPFLAGS = 19 | 20 | 21 | all: $(OBJ) $(LIBS) 22 | 23 | 24 | $(LIBS): $(OBJ) 25 | ar rcs $@ $? 26 | 27 | clean: 28 | $(RM) $(LIBS) *.o 29 | 30 | 31 | .c: 32 | $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $< 33 | 34 | .cpp: 35 | $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $@ $< 36 | -------------------------------------------------------------------------------- /deps/testlib/lut.cpp: -------------------------------------------------------------------------------- 1 | #include "lut.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace lut { 10 | 11 | struct TestContext 12 | { 13 | const char* base; 14 | const char* name; 15 | void (*func)(); 16 | }; 17 | 18 | static std::vector* tests; 19 | 20 | bool RegisterTest(const char* base, const char* name, void (*func)()) 21 | { 22 | if (tests == NULL) 23 | { 24 | tests = new std::vector; 25 | } 26 | 27 | TestContext t; 28 | t.base = base; 29 | t.name = name; 30 | t.func = func; 31 | 32 | tests->push_back(t); 33 | 34 | return true; 35 | } 36 | 37 | int RunAllTests() 38 | { 39 | int num = 0; 40 | 41 | for (size_t i = 0; i < tests->size(); ++i) 42 | { 43 | const TestContext& t = (*tests)[i]; 44 | std::string name = t.base; 45 | name.push_back('.'); 46 | name.append(t.name); 47 | 48 | fprintf(stderr, "==== Test %s.%s\n", t.base, t.name); 49 | (*t.func)(); 50 | ++num; 51 | } 52 | 53 | fprintf(stderr, "==== PASSED %d tests\n", num); 54 | return 0; 55 | } 56 | 57 | } // namespace lut 58 | -------------------------------------------------------------------------------- /deps/testlib/lut.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIGHT_UNIT_TEST_HEADER_H_ 2 | #define _LIGHT_UNIT_TEST_HEADER_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace lut { 9 | 10 | class Tester 11 | { 12 | private: 13 | bool ok_; //result status 14 | const char* fname_; //file name 15 | int line_; //line number 16 | std::stringstream ss_; //message for display 17 | 18 | public: 19 | Tester(const char* f, int l) 20 | : ok_(true), fname_(f), line_(l) 21 | { 22 | } 23 | 24 | ~Tester() 25 | { 26 | if (!ok_) 27 | { 28 | fprintf(stderr, "%s:%d:%s\n", fname_, line_, ss_.str().c_str()); 29 | exit(1); 30 | } 31 | } 32 | 33 | Tester& Is(bool b, const char* msg) 34 | { 35 | if (!b) 36 | { 37 | ss_ << " Assertion failure " << msg; 38 | ok_ = false; 39 | } 40 | return *this; 41 | } 42 | 43 | 44 | #define BINARY_OP(name,op) \ 45 | template \ 46 | Tester& name(const X& x, const Y& y) \ 47 | {\ 48 | if (!(x op y)) \ 49 | {\ 50 | ss_ << " failed: " << x << (" " #op " ") << y; \ 51 | ok_ = false; \ 52 | } \ 53 | return *this; \ 54 | } 55 | 56 | BINARY_OP(IsEq, ==) 57 | BINARY_OP(IsNe, !=) 58 | BINARY_OP(IsGe, >=) 59 | BINARY_OP(IsGt, >) 60 | BINARY_OP(IsLe, <=) 61 | BINARY_OP(IsLt, <) 62 | 63 | #undef BINARY_OP 64 | 65 | template 66 | Tester& operator<<(const V& value) 67 | { 68 | if (!ok_) 69 | { 70 | ss_ << " " << value; 71 | } 72 | return *this; 73 | } 74 | }; 75 | 76 | 77 | #define ASSERT_TRUE(c) ::lut::Tester(__FILE__, __LINE__).Is((c), #c) 78 | #define ASSERT_EQ(a,b) ::lut::Tester(__FILE__, __LINE__).IsEq((a),(b)) 79 | #define ASSERT_NE(a,b) ::lut::Tester(__FILE__, __LINE__).IsNe((a),(b)) 80 | #define ASSERT_GE(a,b) ::lut::Tester(__FILE__, __LINE__).IsGe((a),(b)) 81 | #define ASSERT_GT(a,b) ::lut::Tester(__FILE__, __LINE__).IsGt((a),(b)) 82 | #define ASSERT_LE(a,b) ::lut::Tester(__FILE__, __LINE__).IsLe((a),(b)) 83 | #define ASSERT_LT(a,b) ::lut::Tester(__FILE__, __LINE__).IsLt((a),(b)) 84 | 85 | #define TEST(base,name) \ 86 | class _test_##base##name \ 87 | { \ 88 | public: \ 89 | void _run(); \ 90 | static void Run() \ 91 | { \ 92 | _test_##base##name t; \ 93 | t._run(); \ 94 | } \ 95 | }; \ 96 | class _register_##base##name \ 97 | { \ 98 | public: \ 99 | _register_##base##name() \ 100 | { \ 101 | ::lut::RegisterTest(#base, #name, &_test_##base##name::Run); \ 102 | } \ 103 | }; \ 104 | _register_##base##name auto_register_##base##name; \ 105 | void _test_##base##name::_run() 106 | 107 | 108 | bool RegisterTest(const char *base, const char* name, void (*func)()); 109 | 110 | int RunAllTests(); 111 | 112 | }//namespace lut 113 | 114 | #endif//_LIGHT_UNIT_TEST_HEADER_H_ 115 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | 2 | # C++ 序列化探索 3 | 4 | ## 一、定义 5 | > 在编写应用程序的时候往往需要将程序的某些数据存储在内存中,然后将其写入某个文件或是将它传输到网络中的另一台计算机上以实现通讯。这个将 6 | 程序数据转化成能被存储并传输的格式的过程被称为“序列化”(Serialization),而它的逆过程则可被称为“反序列化” (Deserialization)。简单来 7 | 说,序列化就是将对象实例的状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它根据流重构对象。这两个过程结合起来,可以轻 松地 8 | 存储和传输数据。例如,可以序列化一个对象,然后使用 HTTP 通过 Internet 在客户端和服务器之间传输该对象。 9 | 对象序列化通常用于两个目的: 10 | - (1)将对象存储于硬盘上,便于以后反序列化使用 11 | - (2)在网络上传送对象的字节序列 12 | 13 | ## 二、当前已有的序列化方式 14 | - (1)JSON文本序列化方式 15 | > 例如使用jsoncpp或cJSON等库,将内存中的数据结构序列化为JSON格式的文本串。 16 | 17 | - (2)Google Protocol Buffers(protobuf) 18 | > Google Protocol Buffers (GPB)是Google内部使用的数据编码方式,旨在用来代替XML进行数据交换。可用于数据序列化与反序列化。 19 | > github地址:https://github.com/google/protobuf 20 | > 使用示例:http://blog.csdn.net/k346k346/article/details/51754431 21 | 22 | - (3)Boost的序列化库Serialization 23 | > Boost.Serialization可以创建或重建程序中的等效结构,并保存为二进制数据、文本数据、XML或者有用户自定义的其他文件。 24 | 25 | - (4)MFC的序列化 26 | > Windows平台下可使用MFC中的序列化方法。MFC 对 CObject 类中的序列化提供内置支持。因此,所有从 CObject 派生的类都可利用 CObject 的序列化协议。 27 | 28 | - (5)msgpack的序列化 29 | > MessagePack(简称msgpack)是一个高效的二进制序列化格式。它让你像JSON一样可以在各种语言之间交换数据。但是它比JSON更快、更小。小的整数会被编码 30 | 成一个字节,短的字符串仅仅只需要比它的长度多一字节的大小。 31 | > 官方网站: http://msgpack.org/ 。 32 | 33 | >说明:为了考虑平台的移植性、适用性和高效性,推荐大家使用Google的protobuf和Boost的序列化方案。 34 | 35 | ## 三、C++序列化的探索 36 | 37 | > 本部分代码所实现的C++序列化,支持如下特性: 38 | - (1)对基本数据类型char,short,int,long,string的序列化; 39 | - (2)支持序列化为socket流; 40 | - (3)支持对std::vector、std::list、std::set、std::map的序列化; 41 | 42 | ## 四、使用示例 43 | 44 | - 1、对于基本数据类型的序列化 45 | 46 | ``` 47 | char x = 'a'; 48 | short a = 1; 49 | int b = 2; 50 | long c = 3; 51 | float d = 4; 52 | long long e = 5; 53 | 54 | OutStream os; 55 | os << x << a << b << c << d << e; 56 | 57 | std::string serializestr = os.str(); 58 | 59 | char x1; 60 | short a1; 61 | int b1; 62 | long c1; 63 | float d1; 64 | long long e1; 65 | 66 | InStream is(serializestr); 67 | is >> x1 >> a1 >> b1 >> c1 >> d1 >> e1; 68 | ``` 69 | 70 | - 2、对于自定义类的序列化 71 | 72 | 步骤一:编写自定义类:自定义的类需要继承自Serializable,并实现serialize()和deserialize()方法: 73 | 74 | ``` 75 | class MyTest : public Serializable 76 | { 77 | public: 78 | std::string m_name; 79 | int m_age; 80 | float m_salary; 81 | 82 | public: 83 | 84 | MyTest() 85 | { 86 | m_name.clear(); 87 | m_age = 0; 88 | m_salary = 0.; 89 | } 90 | 91 | MyTest(const char *name, const int age, const float salary) 92 | { 93 | m_name.assign(name); 94 | m_age = age; 95 | m_salary = salary; 96 | } 97 | 98 | MyTest(const MyTest& other) 99 | { 100 | m_name = other.m_name; 101 | m_age = other.m_age; 102 | m_salary = other.m_salary; 103 | } 104 | 105 | ~MyTest() 106 | { 107 | m_name.clear(); 108 | } 109 | 110 | MyTest& operator=(const MyTest& other) 111 | { 112 | if (this != &other) 113 | { 114 | m_name = other.m_name; 115 | m_age = other.m_age; 116 | m_salary = other.m_salary; 117 | } 118 | 119 | return *this; 120 | } 121 | 122 | virtual std::string serialize() 123 | { 124 | OutStream os; 125 | os << m_name << m_age << m_salary; 126 | return os.str(); 127 | } 128 | 129 | virtual int deserialize(std::string &str) 130 | { 131 | InStream is(str); 132 | is >> m_name >> m_age>>m_salary; 133 | return is.size(); 134 | } 135 | 136 | void display() 137 | { 138 | std::cout << m_name << "," << m_age << "," << m_salary << std::endl; 139 | } 140 | }; 141 | 142 | bool operator==(const MyTest &lhs, const MyTest &rhs) 143 | { 144 | return lhs.m_name == rhs.m_name && 145 | lhs.m_age == rhs.m_age && 146 | lhs.m_salary == rhs.m_salary; 147 | } 148 | ``` 149 | 150 | 步骤2:对自定义类的对象进行序列化: 151 | 152 | ``` 153 | std::vector n; 154 | n.push_back(MyTest("aaa", 111, 222)); 155 | n.push_back(MyTest("bbb", 222, 333)); 156 | n.push_back(MyTest("ccc", 333, 444)); 157 | 158 | OutStream os; 159 | os << n; 160 | std::string serializestr = os.str(); 161 | 162 | std::vector n1; 163 | 164 | InStream is(serializestr); 165 | is >> n1; 166 | ``` 167 | 168 | 169 | - 3、对于std::list的序列化: 170 | 171 | ``` 172 | std::list strarr; 173 | strarr.push_back("hello"); 174 | strarr.push_back("world"); 175 | strarr.push_back("hello"); 176 | 177 | OutStream os; 178 | os << strarr; 179 | 180 | std::string codestr = os.str(); 181 | 182 | std::list newstrarr; 183 | InStream is(codestr); 184 | is>>newstrarr; 185 | ``` 186 | 187 | - 4、对于std::set的序列化: 188 | 189 | ``` 190 | std::set strarr; 191 | strarr.insert("hello"); 192 | strarr.insert("world"); 193 | strarr.insert("hello"); 194 | 195 | OutStream os; 196 | os << strarr; 197 | 198 | std::string codestr = os.str(); 199 | 200 | std::set newstrarr; 201 | InStream is(codestr); 202 | is>>newstrarr; 203 | ``` 204 | 205 | - 5、对于std::map的序列化: 206 | 207 | ``` 208 | std::map themap; 209 | themap["first"] = 1; 210 | themap["second"] = 2; 211 | themap["third"] = 3; 212 | themap["fourth"] = 4; 213 | 214 | OutStream os; 215 | os << themap; 216 | 217 | std::string codestr = os.str(); 218 | 219 | std::map newmap; 220 | InStream is(codestr); 221 | is>>newmap; 222 | ``` 223 | 224 | ## 五、FAQ 225 | 226 | -------------------------------------------------------------------------------- /src/serialize.h: -------------------------------------------------------------------------------- 1 | #ifndef _SERIALIZE_HEADER_H_ 2 | #define _SERIALIZE_HEADER_H_ 3 | #include //std::stringstream 4 | #include //std::vector 5 | #include //std::list 6 | #include //std::set 7 | #include //std::map 8 | #include // std::pair 9 | #include //std::back_inserter 10 | #include //memcpy 11 | 12 | //////////////////////////////////////////////////// 13 | // define normal template function 14 | //////////////////////////////////////////////////// 15 | 16 | template 17 | std::string serialize ( SerializableType& a ) 18 | { 19 | return a.serialize ( ); 20 | } 21 | 22 | template 23 | int deserialize ( std::string &str, SerializableType& a ) 24 | { 25 | return a.deserialize ( str ); 26 | } 27 | 28 | ///////////////////////////////////////////////// 29 | //define special template function 30 | //Serialize for C/C++ basic type 31 | //examples: short,int,float,long long,double 32 | ///////////////////////////////////////////////// 33 | #define DEF_BASIC_TYPE_SERIALIZE(Type) \ 34 | template<> \ 35 | std::string inline serialize(Type& b) \ 36 | { \ 37 | std::string ret; \ 38 | ret.append((const char*)&b,sizeof(Type)); \ 39 | return ret; \ 40 | } 41 | 42 | #define DEF_BASIC_TYPE_DESERIALIZE(Type) \ 43 | template<> \ 44 | int inline deserialize(std::string& str,Type& b)\ 45 | { \ 46 | memcpy(&b,str.data(),sizeof(Type)); \ 47 | return sizeof(Type); \ 48 | } 49 | 50 | #define DEF_BASIC_TYPE_SERIALIZE_AND_DESERIALIZE(Type) \ 51 | DEF_BASIC_TYPE_SERIALIZE(Type) \ 52 | DEF_BASIC_TYPE_DESERIALIZE(Type) 53 | 54 | DEF_BASIC_TYPE_SERIALIZE_AND_DESERIALIZE ( char ) 55 | DEF_BASIC_TYPE_SERIALIZE_AND_DESERIALIZE ( unsigned char ) 56 | DEF_BASIC_TYPE_SERIALIZE_AND_DESERIALIZE ( short int ) 57 | DEF_BASIC_TYPE_SERIALIZE_AND_DESERIALIZE ( unsigned short int ) 58 | DEF_BASIC_TYPE_SERIALIZE_AND_DESERIALIZE ( unsigned int ) 59 | DEF_BASIC_TYPE_SERIALIZE_AND_DESERIALIZE ( int ) 60 | DEF_BASIC_TYPE_SERIALIZE_AND_DESERIALIZE ( long int ) 61 | DEF_BASIC_TYPE_SERIALIZE_AND_DESERIALIZE ( unsigned long int ) 62 | DEF_BASIC_TYPE_SERIALIZE_AND_DESERIALIZE ( float ) 63 | DEF_BASIC_TYPE_SERIALIZE_AND_DESERIALIZE ( long long int ) 64 | DEF_BASIC_TYPE_SERIALIZE_AND_DESERIALIZE ( unsigned long long int ) 65 | DEF_BASIC_TYPE_SERIALIZE_AND_DESERIALIZE ( double ) 66 | 67 | ////////////////////////////////////// 68 | //Serialize for type string 69 | ///////////////////////////////////// 70 | 71 | // for c++ type std::string 72 | template<> 73 | std::string inline serialize ( std::string& s ) 74 | { 75 | int len = s.size ( ); 76 | std::string ret; 77 | ret.append ( ::serialize ( len ) ); 78 | ret.append ( s.data ( ), len ); 79 | return ret; 80 | } 81 | 82 | template<> 83 | int inline deserialize ( std::string &str, std::string& s ) 84 | { 85 | int len; 86 | ::deserialize ( str, len ); 87 | s = str.substr ( sizeof (len ), len ); 88 | return sizeof (int )+len; 89 | } 90 | 91 | //////////////////////////////////////////// 92 | //define input and output stream 93 | //for serialize data struct 94 | //////////////////////////////////////////// 95 | 96 | class OutStream 97 | { 98 | public: 99 | 100 | OutStream ( ) : os ( std::ios::binary ) 101 | { 102 | } 103 | 104 | template 105 | OutStream& operator<< ( SerializableType& a ) 106 | { 107 | std::string x = ::serialize ( a ); 108 | os.write ( x.data ( ), x.size ( ) ); 109 | return *this; 110 | } 111 | 112 | template 113 | OutStream& operator<< ( std::vector& a ) 114 | { 115 | int len = a.size ( ); 116 | std::string x = ::serialize ( len ); 117 | os.write ( x.data ( ), x.size ( ) ); 118 | 119 | for ( int i = 0; i < len; ++i ) 120 | { 121 | std::string item = ::serialize ( a[i] ); 122 | os.write ( item.data ( ), item.size ( ) ); 123 | } 124 | 125 | return *this; 126 | } 127 | 128 | template 129 | OutStream& operator<< ( std::list& a ) 130 | { 131 | std::vector temp; 132 | std::copy ( a.begin ( ), a.end ( ), std::back_inserter ( temp ) ); 133 | return this->operator<< ( temp ); 134 | } 135 | 136 | template 137 | OutStream& operator<< ( std::set& a ) 138 | { 139 | std::vector temp; 140 | std::copy ( a.begin ( ), a.end ( ), std::back_inserter ( temp ) ); 141 | return this->operator<< ( temp ); 142 | } 143 | 144 | template 145 | OutStream& operator<< ( std::map& a ) 146 | { 147 | std::vector tempKey; 148 | std::vector tempVal; 149 | 150 | typename std::map::const_iterator it; 151 | for(it=a.begin();it!=a.end ();++it) 152 | { 153 | tempKey.push_back (it->first); 154 | tempVal.push_back (it->second); 155 | } 156 | 157 | this->operator<< ( tempKey ); 158 | return this->operator<< ( tempVal ); 159 | } 160 | 161 | std::string str ( ) 162 | { 163 | return os.str ( ); 164 | } 165 | 166 | public: 167 | std::ostringstream os; 168 | }; 169 | 170 | class InStream 171 | { 172 | public: 173 | 174 | InStream ( std::string &s ) : str ( s ), total ( s.size ( ) ) 175 | { 176 | } 177 | 178 | template 179 | InStream& operator>> ( SerializableType& a ) 180 | { 181 | int ret = ::deserialize ( str, a ); 182 | str = str.substr ( ret ); 183 | return *this; 184 | } 185 | 186 | template 187 | InStream& operator>> ( std::vector& a ) 188 | { 189 | int len = 0; 190 | int ret = ::deserialize ( str, len ); 191 | str = str.substr ( ret ); 192 | 193 | for ( int i = 0; i < len; ++i ) 194 | { 195 | BasicType item; 196 | int size = ::deserialize ( str, item ); 197 | str = str.substr ( size ); 198 | a.push_back ( item ); 199 | } 200 | 201 | return *this; 202 | } 203 | 204 | template 205 | InStream& operator>> ( std::list& a ) 206 | { 207 | std::vector temp; 208 | InStream& ret = this->operator>> ( temp ); 209 | if ( temp.size ( ) > 0 ) 210 | { 211 | std::copy ( temp.begin ( ), temp.end ( ), std::back_inserter ( a ) ); 212 | } 213 | 214 | return ret; 215 | } 216 | 217 | template 218 | InStream& operator>> ( std::set& a ) 219 | { 220 | std::vector temp; 221 | InStream& ret = this->operator>> ( temp ); 222 | if ( temp.size ( ) > 0 ) 223 | { 224 | for ( size_t i = 0; i < temp.size ( ); ++i ) 225 | { 226 | a.insert ( temp[i] ); 227 | } 228 | } 229 | 230 | return ret; 231 | } 232 | 233 | template 234 | InStream& operator>> ( std::map& a ) 235 | { 236 | std::vector tempKey; 237 | std::vector tempVal; 238 | 239 | this->operator>> ( tempKey ); 240 | InStream& ret = this->operator>> ( tempVal ); 241 | 242 | if ( tempKey.size ( ) > 0 && tempVal.size ()==tempKey.size () ) 243 | { 244 | for ( size_t i = 0; i < tempKey.size ( ); ++i ) 245 | { 246 | a.insert ( std::make_pair(tempKey[i],tempVal[i]) ); 247 | } 248 | } 249 | 250 | return ret; 251 | } 252 | 253 | int size ( ) 254 | { 255 | return total - str.size ( ); 256 | } 257 | 258 | protected: 259 | std::string str; 260 | int total; 261 | }; 262 | 263 | //////////////////////////////////////////// 264 | //Serialize for custom class object 265 | //If your class object want to be serialized, 266 | //Plese derive for this base class 267 | /////////////////////////////////////////// 268 | 269 | class Serializable 270 | { 271 | public: 272 | virtual std::string serialize ( ) = 0; 273 | virtual int deserialize ( std::string& ) = 0; 274 | }; 275 | 276 | /////////////////////////////////////////// 277 | //!!!!!!!!!!!!! 278 | //!! NOTE !! 279 | //!!!!!!!!!!!!! 280 | //Now,we can't serialize pointer type,likes 281 | //char* var,char var[],int *var,int var[] 282 | //etc,if you need to serialize array data, 283 | //we suggest you use std::vector instead. 284 | /////////////////////////////////////////// 285 | 286 | #endif 287 | -------------------------------------------------------------------------------- /src/test.cpp: -------------------------------------------------------------------------------- 1 | #include "serialize.h" 2 | #include "testlib/lut.h" 3 | #include 4 | #include 5 | 6 | class MyTest : public Serializable 7 | { 8 | public: 9 | std::string m_name; 10 | int m_age; 11 | float m_salary; 12 | 13 | public: 14 | 15 | MyTest() 16 | { 17 | m_name.clear(); 18 | m_age = 0; 19 | m_salary = 0.; 20 | } 21 | 22 | MyTest(const char *name, const int age, const float salary) 23 | { 24 | m_name.assign(name); 25 | m_age = age; 26 | m_salary = salary; 27 | } 28 | 29 | MyTest(const MyTest& other) 30 | { 31 | m_name = other.m_name; 32 | m_age = other.m_age; 33 | m_salary = other.m_salary; 34 | } 35 | 36 | ~MyTest() 37 | { 38 | m_name.clear(); 39 | } 40 | 41 | MyTest& operator=(const MyTest& other) 42 | { 43 | if (this != &other) 44 | { 45 | m_name = other.m_name; 46 | m_age = other.m_age; 47 | m_salary = other.m_salary; 48 | } 49 | 50 | return *this; 51 | } 52 | 53 | virtual std::string serialize() 54 | { 55 | OutStream os; 56 | os << m_name << m_age << m_salary; 57 | return os.str(); 58 | } 59 | 60 | virtual int deserialize(std::string &str) 61 | { 62 | InStream is(str); 63 | is >> m_name >> m_age>>m_salary; 64 | return is.size(); 65 | } 66 | 67 | void display() 68 | { 69 | std::cout << m_name << "," << m_age << "," << m_salary << std::endl; 70 | } 71 | }; 72 | 73 | bool operator==(const MyTest &lhs, const MyTest &rhs) 74 | { 75 | return lhs.m_name == rhs.m_name && 76 | lhs.m_age == rhs.m_age && 77 | lhs.m_salary == rhs.m_salary; 78 | } 79 | 80 | //////////////////////////////////////////////////////////////////// 81 | 82 | TEST(Serialize, BasicType) 83 | { 84 | char x = 'a'; 85 | short a = 1; 86 | int b = 2; 87 | long c = 3; 88 | float d = 4; 89 | long long e = 5; 90 | 91 | OutStream os; 92 | os << x << a << b << c << d << e; 93 | 94 | std::string serializestr = os.str(); 95 | 96 | char x1; 97 | short a1; 98 | int b1; 99 | long c1; 100 | float d1; 101 | long long e1; 102 | 103 | InStream is(serializestr); 104 | is >> x1 >> a1 >> b1 >> c1 >> d1 >> e1; 105 | 106 | ASSERT_EQ(x, x1); 107 | ASSERT_EQ(a, a1); 108 | ASSERT_EQ(b, b1); 109 | ASSERT_EQ(c, c1); 110 | ASSERT_EQ(d, d1); 111 | ASSERT_EQ(e, e1); 112 | } 113 | 114 | TEST(Serialize, String) 115 | { 116 | std::string f = "hello"; 117 | 118 | OutStream os; 119 | os << f; 120 | 121 | std::string serializestr = os.str(); 122 | 123 | std::string f1; 124 | 125 | InStream is(serializestr); 126 | is >>f1; 127 | 128 | ASSERT_EQ(f, f1); 129 | ASSERT_TRUE(f == f1); 130 | } 131 | 132 | TEST(Serialize, ClassObject) 133 | { 134 | MyTest t("zhang", 23, 3200.2); 135 | 136 | OutStream os; 137 | os << t; 138 | 139 | std::string serializestr = os.str(); 140 | 141 | MyTest t1; 142 | 143 | InStream is(serializestr); 144 | is >> t1; 145 | 146 | //t.display( ); 147 | //t1.display( ); 148 | ASSERT_TRUE(t == t1); 149 | } 150 | 151 | TEST(Serialize, ContainerVector) 152 | { 153 | std::vector n; 154 | n.push_back(MyTest("aaa", 111, 222)); 155 | n.push_back(MyTest("bbb", 222, 333)); 156 | n.push_back(MyTest("ccc", 333, 444)); 157 | 158 | OutStream os; 159 | os << n; 160 | std::string serializestr = os.str(); 161 | 162 | std::vector n1; 163 | 164 | InStream is(serializestr); 165 | is >> n1; 166 | 167 | ASSERT_EQ(n.size(), n1.size()); 168 | 169 | for (size_t i = 0; i < n.size(); ++i) 170 | { 171 | ASSERT_TRUE(n[i] == n1[i]); 172 | } 173 | } 174 | 175 | TEST(Serialize, ContainerList) 176 | { 177 | std::list strarr; 178 | strarr.push_back("hello"); 179 | strarr.push_back("world"); 180 | strarr.push_back("hello"); 181 | 182 | OutStream os; 183 | os << strarr; 184 | 185 | std::string codestr = os.str(); 186 | 187 | std::list newstrarr; 188 | InStream is(codestr); 189 | is>>newstrarr; 190 | 191 | ASSERT_EQ(strarr.size(), newstrarr.size()); 192 | std::list::iterator it, itnew; 193 | for (it = strarr.begin(), itnew = newstrarr.begin(); it != strarr.end() && itnew != newstrarr.end(); ++it, ++itnew) 194 | { 195 | ASSERT_EQ((*it), (*itnew)); 196 | ASSERT_TRUE((*it) == (*itnew)); 197 | } 198 | } 199 | 200 | TEST(Serialize, ContainerSet) 201 | { 202 | std::set strarr; 203 | strarr.insert("hello"); 204 | strarr.insert("world"); 205 | strarr.insert("hello"); 206 | 207 | OutStream os; 208 | os << strarr; 209 | 210 | std::string codestr = os.str(); 211 | 212 | std::set newstrarr; 213 | InStream is(codestr); 214 | is>>newstrarr; 215 | 216 | ASSERT_EQ(strarr.size(), newstrarr.size()); 217 | std::set::iterator it, itnew; 218 | for (it = strarr.begin(), itnew = newstrarr.begin(); it != strarr.end() && itnew != newstrarr.end(); ++it, ++itnew) 219 | { 220 | ASSERT_TRUE((*it) == (*itnew)); 221 | } 222 | } 223 | 224 | TEST(Serialize, ContainerMap) 225 | { 226 | std::map themap; 227 | themap["first"] = 1; 228 | themap["second"] = 2; 229 | themap["third"] = 3; 230 | themap["fourth"] = 4; 231 | 232 | OutStream os; 233 | os << themap; 234 | 235 | std::string codestr = os.str(); 236 | 237 | std::map newmap; 238 | InStream is(codestr); 239 | is>>newmap; 240 | 241 | ASSERT_EQ(themap.size(), newmap.size()); 242 | std::map::const_iterator it, itnew; 243 | for (it = newmap.begin(), itnew = newmap.begin(); it != newmap.end() && itnew != newmap.end(); ++it, ++itnew) 244 | { 245 | ASSERT_TRUE(it->first == itnew->first); 246 | ASSERT_TRUE(it->second == itnew->second); 247 | } 248 | } 249 | 250 | int main(int argc, char *argv[]) 251 | { 252 | return ::lut::RunAllTests(); 253 | } 254 | --------------------------------------------------------------------------------