14510239cf3de258e36fcfbe4fb72ef77567f775
[alexxy/gromacs.git] / src / gromacs / utility / keyvaluetreeserializer.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2016,2017,2018,2019, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35 #include "gmxpre.h"
36
37 #include "keyvaluetreeserializer.h"
38
39 #include "gromacs/utility/iserializer.h"
40 #include "gromacs/utility/keyvaluetree.h"
41 #include "gromacs/utility/keyvaluetreebuilder.h"
42 #include "gromacs/utility/mutex.h"
43
44 namespace gmx
45 {
46
47 namespace
48 {
49
50 class ValueSerializer
51 {
52 public:
53     static void initSerializers();
54
55     static void              serialize(const KeyValueTreeValue& value, ISerializer* serializer);
56     static KeyValueTreeValue deserialize(ISerializer* serializer);
57
58 private:
59     ValueSerializer() = delete;
60
61     typedef void (*SerializerFunction)(const KeyValueTreeValue& value, ISerializer* serializer);
62     typedef void (*DeserializerFunction)(KeyValueTreeValueBuilder* builder, ISerializer* serializer);
63
64     struct Serializer
65     {
66         unsigned char        typeTag;
67         SerializerFunction   serialize;
68         DeserializerFunction deserialize;
69     };
70
71     static Mutex                                         s_initMutex;
72     static std::map<std::type_index, Serializer>         s_serializers;
73     static std::map<unsigned char, DeserializerFunction> s_deserializers;
74 };
75
76 Mutex                                                          ValueSerializer::s_initMutex;
77 std::map<std::type_index, ValueSerializer::Serializer>         ValueSerializer::s_serializers;
78 std::map<unsigned char, ValueSerializer::DeserializerFunction> ValueSerializer::s_deserializers;
79
80 template<typename T>
81 struct SerializationTraits
82 {
83 };
84
85 template<>
86 struct SerializationTraits<KeyValueTreeObject>
87 {
88     static void serialize(const KeyValueTreeObject& value, ISerializer* serializer)
89     {
90         int count = value.properties().size();
91         serializer->doInt(&count);
92         for (const auto& prop : value.properties())
93         {
94             serializer->doString(const_cast<std::string*>(&prop.key()));
95             ValueSerializer::serialize(prop.value(), serializer);
96         }
97     }
98     static void deserialize(KeyValueTreeValueBuilder* value, ISerializer* serializer)
99     {
100         KeyValueTreeObjectBuilder builder(value->createObject());
101         deserializeObject(&builder, serializer);
102     }
103     static void deserializeObject(KeyValueTreeObjectBuilder* builder, ISerializer* serializer)
104     {
105         int         count;
106         std::string key;
107         serializer->doInt(&count);
108         for (int i = 0; i < count; ++i)
109         {
110             serializer->doString(&key);
111             builder->addRawValue(key, ValueSerializer::deserialize(serializer));
112         }
113     }
114 };
115
116 template<>
117 struct SerializationTraits<KeyValueTreeArray>
118 {
119     static void serialize(const KeyValueTreeArray& array, ISerializer* serializer)
120     {
121         int count = array.values().size();
122         serializer->doInt(&count);
123         for (const auto& value : array.values())
124         {
125             ValueSerializer::serialize(value, serializer);
126         }
127     }
128     static void deserialize(KeyValueTreeValueBuilder* value, ISerializer* serializer)
129     {
130         KeyValueTreeArrayBuilder builder(value->createArray());
131         int                      count;
132         serializer->doInt(&count);
133         for (int i = 0; i < count; ++i)
134         {
135             builder.addRawValue(ValueSerializer::deserialize(serializer));
136         }
137     }
138 };
139
140 template<>
141 struct SerializationTraits<std::string>
142 {
143     static void serialize(const std::string& value, ISerializer* serializer)
144     {
145         serializer->doString(const_cast<std::string*>(&value));
146     }
147     static void deserialize(KeyValueTreeValueBuilder* builder, ISerializer* serializer)
148     {
149         std::string value;
150         serializer->doString(&value);
151         builder->setValue<std::string>(value);
152     }
153 };
154
155 template<>
156 struct SerializationTraits<bool>
157 {
158     static void serialize(bool value, ISerializer* serializer) { serializer->doBool(&value); }
159     static void deserialize(KeyValueTreeValueBuilder* builder, ISerializer* serializer)
160     {
161         bool value;
162         serializer->doBool(&value);
163         builder->setValue<bool>(value);
164     }
165 };
166
167 template<>
168 struct SerializationTraits<int>
169 {
170     static void serialize(int value, ISerializer* serializer) { serializer->doInt(&value); }
171     static void deserialize(KeyValueTreeValueBuilder* builder, ISerializer* serializer)
172     {
173         int value;
174         serializer->doInt(&value);
175         builder->setValue<int>(value);
176     }
177 };
178
179 template<>
180 struct SerializationTraits<int64_t>
181 {
182     static void serialize(int64_t value, ISerializer* serializer) { serializer->doInt64(&value); }
183     static void deserialize(KeyValueTreeValueBuilder* builder, ISerializer* serializer)
184     {
185         int64_t value;
186         serializer->doInt64(&value);
187         builder->setValue<int64_t>(value);
188     }
189 };
190
191 template<>
192 struct SerializationTraits<float>
193 {
194     static void serialize(float value, ISerializer* serializer) { serializer->doFloat(&value); }
195     static void deserialize(KeyValueTreeValueBuilder* builder, ISerializer* serializer)
196     {
197         float value;
198         serializer->doFloat(&value);
199         builder->setValue<float>(value);
200     }
201 };
202
203 template<>
204 struct SerializationTraits<double>
205 {
206     static void serialize(double value, ISerializer* serializer) { serializer->doDouble(&value); }
207     static void deserialize(KeyValueTreeValueBuilder* builder, ISerializer* serializer)
208     {
209         double value;
210         serializer->doDouble(&value);
211         builder->setValue<double>(value);
212     }
213 };
214
215 //! Helper function for serializing values of a certain type.
216 template<typename T>
217 void serializeValueType(const KeyValueTreeValue& value, ISerializer* serializer)
218 {
219     SerializationTraits<T>::serialize(value.cast<T>(), serializer);
220 }
221
222 #define SERIALIZER(tag, type)                                                       \
223     {                                                                               \
224         std::type_index(typeid(type)),                                              \
225         {                                                                           \
226             tag, &serializeValueType<type>, &SerializationTraits<type>::deserialize \
227         }                                                                           \
228     }
229
230 // static
231 void ValueSerializer::initSerializers()
232 {
233     lock_guard<Mutex> lock(s_initMutex);
234     if (!s_serializers.empty())
235     {
236         return;
237     }
238     s_serializers = {
239         SERIALIZER('O', KeyValueTreeObject),
240         SERIALIZER('A', KeyValueTreeArray),
241         SERIALIZER('s', std::string),
242         SERIALIZER('b', bool),
243         SERIALIZER('i', int),
244         SERIALIZER('l', int64_t),
245         SERIALIZER('f', float),
246         SERIALIZER('d', double),
247     };
248     for (const auto& item : s_serializers)
249     {
250         s_deserializers[item.second.typeTag] = item.second.deserialize;
251     }
252 }
253
254 void ValueSerializer::serialize(const KeyValueTreeValue& value, ISerializer* serializer)
255 {
256     auto iter = s_serializers.find(value.type());
257     GMX_RELEASE_ASSERT(iter != s_serializers.end(), "Unknown value type for serializization");
258     unsigned char typeTag = iter->second.typeTag;
259     serializer->doUChar(&typeTag);
260     iter->second.serialize(value, serializer);
261 }
262
263 KeyValueTreeValue ValueSerializer::deserialize(ISerializer* serializer)
264 {
265     unsigned char typeTag;
266     serializer->doUChar(&typeTag);
267     auto iter = s_deserializers.find(typeTag);
268     GMX_RELEASE_ASSERT(iter != s_deserializers.end(), "Unknown type tag for deserializization");
269     KeyValueTreeValueBuilder builder;
270     iter->second(&builder, serializer);
271     return builder.build();
272 }
273
274 } // namespace
275
276 //! \cond libapi
277 void serializeKeyValueTree(const KeyValueTreeObject& root, ISerializer* serializer)
278 {
279     GMX_RELEASE_ASSERT(!serializer->reading(), "Incorrect serializer direction");
280     ValueSerializer::initSerializers();
281     SerializationTraits<KeyValueTreeObject>::serialize(root, serializer);
282 }
283
284 KeyValueTreeObject deserializeKeyValueTree(ISerializer* serializer)
285 {
286     GMX_RELEASE_ASSERT(serializer->reading(), "Incorrect serializer direction");
287     ValueSerializer::initSerializers();
288     KeyValueTreeBuilder       builder;
289     KeyValueTreeObjectBuilder obj(builder.rootObject());
290     SerializationTraits<KeyValueTreeObject>::deserializeObject(&obj, serializer);
291     return builder.build();
292 }
293 //! \endcond
294
295 } // namespace gmx