Replace gmx::Mutex with std::mutex
[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,2021, 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 <mutex>
40
41 #include "gromacs/utility/iserializer.h"
42 #include "gromacs/utility/keyvaluetree.h"
43 #include "gromacs/utility/keyvaluetreebuilder.h"
44
45 namespace gmx
46 {
47
48 namespace
49 {
50
51 class ValueSerializer
52 {
53 public:
54     static void initSerializers();
55
56     static void              serialize(const KeyValueTreeValue& value, ISerializer* serializer);
57     static KeyValueTreeValue deserialize(ISerializer* serializer);
58
59 private:
60     ValueSerializer() = delete;
61
62     typedef void (*SerializerFunction)(const KeyValueTreeValue& value, ISerializer* serializer);
63     typedef void (*DeserializerFunction)(KeyValueTreeValueBuilder* builder, ISerializer* serializer);
64
65     struct Serializer
66     {
67         unsigned char        typeTag;
68         SerializerFunction   serialize;
69         DeserializerFunction deserialize;
70     };
71
72     static std::mutex                                    s_initMutex;
73     static std::map<std::type_index, Serializer>         s_serializers;
74     static std::map<unsigned char, DeserializerFunction> s_deserializers;
75 };
76
77 std::mutex                                                     ValueSerializer::s_initMutex;
78 std::map<std::type_index, ValueSerializer::Serializer>         ValueSerializer::s_serializers;
79 std::map<unsigned char, ValueSerializer::DeserializerFunction> ValueSerializer::s_deserializers;
80
81 template<typename T>
82 struct SerializationTraits
83 {
84 };
85
86 template<>
87 struct SerializationTraits<KeyValueTreeObject>
88 {
89     static void serialize(const KeyValueTreeObject& value, ISerializer* serializer)
90     {
91         int count = value.properties().size();
92         serializer->doInt(&count);
93         for (const auto& prop : value.properties())
94         {
95             serializer->doString(const_cast<std::string*>(&prop.key()));
96             ValueSerializer::serialize(prop.value(), serializer);
97         }
98     }
99     static void deserialize(KeyValueTreeValueBuilder* value, ISerializer* serializer)
100     {
101         KeyValueTreeObjectBuilder builder(value->createObject());
102         deserializeObject(&builder, serializer);
103     }
104     static void deserializeObject(KeyValueTreeObjectBuilder* builder, ISerializer* serializer)
105     {
106         int         count;
107         std::string key;
108         serializer->doInt(&count);
109         for (int i = 0; i < count; ++i)
110         {
111             serializer->doString(&key);
112             builder->addRawValue(key, ValueSerializer::deserialize(serializer));
113         }
114     }
115 };
116
117 template<>
118 struct SerializationTraits<KeyValueTreeArray>
119 {
120     static void serialize(const KeyValueTreeArray& array, ISerializer* serializer)
121     {
122         int count = array.values().size();
123         serializer->doInt(&count);
124         for (const auto& value : array.values())
125         {
126             ValueSerializer::serialize(value, serializer);
127         }
128     }
129     static void deserialize(KeyValueTreeValueBuilder* value, ISerializer* serializer)
130     {
131         KeyValueTreeArrayBuilder builder(value->createArray());
132         int                      count;
133         serializer->doInt(&count);
134         for (int i = 0; i < count; ++i)
135         {
136             builder.addRawValue(ValueSerializer::deserialize(serializer));
137         }
138     }
139 };
140
141 template<>
142 struct SerializationTraits<std::string>
143 {
144     static void serialize(const std::string& value, ISerializer* serializer)
145     {
146         serializer->doString(const_cast<std::string*>(&value));
147     }
148     static void deserialize(KeyValueTreeValueBuilder* builder, ISerializer* serializer)
149     {
150         std::string value;
151         serializer->doString(&value);
152         builder->setValue<std::string>(value);
153     }
154 };
155
156 template<>
157 struct SerializationTraits<bool>
158 {
159     static void serialize(bool value, ISerializer* serializer) { serializer->doBool(&value); }
160     static void deserialize(KeyValueTreeValueBuilder* builder, ISerializer* serializer)
161     {
162         bool value;
163         serializer->doBool(&value);
164         builder->setValue<bool>(value);
165     }
166 };
167
168 template<>
169 struct SerializationTraits<int>
170 {
171     static void serialize(int value, ISerializer* serializer) { serializer->doInt(&value); }
172     static void deserialize(KeyValueTreeValueBuilder* builder, ISerializer* serializer)
173     {
174         int value;
175         serializer->doInt(&value);
176         builder->setValue<int>(value);
177     }
178 };
179
180 template<>
181 struct SerializationTraits<int64_t>
182 {
183     static void serialize(int64_t value, ISerializer* serializer) { serializer->doInt64(&value); }
184     static void deserialize(KeyValueTreeValueBuilder* builder, ISerializer* serializer)
185     {
186         int64_t value;
187         serializer->doInt64(&value);
188         builder->setValue<int64_t>(value);
189     }
190 };
191
192 template<>
193 struct SerializationTraits<float>
194 {
195     static void serialize(float value, ISerializer* serializer) { serializer->doFloat(&value); }
196     static void deserialize(KeyValueTreeValueBuilder* builder, ISerializer* serializer)
197     {
198         float value;
199         serializer->doFloat(&value);
200         builder->setValue<float>(value);
201     }
202 };
203
204 template<>
205 struct SerializationTraits<double>
206 {
207     static void serialize(double value, ISerializer* serializer) { serializer->doDouble(&value); }
208     static void deserialize(KeyValueTreeValueBuilder* builder, ISerializer* serializer)
209     {
210         double value;
211         serializer->doDouble(&value);
212         builder->setValue<double>(value);
213     }
214 };
215
216 //! Helper function for serializing values of a certain type.
217 template<typename T>
218 void serializeValueType(const KeyValueTreeValue& value, ISerializer* serializer)
219 {
220     SerializationTraits<T>::serialize(value.cast<T>(), serializer);
221 }
222
223 #define SERIALIZER(tag, type)                                                       \
224     {                                                                               \
225         std::type_index(typeid(type)),                                              \
226         {                                                                           \
227             tag, &serializeValueType<type>, &SerializationTraits<type>::deserialize \
228         }                                                                           \
229     }
230
231 // static
232 void ValueSerializer::initSerializers()
233 {
234     std::lock_guard<std::mutex> lock(s_initMutex);
235     if (!s_serializers.empty())
236     {
237         return;
238     }
239     s_serializers = {
240         SERIALIZER('O', KeyValueTreeObject),
241         SERIALIZER('A', KeyValueTreeArray),
242         SERIALIZER('s', std::string),
243         SERIALIZER('b', bool),
244         SERIALIZER('i', int),
245         SERIALIZER('l', int64_t),
246         SERIALIZER('f', float),
247         SERIALIZER('d', double),
248     };
249     for (const auto& item : s_serializers)
250     {
251         s_deserializers[item.second.typeTag] = item.second.deserialize;
252     }
253 }
254
255 void ValueSerializer::serialize(const KeyValueTreeValue& value, ISerializer* serializer)
256 {
257     auto iter = s_serializers.find(value.type());
258     GMX_RELEASE_ASSERT(iter != s_serializers.end(), "Unknown value type for serializization");
259     unsigned char typeTag = iter->second.typeTag;
260     serializer->doUChar(&typeTag);
261     iter->second.serialize(value, serializer);
262 }
263
264 KeyValueTreeValue ValueSerializer::deserialize(ISerializer* serializer)
265 {
266     unsigned char typeTag;
267     serializer->doUChar(&typeTag);
268     auto iter = s_deserializers.find(typeTag);
269     GMX_RELEASE_ASSERT(iter != s_deserializers.end(), "Unknown type tag for deserializization");
270     KeyValueTreeValueBuilder builder;
271     iter->second(&builder, serializer);
272     return builder.build();
273 }
274
275 } // namespace
276
277 //! \cond libapi
278 void serializeKeyValueTree(const KeyValueTreeObject& root, ISerializer* serializer)
279 {
280     GMX_RELEASE_ASSERT(!serializer->reading(), "Incorrect serializer direction");
281     ValueSerializer::initSerializers();
282     SerializationTraits<KeyValueTreeObject>::serialize(root, serializer);
283 }
284
285 KeyValueTreeObject deserializeKeyValueTree(ISerializer* serializer)
286 {
287     GMX_RELEASE_ASSERT(serializer->reading(), "Incorrect serializer direction");
288     ValueSerializer::initSerializers();
289     KeyValueTreeBuilder       builder;
290     KeyValueTreeObjectBuilder obj(builder.rootObject());
291     SerializationTraits<KeyValueTreeObject>::deserializeObject(&obj, serializer);
292     return builder.build();
293 }
294 //! \endcond
295
296 } // namespace gmx