From b66461aab102b6958f778a3d83d534b32e1f5fcc Mon Sep 17 00:00:00 2001 From: zwkno1 Date: Thu, 14 Mar 2019 17:21:55 +0800 Subject: [PATCH] support xml --- CMakeLists.txt | 7 +- examples/CMakeLists.txt | 20 +- examples/example.cpp | 95 ++++++++ examples/example_json.cpp | 74 ------- include/serialization/detail/json_iarchive.h | 22 +- include/serialization/detail/json_oarchive.h | 32 ++- .../detail/serialization_error.h | 2 +- .../detail/serialization_helper.h | 33 ++- include/serialization/detail/xml_iarchive.h | 176 ++++++++++----- include/serialization/detail/xml_oarchive.h | 169 ++++++++------ test/CMakeLists.txt | 1 + test/xmltest.cpp | 206 ++++++++++++++++++ 12 files changed, 593 insertions(+), 244 deletions(-) create mode 100644 examples/example.cpp delete mode 100644 examples/example_json.cpp create mode 100644 test/xmltest.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 045e8c7..3c5519d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,12 @@ cmake_minimum_required (VERSION 2.8) +option(ENABLE_TEST "enablle unittest" OFF) +option(ENABLE_PROTOBUF_EXAMPLE "protobuf example" OFF) + set(CMAKE_CXX_STANDARD 17) add_subdirectory(examples) - -option(ENABLE_TEST "enablle unittest" OFF) -option(ENABLE_PROTOBUF_EXAMPLE "protobuf example" OFF) - if (ENABLE_TEST) enable_testing() include(GNUInstallDirs) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 1c51c45..48264f6 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -4,8 +4,8 @@ project(serialize_example) include_directories(../include) -add_executable(example_json - example_json.cpp +add_executable(example + example.cpp ) if(ENABLE_PROTOBUF_EXAMPLE) @@ -17,13 +17,13 @@ if(ENABLE_PROTOBUF_EXAMPLE) file(GLOB ProtoFiles "${CMAKE_CURRENT_SOURCE_DIR}/*.proto") PROTOBUF_GENERATE_CPP(ProtoSources ProtoHeaders ${ProtoFiles}) -include_directories(${CMAKE_CURRENT_BINARY_DIR}) - -add_executable(example_protobuf - example_protobuf.cpp - ${ProtoSources} - ${ProtoHeaders} - ) -target_link_libraries(example_protobuf ${PROTOBUF_LIBRARY} ${CMAKE_THREAD_LIBS_INIT}) + include_directories(${CMAKE_CURRENT_BINARY_DIR}) + + add_executable(example_protobuf + example_protobuf.cpp + ${ProtoSources} + ${ProtoHeaders} + ) + target_link_libraries(example_protobuf ${PROTOBUF_LIBRARY} ${CMAKE_THREAD_LIBS_INIT}) endif() diff --git a/examples/example.cpp b/examples/example.cpp new file mode 100644 index 0000000..138358d --- /dev/null +++ b/examples/example.cpp @@ -0,0 +1,95 @@ + +#include +#include + +// print debug message +//#define ENABLE_SERIALIZATION_TRACE 1 + +#include + +struct Person +{ + std::string name; + int32_t age; + + bool operator==(const Person & other) const + { + return (name == other.name) && (age == other.age); + } + + SERIALIZATION_DEFINE(name, age) +}; + +struct AddressBook +{ + std::vector people; + std::optional opt; + std::map mapTest; + std::vector > > vectorTest; + + bool operator==(const AddressBook & other) const + { + return (people == other.people) + && (opt == other.opt) + && (mapTest == other.mapTest) + && (vectorTest == other.vectorTest); + } + + SERIALIZATION_DEFINE(people, opt, mapTest, vectorTest) +}; + +int main(int argc, char * argv[]) +{ + try + { + AddressBook ab = { + { + {"aaaaaaa", 12}, + {"qwasasdq", 22331}, + {"12qweqweqweqwe", 123123} + }, + "opt string", + { + {"a", {"a", 1} }, + {"b", {"b", 2} }, + {"c", {"c", 3} }, + }, + { + { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }, + { {11, 12, 13}, {14, 15, 16} }, + { {21, 22, 23} }, + } + }; + + // json serialize + serialization::json_oarchive json_oa; + serialization::serialize(json_oa, ab); + std::cout << "json serilize result: " << json_oa.data() << std::endl; + + // json unserialize + AddressBook ab2; + serialization::json_iarchive json_ia; + json_ia.load_data(json_oa.data()); + serialization::unserialize(json_ia, ab2); + std::cout << "json unserilize result: " << (ab == ab2 ? "success" : "fail") << std::endl; + + // xml serialize + serialization::xml_oarchive xml_oa; + serialization::serialize(xml_oa, ab); + std::string xml_str = xml_oa.data(); + std::cout << "xml serilize result: " << xml_str << std::endl; + + // xml unserialize + AddressBook ab3; + serialization::xml_iarchive xml_ia; + xml_ia.load_data(&xml_str[0]); + serialization::unserialize(xml_ia, ab3); + std::cout << "xml unserilize result: " << (ab == ab3 ? "success" : "fail") << std::endl; + + } + catch (serialization::serialization_error & err) + { + std::cout << err.where() << ":" << err.what() << std::endl; + } +} + diff --git a/examples/example_json.cpp b/examples/example_json.cpp deleted file mode 100644 index 89a8584..0000000 --- a/examples/example_json.cpp +++ /dev/null @@ -1,74 +0,0 @@ - -#include -#include - -// print debug message -//#define ENABLE_SERIALIZATION_TRACE 1 - -#include - -struct Person -{ - std::string name; - int32_t age; - - bool operator==(const Person & other) const - { - return (name == other.name) && (age == other.age); - } - - SERIALIZATION_DEFINE(name, age) -}; - -struct AddressBook -{ - std::vector people; - //std::vector> address; - //std::map test; - std::optional opt; - //SERIALIZATION_DEFINE(people, address, test, opt) - // - - bool operator==(const AddressBook & other) const - { - return (people == other.people) && (opt == other.opt); - } - - SERIALIZATION_DEFINE(people, opt) -}; - -int main(int argc, char * argv[]) -{ - try - { - AddressBook ab = { - { - {"aaaaaaa", 12}, - {"qwasasdq", 22331}, - {"12qweqweqweqwe", 123123} - }, - "opt string" - }; - - // serialize - serialization::json_oarchive oa; - serialization::serialize(oa, ab); - std::cout << oa.data() << std::endl; - - AddressBook ab2; - // unserialize - serialization::json_iarchive ia; - ia.load_data(oa.data()); - serialization::unserialize(ia, ab2); - - if(ab == ab2) - std::cout << "ok" << std::endl; - else - std::cout << "error" << std::endl; - } - catch (serialization::serialization_error & err) - { - std::cout << err.where() << ":" << err.what() << std::endl; - } -} - diff --git a/include/serialization/detail/json_iarchive.h b/include/serialization/detail/json_iarchive.h index 8c40c0e..87cc44a 100644 --- a/include/serialization/detail/json_iarchive.h +++ b/include/serialization/detail/json_iarchive.h @@ -81,23 +81,31 @@ class json_iarchive size_type sequence_size() const { if(stack_.empty() || (!stack_.top()->IsArray())) - return 0; + throw_serialization_error("expect array", ""); + return stack_.top()->GetArray().Size(); + } + + size_type load_sequence_start() const + { + if(stack_.empty() || (!stack_.top()->IsArray())) + throw_serialization_error("expect array", "json"); return stack_.top()->GetArray().Size(); } - bool load_sequence_start(size_type i) const + void load_sequence_end() const + { + } + + void load_sequence_item_start(size_type i) const { serialization_trace trace(__func__, "json"); assert(!stack_.empty()); - if(stack_.empty() || (!stack_.top()->IsArray())) - throw_serialization_error("expect array", ""); if(i >= stack_.top()->GetArray().Size()) - return false; + throw_serialization_error("array size", "json"); stack_.push(&stack_.top()->GetArray()[i]); - return true; } - void load_sequence_end() const + void load_sequence_item_end() const { serialization_trace trace(__func__, "json"); assert(!stack_.empty()); diff --git a/include/serialization/detail/json_oarchive.h b/include/serialization/detail/json_oarchive.h index 996afb1..d2c1086 100644 --- a/include/serialization/detail/json_oarchive.h +++ b/include/serialization/detail/json_oarchive.h @@ -18,6 +18,16 @@ class json_oarchive { } + const char * data() const + { + return buffer_.GetString(); + } + + size_t size() const + { + return buffer_.GetSize(); + } + void save_key_start(const char * key) { serialization_trace trace(__func__, key); @@ -41,7 +51,7 @@ class json_oarchive writer_.EndObject(); } - void save_sequence_start() + void save_sequence_start(std::size_t size) { serialization_trace trace(__func__, "json"); writer_.StartArray(); @@ -53,6 +63,14 @@ class json_oarchive writer_.EndArray(); } + void save_sequence_item_start() + { + } + + void save_sequence_item_end() + { + } + void save(bool v) { writer_.Bool(v); @@ -100,18 +118,8 @@ class json_oarchive serialization_trace trace(__func__, "json"); } - const char * data() const - { - return buffer_.GetString(); - } - - size_t size() const - { - return buffer_.GetSize(); - } - private: - rapidjson::StringBuffer buffer_; + rapidjson::StringBuffer buffer_; rapidjson::Writer writer_; }; diff --git a/include/serialization/detail/serialization_error.h b/include/serialization/detail/serialization_error.h index 6898669..90223f2 100644 --- a/include/serialization/detail/serialization_error.h +++ b/include/serialization/detail/serialization_error.h @@ -31,7 +31,7 @@ class serialization_error: public std::exception const char *m_where; }; -void throw_serialization_error(const char * where, const char * what) +inline void throw_serialization_error(const char * where, const char * what) { throw serialization_error(what, where); } diff --git a/include/serialization/detail/serialization_helper.h b/include/serialization/detail/serialization_helper.h index 5d28121..1f8146b 100644 --- a/include/serialization/detail/serialization_helper.h +++ b/include/serialization/detail/serialization_helper.h @@ -68,10 +68,12 @@ inline void serialize_container_helper(Archive & ar, const T & v) { serialization_trace trace(__func__, __FILE__, __LINE__); - ar.save_sequence_start(); + ar.save_sequence_start(v.size()); for(const auto & i : v) { + ar.save_sequence_item_start(); serialize_helper(ar, i); + ar.save_sequence_item_end(); } ar.save_sequence_end(); } @@ -165,15 +167,18 @@ inline void unserialize_helper(const Archive & ar, std::vector & v) { serialization_trace trace(__func__, __FILE__, __LINE__); - v.reserve(ar.sequence_size()); - - for(size_type i = 0; ar.load_sequence_start(i); ++i) + auto size = ar.load_sequence_start(); + v.reserve(size); + for(size_type i = 0; i < size; ++i) { + ar.load_sequence_item_start(i); T tmp; unserialize_helper(ar, tmp); v.push_back(std::move(tmp)); - ar.load_sequence_end(); + ar.load_sequence_item_end(); } + + ar.load_sequence_end(); } //array @@ -182,15 +187,17 @@ inline void unserialize_helper(const Archive & ar, T (&v)[N]) { serialization_trace trace(__func__, __FILE__, __LINE__); - if(ar.sequence_size() != N) + auto size = ar.load_sequence_start(); + if(size != N) throw_serialization_error("array", "size error"); - for(size_type i = 0; ar.load_sequence_start(i); ++i) + for(size_type i = 0; i < size; ++i) { + ar.load_sequence_item_start(i); unserialize_helper(ar, v[i]); - ar.load_sequence_end(); + ar.load_sequence_item_end(); } - + ar.load_sequence_end(); } //map @@ -199,14 +206,16 @@ inline void unserialize_helper(const Archive & ar, std::map & v) { serialization_trace trace(__func__, __FILE__, __LINE__); - for(size_type i = 0; ar.load_sequence_start(i); ++i) + auto size = ar.load_sequence_start(); + for(size_type i = 0; i < size; ++i) { + ar.load_sequence_item_start(i); typename std::pair tmp; unserialize_helper(ar, tmp); *std::insert_iterator>(v, v.end()) = std::move(tmp); - ar.load_sequence_end(); + ar.load_sequence_item_end(); } - + ar.load_sequence_end(); } } // namespace serialization diff --git a/include/serialization/detail/xml_iarchive.h b/include/serialization/detail/xml_iarchive.h index 61ddd87..419ec7f 100644 --- a/include/serialization/detail/xml_iarchive.h +++ b/include/serialization/detail/xml_iarchive.h @@ -5,6 +5,8 @@ #include #include +#include +#include #include namespace serialization @@ -12,104 +14,162 @@ namespace serialization class xml_iarchive { - typedef rapidxml::xml_node<> xml_node_type; - typedef rapidxml::xml_document<> xml_document_type; public: - xml_iarchive(const std::string & root = "", size_t size = 0) - : root_(root) - , index_(0) - { - } + xml_iarchive() + { + } - bool load_from_string(std::string & xml) + void load_data(char * data) { - doc_.clear(); + document_.clear(); try { - doc_.parse<0>(&xml[0]); - return true; + document_.parse<0>(data); } - catch(const rapidxml::parse_error & ) + catch(const rapidxml::parse_error & e) { - return false; + throw_serialization_error("xml parse", e.what()); } } - void load_start(const char * name) const + void load_key_start(const char * key) const + { + serialization_trace trace(__func__, key); + + auto node = stack_.top()->first_node(key); + if(node == nullptr) + throw_serialization_error("expect key", key); + stack_.push(node); + } + + bool load_key_start_optional(const char * key) const { - if(!check_node_name(current_, name)) - throw_serialization_error("load start", name); - stack_.push(current_); - current_ = current_->first_node(); + serialization_trace trace(__func__, key); + + auto node = stack_.top()->first_node(key); + if(node == nullptr) + { + return false; + } + stack_.push(node); + return true; } - void load_end(const char * name) const + void load_key_end(const char * key) const { - assert(stack_.size() != 0); - current_ = stack_.top(); + serialization_trace trace(__func__, key); stack_.pop(); - current_ = current_->next_sibling(); } - template - void load(T & out) const + void load_object_start() const { - assert(stack_.size() != 0); - current_ = stack_.top(); - get_value(current_->value(), out); } - void unserialize_start() const + void load_object_end() const { - stack_ = decltype(stack_)(); - current_ = doc_.first_node(); - if(!check_node_name(current_, root_.data())) - throw_serialization_error("unserialize start", "check node name"); - if(!current_) - throw_serialization_error("unserialize start", "check node name"); - current_ = current_->first_node(); } - void unserialize_end() const + size_type load_sequence_start() const { + serialization_trace trace(__func__, "xml"); + auto node = stack_.top()->first_node("sequence"); + if(node == nullptr) + { + throw_serialization_error(__func__, "expect sequence"); + } + auto attr = node->first_attribute("size"); + if(attr == nullptr) + { + throw_serialization_error(__func__, "expect sequence size"); + } + + char *end = attr->value(); + size_type size = std::strtoull(attr->value(), &end, 10); + if(end - attr->value() != attr->value_size()) + { + throw_serialization_error(__func__, "bad sequence size"); + } + + stack_.push(node); + node = (size == 0 ? nullptr : stack_.top()->first_node("item")); + stack_.push(node); + + return size; + } + + void load_sequence_end() const + { + serialization_trace trace(__func__, "xml"); + stack_.pop(); + stack_.pop(); + } + + bool load_sequence_item_start(size_type i) const + { + serialization_trace trace(__func__, "xml"); + + if(stack_.top() == nullptr) + { + throw_serialization_error("load sequence item", "xml"); + } + return true; + } + + void load_sequence_item_end() const + { + serialization_trace trace(__func__, "json"); + stack_.top() = stack_.top()->next_sibling("item"); } -private: template - void get_value(const char * str, T & dst) const + void load(T & v) const { - if(!str) - throw_serialization_error("get value", "null value"); std::stringstream ss; - ss << str; - ss >> dst; - if(!ss.eof()) - throw_serialization_error("get value", "eof"); + ss << stack_.top()->value(); + ss >> v; + if(!ss.eof()) + { + throw_serialization_error("load ", "xml"); + } } - void get_value(const char * str, std::string & dst) const + void load(std::string & v) const { - if(!str) - throw_serialization_error("get value", "null value"); - dst = str; + v = stack_.top()->value(); } - bool check_node_name(xml_node_type * node, const char * str) const + void load(bool & v) const { - if(node == 0 || std::strcmp(node->name(), str) != 0) - return false; - return true; + if(std::strcmp(stack_.top()->value(), "true")) + { + v = true; + } + else if(std::strcmp(stack_.top()->value(), "false")) + { + v = false; + } + throw_serialization_error("load ", "xml"); } - xml_document_type doc_; - - std::string root_; + void unserialize_start() const + { + serialization_trace trace(__func__, "xml"); + stack_ = std::stack *> {}; + auto node = document_.first_node("serialization"); + if(node == nullptr) + throw_serialization_error("serilization root", "xml"); + stack_.push(node); + } - mutable xml_node_type * current_; + void unserialize_end() const + { + serialization_trace trace(__func__, "xml"); + } - mutable std::stack stack_; +private: + rapidxml::xml_document<> document_; - mutable size_t index_; + mutable std::stack * > stack_; }; } // namespace serialization diff --git a/include/serialization/detail/xml_oarchive.h b/include/serialization/detail/xml_oarchive.h index a767b9f..6cb1952 100644 --- a/include/serialization/detail/xml_oarchive.h +++ b/include/serialization/detail/xml_oarchive.h @@ -1,120 +1,157 @@ #pragma once -#include -#include -#include -#include +#include #include #include +#include +#include namespace serialization { class xml_oarchive { - typedef rapidxml::xml_node<> xml_node_type; - typedef rapidxml::xml_document<> xml_document_type; - typedef std::string::const_iterator const_iterator; - typedef std::string::size_type size_type; public: - xml_oarchive(const std::string & root = "", size_t size = 0) - : root_(root) - { - if(size != 0) - data_.reserve(size); - } + xml_oarchive() + { + } const char * data() const { - return data_.data(); + return str_.data(); } - size_type size() const + std::size_t size() const { - return data_.size(); + return str_.size(); } - const_iterator begin() const - { - return data_.begin(); - } + void save_key_start(const char * key) + { + serialization_trace trace(__func__, key); + auto node = document_.allocate_node(rapidxml::node_element, key); + current_->append_node(node); + current_ = node; + } - const_iterator end() const - { - return data_.end(); + void save_key_end(const char * key) + { + serialization_trace trace(__func__, key); + current_ = current_->parent(); } - void save_start(const char * name) + void save_object_start() { - current_ = create_node(name); - parent_->append_node(current_); - stack_.push(parent_); - parent_ = current_; } - void save_end(const char * name) + void save_object_end() { - parent_ = stack_.top(); - stack_.pop(); - current_ = 0; } - template - void save(const T & v) + void save_sequence_start(size_type size) { - if(!current_) - throw_serialization_error("save", "xml node null"); - current_->value(get_string(v, doc_)); + serialization_trace trace(__func__, "xml"); + auto node = document_.allocate_node(rapidxml::node_element, "sequence"); + auto attr = document_.allocate_attribute("size", document_.allocate_string(std::to_string(size).c_str())); + node->append_attribute(attr); + current_->append_node(node); + current_ = node; } - void serialize_start() + void save_sequence_end() { - doc_.clear(); - stack_ = decltype(stack_)(); - parent_ = doc_.allocate_node(rapidxml::node_element, doc_.allocate_string(root_.c_str())); - current_ = 0; - doc_.append_node(parent_); + serialization_trace trace(__func__, "xml"); + current_ = current_->parent(); } - void serialize_end() + void save_sequence_item_start() { - rapidxml::print(std::back_inserter(data_), doc_); + serialization_trace trace(__func__, "xml"); + auto node = document_.allocate_node(rapidxml::node_element, "item"); + current_->append_node(node); + current_ = node; } -private: - template - bool write_container(const Argument & arg, const Container & in, const char * type, std::size_t size); + void save_sequence_item_end() + { + serialization_trace trace(__func__, "xml"); + current_ = current_->parent(); + } + + void save(int v) + { + char buffer[64]; + const char* end = rapidjson::internal::i64toa(v, buffer); + current_->value(document_.allocate_string(buffer, end - buffer), end - buffer); + } - xml_node_type * create_node(const char * name, const char * value = 0, std::size_t value_size = 0) + void save(uint v) + { + char buffer[64]; + const char* end = rapidjson::internal::u64toa(v, buffer); + current_->value(document_.allocate_string(buffer, end - buffer), end - buffer); + } + + void save(int64_t v) + { + char buffer[64]; + const char* end = rapidjson::internal::i64toa(v, buffer); + current_->value(document_.allocate_string(buffer, end - buffer), end - buffer); + } + + void save(uint64_t v) + { + char buffer[64]; + const char* end = rapidjson::internal::u64toa(v, buffer); + current_->value(document_.allocate_string(buffer, end - buffer), end - buffer); + } + + void save(double v) { - auto node = doc_.allocate_node(rapidxml::node_element, name, value, 0, value_size); - //parent_->append_node(node); - return node; + char buffer[64]; + const char* end = rapidjson::internal::dtoa(v, buffer); + current_->value(document_.allocate_string(buffer, end - buffer), end - buffer); } - template - char * get_string(const T & in, xml_document_type & doc) + void save(const std::string & v) { - std::stringstream ss; - ss << in; - return doc.allocate_string(ss.str().c_str()); + current_->value(v.c_str(), v.size()); } - char * get_string(const std::string & str, xml_document_type & doc) + void save(bool v) { - return doc.allocate_string(str.c_str()); + if(v) + { + current_->value("true"); + } + else + { + current_->value("false"); + } } - std::string data_; + void serialize_start() + { + serialization_trace trace(__func__, "xml"); + document_.clear(); + current_ = document_.allocate_node(rapidxml::node_element, "serialization"); + document_.append_node(current_); + str_.clear(); + } + + void serialize_end() + { + serialization_trace trace(__func__, "xml"); + rapidxml::print(std::back_inserter(str_), document_, rapidxml::print_no_indenting); + } - xml_document_type doc_; +private: + rapidxml::xml_document<> document_; - std::string root_; + rapidxml::xml_node<> *current_; - xml_node_type * current_; - xml_node_type * parent_; - std::stack stack_; + std::string str_; }; } // namespace serialization diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 36a96af..f8b550f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -10,6 +10,7 @@ include_directories(../include set(UNITTEST_SOURCES jsontest.cpp + xmltest.cpp unittest.cpp ) diff --git a/test/xmltest.cpp b/test/xmltest.cpp new file mode 100644 index 0000000..6f84f0c --- /dev/null +++ b/test/xmltest.cpp @@ -0,0 +1,206 @@ +#include "unittest.h" + +#include +#include + +struct TestInt +{ + int value; + bool operator==(const TestInt & other) const { return value == other.value; } + SERIALIZATION_DEFINE(value); +}; + +struct TestUint +{ + uint value; + bool operator==(const TestUint & other) const { return value == other.value; } + SERIALIZATION_DEFINE(value); +}; + +struct TestInt32 +{ + int32_t value; + bool operator==(const TestInt32 & other) const { return value == other.value; } + SERIALIZATION_DEFINE(value); +}; + +struct TestUint32 +{ + uint32_t value; + bool operator==(const TestUint32 & other) const { return value == other.value; } + SERIALIZATION_DEFINE(value); +}; + +struct TestInt64 +{ + int64_t value; + bool operator==(const TestInt64 & other) const { return value == other.value; } + SERIALIZATION_DEFINE(value); +}; + +struct TestUint64 +{ + uint64_t value; + bool operator==(const TestUint64 & other) const { return value == other.value; } + SERIALIZATION_DEFINE(value); +}; + +struct TestDouble +{ + double value; + SERIALIZATION_DEFINE(value); +}; + +struct TestString +{ + std::string value; + bool operator==(const TestString & other) const { return value == other.value; } + SERIALIZATION_DEFINE(value); +}; + +template +void check_serialize(const T & v) +{ + T v2; + try + { + // serialize + serialization::xml_oarchive oa; + serialization::serialize(oa, v); + + // unserialize + std::string str = oa.data(); + serialization::xml_iarchive ia; + ia.load_data(&str[0]); + serialization::unserialize(ia, v2); + } + catch (serialization::serialization_error & err) + { + std::cout << "serialization error: " << err.where() << ":" << err.what() << std::endl; + } + + EXPECT_EQ(v, v2); +} + +template +void test_integer() +{ + typedef decltype(T::value) int_type; + int_type gap = std::numeric_limits::max()/int_type{997}; + for(int_type i = std::numeric_limits::min(); i < std::numeric_limits::max() - gap; i += gap) + { + if(i > std::numeric_limits::max() - gap) + i = std::numeric_limits::max(); + + T a{i}; + //std::cout << i << ","; + check_serialize(a); + } + //std::cout << std::endl; +} + +TEST(test_xml, test_int) +{ + test_integer(); +} + +TEST(test_xml, test_uint) +{ + test_integer(); +} + +TEST(test_xml, test_int32) +{ + test_integer(); +} + +TEST(test_xml, test_uint32) +{ + test_integer(); +} + +TEST(test_xml, test_int64) +{ + test_integer(); +} + +TEST(test_xml, test_uint64) +{ + test_integer(); +} + +TEST(test_xml, test_double) +{ + TestDouble a,b; + // int can convert to double + TestInt c; + double values[10] = { 0, 2, 16, -4, 1.2, 4.3, 5.555, 6.3333, 1.3333333, -1212.122132111}; + for(int i = 0; i < 10; ++i) + { + try + { + // serialize + serialization::xml_oarchive oa; + if(i < 4) + { + c.value = values[i]; + serialization::serialize(oa, c); + } + else + { + a.value = values[i]; + serialization::serialize(oa, a); + } + // unserialize + serialization::xml_iarchive ia; + std::string str = oa.data(); + //std::cout << oa.data() << std::endl; + ia.load_data(&str[0]); + serialization::unserialize(ia, b); + } + catch (serialization::serialization_error & err) + { + std::cout << "serialization error: " << err.where() << ":" << err.what() << std::endl; + } + + if(i < 4) + { + EXPECT_NEAR(c.value, b.value, 0.0); + } + else + { + EXPECT_NEAR(a.value, b.value, 0.0); + } + } +} + +TEST(test_xml, test_string) +{ + TestString a,b; + const char * values[] = { "", "asadasdas\"", R"(!@#$%&^*&*_++_**&^%$%#@#!~!{}:"?>>