Index: ps/trunk/source/simulation2/serialization/SerializeTemplates.h =================================================================== --- ps/trunk/source/simulation2/serialization/SerializeTemplates.h (revision 23043) +++ ps/trunk/source/simulation2/serialization/SerializeTemplates.h (revision 23044) @@ -1,312 +1,343 @@ -/* Copyright (C) 2016 Wildfire Games. +/* Copyright (C) 2019 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. 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 2 of the License, or * (at your option) any later version. * * 0 A.D. 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 0 A.D. If not, see . */ #ifndef INCLUDED_SERIALIZETEMPLATES #define INCLUDED_SERIALIZETEMPLATES /** * @file * Helper templates for serializing/deserializing common objects. */ #include "simulation2/components/ICmpPathfinder.h" +#include "simulation2/serialization/IDeserializer.h" +#include "simulation2/serialization/ISerializer.h" + +#include +#include template struct SerializeVector { template void operator()(ISerializer& serialize, const char* name, std::vector& value) { size_t len = value.size(); serialize.NumberU32_Unbounded("length", (u32)len); for (size_t i = 0; i < len; ++i) ELEM()(serialize, name, value[i]); } template void operator()(IDeserializer& deserialize, const char* name, std::vector& value) { value.clear(); u32 len; deserialize.NumberU32_Unbounded("length", len); value.reserve(len); // TODO: watch out for out-of-memory for (size_t i = 0; i < len; ++i) { T el; ELEM()(deserialize, name, el); value.push_back(el); } } }; template struct SerializeRepetitiveVector { template void operator()(ISerializer& serialize, const char* name, std::vector& value) { size_t len = value.size(); serialize.NumberU32_Unbounded("length", (u32)len); if (len == 0) return; u32 count = 1; T prevVal = value[0]; for (size_t i = 1; i < len; ++i) { if (prevVal == value[i]) { count++; continue; } serialize.NumberU32_Unbounded("#", count); ELEM()(serialize, name, prevVal); count = 1; prevVal = value[i]; } serialize.NumberU32_Unbounded("#", count); ELEM()(serialize, name, prevVal); } template void operator()(IDeserializer& deserialize, const char* name, std::vector& value) { value.clear(); u32 len; deserialize.NumberU32_Unbounded("length", len); value.reserve(len); // TODO: watch out for out-of-memory for (size_t i = 0; i < len;) { u32 count; deserialize.NumberU32_Unbounded("#", count); T el; ELEM()(deserialize, name, el); i += count; value.insert(value.end(), count, el); } } }; +template +struct SerializeSet +{ + template + void operator()(ISerializer& serialize, const char* name, const std::set& value) + { + serialize.NumberU32_Unbounded("size", static_cast(value.size())); + for (const T& elem : value) + ELEM()(serialize, name, elem); + } + + template + void operator()(IDeserializer& deserialize, const char* name, std::set& value) + { + value.clear(); + u32 size; + deserialize.NumberU32_Unbounded("size", size); + for (size_t i = 0; i < size; ++i) + { + T el; + ELEM()(deserialize, name, el); + value.emplace(std::move(el)); + } + } +}; + template struct SerializeMap { template void operator()(ISerializer& serialize, const char* UNUSED(name), std::map& value) { size_t len = value.size(); serialize.NumberU32_Unbounded("length", (u32)len); for (typename std::map::iterator it = value.begin(); it != value.end(); ++it) { KS()(serialize, "key", it->first); VS()(serialize, "value", it->second); } } template void operator()(ISerializer& serialize, const char* UNUSED(name), std::map& value, C& context) { size_t len = value.size(); serialize.NumberU32_Unbounded("length", (u32)len); for (typename std::map::iterator it = value.begin(); it != value.end(); ++it) { KS()(serialize, "key", it->first); VS()(serialize, "value", it->second, context); } } template void operator()(IDeserializer& deserialize, const char* UNUSED(name), M& value) { typedef typename M::key_type K; typedef typename M::value_type::second_type V; // M::data_type gives errors with gcc value.clear(); u32 len; deserialize.NumberU32_Unbounded("length", len); for (size_t i = 0; i < len; ++i) { K k; V v; KS()(deserialize, "key", k); VS()(deserialize, "value", v); - value.insert(std::make_pair(k, v)); + value.emplace(std::move(k), std::move(v)); } } template void operator()(IDeserializer& deserialize, const char* UNUSED(name), M& value, C& context) { typedef typename M::key_type K; typedef typename M::value_type::second_type V; // M::data_type gives errors with gcc value.clear(); u32 len; deserialize.NumberU32_Unbounded("length", len); for (size_t i = 0; i < len; ++i) { K k; V v; KS()(deserialize, "key", k); VS()(deserialize, "value", v, context); - value.insert(std::make_pair(k, v)); + value.emplace(std::move(k), std::move(v)); } } }; // We have to order the map before serializing to make things consistent template struct SerializeUnorderedMap { template void operator()(ISerializer& serialize, const char* name, boost::unordered_map& value) { std::map ordered_value(value.begin(), value.end()); SerializeMap()(serialize, name, ordered_value); } template void operator()(IDeserializer& deserialize, const char* name, boost::unordered_map& value) { SerializeMap()(deserialize, name, value); } }; template struct SerializeU8_Enum { void operator()(ISerializer& serialize, const char* name, T value) { serialize.NumberU8(name, value, 0, max); } void operator()(IDeserializer& deserialize, const char* name, T& value) { u8 val; deserialize.NumberU8(name, val, 0, max); - value = (T)val; + value = static_cast(val); } }; struct SerializeU8_Unbounded { void operator()(ISerializer& serialize, const char* name, u8 value) { serialize.NumberU8_Unbounded(name, value); } void operator()(IDeserializer& deserialize, const char* name, u8& value) { deserialize.NumberU8_Unbounded(name, value); } }; struct SerializeU16_Unbounded { void operator()(ISerializer& serialize, const char* name, u16 value) { serialize.NumberU16_Unbounded(name, value); } void operator()(IDeserializer& deserialize, const char* name, u16& value) { deserialize.NumberU16_Unbounded(name, value); } }; struct SerializeU32_Unbounded { void operator()(ISerializer& serialize, const char* name, u32 value) { serialize.NumberU32_Unbounded(name, value); } void operator()(IDeserializer& deserialize, const char* name, u32& value) { deserialize.NumberU32_Unbounded(name, value); } }; struct SerializeI32_Unbounded { void operator()(ISerializer& serialize, const char* name, i32 value) { serialize.NumberI32_Unbounded(name, value); } void operator()(IDeserializer& deserialize, const char* name, i32& value) { deserialize.NumberI32_Unbounded(name, value); } }; struct SerializeBool { void operator()(ISerializer& serialize, const char* name, bool value) { serialize.Bool(name, value); } void operator()(IDeserializer& deserialize, const char* name, bool& value) { deserialize.Bool(name, value); } }; struct SerializeString { void operator()(ISerializer& serialize, const char* name, const std::string& value) { serialize.StringASCII(name, value, 0, UINT32_MAX); } void operator()(IDeserializer& deserialize, const char* name, std::string& value) { deserialize.StringASCII(name, value, 0, UINT32_MAX); } }; struct SerializeWaypoint { void operator()(ISerializer& serialize, const char* UNUSED(name), const Waypoint& value) { serialize.NumberFixed_Unbounded("waypoint x", value.x); serialize.NumberFixed_Unbounded("waypoint z", value.z); } void operator()(IDeserializer& deserialize, const char* UNUSED(name), Waypoint& value) { deserialize.NumberFixed_Unbounded("waypoint x", value.x); deserialize.NumberFixed_Unbounded("waypoint z", value.z); } }; struct SerializeGoal { template void operator()(S& serialize, const char* UNUSED(name), PathGoal& value) { SerializeU8_Enum()(serialize, "type", value.type); serialize.NumberFixed_Unbounded("goal x", value.x); serialize.NumberFixed_Unbounded("goal z", value.z); serialize.NumberFixed_Unbounded("goal u x", value.u.X); serialize.NumberFixed_Unbounded("goal u z", value.u.Y); serialize.NumberFixed_Unbounded("goal v x", value.v.X); serialize.NumberFixed_Unbounded("goal v z", value.v.Y); serialize.NumberFixed_Unbounded("goal hw", value.hw); serialize.NumberFixed_Unbounded("goal hh", value.hh); serialize.NumberFixed_Unbounded("maxdist", value.maxdist); } }; #endif // INCLUDED_SERIALIZETEMPLATES Index: ps/trunk/source/simulation2/tests/test_SerializeTemplates.h =================================================================== --- ps/trunk/source/simulation2/tests/test_SerializeTemplates.h (nonexistent) +++ ps/trunk/source/simulation2/tests/test_SerializeTemplates.h (revision 23044) @@ -0,0 +1,56 @@ +/* Copyright (C) 2019 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. 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 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. 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 0 A.D. If not, see . + */ + +#include "lib/self_test.h" + +#include "scriptinterface/ScriptInterface.h" +#include "simulation2/serialization/DebugSerializer.h" +#include "simulation2/serialization/SerializeTemplates.h" + +#include +#include +#include + +class TestSerializeTemplates : public CxxTest::TestSuite +{ +public: + void test_Debug_vector() + { + ScriptInterface script("Test", "Test", g_ScriptRuntime); + std::stringstream stream; + + CDebugSerializer serialize(script, stream); + std::vector value = { + 3, 0, 1, 4, 1, 5 + }; + SerializeVector()(serialize, "E", value); + TS_ASSERT_STR_EQUALS(stream.str(), "length: 6\nE: 3\nE: 0\nE: 1\nE: 4\nE: 1\nE: 5\n"); + } + + void test_Debug_set() + { + ScriptInterface script("Test", "Test", g_ScriptRuntime); + std::stringstream stream; + + CDebugSerializer serialize(script, stream); + std::set value = { + 3, 0, 1, 4, 1, 5 + }; + SerializeSet()(serialize, "E", value); + TS_ASSERT_STR_EQUALS(stream.str(), "size: 5\nE: 0\nE: 1\nE: 3\nE: 4\nE: 5\n"); + } +};